summaryrefslogtreecommitdiff
path: root/compiler/cmm/CmmSwitch.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/cmm/CmmSwitch.hs')
-rw-r--r--compiler/cmm/CmmSwitch.hs201
1 files changed, 147 insertions, 54 deletions
diff --git a/compiler/cmm/CmmSwitch.hs b/compiler/cmm/CmmSwitch.hs
index ce779465e3..8ded03bdf3 100644
--- a/compiler/cmm/CmmSwitch.hs
+++ b/compiler/cmm/CmmSwitch.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE GADTs #-}
module CmmSwitch (
- SwitchTargets,
- mkSwitchTargets,
+ SwitchTargets, LabelInfo,
+ liLbl, liWeight, mkSwitchTargets,
switchTargetsCases, switchTargetsDefault, switchTargetsRange, switchTargetsSigned,
mapSwitchTargets, switchTargetsToTable, switchTargetsFallThrough,
switchTargetsToList, eqSwitchTargetWith,
@@ -9,6 +9,8 @@ module CmmSwitch (
SwitchPlan(..),
targetSupportsSwitch,
createSwitchPlan,
+
+ SeparatedList,
) where
import GhcPrelude
@@ -18,9 +20,11 @@ import DynFlags
import Hoopl.Label (Label)
import Data.Maybe
+import Data.Bifunctor
import Data.List (groupBy)
import Data.Function (on)
import qualified Data.Map as M
+import BasicTypes (BranchWeight, combinedFreqs, moreLikely, neverFreq)
-- Note [Cmm Switches, the general plan]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -103,17 +107,27 @@ minJumpTableOffset = 2
-- optional default value and a map from values to jump labels.
data SwitchTargets =
SwitchTargets
- Bool -- Signed values
- (Integer, Integer) -- Range
- (Maybe Label) -- Default value
- (M.Map Integer Label) -- The branches
- deriving (Show, Eq)
+ { st_signed :: Bool -- Signed values
+ , st_range :: (Integer, Integer) -- Range
+ , st_defLabel :: (Maybe LabelInfo) -- Default value
+ , st_valMap :: (M.Map Integer LabelInfo) -- The branches
+ } deriving (Show, Eq)
+
+-- | A label annotated with a branch weight.
+type LabelInfo = (Label, BranchWeight)
+
+liLbl :: LabelInfo -> Label
+liLbl = fst
+
+liWeight :: LabelInfo -> BranchWeight
+liWeight = snd
-- | The smart constructor mkSwitchTargets normalises the map a bit:
-- * No entries outside the range
-- * No entries equal to the default
-- * No default if all elements have explicit values
-mkSwitchTargets :: Bool -> (Integer, Integer) -> Maybe Label -> M.Map Integer Label -> SwitchTargets
+mkSwitchTargets :: Bool -> (Integer, Integer) -> Maybe LabelInfo
+ -> M.Map Integer LabelInfo -> SwitchTargets
mkSwitchTargets signed range@(lo,hi) mbdef ids
= SwitchTargets signed range mbdef' ids'
where
@@ -135,14 +149,16 @@ mkSwitchTargets signed range@(lo,hi) mbdef ids
-- | Changes all labels mentioned in the SwitchTargets value
mapSwitchTargets :: (Label -> Label) -> SwitchTargets -> SwitchTargets
mapSwitchTargets f (SwitchTargets signed range mbdef branches)
- = SwitchTargets signed range (fmap f mbdef) (fmap f branches)
+ = SwitchTargets signed range
+ (fmap (first f) mbdef)
+ (fmap (first f) branches)
-- | Returns the list of non-default branches of the SwitchTargets value
-switchTargetsCases :: SwitchTargets -> [(Integer, Label)]
+switchTargetsCases :: SwitchTargets -> [(Integer, LabelInfo)]
switchTargetsCases (SwitchTargets _ _ _ branches) = M.toList branches
-- | Return the default label of the SwitchTargets value
-switchTargetsDefault :: SwitchTargets -> Maybe Label
+switchTargetsDefault :: SwitchTargets -> Maybe LabelInfo
switchTargetsDefault (SwitchTargets _ _ mbdef _) = mbdef
-- | Return the range of the SwitchTargets value
@@ -161,7 +177,7 @@ switchTargetsSigned (SwitchTargets signed _ _ _) = signed
-- The conversion from Integer to Int is a bit of a wart, as the actual
-- scrutinee might be an unsigned word, but it just works, due to wrap-around
-- arithmetic (as verified by the CmmSwitchTest test case).
-switchTargetsToTable :: SwitchTargets -> (Int, [Maybe Label])
+switchTargetsToTable :: SwitchTargets -> (Int, [Maybe LabelInfo])
switchTargetsToTable (SwitchTargets _ (lo,hi) mbdef branches)
= (fromIntegral (-start), [ labelFor i | i <- [start..hi] ])
where
@@ -198,27 +214,37 @@ switchTargetsToTable (SwitchTargets _ (lo,hi) mbdef branches)
-- | The list of all labels occuring in the SwitchTargets value.
switchTargetsToList :: SwitchTargets -> [Label]
switchTargetsToList (SwitchTargets _ _ mbdef branches)
- = maybeToList mbdef ++ M.elems branches
+ = map liLbl (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
+ -> ([([Integer], LabelInfo)], Maybe LabelInfo)
switchTargetsFallThrough (SwitchTargets _ _ mbdef branches) = (groups, mbdef)
where
groups = map (\xs -> (map fst xs, snd (head xs))) $
- groupBy ((==) `on` snd) $
+ groupBy ((==) `on` (liLbl . snd)) $
M.toList branches
-- | Custom equality helper, needed for "CmmCommonBlockElim"
-eqSwitchTargetWith :: (Label -> Label -> Bool) -> SwitchTargets -> SwitchTargets -> Bool
-eqSwitchTargetWith eq (SwitchTargets signed1 range1 mbdef1 ids1) (SwitchTargets signed2 range2 mbdef2 ids2) =
- signed1 == signed2 && range1 == range2 && goMB mbdef1 mbdef2 && goList (M.toList ids1) (M.toList ids2)
+eqSwitchTargetWith :: (Label -> Label -> Bool)
+ -> SwitchTargets -> SwitchTargets
+ -> Bool
+eqSwitchTargetWith eq
+ (SwitchTargets signed1 range1 mbdef1 ids1)
+ (SwitchTargets signed2 range2 mbdef2 ids2) =
+ signed1 == signed2 && 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
+ goMB (Just l1) (Just l2) = liLbl l1 `eq` liLbl l2
goMB _ _ = False
goList [] [] = True
- goList ((i1,l1):ls1) ((i2,l2):ls2) = i1 == i2 && l1 `eq` l2 && goList ls1 ls2
+ goList ((i1,l1):ls1) ((i2,l2):ls2) =
+ i1 == i2 &&
+ liLbl l1 `eq` liLbl l2 &&
+ goList ls1 ls2
goList _ _ = False
-----------------------------------------------------------------------------
@@ -228,10 +254,23 @@ eqSwitchTargetWith eq (SwitchTargets signed1 range1 mbdef1 ids1) (SwitchTargets
-- | A SwitchPlan abstractly describes how a Switch statement ought to be
-- implemented. See Note [createSwitchPlan]
data SwitchPlan
- = Unconditionally Label
- | IfEqual Integer Label SwitchPlan
- | IfLT Bool Integer SwitchPlan SwitchPlan
- | JumpTable SwitchTargets
+ = Unconditionally
+ { sp_ucTarget :: LabelInfo }
+ | IfEqual
+ { sp_val :: Integer
+ , sp_eqTarget :: LabelInfo
+ , sp_else :: SwitchPlan
+ , sp_likely ::(Maybe Bool)
+ }
+ | IfLT
+ { sp_signed :: Bool
+ , sp_val :: Integer
+ , sp_ltTarget :: SwitchPlan
+ , sp_else :: SwitchPlan
+ , sp_likely :: (Maybe Bool)
+ }
+ | JumpTable
+ { sp_jmpTable :: SwitchTargets }
deriving Show
--
-- Note [createSwitchPlan]
@@ -251,6 +290,20 @@ data SwitchPlan
-- findSingleValues
-- 5. The thus collected pieces are assembled to a balanced binary tree.
+-- | Accumulated weight of all branches in a switchplan
+planWeight :: SwitchPlan -> BranchWeight
+planWeight Unconditionally { sp_ucTarget = target }
+ = liWeight target
+planWeight IfEqual {sp_eqTarget = target, sp_else = alt }
+ = combinedFreqs (liWeight target) (planWeight alt)
+planWeight IfLT {sp_ltTarget = target, sp_else = alt }
+ = combinedFreqs (planWeight target) (planWeight alt)
+planWeight JumpTable {sp_jmpTable = table }
+ = foldl1 combinedFreqs lblWeights `combinedFreqs` maybe neverFreq liWeight def
+ where
+ lblWeights = map liWeight $ M.elems (st_valMap table)
+ def = st_defLabel table
+
{-
Note [Two alts + default]
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -323,28 +376,36 @@ targetSupportsSwitch _ = False
-- | This function creates a SwitchPlan from a SwitchTargets value, breaking it
-- down into smaller pieces suitable for code generation.
-createSwitchPlan :: SwitchTargets -> SwitchPlan
+createSwitchPlan :: Bool -> SwitchTargets -> SwitchPlan
-- Lets do the common case of a singleton map quicky and efficiently (#10677)
-createSwitchPlan (SwitchTargets _signed _range (Just defLabel) m)
- | [(x, l)] <- M.toList m
- = IfEqual x l (Unconditionally defLabel)
+createSwitchPlan _ (SwitchTargets _signed _range (Just defInfo) m)
+ | [(x, li)] <- M.toList m
+ = IfEqual x li
+ (Unconditionally defInfo)
+ (moreLikely (liWeight li) (liWeight defInfo))
-- And another common case, matching "booleans"
-createSwitchPlan (SwitchTargets _signed (lo,hi) Nothing m)
- | [(x1, l1), (_x2,l2)] <- M.toAscList m
+createSwitchPlan _ (SwitchTargets _signed (lo,hi) Nothing m)
+ | [(x1, li1@(l1,f1)), (_x2,li2@(l2,f2))] <- M.toAscList m
--Checking If |range| = 2 is enough if we have two unique literals
, hi - lo == 1
- = IfEqual x1 l1 (Unconditionally l2)
+ = IfEqual x1 li1 (Unconditionally li2) (moreLikely f1 f2)
-- See Note [Two alts + default]
-createSwitchPlan (SwitchTargets _signed _range (Just defLabel) m)
- | [(x1, l1), (x2,l2)] <- M.toAscList m
- = IfEqual x1 l1 (IfEqual x2 l2 (Unconditionally defLabel))
-createSwitchPlan (SwitchTargets signed range mbdef m) =
- -- pprTrace "createSwitchPlan" (text (show ids) $$ text (show (range,m)) $$ text (show pieces) $$ text (show flatPlan) $$ text (show plan)) $
+createSwitchPlan _ (SwitchTargets _signed _range (Just def@(defLabel, fdef)) m)
+ | [(x1, li1@(l1,f1)), (x2,li2@(l2,f2))] <- M.toAscList m
+ = IfEqual x1 li1
+ (IfEqual x2 li2 (Unconditionally def) (moreLikely f2 fdef))
+ (moreLikely f1 (combinedFreqs f2 fdef))
+createSwitchPlan balance (SwitchTargets signed range mbdef m) =
+ --pprTrace "createSwitchPlan"
+ --(text (show (range,m)) $$ text (show pieces) $$
+ --text (show flatPlan) $$ text (show plan)) $
plan
where
+ pieces :: [M.Map Integer LabelInfo]
pieces = concatMap breakTooSmall $ splitAtHoles maxJumpTableHole m
- flatPlan = findSingleValues $ mkFlatSwitchPlan signed mbdef range pieces
- plan = buildTree signed $ flatPlan
+ flatPlan = findSingleValues $
+ mkFlatSwitchPlan signed mbdef range pieces
+ plan = buildTree balance signed $ flatPlan
---
@@ -381,26 +442,39 @@ breakTooSmall m
type FlatSwitchPlan = SeparatedList Integer SwitchPlan
-mkFlatSwitchPlan :: Bool -> Maybe Label -> (Integer, Integer) -> [M.Map Integer Label] -> FlatSwitchPlan
+{-TODO:
+ Given the branch weights in LabelInfo we could do better
+ than binary search. Look at buildTree, findSingleValues, mkFlatSwitchPlan
+ if you implement this.
+-}
+-- | mkFlatSwitchPlan byWeight signed defLabel range maps
+mkFlatSwitchPlan :: Bool -- ^ Values are signed
+ -> Maybe LabelInfo -- ^ Default alternative
+ -> (Integer, Integer) -- ^ Range of possible values
+ -> [M.Map Integer LabelInfo] -- ^ Value to branch mapping.
+ -> FlatSwitchPlan
-- If we have no default (i.e. undefined where there is no entry), we can
-- branch at the minimum of each map
-mkFlatSwitchPlan _ Nothing _ [] = pprPanic "mkFlatSwitchPlan with nothing left to do" empty
+mkFlatSwitchPlan _ Nothing _ []
+ = pprPanic "mkFlatSwitchPlan with nothing left to do" empty
mkFlatSwitchPlan signed Nothing _ (m:ms)
- = (mkLeafPlan signed Nothing m , [ (fst (M.findMin m'), mkLeafPlan signed Nothing m') | m' <- ms ])
+ = (mkLeafPlan signed Nothing m ,
+ [ (fst (M.findMin m'), mkLeafPlan signed Nothing m') | m' <- ms ])
-- If we have a default, we have to interleave segments that jump
-- to the default between the maps
-mkFlatSwitchPlan signed (Just l) r ms = let ((_,p1):ps) = go r ms in (p1, ps)
+mkFlatSwitchPlan signed (Just li@(l,f)) r ms
+ = let ((_,p1):ps) = go r ms in (p1, ps)
where
go (lo,hi) []
| lo > hi = []
- | otherwise = [(lo, Unconditionally l)]
+ | otherwise = [(lo, Unconditionally li)]
go (lo,hi) (m:ms)
| lo < min
- = (lo, Unconditionally l) : go (min,hi) (m:ms)
+ = (lo, Unconditionally li) : go (min,hi) (m:ms)
| lo == min
- = (lo, mkLeafPlan signed (Just l) m) : go (max+1,hi) ms
+ = (lo, mkLeafPlan signed (Just li) m) : go (max+1,hi) ms
| otherwise
= pprPanic "mkFlatSwitchPlan" (integer lo <+> integer min)
where
@@ -408,10 +482,10 @@ mkFlatSwitchPlan signed (Just l) r ms = let ((_,p1):ps) = go r ms in (p1, ps)
max = fst (M.findMax m)
-mkLeafPlan :: Bool -> Maybe Label -> M.Map Integer Label -> SwitchPlan
+mkLeafPlan :: Bool -> Maybe LabelInfo -> M.Map Integer LabelInfo -> SwitchPlan
mkLeafPlan signed mbdef m
- | [(_,l)] <- M.toList m -- singleton map
- = Unconditionally l
+ | [(_,li@(l,_f))] <- M.toList m -- singleton map
+ = Unconditionally li
| otherwise
= JumpTable $ mkSwitchTargets signed (min,max) mbdef m
where
@@ -427,7 +501,10 @@ mkLeafPlan signed mbdef m
findSingleValues :: FlatSwitchPlan -> FlatSwitchPlan
findSingleValues (Unconditionally l, (i, Unconditionally l2) : (i', Unconditionally l3) : xs)
| l == l3 && i + 1 == i'
- = findSingleValues (IfEqual i l2 (Unconditionally l), xs)
+ = findSingleValues
+ (IfEqual i l2
+ (Unconditionally l) (moreLikely (liWeight l2) (liWeight l))
+ , xs)
findSingleValues (p, (i,p'):xs)
= (p,i) `consSL` findSingleValues (p', xs)
findSingleValues (p, [])
@@ -437,12 +514,28 @@ findSingleValues (p, [])
--- Step 5: Actually build the tree
---
--- Build a balanced tree from a separated list
-buildTree :: Bool -> FlatSwitchPlan -> SwitchPlan
-buildTree _ (p,[]) = p
-buildTree signed sl = IfLT signed m (buildTree signed sl1) (buildTree signed sl2)
- where
+-- | Build a balanced tree from a separated list
+-- Potentially by weight
+buildTree :: Bool -> Bool -> FlatSwitchPlan -> SwitchPlan
+buildTree _ _ (p,[]) = p
+buildTree byWeight signed sl
+ = --traceShow (m,likely,(planWeight left),(planWeight right), byWeight ) $
+ IfLT
+ { sp_signed = signed
+ , sp_val = m
+ , sp_ltTarget = left
+ , sp_else = right
+ , sp_likely = likely
+ }
+ where
(sl1, m, sl2) = divideSL sl
+ left = (buildTree byWeight signed sl1) :: SwitchPlan
+ right = (buildTree byWeight signed sl2)
+ likely = if byWeight
+ then moreLikely (planWeight left) (planWeight right)
+ else Nothing
+
+