[project @ 2000-01-28 18:07:55 by sewardj]
authorsewardj <unknown>
Fri, 28 Jan 2000 18:07:56 +0000 (18:07 +0000)
committersewardj <unknown>
Fri, 28 Jan 2000 18:07:56 +0000 (18:07 +0000)
Modifications to make x86 register spilling to work reasonably.  It
should work ok most of the time, although there is still a remote
possibility that the allocator simply will be unable to complete
spilling, and will just give up.

-- Incrementally try with 0, 1, 2 and 3 spill regs, so as not to
   unduly restrict the supply of regs in code which doesn't need spilling.

-- Remove the use of %ecx for shift values, so it is always available
   as the first-choice spill temporary.  For code which doesn't do
   int division, make %edx and %eax available for spilling too.
   Shifts by a non-constant amount (very rare) are now done by
   a short test-and-jump sequence, so that %ecx is not tied up.

-- x86 FP: do sin, cos, tan in-line so we get the same answers as gcc.

-- Moved a little code around to remove recursive dependencies.

-- Fix a subtle bug in x86 regUsage, which could cause underestimation
   of live ranges.

ghc/compiler/nativeGen/AsmCodeGen.lhs
ghc/compiler/nativeGen/AsmRegAlloc.lhs
ghc/compiler/nativeGen/MachCode.lhs
ghc/compiler/nativeGen/MachMisc.hi-boot
ghc/compiler/nativeGen/MachMisc.hi-boot-5
ghc/compiler/nativeGen/MachMisc.lhs
ghc/compiler/nativeGen/MachRegs.lhs
ghc/compiler/nativeGen/PprMach.lhs
ghc/compiler/nativeGen/RegAllocInfo.lhs

index aa5d4e4..31c3825 100644 (file)
@@ -21,7 +21,7 @@ import AbsCSyn                ( AbstractC, MagicId )
 import AsmRegAlloc     ( runRegAllocate )
 import OrdList         ( OrdList )
 import PrimOp          ( commutableOp, PrimOp(..) )
 import AsmRegAlloc     ( runRegAllocate )
 import OrdList         ( OrdList )
 import PrimOp          ( commutableOp, PrimOp(..) )
-import RegAllocInfo    ( mkMRegsState, MRegsState )
+import RegAllocInfo    ( mkMRegsState, MRegsState, findReservedRegs )
 import Stix            ( StixTree(..), StixReg(..), 
                           pprStixTrees, CodeSegment(..) )
 import PrimRep         ( isFloatingRep, PrimRep(..) )
 import Stix            ( StixTree(..), StixReg(..), 
                           pprStixTrees, CodeSegment(..) )
 import PrimRep         ( isFloatingRep, PrimRep(..) )
@@ -130,7 +130,7 @@ might be needed.
 scheduleMachCode :: [InstrList] -> [[Instr]]
 
 scheduleMachCode
 scheduleMachCode :: [InstrList] -> [[Instr]]
 
 scheduleMachCode
-  = map (runRegAllocate freeRegsState reservedRegs)
+  = map (runRegAllocate freeRegsState findReservedRegs)
   where
     freeRegsState = mkMRegsState (extractMappedRegNos freeRegs)
 \end{code}
   where
     freeRegsState = mkMRegsState (extractMappedRegNos freeRegs)
 \end{code}
index 9a6fca0..2ddb991 100644 (file)
@@ -31,24 +31,38 @@ things the hard way.
 \begin{code}
 runRegAllocate
     :: MRegsState
 \begin{code}
 runRegAllocate
     :: MRegsState
-    -> [RegNo]
+    -> ([Instr] -> [[RegNo]])
     -> InstrList
     -> [Instr]
 
     -> InstrList
     -> [Instr]
 
-runRegAllocate regs reserve_regs instrs
+runRegAllocate regs find_reserve_regs instrs
   = case simpleAlloc of
   = case simpleAlloc of
-       Just x  -> x
-       Nothing -> hairyAlloc
+       Just simple -> simple
+       Nothing     -> tryHairy reserves
   where
   where
-    flatInstrs = flattenOrdList instrs
-    simpleAlloc = simpleRegAlloc regs [] emptyFM   flatInstrs
-    hairyAlloc = hairyRegAlloc  regs reserve_regs flatInstrs
+    tryHairy [] 
+       = error "nativeGen: register allocator: too difficult!  Try -fvia-C.\n"
+    tryHairy (resv:resvs)
+       = case hairyAlloc resv of
+            Just success -> success
+            Nothing      -> fooble resvs (tryHairy resvs)
+
+    fooble [] x = x
+    fooble (resvs:_) x = trace ("nativeGen: spilling with " 
+                                ++ show (length resvs - 2) ++ 
+                                " int temporaries") x
+
+    reserves         = find_reserve_regs flatInstrs
+    flatInstrs       = flattenOrdList instrs
+    simpleAlloc      = simpleRegAlloc regs [] emptyFM   flatInstrs
+    hairyAlloc resvd = hairyRegAlloc  regs resvd flatInstrs
 
 
-runHairyRegAllocate            -- use only hairy for i386!
+
+runHairyRegAllocate
     :: MRegsState
     -> [RegNo]
     -> InstrList
     :: MRegsState
     -> [RegNo]
     -> InstrList
-    -> [Instr]
+    -> Maybe [Instr]
 
 runHairyRegAllocate regs reserve_regs instrs
   = hairyRegAlloc regs reserve_regs flatInstrs
 
 runHairyRegAllocate regs reserve_regs instrs
   = hairyRegAlloc regs reserve_regs flatInstrs
@@ -83,7 +97,8 @@ simpleRegAlloc free live env (instr:instrs)
   where
     instr3 = patchRegs instr (lookup env2)
 
   where
     instr3 = patchRegs instr (lookup env2)
 
-    (srcs, dsts) = case regUsage instr of (RU s d) -> (regSetToList s, regSetToList d)
+    (srcs, dsts) = case regUsage instr of 
+                      (RU s d) -> (regSetToList s, regSetToList d)
 
     lookup env x = case lookupFM env x of Just y -> y; Nothing -> x
 
 
     lookup env x = case lookupFM env x of Just y -> y; Nothing -> x
 
@@ -121,40 +136,49 @@ Here is the ``clever'' bit. First go backward (i.e. left), looking for
 the last use of dynamic registers. Then go forward (i.e. right), filling
 registers with static placements.
 
 the last use of dynamic registers. Then go forward (i.e. right), filling
 registers with static placements.
 
+hairyRegAlloc takes reserve_regs as the regs to use as spill
+temporaries.  First it tries to allocate using all regs except
+reserve_regs.  If that fails, it inserts spill code and tries again to
+allocate regs, but this time with the spill temporaries available.
+Even this might not work if there are insufficient spill temporaries:
+in the worst case on x86, we'd need 3 of them, for insns like
+addl (reg1,reg2,4) reg3, since this insn uses all 3 regs as input.
+
 \begin{code}
 hairyRegAlloc
     :: MRegsState
     -> [RegNo]
     -> [Instr]
 \begin{code}
 hairyRegAlloc
     :: MRegsState
     -> [RegNo]
     -> [Instr]
-    -> [Instr]
+    -> Maybe [Instr]
 
 hairyRegAlloc regs reserve_regs instrs =
 
 hairyRegAlloc regs reserve_regs instrs =
-  case mapAccumB (doRegAlloc reserve_regs) (RH regs' 1 emptyFM) noFuture instrs of 
-   (RH _ mloc1 _, _, instrs')
-     | mloc1 == 1 -> instrs'
-     | otherwise  ->
-      let
-       instrs_patched' = patchMem instrs'
-       instrs_patched  = flattenOrdList instrs_patched'
-      in
-      case mapAccumB do_RegAlloc_Nil (RH regs'' mloc1 emptyFM) noFuture instrs_patched of
-        ((RH _ mloc2 _),_,instrs'') 
-           | mloc2 == mloc1 -> instrs'' 
-            | otherwise      -> instrs''
-              --pprPanic "runRegAllocate" (ppr mloc2 <+> ppr mloc1)
+  case mapAccumB (doRegAlloc reserve_regs) 
+                 (RH regs' 1 emptyFM) noFuture instrs of 
+     (RH _ mloc1 _, _, instrs')
+        -- succeeded w/out using reserves
+        | mloc1 == 1 -> Just instrs'
+        -- failed, and no reserves avail, so pointless to attempt spilling 
+        | null reserve_regs -> Nothing
+        -- failed, but we have reserves, so attempt to do spilling
+        | otherwise  
+        -> let instrs_patched' = patchMem instrs'
+               instrs_patched  = flattenOrdList instrs_patched'
+           in
+               case mapAccumB (doRegAlloc []) (RH regs'' mloc1 emptyFM) 
+                    noFuture instrs_patched of
+                  ((RH _ mloc2 _),_,instrs'') 
+                     -- successfully allocated the patched code
+                    | mloc2 == mloc1 -> Just instrs''
+                     -- no; we have to give up
+                     | otherwise      -> Nothing 
+                       -- instrs''
+                      -- pprPanic "runRegAllocate" (ppr mloc2 <+> ppr mloc1)
   where
     regs'  = regs `useMRegs` reserve_regs
     regs'' = mkMRegsState reserve_regs
 
   where
     regs'  = regs `useMRegs` reserve_regs
     regs'' = mkMRegsState reserve_regs
 
-do_RegAlloc_Nil = doRegAlloc [] -- out here to avoid CAF (sigh)
-do_RegAlloc_Nil
-    :: RegHistory MRegsState
-    -> RegFuture
-    -> Instr
-    -> (RegHistory MRegsState, RegFuture, Instr)
-
-noFuture :: RegFuture
-noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
+    noFuture :: RegFuture
+    noFuture = RF emptyRegSet (FL emptyRegSet emptyFM) emptyFM
 \end{code}
 
 Here we patch instructions that reference ``registers'' which are really in
 \end{code}
 
 Here we patch instructions that reference ``registers'' which are really in
@@ -225,7 +249,8 @@ getUsage (RF next_in_use future reg_conflicts) instr
               (RL in_use future') = regLiveness instr (RL next_in_use future)
               live_through = in_use `minusRegSet` dsts
               last_used = [ r | r <- regSetToList srcs,
               (RL in_use future') = regLiveness instr (RL next_in_use future)
               live_through = in_use `minusRegSet` dsts
               last_used = [ r | r <- regSetToList srcs,
-                            not (r `elementOfRegSet` (fstFL future) || r `elementOfRegSet` in_use)]
+                            not (r `elementOfRegSet` (fstFL future) 
+                                  || r `elementOfRegSet` in_use)]
 
               in_use' = srcs `unionRegSets` live_through
 
 
               in_use' = srcs `unionRegSets` live_through
 
@@ -245,7 +270,9 @@ getUsage (RF next_in_use future reg_conflicts) instr
                  Nothing        -> live_dynamics
                  Just conflicts -> conflicts `unionRegSets` live_dynamics
 
                  Nothing        -> live_dynamics
                  Just conflicts -> conflicts `unionRegSets` live_dynamics
 
-              live_dynamics = mkRegSet [ r | r@(UnmappedReg _ _) <- regSetToList live_through ]
+              live_dynamics 
+                  = mkRegSet [ r | r@(UnmappedReg _ _) 
+                                      <- regSetToList live_through ]
 
 doRegAlloc'
     :: [RegNo]
 
 doRegAlloc'
     :: [RegNo]
@@ -254,7 +281,8 @@ doRegAlloc'
     -> Instr
     -> (RegHistory MRegsState, Instr)
 
     -> Instr
     -> (RegHistory MRegsState, Instr)
 
-doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) instr =
+doRegAlloc' reserved (RH frs loc env) 
+                     (RI in_use srcs dsts lastu conflicts) instr =
 
     (RH frs'' loc' env'', patchRegs instr dynToStatic)
 
 
     (RH frs'' loc' env'', patchRegs instr dynToStatic)
 
@@ -264,14 +292,17 @@ doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) inst
       free :: [RegNo]
       free = extractMappedRegNos (map dynToStatic lastu)
 
       free :: [RegNo]
       free = extractMappedRegNos (map dynToStatic lastu)
 
-      -- (1) free registers that are used last as source operands in this instruction
-      frs_not_in_use = frs `useMRegs` (extractMappedRegNos (regSetToList in_use))
+      -- (1) free registers that are used last as 
+      --     source operands in this instruction
+      frs_not_in_use = frs `useMRegs` 
+                       (extractMappedRegNos (regSetToList in_use))
       frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
 
       -- (2) allocate new registers for the destination operands
       -- allocate registers for new dynamics
 
       frs' = (frs_not_in_use `freeMRegs` free) `useMRegs` reserved
 
       -- (2) allocate new registers for the destination operands
       -- allocate registers for new dynamics
 
-      new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts, r `not_elem` keysFM env ]
+      new_dynamix = [ r | r@(UnmappedReg _ _) <- regSetToList dsts, 
+                          r `not_elem` keysFM env ]
 
       (frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
 
 
       (frs'', loc', new) = foldr allocateNewRegs (frs', loc, []) new_dynamix
 
@@ -283,14 +314,16 @@ doRegAlloc' reserved (RH frs loc env) (RI in_use srcs dsts lastu conflicts) inst
       dynToStatic dyn@(UnmappedReg _ _) =
        case lookupFM env' dyn of
            Just r -> r
       dynToStatic dyn@(UnmappedReg _ _) =
        case lookupFM env' dyn of
            Just r -> r
-           Nothing -> trace "Lost register; possibly a floating point type error in a _ccall_?" dyn
+           Nothing -> trace ("Lost register; possibly a floating point"
+                              ++" type error in a _ccall_?") dyn
       dynToStatic other = other
 
       allocateNewRegs :: Reg 
                       -> (MRegsState, Int, [(Reg, Reg)]) 
                      -> (MRegsState, Int, [(Reg, Reg)])
 
       dynToStatic other = other
 
       allocateNewRegs :: Reg 
                       -> (MRegsState, Int, [(Reg, Reg)]) 
                      -> (MRegsState, Int, [(Reg, Reg)])
 
-      allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst) = (fs', mem', (d, f) : lst)
+      allocateNewRegs d@(UnmappedReg _ pk) (fs, mem, lst) 
+         = (fs', mem', (d, f) : lst)
        where 
         (fs', f, mem') = 
           case acceptable fs of
        where 
         (fs', f, mem') = 
           case acceptable fs of
index a4bd777..b38b24b 100644 (file)
@@ -34,7 +34,6 @@ import UniqSupply     ( returnUs, thenUs, mapUs, mapAndUnzipUs,
                          mapAccumLUs, UniqSM
                        )
 import Outputable
                          mapAccumLUs, UniqSM
                        )
 import Outputable
-import PprMach                 ( pprSize )
 \end{code}
 
 Code extractor for an entire stix tree---stix statement level.
 \end{code}
 
 Code extractor for an entire stix tree---stix statement level.
@@ -499,6 +498,15 @@ getRegister (StPrim primop [x]) -- unary PrimOps
       FloatSqrtOp  -> trivialUFCode FloatRep  (GSQRT F) x
       DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
 
       FloatSqrtOp  -> trivialUFCode FloatRep  (GSQRT F) x
       DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
 
+      FloatSinOp  -> trivialUFCode FloatRep  (GSIN F) x
+      DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
+
+      FloatCosOp  -> trivialUFCode FloatRep  (GCOS F) x
+      DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
+
+      FloatTanOp  -> trivialUFCode FloatRep  (GTAN F) x
+      DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
+
       Double2FloatOp -> trivialUFCode FloatRep  GDTOF x
       Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
 
       Double2FloatOp -> trivialUFCode FloatRep  GDTOF x
       Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
 
@@ -523,9 +531,9 @@ getRegister (StPrim primop [x]) -- unary PrimOps
              FloatExpOp    -> (True,  SLIT("exp"))
              FloatLogOp    -> (True,  SLIT("log"))
 
              FloatExpOp    -> (True,  SLIT("exp"))
              FloatLogOp    -> (True,  SLIT("log"))
 
-             FloatSinOp    -> (True,  SLIT("sin"))
-             FloatCosOp    -> (True,  SLIT("cos"))
-             FloatTanOp    -> (True,  SLIT("tan"))
+             --FloatSinOp    -> (True,  SLIT("sin"))
+             --FloatCosOp    -> (True,  SLIT("cos"))
+             --FloatTanOp    -> (True,  SLIT("tan"))
 
              FloatAsinOp   -> (True,  SLIT("asin"))
              FloatAcosOp   -> (True,  SLIT("acos"))
 
              FloatAsinOp   -> (True,  SLIT("asin"))
              FloatAcosOp   -> (True,  SLIT("acos"))
@@ -538,9 +546,9 @@ getRegister (StPrim primop [x]) -- unary PrimOps
              DoubleExpOp   -> (False, SLIT("exp"))
              DoubleLogOp   -> (False, SLIT("log"))
 
              DoubleExpOp   -> (False, SLIT("exp"))
              DoubleLogOp   -> (False, SLIT("log"))
 
-             DoubleSinOp   -> (False, SLIT("sin"))
-             DoubleCosOp   -> (False, SLIT("cos"))
-             DoubleTanOp   -> (False, SLIT("tan"))
+             --DoubleSinOp   -> (False, SLIT("sin"))
+             --DoubleCosOp   -> (False, SLIT("cos"))
+             --DoubleTanOp   -> (False, SLIT("tan"))
 
              DoubleAsinOp  -> (False, SLIT("asin"))
              DoubleAcosOp  -> (False, SLIT("acos"))
 
              DoubleAsinOp  -> (False, SLIT("asin"))
              DoubleAcosOp  -> (False, SLIT("acos"))
@@ -674,6 +682,65 @@ getRegister (StPrim primop [x, y]) -- dyadic PrimOps
 
       {- Case2: shift length is complex (non-immediate) -}
     shift_code instr x y{-amount-}
 
       {- Case2: shift length is complex (non-immediate) -}
     shift_code instr x y{-amount-}
+     = getRegister x   `thenUs` \ register1 ->
+       getRegister y   `thenUs` \ register2 ->
+       getUniqLabelNCG `thenUs` \ lbl_test3 ->
+       getUniqLabelNCG `thenUs` \ lbl_test2 ->
+       getUniqLabelNCG `thenUs` \ lbl_test1 ->
+       getUniqLabelNCG `thenUs` \ lbl_test0 ->
+       getUniqLabelNCG `thenUs` \ lbl_after ->
+       getNewRegNCG IntRep   `thenUs` \ tmp ->
+       let code__2 dst
+              = let src_val  = registerName register1 dst
+                    code_val = registerCode register1 dst
+                    src_amt  = registerName register2 tmp
+                    code_amt = registerCode register2 tmp
+                    r_dst    = OpReg dst
+                    r_tmp    = OpReg tmp
+                in
+                    code_val .
+                    code_amt .
+                    mkSeqInstrs [
+                       COMMENT (_PK_ "begin shift sequence"),
+                       MOV L (OpReg src_val) r_dst,
+                       MOV L (OpReg src_amt) r_tmp,
+
+                       BT L (ImmInt 4) r_tmp,
+                       JXX GEU lbl_test3,
+                       instr (OpImm (ImmInt 16)) r_dst,
+
+                       LABEL lbl_test3,
+                       BT L (ImmInt 3) r_tmp,
+                       JXX GEU lbl_test2,
+                       instr (OpImm (ImmInt 8)) r_dst,
+
+                       LABEL lbl_test2,
+                       BT L (ImmInt 2) r_tmp,
+                       JXX GEU lbl_test1,
+                       instr (OpImm (ImmInt 4)) r_dst,
+
+                       LABEL lbl_test1,
+                       BT L (ImmInt 1) r_tmp,
+                       JXX GEU lbl_test0,
+                       instr (OpImm (ImmInt 2)) r_dst,
+
+                       LABEL lbl_test0,
+                       BT L (ImmInt 0) r_tmp,
+                       JXX GEU lbl_after,
+                       instr (OpImm (ImmInt 1)) r_dst,
+                       LABEL lbl_after,
+                                           
+                       COMMENT (_PK_ "end shift sequence")
+                    ]
+       in
+       returnUs (Any IntRep code__2)
+
+{-
+     -- since ECX is always used as a spill temporary, we can't
+     -- use it here to do non-immediate shifts.  No big deal --
+     -- they are only very rare, and we can give an equivalent
+     -- insn sequence which doesn't use ECX.
+     -- DO NOT USE THIS CODE, SINCE IT IS INCOMPATIBLE WITH THE SPILLER
      = getRegister y           `thenUs` \ register1 ->  
        getRegister x           `thenUs` \ register2 ->
        let
      = getRegister y           `thenUs` \ register1 ->  
        getRegister x           `thenUs` \ register2 ->
        let
@@ -699,6 +766,7 @@ getRegister (StPrim primop [x, y]) -- dyadic PrimOps
                      mkSeqInstr (instr (OpReg ecx) (OpReg eax))
        in
        returnUs (Fixed IntRep eax code__2)
                      mkSeqInstr (instr (OpReg ecx) (OpReg eax))
        in
        returnUs (Fixed IntRep eax code__2)
+-}
 
     --------------------
     add_code :: Size -> StixTree -> StixTree -> UniqSM Register
 
     --------------------
     add_code :: Size -> StixTree -> StixTree -> UniqSM Register
@@ -2441,10 +2509,10 @@ condIntReg cond x y
        code = condCode condition
        cond = condName condition
        -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
        code = condCode condition
        cond = condName condition
        -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
-       code__2 dst = code . mkSeqInstrs [
+       code__2 dst = code . mkSeqInstrs [COMMENT (_PK_ "aaaaa"),
            SETCC cond (OpReg tmp),
            AND L (OpImm (ImmInt 1)) (OpReg tmp),
            SETCC cond (OpReg tmp),
            AND L (OpImm (ImmInt 1)) (OpReg tmp),
-           MOV L (OpReg tmp) (OpReg dst)]
+           MOV L (OpReg tmp) (OpReg dst) ,COMMENT (_PK_ "bbbbb")]
     in
     returnUs (Any IntRep code__2)
 
     in
     returnUs (Any IntRep code__2)
 
index 91f6330..242c93a 100644 (file)
@@ -1,7 +1,8 @@
 _interface_ MachMisc 1
 _exports_
 _interface_ MachMisc 1
 _exports_
-MachMisc fixedHdrSize fmtAsmLbl underscorePrefix;
+MachMisc Instr fixedHdrSize fmtAsmLbl underscorePrefix;
 _declarations_
 1 fixedHdrSize _:_ PrelBase.Int ;;
 2 fmtAsmLbl _:_ PrelBase.String -> PrelBase.String ;;
 1 underscorePrefix _:_ PrelBase.Bool ;;
 _declarations_
 1 fixedHdrSize _:_ PrelBase.Int ;;
 2 fmtAsmLbl _:_ PrelBase.String -> PrelBase.String ;;
 1 underscorePrefix _:_ PrelBase.Bool ;;
+1 data Instr;
\ No newline at end of file
index 6fb5f9e..8c2a6f2 100644 (file)
@@ -1,5 +1,6 @@
 __interface MachMisc 1 0 where
 __interface MachMisc 1 0 where
-__export MachMisc fixedHdrSize fmtAsmLbl underscorePrefix;
+__export MachMisc Instr fixedHdrSize fmtAsmLbl underscorePrefix;
 1 fixedHdrSize :: PrelBase.Int ;
 2 fmtAsmLbl :: PrelBase.String -> PrelBase.String ;
 1 underscorePrefix :: PrelBase.Bool ;
 1 fixedHdrSize :: PrelBase.Int ;
 2 fmtAsmLbl :: PrelBase.String -> PrelBase.String ;
 1 underscorePrefix :: PrelBase.Bool ;
+1 data Instr ;
index d31af20..893bf87 100644 (file)
@@ -507,6 +507,7 @@ current translation.
              | SAR           Size Operand Operand -- 1st operand must be an Imm or CL
              | SHR           Size Operand Operand -- 1st operand must be an Imm or CL
              | NOP
              | SAR           Size Operand Operand -- 1st operand must be an Imm or CL
              | SHR           Size Operand Operand -- 1st operand must be an Imm or CL
              | NOP
+              | BT            Size Imm Operand
 
 -- Float Arithmetic. -- ToDo for 386
 
 
 -- Float Arithmetic. -- ToDo for 386
 
@@ -539,6 +540,9 @@ current translation.
              | GABS          Size Reg Reg -- src, dst
              | GNEG          Size Reg Reg -- src, dst
              | GSQRT         Size Reg Reg -- src, dst
              | GABS          Size Reg Reg -- src, dst
              | GNEG          Size Reg Reg -- src, dst
              | GSQRT         Size Reg Reg -- src, dst
+             | GSIN          Size Reg Reg -- src, dst
+             | GCOS          Size Reg Reg -- src, dst
+             | GTAN          Size Reg Reg -- src, dst
 
               | GFREE         -- do ffree on all x86 regs; an ugly hack
 -- Comparison
 
               | GFREE         -- do ffree on all x86 regs; an ugly hack
 -- Comparison
@@ -598,6 +602,7 @@ is_G_instr instr
        GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
        GCMP _ _ _ -> True; GABS _ _ _ -> True
        GNEG _ _ _ -> True; GSQRT _ _ _ -> True
        GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True
        GCMP _ _ _ -> True; GABS _ _ _ -> True
        GNEG _ _ _ -> True; GSQRT _ _ _ -> True
+        GSIN _ _ _ -> True; GCOS _ _ _ -> True; GTAN _ _ _ -> True;
         GFREE -> panic "is_G_instr: GFREE (!)"
         other -> False
 
         GFREE -> panic "is_G_instr: GFREE (!)"
         other -> False
 
index f32024f..446e7dd 100644 (file)
@@ -26,13 +26,13 @@ module MachRegs (
        callClobberedRegs,
        callerSaves,
        extractMappedRegNos,
        callClobberedRegs,
        callerSaves,
        extractMappedRegNos,
+        mappedRegNo,
        freeMappedRegs,
        freeReg, freeRegs,
        getNewRegNCG,
        magicIdRegMaybe,
        mkReg,
        realReg,
        freeMappedRegs,
        freeReg, freeRegs,
        getNewRegNCG,
        magicIdRegMaybe,
        mkReg,
        realReg,
-       reservedRegs,
        saveLoc,
        spRel,
        stgReg,
        saveLoc,
        spRel,
        stgReg,
@@ -336,6 +336,10 @@ extractMappedRegNos regs
   where
     ex (MappedReg i) acc = IBOX(i) : acc  -- we'll take it
     ex _            acc = acc            -- leave it out
   where
     ex (MappedReg i) acc = IBOX(i) : acc  -- we'll take it
     ex _            acc = acc            -- leave it out
+
+mappedRegNo :: Reg -> RegNo
+mappedRegNo (MappedReg i) = IBOX(i)
+mappedRegNo _             = pprPanic "mappedRegNo" empty
 \end{code}
 
 ** Machine-specific Reg stuff: **
 \end{code}
 
 ** Machine-specific Reg stuff: **
@@ -733,40 +737,7 @@ magicIdRegMaybe HpLim                      = Just (FixedReg ILIT(REG_HpLim))
 magicIdRegMaybe _                      = Nothing
 \end{code}
 
 magicIdRegMaybe _                      = Nothing
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{Free, reserved, call-clobbered, and argument registers}
-%*                                                                     *
-%************************************************************************
-
-@freeRegs@ is the list of registers we can use in register allocation.
-@freeReg@ (below) says if a particular register is free.
-
-With a per-instruction clobber list, we might be able to get some of
-these back, but it's probably not worth the hassle.
-
-@callClobberedRegs@ ... the obvious.
-
-@argRegs@: assuming a call with N arguments, what registers will be
-used to hold arguments?  (NB: it doesn't know whether the arguments
-are integer or floating-point...)
-
 \begin{code}
 \begin{code}
-reservedRegs :: [RegNo]
-reservedRegs
-#if alpha_TARGET_ARCH
-  = [NCG_Reserved_I1, NCG_Reserved_I2,
-     NCG_Reserved_F1, NCG_Reserved_F2]
-#endif
-#if i386_TARGET_ARCH
-  = [{-certainly cannot afford any!-}]
-#endif
-#if sparc_TARGET_ARCH
-  = [NCG_Reserved_I1, NCG_Reserved_I2,
-     NCG_Reserved_F1, NCG_Reserved_F2,
-     NCG_Reserved_D1, NCG_Reserved_D2]
-#endif
-
 -------------------------------
 freeRegs :: [Reg]
 freeRegs
 -------------------------------
 freeRegs :: [Reg]
 freeRegs
index e35e22c..6232f37 100644 (file)
@@ -941,7 +941,7 @@ pprInstr v@(MOV size s@(OpReg src) d@(OpReg dst)) -- hack
 #ifdef DEBUG
     (<>) (ptext SLIT("# warning: ")) (pprSizeOpOp SLIT("mov") size s d)
 #else
 #ifdef DEBUG
     (<>) (ptext SLIT("# warning: ")) (pprSizeOpOp SLIT("mov") size s d)
 #else
-    (ptext SLIT(""))
+    empty
 #endif
 pprInstr (MOV size src dst)
   = pprSizeOpOp SLIT("mov") size src dst
 #endif
 pprInstr (MOV size src dst)
   = pprSizeOpOp SLIT("mov") size src dst
@@ -977,9 +977,9 @@ pprInstr (XOR size src dst) = pprSizeOpOp SLIT("xor")  size src dst
 pprInstr (NOT size op) = pprSizeOp SLIT("not") size op
 pprInstr (NEGI size op) = pprSizeOp SLIT("neg") size op
 
 pprInstr (NOT size op) = pprSizeOp SLIT("not") size op
 pprInstr (NEGI size op) = pprSizeOp SLIT("neg") size op
 
-pprInstr (SHL size imm dst) = pprSizeByteOpOp SLIT("shl")  size imm dst
-pprInstr (SAR size imm dst) = pprSizeByteOpOp SLIT("sar")  size imm dst
-pprInstr (SHR size imm dst) = pprSizeByteOpOp SLIT("shr")  size imm dst
+pprInstr (SHL size imm dst) = {-pprSizeByteOpOp-} pprSizeOpOp SLIT("shl")  size imm dst
+pprInstr (SAR size imm dst) = {-pprSizeByteOpOp-} pprSizeOpOp SLIT("sar")  size imm dst
+pprInstr (SHR size imm dst) = {-pprSizeByteOpOp-} pprSizeOpOp SLIT("shr")  size imm dst
 
 pprInstr (CMP size src dst) = pprSizeOpOp SLIT("cmp")  size src dst
 pprInstr (TEST size src dst) = pprSizeOpOp SLIT("test")  size src dst
 
 pprInstr (CMP size src dst) = pprSizeOpOp SLIT("cmp")  size src dst
 pprInstr (TEST size src dst) = pprSizeOpOp SLIT("test")  size src dst
@@ -989,6 +989,7 @@ pprInstr PUSHA = ptext SLIT("\tpushal")
 pprInstr POPA = ptext SLIT("\tpopal")
 
 pprInstr (NOP) = ptext SLIT("\tnop")
 pprInstr POPA = ptext SLIT("\tpopal")
 
 pprInstr (NOP) = ptext SLIT("\tnop")
+pprInstr (BT size imm src) = pprSizeImmOp SLIT("bt") size imm src
 pprInstr (CLTD) = ptext SLIT("\tcltd")
 
 pprInstr (SETCC cond op) = pprCondInstr SLIT("set") cond (pprOperand B op)
 pprInstr (CLTD) = ptext SLIT("\tcltd")
 
 pprInstr (SETCC cond op) = pprCondInstr SLIT("set") cond (pprOperand B op)
@@ -1047,6 +1048,15 @@ pprInstr g@(GNEG sz src dst)
    = pprG g (hcat [gtab, gpush src 0, text " ; fchs ; ", gpop dst 1])
 pprInstr g@(GSQRT sz src dst)
    = pprG g (hcat [gtab, gpush src 0, text " ; fsqrt ; ", gpop dst 1])
    = pprG g (hcat [gtab, gpush src 0, text " ; fchs ; ", gpop dst 1])
 pprInstr g@(GSQRT sz src dst)
    = pprG g (hcat [gtab, gpush src 0, text " ; fsqrt ; ", gpop dst 1])
+pprInstr g@(GSIN sz src dst)
+   = pprG g (hcat [gtab, gpush src 0, text " ; fsin ; ", gpop dst 1])
+pprInstr g@(GCOS sz src dst)
+   = pprG g (hcat [gtab, gpush src 0, text " ; fcos ; ", gpop dst 1])
+
+pprInstr g@(GTAN sz src dst)
+   = pprG g (hcat [gtab, text "ffree %st(6) ; ",
+                   gpush src 0, text " ; fptan ; ", 
+                   text " fstp %st(0) ; ", gpop dst 1])
 
 pprInstr g@(GADD sz src1 src2 dst)
    = pprG g (hcat [gtab, gpush src1 0, 
 
 pprInstr g@(GADD sz src1 src2 dst)
    = pprG g (hcat [gtab, gpush src1 0, 
@@ -1106,6 +1116,9 @@ pprGInstr (GCMP sz src dst) = pprSizeRegReg SLIT("gcmp") sz src dst
 pprGInstr (GABS sz src dst) = pprSizeRegReg SLIT("gabs") sz src dst
 pprGInstr (GNEG sz src dst) = pprSizeRegReg SLIT("gneg") sz src dst
 pprGInstr (GSQRT sz src dst) = pprSizeRegReg SLIT("gsqrt") sz src dst
 pprGInstr (GABS sz src dst) = pprSizeRegReg SLIT("gabs") sz src dst
 pprGInstr (GNEG sz src dst) = pprSizeRegReg SLIT("gneg") sz src dst
 pprGInstr (GSQRT sz src dst) = pprSizeRegReg SLIT("gsqrt") sz src dst
+pprGInstr (GSIN sz src dst) = pprSizeRegReg SLIT("gsin") sz src dst
+pprGInstr (GCOS sz src dst) = pprSizeRegReg SLIT("gcos") sz src dst
+pprGInstr (GTAN sz src dst) = pprSizeRegReg SLIT("gtan") sz src dst
 
 pprGInstr (GADD sz src1 src2 dst) = pprSizeRegRegReg SLIT("gadd") sz src1 src2 dst
 pprGInstr (GSUB sz src1 src2 dst) = pprSizeRegRegReg SLIT("gsub") sz src1 src2 dst
 
 pprGInstr (GADD sz src1 src2 dst) = pprSizeRegRegReg SLIT("gadd") sz src1 src2 dst
 pprGInstr (GSUB sz src1 src2 dst) = pprSizeRegRegReg SLIT("gsub") sz src1 src2 dst
@@ -1124,6 +1137,19 @@ pprOperand s (OpReg r) = pprReg s r
 pprOperand s (OpImm i) = pprDollImm i
 pprOperand s (OpAddr ea) = pprAddr ea
 
 pprOperand s (OpImm i) = pprDollImm i
 pprOperand s (OpAddr ea) = pprAddr ea
 
+pprSizeImmOp :: FAST_STRING -> Size -> Imm -> Operand -> SDoc
+pprSizeImmOp name size imm op1
+  = hcat [
+        char '\t',
+       ptext name,
+       pprSize size,
+       space,
+       char '$',
+       pprImm imm,
+       comma,
+       pprOperand size op1
+    ]
+       
 pprSizeOp :: FAST_STRING -> Size -> Operand -> SDoc
 pprSizeOp name size op1
   = hcat [
 pprSizeOp :: FAST_STRING -> Size -> Operand -> SDoc
 pprSizeOp name size op1
   = hcat [
index eab566c..c1bd50c 100644 (file)
@@ -35,6 +35,7 @@ module RegAllocInfo (
        patchRegs,
        regLiveness,
        spillReg,
        patchRegs,
        regLiveness,
        spillReg,
+       IF_ARCH_i386(findReservedRegs COMMA,)
 
        RegSet,
        elementOfRegSet,
 
        RegSet,
        elementOfRegSet,
@@ -64,7 +65,6 @@ import OrdList                ( mkUnitList )
 import PrimRep         ( PrimRep(..) )
 import UniqSet         -- quite a bit of it
 import Outputable
 import PrimRep         ( PrimRep(..) )
 import UniqSet         -- quite a bit of it
 import Outputable
-import PprMach         ( pprInstr )
 \end{code}
 
 %************************************************************************
 \end{code}
 
 %************************************************************************
@@ -354,22 +354,24 @@ regUsage instr = case instr of
 #if i386_TARGET_ARCH
 
 regUsage instr = case instr of
 #if i386_TARGET_ARCH
 
 regUsage instr = case instr of
-    MOV  sz src dst    -> usage2 src dst
-    MOVZxL sz src dst  -> usage2 src dst
-    MOVSxL sz src dst  -> usage2 src dst
-    LEA  sz src dst    -> usage2 src dst
-    ADD  sz src dst    -> usage2 src dst
-    SUB  sz src dst    -> usage2 src dst
-    IMUL sz src dst    -> usage2 src dst
+    MOV  sz src dst    -> usage2  src dst
+    MOVZxL sz src dst  -> usage2  src dst
+    MOVSxL sz src dst  -> usage2  src dst
+    LEA  sz src dst    -> usage2  src dst
+    ADD  sz src dst    -> usage2s src dst
+    SUB  sz src dst    -> usage2s src dst
+    IMUL sz src dst    -> usage2s src dst
     IDIV sz src                -> usage (eax:edx:opToReg src) [eax,edx]
     IDIV sz src                -> usage (eax:edx:opToReg src) [eax,edx]
-    AND  sz src dst    -> usage2 src dst
-    OR   sz src dst    -> usage2 src dst
-    XOR  sz src dst    -> usage2 src dst
+    AND  sz src dst    -> usage2s src dst
+    OR   sz src dst    -> usage2s src dst
+    XOR  sz src dst    -> usage2s src dst
     NOT  sz op         -> usage1 op
     NEGI sz op         -> usage1 op
     NOT  sz op         -> usage1 op
     NEGI sz op         -> usage1 op
-    SHL  sz dst len    -> usage2 dst len -- len is either an Imm or ecx.
-    SAR  sz dst len    -> usage2 dst len -- len is either an Imm or ecx.
-    SHR  sz len dst    -> usage2 dst len -- len is either an Imm or ecx.
+    SHL  sz len dst    -> usage2s len dst -- len is either an Imm or ecx.
+    SAR  sz len dst    -> usage2s len dst -- len is either an Imm or ecx.
+    SHR  sz len dst    -> usage2s len dst -- len is either an Imm or ecx.
+    BT   sz imm src    -> usage (opToReg src) []
+
     PUSH sz op         -> usage (opToReg op) []
     POP  sz op         -> usage [] (opToReg op)
     TEST sz src dst    -> usage (opToReg src ++ opToReg dst) []
     PUSH sz op         -> usage (opToReg op) []
     POP  sz op         -> usage [] (opToReg op)
     TEST sz src dst    -> usage (opToReg src ++ opToReg dst) []
@@ -403,21 +405,35 @@ regUsage instr = case instr of
     GABS sz src dst    -> usage [src] [dst]
     GNEG sz src dst    -> usage [src] [dst]
     GSQRT sz src dst   -> usage [src] [dst]
     GABS sz src dst    -> usage [src] [dst]
     GNEG sz src dst    -> usage [src] [dst]
     GSQRT sz src dst   -> usage [src] [dst]
+    GSIN sz src dst    -> usage [src] [dst]
+    GCOS sz src dst    -> usage [src] [dst]
+    GTAN sz src dst    -> usage [src] [dst]
 
     COMMENT _          -> noUsage
     SEGMENT _          -> noUsage
     LABEL _            -> noUsage
     ASCII _ _          -> noUsage
     DATA _ _           -> noUsage
 
     COMMENT _          -> noUsage
     SEGMENT _          -> noUsage
     LABEL _            -> noUsage
     ASCII _ _          -> noUsage
     DATA _ _           -> noUsage
-    _                  -> error ("regUsage(x86): " ++ showSDoc (pprInstr instr))
+    _                  -> pprPanic "regUsage(x86) " empty
+
  where
  where
+    -- 2 operand form in which the second operand is purely a destination
     usage2 :: Operand -> Operand -> RegUsage
     usage2 op (OpReg reg) = usage (opToReg op) [reg]
     usage2 op (OpAddr ea) = usage (opToReg op ++ addrToRegs ea) []
     usage2 op (OpImm imm) = usage (opToReg op) []
     usage2 :: Operand -> Operand -> RegUsage
     usage2 op (OpReg reg) = usage (opToReg op) [reg]
     usage2 op (OpAddr ea) = usage (opToReg op ++ addrToRegs ea) []
     usage2 op (OpImm imm) = usage (opToReg op) []
+
+    -- 2 operand form in which the second operand is also an input
+    usage2s :: Operand -> Operand -> RegUsage
+    usage2s op (OpReg reg) = usage (opToReg op ++ [reg]) [reg]
+    usage2s op (OpAddr ea) = usage (opToReg op ++ addrToRegs ea) []
+    usage2s op (OpImm imm) = usage (opToReg op) []
+
+    -- 1 operand form in which the operand is both used and written
     usage1 :: Operand -> RegUsage
     usage1 (OpReg reg)    = usage [reg] [reg]
     usage1 (OpAddr ea)    = usage (addrToRegs ea) []
     usage1 :: Operand -> RegUsage
     usage1 (OpReg reg)    = usage [reg] [reg]
     usage1 (OpAddr ea)    = usage (addrToRegs ea) []
+
     allFPRegs = [fake0,fake1,fake2,fake3,fake4,fake5]
 
     --callClobberedRegs = [ eax, ecx, edx ] -- according to gcc, anyway.
     allFPRegs = [fake0,fake1,fake2,fake3,fake4,fake5]
 
     --callClobberedRegs = [ eax, ecx, edx ] -- according to gcc, anyway.
@@ -442,6 +458,14 @@ regUsage instr = case instr of
     interesting (FixedReg _) = False
     interesting _ = True
 
     interesting (FixedReg _) = False
     interesting _ = True
 
+
+-- Allow the spiller to decide whether or not it can use 
+-- %eax and %edx as spill temporaries.
+hasFixedEAXorEDX instr = case instr of
+    IDIV _ _ -> True
+    CLTD     -> True
+    other    -> False
+
 #endif {- i386_TARGET_ARCH -}
 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 #if sparc_TARGET_ARCH
 #endif {- i386_TARGET_ARCH -}
 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 #if sparc_TARGET_ARCH
@@ -495,6 +519,71 @@ regUsage instr = case instr of
 #endif {- sparc_TARGET_ARCH -}
 \end{code}
 
 #endif {- sparc_TARGET_ARCH -}
 \end{code}
 
+
+%************************************************************************
+%*                                                                     *
+\subsection{Free, reserved, call-clobbered, and argument registers}
+%*                                                                     *
+%************************************************************************
+
+@freeRegs@ is the list of registers we can use in register allocation.
+@freeReg@ (below) says if a particular register is free.
+
+With a per-instruction clobber list, we might be able to get some of
+these back, but it's probably not worth the hassle.
+
+@callClobberedRegs@ ... the obvious.
+
+@argRegs@: assuming a call with N arguments, what registers will be
+used to hold arguments?  (NB: it doesn't know whether the arguments
+are integer or floating-point...)
+
+findReservedRegs tells us which regs can be used as spill temporaries.
+The list of instructions for which we are attempting allocation is
+supplied.  This is so that we can (at least for x86) examine it to
+discover which registers are being used in a fixed way -- for example,
+%eax and %edx are used by integer division, so they can't be used as
+spill temporaries.  However, most instruction lists don't do integer
+division, so we don't want to rule them out altogether.
+
+findReservedRegs returns not a list of spill temporaries, but a list
+of list of them.  This is so that the allocator can attempt allocating
+with at first no spill temps, then if that fails, increasing numbers.
+For x86 it is important that we minimise the number of regs reserved
+as spill temporaries, since there are so few.  For Alpha and Sparc
+this isn't a concern; we just ignore the supplied code list and return
+a singleton list which we know will satisfy all spill demands.
+
+\begin{code}
+findReservedRegs :: [Instr] -> [[RegNo]]
+findReservedRegs instrs
+#if alpha_TARGET_ARCH
+  = [[NCG_Reserved_I1, NCG_Reserved_I2,
+      NCG_Reserved_F1, NCG_Reserved_F2]]
+#endif
+#if sparc_TARGET_ARCH
+  = [[NCG_Reserved_I1, NCG_Reserved_I2,
+      NCG_Reserved_F1, NCG_Reserved_F2,
+      NCG_Reserved_D1, NCG_Reserved_D2]]
+#endif
+#if i386_TARGET_ARCH
+    -- Sigh.  This is where it gets complicated.
+  = -- first of all, try without any at all.
+    map (map mappedRegNo) (
+    [ [],
+    -- if that doesn't work, try one integer reg (which might fail)
+    -- and two float regs (which will always fix any float insns)
+      [ecx, fake4,fake5]
+    ]
+    -- dire straits (but still correct): see if we can bag %eax and %edx
+    ++ if   any hasFixedEAXorEDX instrs
+       then []  -- bummer
+       else [ [ecx,edx,fake4,fake5],
+              [ecx,edx,eax,fake4,fake5] ]
+    )
+#endif
+\end{code}
+
 %************************************************************************
 %*                                                                     *
 \subsection{@RegLiveness@ type; @regLiveness@ function}
 %************************************************************************
 %*                                                                     *
 \subsection{@RegLiveness@ type; @regLiveness@ function}
@@ -655,6 +744,7 @@ patchRegs instr env = case instr of
     SHL  sz imm dst    -> patch2 (SHL  sz) imm dst
     SAR  sz imm dst    -> patch2 (SAR  sz) imm dst
     SHR  sz imm dst    -> patch2 (SHR  sz) imm dst
     SHL  sz imm dst    -> patch2 (SHL  sz) imm dst
     SAR  sz imm dst    -> patch2 (SAR  sz) imm dst
     SHR  sz imm dst    -> patch2 (SHR  sz) imm dst
+    BT   sz imm src     -> patch1 (BT sz imm) src
     TEST sz src dst    -> patch2 (TEST sz) src dst
     CMP  sz src dst    -> patch2 (CMP  sz) src dst
     PUSH sz op         -> patch1 (PUSH sz) op
     TEST sz src dst    -> patch2 (TEST sz) src dst
     CMP  sz src dst    -> patch2 (CMP  sz) src dst
     PUSH sz op         -> patch1 (PUSH sz) op
@@ -684,6 +774,9 @@ patchRegs instr env = case instr of
     GABS sz src dst    -> GABS sz (env src) (env dst)
     GNEG sz src dst    -> GNEG sz (env src) (env dst)
     GSQRT sz src dst   -> GSQRT sz (env src) (env dst)
     GABS sz src dst    -> GABS sz (env src) (env dst)
     GNEG sz src dst    -> GNEG sz (env src) (env dst)
     GSQRT sz src dst   -> GSQRT sz (env src) (env dst)
+    GSIN sz src dst    -> GSIN sz (env src) (env dst)
+    GCOS sz src dst    -> GCOS sz (env src) (env dst)
+    GTAN sz src dst    -> GTAN sz (env src) (env dst)
 
     COMMENT _          -> instr
     SEGMENT _          -> instr
 
     COMMENT _          -> instr
     SEGMENT _          -> instr
@@ -693,7 +786,8 @@ patchRegs instr env = case instr of
     JXX _ _            -> instr
     CALL _             -> instr
     CLTD               -> instr
     JXX _ _            -> instr
     CALL _             -> instr
     CLTD               -> instr
-    _                  -> error ("patchInstr: " ++ showSDoc (pprInstr instr)) --instr
+    _                  -> pprPanic "patchInstr(x86)" empty
+
   where
     patch1 insn op      = insn (patchOp op)
     patch2 insn src dst = insn (patchOp src) (patchOp dst)
   where
     patch1 insn op      = insn (patchOp op)
     patch2 insn src dst = insn (patchOp src) (patchOp dst)
@@ -761,7 +855,7 @@ patchRegs instr env = case instr of
 
 Spill to memory, and load it back...
 
 
 Spill to memory, and load it back...
 
-JRS, 000122: on x86, don't spill directly below the stack pointer, since 
+JRS, 000122: on x86, don't spill directly above the stack pointer, since 
 some insn sequences (int <-> conversions) use this as a temp location.
 Leave 16 bytes of slop.
 
 some insn sequences (int <-> conversions) use this as a temp location.
 Leave 16 bytes of slop.
 
@@ -769,36 +863,44 @@ Leave 16 bytes of slop.
 spillReg, loadReg :: Reg -> Reg -> InstrList
 
 spillReg dyn (MemoryReg i pk)
 spillReg, loadReg :: Reg -> Reg -> InstrList
 
 spillReg dyn (MemoryReg i pk)
-  | i >= 0  -- JRS paranoia
-  = let
-       sz = primRepToSize pk
+  | i >= 0 -- JRS paranoia
+  = let        sz = primRepToSize pk
     in
     mkUnitList (
        {-Alpha: spill below the stack pointer (?)-}
         IF_ARCH_alpha( ST sz dyn (spRel i)
 
        {-I386: spill above stack pointer leaving 2 words/spill-}
     in
     mkUnitList (
        {-Alpha: spill below the stack pointer (?)-}
         IF_ARCH_alpha( ST sz dyn (spRel i)
 
        {-I386: spill above stack pointer leaving 2 words/spill-}
-       ,IF_ARCH_i386 ( if pk == FloatRep || pk == DoubleRep
-                        then GST DF dyn (spRel (16 + 2 * i))
-                        else MOV sz (OpReg dyn) (OpAddr (spRel (16 + 2 * i)))
+       ,IF_ARCH_i386 ( let loc | i < 60    = 4 + 2 * i
+                                | otherwise = -2000 - 2 * i
+                        in
+                        if pk == FloatRep || pk == DoubleRep
+                        then GST DF dyn (spRel loc)
+                        else MOV sz (OpReg dyn) (OpAddr (spRel loc))
 
        {-SPARC: spill below frame pointer leaving 2 words/spill-}
        ,IF_ARCH_sparc( ST sz dyn (fpRel (-2 * i))
         ,)))
     )
 
        {-SPARC: spill below frame pointer leaving 2 words/spill-}
        ,IF_ARCH_sparc( ST sz dyn (fpRel (-2 * i))
         ,)))
     )
-
+  | otherwise
+  = pprPanic "spillReg:" (text "invalid spill location: " <> int i)
+   
 ----------------------------
 loadReg (MemoryReg i pk) dyn
 ----------------------------
 loadReg (MemoryReg i pk) dyn
-  | i >= 0  -- JRS paranoia
-  = let
-       sz = primRepToSize pk
+  | i >= 0 -- JRS paranoia
+  = let        sz = primRepToSize pk
     in
     mkUnitList (
         IF_ARCH_alpha( LD  sz dyn (spRel i)
     in
     mkUnitList (
         IF_ARCH_alpha( LD  sz dyn (spRel i)
-       ,IF_ARCH_i386 ( if   pk == FloatRep || pk == DoubleRep
-                        then GLD DF (spRel (16 + 2 * i)) dyn
-                        else MOV sz (OpAddr (spRel (16 + 2 * i))) (OpReg dyn)
+       ,IF_ARCH_i386 ( let loc | i < 60    = 4 + 2 * i
+                                | otherwise = -2000 - 2 * i
+                        in
+                        if   pk == FloatRep || pk == DoubleRep
+                        then GLD DF (spRel loc) dyn
+                        else MOV sz (OpAddr (spRel loc)) (OpReg dyn)
        ,IF_ARCH_sparc( LD  sz (fpRel (-2 * i)) dyn
        ,)))
     )
        ,IF_ARCH_sparc( LD  sz (fpRel (-2 * i)) dyn
        ,)))
     )
+  | otherwise
+  = pprPanic "loadReg:" (text "invalid spill location: " <> int i)
 \end{code}
 \end{code}