1 -----------------------------------------------------------------------------
3 -- Generating machine code (instruction selection)
5 -- (c) The University of Glasgow 1996-2004
7 -----------------------------------------------------------------------------
16 #include "HsVersions.h"
17 #include "nativeGen/NCG.h"
21 import SPARC.CodeGen.Amode
22 import SPARC.CodeGen.CondCode
23 import SPARC.CodeGen.Gen64
24 import SPARC.CodeGen.Gen32
25 import SPARC.CodeGen.CCall
26 import SPARC.CodeGen.Base
36 -- Our intermediate code:
42 import StaticFlags ( opt_PIC )
44 import qualified Outputable as O
47 import Control.Monad ( mapAndUnzipM )
50 -- | Top level code generation
54 -> NatM [NatCmmTop Instr]
57 (CmmProc info lab params (ListGraph blocks))
59 (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks
61 let proc = CmmProc info lab params (ListGraph $ concat nat_blocks)
62 let tops = proc : concat statics
66 cmmTopCodeGen _ (CmmData sec dat) = do
67 return [CmmData sec dat] -- no translation, we just use CmmStatic
70 -- | Do code generation on a single block of CMM code.
71 -- code generation may introduce new basic block boundaries, which
72 -- are indicated by the NEWBLOCK instruction. We must split up the
73 -- instruction stream into basic blocks again. Also, we extract
77 -> NatM ( [NatBasicBlock Instr]
80 basicBlockCodeGen (BasicBlock id stmts) = do
81 instrs <- stmtsToInstrs stmts
83 (top,other_blocks,statics)
84 = foldrOL mkBlocks ([],[],[]) instrs
86 mkBlocks (NEWBLOCK id) (instrs,blocks,statics)
87 = ([], BasicBlock id instrs : blocks, statics)
89 mkBlocks (LDATA sec dat) (instrs,blocks,statics)
90 = (instrs, blocks, CmmData sec dat:statics)
92 mkBlocks instr (instrs,blocks,statics)
93 = (instr:instrs, blocks, statics)
97 $ BasicBlock id top : other_blocks
99 return (blocksChecked, statics)
102 -- | Enforce the invariant that all basic blocks must end with a jump.
103 -- For SPARC this is a jump, then a nop for the branch delay slot.
105 -- If the branch isn't there then the register liveness determinator
106 -- will get the liveness information wrong. This will cause a bad
107 -- allocation, which is seriously difficult to debug.
109 -- If there is an instr in the branch delay slot, then the allocator
110 -- will also get confused and give a bad allocation.
113 :: NatBasicBlock Instr -> NatBasicBlock Instr
115 checkBlockEnd block@(BasicBlock _ instrs)
116 | Just (i1, i2) <- takeLast2 instrs
123 ("SPARC.CodeGen: bad instrs at end of block\n")
124 (text "block:\n" <> ppr block)
126 takeLast2 :: [a] -> Maybe (a, a)
131 x1:x2:[] -> Just (x1, x2)
135 -- | Convert some Cmm statements to SPARC instructions.
136 stmtsToInstrs :: [CmmStmt] -> NatM InstrBlock
138 = do instrss <- mapM stmtToInstrs stmts
139 return (concatOL instrss)
142 stmtToInstrs :: CmmStmt -> NatM InstrBlock
143 stmtToInstrs stmt = case stmt of
144 CmmNop -> return nilOL
145 CmmComment s -> return (unitOL (COMMENT s))
148 | isFloatType ty -> assignReg_FltCode size reg src
149 | isWord64 ty -> assignReg_I64Code reg src
150 | otherwise -> assignReg_IntCode size reg src
151 where ty = cmmRegType reg
152 size = cmmTypeSize ty
155 | isFloatType ty -> assignMem_FltCode size addr src
156 | isWord64 ty -> assignMem_I64Code addr src
157 | otherwise -> assignMem_IntCode size addr src
158 where ty = cmmExprType src
159 size = cmmTypeSize ty
161 CmmCall target result_regs args _ _
162 -> genCCall target result_regs args
164 CmmBranch id -> genBranch id
165 CmmCondBranch arg id -> genCondJump id arg
166 CmmSwitch arg ids -> genSwitch arg ids
167 CmmJump arg _ -> genJump arg
170 -> panic "stmtToInstrs: return statement should have been cps'd away"
174 Now, given a tree (the argument to an CmmLoad) that references memory,
175 produce a suitable addressing mode.
177 A Rule of the Game (tm) for Amodes: use of the addr bit must
178 immediately follow use of the code part, since the code part puts
179 values in registers which the addr then refers to. So you can't put
180 anything in between, lest it overwrite some of those registers. If
181 you need to do some other computation between the code part and use of
182 the addr bit, first store the effective address from the amode in a
183 temporary, then do the other computation, and then use the temporary:
187 ... other computation ...
193 -- | Convert a BlockId to some CmmStatic data
194 jumpTableEntry :: Maybe BlockId -> CmmStatic
195 jumpTableEntry Nothing = CmmStaticLit (CmmInt 0 wordWidth)
196 jumpTableEntry (Just (BlockId id)) = CmmStaticLit (CmmLabel blockLabel)
197 where blockLabel = mkAsmTempLabel id
201 -- -----------------------------------------------------------------------------
202 -- Generating assignments
204 -- Assignments are really at the heart of the whole code generation
205 -- business. Almost all top-level nodes of any real importance are
206 -- assignments, which correspond to loads, stores, or register
207 -- transfers. If we're really lucky, some of the register transfers
208 -- will go away, because we can use the destination register to
209 -- complete the code generation for the right hand side. This only
210 -- fails when the right hand side is forced into a fixed register
211 -- (e.g. the result of a call).
213 assignMem_IntCode :: Size -> CmmExpr -> CmmExpr -> NatM InstrBlock
214 assignMem_IntCode pk addr src = do
215 (srcReg, code) <- getSomeReg src
216 Amode dstAddr addr_code <- getAmode addr
217 return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr
220 assignReg_IntCode :: Size -> CmmReg -> CmmExpr -> NatM InstrBlock
221 assignReg_IntCode _ reg src = do
224 Any _ code -> code dst
225 Fixed _ freg fcode -> fcode `snocOL` OR False g0 (RIReg freg) dst
227 dst = getRegisterReg reg
231 -- Floating point assignment to memory
232 assignMem_FltCode :: Size -> CmmExpr -> CmmExpr -> NatM InstrBlock
233 assignMem_FltCode pk addr src = do
234 Amode dst__2 code1 <- getAmode addr
235 (src__2, code2) <- getSomeReg src
236 tmp1 <- getNewRegNat pk
238 pk__2 = cmmExprType src
239 code__2 = code1 `appOL` code2 `appOL`
240 if sizeToWidth pk == typeWidth pk__2
241 then unitOL (ST pk src__2 dst__2)
242 else toOL [ FxTOy (cmmTypeSize pk__2) pk src__2 tmp1
246 -- Floating point assignment to a register/temporary
247 assignReg_FltCode :: Size -> CmmReg -> CmmExpr -> NatM InstrBlock
248 assignReg_FltCode pk dstCmmReg srcCmmExpr = do
249 srcRegister <- getRegister srcCmmExpr
250 let dstReg = getRegisterReg dstCmmReg
252 return $ case srcRegister of
253 Any _ code -> code dstReg
254 Fixed _ srcFixedReg srcCode -> srcCode `snocOL` FMOV pk srcFixedReg dstReg
259 genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock
261 genJump (CmmLit (CmmLabel lbl))
262 = return (toOL [CALL (Left target) 0 True, NOP])
268 (target, code) <- getSomeReg tree
269 return (code `snocOL` JMP (AddrRegReg target g0) `snocOL` NOP)
271 -- -----------------------------------------------------------------------------
272 -- Unconditional branches
274 genBranch :: BlockId -> NatM InstrBlock
275 genBranch = return . toOL . mkJumpInstr
278 -- -----------------------------------------------------------------------------
282 Conditional jumps are always to local labels, so we can use branch
283 instructions. We peek at the arguments to decide what kind of
286 SPARC: First, we have to ensure that the condition codes are set
287 according to the supplied comparison operation. We generate slightly
288 different code for floating point comparisons, because a floating
289 point operation cannot directly precede a @BF@. We assume the worst
290 and fill that slot with a @NOP@.
292 SPARC: Do not fill the delay slots here; you will confuse the register
298 :: BlockId -- the branch target
299 -> CmmExpr -- the condition on which to branch
304 genCondJump bid bool = do
305 CondCode is_float cond code <- getCondCode bool
310 then [NOP, BF cond False bid, NOP]
311 else [BI cond False bid, NOP]
317 -- -----------------------------------------------------------------------------
318 -- Generating a table-branch
320 genSwitch :: CmmExpr -> [Maybe BlockId] -> NatM InstrBlock
323 = error "MachCodeGen: sparc genSwitch PIC not finished\n"
326 = do (e_reg, e_code) <- getSomeReg expr
328 base_reg <- getNewRegNat II32
329 offset_reg <- getNewRegNat II32
330 dst <- getNewRegNat II32
332 label <- getNewLabelNat
333 let jumpTable = map jumpTableEntry ids
335 return $ e_code `appOL`
338 [ LDATA ReadOnlyData (CmmDataLabel label : jumpTable)
340 -- load base of jump table
341 , SETHI (HI (ImmCLbl label)) base_reg
342 , OR False base_reg (RIImm $ LO $ ImmCLbl label) base_reg
344 -- the addrs in the table are 32 bits wide..
345 , SLL e_reg (RIImm $ ImmInt 2) offset_reg
347 -- load and jump to the destination
348 , LD II32 (AddrRegReg base_reg offset_reg) dst
349 , JMP_TBL (AddrRegImm dst (ImmInt 0)) [i | Just i <- ids]