summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoachim Breitner <mail@joachim-breitner.de>2015-03-16 21:10:59 +0100
committerJoachim Breitner <mail@joachim-breitner.de>2015-03-16 21:15:12 +0100
commit01164fc91f00245b3c946840027532a1b2c17a22 (patch)
tree218c2aa3466dfd2ffff7f70abe16337d1d7b5996
parent6beea8b6c6dcd45272ad12b178a8128547768b09 (diff)
downloadhaskell-01164fc91f00245b3c946840027532a1b2c17a22.tar.gz
CmmSwitch: Avoid a -1 for jump tables
-rw-r--r--compiler/cmm/CmmSwitch.hs29
1 files changed, 28 insertions, 1 deletions
diff --git a/compiler/cmm/CmmSwitch.hs b/compiler/cmm/CmmSwitch.hs
index 60fa8ed258..b0629642ec 100644
--- a/compiler/cmm/CmmSwitch.hs
+++ b/compiler/cmm/CmmSwitch.hs
@@ -127,10 +127,37 @@ 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] ])
+ = (fromIntegral (-start), [ labelFor i | i <- [start..hi] ])
where
labelFor i = case M.lookup i branches of Just l -> Just l
Nothing -> mbdef
+ start | lo >= 0 && lo < 2 = 0 -- See Note [Jump Table Offset]
+ | otherwise = lo
+
+-- Note [Jump Table Offset]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~
+--
+-- Usually, the code for a jump table starting at x will first subtract x from
+-- the value, to avoid a large amount of empty entries. But if x is very small,
+-- the extra entries are no worse than the subtraction in terms of code size, and
+-- not having to do the subtraction is quicker.
+--
+-- I.e. instead of
+-- _u20N:
+-- leaq -1(%r14),%rax
+-- jmp *_n20R(,%rax,8)
+-- _n20R:
+-- .quad _c20p
+-- .quad _c20q
+-- do
+-- _u20N:
+-- jmp *_n20Q(,%r14,8)
+--
+-- _n20Q:
+-- .quad 0
+-- .quad _c20p
+-- .quad _c20q
+-- .quad _c20r
switchTargetsToList :: SwitchTargets -> [Label]
switchTargetsToList (SwitchTargets _ _ mbdef branches)