[commit: ghc] wip/T10137: CmmSwitch: Move table offset to code generation phase (8f5d606)

git at git.haskell.org git at git.haskell.org
Wed Mar 4 22:21:41 UTC 2015


Repository : ssh://git@git.haskell.org/ghc

On branch  : wip/T10137
Link       : http://ghc.haskell.org/trac/ghc/changeset/8f5d60622b107d1bbf306abbc6fefb56c040c35e/ghc

>---------------------------------------------------------------

commit 8f5d60622b107d1bbf306abbc6fefb56c040c35e
Author: Joachim Breitner <mail at joachim-breitner.de>
Date:   Wed Mar 4 23:13:28 2015 +0100

    CmmSwitch: Move table offset to code generation phase
    
    Previously, if a switch statement would not start with 0, the Stg → Cmm
    phase would offset the scrutinee to make the table zero-based. In order
    to have CmmSwitch a bit higher level, this step is moved to the Cmm →
    Assembly phase.
    
    This also means that in the llvm backend, more is more
    logic left to the LLVM compiler (which hopefully knows best how to
    compile a switch statement).


>---------------------------------------------------------------

8f5d60622b107d1bbf306abbc6fefb56c040c35e
 compiler/cmm/CmmNode.hs             | 18 ++++++++++++------
 compiler/codeGen/StgCmmUtils.hs     |  6 +++---
 compiler/nativeGen/PPC/CodeGen.hs   |  6 +++---
 compiler/nativeGen/SPARC/CodeGen.hs |  4 ++--
 compiler/nativeGen/X86/CodeGen.hs   |  6 +++---
 5 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/compiler/cmm/CmmNode.hs b/compiler/cmm/CmmNode.hs
index 4b3dfd2..90d1b77 100644
--- a/compiler/cmm/CmmNode.hs
+++ b/compiler/cmm/CmmNode.hs
@@ -723,13 +723,19 @@ switchTargetsCases (SwitchTargets _ _ branches) = M.toList branches
 switchTargetsDefault :: SwitchTargets -> Maybe Label
 switchTargetsDefault (SwitchTargets _ mbdef _) = mbdef
 
-switchTargetsToTable :: SwitchTargets -> [Maybe Label]
-switchTargetsToTable (SwitchTargets _ mbdef branches)
-    | min < 0 = pprPanic "mapSwitchTargets" empty
-    | otherwise = [ labelFor i | i <- [0..max] ]
+-- switchTargetsToTable creates a dense jump table, usable for code generation.
+-- This is not possible if there is no explicit range, so before code generation
+-- all switch statements need to be transformed to one with an explicit range.
+--
+-- Returns an offset to add to the value; the list is 0-based on the result
+--
+-- TODO: Is the conversion from Integral to Int fishy?
+switchTargetsToTable :: SwitchTargets -> (Int, [Maybe Label])
+switchTargetsToTable (SwitchTargets Nothing _mbdef _branches)
+    = pprPanic "switchTargetsToTable" empty
+switchTargetsToTable (SwitchTargets (Just (lo,hi)) mbdef branches)
+    = (fromIntegral (-lo), [ labelFor i | i <- [lo..hi] ])
   where
-    min = fst (M.findMin branches)
-    max = fst (M.findMax branches)
     labelFor i = case M.lookup i branches of Just l -> Just l
                                              Nothing -> mbdef
 
diff --git a/compiler/codeGen/StgCmmUtils.hs b/compiler/codeGen/StgCmmUtils.hs
index df913d1..0f2d4b2 100644
--- a/compiler/codeGen/StgCmmUtils.hs
+++ b/compiler/codeGen/StgCmmUtils.hs
@@ -546,10 +546,10 @@ mk_switch tag_expr branches mb_deflt lo_tag hi_tag via_C
         arms :: M.Map Integer BlockId
         arms = M.fromList [ (fromIntegral i, l) | (i,l) <- branches ]
 
-       dflags <- getDynFlags
+        range = (fromIntegral real_lo_tag, fromIntegral real_hi_tag)
        return $ mkSwitch
-           (cmmOffset dflags tag_expr (- real_lo_tag))
-           (mkSwitchTargets (Just (0, fromIntegral (real_hi_tag-real_lo_tag))) Nothing arms)
+           tag_expr
+           (mkSwitchTargets (Just range) Nothing arms)
 
   -- if we can knock off a bunch of default cases with one if, then do so
   | Just deflt <- mb_deflt, (lowest_branch - lo_tag) >= n_branches
diff --git a/compiler/nativeGen/PPC/CodeGen.hs b/compiler/nativeGen/PPC/CodeGen.hs
index 552d9ac..fb42c07 100644
--- a/compiler/nativeGen/PPC/CodeGen.hs
+++ b/compiler/nativeGen/PPC/CodeGen.hs
@@ -1205,7 +1205,7 @@ genSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> NatM InstrBlock
 genSwitch dflags expr targets
   | gopt Opt_PIC dflags
   = do
-        (reg,e_code) <- getSomeReg expr
+        (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)
         tmp <- getNewRegNat II32
         lbl <- getNewLabelNat
         dflags <- getDynFlags
@@ -1221,7 +1221,7 @@ genSwitch dflags expr targets
         return code
   | otherwise
   = do
-        (reg,e_code) <- getSomeReg expr
+        (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)
         tmp <- getNewRegNat II32
         lbl <- getNewLabelNat
         let code = e_code `appOL` toOL [
@@ -1232,7 +1232,7 @@ genSwitch dflags expr targets
                             BCTR ids (Just lbl)
                     ]
         return code
-  where ids = switchTargetsToTable targets
+  where (offset, ids) = switchTargetsToTable targets
 
 generateJumpTableForInstr :: DynFlags -> Instr
                           -> Maybe (NatCmmDecl CmmStatics Instr)
diff --git a/compiler/nativeGen/SPARC/CodeGen.hs b/compiler/nativeGen/SPARC/CodeGen.hs
index 8631ab8..3f49afe 100644
--- a/compiler/nativeGen/SPARC/CodeGen.hs
+++ b/compiler/nativeGen/SPARC/CodeGen.hs
@@ -314,7 +314,7 @@ genSwitch dflags expr targets
         = error "MachCodeGen: sparc genSwitch PIC not finished\n"
 
         | otherwise
-        = do    (e_reg, e_code) <- getSomeReg expr
+        = do    (e_reg, e_code) <- getSomeReg (cmmOffset dflags expr offset)
 
                 base_reg        <- getNewRegNat II32
                 offset_reg      <- getNewRegNat II32
@@ -335,7 +335,7 @@ genSwitch dflags expr targets
                         , LD      II32 (AddrRegReg base_reg offset_reg) dst
                         , JMP_TBL (AddrRegImm dst (ImmInt 0)) ids label
                         , NOP ]
-  where ids = switchTargetsToTable targets
+  where (offset, ids) = switchTargetsToTable targets
 
 generateJumpTableForInstr :: DynFlags -> Instr
                           -> Maybe (NatCmmDecl CmmStatics Instr)
diff --git a/compiler/nativeGen/X86/CodeGen.hs b/compiler/nativeGen/X86/CodeGen.hs
index 6e0e8ad..a826531 100644
--- a/compiler/nativeGen/X86/CodeGen.hs
+++ b/compiler/nativeGen/X86/CodeGen.hs
@@ -2589,7 +2589,7 @@ genSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> NatM InstrBlock
 genSwitch dflags expr targets
   | gopt Opt_PIC dflags
   = do
-        (reg,e_code) <- getSomeReg expr
+        (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)
         lbl <- getNewLabelNat
         dflags <- getDynFlags
         dynRef <- cmmMakeDynamicReference dflags DataReference lbl
@@ -2631,14 +2631,14 @@ genSwitch dflags expr targets
                            ]
   | otherwise
   = do
-        (reg,e_code) <- getSomeReg expr
+        (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)
         lbl <- getNewLabelNat
         let op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg (wORD_SIZE dflags)) (ImmCLbl lbl))
             code = e_code `appOL` toOL [
                     JMP_TBL op ids ReadOnlyData lbl
                  ]
         return code
-  where ids = switchTargetsToTable targets
+  where (offset, ids) = switchTargetsToTable targets
 
 generateJumpTableForInstr :: DynFlags -> Instr -> Maybe (NatCmmDecl (Alignment, CmmStatics) Instr)
 generateJumpTableForInstr dflags (JMP_TBL _ ids section lbl)



More information about the ghc-commits mailing list