2 % (c) The AQUA Project, Glasgow University, 1993-1995
6 #include "HsVersions.h"
11 -- and, for self-sufficiency
12 PprStyle, StixTree, CSeq
17 import AbsCSyn ( AbstractC, MagicId(..), kindFromMagicId )
18 import AbsPrel ( PrimOp(..)
19 IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
20 IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
22 import AsmRegAlloc ( runRegAllocate, mkReg, extractMappedRegNos,
23 Reg(..), RegLiveness(..), RegUsage(..),
24 FutureLive(..), MachineRegisters(..), MachineCode(..)
26 import CLabelInfo ( CLabel, isAsmTemp )
27 import SparcCode {- everything -}
29 import Maybes ( maybeToBool, Maybe(..) )
30 import OrdList -- ( mkEmptyList, mkUnitList, mkSeqList, mkParList, OrdList )
32 import PrimKind ( PrimKind(..), isFloatingKind )
41 type CodeBlock a = (OrdList a -> OrdList a)
45 %************************************************************************
47 \subsection[SparcCodeGen]{Generating Sparc Code}
49 %************************************************************************
51 This is the top-level code-generation function for the Sparc.
55 sparcCodeGen :: PprStyle -> [[StixTree]] -> SUniqSM Unpretty
56 sparcCodeGen sty trees =
57 mapSUs genSparcCode trees `thenSUs` \ dynamicCodes ->
59 staticCodes = scheduleSparcCode dynamicCodes
60 pretty = printLabeledCodes sty staticCodes
66 This bit does the code scheduling. The scheduler must also deal with
67 register allocation of temporaries. Much parallelism can be exposed via
68 the OrdList, but more might occur, so further analysis might be needed.
72 scheduleSparcCode :: [SparcCode] -> [SparcInstr]
73 scheduleSparcCode = concat . map (runRegAllocate freeSparcRegs reservedRegs)
75 freeSparcRegs :: SparcRegs
76 freeSparcRegs = mkMRegs (extractMappedRegNos freeRegs)
81 Registers passed up the tree. If the stix code forces the register
82 to live in a pre-decided machine register, it comes out as @Fixed@;
83 otherwise, it comes out as @Any@, and the parent can decide which
84 register to put it in.
89 = Fixed Reg PrimKind (CodeBlock SparcInstr)
90 | Any PrimKind (Reg -> (CodeBlock SparcInstr))
92 registerCode :: Register -> Reg -> CodeBlock SparcInstr
93 registerCode (Fixed _ _ code) reg = code
94 registerCode (Any _ code) reg = code reg
96 registerName :: Register -> Reg -> Reg
97 registerName (Fixed reg _ _) _ = reg
98 registerName (Any _ _) reg = reg
100 registerKind :: Register -> PrimKind
101 registerKind (Fixed _ pk _) = pk
102 registerKind (Any pk _) = pk
104 isFixed :: Register -> Bool
105 isFixed (Fixed _ _ _) = True
106 isFixed (Any _ _) = False
110 Memory addressing modes passed up the tree.
114 data Amode = Amode Addr (CodeBlock SparcInstr)
116 amodeAddr (Amode addr _) = addr
117 amodeCode (Amode _ code) = code
121 Condition codes passed up the tree.
125 data Condition = Condition Bool Cond (CodeBlock SparcInstr)
127 condName (Condition _ cond _) = cond
128 condFloat (Condition float _ _) = float
129 condCode (Condition _ _ code) = code
133 General things for putting together code sequences.
137 asmVoid :: OrdList SparcInstr
138 asmVoid = mkEmptyList
140 asmInstr :: SparcInstr -> SparcCode
141 asmInstr i = mkUnitList i
143 asmSeq :: [SparcInstr] -> SparcCode
144 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
146 asmParThen :: [SparcCode] -> (CodeBlock SparcInstr)
147 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
149 returnInstr :: SparcInstr -> SUniqSM (CodeBlock SparcInstr)
150 returnInstr instr = returnSUs (\xs -> mkSeqList (asmInstr instr) xs)
152 returnInstrs :: [SparcInstr] -> SUniqSM (CodeBlock SparcInstr)
153 returnInstrs instrs = returnSUs (\xs -> mkSeqList (asmSeq instrs) xs)
155 returnSeq :: (CodeBlock SparcInstr) -> [SparcInstr] -> SUniqSM (CodeBlock SparcInstr)
156 returnSeq code instrs = returnSUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
158 mkSeqInstr :: SparcInstr -> (CodeBlock SparcInstr)
159 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
161 mkSeqInstrs :: [SparcInstr] -> (CodeBlock SparcInstr)
162 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
166 Top level sparc code generator for a chunk of stix code.
170 genSparcCode :: [StixTree] -> SUniqSM (SparcCode)
173 mapSUs getCode trees `thenSUs` \ blocks ->
174 returnSUs (foldr (.) id blocks asmVoid)
178 Code extractor for an entire stix tree---stix statement level.
183 :: StixTree -- a stix statement
184 -> SUniqSM (CodeBlock SparcInstr)
186 getCode (StSegment seg) = returnInstr (SEGMENT seg)
188 getCode (StAssign pk dst src)
189 | isFloatingKind pk = assignFltCode pk dst src
190 | otherwise = assignIntCode pk dst src
192 getCode (StLabel lab) = returnInstr (LABEL lab)
194 getCode (StFunBegin lab) = returnInstr (LABEL lab)
196 getCode (StFunEnd lab) = returnSUs id
198 getCode (StJump arg) = genJump arg
200 getCode (StFallThrough lbl) = returnSUs id
202 getCode (StCondJump lbl arg) = genCondJump lbl arg
204 getCode (StData kind args) =
205 mapAndUnzipSUs getData args `thenSUs` \ (codes, imms) ->
206 returnSUs (\xs -> mkSeqList (asmInstr (DATA (kindToSize kind) imms))
207 (foldr1 (.) codes xs))
209 getData :: StixTree -> SUniqSM (CodeBlock SparcInstr, Imm)
210 getData (StInt i) = returnSUs (id, ImmInteger i)
211 #if __GLASGOW_HASKELL__ >= 23
212 -- getData (StDouble d) = returnSUs (id, strImmLit ('0' : 'r' : _showRational 30 d))
214 getData (StDouble d) = returnSUs (id, strImmLit ('0' : 'r' : ppShow 80 (ppRational d)))
216 getData (StDouble d) = returnSUs (id, strImmLit ('0' : 'r' : show d))
218 getData (StLitLbl s) = returnSUs (id, ImmLab s)
219 getData (StLitLit s) = returnSUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
220 getData (StString s) =
221 getUniqLabelNCG `thenSUs` \ lbl ->
222 returnSUs (mkSeqInstrs [LABEL lbl, ASCII True (_UNPK_ s)], ImmCLbl lbl)
223 getData (StCLbl l) = returnSUs (id, ImmCLbl l)
225 getCode (StCall fn VoidKind args) = genCCall fn VoidKind args
227 getCode (StComment s) = returnInstr (COMMENT s)
231 Generate code to get a subtree into a register.
235 getReg :: StixTree -> SUniqSM Register
237 getReg (StReg (StixMagicId stgreg)) =
238 case stgRegMap stgreg of
239 Just reg -> returnSUs (Fixed reg (kindFromMagicId stgreg) id)
242 getReg (StReg (StixTemp u pk)) = returnSUs (Fixed (UnmappedReg u pk) pk id)
244 getReg (StDouble d) =
245 getUniqLabelNCG `thenSUs` \ lbl ->
246 getNewRegNCG PtrKind `thenSUs` \ tmp ->
247 let code dst = mkSeqInstrs [
250 #if __GLASGOW_HASKELL__ >= 23
251 -- DATA DF [strImmLit ('0' : 'r' : (_showRational 30 d))],
252 DATA DF [strImmLit ('0' : 'r' : ppShow 80 (ppRational d))],
254 DATA DF [strImmLit ('0' : 'r' : (show d))],
257 SETHI (HI (ImmCLbl lbl)) tmp,
258 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
260 returnSUs (Any DoubleKind code)
262 getReg (StString s) =
263 getUniqLabelNCG `thenSUs` \ lbl ->
264 let code dst = mkSeqInstrs [
267 ASCII True (_UNPK_ s),
269 SETHI (HI (ImmCLbl lbl)) dst,
270 OR False dst (RIImm (LO (ImmCLbl lbl))) dst]
272 returnSUs (Any PtrKind code)
274 getReg (StLitLit s) | _HEAD_ s == '"' && last xs == '"' =
275 getUniqLabelNCG `thenSUs` \ lbl ->
276 let code dst = mkSeqInstrs [
279 ASCII False (init xs),
281 SETHI (HI (ImmCLbl lbl)) dst,
282 OR False dst (RIImm (LO (ImmCLbl lbl))) dst]
284 returnSUs (Any PtrKind code)
286 xs = _UNPK_ (_TAIL_ s)
288 getReg tree@(StIndex _ _ _) = getReg (mangleIndexTree tree)
290 getReg (StCall fn kind args) =
291 genCCall fn kind args `thenSUs` \ call ->
292 returnSUs (Fixed reg kind call)
294 reg = if isFloatingKind kind then f0 else o0
296 getReg (StPrim primop args) =
299 CharGtOp -> condIntReg GT args
300 CharGeOp -> condIntReg GE args
301 CharEqOp -> condIntReg EQ args
302 CharNeOp -> condIntReg NE args
303 CharLtOp -> condIntReg LT args
304 CharLeOp -> condIntReg LE args
306 IntAddOp -> trivialCode (ADD False False) args
308 IntSubOp -> trivialCode (SUB False False) args
309 IntMulOp -> call SLIT(".umul") IntKind
310 IntQuotOp -> call SLIT(".div") IntKind
311 IntDivOp -> call SLIT("stg_div") IntKind
312 IntRemOp -> call SLIT(".rem") IntKind
313 IntNegOp -> trivialUCode (SUB False False g0) args
314 IntAbsOp -> absIntCode args
316 AndOp -> trivialCode (AND False) args
317 OrOp -> trivialCode (OR False) args
318 NotOp -> trivialUCode (XNOR False g0) args
319 SllOp -> trivialCode SLL args
320 SraOp -> trivialCode SRA args
321 SrlOp -> trivialCode SRL args
322 ISllOp -> panic "SparcGen:isll"
323 ISraOp -> panic "SparcGen:isra"
324 ISrlOp -> panic "SparcGen:isrl"
326 IntGtOp -> condIntReg GT args
327 IntGeOp -> condIntReg GE args
328 IntEqOp -> condIntReg EQ args
329 IntNeOp -> condIntReg NE args
330 IntLtOp -> condIntReg LT args
331 IntLeOp -> condIntReg LE args
333 WordGtOp -> condIntReg GU args
334 WordGeOp -> condIntReg GEU args
335 WordEqOp -> condIntReg EQ args
336 WordNeOp -> condIntReg NE args
337 WordLtOp -> condIntReg LU args
338 WordLeOp -> condIntReg LEU args
340 AddrGtOp -> condIntReg GU args
341 AddrGeOp -> condIntReg GEU args
342 AddrEqOp -> condIntReg EQ args
343 AddrNeOp -> condIntReg NE args
344 AddrLtOp -> condIntReg LU args
345 AddrLeOp -> condIntReg LEU args
347 FloatAddOp -> trivialFCode FloatKind FADD args
348 FloatSubOp -> trivialFCode FloatKind FSUB args
349 FloatMulOp -> trivialFCode FloatKind FMUL args
350 FloatDivOp -> trivialFCode FloatKind FDIV args
351 FloatNegOp -> trivialUFCode FloatKind (FNEG F) args
353 FloatGtOp -> condFltReg GT args
354 FloatGeOp -> condFltReg GE args
355 FloatEqOp -> condFltReg EQ args
356 FloatNeOp -> condFltReg NE args
357 FloatLtOp -> condFltReg LT args
358 FloatLeOp -> condFltReg LE args
360 FloatExpOp -> promoteAndCall SLIT("exp") DoubleKind
361 FloatLogOp -> promoteAndCall SLIT("log") DoubleKind
362 FloatSqrtOp -> promoteAndCall SLIT("sqrt") DoubleKind
364 FloatSinOp -> promoteAndCall SLIT("sin") DoubleKind
365 FloatCosOp -> promoteAndCall SLIT("cos") DoubleKind
366 FloatTanOp -> promoteAndCall SLIT("tan") DoubleKind
368 FloatAsinOp -> promoteAndCall SLIT("asin") DoubleKind
369 FloatAcosOp -> promoteAndCall SLIT("acos") DoubleKind
370 FloatAtanOp -> promoteAndCall SLIT("atan") DoubleKind
372 FloatSinhOp -> promoteAndCall SLIT("sinh") DoubleKind
373 FloatCoshOp -> promoteAndCall SLIT("cosh") DoubleKind
374 FloatTanhOp -> promoteAndCall SLIT("tanh") DoubleKind
376 FloatPowerOp -> promoteAndCall SLIT("pow") DoubleKind
378 DoubleAddOp -> trivialFCode DoubleKind FADD args
379 DoubleSubOp -> trivialFCode DoubleKind FSUB args
380 DoubleMulOp -> trivialFCode DoubleKind FMUL args
381 DoubleDivOp -> trivialFCode DoubleKind FDIV args
382 DoubleNegOp -> trivialUFCode DoubleKind (FNEG DF) args
384 DoubleGtOp -> condFltReg GT args
385 DoubleGeOp -> condFltReg GE args
386 DoubleEqOp -> condFltReg EQ args
387 DoubleNeOp -> condFltReg NE args
388 DoubleLtOp -> condFltReg LT args
389 DoubleLeOp -> condFltReg LE args
391 DoubleExpOp -> call SLIT("exp") DoubleKind
392 DoubleLogOp -> call SLIT("log") DoubleKind
393 DoubleSqrtOp -> call SLIT("sqrt") DoubleKind
395 DoubleSinOp -> call SLIT("sin") DoubleKind
396 DoubleCosOp -> call SLIT("cos") DoubleKind
397 DoubleTanOp -> call SLIT("tan") DoubleKind
399 DoubleAsinOp -> call SLIT("asin") DoubleKind
400 DoubleAcosOp -> call SLIT("acos") DoubleKind
401 DoubleAtanOp -> call SLIT("atan") DoubleKind
403 DoubleSinhOp -> call SLIT("sinh") DoubleKind
404 DoubleCoshOp -> call SLIT("cosh") DoubleKind
405 DoubleTanhOp -> call SLIT("tanh") DoubleKind
407 DoublePowerOp -> call SLIT("pow") DoubleKind
409 OrdOp -> coerceIntCode IntKind args
410 ChrOp -> chrCode args
412 Float2IntOp -> coerceFP2Int args
413 Int2FloatOp -> coerceInt2FP FloatKind args
414 Double2IntOp -> coerceFP2Int args
415 Int2DoubleOp -> coerceInt2FP DoubleKind args
417 Double2FloatOp -> trivialUFCode FloatKind (FxTOy DF F) args
418 Float2DoubleOp -> trivialUFCode DoubleKind (FxTOy F DF) args
421 call fn pk = getReg (StCall fn pk args)
422 promoteAndCall fn pk = getReg (StCall fn pk (map promote args))
424 promote x = StPrim Float2DoubleOp [x]
426 getReg (StInd pk mem) =
427 getAmode mem `thenSUs` \ amode ->
429 code = amodeCode amode
430 src = amodeAddr amode
432 code__2 dst = code . mkSeqInstr (LD size src dst)
434 returnSUs (Any pk code__2)
439 src = ImmInt (fromInteger i)
440 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
442 returnSUs (Any IntKind code)
447 code dst = mkSeqInstrs [
448 SETHI (HI imm__2) dst,
449 OR False dst (RIImm (LO imm__2)) dst]
451 returnSUs (Any PtrKind code)
454 imm__2 = case imm of Just x -> x
458 Now, given a tree (the argument to an StInd) that references memory,
459 produce a suitable addressing mode.
463 getAmode :: StixTree -> SUniqSM Amode
465 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
467 getAmode (StPrim IntSubOp [x, StInt i])
469 getNewRegNCG PtrKind `thenSUs` \ tmp ->
470 getReg x `thenSUs` \ register ->
472 code = registerCode register tmp
473 reg = registerName register tmp
474 off = ImmInt (-(fromInteger i))
476 returnSUs (Amode (AddrRegImm reg off) code)
479 getAmode (StPrim IntAddOp [x, StInt i])
481 getNewRegNCG PtrKind `thenSUs` \ tmp ->
482 getReg x `thenSUs` \ register ->
484 code = registerCode register tmp
485 reg = registerName register tmp
486 off = ImmInt (fromInteger i)
488 returnSUs (Amode (AddrRegImm reg off) code)
490 getAmode (StPrim IntAddOp [x, y]) =
491 getNewRegNCG PtrKind `thenSUs` \ tmp1 ->
492 getNewRegNCG IntKind `thenSUs` \ tmp2 ->
493 getReg x `thenSUs` \ register1 ->
494 getReg y `thenSUs` \ register2 ->
496 code1 = registerCode register1 tmp1 asmVoid
497 reg1 = registerName register1 tmp1
498 code2 = registerCode register2 tmp2 asmVoid
499 reg2 = registerName register2 tmp2
500 code__2 = asmParThen [code1, code2]
502 returnSUs (Amode (AddrRegReg reg1 reg2) code__2)
506 getNewRegNCG PtrKind `thenSUs` \ tmp ->
508 code = mkSeqInstr (SETHI (HI imm__2) tmp)
510 returnSUs (Amode (AddrRegImm tmp (LO imm__2)) code)
513 imm__2 = case imm of Just x -> x
516 getNewRegNCG PtrKind `thenSUs` \ tmp ->
517 getReg other `thenSUs` \ register ->
519 code = registerCode register tmp
520 reg = registerName register tmp
523 returnSUs (Amode (AddrRegImm reg off) code)
527 Try to get a value into a specific register (or registers) for a call. The Sparc
528 calling convention is an absolute nightmare. The first 6x32 bits of arguments are
529 mapped into %o0 through %o5, and the remaining arguments are dumped to the stack,
530 beginning at [%sp+92]. (Note that %o6 == %sp.) Our first argument is a pair of
531 the list of remaining argument registers to be assigned for this call and the next
532 stack offset to use for overflowing arguments. This way, @getCallArg@ can be applied
533 to all of a call's arguments using @mapAccumL@.
538 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
539 -> StixTree -- Current argument
540 -> SUniqSM (([Reg],Int), CodeBlock SparcInstr) -- Updated accumulator and code
542 -- We have to use up all of our argument registers first.
544 getCallArg (dst:dsts, offset) arg =
545 getReg arg `thenSUs` \ register ->
546 getNewRegNCG (registerKind register)
549 reg = if isFloatingKind pk then tmp else dst
550 code = registerCode register reg
551 src = registerName register reg
552 pk = registerKind register
554 returnSUs (case pk of
557 [] -> (([], offset + 1), code . mkSeqInstrs [
558 -- conveniently put the second part in the right stack
559 -- location, and load the first part into %o5
560 ST DF src (spRel (offset - 1)),
561 LD W (spRel (offset - 1)) dst])
562 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
563 ST DF src (spRel (-2)),
564 LD W (spRel (-2)) dst,
565 LD W (spRel (-1)) dst__2])
566 FloatKind -> ((dsts, offset), code . mkSeqInstrs [
567 ST F src (spRel (-2)),
568 LD W (spRel (-2)) dst])
569 _ -> ((dsts, offset), if isFixed register then
570 code . mkSeqInstr (OR False g0 (RIReg src) dst)
573 -- Once we have run out of argument registers, we move to the stack
575 getCallArg ([], offset) arg =
576 getReg arg `thenSUs` \ register ->
577 getNewRegNCG (registerKind register)
580 code = registerCode register tmp
581 src = registerName register tmp
582 pk = registerKind register
584 words = if pk == DoubleKind then 2 else 1
586 returnSUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
590 Set up a condition code for a conditional branch.
594 getCondition :: StixTree -> SUniqSM Condition
596 getCondition (StPrim primop args) =
599 CharGtOp -> condIntCode GT args
600 CharGeOp -> condIntCode GE args
601 CharEqOp -> condIntCode EQ args
602 CharNeOp -> condIntCode NE args
603 CharLtOp -> condIntCode LT args
604 CharLeOp -> condIntCode LE args
606 IntGtOp -> condIntCode GT args
607 IntGeOp -> condIntCode GE args
608 IntEqOp -> condIntCode EQ args
609 IntNeOp -> condIntCode NE args
610 IntLtOp -> condIntCode LT args
611 IntLeOp -> condIntCode LE args
613 WordGtOp -> condIntCode GU args
614 WordGeOp -> condIntCode GEU args
615 WordEqOp -> condIntCode EQ args
616 WordNeOp -> condIntCode NE args
617 WordLtOp -> condIntCode LU args
618 WordLeOp -> condIntCode LEU args
620 AddrGtOp -> condIntCode GU args
621 AddrGeOp -> condIntCode GEU args
622 AddrEqOp -> condIntCode EQ args
623 AddrNeOp -> condIntCode NE args
624 AddrLtOp -> condIntCode LU args
625 AddrLeOp -> condIntCode LEU args
627 FloatGtOp -> condFltCode GT args
628 FloatGeOp -> condFltCode GE args
629 FloatEqOp -> condFltCode EQ args
630 FloatNeOp -> condFltCode NE args
631 FloatLtOp -> condFltCode LT args
632 FloatLeOp -> condFltCode LE args
634 DoubleGtOp -> condFltCode GT args
635 DoubleGeOp -> condFltCode GE args
636 DoubleEqOp -> condFltCode EQ args
637 DoubleNeOp -> condFltCode NE args
638 DoubleLtOp -> condFltCode LT args
639 DoubleLeOp -> condFltCode LE args
643 Turn a boolean expression into a condition, to be passed
648 condIntCode, condFltCode :: Cond -> [StixTree] -> SUniqSM Condition
650 condIntCode cond [x, StInt y]
652 getReg x `thenSUs` \ register ->
653 getNewRegNCG IntKind `thenSUs` \ tmp ->
655 code = registerCode register tmp
656 src1 = registerName register tmp
657 src2 = ImmInt (fromInteger y)
658 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
660 returnSUs (Condition False cond code__2)
662 condIntCode cond [x, y] =
663 getReg x `thenSUs` \ register1 ->
664 getReg y `thenSUs` \ register2 ->
665 getNewRegNCG IntKind `thenSUs` \ tmp1 ->
666 getNewRegNCG IntKind `thenSUs` \ tmp2 ->
668 code1 = registerCode register1 tmp1 asmVoid
669 src1 = registerName register1 tmp1
670 code2 = registerCode register2 tmp2 asmVoid
671 src2 = registerName register2 tmp2
672 code__2 = asmParThen [code1, code2] .
673 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
675 returnSUs (Condition False cond code__2)
677 condFltCode cond [x, y] =
678 getReg x `thenSUs` \ register1 ->
679 getReg y `thenSUs` \ register2 ->
680 getNewRegNCG (registerKind register1)
682 getNewRegNCG (registerKind register2)
684 getNewRegNCG DoubleKind `thenSUs` \ tmp ->
686 promote x = asmInstr (FxTOy F DF x tmp)
688 pk1 = registerKind register1
689 code1 = registerCode register1 tmp1
690 src1 = registerName register1 tmp1
692 pk2 = registerKind register2
693 code2 = registerCode register2 tmp2
694 src2 = registerName register2 tmp2
698 asmParThen [code1 asmVoid, code2 asmVoid] .
699 mkSeqInstr (FCMP True (kindToSize pk1) src1 src2)
700 else if pk1 == FloatKind then
701 asmParThen [code1 (promote src1), code2 asmVoid] .
702 mkSeqInstr (FCMP True DF tmp src2)
704 asmParThen [code1 asmVoid, code2 (promote src2)] .
705 mkSeqInstr (FCMP True DF src1 tmp)
707 returnSUs (Condition True cond code__2)
711 Turn those condition codes into integers now (when they appear on
712 the right hand side of an assignment).
714 Do not fill the delay slots here; you will confuse the register allocator.
718 condIntReg :: Cond -> [StixTree] -> SUniqSM Register
720 condIntReg EQ [x, StInt 0] =
721 getReg x `thenSUs` \ register ->
722 getNewRegNCG IntKind `thenSUs` \ tmp ->
724 code = registerCode register tmp
725 src = registerName register tmp
726 code__2 dst = code . mkSeqInstrs [
727 SUB False True g0 (RIReg src) g0,
728 SUB True False g0 (RIImm (ImmInt (-1))) dst]
730 returnSUs (Any IntKind code__2)
732 condIntReg EQ [x, y] =
733 getReg x `thenSUs` \ register1 ->
734 getReg y `thenSUs` \ register2 ->
735 getNewRegNCG IntKind `thenSUs` \ tmp1 ->
736 getNewRegNCG IntKind `thenSUs` \ tmp2 ->
738 code1 = registerCode register1 tmp1 asmVoid
739 src1 = registerName register1 tmp1
740 code2 = registerCode register2 tmp2 asmVoid
741 src2 = registerName register2 tmp2
742 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
743 XOR False src1 (RIReg src2) dst,
744 SUB False True g0 (RIReg dst) g0,
745 SUB True False g0 (RIImm (ImmInt (-1))) dst]
747 returnSUs (Any IntKind code__2)
749 condIntReg NE [x, StInt 0] =
750 getReg x `thenSUs` \ register ->
751 getNewRegNCG IntKind `thenSUs` \ tmp ->
753 code = registerCode register tmp
754 src = registerName register tmp
755 code__2 dst = code . mkSeqInstrs [
756 SUB False True g0 (RIReg src) g0,
757 ADD True False g0 (RIImm (ImmInt 0)) dst]
759 returnSUs (Any IntKind code__2)
761 condIntReg NE [x, y] =
762 getReg x `thenSUs` \ register1 ->
763 getReg y `thenSUs` \ register2 ->
764 getNewRegNCG IntKind `thenSUs` \ tmp1 ->
765 getNewRegNCG IntKind `thenSUs` \ tmp2 ->
767 code1 = registerCode register1 tmp1 asmVoid
768 src1 = registerName register1 tmp1
769 code2 = registerCode register2 tmp2 asmVoid
770 src2 = registerName register2 tmp2
771 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
772 XOR False src1 (RIReg src2) dst,
773 SUB False True g0 (RIReg dst) g0,
774 ADD True False g0 (RIImm (ImmInt 0)) dst]
776 returnSUs (Any IntKind code__2)
778 condIntReg cond args =
779 getUniqLabelNCG `thenSUs` \ lbl1 ->
780 getUniqLabelNCG `thenSUs` \ lbl2 ->
781 condIntCode cond args `thenSUs` \ condition ->
783 code = condCode condition
784 cond = condName condition
785 code__2 dst = code . mkSeqInstrs [
786 BI cond False (ImmCLbl lbl1), NOP,
787 OR False g0 (RIImm (ImmInt 0)) dst,
788 BI ALWAYS False (ImmCLbl lbl2), NOP,
790 OR False g0 (RIImm (ImmInt 1)) dst,
793 returnSUs (Any IntKind code__2)
795 condFltReg :: Cond -> [StixTree] -> SUniqSM Register
797 condFltReg cond args =
798 getUniqLabelNCG `thenSUs` \ lbl1 ->
799 getUniqLabelNCG `thenSUs` \ lbl2 ->
800 condFltCode cond args `thenSUs` \ condition ->
802 code = condCode condition
803 cond = condName condition
804 code__2 dst = code . mkSeqInstrs [
806 BF cond False (ImmCLbl lbl1), NOP,
807 OR False g0 (RIImm (ImmInt 0)) dst,
808 BI ALWAYS False (ImmCLbl lbl2), NOP,
810 OR False g0 (RIImm (ImmInt 1)) dst,
813 returnSUs (Any IntKind code__2)
817 Assignments are really at the heart of the whole code generation business.
818 Almost all top-level nodes of any real importance are assignments, which
819 correspond to loads, stores, or register transfers. If we're really lucky,
820 some of the register transfers will go away, because we can use the destination
821 register to complete the code generation for the right hand side. This only
822 fails when the right hand side is forced into a fixed register (e.g. the result
827 assignIntCode :: PrimKind -> StixTree -> StixTree -> SUniqSM (CodeBlock SparcInstr)
829 assignIntCode pk (StInd _ dst) src =
830 getNewRegNCG IntKind `thenSUs` \ tmp ->
831 getAmode dst `thenSUs` \ amode ->
832 getReg src `thenSUs` \ register ->
834 code1 = amodeCode amode asmVoid
835 dst__2 = amodeAddr amode
836 code2 = registerCode register tmp asmVoid
837 src__2 = registerName register tmp
839 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
843 assignIntCode pk dst src =
844 getReg dst `thenSUs` \ register1 ->
845 getReg src `thenSUs` \ register2 ->
847 dst__2 = registerName register1 g0
848 code = registerCode register2 dst__2
849 src__2 = registerName register2 dst__2
850 code__2 = if isFixed register2 then
851 code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
856 assignFltCode :: PrimKind -> StixTree -> StixTree -> SUniqSM (CodeBlock SparcInstr)
858 assignFltCode pk (StInd _ dst) src =
859 getNewRegNCG pk `thenSUs` \ tmp ->
860 getAmode dst `thenSUs` \ amode ->
861 getReg src `thenSUs` \ register ->
864 dst__2 = amodeAddr amode
866 code1 = amodeCode amode asmVoid
867 code2 = registerCode register tmp asmVoid
869 src__2 = registerName register tmp
870 pk__2 = registerKind register
871 sz__2 = kindToSize pk__2
873 code__2 = asmParThen [code1, code2] .
875 mkSeqInstr (ST sz src__2 dst__2)
877 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp, ST sz tmp dst__2]
881 assignFltCode pk dst src =
882 getReg dst `thenSUs` \ register1 ->
883 getReg src `thenSUs` \ register2 ->
884 getNewRegNCG (registerKind register2)
888 dst__2 = registerName register1 g0 -- must be Fixed
890 reg__2 = if pk /= pk__2 then tmp else dst__2
892 code = registerCode register2 reg__2
893 src__2 = registerName register2 reg__2
894 pk__2 = registerKind register2
895 sz__2 = kindToSize pk__2
897 code__2 = if pk /= pk__2 then code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
898 else if isFixed register2 then code . mkSeqInstr (FMOV sz src__2 dst__2)
905 Generating an unconditional branch. We accept two types of targets:
906 an immediate CLabel or a tree that gets evaluated into a register.
907 Any CLabels which are AsmTemporaries are assumed to be in the local
908 block of code, close enough for a branch instruction. Other CLabels
909 are assumed to be far away, so we use call.
911 Do not fill the delay slots here; you will confuse the register allocator.
916 :: StixTree -- the branch target
917 -> SUniqSM (CodeBlock SparcInstr)
920 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
921 | otherwise = returnInstrs [CALL target 0 True, NOP]
926 getReg tree `thenSUs` \ register ->
927 getNewRegNCG PtrKind `thenSUs` \ tmp ->
929 code = registerCode register tmp
930 target = registerName register tmp
932 returnSeq code [JMP (AddrRegReg target g0), NOP]
936 Conditional jumps are always to local labels, so we can use
937 branch instructions. First, we have to ensure that the condition
938 codes are set according to the supplied comparison operation.
939 We generate slightly different code for floating point comparisons,
940 because a floating point operation cannot directly precede a @BF@.
941 We assume the worst and fill that slot with a @NOP@.
943 Do not fill the delay slots here; you will confuse the register allocator.
948 :: CLabel -- the branch target
949 -> StixTree -- the condition on which to branch
950 -> SUniqSM (CodeBlock SparcInstr)
952 genCondJump lbl bool =
953 getCondition bool `thenSUs` \ condition ->
955 code = condCode condition
956 cond = condName condition
959 if condFloat condition then
960 returnSeq code [NOP, BF cond False target, NOP]
962 returnSeq code [BI cond False target, NOP]
966 Now the biggest nightmare---calls. Most of the nastiness is buried in
967 getCallArg, which moves the arguments to the correct registers/stack
968 locations. Apart from that, the code is easy.
970 Do not fill the delay slots here; you will confuse the register allocator.
975 :: FAST_STRING -- function to call
976 -> PrimKind -- type of the result
977 -> [StixTree] -- arguments (of mixed type)
978 -> SUniqSM (CodeBlock SparcInstr)
980 genCCall fn kind args =
981 mapAccumLNCG getCallArg (argRegs,stackArgLoc) args
982 `thenSUs` \ ((unused,_), argCode) ->
984 nRegs = length argRegs - length unused
985 call = CALL fn__2 nRegs False
986 code = asmParThen (map ($ asmVoid) argCode)
988 returnSeq code [call, NOP]
990 -- function names that begin with '.' are assumed to be special internally
991 -- generated names like '.mul,' which don't get an underscore prefix
992 fn__2 = case (_HEAD_ fn) of
993 '.' -> ImmLit (uppPStr fn)
994 _ -> ImmLab (uppPStr fn)
996 mapAccumLNCG f b [] = returnSUs (b, [])
997 mapAccumLNCG f b (x:xs) =
998 f b x `thenSUs` \ (b__2, x__2) ->
999 mapAccumLNCG f b__2 xs `thenSUs` \ (b__3, xs__2) ->
1000 returnSUs (b__3, x__2:xs__2)
1004 Trivial (dyadic) instructions. Only look for constants on the right hand
1005 side, because that's where the generic optimizer will have put them.
1010 :: (Reg -> RI -> Reg -> SparcInstr)
1014 trivialCode instr [x, StInt y]
1016 getReg x `thenSUs` \ register ->
1017 getNewRegNCG IntKind `thenSUs` \ tmp ->
1019 code = registerCode register tmp
1020 src1 = registerName register tmp
1021 src2 = ImmInt (fromInteger y)
1022 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
1024 returnSUs (Any IntKind code__2)
1026 trivialCode instr [x, y] =
1027 getReg x `thenSUs` \ register1 ->
1028 getReg y `thenSUs` \ register2 ->
1029 getNewRegNCG IntKind `thenSUs` \ tmp1 ->
1030 getNewRegNCG IntKind `thenSUs` \ tmp2 ->
1032 code1 = registerCode register1 tmp1 asmVoid
1033 src1 = registerName register1 tmp1
1034 code2 = registerCode register2 tmp2 asmVoid
1035 src2 = registerName register2 tmp2
1036 code__2 dst = asmParThen [code1, code2] .
1037 mkSeqInstr (instr src1 (RIReg src2) dst)
1039 returnSUs (Any IntKind code__2)
1043 -> (Size -> Reg -> Reg -> Reg -> SparcInstr)
1047 trivialFCode pk instr [x, y] =
1048 getReg x `thenSUs` \ register1 ->
1049 getReg y `thenSUs` \ register2 ->
1050 getNewRegNCG (registerKind register1)
1052 getNewRegNCG (registerKind register2)
1054 getNewRegNCG DoubleKind `thenSUs` \ tmp ->
1056 promote x = asmInstr (FxTOy F DF x tmp)
1058 pk1 = registerKind register1
1059 code1 = registerCode register1 tmp1
1060 src1 = registerName register1 tmp1
1062 pk2 = registerKind register2
1063 code2 = registerCode register2 tmp2
1064 src2 = registerName register2 tmp2
1068 asmParThen [code1 asmVoid, code2 asmVoid] .
1069 mkSeqInstr (instr (kindToSize pk) src1 src2 dst)
1070 else if pk1 == FloatKind then
1071 asmParThen [code1 (promote src1), code2 asmVoid] .
1072 mkSeqInstr (instr DF tmp src2 dst)
1074 asmParThen [code1 asmVoid, code2 (promote src2)] .
1075 mkSeqInstr (instr DF src1 tmp dst)
1077 returnSUs (Any (if pk1 == pk2 then pk1 else DoubleKind) code__2)
1081 Trivial unary instructions. Note that we don't have to worry about
1082 matching an StInt as the argument, because genericOpt will already
1083 have handled the constant-folding.
1088 :: (RI -> Reg -> SparcInstr)
1092 trivialUCode instr [x] =
1093 getReg x `thenSUs` \ register ->
1094 getNewRegNCG IntKind `thenSUs` \ tmp ->
1096 code = registerCode register tmp
1097 src = registerName register tmp
1098 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
1100 returnSUs (Any IntKind code__2)
1104 -> (Reg -> Reg -> SparcInstr)
1108 trivialUFCode pk instr [x] =
1109 getReg x `thenSUs` \ register ->
1110 getNewRegNCG pk `thenSUs` \ tmp ->
1112 code = registerCode register tmp
1113 src = registerName register tmp
1114 code__2 dst = code . mkSeqInstr (instr src dst)
1116 returnSUs (Any pk code__2)
1120 Absolute value on integers, mostly for gmp size check macros. Again,
1121 the argument cannot be an StInt, because genericOpt already folded
1124 Do not fill the delay slots here; you will confuse the register allocator.
1128 absIntCode :: [StixTree] -> SUniqSM Register
1130 getReg x `thenSUs` \ register ->
1131 getNewRegNCG IntKind `thenSUs` \ reg ->
1132 getUniqLabelNCG `thenSUs` \ lbl ->
1134 code = registerCode register reg
1135 src = registerName register reg
1136 code__2 dst = code . mkSeqInstrs [
1137 SUB False True g0 (RIReg src) dst,
1138 BI GE False (ImmCLbl lbl), NOP,
1139 OR False g0 (RIReg src) dst,
1142 returnSUs (Any IntKind code__2)
1146 Simple integer coercions that don't require any code to be generated.
1147 Here we just change the type on the register passed on up
1151 coerceIntCode :: PrimKind -> [StixTree] -> SUniqSM Register
1152 coerceIntCode pk [x] =
1153 getReg x `thenSUs` \ register ->
1155 Fixed reg _ code -> returnSUs (Fixed reg pk code)
1156 Any _ code -> returnSUs (Any pk code)
1160 Integer to character conversion. We try to do this in one step if
1161 the original object is in memory.
1165 chrCode :: [StixTree] -> SUniqSM Register
1166 chrCode [StInd pk mem] =
1167 getAmode mem `thenSUs` \ amode ->
1169 code = amodeCode amode
1170 src = amodeAddr amode
1171 srcOff = offset src 3
1172 src__2 = case srcOff of Just x -> x
1173 code__2 dst = if maybeToBool srcOff then
1174 code . mkSeqInstr (LD UB src__2 dst)
1176 code . mkSeqInstrs [
1177 LD (kindToSize pk) src dst,
1178 AND False dst (RIImm (ImmInt 255)) dst]
1180 returnSUs (Any pk code__2)
1183 getReg x `thenSUs` \ register ->
1184 getNewRegNCG IntKind `thenSUs` \ reg ->
1186 code = registerCode register reg
1187 src = registerName register reg
1188 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
1190 returnSUs (Any IntKind code__2)
1194 More complicated integer/float conversions. Here we have to store
1195 temporaries in memory to move between the integer and the floating
1196 point register sets.
1200 coerceInt2FP :: PrimKind -> [StixTree] -> SUniqSM Register
1201 coerceInt2FP pk [x] =
1202 getReg x `thenSUs` \ register ->
1203 getNewRegNCG IntKind `thenSUs` \ reg ->
1205 code = registerCode register reg
1206 src = registerName register reg
1208 code__2 dst = code . mkSeqInstrs [
1209 ST W src (spRel (-2)),
1210 LD W (spRel (-2)) dst,
1211 FxTOy W (kindToSize pk) dst dst]
1213 returnSUs (Any pk code__2)
1215 coerceFP2Int :: [StixTree] -> SUniqSM Register
1217 getReg x `thenSUs` \ register ->
1218 getNewRegNCG IntKind `thenSUs` \ reg ->
1219 getNewRegNCG FloatKind `thenSUs` \ tmp ->
1221 code = registerCode register reg
1222 src = registerName register reg
1223 pk = registerKind register
1225 code__2 dst = code . mkSeqInstrs [
1226 FxTOy (kindToSize pk) W src tmp,
1227 ST W tmp (spRel (-2)),
1228 LD W (spRel (-2)) dst]
1230 returnSUs (Any IntKind code__2)
1234 Some random little helpers.
1238 maybeImm :: StixTree -> Maybe Imm
1240 | i >= toInteger minInt && i <= toInteger maxInt = Just (ImmInt (fromInteger i))
1241 | otherwise = Just (ImmInteger i)
1242 maybeImm (StLitLbl s) = Just (ImmLab s)
1243 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
1244 maybeImm (StCLbl l) = Just (ImmCLbl l)
1245 maybeImm _ = Nothing
1247 mangleIndexTree :: StixTree -> StixTree
1249 mangleIndexTree (StIndex pk base (StInt i)) =
1250 StPrim IntAddOp [base, off]
1252 off = StInt (i * size pk)
1253 size :: PrimKind -> Integer
1254 size pk = case kindToSize pk of
1255 {SB -> 1; UB -> 1; HW -> 2; UHW -> 2; W -> 4; D -> 8; F -> 4; DF -> 8}
1257 mangleIndexTree (StIndex pk base off) =
1259 CharKind -> StPrim IntAddOp [base, off]
1260 _ -> StPrim IntAddOp [base, off__2]
1262 off__2 = StPrim SllOp [off, StInt (shift pk)]
1263 shift :: PrimKind -> Integer
1264 shift DoubleKind = 3
1267 cvtLitLit :: String -> String
1268 cvtLitLit "stdin" = "__iob+0x0" -- This one is probably okay...
1269 cvtLitLit "stdout" = "__iob+0x14" -- but these next two are dodgy at best
1270 cvtLitLit "stderr" = "__iob+0x28"
1273 | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
1275 isHex ('0':'x':xs) = all isHexDigit xs
1277 -- Now, where have I seen this before?
1278 isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
1283 spRel gives us a stack relative addressing mode for volatile temporaries
1284 and for excess call arguments.
1289 :: Int -- desired stack offset in words, positive or negative
1291 spRel n = AddrRegImm sp (ImmInt (n * 4))
1293 stackArgLoc = 23 :: Int -- where to stack extra call arguments (beyond 6x32 bits)
1299 getNewRegNCG :: PrimKind -> SUniqSM Reg
1301 getSUnique `thenSUs` \ u ->
1302 returnSUs (mkReg u pk)