diff options
author | Ben Gamari <bgamari.foss@gmail.com> | 2017-02-07 22:49:06 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2017-02-08 10:25:59 -0500 |
commit | 3eb737ee3f900f256a7474b199a4ab40178a8cac (patch) | |
tree | c29fff652630ff28224c730faae7a4ace67f7049 /compiler/cmm/CmmLayoutStack.hs | |
parent | 421308ef6ae3987f8077c6bfe1d9a6a03e53458c (diff) | |
download | haskell-3eb737ee3f900f256a7474b199a4ab40178a8cac.tar.gz |
Generalize CmmUnwind and pass unwind information through NCG
As discussed in D1532, Trac Trac #11337, and Trac Trac #11338, the stack
unwinding information produced by GHC is currently quite approximate.
Essentially we assume that register values do not change at all within a
basic block. While this is somewhat true in normal Haskell code, blocks
containing foreign calls often break this assumption. This results in
unreliable call stacks, especially in the code containing foreign calls.
This is worse than it sounds as unreliable unwinding information can at
times result in segmentation faults.
This patch set attempts to improve this situation by tracking unwinding
information with finer granularity. By dispensing with the assumption of
one unwinding table per block, we allow the compiler to accurately
represent the areas surrounding foreign calls.
Towards this end we generalize the representation of unwind information
in the backend in three ways,
* Multiple CmmUnwind nodes can occur per block
* CmmUnwind nodes can now carry unwind information for multiple
registers (while not strictly necessary; this makes emitting
unwinding information a bit more convenient in the compiler)
* The NCG backend is given an opportunity to modify the unwinding
records since it may need to make adjustments due to, for instance,
native calling convention requirements for foreign calls (see
#11353).
This sets the stage for resolving #11337 and #11338.
Test Plan: Validate
Reviewers: scpmw, simonmar, austin, erikd
Subscribers: qnikst, thomie
Differential Revision: https://phabricator.haskell.org/D2741
Diffstat (limited to 'compiler/cmm/CmmLayoutStack.hs')
-rw-r--r-- | compiler/cmm/CmmLayoutStack.hs | 32 |
1 files changed, 17 insertions, 15 deletions
diff --git a/compiler/cmm/CmmLayoutStack.hs b/compiler/cmm/CmmLayoutStack.hs index 0f8495f3e6..60f89704f0 100644 --- a/compiler/cmm/CmmLayoutStack.hs +++ b/compiler/cmm/CmmLayoutStack.hs @@ -275,10 +275,11 @@ layout dflags procpoints liveness entry entry_args final_stackmaps final_sp_high -- let middle_pre = blockToList $ foldl blockSnoc middle1 middle2 - final_blocks = manifestSp dflags final_stackmaps stack0 sp0 final_sp_high entry0 - middle_pre sp_off last1 fixup_blocks + let final_blocks = + manifestSp dflags final_stackmaps stack0 sp0 final_sp_high + entry0 middle_pre sp_off last1 fixup_blocks - acc_stackmaps' = mapUnion acc_stackmaps out + let acc_stackmaps' = mapUnion acc_stackmaps out -- If this block jumps to the GC, then we do not take its -- stack usage into account for the high-water mark. @@ -793,19 +794,20 @@ manifestSp dflags stackmaps stack0 sp0 sp_high adj_pre_sp = mapExpDeep (areaToSp dflags sp0 sp_high area_off) adj_post_sp = mapExpDeep (areaToSp dflags (sp0 - sp_off) sp_high area_off) - -- Add unwind pseudo-instructions to document Sp level for debugging + -- Add unwind pseudo-instructions at the beginning of each block to + -- document Sp level for debugging add_unwind_info block - | debugLevel dflags > 0 = CmmUnwind Sp sp_unwind : block + | debugLevel dflags > 0 = + CmmUnwind [(Sp, sp_unwind)] : block | otherwise = block sp_unwind = CmmRegOff (CmmGlobal Sp) (sp0 - wORD_SIZE dflags) - final_middle = maybeAddSpAdj dflags sp_off $ - blockFromList $ - add_unwind_info $ - map adj_pre_sp $ - elimStackStores stack0 stackmaps area_off $ - middle_pre - + final_middle = maybeAddSpAdj dflags sp_off + . blockFromList + . add_unwind_info + . map adj_pre_sp + . elimStackStores stack0 stackmaps area_off + $ middle_pre final_last = optStackCheck (adj_post_sp last) final_block = blockJoin first final_middle final_last @@ -823,9 +825,9 @@ getAreaOff stackmaps (Young l) = maybeAddSpAdj :: DynFlags -> ByteOff -> Block CmmNode O O -> Block CmmNode O O maybeAddSpAdj _ 0 block = block -maybeAddSpAdj dflags sp_off block - = block `blockSnoc` CmmAssign spReg (cmmOffset dflags (CmmReg spReg) sp_off) - +maybeAddSpAdj dflags sp_off block = block `blockSnoc` adj + where + adj = CmmAssign spReg (cmmOffset dflags (CmmReg spReg) sp_off) {- Sp(L) is the Sp offset on entry to block L relative to the base of the |