[commit: ghc] wip/T10137: Add an (optional) range field to the SwitchTargets data type (86db745)
git at git.haskell.org
git at git.haskell.org
Wed Mar 4 22:21:39 UTC 2015
Repository : ssh://git@git.haskell.org/ghc
On branch : wip/T10137
Link : http://ghc.haskell.org/trac/ghc/changeset/86db7454880dbcfeec5f529492b68ef1cc71277f/ghc
>---------------------------------------------------------------
commit 86db7454880dbcfeec5f529492b68ef1cc71277f
Author: Joachim Breitner <mail at joachim-breitner.de>
Date: Wed Mar 4 22:16:44 2015 +0100
Add an (optional) range field to the SwitchTargets data type
As there is one in the Cmm syntax, and we might be able to exploit that
during code generation.
>---------------------------------------------------------------
86db7454880dbcfeec5f529492b68ef1cc71277f
compiler/cmm/CmmNode.hs | 36 +++++++++++++++++++++++-------------
compiler/cmm/CmmParse.y | 26 ++++++++++++++------------
compiler/codeGen/StgCmmUtils.hs | 9 +++------
3 files changed, 40 insertions(+), 31 deletions(-)
diff --git a/compiler/cmm/CmmNode.hs b/compiler/cmm/CmmNode.hs
index a3edc3f..4b3dfd2 100644
--- a/compiler/cmm/CmmNode.hs
+++ b/compiler/cmm/CmmNode.hs
@@ -698,25 +698,34 @@ combineTickScopes s1 s2
-- See Note [Switch Table]
data SwitchTargets =
- SwitchTargets (Maybe Label) (M.Map Integer Label)
+ SwitchTargets (Maybe (Integer, Integer)) (Maybe Label) (M.Map Integer Label)
deriving Eq
-mkSwitchTargets :: Maybe Label -> M.Map Integer Label -> SwitchTargets
-mkSwitchTargets = SwitchTargets
+-- mkSwitchTargets normalises the map a bit:
+mkSwitchTargets :: Maybe (Integer, Integer) -> Maybe Label -> M.Map Integer Label -> SwitchTargets
+mkSwitchTargets mbrange mbdef ids
+ = SwitchTargets mbrange mbdef $ dropDefault $ restrict ids
+ where
+ -- It drops entries outside the range, if there is a range
+ restrict | Just (lo,hi) <- mbrange = M.filterWithKey (\x _ -> lo <= x && x <= hi)
+ | otherwise = id
+ -- It entries that equal the default, if there is a default
+ dropDefault | Just l <- mbdef = M.filter (/= l)
+ | otherwise = id
mapSwitchTargets :: (Label -> Label) -> SwitchTargets -> SwitchTargets
-mapSwitchTargets f (SwitchTargets mbdef branches)
- = SwitchTargets (fmap f mbdef) (fmap f branches)
+mapSwitchTargets f (SwitchTargets range mbdef branches)
+ = SwitchTargets range (fmap f mbdef) (fmap f branches)
switchTargetsCases :: SwitchTargets -> [(Integer, Label)]
-switchTargetsCases (SwitchTargets _ branches) = M.toList branches
+switchTargetsCases (SwitchTargets _ _ branches) = M.toList branches
switchTargetsDefault :: SwitchTargets -> Maybe Label
-switchTargetsDefault (SwitchTargets mbdef _) = mbdef
+switchTargetsDefault (SwitchTargets _ mbdef _) = mbdef
switchTargetsToTable :: SwitchTargets -> [Maybe Label]
-switchTargetsToTable (SwitchTargets mbdef branches)
- | min < 0 = pprPanic "mapSwitchTargets" empty
+switchTargetsToTable (SwitchTargets _ mbdef branches)
+ | min < 0 = pprPanic "mapSwitchTargets" empty
| otherwise = [ labelFor i | i <- [0..max] ]
where
min = fst (M.findMin branches)
@@ -725,20 +734,21 @@ switchTargetsToTable (SwitchTargets mbdef branches)
Nothing -> mbdef
switchTargetsToList :: SwitchTargets -> [Label]
-switchTargetsToList (SwitchTargets mbdef branches) = maybeToList mbdef ++ M.elems branches
+switchTargetsToList (SwitchTargets _ mbdef branches)
+ = maybeToList mbdef ++ M.elems branches
-- | Groups cases with equal targets, suitable for pretty-printing to a
-- c-like switch statement with fall-through semantics.
switchTargetsFallThrough :: SwitchTargets -> ([([Integer], Label)], Maybe Label)
-switchTargetsFallThrough (SwitchTargets mbdef branches) = (groups, mbdef)
+switchTargetsFallThrough (SwitchTargets _ mbdef branches) = (groups, mbdef)
where
groups = map (\xs -> (map fst xs, snd (head xs))) $
groupBy ((==) `on` snd) $
M.toList branches
eqSwitchTargetWith :: (Label -> Label -> Bool) -> SwitchTargets -> SwitchTargets -> Bool
-eqSwitchTargetWith eq (SwitchTargets mbdef1 ids1) (SwitchTargets mbdef2 ids2) =
- goMB mbdef1 mbdef2 && goList (M.toList ids1) (M.toList ids2)
+eqSwitchTargetWith eq (SwitchTargets range1 mbdef1 ids1) (SwitchTargets range2 mbdef2 ids2) =
+ range1 == range2 && goMB mbdef1 mbdef2 && goList (M.toList ids1) (M.toList ids2)
where
goMB Nothing Nothing = True
goMB (Just l1) (Just l2) = l1 `eq` l2
diff --git a/compiler/cmm/CmmParse.y b/compiler/cmm/CmmParse.y
index 4f286f5..7ec1e4a 100644
--- a/compiler/cmm/CmmParse.y
+++ b/compiler/cmm/CmmParse.y
@@ -677,24 +677,24 @@ globals :: { [GlobalReg] }
: GLOBALREG { [$1] }
| GLOBALREG ',' globals { $1 : $3 }
-maybe_range :: { Maybe (Int,Int) }
- : '[' INT '..' INT ']' { Just (fromIntegral $2, fromIntegral $4) }
+maybe_range :: { Maybe (Integer,Integer) }
+ : '[' INT '..' INT ']' { Just ($2, $4) }
| {- empty -} { Nothing }
-arms :: { [CmmParse ([Int],Either BlockId (CmmParse ()))] }
+arms :: { [CmmParse ([Integer],Either BlockId (CmmParse ()))] }
: {- empty -} { [] }
| arm arms { $1 : $2 }
-arm :: { CmmParse ([Int],Either BlockId (CmmParse ())) }
+arm :: { CmmParse ([Integer],Either BlockId (CmmParse ())) }
: 'case' ints ':' arm_body { do b <- $4; return ($2, b) }
arm_body :: { CmmParse (Either BlockId (CmmParse ())) }
: '{' body '}' { return (Right (withSourceNote $1 $3 $2)) }
| 'goto' NAME ';' { do l <- lookupLabel $2; return (Left l) }
-ints :: { [Int] }
- : INT { [ fromIntegral $1 ] }
- | INT ',' ints { fromIntegral $1 : $3 }
+ints :: { [Integer] }
+ : INT { [ $1 ] }
+ | INT ',' ints { $1 : $3 }
default :: { Maybe (CmmParse ()) }
: 'default' ':' '{' body '}' { Just (withSourceNote $3 $5 $4) }
@@ -1308,7 +1308,9 @@ withSourceNote a b parse = do
-- optional range on the switch (eg. switch [0..7] {...}), or by
-- the minimum/maximum values from the branches.
-doSwitch :: Maybe (Int,Int) -> CmmParse CmmExpr -> [([Int],Either BlockId (CmmParse ()))]
+doSwitch :: Maybe (Integer,Integer)
+ -> CmmParse CmmExpr
+ -> [([Integer],Either BlockId (CmmParse ()))]
-> Maybe (CmmParse ()) -> CmmParse ()
doSwitch mb_range scrut arms deflt
= do
@@ -1326,13 +1328,13 @@ doSwitch mb_range scrut arms deflt
expr <- scrut
-- ToDo: check for out of range and jump to default if necessary
- emit $ mkSwitch expr (mkSwitchTargets dflt_entry table)
+ emit $ mkSwitch expr (mkSwitchTargets mb_range dflt_entry table)
where
- emitArm :: ([Int],Either BlockId (CmmParse ())) -> CmmParse [(Integer,BlockId)]
- emitArm (ints,Left blockid) = return [ (fromIntegral i,blockid) | i <- ints ]
+ emitArm :: ([Integer],Either BlockId (CmmParse ())) -> CmmParse [(Integer,BlockId)]
+ emitArm (ints,Left blockid) = return [ (i,blockid) | i <- ints ]
emitArm (ints,Right code) = do
blockid <- forkLabelledCode code
- return [ (fromIntegral i,blockid) | i <- ints ]
+ return [ (i,blockid) | i <- ints ]
forkLabelledCode :: CmmParse () -> CmmParse BlockId
forkLabelledCode p = do
diff --git a/compiler/codeGen/StgCmmUtils.hs b/compiler/codeGen/StgCmmUtils.hs
index 4935c7f..df913d1 100644
--- a/compiler/codeGen/StgCmmUtils.hs
+++ b/compiler/codeGen/StgCmmUtils.hs
@@ -544,15 +544,12 @@ mk_switch tag_expr branches mb_deflt lo_tag hi_tag via_C
-- either end of the range (see below), so the first
-- tag of a real branch is real_lo_tag (not lo_tag).
arms :: M.Map Integer BlockId
- arms = M.fromList [ (fromIntegral (i - real_lo_tag), l)
- | (i,l) <- branches
- , real_lo_tag <= i
- , i <= real_hi_tag
- ]
+ arms = M.fromList [ (fromIntegral i, l) | (i,l) <- branches ]
+
dflags <- getDynFlags
return $ mkSwitch
(cmmOffset dflags tag_expr (- real_lo_tag))
- (mkSwitchTargets Nothing arms)
+ (mkSwitchTargets (Just (0, fromIntegral (real_hi_tag-real_lo_tag))) 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
More information about the ghc-commits
mailing list