{-# LANGUAGE GADTs #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module Assembly where
import Compiler.Hoopl as Hoopl hiding ((<*>))
import Control.Applicative
import Data.Foldable
import qualified Data.List
import Data.Maybe (fromMaybe)
import Data.Monoid
import Data.Traversable
import Lens.Family hiding (Constant)
import LinearScan
import LinearScan.Hoopl
import LinearScan.Hoopl.DSL
default (Int)
-- | The basic instructions that have nothing to do with control flow.
data Instruction reg
= Add reg reg reg
| Nop
deriving (Eq, Functor, Foldable, Traversable)
instance Show r => Show (Instruction r) where
show (Add x1 x2 x3) = "add " ++ show x1 ++ " " ++ show x2 ++ " " ++ show x3
show Nop = "nop"
-- | Tests used for branching (correspond to branching instructions)
data Test = Zero -- ^ beq
| NonZero -- ^ bne
| Positive -- ^ bgt
| Negative -- ^ blt
deriving (Eq, Show)
data CConv = InlineC
| CConvC { ccArgs :: [PhysReg]
, ccResults :: [PhysReg]
, ccIsBrack :: Bool
}
deriving (Eq, Show)
type Src a = a -- ^ Type synonym for indicating source operands
type Dst a = a -- ^ Type synonym for indicating destination operands
type Success a = a -- ^ Type synonym for indicating success or true branch
type Failure a = a -- ^ Type synonym for indicating failure or false branch
data Node v e x where
Label :: Label -> Node v C O
Alloc :: Maybe (Src v) -> Dst v -> Node v O O
Reclaim :: Src v -> Node v O O
Instr :: Instruction v -> Node v O O
Call :: CConv -> Int -> Node v O O
LoadConst :: Int -> Dst v -> Node v O O
Move :: Src v -> Dst v -> Node v O O
Copy :: Src v -> Dst v -> Node v O O
Save :: Src v -> Dst Int -> Node v O O
Restore :: Src Int -> Dst v -> Node v O O
Trace :: String -> Node v O O
Jump :: Label -> Node v O C
Branch :: Test -> v -> Success Label -> Failure Label -> Node v O C
ReturnInstr :: [PhysReg] -> Instruction v -> Node v O C
deriving instance Eq v => Eq (Node v e x)
instance Show v => Show (Node v e x) where
show (Label l) = show l ++ ":"
show (Alloc x1 x2) = "\t@alloc " ++
(case x1 of Just v -> " " ++ show v ; _ -> " _")
++ " " ++ show x2
show (Reclaim v) = "\t@reclaim " ++ show v
show (Instr i) = "\t" ++ show i
show (Call c l) = "\t@call " ++ show c ++ " " ++ show l
show (LoadConst _c v) = "\t@lc " ++ show v -- ++ " " ++ show c
show (Move x1 x2) = "\t@mvrr " ++ show x1 ++ " " ++ show x2
show (Copy x1 x2) = "\t@cprr " ++ show x1 ++ " " ++ show x2
show (Save src dst) = "\t@save " ++ show src ++ " " ++ show dst
show (Restore src dst) = "\t@restore " ++ show src ++ " " ++ show dst
show (Trace str) = "\tTRACE " ++ " " ++ show str
show (Jump l) = "\t@jmp " ++ show l
show (Branch c v t f) = "\t@b" ++ show c ++ " " ++ show v
++ " " ++ show t ++ "; @jmp " ++ show f
show (ReturnInstr regs i) = "\t@return " ++ show regs ++ " " ++ show i
instance NonLocal (Node v) where
entryLabel (Label l) = l
successors (Jump l) = [l]
successors (Branch _ _ t f) = [t, f]
successors (ReturnInstr _ _) = []
instance HooplNode (Node v) where
mkBranchNode = Jump
mkLabelNode = Label
variables :: Applicative f => LensLike f (Node v1 e x) (Node v2 e x) v1 v2
variables f = go
where
go (Alloc msrc dst) = Alloc <$> traverse f msrc <*> f dst
go (Reclaim src) = Reclaim <$> f src
go (Instr i) = Instr <$> traverse f i
go (LoadConst c dst) = LoadConst c <$> f dst
go (Move src dst) = Move <$> f src <*> f dst
go (Copy src dst) = Copy <$> f src <*> f dst
go (Save src x) = Save <$> f src <*> pure x
go (Restore x src) = Restore x <$> f src
go (Trace str) = pure $ Trace str
go (Branch x1 cond x2 x3) = Branch x1 <$> f cond <*> pure x2 <*> pure x3
go (Call cc i) = pure $ Call cc i
go (ReturnInstr liveInRegs i) = ReturnInstr liveInRegs <$> traverse f i
go (Label x) = pure $ Label x
go (Jump x) = pure $ Jump x
add :: v -> v -> v -> BodyNode (Node v)
add x0 x1 x2 = bodyNode $ Instr (Add x0 x1 x2)
nop :: BodyNode (Node v)
nop = bodyNode $ Instr Nop
move :: v -> v -> BodyNode (Node v)
move x0 x1 = bodyNode $ Move x0 x1
call :: Int -> BodyNode (Node v)
call dst = bodyNode $ Call InlineC dst
lc :: v -> BodyNode (Node v)
lc x0 = bodyNode $ LoadConst 0 x0
save :: v -> Dst PhysReg -> BodyNode (Node v)
save r dst = bodyNode $ Save r dst
restore :: Src PhysReg -> v -> BodyNode (Node v)
restore src r = bodyNode $ Restore src r
trace :: String -> BodyNode (Node v)
trace str = bodyNode $ Trace str
branch :: Test -> v -> String -> String -> EndNode (Node v)
branch tst v good bad =
endNode $ Branch tst v <$> getLabel good <*> getLabel bad
return_ :: EndNode (Node v)
return_ = endNode $ return $ ReturnInstr [] Nop
data Assign a b = Assign a b
instance Show a => Show (Assign a PhysReg) where
show (Assign v (-1)) = "<<v" ++ show v ++ ">>"
-- show (Assign v r) = "r" ++ show r ++ "|v" ++ show v
show (Assign _ r) = show r
data IRVar = PhysicalIV PhysReg | VirtualIV Int deriving Eq
instance Show IRVar where
show (PhysicalIV r) = "r" ++ show r
show (VirtualIV n) = "v" ++ show n
instance NodeAlloc Node IRVar (Assign VarId PhysReg) where
fromVar (PhysicalIV r) = Left r
fromVar (VirtualIV n) = Right n
fromReg (Assign _ r) = r
isCall (Call {}) = True
isCall _ = False
isBranch (Jump {}) = True
isBranch (Branch {}) = True
isBranch _ = False
retargetBranch (Jump _) _ lab = Jump lab
retargetBranch (Branch b v x y) old lab
| x == old = Branch b v lab y
| otherwise = Branch b v x lab
retargetBranch x _ _ = error $ "Cannot retarget " ++ show x
mkLabelOp = Label
mkJumpOp = Jump
getReferences = go
where
go :: Node IRVar e x -> [VarInfo]
go (Label _) = mempty
go (Instr i) = fromInstr i
go (Jump _) = mempty
go (Call _ _) = mempty
go (Move src dst) = mkv Input src <> mkv Output dst
go (LoadConst _ v) = mkv Output v
go (Branch _ v _ _) = mkv Input v
go (Trace _) = mempty
go (ReturnInstr _ i) = fromInstr i
go n = error $ "getReferences: unhandled node: " ++ show n
fromInstr :: Instruction IRVar -> [VarInfo]
fromInstr Nop = mempty
fromInstr (Add s1 s2 d1) =
mkv Input s1 <> mkv Input s2 <> mkv Output d1
mkv :: VarKind -> IRVar -> [VarInfo]
mkv k (PhysicalIV n) = [vinfo k (Left n)]
mkv k (VirtualIV n) = [vinfo k (Right n)]
vinfo k en = VarInfo
{ varId = en
, varKind = k
, regRequired = True
}
setRegisters m g = do
for_ m $ \(v, r) -> setAssignment r v
return $ over variables go g
where
go :: IRVar -> Assign VarId PhysReg
go (PhysicalIV r) = Assign (-1) r
go (VirtualIV n) = Assign n (fromMaybe (-1) (Data.List.lookup n m))
mkMoveOps src dst = do
vid <- getAssignment src
return [Move (Assign vid src) (Assign vid dst)]
mkSwapOps src dst =
liftA2 (++) (mkRestoreOps Nothing dst)
(mkSaveOps src Nothing)
mkSaveOps src dst = do
off <- getStackSlot dst
vid <- getAssignment src
return [Save (Assign vid src) off]
mkRestoreOps src dst = do
off <- getStackSlot src
vid <- getAssignment dst
return [Restore off (Assign vid dst)]
op1ToString = show
var :: Int -> IRVar
var = VirtualIV
v0 = var 0
v1 = var 1
v2 = var 2
v3 = var 3
v4 = var 4
v5 = var 5
v6 = var 6
v7 = var 7
v8 = var 8
v9 = var 9
v10 = var 10
v11 = var 11
v12 = var 12
v13 = var 13
v14 = var 14
v15 = var 15
v16 = var 16
v17 = var 17
v18 = var 18
v19 = var 19
v20 = var 20
v21 = var 21
v22 = var 22
v23 = var 23
v24 = var 24
v25 = var 25
v26 = var 26
v27 = var 27
v28 = var 28
v29 = var 29
v30 = var 30
v31 = var 31
v32 = var 32
v33 = var 33
v34 = var 34
v35 = var 35
v36 = var 36
v37 = var 37
v38 = var 38
v39 = var 39
v40 = var 40
reg :: PhysReg -> IRVar -> Assign VarId PhysReg
reg _ (PhysicalIV _) = error "Don't use reg to reference a literal register"
reg r (VirtualIV v) = Assign v r
r0 = reg 0
r1 = reg 1
r2 = reg 2
r3 = reg 3
r4 = reg 4
r5 = reg 5
r6 = reg 6
r7 = reg 7
r8 = reg 8
r9 = reg 9
r10 = reg 10
r11 = reg 11
r12 = reg 12
r13 = reg 13
r14 = reg 14
r15 = reg 15
r16 = reg 16
r17 = reg 17
r18 = reg 18
r19 = reg 19
r20 = reg 20
r21 = reg 21
r22 = reg 22
r23 = reg 23
r24 = reg 24
r25 = reg 25
r26 = reg 26
r27 = reg 27
r28 = reg 28
r29 = reg 29
r30 = reg 30
r31 = reg 31
r32 = reg 32