diff options
Diffstat (limited to 'CodeGen.hs')
-rw-r--r-- | CodeGen.hs | 124 |
1 files changed, 95 insertions, 29 deletions
@@ -17,6 +17,7 @@ import Defs import Intermediate import qualified LifetimeAnalysis as LA import RegAlloc +import ReplaceRefs import Utils import X64 (Register(..), CondCode(..), XRef(..), Ins(..), xref) import qualified X64 as X64 @@ -95,12 +96,16 @@ codegenFunc (IRFunc _ name al bbs sid) = do aliascandidates = findAliasCandidates bbs :: [(Ref, Ref)] gpRegs = [R8, R9, R10, R11, R12, R13, R14, R15] + -- gpRegs = [R8] allocation = regalloc lifespans gpRegs aliascandidates :: Map.Map Ref (Allocation Register) spillrefs = map fst $ filter (isAllocMem . snd) $ Map.toList allocation (spilloffsets, spillsz) = initLast $ scanl (+) 0 $ map refSize spillrefs spilloffsetmap = Map.fromList $ zip spillrefs spilloffsets + structrefs = filter isStructTemp $ findAllRefsBBList bbs + structspace = sum $ map refSize structrefs + usedregs = uniq $ sort $ catMaybes $ flip map (Map.toList allocation) $ \(_, a) -> case a of AllocReg reg -> Just reg AllocMem -> Nothing @@ -110,31 +115,52 @@ codegenFunc (IRFunc _ name al bbs sid) = do traceM $ "ALLOCATION: " ++ show allocation let nsaves = length usedregs - alignoff = if odd nsaves then 8 else 0 + framesize' = 8 {- ret addr -} + 8 {- rbp -} + 8 * nsaves + + fromIntegral structspace + fromIntegral spillsz + alignoff = roundUp framesize' 16 - framesize' + framesize = framesize' + alignoff allocationXref = flip Map.mapWithKey allocation $ \ref alloc -> case alloc of AllocReg reg -> XReg (fromIntegral $ refSize ref) reg AllocMem -> XMem (fromIntegral $ refSize ref) (Just RSP) (0, RAX) Nothing (fromIntegral $ spilloffsetmap ! ref) - allocmap = foldl inserter allocationXref (zip al [0::Int ..]) + allocmap' = fst $ foldl arginserter (allocationXref, 0) al + where + arginserter (m, off) (t, n) = + (Map.insert (Argument (sizeof t) n) + (XMem (fromIntegral $ sizeof t) + (Just RSP) (0, RAX) Nothing + (fromIntegral framesize + off)) + m, + off + fromIntegral (sizeof t)) + + allocmap = fst $ foldl structinserter (allocmap', spillsz) structrefs where - inserter m ((t, n), i) = - let offset = fromIntegral spillsz + alignoff + 8 * nsaves + - 8 {- rbp -} + 8 {- ret addr -} + 8 * i - in Map.insert (Argument (sizeof t) n) - (XMem (fromIntegral $ sizeof t) - (Just RSP) (0, RAX) Nothing - (fromIntegral offset)) - m + structinserter (m, off) temp@(StructTemp sz _) = + (Map.insert temp + (XMem (fromIntegral sz) + (Just RSP) (0, RAX) Nothing + (fromIntegral off)) + m, + off + sz) + structinserter _ _ = undefined + + traceM $ "nsaves = " ++ show nsaves + traceM $ "structspace = " ++ show structspace + traceM $ "spillsz = " ++ show spillsz + traceM $ "framesize' = " ++ show framesize' + traceM $ "alignoff = " ++ show alignoff + traceM $ "framesize = " ++ show framesize newLabel name addIns $ PUSH (xref $ XReg 8 RBP) addIns $ MOV (xref $ XReg 8 RBP) (xref $ XReg 8 RSP) forM_ usedregs $ \reg -> addIns $ PUSH (xref $ XReg 8 reg) - when (odd $ length usedregs) $ addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm 8) - when (spillsz /= 0) $ addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral spillsz) + let stackspill = spillsz + structspace + fromIntegral alignoff + when (stackspill /= 0) $ + addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral stackspill) setRegsToRestore usedregs - setSpillSize spillsz + setSpillSize stackspill let ([startbb], rest) = partition (\(BB i _ _) -> i == sid) bbs codegenBB allocmap startbb @@ -192,6 +218,20 @@ mkmov a@(XMem _ _ _ _ _) b@(XImm v) | v < 2 ^ (32 :: Int) = MOV (xref a) (xref b mkmov a b = CALL $ "Invalid mkmov: " ++ show a ++ "; " ++ show b -- mkmov a b = error $ "Invalid mkmov: " ++ show a ++ "; " ++ show b +emitmemcpy :: XRef -> XRef -> CGMonad () +emitmemcpy dst@(XMem sz _ _ _ _) src@(XMem sz2 _ _ _ _) + | sz /= sz2 = error $ "Inconsistent sizes in emitmemcpy: " ++ show dst ++ "; " ++ show src + | sz `elem` [1, 2, 4, 8] = do + addIns $ mkmov (XReg sz RAX) src + addIns $ mkmov dst (XReg sz RAX) + | sz > 8 = do + addIns $ mkmov (XReg 8 RAX) (X64.xrefSetSize 8 src) + addIns $ mkmov (X64.xrefSetSize 8 dst) (XReg 8 RAX) + emitmemcpy (X64.offsetXMem 8 $ X64.xrefSetSize (sz - 8) dst) + (X64.offsetXMem 8 $ X64.xrefSetSize (sz - 8) src) + | otherwise = error $ "Invalid size in emitmemcpy: " ++ show dst ++ "; " ++ show src +emitmemcpy _ _ = undefined + mkcmp :: XRef -> XRef -> X64.Ins mkcmp a b@(XImm _) = CMPi (xref a) (xref b) mkcmp a b = CMP (xref a) (xref b) @@ -244,6 +284,24 @@ codegenIns m (ILoad d s) = do where dm = mkxref d m sm = mkxref s m sz = fromIntegral $ refSize d +codegenIns m (ISet d off s) + | X64.isXMem sm = do + addIns $ mkmov (XReg sz RAX) sm + addIns $ mkmov dm (XReg sz RAX) + | otherwise = do + addIns $ mkmov dm sm + where dm = X64.xrefSetSize sz $ X64.offsetXMem (fromIntegral off) $ mkxref d m + sm = mkxref s m + sz = fromIntegral $ refSize s +codegenIns m (IGet d s off) + | X64.isXMem dm = do + addIns $ mkmov (XReg sz RAX) sm + addIns $ mkmov dm (XReg sz RAX) + | otherwise = do + addIns $ mkmov dm sm + where dm = mkxref d m + sm = X64.xrefSetSize sz $ X64.offsetXMem (fromIntegral off) $ mkxref s m + sz = fromIntegral $ refSize d codegenIns m (IAri AMul d s1 s2) = do let sz = fromIntegral $ refSize d addIns $ mkmov (XReg sz RAX) (mkxref s1 m) @@ -275,7 +333,7 @@ codegenIns m (IAri at d s1 s2) = case arithTypeToCondCode at of addIns $ SETCC cc (xref $ X64.xrefSetSize 1 dm) addIns $ AND (xref $ X64.xrefSetSize 4 dm) (xref $ XImm 0xff) Nothing -> do - (_, s1m', s2', s2m') <- + (s1', s1m', s2', s2m') <- if dm == s2m then if dm == s1m then return (s1, s1m, s2, s2m) @@ -289,27 +347,35 @@ codegenIns m (IAri at d s1 s2) = case arithTypeToCondCode at of addIns $ mkmov (XReg (fromIntegral $ refSize s2') RAX) s2m' return $ XReg (fromIntegral $ refSize s2') RAX else return s2m' - when (dm /= s1m') $ addIns $ mkmov dm s1m' + when (dm /= s1m') $ if X64.isXMem dm && X64.isXMem s1m' + then do + addIns $ mkmov (XReg (fromIntegral $ refSize s1') RBX) s1m' + addIns $ mkmov dm (XReg (fromIntegral $ refSize s1') RBX) + else do + addIns $ mkmov dm s1m' addIns $ fromJust (arithTypeToIns at) dm arg2 where dm = mkxref d m s1m = mkxref s1 m s2m = mkxref s2 m codegenIns m (ICall n rs) = do - when (odd $ length rs) $ addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm 8) - forM_ (zip (reverse rs) [1::Int ..]) $ \(r, i) -> + let sizes = map (flip roundUp 8 . refSize) rs + offsets = init $ scanl (+) 0 $ reverse sizes + totalsize = sum sizes + alignment = roundUp totalsize 16 - totalsize + forM_ (zip rs offsets) $ \(r, off) -> let sz = fromIntegral $ refSize r - src = (mkxref r m) - dst = (XMem sz (Just RSP) (0, RAX) Nothing (fromIntegral $ (-8) * i)) - in if X64.isXMem (mkxref r m) + src = mkxref r m + dst = XMem sz (Just RSP) (0, RAX) Nothing (fromIntegral $ off - alignment - totalsize) + in if X64.isXMem src then do - addIns $ mkmov (XReg sz RAX) src - addIns $ mkmov dst (XReg sz RAX) - else do - addIns $ mkmov dst src - when (length rs > 0) $ addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm (fromIntegral $ 8 * length rs)) + traceM $ "call stuff with dst = " ++ show dst ++ ", src = " ++ show src + emitmemcpy dst src + else addIns $ mkmov dst src + when (alignment /= 0) $ addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral alignment) + when (length rs > 0) $ addIns $ SUB (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral totalsize) addIns $ CALL n - when (length rs > 0) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm (fromIntegral $ 8 * length rs)) - when (odd $ length rs) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm 8) + when (length rs > 0) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral totalsize) + when (alignment /= 0) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral alignment) codegenIns m (ICallr d n rs) = do codegenIns m (ICall n rs) addIns $ mkmov (mkxref d m) (XReg (fromIntegral $ refSize d) RAX) @@ -386,7 +452,6 @@ codegenTerm _ IRet = do spillsz <- gets spillSize when (spillsz /= 0) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral spillsz) usedregs <- gets regsToRestore - when (odd $ length usedregs) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm 8) forM_ (reverse usedregs) $ \reg -> addIns $ POP (xref $ XReg 8 reg) addIns $ mkmov (XReg 8 RSP) (XReg 8 RBP) addIns $ POP (xref $ XReg 8 RBP) @@ -396,7 +461,6 @@ codegenTerm m (IRetr r) = do spillsz <- gets spillSize when (spillsz /= 0) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm $ fromIntegral spillsz) usedregs <- gets regsToRestore - when (odd $ length usedregs) $ addIns $ ADD (xref $ XReg 8 RSP) (xref $ XImm 8) forM_ (reverse usedregs) $ \reg -> addIns $ POP (xref $ XReg 8 reg) addIns $ mkmov (XReg 8 RSP) (XReg 8 RBP) addIns $ POP (xref $ XReg 8 RBP) @@ -417,6 +481,8 @@ collectTempRefs bbs = listRefsIns (ILea a _) = [[LA.Write a]] listRefsIns (IStore a b) = [[LA.Read a, LA.Read b]] listRefsIns (ILoad a b) = [[LA.Read b], [LA.Write a]] + listRefsIns (ISet a _ b) = [[LA.Read b, LA.Write a]] + listRefsIns (IGet a b _) = [[LA.Read b, LA.Write a]] listRefsIns (IAri at a b c) -- if not commutative, we don't want to have to xchg the operands | isCommutative at = [[LA.Read b, LA.Read c], [LA.Write a]] |