aboutsummaryrefslogtreecommitdiff
path: root/X64Optimiser.hs
diff options
context:
space:
mode:
Diffstat (limited to 'X64Optimiser.hs')
-rw-r--r--X64Optimiser.hs63
1 files changed, 60 insertions, 3 deletions
diff --git a/X64Optimiser.hs b/X64Optimiser.hs
index fa5d113..195389f 100644
--- a/X64Optimiser.hs
+++ b/X64Optimiser.hs
@@ -1,6 +1,7 @@
module X64Optimiser(x64Optimise) where
import Data.List
+import Data.Maybe
import Defs
import X64
@@ -9,7 +10,10 @@ import X64
x64Optimise :: Asm -> Error Asm
x64Optimise asm =
return $
- funcopt optCoalesceInstructions $
+ funcopt optSimpleInstructions $
+ funcopt optDoubleAdd $
+ funcopt optMergeRSP $
+ funcopt optMergeRSP $ -- #HACK (sometimes needed to eliminate all rsp arithmetic)
optUnnecessaryJumps $
funcopt optSimpleInstructions $
asm
@@ -35,10 +39,12 @@ optSimpleInstructions (name, inss) = (name, concat $ map goI inss)
goI (MOVi (Reg (XReg 8 r)) (Imm (XImm 0))) = [XOR (RegMem (XReg 4 r)) (RegMemImm (XReg 4 r))]
goI (MOVi (Reg a) (Imm (XImm 0))) = [XOR (RegMem a) (RegMemImm a)]
goI (MOVSX (Reg a) (RegMem b)) | a == b = []
+ goI (ADD _ (RegMemImm (XImm 0))) = []
+ goI (SUB _ (RegMemImm (XImm 0))) = []
goI ins = [ins]
-optCoalesceInstructions :: Func -> Func
-optCoalesceInstructions (name, inss) = (name, go inss)
+optMergeRSP :: Func -> Func
+optMergeRSP (name, inss) = (name, go inss)
where
go :: [Ins] -> [Ins]
go [] = []
@@ -76,3 +82,54 @@ optCoalesceInstructions (name, inss) = (name, go inss)
XMem _ _ (_, RSP) _ _ -> Nothing
x@(XReg _ _) -> Just x
x@(XMem _ _ _ _ _) -> Just x
+
+optDoubleAdd :: Func -> Func
+optDoubleAdd (name, inss) = (name, go inss)
+ where
+ go :: [Ins] -> [Ins]
+ go [] = []
+ go (add@(ADD (RegMem xreg@(XReg _ xregReg)) (RegMemImm (XImm _))) : rest) =
+ let midx = flip findIndex rest $ \ins -> case ins of
+ ADD (RegMem xreg2@(XReg _ _)) (RegMemImm (XImm _)) | xreg == xreg2 -> True
+ SUB (RegMem xreg2@(XReg _ _)) (RegMemImm (XImm _)) | xreg == xreg2 -> True
+ _ -> False
+ in case midx of
+ Nothing -> add : go rest
+ Just idx -> if all (canSkip xregReg) (take idx rest)
+ then go $ merge add (rest !! idx) : take idx rest ++ drop (idx + 1) rest
+ else add : go rest
+ go (ins : rest) = ins : go rest
+
+ canSkip :: Register -> Ins -> Bool
+ canSkip _ (CALL _) = False
+ canSkip _ (JMP _) = False
+ canSkip _ (JCC _ _) = False
+ canSkip _ RET = False
+ canSkip reg ins =
+ isJust $ xrefMapM (\y -> if y `containsReg` reg then Nothing else Just y) ins
+
+ containsReg :: XRef -> Register -> Bool
+ containsReg (XReg _ r) reg | r == reg = True
+ containsReg (XMem _ (Just r) _ _ _) reg | r == reg = True
+ containsReg (XMem _ _ (s, r) _ _) reg | s /= 0 && r == reg = True
+ containsReg _ _ = False
+
+ merge :: Ins -> Ins -> Ins
+ merge ins1 ins2 =
+ let e1 = effectOf ins1
+ e2 = effectOf ins2
+ dst1 = destOf ins1
+ dst2 = destOf ins2
+ in if dst1 == dst2
+ then ADD (RegMem dst1) (RegMemImm $ XImm $ e1 + e2)
+ else undefined
+
+ effectOf :: Ins -> Offset
+ effectOf (ADD _ (RegMemImm (XImm i))) = i
+ effectOf (SUB _ (RegMemImm (XImm i))) = -i
+ effectOf _ = undefined
+
+ destOf :: Ins -> XRef
+ destOf (ADD (RegMem d) _) = d
+ destOf (SUB (RegMem d) _) = d
+ destOf _ = undefined