1 -- | Generating C calls
2 module SPARC.CodeGen.CCall (
8 import SPARC.CodeGen.Gen64
9 import SPARC.CodeGen.Gen32
10 import SPARC.CodeGen.Base
31 Now the biggest nightmare---calls. Most of the nastiness is buried in
32 @get_arg@, which moves the arguments to the correct registers/stack
33 locations. Apart from that, the code is easy.
35 The SPARC calling convention is an absolute
36 nightmare. The first 6x32 bits of arguments are mapped into
37 %o0 through %o5, and the remaining arguments are dumped to the
38 stack, beginning at [%sp+92]. (Note that %o6 == %sp.)
40 If we have to put args on the stack, move %o6==%sp down by
41 the number of words to go on the stack, to ensure there's enough space.
43 According to Fraser and Hanson's lcc book, page 478, fig 17.2,
44 16 words above the stack pointer is a word for the address of
45 a structure return value. I use this as a temporary location
46 for moving values from float to int regs. Certainly it isn't
47 safe to put anything in the 16 words starting at %sp, since
48 this area can get trashed at any time due to window overflows
49 caused by signal handlers.
51 A final complication (if the above isn't enough) is that
52 we can't blithely calculate the arguments one by one into
53 %o0 .. %o5. Consider the following nested calls:
57 Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately
58 the inner call will itself use %o0, which trashes the value put there
59 in preparation for the outer call. Upshot: we need to calculate the
60 args into temporary regs, and move those to arg regs or onto the
61 stack only immediately prior to the call proper. Sigh.
65 :: CmmCallTarget -- function to call
66 -> [HintedCmmFormal] -- where to put the result
67 -> [HintedCmmActual] -- arguments (of mixed type)
72 -- On SPARC under TSO (Total Store Ordering), writes earlier in the instruction stream
73 -- are guaranteed to take place before writes afterwards (unlike on PowerPC).
74 -- Ref: Section 8.4 of the SPARC V9 Architecture manual.
76 -- In the SPARC case we don't need a barrier.
78 genCCall (CmmPrim (MO_WriteBarrier)) _ _
81 genCCall target dest_regs argsAndHints
83 -- need to remove alignment information
84 let argsAndHints' | (CmmPrim mop) <- target,
93 -- strip hints from the arg regs
95 args = map hintlessCmm argsAndHints'
98 -- work out the arguments, and assign them to integer regs
99 argcode_and_vregs <- mapM arg_to_int_vregs args
100 let (argcodes, vregss) = unzip argcode_and_vregs
101 let vregs = concat vregss
103 let n_argRegs = length allArgRegs
104 let n_argRegs_used = min (length vregs) n_argRegs
107 -- deal with static vs dynamic call targets
108 callinsns <- case target of
109 CmmCallee (CmmLit (CmmLabel lbl)) _ ->
110 return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))
113 -> do (dyn_c, [dyn_r]) <- arg_to_int_vregs expr
114 return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
117 -> do res <- outOfLineMachOp mop
118 lblOrMopExpr <- case res of
120 return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))
123 (dyn_c, [dyn_r]) <- arg_to_int_vregs mopExpr
124 return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)
128 let argcode = concatOL argcodes
130 let (move_sp_down, move_sp_up)
131 = let diff = length vregs - n_argRegs
132 nn = if odd diff then diff + 1 else diff -- keep 8-byte alignment
135 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
138 = toOL (move_final vregs allArgRegs extraStackArgsHere)
143 transfer_code `appOL`
147 assign_code dest_regs
150 -- | Generate code to calculate an argument, and move it into one
151 -- or two integer vregs.
152 arg_to_int_vregs :: CmmExpr -> NatM (OrdList Instr, [Reg])
155 -- If the expr produces a 64 bit int, then we can just use iselExpr64
156 | isWord64 (cmmExprType arg)
157 = do (ChildCode64 code r_lo) <- iselExpr64 arg
158 let r_hi = getHiVRegFromLo r_lo
159 return (code, [r_hi, r_lo])
162 = do (src, code) <- getSomeReg arg
163 let pk = cmmExprType arg
165 case cmmTypeSize pk of
167 -- Load a 64 bit float return value into two integer regs.
169 v1 <- getNewRegNat II32
170 v2 <- getNewRegNat II32
174 FMOV FF64 src f0 `snocOL`
175 ST FF32 f0 (spRel 16) `snocOL`
176 LD II32 (spRel 16) v1 `snocOL`
177 ST FF32 f1 (spRel 16) `snocOL`
178 LD II32 (spRel 16) v2
180 return (code2, [v1,v2])
182 -- Load a 32 bit float return value into an integer reg
184 v1 <- getNewRegNat II32
188 ST FF32 src (spRel 16) `snocOL`
189 LD II32 (spRel 16) v1
193 -- Move an integer return value into its destination reg.
195 v1 <- getNewRegNat II32
199 OR False g0 (RIReg src) v1
204 -- | Move args from the integer vregs into which they have been
205 -- marshalled, into %o0 .. %o5, and the rest onto the stack.
207 move_final :: [Reg] -> [Reg] -> Int -> [Instr]
213 -- out of aregs; move to stack
214 move_final (v:vs) [] offset
215 = ST II32 v (spRel offset)
216 : move_final vs [] (offset+1)
218 -- move into an arg (%o[0..5]) reg
219 move_final (v:vs) (a:az) offset
220 = OR False g0 (RIReg v) a
221 : move_final vs az offset
224 -- | Assign results returned from the call into their
227 assign_code :: [CmmHinted LocalReg] -> OrdList Instr
229 assign_code [] = nilOL
231 assign_code [CmmHinted dest _hint]
232 = let rep = localRegType dest
233 width = typeWidth rep
234 r_dest = getRegisterReg (CmmLocal dest)
239 = unitOL $ FMOV FF32 (regSingle $ fReg 0) r_dest
243 = unitOL $ FMOV FF64 (regSingle $ fReg 0) r_dest
245 | not $ isFloatType rep
247 = unitOL $ mkRegRegMoveInstr (regSingle $ oReg 0) r_dest
249 | not $ isFloatType rep
251 , r_dest_hi <- getHiVRegFromLo r_dest
252 = toOL [ mkRegRegMoveInstr (regSingle $ oReg 0) r_dest_hi
253 , mkRegRegMoveInstr (regSingle $ oReg 1) r_dest]
256 = panic "SPARC.CodeGen.GenCCall: no match"
261 = panic "SPARC.CodeGen.GenCCall: no match"
265 -- | Generate a call to implement an out-of-line floating point operation
268 -> NatM (Either CLabel CmmExpr)
271 = do let functionName
272 = outOfLineMachOp_table mop
274 dflags <- getDynFlagsNat
275 mopExpr <- cmmMakeDynamicReference dflags addImportNat CallReference
276 $ mkForeignLabel functionName Nothing ForeignLabelInExternalPackage IsFunction
280 CmmLit (CmmLabel lbl) -> Left lbl
283 return mopLabelOrExpr
286 -- | Decide what C function to use to implement a CallishMachOp
288 outOfLineMachOp_table
292 outOfLineMachOp_table mop
294 MO_F32_Exp -> fsLit "expf"
295 MO_F32_Log -> fsLit "logf"
296 MO_F32_Sqrt -> fsLit "sqrtf"
297 MO_F32_Pwr -> fsLit "powf"
299 MO_F32_Sin -> fsLit "sinf"
300 MO_F32_Cos -> fsLit "cosf"
301 MO_F32_Tan -> fsLit "tanf"
303 MO_F32_Asin -> fsLit "asinf"
304 MO_F32_Acos -> fsLit "acosf"
305 MO_F32_Atan -> fsLit "atanf"
307 MO_F32_Sinh -> fsLit "sinhf"
308 MO_F32_Cosh -> fsLit "coshf"
309 MO_F32_Tanh -> fsLit "tanhf"
311 MO_F64_Exp -> fsLit "exp"
312 MO_F64_Log -> fsLit "log"
313 MO_F64_Sqrt -> fsLit "sqrt"
314 MO_F64_Pwr -> fsLit "pow"
316 MO_F64_Sin -> fsLit "sin"
317 MO_F64_Cos -> fsLit "cos"
318 MO_F64_Tan -> fsLit "tan"
320 MO_F64_Asin -> fsLit "asin"
321 MO_F64_Acos -> fsLit "acos"
322 MO_F64_Atan -> fsLit "atan"
324 MO_F64_Sinh -> fsLit "sinh"
325 MO_F64_Cosh -> fsLit "cosh"
326 MO_F64_Tanh -> fsLit "tanh"
328 MO_Memcpy -> fsLit "memcpy"
329 MO_Memset -> fsLit "memset"
330 MO_Memmove -> fsLit "memmove"
332 _ -> pprPanic "outOfLineMachOp(sparc): Unknown callish mach op "
333 (pprCallishMachOp mop)