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, extractMappedRegNos, mkReg,
23 Reg(..), RegLiveness(..), RegUsage(..), FutureLive(..),
24 MachineRegisters(..), MachineCode(..)
26 import CLabelInfo ( CLabel, isAsmTemp )
27 import AlphaCode {- 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[AlphaCodeGen]{Generating Alpha Code}
49 %************************************************************************
51 This is the top-level code-generation function for the Alpha.
55 alphaCodeGen :: PprStyle -> [[StixTree]] -> SUniqSM Unpretty
56 alphaCodeGen sty trees =
57 mapSUs genAlphaCode trees `thenSUs` \ dynamicCodes ->
59 staticCodes = scheduleAlphaCode 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 scheduleAlphaCode :: [AlphaCode] -> [AlphaInstr]
73 scheduleAlphaCode = concat . map (runRegAllocate freeAlphaRegs reservedRegs)
75 freeAlphaRegs :: AlphaRegs
76 freeAlphaRegs = mkMRegs (extractMappedRegNos freeRegs)
80 Registers passed up the tree. If the stix code forces the register
81 to live in a pre-decided machine register, it comes out as @Fixed@;
82 otherwise, it comes out as @Any@, and the parent can decide which
83 register to put it in.
88 = Fixed Reg PrimKind (CodeBlock AlphaInstr)
89 | Any PrimKind (Reg -> (CodeBlock AlphaInstr))
91 registerCode :: Register -> Reg -> CodeBlock AlphaInstr
92 registerCode (Fixed _ _ code) reg = code
93 registerCode (Any _ code) reg = code reg
95 registerName :: Register -> Reg -> Reg
96 registerName (Fixed reg _ _) _ = reg
97 registerName (Any _ _) reg = reg
99 registerKind :: Register -> PrimKind
100 registerKind (Fixed _ pk _) = pk
101 registerKind (Any pk _) = pk
103 isFixed :: Register -> Bool
104 isFixed (Fixed _ _ _) = True
105 isFixed (Any _ _) = False
109 Memory addressing modes passed up the tree.
113 data Amode = Amode Addr (CodeBlock AlphaInstr)
115 amodeAddr (Amode addr _) = addr
116 amodeCode (Amode _ code) = code
120 General things for putting together code sequences.
124 asmVoid :: OrdList AlphaInstr
125 asmVoid = mkEmptyList
127 asmInstr :: AlphaInstr -> AlphaCode
128 asmInstr i = mkUnitList i
130 asmSeq :: [AlphaInstr] -> AlphaCode
131 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
133 asmParThen :: [AlphaCode] -> CodeBlock AlphaInstr
134 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
136 returnInstr :: AlphaInstr -> SUniqSM (CodeBlock AlphaInstr)
137 returnInstr instr = returnSUs (\xs -> mkSeqList (asmInstr instr) xs)
139 returnInstrs :: [AlphaInstr] -> SUniqSM (CodeBlock AlphaInstr)
140 returnInstrs instrs = returnSUs (\xs -> mkSeqList (asmSeq instrs) xs)
142 returnSeq :: (CodeBlock AlphaInstr) -> [AlphaInstr] -> SUniqSM (CodeBlock AlphaInstr)
143 returnSeq code instrs = returnSUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
145 mkSeqInstr :: AlphaInstr -> (CodeBlock AlphaInstr)
146 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
148 mkSeqInstrs :: [AlphaInstr] -> (CodeBlock AlphaInstr)
149 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
153 Top level alpha code generator for a chunk of stix code.
157 genAlphaCode :: [StixTree] -> SUniqSM (AlphaCode)
160 mapSUs getCode trees `thenSUs` \ blocks ->
161 returnSUs (foldr (.) id blocks asmVoid)
165 Code extractor for an entire stix tree---stix statement level.
170 :: StixTree -- a stix statement
171 -> SUniqSM (CodeBlock AlphaInstr)
173 getCode (StSegment seg) = returnInstr (SEGMENT seg)
175 getCode (StAssign pk dst src)
176 | isFloatingKind pk = assignFltCode pk dst src
177 | otherwise = assignIntCode pk dst src
179 getCode (StLabel lab) = returnInstr (LABEL lab)
181 getCode (StFunBegin lab) = returnInstr (FUNBEGIN lab)
183 getCode (StFunEnd lab) = returnInstr (FUNEND lab)
185 getCode (StJump arg) = genJump arg
187 -- When falling through on the alpha, we still have to load pv with the
188 -- address of the next routine, so that it can load gp
189 getCode (StFallThrough lbl) = returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
191 getCode (StCondJump lbl arg) = genCondJump lbl arg
193 getCode (StData kind args) =
194 mapAndUnzipSUs getData args `thenSUs` \ (codes, imms) ->
195 returnSUs (\xs -> mkSeqList (asmInstr (DATA (kindToSize kind) imms))
196 (foldr1 (.) codes xs))
198 getData :: StixTree -> SUniqSM (CodeBlock AlphaInstr, Imm)
199 getData (StInt i) = returnSUs (id, ImmInteger i)
200 #if __GLASGOW_HASKELL__ >= 23
201 -- getData (StDouble d) = returnSUs (id, strImmLab (_showRational 30 d))
202 getData (StDouble d) = returnSUs (id, ImmLab (prettyToUn (ppRational d)))
204 getData (StDouble d) = returnSUs (id, strImmLab (show d))
206 getData (StLitLbl s) = returnSUs (id, ImmLab s)
207 getData (StLitLit s) = returnSUs (id, strImmLab (cvtLitLit (_UNPK_ s)))
208 getData (StString s) =
209 getUniqLabelNCG `thenSUs` \ lbl ->
210 returnSUs (mkSeqInstrs [LABEL lbl, ASCII True (_UNPK_ s)], ImmCLbl lbl)
211 getData (StCLbl l) = returnSUs (id, ImmCLbl l)
213 getCode (StCall fn VoidKind args) = genCCall fn VoidKind args
215 getCode (StComment s) = returnInstr (COMMENT s)
219 Generate code to get a subtree into a register.
223 getReg :: StixTree -> SUniqSM Register
225 getReg (StReg (StixMagicId stgreg)) =
226 case stgRegMap stgreg of
227 Just reg -> returnSUs (Fixed reg (kindFromMagicId stgreg) id)
230 getReg (StReg (StixTemp u pk)) = returnSUs (Fixed (UnmappedReg u pk) pk id)
232 getReg (StDouble d) =
233 getUniqLabelNCG `thenSUs` \ lbl ->
234 getNewRegNCG PtrKind `thenSUs` \ tmp ->
235 let code dst = mkSeqInstrs [
238 #if __GLASGOW_HASKELL__ >= 23
239 -- DATA TF [strImmLab (_showRational 30 d)],
240 DATA TF [ImmLab (prettyToUn (ppRational d))],
242 DATA TF [strImmLab (show d)],
245 LDA tmp (AddrImm (ImmCLbl lbl)),
246 LD TF dst (AddrReg tmp)]
248 returnSUs (Any DoubleKind code)
250 getReg (StString s) =
251 getUniqLabelNCG `thenSUs` \ lbl ->
252 let code dst = mkSeqInstrs [
255 ASCII True (_UNPK_ s),
257 LDA dst (AddrImm (ImmCLbl lbl))]
259 returnSUs (Any PtrKind code)
261 getReg (StLitLit s) | _HEAD_ s == '"' && last xs == '"' =
262 getUniqLabelNCG `thenSUs` \ lbl ->
263 let code dst = mkSeqInstrs [
266 ASCII False (init xs),
268 LDA dst (AddrImm (ImmCLbl lbl))]
270 returnSUs (Any PtrKind code)
272 xs = _UNPK_ (_TAIL_ s)
274 getReg tree@(StIndex _ _ _) = getReg (mangleIndexTree tree)
276 getReg (StCall fn kind args) =
277 genCCall fn kind args `thenSUs` \ call ->
278 returnSUs (Fixed reg kind call)
280 reg = if isFloatingKind kind then f0 else v0
282 getReg (StPrim primop args) =
285 CharGtOp -> case args of [x,y] -> trivialCode (CMP LT) [y,x]
286 CharGeOp -> case args of [x,y] -> trivialCode (CMP LE) [y,x]
287 CharEqOp -> trivialCode (CMP EQ) args
288 CharNeOp -> intNECode args
289 CharLtOp -> trivialCode (CMP LT) args
290 CharLeOp -> trivialCode (CMP LE) args
292 IntAddOp -> trivialCode (ADD Q False) args
294 IntSubOp -> trivialCode (SUB Q False) args
295 IntMulOp -> trivialCode (MUL Q False) args
296 IntQuotOp -> trivialCode (DIV Q False) args
297 IntRemOp -> trivialCode (REM Q False) args
298 IntNegOp -> trivialUCode (NEG Q False) args
299 IntAbsOp -> trivialUCode (ABS Q) args
301 AndOp -> trivialCode AND args
302 OrOp -> trivialCode OR args
303 NotOp -> trivialUCode NOT args
304 SllOp -> trivialCode SLL args
305 SraOp -> trivialCode SRA args
306 SrlOp -> trivialCode SRL args
307 ISllOp -> panic "AlphaGen:isll"
308 ISraOp -> panic "AlphaGen:isra"
309 ISrlOp -> panic "AlphaGen:isrl"
311 IntGtOp -> case args of [x,y] -> trivialCode (CMP LT) [y,x]
312 IntGeOp -> case args of [x,y] -> trivialCode (CMP LE) [y,x]
313 IntEqOp -> trivialCode (CMP EQ) args
314 IntNeOp -> intNECode args
315 IntLtOp -> trivialCode (CMP LT) args
316 IntLeOp -> trivialCode (CMP LE) args
318 WordGtOp -> case args of [x,y] -> trivialCode (CMP ULT) [y,x]
319 WordGeOp -> case args of [x,y] -> trivialCode (CMP ULE) [y,x]
320 WordEqOp -> trivialCode (CMP EQ) args
321 WordNeOp -> intNECode args
322 WordLtOp -> trivialCode (CMP ULT) args
323 WordLeOp -> trivialCode (CMP ULE) args
325 AddrGtOp -> case args of [x,y] -> trivialCode (CMP ULT) [y,x]
326 AddrGeOp -> case args of [x,y] -> trivialCode (CMP ULE) [y,x]
327 AddrEqOp -> trivialCode (CMP EQ) args
328 AddrNeOp -> intNECode args
329 AddrLtOp -> trivialCode (CMP ULT) args
330 AddrLeOp -> trivialCode (CMP ULE) args
332 FloatAddOp -> trivialFCode (FADD TF) args
333 FloatSubOp -> trivialFCode (FSUB TF) args
334 FloatMulOp -> trivialFCode (FMUL TF) args
335 FloatDivOp -> trivialFCode (FDIV TF) args
336 FloatNegOp -> trivialUFCode (FNEG TF) args
338 FloatGtOp -> cmpFCode (FCMP TF LE) EQ args
339 FloatGeOp -> cmpFCode (FCMP TF LT) EQ args
340 FloatEqOp -> cmpFCode (FCMP TF EQ) NE args
341 FloatNeOp -> cmpFCode (FCMP TF EQ) EQ args
342 FloatLtOp -> cmpFCode (FCMP TF LT) NE args
343 FloatLeOp -> cmpFCode (FCMP TF LE) NE args
345 FloatExpOp -> call SLIT("exp") DoubleKind
346 FloatLogOp -> call SLIT("log") DoubleKind
347 FloatSqrtOp -> call SLIT("sqrt") DoubleKind
349 FloatSinOp -> call SLIT("sin") DoubleKind
350 FloatCosOp -> call SLIT("cos") DoubleKind
351 FloatTanOp -> call SLIT("tan") DoubleKind
353 FloatAsinOp -> call SLIT("asin") DoubleKind
354 FloatAcosOp -> call SLIT("acos") DoubleKind
355 FloatAtanOp -> call SLIT("atan") DoubleKind
357 FloatSinhOp -> call SLIT("sinh") DoubleKind
358 FloatCoshOp -> call SLIT("cosh") DoubleKind
359 FloatTanhOp -> call SLIT("tanh") DoubleKind
361 FloatPowerOp -> call SLIT("pow") DoubleKind
363 DoubleAddOp -> trivialFCode (FADD TF) args
364 DoubleSubOp -> trivialFCode (FSUB TF) args
365 DoubleMulOp -> trivialFCode (FMUL TF) args
366 DoubleDivOp -> trivialFCode (FDIV TF) args
367 DoubleNegOp -> trivialUFCode (FNEG TF) args
369 DoubleGtOp -> cmpFCode (FCMP TF LE) EQ args
370 DoubleGeOp -> cmpFCode (FCMP TF LT) EQ args
371 DoubleEqOp -> cmpFCode (FCMP TF EQ) NE args
372 DoubleNeOp -> cmpFCode (FCMP TF EQ) EQ args
373 DoubleLtOp -> cmpFCode (FCMP TF LT) NE args
374 DoubleLeOp -> cmpFCode (FCMP TF LE) NE args
376 DoubleExpOp -> call SLIT("exp") DoubleKind
377 DoubleLogOp -> call SLIT("log") DoubleKind
378 DoubleSqrtOp -> call SLIT("sqrt") DoubleKind
380 DoubleSinOp -> call SLIT("sin") DoubleKind
381 DoubleCosOp -> call SLIT("cos") DoubleKind
382 DoubleTanOp -> call SLIT("tan") DoubleKind
384 DoubleAsinOp -> call SLIT("asin") DoubleKind
385 DoubleAcosOp -> call SLIT("acos") DoubleKind
386 DoubleAtanOp -> call SLIT("atan") DoubleKind
388 DoubleSinhOp -> call SLIT("sinh") DoubleKind
389 DoubleCoshOp -> call SLIT("cosh") DoubleKind
390 DoubleTanhOp -> call SLIT("tanh") DoubleKind
392 DoublePowerOp -> call SLIT("pow") DoubleKind
394 OrdOp -> coerceIntCode IntKind args
395 ChrOp -> chrCode args
397 Float2IntOp -> coerceFP2Int args
398 Int2FloatOp -> coerceInt2FP args
399 Double2IntOp -> coerceFP2Int args
400 Int2DoubleOp -> coerceInt2FP args
402 Double2FloatOp -> coerceFltCode args
403 Float2DoubleOp -> coerceFltCode args
406 call fn pk = getReg (StCall fn pk args)
408 getReg (StInd pk mem) =
409 getAmode mem `thenSUs` \ amode ->
411 code = amodeCode amode
412 src = amodeAddr amode
414 code__2 dst = code . mkSeqInstr (LD size dst src)
416 returnSUs (Any pk code__2)
421 code dst = mkSeqInstr (OR zero (RIImm src) dst)
423 returnSUs (Any IntKind code)
426 code dst = mkSeqInstr (LDI Q dst src)
428 returnSUs (Any IntKind code)
430 src = ImmInt (fromInteger i)
435 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
437 returnSUs (Any PtrKind code)
440 imm__2 = case imm of Just x -> x
444 Now, given a tree (the argument to an StInd) that references memory,
445 produce a suitable addressing mode.
449 getAmode :: StixTree -> SUniqSM Amode
451 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
453 getAmode (StPrim IntSubOp [x, StInt i]) =
454 getNewRegNCG PtrKind `thenSUs` \ tmp ->
455 getReg x `thenSUs` \ register ->
457 code = registerCode register tmp
458 reg = registerName register tmp
459 off = ImmInt (-(fromInteger i))
461 returnSUs (Amode (AddrRegImm reg off) code)
464 getAmode (StPrim IntAddOp [x, StInt i]) =
465 getNewRegNCG PtrKind `thenSUs` \ tmp ->
466 getReg x `thenSUs` \ register ->
468 code = registerCode register tmp
469 reg = registerName register tmp
470 off = ImmInt (fromInteger i)
472 returnSUs (Amode (AddrRegImm reg off) code)
476 returnSUs (Amode (AddrImm imm__2) id)
479 imm__2 = case imm of Just x -> x
482 getNewRegNCG PtrKind `thenSUs` \ tmp ->
483 getReg other `thenSUs` \ register ->
485 code = registerCode register tmp
486 reg = registerName register tmp
488 returnSUs (Amode (AddrReg reg) code)
492 Try to get a value into a specific register (or registers) for a call.
493 The first 6 arguments go into the appropriate argument register
494 (separate registers for integer and floating point arguments, but used
495 in lock-step), and the remaining arguments are dumped to the stack,
496 beginning at 0(sp). Our first argument is a pair of the list of
497 remaining argument registers to be assigned for this call and the next
498 stack offset to use for overflowing arguments. This way, @getCallArg@
499 can be applied to all of a call's arguments using @mapAccumL@.
504 :: ([(Reg,Reg)],Int) -- Argument registers and stack offset (accumulator)
505 -> StixTree -- Current argument
506 -> SUniqSM (([(Reg,Reg)],Int), CodeBlock AlphaInstr) -- Updated accumulator and code
508 -- We have to use up all of our argument registers first.
510 getCallArg ((iDst,fDst):dsts, offset) arg =
511 getReg arg `thenSUs` \ register ->
513 reg = if isFloatingKind pk then fDst else iDst
514 code = registerCode register reg
515 src = registerName register reg
516 pk = registerKind register
519 if isFloatingKind pk then
520 ((dsts, offset), if isFixed register then
521 code . mkSeqInstr (FMOV src fDst)
524 ((dsts, offset), if isFixed register then
525 code . mkSeqInstr (OR src (RIReg src) iDst)
528 -- Once we have run out of argument registers, we move to the stack
530 getCallArg ([], offset) arg =
531 getReg arg `thenSUs` \ register ->
532 getNewRegNCG (registerKind register)
535 code = registerCode register tmp
536 src = registerName register tmp
537 pk = registerKind register
540 returnSUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
544 Assignments are really at the heart of the whole code generation business.
545 Almost all top-level nodes of any real importance are assignments, which
546 correspond to loads, stores, or register transfers. If we're really lucky,
547 some of the register transfers will go away, because we can use the destination
548 register to complete the code generation for the right hand side. This only
549 fails when the right hand side is forced into a fixed register (e.g. the result
554 assignIntCode :: PrimKind -> StixTree -> StixTree -> SUniqSM (CodeBlock AlphaInstr)
556 assignIntCode pk (StInd _ dst) src =
557 getNewRegNCG IntKind `thenSUs` \ tmp ->
558 getAmode dst `thenSUs` \ amode ->
559 getReg src `thenSUs` \ register ->
561 code1 = amodeCode amode asmVoid
562 dst__2 = amodeAddr amode
563 code2 = registerCode register tmp asmVoid
564 src__2 = registerName register tmp
566 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
570 assignIntCode pk dst src =
571 getReg dst `thenSUs` \ register1 ->
572 getReg src `thenSUs` \ register2 ->
574 dst__2 = registerName register1 zero
575 code = registerCode register2 dst__2
576 src__2 = registerName register2 dst__2
577 code__2 = if isFixed register2 then
578 code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
583 assignFltCode :: PrimKind -> StixTree -> StixTree -> SUniqSM (CodeBlock AlphaInstr)
585 assignFltCode pk (StInd _ dst) src =
586 getNewRegNCG pk `thenSUs` \ tmp ->
587 getAmode dst `thenSUs` \ amode ->
588 getReg src `thenSUs` \ register ->
590 code1 = amodeCode amode asmVoid
591 dst__2 = amodeAddr amode
592 code2 = registerCode register tmp asmVoid
593 src__2 = registerName register tmp
595 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
599 assignFltCode pk dst src =
600 getReg dst `thenSUs` \ register1 ->
601 getReg src `thenSUs` \ register2 ->
603 dst__2 = registerName register1 zero
604 code = registerCode register2 dst__2
605 src__2 = registerName register2 dst__2
606 code__2 = if isFixed register2 then
607 code . mkSeqInstr (FMOV src__2 dst__2)
614 Generating an unconditional branch. We accept two types of targets:
615 an immediate CLabel or a tree that gets evaluated into a register.
616 Any CLabels which are AsmTemporaries are assumed to be in the local
617 block of code, close enough for a branch instruction. Other CLabels
618 are assumed to be far away, so we use jmp.
623 :: StixTree -- the branch target
624 -> SUniqSM (CodeBlock AlphaInstr)
627 | isAsmTemp lbl = returnInstr (BR target)
628 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zero (AddrReg pv) 0]
633 getReg tree `thenSUs` \ register ->
634 getNewRegNCG PtrKind `thenSUs` \ tmp ->
636 dst = registerName register pv
637 code = registerCode register pv
638 target = registerName register pv
640 if isFixed register then
641 returnSeq code [OR dst (RIReg dst) pv, JMP zero (AddrReg pv) 0]
643 returnSUs (code . mkSeqInstr (JMP zero (AddrReg pv) 0))
647 Conditional jumps are always to local labels, so we can use
648 branch instructions. We peek at the arguments to decide what kind
649 of comparison to do. For comparisons with 0, we're laughing, because
650 we can just do the desired conditional branch.
655 :: CLabel -- the branch target
656 -> StixTree -- the condition on which to branch
657 -> SUniqSM (CodeBlock AlphaInstr)
659 genCondJump lbl (StPrim op [x, StInt 0]) =
660 getReg x `thenSUs` \ register ->
661 getNewRegNCG (registerKind register)
664 code = registerCode register tmp
665 value = registerName register tmp
666 pk = registerKind register
669 returnSeq code [BI (cmpOp op) value target]
684 cmpOp WordGeOp = ALWAYS
687 cmpOp WordLtOp = NEVER
690 cmpOp AddrGeOp = ALWAYS
693 cmpOp AddrLtOp = NEVER
696 genCondJump lbl (StPrim op [x, StDouble 0.0]) =
697 getReg x `thenSUs` \ register ->
698 getNewRegNCG (registerKind register)
701 code = registerCode register tmp
702 value = registerName register tmp
703 pk = registerKind register
706 returnSUs (code . mkSeqInstr (BF (cmpOp op) value target))
714 cmpOp DoubleGtOp = GT
715 cmpOp DoubleGeOp = GE
716 cmpOp DoubleEqOp = EQ
717 cmpOp DoubleNeOp = NE
718 cmpOp DoubleLtOp = LT
719 cmpOp DoubleLeOp = LE
721 genCondJump lbl (StPrim op args)
723 trivialFCode instr args `thenSUs` \ register ->
724 getNewRegNCG DoubleKind `thenSUs` \ tmp ->
726 code = registerCode register tmp
727 result = registerName register tmp
730 returnSUs (code . mkSeqInstr (BF cond result target))
732 fltCmpOp op = case op of
746 (instr, cond) = case op of
747 FloatGtOp -> (FCMP TF LE, EQ)
748 FloatGeOp -> (FCMP TF LT, EQ)
749 FloatEqOp -> (FCMP TF EQ, NE)
750 FloatNeOp -> (FCMP TF EQ, EQ)
751 FloatLtOp -> (FCMP TF LT, NE)
752 FloatLeOp -> (FCMP TF LE, NE)
753 DoubleGtOp -> (FCMP TF LE, EQ)
754 DoubleGeOp -> (FCMP TF LT, EQ)
755 DoubleEqOp -> (FCMP TF EQ, NE)
756 DoubleNeOp -> (FCMP TF EQ, EQ)
757 DoubleLtOp -> (FCMP TF LT, NE)
758 DoubleLeOp -> (FCMP TF LE, NE)
760 genCondJump lbl (StPrim op args) =
761 trivialCode instr args `thenSUs` \ register ->
762 getNewRegNCG IntKind `thenSUs` \ tmp ->
764 code = registerCode register tmp
765 result = registerName register tmp
768 returnSUs (code . mkSeqInstr (BI cond result target))
770 (instr, cond) = case op of
771 CharGtOp -> (CMP LE, EQ)
772 CharGeOp -> (CMP LT, EQ)
773 CharEqOp -> (CMP EQ, NE)
774 CharNeOp -> (CMP EQ, EQ)
775 CharLtOp -> (CMP LT, NE)
776 CharLeOp -> (CMP LE, NE)
777 IntGtOp -> (CMP LE, EQ)
778 IntGeOp -> (CMP LT, EQ)
779 IntEqOp -> (CMP EQ, NE)
780 IntNeOp -> (CMP EQ, EQ)
781 IntLtOp -> (CMP LT, NE)
782 IntLeOp -> (CMP LE, NE)
783 WordGtOp -> (CMP ULE, EQ)
784 WordGeOp -> (CMP ULT, EQ)
785 WordEqOp -> (CMP EQ, NE)
786 WordNeOp -> (CMP EQ, EQ)
787 WordLtOp -> (CMP ULT, NE)
788 WordLeOp -> (CMP ULE, NE)
789 AddrGtOp -> (CMP ULE, EQ)
790 AddrGeOp -> (CMP ULT, EQ)
791 AddrEqOp -> (CMP EQ, NE)
792 AddrNeOp -> (CMP EQ, EQ)
793 AddrLtOp -> (CMP ULT, NE)
794 AddrLeOp -> (CMP ULE, NE)
798 Now the biggest nightmare---calls. Most of the nastiness is buried in
799 getCallArg, which moves the arguments to the correct registers/stack
800 locations. Apart from that, the code is easy.
805 :: FAST_STRING -- function to call
806 -> PrimKind -- type of the result
807 -> [StixTree] -- arguments (of mixed type)
808 -> SUniqSM (CodeBlock AlphaInstr)
810 genCCall fn kind args =
811 mapAccumLNCG getCallArg (argRegs,stackArgLoc) args
812 `thenSUs` \ ((unused,_), argCode) ->
814 nRegs = length argRegs - length unused
815 code = asmParThen (map ($ asmVoid) argCode)
818 LDA pv (AddrImm (ImmLab (uppPStr fn))),
819 JSR ra (AddrReg pv) nRegs,
820 LDGP gp (AddrReg ra)]
822 mapAccumLNCG f b [] = returnSUs (b, [])
823 mapAccumLNCG f b (x:xs) =
824 f b x `thenSUs` \ (b__2, x__2) ->
825 mapAccumLNCG f b__2 xs `thenSUs` \ (b__3, xs__2) ->
826 returnSUs (b__3, x__2:xs__2)
830 Trivial (dyadic) instructions. Only look for constants on the right hand
831 side, because that's where the generic optimizer will have put them.
836 :: (Reg -> RI -> Reg -> AlphaInstr)
840 trivialCode instr [x, StInt y]
842 getReg x `thenSUs` \ register ->
843 getNewRegNCG IntKind `thenSUs` \ tmp ->
845 code = registerCode register tmp
846 src1 = registerName register tmp
847 src2 = ImmInt (fromInteger y)
848 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
850 returnSUs (Any IntKind code__2)
852 trivialCode instr [x, y] =
853 getReg x `thenSUs` \ register1 ->
854 getReg y `thenSUs` \ register2 ->
855 getNewRegNCG IntKind `thenSUs` \ tmp1 ->
856 getNewRegNCG IntKind `thenSUs` \ tmp2 ->
858 code1 = registerCode register1 tmp1 asmVoid
859 src1 = registerName register1 tmp1
860 code2 = registerCode register2 tmp2 asmVoid
861 src2 = registerName register2 tmp2
862 code__2 dst = asmParThen [code1, code2] .
863 mkSeqInstr (instr src1 (RIReg src2) dst)
865 returnSUs (Any IntKind code__2)
868 :: (Reg -> Reg -> Reg -> AlphaInstr)
872 trivialFCode instr [x, y] =
873 getReg x `thenSUs` \ register1 ->
874 getReg y `thenSUs` \ register2 ->
875 getNewRegNCG DoubleKind `thenSUs` \ tmp1 ->
876 getNewRegNCG DoubleKind `thenSUs` \ tmp2 ->
878 code1 = registerCode register1 tmp1
879 src1 = registerName register1 tmp1
881 code2 = registerCode register2 tmp2
882 src2 = registerName register2 tmp2
884 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
885 mkSeqInstr (instr src1 src2 dst)
887 returnSUs (Any DoubleKind code__2)
891 Some bizarre special code for getting condition codes into registers.
892 Integer non-equality is a test for equality followed by an XOR with 1.
893 (Integer comparisons always set the result register to 0 or 1.) Floating
894 point comparisons of any kind leave the result in a floating point register,
895 so we need to wrangle an integer register out of things.
903 trivialCode (CMP EQ) args `thenSUs` \ register ->
904 getNewRegNCG IntKind `thenSUs` \ tmp ->
906 code = registerCode register tmp
907 src = registerName register tmp
908 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
910 returnSUs (Any IntKind code__2)
913 :: (Reg -> Reg -> Reg -> AlphaInstr)
918 cmpFCode instr cond args =
919 trivialFCode instr args `thenSUs` \ register ->
920 getNewRegNCG DoubleKind `thenSUs` \ tmp ->
921 getUniqLabelNCG `thenSUs` \ lbl ->
923 code = registerCode register tmp
924 result = registerName register tmp
926 code__2 dst = code . mkSeqInstrs [
927 OR zero (RIImm (ImmInt 1)) dst,
928 BF cond result (ImmCLbl lbl),
929 OR zero (RIReg zero) dst,
932 returnSUs (Any IntKind code__2)
936 Trivial unary instructions. Note that we don't have to worry about
937 matching an StInt as the argument, because genericOpt will already
938 have handled the constant-folding.
943 :: (RI -> Reg -> AlphaInstr)
947 trivialUCode instr [x] =
948 getReg x `thenSUs` \ register ->
949 getNewRegNCG IntKind `thenSUs` \ tmp ->
951 code = registerCode register tmp
952 src = registerName register tmp
953 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
955 returnSUs (Any IntKind code__2)
958 :: (Reg -> Reg -> AlphaInstr)
962 trivialUFCode instr [x] =
963 getReg x `thenSUs` \ register ->
964 getNewRegNCG DoubleKind `thenSUs` \ tmp ->
966 code = registerCode register tmp
967 src = registerName register tmp
968 code__2 dst = code . mkSeqInstr (instr src dst)
970 returnSUs (Any DoubleKind code__2)
974 Simple coercions that don't require any code to be generated.
975 Here we just change the type on the register passed on up
979 coerceIntCode :: PrimKind -> [StixTree] -> SUniqSM Register
980 coerceIntCode pk [x] =
981 getReg x `thenSUs` \ register ->
983 Fixed reg _ code -> returnSUs (Fixed reg pk code)
984 Any _ code -> returnSUs (Any pk code)
986 coerceFltCode :: [StixTree] -> SUniqSM Register
988 getReg x `thenSUs` \ register ->
990 Fixed reg _ code -> returnSUs (Fixed reg DoubleKind code)
991 Any _ code -> returnSUs (Any DoubleKind code)
995 Integer to character conversion.
1000 getReg x `thenSUs` \ register ->
1001 getNewRegNCG IntKind `thenSUs` \ reg ->
1003 code = registerCode register reg
1004 src = registerName register reg
1005 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
1007 returnSUs (Any IntKind code__2)
1011 More complicated integer/float conversions. Here we have to store
1012 temporaries in memory to move between the integer and the floating
1013 point register sets.
1017 coerceInt2FP :: [StixTree] -> SUniqSM Register
1019 getReg x `thenSUs` \ register ->
1020 getNewRegNCG IntKind `thenSUs` \ reg ->
1022 code = registerCode register reg
1023 src = registerName register reg
1025 code__2 dst = code . mkSeqInstrs [
1027 LD TF dst (spRel 0),
1030 returnSUs (Any DoubleKind code__2)
1032 coerceFP2Int :: [StixTree] -> SUniqSM Register
1034 getReg x `thenSUs` \ register ->
1035 getNewRegNCG DoubleKind `thenSUs` \ tmp ->
1037 code = registerCode register tmp
1038 src = registerName register tmp
1040 code__2 dst = code . mkSeqInstrs [
1042 ST TF tmp (spRel 0),
1045 returnSUs (Any IntKind code__2)
1049 Some random little helpers.
1053 is8Bits :: Integer -> Bool
1054 is8Bits i = i >= -256 && i < 256
1056 maybeImm :: StixTree -> Maybe Imm
1058 | i >= toInteger minInt && i <= toInteger maxInt = Just (ImmInt (fromInteger i))
1059 | otherwise = Just (ImmInteger i)
1060 maybeImm (StLitLbl s) = Just (ImmLab s)
1061 maybeImm (StLitLit s) = Just (strImmLab (cvtLitLit (_UNPK_ s)))
1062 maybeImm (StCLbl l) = Just (ImmCLbl l)
1063 maybeImm _ = Nothing
1065 mangleIndexTree :: StixTree -> StixTree
1067 mangleIndexTree (StIndex pk base (StInt i)) =
1068 StPrim IntAddOp [base, off]
1070 off = StInt (i * size pk)
1071 size :: PrimKind -> Integer
1072 size pk = case kindToSize pk of
1073 {B -> 1; BU -> 1; W -> 2; WU -> 2; L -> 4; FF -> 4; SF -> 4; _ -> 8}
1075 mangleIndexTree (StIndex pk base off) =
1077 CharKind -> StPrim IntAddOp [base, off]
1078 _ -> StPrim IntAddOp [base, off__2]
1080 off__2 = StPrim SllOp [off, StInt 3]
1082 cvtLitLit :: String -> String
1083 cvtLitLit "stdin" = "_iob+0" -- This one is probably okay...
1084 cvtLitLit "stdout" = "_iob+56" -- but these next two are dodgy at best
1085 cvtLitLit "stderr" = "_iob+112"
1088 | otherwise = error ("Native code generator can't handle ``" ++ s ++ "''")
1090 isHex ('0':'x':xs) = all isHexDigit xs
1092 -- Now, where have I seen this before?
1093 isHexDigit c = isDigit c || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'
1098 spRel gives us a stack relative addressing mode for volatile temporaries
1099 and for excess call arguments.
1104 :: Int -- desired stack offset in words, positive or negative
1106 spRel n = AddrRegImm sp (ImmInt (n * 8))
1108 stackArgLoc = 0 :: Int -- where to stack extra call arguments (beyond 6)
1114 getNewRegNCG :: PrimKind -> SUniqSM Reg
1116 getSUnique `thenSUs` \ u ->
1117 returnSUs (mkReg u pk)