diff options
author | Jan Stolarek <jan.stolarek@p.lodz.pl> | 2013-09-04 14:11:40 +0100 |
---|---|---|
committer | Jan Stolarek <jan.stolarek@p.lodz.pl> | 2013-09-04 14:49:16 +0100 |
commit | d02a50ee1437a24a0fb584286cf8f16cff59d217 (patch) | |
tree | e4d2fabb7f61f5b4d6ebc48c0e92f56a7d84cacd | |
parent | e30c84cb5adcd35e4b8301804af39df605ffcc7f (diff) | |
download | haskell-d02a50ee1437a24a0fb584286cf8f16cff59d217.tar.gz |
Fix definition of DefinerOfRegs for CmmForeignCall
And update comments
-rw-r--r-- | compiler/cmm/CmmNode.hs | 79 | ||||
-rw-r--r-- | compiler/cmm/CmmSink.hs | 7 |
2 files changed, 78 insertions, 8 deletions
diff --git a/compiler/cmm/CmmNode.hs b/compiler/cmm/CmmNode.hs index e6b1a5ac02..7a4fb98a79 100644 --- a/compiler/cmm/CmmNode.hs +++ b/compiler/cmm/CmmNode.hs @@ -52,7 +52,7 @@ data CmmNode e x where [CmmActual] -> -- zero or more arguments CmmNode O O -- Semantics: clobbers any GlobalRegs for which callerSaves r == True - -- See Note [foreign calls clobber GlobalRegs] + -- See Note [Unsafe foreign calls clobber caller-save registers] -- -- Invariant: the arguments and the ForeignTarget must not -- mention any registers for which CodeGen.Platform.callerSaves @@ -158,8 +158,8 @@ made manifest in CmmLayoutStack, where they are lowered into the above sequence. -} -{- Note [foreign calls clobber GlobalRegs] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +{- Note [Unsafe foreign calls clobber caller-save registers] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A foreign call is defined to clobber any GlobalRegs that are mapped to caller-saves machine registers (according to the prevailing C ABI). @@ -329,8 +329,9 @@ instance DefinerOfRegs GlobalReg (CmmNode e x) where foldRegsDefd dflags f z n = case n of CmmAssign lhs _ -> fold f z lhs CmmUnsafeForeignCall tgt _ _ -> fold f z (foreignTargetRegs tgt) - CmmCall {} -> fold f z activeRegs - CmmForeignCall {tgt=tgt} -> fold f z (foreignTargetRegs tgt) + CmmCall {} -> fold f z activeRegs + CmmForeignCall {} -> fold f z activeRegs + -- See Note [Safe foreign calls clobber STG registers] _ -> z where fold :: forall a b. DefinerOfRegs GlobalReg a => @@ -344,6 +345,74 @@ instance DefinerOfRegs GlobalReg (CmmNode e x) where foreignTargetRegs (ForeignTarget _ (ForeignConvention _ _ _ CmmNeverReturns)) = [] foreignTargetRegs _ = activeCallerSavesRegs +-- Note [Safe foreign calls clobber STG registers] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- +-- During stack layout phase every safe foreign call is expanded into a block +-- that contains unsafe foreign call (instead of safe foreign call) and ends +-- with a normal call (See Note [Foreign calls]). This means that we must +-- treat safe foreign call as if it was a normal call (because eventually it +-- will be). This is important if we try to run sinking pass before stack +-- layout phase. Consider this example of what might go wrong (this is cmm +-- code from stablename001 test). Here is code after common block elimination +-- (before stack layout): +-- +-- c1q6: +-- _s1pf::P64 = R1; +-- _c1q8::I64 = performMajorGC; +-- I64[(young<c1q9> + 8)] = c1q9; +-- foreign call "ccall" arg hints: [] result hints: [] (_c1q8::I64)(...) +-- returns to c1q9 args: ([]) ress: ([])ret_args: 8ret_off: 8; +-- c1q9: +-- I64[(young<c1qb> + 8)] = c1qb; +-- R1 = _s1pc::P64; +-- call stg_makeStableName#(R1) returns to c1qb, args: 8, res: 8, upd: 8; +-- +-- If we run sinking pass now (still before stack layout) we will get this: +-- +-- c1q6: +-- I64[(young<c1q9> + 8)] = c1q9; +-- foreign call "ccall" arg hints: [] result hints: [] performMajorGC(...) +-- returns to c1q9 args: ([]) ress: ([])ret_args: 8ret_off: 8; +-- c1q9: +-- I64[(young<c1qb> + 8)] = c1qb; +-- _s1pf::P64 = R1; <------ _s1pf sunk past safe foreign call +-- R1 = _s1pc::P64; +-- call stg_makeStableName#(R1) returns to c1qb, args: 8, res: 8, upd: 8; +-- +-- Notice that _s1pf was sunk past a foreign call. When we run stack layout +-- safe call to performMajorGC will be turned into: +-- +-- c1q6: +-- _s1pc::P64 = P64[Sp + 8]; +-- I64[Sp - 8] = c1q9; +-- Sp = Sp - 8; +-- I64[I64[CurrentTSO + 24] + 16] = Sp; +-- P64[CurrentNursery + 8] = Hp + 8; +-- (_u1qI::I64) = call "ccall" arg hints: [PtrHint,] +-- result hints: [PtrHint] suspendThread(BaseReg, 0); +-- call "ccall" arg hints: [] result hints: [] performMajorGC(); +-- (_u1qJ::I64) = call "ccall" arg hints: [PtrHint] +-- result hints: [PtrHint] resumeThread(_u1qI::I64); +-- BaseReg = _u1qJ::I64; +-- _u1qK::P64 = CurrentTSO; +-- _u1qL::P64 = I64[_u1qK::P64 + 24]; +-- Sp = I64[_u1qL::P64 + 16]; +-- SpLim = _u1qL::P64 + 192; +-- HpAlloc = 0; +-- Hp = I64[CurrentNursery + 8] - 8; +-- HpLim = I64[CurrentNursery] + (%MO_SS_Conv_W32_W64(I32[CurrentNursery + 48]) * 4096 - 1); +-- call (I64[Sp])() returns to c1q9, args: 8, res: 8, upd: 8; +-- c1q9: +-- I64[(young<c1qb> + 8)] = c1qb; +-- _s1pf::P64 = R1; <------ INCORRECT! +-- R1 = _s1pc::P64; +-- call stg_makeStableName#(R1) returns to c1qb, args: 8, res: 8, upd: 8; +-- +-- Notice that c1q6 now ends with a call. Sinking _s1pf::P64 = R1 past that +-- call is clearly incorrect. This is what would happen if we assumed that +-- safe foreign call has the same semantics as unsafe foreign call. To prevent +-- this we need to treat safe foreign call as if was normal call. ----------------------------------- -- mapping Expr in CmmNode diff --git a/compiler/cmm/CmmSink.hs b/compiler/cmm/CmmSink.hs index 12e1f662ba..41323ecad3 100644 --- a/compiler/cmm/CmmSink.hs +++ b/compiler/cmm/CmmSink.hs @@ -501,10 +501,10 @@ conflicts dflags (r, rhs, addr) node | SpMem{} <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True -- (4) assignments that read caller-saves GlobalRegs conflict with a - -- foreign call. See Note [foreign calls clobber GlobalRegs]. + -- foreign call. See Note [Unsafe foreign calls clobber caller-save registers] | CmmUnsafeForeignCall{} <- node, anyCallerSavesRegs dflags rhs = True - -- (5) foreign calls clobber heap: see Note [foreign calls clobber heap] + -- (5) foreign calls clobber heap: see Note [Foreign calls clobber heap] | CmmUnsafeForeignCall{} <- node, memConflicts addr AnyMem = True -- (6) native calls clobber any memory @@ -563,7 +563,8 @@ data AbsMem -- that was written in the same basic block. To take advantage of -- non-aliasing of heap memory we will have to be more clever. --- Note [foreign calls clobber] +-- Note [Foreign calls clobber heap] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- -- It is tempting to say that foreign calls clobber only -- non-heap/stack memory, but unfortunately we break this invariant in |