2 % (c) The AQUA Project, Glasgow University, 1996
4 \section[MachCode]{Generating machine code}
6 This is a big module, but, if you pay attention to
7 (a) the sectioning, (b) the type signatures, and
8 (c) the \tr{#if blah_TARGET_ARCH} things, the
9 structure should not be too overwhelming.
12 #include "HsVersions.h"
13 #include "nativeGen/NCG.h"
15 module MachCode ( stmt2Instrs, asmVoid, SYN_IE(InstrList) ) where
19 import MachMisc -- may differ per-platform
22 import AbsCSyn ( MagicId )
23 import AbsCUtils ( magicIdPrimRep )
24 import CLabel ( isAsmTemp, CLabel )
25 import Maybes ( maybeToBool, expectJust )
26 import OrdList -- quite a bit of it
27 import Outputable ( PprStyle(..) )
28 import Pretty ( ptext, rational )
29 import PrimRep ( isFloatingRep, PrimRep(..) )
30 import PrimOp ( PrimOp(..), showPrimOp )
31 import Stix ( getUniqLabelNCG, StixTree(..),
32 StixReg(..), CodeSegment(..)
34 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
35 mapAccumLUs, SYN_IE(UniqSM)
37 import Util ( panic, assertPanic )
40 Code extractor for an entire stix tree---stix statement level.
43 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
45 stmt2Instrs stmt = case stmt of
46 StComment s -> returnInstr (COMMENT s)
47 StSegment seg -> returnInstr (SEGMENT seg)
48 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
49 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
50 StLabel lab -> returnInstr (LABEL lab)
52 StJump arg -> genJump arg
53 StCondJump lab arg -> genCondJump lab arg
54 StCall fn VoidRep args -> genCCall fn VoidRep args
57 | isFloatingRep pk -> assignFltCode pk dst src
58 | otherwise -> assignIntCode pk dst src
61 -- When falling through on the Alpha, we still have to load pv
62 -- with the address of the next routine, so that it can load gp.
63 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
67 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
68 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
69 (foldr1 (.) codes xs))
71 getData :: StixTree -> UniqSM (InstrBlock, Imm)
73 getData (StInt i) = returnUs (id, ImmInteger i)
74 getData (StDouble d) = returnUs (id, dblImmLit d)
75 getData (StLitLbl s) = returnUs (id, ImmLab s)
76 getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
77 getData (StCLbl l) = returnUs (id, ImmCLbl l)
78 getData (StString s) =
79 getUniqLabelNCG `thenUs` \ lbl ->
80 returnUs (mkSeqInstrs [LABEL lbl,
81 ASCII True (_UNPK_ s)],
85 %************************************************************************
87 \subsection{General things for putting together code sequences}
89 %************************************************************************
92 type InstrList = OrdList Instr
93 type InstrBlock = InstrList -> InstrList
98 asmInstr :: Instr -> InstrList
99 asmInstr i = mkUnitList i
101 asmSeq :: [Instr] -> InstrList
102 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
104 asmParThen :: [InstrList] -> InstrBlock
105 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
107 returnInstr :: Instr -> UniqSM InstrBlock
108 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
110 returnInstrs :: [Instr] -> UniqSM InstrBlock
111 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
113 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
114 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
116 mkSeqInstr :: Instr -> InstrBlock
117 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
119 mkSeqInstrs :: [Instr] -> InstrBlock
120 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
124 mangleIndexTree :: StixTree -> StixTree
126 mangleIndexTree (StIndex pk base (StInt i))
127 = StPrim IntAddOp [base, off]
129 off = StInt (i * sizeOf pk)
131 #ifndef i386_TARGET_ARCH
132 mangleIndexTree (StIndex pk base off)
133 = StPrim IntAddOp [base,
139 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
140 StPrim SllOp [off, StInt s]
143 shift DoubleRep = 3::Integer
144 shift _ = IF_ARCH_alpha(3,2)
146 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
147 -- that do include the size of the primitive kind we're addressing. When StIndex
148 -- is expanded to actual code, the index (in units) is by the above code approp.
149 -- shifted to get the no. of bytes. Since Address amodes do contain size info
150 -- explicitly, we disable the shifting for x86s.
151 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
157 maybeImm :: StixTree -> Maybe Imm
159 maybeImm (StLitLbl s) = Just (ImmLab s)
160 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
161 maybeImm (StCLbl l) = Just (ImmCLbl l)
164 | i >= toInteger minInt && i <= toInteger maxInt
165 = Just (ImmInt (fromInteger i))
167 = Just (ImmInteger i)
172 %************************************************************************
174 \subsection{The @Register@ type}
176 %************************************************************************
178 @Register@s passed up the tree. If the stix code forces the register
179 to live in a pre-decided machine register, it comes out as @Fixed@;
180 otherwise, it comes out as @Any@, and the parent can decide which
181 register to put it in.
185 = Fixed PrimRep Reg InstrBlock
186 | Any PrimRep (Reg -> InstrBlock)
188 registerCode :: Register -> Reg -> InstrBlock
189 registerCode (Fixed _ _ code) reg = code
190 registerCode (Any _ code) reg = code reg
192 registerName :: Register -> Reg -> Reg
193 registerName (Fixed _ reg _) _ = reg
194 registerName (Any _ _) reg = reg
196 registerRep :: Register -> PrimRep
197 registerRep (Fixed pk _ _) = pk
198 registerRep (Any pk _) = pk
200 isFixed :: Register -> Bool
201 isFixed (Fixed _ _ _) = True
202 isFixed (Any _ _) = False
205 Generate code to get a subtree into a @Register@:
207 getRegister :: StixTree -> UniqSM Register
209 getRegister (StReg (StixMagicId stgreg))
210 = case (magicIdRegMaybe stgreg) of
211 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
214 getRegister (StReg (StixTemp u pk))
215 = returnUs (Fixed pk (UnmappedReg u pk) id)
217 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
219 getRegister (StCall fn kind args)
220 = genCCall fn kind args `thenUs` \ call ->
221 returnUs (Fixed kind reg call)
223 reg = if isFloatingRep kind
224 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
225 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
227 getRegister (StString s)
228 = getUniqLabelNCG `thenUs` \ lbl ->
230 imm_lbl = ImmCLbl lbl
232 code dst = mkSeqInstrs [
235 ASCII True (_UNPK_ s),
237 #if alpha_TARGET_ARCH
238 LDA dst (AddrImm imm_lbl)
241 MOV L (OpImm imm_lbl) (OpReg dst)
243 #if sparc_TARGET_ARCH
244 SETHI (HI imm_lbl) dst,
245 OR False dst (RIImm (LO imm_lbl)) dst
249 returnUs (Any PtrRep code)
251 getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
252 = getUniqLabelNCG `thenUs` \ lbl ->
254 imm_lbl = ImmCLbl lbl
256 code dst = mkSeqInstrs [
259 ASCII False (init xs),
261 #if alpha_TARGET_ARCH
262 LDA dst (AddrImm imm_lbl)
265 MOV L (OpImm imm_lbl) (OpReg dst)
267 #if sparc_TARGET_ARCH
268 SETHI (HI imm_lbl) dst,
269 OR False dst (RIImm (LO imm_lbl)) dst
273 returnUs (Any PtrRep code)
275 xs = _UNPK_ (_TAIL_ s)
277 -- end of machine-"independent" bit; here we go on the rest...
279 #if alpha_TARGET_ARCH
281 getRegister (StDouble d)
282 = getUniqLabelNCG `thenUs` \ lbl ->
283 getNewRegNCG PtrRep `thenUs` \ tmp ->
284 let code dst = mkSeqInstrs [
287 DATA TF [ImmLab (rational d)],
289 LDA tmp (AddrImm (ImmCLbl lbl)),
290 LD TF dst (AddrReg tmp)]
292 returnUs (Any DoubleRep code)
294 getRegister (StPrim primop [x]) -- unary PrimOps
296 IntNegOp -> trivialUCode (NEG Q False) x
297 IntAbsOp -> trivialUCode (ABS Q) x
299 NotOp -> trivialUCode NOT x
301 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
302 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
304 OrdOp -> coerceIntCode IntRep x
307 Float2IntOp -> coerceFP2Int x
308 Int2FloatOp -> coerceInt2FP pr x
309 Double2IntOp -> coerceFP2Int x
310 Int2DoubleOp -> coerceInt2FP pr x
312 Double2FloatOp -> coerceFltCode x
313 Float2DoubleOp -> coerceFltCode x
315 other_op -> getRegister (StCall fn DoubleRep [x])
317 fn = case other_op of
318 FloatExpOp -> SLIT("exp")
319 FloatLogOp -> SLIT("log")
320 FloatSqrtOp -> SLIT("sqrt")
321 FloatSinOp -> SLIT("sin")
322 FloatCosOp -> SLIT("cos")
323 FloatTanOp -> SLIT("tan")
324 FloatAsinOp -> SLIT("asin")
325 FloatAcosOp -> SLIT("acos")
326 FloatAtanOp -> SLIT("atan")
327 FloatSinhOp -> SLIT("sinh")
328 FloatCoshOp -> SLIT("cosh")
329 FloatTanhOp -> SLIT("tanh")
330 DoubleExpOp -> SLIT("exp")
331 DoubleLogOp -> SLIT("log")
332 DoubleSqrtOp -> SLIT("sqrt")
333 DoubleSinOp -> SLIT("sin")
334 DoubleCosOp -> SLIT("cos")
335 DoubleTanOp -> SLIT("tan")
336 DoubleAsinOp -> SLIT("asin")
337 DoubleAcosOp -> SLIT("acos")
338 DoubleAtanOp -> SLIT("atan")
339 DoubleSinhOp -> SLIT("sinh")
340 DoubleCoshOp -> SLIT("cosh")
341 DoubleTanhOp -> SLIT("tanh")
343 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
345 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
347 CharGtOp -> trivialCode (CMP LTT) y x
348 CharGeOp -> trivialCode (CMP LE) y x
349 CharEqOp -> trivialCode (CMP EQQ) x y
350 CharNeOp -> int_NE_code x y
351 CharLtOp -> trivialCode (CMP LTT) x y
352 CharLeOp -> trivialCode (CMP LE) x y
354 IntGtOp -> trivialCode (CMP LTT) y x
355 IntGeOp -> trivialCode (CMP LE) y x
356 IntEqOp -> trivialCode (CMP EQQ) x y
357 IntNeOp -> int_NE_code x y
358 IntLtOp -> trivialCode (CMP LTT) x y
359 IntLeOp -> trivialCode (CMP LE) x y
361 WordGtOp -> trivialCode (CMP ULT) y x
362 WordGeOp -> trivialCode (CMP ULE) x y
363 WordEqOp -> trivialCode (CMP EQQ) x y
364 WordNeOp -> int_NE_code x y
365 WordLtOp -> trivialCode (CMP ULT) x y
366 WordLeOp -> trivialCode (CMP ULE) x y
368 AddrGtOp -> trivialCode (CMP ULT) y x
369 AddrGeOp -> trivialCode (CMP ULE) y x
370 AddrEqOp -> trivialCode (CMP EQQ) x y
371 AddrNeOp -> int_NE_code x y
372 AddrLtOp -> trivialCode (CMP ULT) x y
373 AddrLeOp -> trivialCode (CMP ULE) x y
375 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
376 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
377 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
378 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
379 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
380 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
382 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
383 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
384 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
385 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
386 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
387 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
389 IntAddOp -> trivialCode (ADD Q False) x y
390 IntSubOp -> trivialCode (SUB Q False) x y
391 IntMulOp -> trivialCode (MUL Q False) x y
392 IntQuotOp -> trivialCode (DIV Q False) x y
393 IntRemOp -> trivialCode (REM Q False) x y
395 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
396 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
397 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
398 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
400 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
401 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
402 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
403 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
405 AndOp -> trivialCode AND x y
406 OrOp -> trivialCode OR x y
407 XorOp -> trivialCode XOR x y
408 SllOp -> trivialCode SLL x y
409 SraOp -> trivialCode SRA x y
410 SrlOp -> trivialCode SRL x y
412 ISllOp -> panic "AlphaGen:isll"
413 ISraOp -> panic "AlphaGen:isra"
414 ISrlOp -> panic "AlphaGen:isrl"
416 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x,y])
417 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x,y])
419 {- ------------------------------------------------------------
420 Some bizarre special code for getting condition codes into
421 registers. Integer non-equality is a test for equality
422 followed by an XOR with 1. (Integer comparisons always set
423 the result register to 0 or 1.) Floating point comparisons of
424 any kind leave the result in a floating point register, so we
425 need to wrangle an integer register out of things.
427 int_NE_code :: StixTree -> StixTree -> UniqSM Register
430 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
431 getNewRegNCG IntRep `thenUs` \ tmp ->
433 code = registerCode register tmp
434 src = registerName register tmp
435 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
437 returnUs (Any IntRep code__2)
439 {- ------------------------------------------------------------
440 Comments for int_NE_code also apply to cmpF_code
443 :: (Reg -> Reg -> Reg -> Instr)
445 -> StixTree -> StixTree
448 cmpF_code instr cond x y
449 = trivialFCode pr instr x y `thenUs` \ register ->
450 getNewRegNCG DoubleRep `thenUs` \ tmp ->
451 getUniqLabelNCG `thenUs` \ lbl ->
453 code = registerCode register tmp
454 result = registerName register tmp
456 code__2 dst = code . mkSeqInstrs [
457 OR zeroh (RIImm (ImmInt 1)) dst,
458 BF cond result (ImmCLbl lbl),
459 OR zeroh (RIReg zeroh) dst,
462 returnUs (Any IntRep code__2)
464 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
465 ------------------------------------------------------------
467 getRegister (StInd pk mem)
468 = getAmode mem `thenUs` \ amode ->
470 code = amodeCode amode
471 src = amodeAddr amode
472 size = primRepToSize pk
473 code__2 dst = code . mkSeqInstr (LD size dst src)
475 returnUs (Any pk code__2)
477 getRegister (StInt i)
480 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
482 returnUs (Any IntRep code)
485 code dst = mkSeqInstr (LDI Q dst src)
487 returnUs (Any IntRep code)
489 src = ImmInt (fromInteger i)
494 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
496 returnUs (Any PtrRep code)
499 imm__2 = case imm of Just x -> x
501 #endif {- alpha_TARGET_ARCH -}
502 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
505 getRegister (StReg (StixTemp u pk)) = returnUs (Fixed pk (UnmappedReg u pk) id)
507 getRegister (StDouble 0.0)
509 code dst = mkSeqInstrs [FLDZ]
511 returnUs (Any DoubleRep code)
513 getRegister (StDouble 1.0)
515 code dst = mkSeqInstrs [FLD1]
517 returnUs (Any DoubleRep code)
519 getRegister (StDouble d)
520 = getUniqLabelNCG `thenUs` \ lbl ->
521 --getNewRegNCG PtrRep `thenUs` \ tmp ->
522 let code dst = mkSeqInstrs [
525 DATA DF [dblImmLit d],
527 FLD DF (OpImm (ImmCLbl lbl))
530 returnUs (Any DoubleRep code)
532 getRegister (StPrim primop [x]) -- unary PrimOps
534 IntNegOp -> trivialUCode (NEGI L) x
535 IntAbsOp -> absIntCode x
537 NotOp -> trivialUCode (NOT L) x
539 FloatNegOp -> trivialUFCode FloatRep FCHS x
540 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
541 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
543 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
545 OrdOp -> coerceIntCode IntRep x
548 Float2IntOp -> coerceFP2Int x
549 Int2FloatOp -> coerceInt2FP FloatRep x
550 Double2IntOp -> coerceFP2Int x
551 Int2DoubleOp -> coerceInt2FP DoubleRep x
553 Double2FloatOp -> coerceFltCode x
554 Float2DoubleOp -> coerceFltCode x
558 fixed_x = if is_float_op -- promote to double
559 then StPrim Float2DoubleOp [x]
562 getRegister (StCall fn DoubleRep [x])
566 FloatExpOp -> (True, SLIT("exp"))
567 FloatLogOp -> (True, SLIT("log"))
569 FloatSinOp -> (True, SLIT("sin"))
570 FloatCosOp -> (True, SLIT("cos"))
571 FloatTanOp -> (True, SLIT("tan"))
573 FloatAsinOp -> (True, SLIT("asin"))
574 FloatAcosOp -> (True, SLIT("acos"))
575 FloatAtanOp -> (True, SLIT("atan"))
577 FloatSinhOp -> (True, SLIT("sinh"))
578 FloatCoshOp -> (True, SLIT("cosh"))
579 FloatTanhOp -> (True, SLIT("tanh"))
581 DoubleExpOp -> (False, SLIT("exp"))
582 DoubleLogOp -> (False, SLIT("log"))
584 DoubleSinOp -> (False, SLIT("sin"))
585 DoubleCosOp -> (False, SLIT("cos"))
586 DoubleTanOp -> (False, SLIT("tan"))
588 DoubleAsinOp -> (False, SLIT("asin"))
589 DoubleAcosOp -> (False, SLIT("acos"))
590 DoubleAtanOp -> (False, SLIT("atan"))
592 DoubleSinhOp -> (False, SLIT("sinh"))
593 DoubleCoshOp -> (False, SLIT("cosh"))
594 DoubleTanhOp -> (False, SLIT("tanh"))
596 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
598 CharGtOp -> condIntReg GTT x y
599 CharGeOp -> condIntReg GE x y
600 CharEqOp -> condIntReg EQQ x y
601 CharNeOp -> condIntReg NE x y
602 CharLtOp -> condIntReg LTT x y
603 CharLeOp -> condIntReg LE x y
605 IntGtOp -> condIntReg GTT x y
606 IntGeOp -> condIntReg GE x y
607 IntEqOp -> condIntReg EQQ x y
608 IntNeOp -> condIntReg NE x y
609 IntLtOp -> condIntReg LTT x y
610 IntLeOp -> condIntReg LE x y
612 WordGtOp -> condIntReg GU x y
613 WordGeOp -> condIntReg GEU x y
614 WordEqOp -> condIntReg EQQ x y
615 WordNeOp -> condIntReg NE x y
616 WordLtOp -> condIntReg LU x y
617 WordLeOp -> condIntReg LEU x y
619 AddrGtOp -> condIntReg GU x y
620 AddrGeOp -> condIntReg GEU x y
621 AddrEqOp -> condIntReg EQQ x y
622 AddrNeOp -> condIntReg NE x y
623 AddrLtOp -> condIntReg LU x y
624 AddrLeOp -> condIntReg LEU x y
626 FloatGtOp -> condFltReg GTT x y
627 FloatGeOp -> condFltReg GE x y
628 FloatEqOp -> condFltReg EQQ x y
629 FloatNeOp -> condFltReg NE x y
630 FloatLtOp -> condFltReg LTT x y
631 FloatLeOp -> condFltReg LE x y
633 DoubleGtOp -> condFltReg GTT x y
634 DoubleGeOp -> condFltReg GE x y
635 DoubleEqOp -> condFltReg EQQ x y
636 DoubleNeOp -> condFltReg NE x y
637 DoubleLtOp -> condFltReg LTT x y
638 DoubleLeOp -> condFltReg LE x y
640 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
641 -- this should be optimised by the generic Opts,
642 -- I don't know why it is not (sometimes)!
644 [x, StInt 0] -> getRegister x
649 IntSubOp -> sub_code L x y
650 IntQuotOp -> quot_code L x y True{-division-}
651 IntRemOp -> quot_code L x y False{-remainder-}
652 IntMulOp -> trivialCode (IMUL L) x y {-True-}
654 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
655 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
656 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
657 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
659 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
660 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
661 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
662 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
664 AndOp -> trivialCode (AND L) x y {-True-}
665 OrOp -> trivialCode (OR L) x y {-True-}
666 XorOp -> trivialCode (XOR L) x y {-True-}
668 {- Shift ops on x86s have constraints on their source, it
669 either has to be Imm, CL or 1
670 => trivialCode's is not restrictive enough (sigh.)
673 SllOp -> shift_code (SHL L) x y {-False-}
674 SraOp -> shift_code (SAR L) x y {-False-}
675 SrlOp -> shift_code (SHR L) x y {-False-}
678 ISllOp -> panic "I386Gen:isll"
679 ISraOp -> panic "I386Gen:isra"
680 ISrlOp -> panic "I386Gen:isrl"
682 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
683 where promote x = StPrim Float2DoubleOp [x]
684 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
686 shift_code :: (Operand -> Operand -> Instr)
690 {- Case1: shift length as immediate -}
691 -- Code is the same as the first eq. for trivialCode -- sigh.
692 shift_code instr x y{-amount-}
694 = getRegister x `thenUs` \ register ->
696 op_imm = OpImm imm__2
699 code = registerCode register dst
700 src = registerName register dst
702 mkSeqInstr (COMMENT SLIT("shift_code")) .
704 if isFixed register && src /= dst
706 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
707 instr op_imm (OpReg dst)]
709 mkSeqInstr (instr op_imm (OpReg src))
711 returnUs (Any IntRep code__2)
714 imm__2 = case imm of Just x -> x
716 {- Case2: shift length is complex (non-immediate) -}
717 shift_code instr x y{-amount-}
718 = getRegister y `thenUs` \ register1 ->
719 getRegister x `thenUs` \ register2 ->
720 -- getNewRegNCG IntRep `thenUs` \ dst ->
722 -- Note: we force the shift length to be loaded
723 -- into ECX, so that we can use CL when shifting.
724 -- (only register location we are allowed
725 -- to put shift amounts.)
727 -- The shift instruction is fed ECX as src reg,
728 -- but we coerce this into CL when printing out.
729 src1 = registerName register1 ecx
730 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
731 registerCode register1 ecx .
732 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
734 registerCode register1 ecx
737 code2 = registerCode register2 eax
738 src2 = registerName register2 eax
741 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
743 returnUs (Fixed IntRep eax code__2)
745 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
747 add_code sz x (StInt y)
748 = getRegister x `thenUs` \ register ->
749 getNewRegNCG IntRep `thenUs` \ tmp ->
751 code = registerCode register tmp
752 src1 = registerName register tmp
753 src2 = ImmInt (fromInteger y)
755 mkSeqInstr (LEA sz (OpAddr (Address (Just src1) Nothing src2)) (OpReg dst))
757 returnUs (Any IntRep code__2)
759 add_code sz x (StInd _ mem)
760 = getRegister x `thenUs` \ register1 ->
761 --getNewRegNCG (registerRep register1)
762 -- `thenUs` \ tmp1 ->
763 getAmode mem `thenUs` \ amode ->
765 code2 = amodeCode amode
766 src2 = amodeAddr amode
768 -- fixedname = registerName register1 eax
769 code__2 dst = let code1 = registerCode register1 dst
770 src1 = registerName register1 dst
771 in asmParThen [code2 asmVoid,code1 asmVoid] .
772 if isFixed register1 && src1 /= dst
773 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
774 ADD sz (OpAddr src2) (OpReg dst)]
776 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
778 returnUs (Any IntRep code__2)
780 add_code sz (StInd _ mem) y
781 = getRegister y `thenUs` \ register2 ->
782 --getNewRegNCG (registerRep register2)
783 -- `thenUs` \ tmp2 ->
784 getAmode mem `thenUs` \ amode ->
786 code1 = amodeCode amode
787 src1 = amodeAddr amode
789 -- fixedname = registerName register2 eax
790 code__2 dst = let code2 = registerCode register2 dst
791 src2 = registerName register2 dst
792 in asmParThen [code1 asmVoid,code2 asmVoid] .
793 if isFixed register2 && src2 /= dst
794 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
795 ADD sz (OpAddr src1) (OpReg dst)]
797 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
799 returnUs (Any IntRep code__2)
802 = getRegister x `thenUs` \ register1 ->
803 getRegister y `thenUs` \ register2 ->
804 getNewRegNCG IntRep `thenUs` \ tmp1 ->
805 getNewRegNCG IntRep `thenUs` \ tmp2 ->
807 code1 = registerCode register1 tmp1 asmVoid
808 src1 = registerName register1 tmp1
809 code2 = registerCode register2 tmp2 asmVoid
810 src2 = registerName register2 tmp2
811 code__2 dst = asmParThen [code1, code2] .
812 mkSeqInstr (LEA sz (OpAddr (Address (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
814 returnUs (Any IntRep code__2)
817 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
819 sub_code sz x (StInt y)
820 = getRegister x `thenUs` \ register ->
821 getNewRegNCG IntRep `thenUs` \ tmp ->
823 code = registerCode register tmp
824 src1 = registerName register tmp
825 src2 = ImmInt (-(fromInteger y))
827 mkSeqInstr (LEA sz (OpAddr (Address (Just src1) Nothing src2)) (OpReg dst))
829 returnUs (Any IntRep code__2)
831 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
836 -> StixTree -> StixTree
837 -> Bool -- True => division, False => remainder operation
840 -- x must go into eax, edx must be a sign-extension of eax, and y
841 -- should go in some other register (or memory), so that we get
842 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
843 -- put y in memory (if it is not there already)
845 quot_code sz x (StInd pk mem) is_division
846 = getRegister x `thenUs` \ register1 ->
847 getNewRegNCG IntRep `thenUs` \ tmp1 ->
848 getAmode mem `thenUs` \ amode ->
850 code1 = registerCode register1 tmp1 asmVoid
851 src1 = registerName register1 tmp1
852 code2 = amodeCode amode asmVoid
853 src2 = amodeAddr amode
854 code__2 = asmParThen [code1, code2] .
855 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
857 IDIV sz (OpAddr src2)]
859 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
861 quot_code sz x (StInt i) is_division
862 = getRegister x `thenUs` \ register1 ->
863 getNewRegNCG IntRep `thenUs` \ tmp1 ->
865 code1 = registerCode register1 tmp1 asmVoid
866 src1 = registerName register1 tmp1
867 src2 = ImmInt (fromInteger i)
868 code__2 = asmParThen [code1] .
869 mkSeqInstrs [-- we put src2 in (ebx)
870 MOV L (OpImm src2) (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))),
871 MOV L (OpReg src1) (OpReg eax),
873 IDIV sz (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1)))]
875 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
877 quot_code sz x y is_division
878 = getRegister x `thenUs` \ register1 ->
879 getNewRegNCG IntRep `thenUs` \ tmp1 ->
880 getRegister y `thenUs` \ register2 ->
881 getNewRegNCG IntRep `thenUs` \ tmp2 ->
883 code1 = registerCode register1 tmp1 asmVoid
884 src1 = registerName register1 tmp1
885 code2 = registerCode register2 tmp2 asmVoid
886 src2 = registerName register2 tmp2
887 code__2 = asmParThen [code1, code2] .
888 if src2 == ecx || src2 == esi
889 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
891 IDIV sz (OpReg src2)]
892 else mkSeqInstrs [ -- we put src2 in (ebx)
893 MOV L (OpReg src2) (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))),
894 MOV L (OpReg src1) (OpReg eax),
896 IDIV sz (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1)))]
898 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
899 -----------------------
901 getRegister (StInd pk mem)
902 = getAmode mem `thenUs` \ amode ->
904 code = amodeCode amode
905 src = amodeAddr amode
906 size = primRepToSize pk
908 if pk == DoubleRep || pk == FloatRep
909 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
910 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
912 returnUs (Any pk code__2)
915 getRegister (StInt i)
917 src = ImmInt (fromInteger i)
918 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
920 returnUs (Any IntRep code)
925 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
927 returnUs (Any PtrRep code)
930 imm__2 = case imm of Just x -> x
932 #endif {- i386_TARGET_ARCH -}
933 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
934 #if sparc_TARGET_ARCH
936 getRegister (StDouble d)
937 = getUniqLabelNCG `thenUs` \ lbl ->
938 getNewRegNCG PtrRep `thenUs` \ tmp ->
939 let code dst = mkSeqInstrs [
942 DATA DF [dblImmLit d],
944 SETHI (HI (ImmCLbl lbl)) tmp,
945 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
947 returnUs (Any DoubleRep code)
949 getRegister (StPrim primop [x]) -- unary PrimOps
951 IntNegOp -> trivialUCode (SUB False False g0) x
952 IntAbsOp -> absIntCode x
953 NotOp -> trivialUCode (XNOR False g0) x
955 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
957 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
959 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
960 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
962 OrdOp -> coerceIntCode IntRep x
965 Float2IntOp -> coerceFP2Int x
966 Int2FloatOp -> coerceInt2FP FloatRep x
967 Double2IntOp -> coerceFP2Int x
968 Int2DoubleOp -> coerceInt2FP DoubleRep x
972 fixed_x = if is_float_op -- promote to double
973 then StPrim Float2DoubleOp [x]
976 getRegister (StCall fn DoubleRep [x])
980 FloatExpOp -> (True, SLIT("exp"))
981 FloatLogOp -> (True, SLIT("log"))
982 FloatSqrtOp -> (True, SLIT("sqrt"))
984 FloatSinOp -> (True, SLIT("sin"))
985 FloatCosOp -> (True, SLIT("cos"))
986 FloatTanOp -> (True, SLIT("tan"))
988 FloatAsinOp -> (True, SLIT("asin"))
989 FloatAcosOp -> (True, SLIT("acos"))
990 FloatAtanOp -> (True, SLIT("atan"))
992 FloatSinhOp -> (True, SLIT("sinh"))
993 FloatCoshOp -> (True, SLIT("cosh"))
994 FloatTanhOp -> (True, SLIT("tanh"))
996 DoubleExpOp -> (False, SLIT("exp"))
997 DoubleLogOp -> (False, SLIT("log"))
998 DoubleSqrtOp -> (True, SLIT("sqrt"))
1000 DoubleSinOp -> (False, SLIT("sin"))
1001 DoubleCosOp -> (False, SLIT("cos"))
1002 DoubleTanOp -> (False, SLIT("tan"))
1004 DoubleAsinOp -> (False, SLIT("asin"))
1005 DoubleAcosOp -> (False, SLIT("acos"))
1006 DoubleAtanOp -> (False, SLIT("atan"))
1008 DoubleSinhOp -> (False, SLIT("sinh"))
1009 DoubleCoshOp -> (False, SLIT("cosh"))
1010 DoubleTanhOp -> (False, SLIT("tanh"))
1011 _ -> panic ("Monadic PrimOp not handled: " ++ showPrimOp PprDebug primop)
1013 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1015 CharGtOp -> condIntReg GTT x y
1016 CharGeOp -> condIntReg GE x y
1017 CharEqOp -> condIntReg EQQ x y
1018 CharNeOp -> condIntReg NE x y
1019 CharLtOp -> condIntReg LTT x y
1020 CharLeOp -> condIntReg LE x y
1022 IntGtOp -> condIntReg GTT x y
1023 IntGeOp -> condIntReg GE x y
1024 IntEqOp -> condIntReg EQQ x y
1025 IntNeOp -> condIntReg NE x y
1026 IntLtOp -> condIntReg LTT x y
1027 IntLeOp -> condIntReg LE x y
1029 WordGtOp -> condIntReg GU x y
1030 WordGeOp -> condIntReg GEU x y
1031 WordEqOp -> condIntReg EQQ x y
1032 WordNeOp -> condIntReg NE x y
1033 WordLtOp -> condIntReg LU x y
1034 WordLeOp -> condIntReg LEU x y
1036 AddrGtOp -> condIntReg GU x y
1037 AddrGeOp -> condIntReg GEU x y
1038 AddrEqOp -> condIntReg EQQ x y
1039 AddrNeOp -> condIntReg NE x y
1040 AddrLtOp -> condIntReg LU x y
1041 AddrLeOp -> condIntReg LEU x y
1043 FloatGtOp -> condFltReg GTT x y
1044 FloatGeOp -> condFltReg GE x y
1045 FloatEqOp -> condFltReg EQQ x y
1046 FloatNeOp -> condFltReg NE x y
1047 FloatLtOp -> condFltReg LTT x y
1048 FloatLeOp -> condFltReg LE x y
1050 DoubleGtOp -> condFltReg GTT x y
1051 DoubleGeOp -> condFltReg GE x y
1052 DoubleEqOp -> condFltReg EQQ x y
1053 DoubleNeOp -> condFltReg NE x y
1054 DoubleLtOp -> condFltReg LTT x y
1055 DoubleLeOp -> condFltReg LE x y
1057 IntAddOp -> trivialCode (ADD False False) x y
1058 IntSubOp -> trivialCode (SUB False False) x y
1060 -- ToDo: teach about V8+ SPARC mul/div instructions
1061 IntMulOp -> imul_div SLIT(".umul") x y
1062 IntQuotOp -> imul_div SLIT(".div") x y
1063 IntRemOp -> imul_div SLIT(".rem") x y
1065 FloatAddOp -> trivialFCode FloatRep FADD x y
1066 FloatSubOp -> trivialFCode FloatRep FSUB x y
1067 FloatMulOp -> trivialFCode FloatRep FMUL x y
1068 FloatDivOp -> trivialFCode FloatRep FDIV x y
1070 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1071 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1072 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1073 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1075 AndOp -> trivialCode (AND False) x y
1076 OrOp -> trivialCode (OR False) x y
1077 XorOp -> trivialCode (XOR False) x y
1078 SllOp -> trivialCode SLL x y
1079 SraOp -> trivialCode SRA x y
1080 SrlOp -> trivialCode SRL x y
1082 ISllOp -> panic "SparcGen:isll"
1083 ISraOp -> panic "SparcGen:isra"
1084 ISrlOp -> panic "SparcGen:isrl"
1086 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
1087 where promote x = StPrim Float2DoubleOp [x]
1088 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
1090 imul_div fn x y = getRegister (StCall fn IntRep [x, y])
1092 getRegister (StInd pk mem)
1093 = getAmode mem `thenUs` \ amode ->
1095 code = amodeCode amode
1096 src = amodeAddr amode
1097 size = primRepToSize pk
1098 code__2 dst = code . mkSeqInstr (LD size src dst)
1100 returnUs (Any pk code__2)
1102 getRegister (StInt i)
1105 src = ImmInt (fromInteger i)
1106 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1108 returnUs (Any IntRep code)
1113 code dst = mkSeqInstrs [
1114 SETHI (HI imm__2) dst,
1115 OR False dst (RIImm (LO imm__2)) dst]
1117 returnUs (Any PtrRep code)
1120 imm__2 = case imm of Just x -> x
1122 #endif {- sparc_TARGET_ARCH -}
1125 %************************************************************************
1127 \subsection{The @Amode@ type}
1129 %************************************************************************
1131 @Amode@s: Memory addressing modes passed up the tree.
1133 data Amode = Amode Address InstrBlock
1135 amodeAddr (Amode addr _) = addr
1136 amodeCode (Amode _ code) = code
1139 Now, given a tree (the argument to an StInd) that references memory,
1140 produce a suitable addressing mode.
1143 getAmode :: StixTree -> UniqSM Amode
1145 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1147 #if alpha_TARGET_ARCH
1149 getAmode (StPrim IntSubOp [x, StInt i])
1150 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1151 getRegister x `thenUs` \ register ->
1153 code = registerCode register tmp
1154 reg = registerName register tmp
1155 off = ImmInt (-(fromInteger i))
1157 returnUs (Amode (AddrRegImm reg off) code)
1159 getAmode (StPrim IntAddOp [x, StInt i])
1160 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1161 getRegister x `thenUs` \ register ->
1163 code = registerCode register tmp
1164 reg = registerName register tmp
1165 off = ImmInt (fromInteger i)
1167 returnUs (Amode (AddrRegImm reg off) code)
1171 = returnUs (Amode (AddrImm imm__2) id)
1174 imm__2 = case imm of Just x -> x
1177 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1178 getRegister other `thenUs` \ register ->
1180 code = registerCode register tmp
1181 reg = registerName register tmp
1183 returnUs (Amode (AddrReg reg) code)
1185 #endif {- alpha_TARGET_ARCH -}
1186 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1187 #if i386_TARGET_ARCH
1189 getAmode (StPrim IntSubOp [x, StInt i])
1190 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1191 getRegister x `thenUs` \ register ->
1193 code = registerCode register tmp
1194 reg = registerName register tmp
1195 off = ImmInt (-(fromInteger i))
1197 returnUs (Amode (Address (Just reg) Nothing off) code)
1199 getAmode (StPrim IntAddOp [x, StInt i])
1202 code = mkSeqInstrs []
1204 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1207 imm__2 = case imm of Just x -> x
1209 getAmode (StPrim IntAddOp [x, StInt i])
1210 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1211 getRegister x `thenUs` \ register ->
1213 code = registerCode register tmp
1214 reg = registerName register tmp
1215 off = ImmInt (fromInteger i)
1217 returnUs (Amode (Address (Just reg) Nothing off) code)
1219 getAmode (StPrim IntAddOp [x, y])
1220 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1221 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1222 getRegister x `thenUs` \ register1 ->
1223 getRegister y `thenUs` \ register2 ->
1225 code1 = registerCode register1 tmp1 asmVoid
1226 reg1 = registerName register1 tmp1
1227 code2 = registerCode register2 tmp2 asmVoid
1228 reg2 = registerName register2 tmp2
1229 code__2 = asmParThen [code1, code2]
1231 returnUs (Amode (Address (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1236 code = mkSeqInstrs []
1238 returnUs (Amode (ImmAddr imm__2 0) code)
1241 imm__2 = case imm of Just x -> x
1244 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1245 getRegister other `thenUs` \ register ->
1247 code = registerCode register tmp
1248 reg = registerName register tmp
1251 returnUs (Amode (Address (Just reg) Nothing (ImmInt 0)) code)
1253 #endif {- i386_TARGET_ARCH -}
1254 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1255 #if sparc_TARGET_ARCH
1257 getAmode (StPrim IntSubOp [x, StInt i])
1259 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1260 getRegister x `thenUs` \ register ->
1262 code = registerCode register tmp
1263 reg = registerName register tmp
1264 off = ImmInt (-(fromInteger i))
1266 returnUs (Amode (AddrRegImm reg off) code)
1269 getAmode (StPrim IntAddOp [x, StInt i])
1271 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1272 getRegister x `thenUs` \ register ->
1274 code = registerCode register tmp
1275 reg = registerName register tmp
1276 off = ImmInt (fromInteger i)
1278 returnUs (Amode (AddrRegImm reg off) code)
1280 getAmode (StPrim IntAddOp [x, y])
1281 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1282 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1283 getRegister x `thenUs` \ register1 ->
1284 getRegister y `thenUs` \ register2 ->
1286 code1 = registerCode register1 tmp1 asmVoid
1287 reg1 = registerName register1 tmp1
1288 code2 = registerCode register2 tmp2 asmVoid
1289 reg2 = registerName register2 tmp2
1290 code__2 = asmParThen [code1, code2]
1292 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1296 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1298 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1300 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1303 imm__2 = case imm of Just x -> x
1306 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1307 getRegister other `thenUs` \ register ->
1309 code = registerCode register tmp
1310 reg = registerName register tmp
1313 returnUs (Amode (AddrRegImm reg off) code)
1315 #endif {- sparc_TARGET_ARCH -}
1318 %************************************************************************
1320 \subsection{The @CondCode@ type}
1322 %************************************************************************
1324 Condition codes passed up the tree.
1326 data CondCode = CondCode Bool Cond InstrBlock
1328 condName (CondCode _ cond _) = cond
1329 condFloat (CondCode is_float _ _) = is_float
1330 condCode (CondCode _ _ code) = code
1333 Set up a condition code for a conditional branch.
1336 getCondCode :: StixTree -> UniqSM CondCode
1338 #if alpha_TARGET_ARCH
1339 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1340 #endif {- alpha_TARGET_ARCH -}
1341 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1343 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1344 -- yes, they really do seem to want exactly the same!
1346 getCondCode (StPrim primop [x, y])
1348 CharGtOp -> condIntCode GTT x y
1349 CharGeOp -> condIntCode GE x y
1350 CharEqOp -> condIntCode EQQ x y
1351 CharNeOp -> condIntCode NE x y
1352 CharLtOp -> condIntCode LTT x y
1353 CharLeOp -> condIntCode LE x y
1355 IntGtOp -> condIntCode GTT x y
1356 IntGeOp -> condIntCode GE x y
1357 IntEqOp -> condIntCode EQQ x y
1358 IntNeOp -> condIntCode NE x y
1359 IntLtOp -> condIntCode LTT x y
1360 IntLeOp -> condIntCode LE x y
1362 WordGtOp -> condIntCode GU x y
1363 WordGeOp -> condIntCode GEU x y
1364 WordEqOp -> condIntCode EQQ x y
1365 WordNeOp -> condIntCode NE x y
1366 WordLtOp -> condIntCode LU x y
1367 WordLeOp -> condIntCode LEU x y
1369 AddrGtOp -> condIntCode GU x y
1370 AddrGeOp -> condIntCode GEU x y
1371 AddrEqOp -> condIntCode EQQ x y
1372 AddrNeOp -> condIntCode NE x y
1373 AddrLtOp -> condIntCode LU x y
1374 AddrLeOp -> condIntCode LEU x y
1376 FloatGtOp -> condFltCode GTT x y
1377 FloatGeOp -> condFltCode GE x y
1378 FloatEqOp -> condFltCode EQQ x y
1379 FloatNeOp -> condFltCode NE x y
1380 FloatLtOp -> condFltCode LTT x y
1381 FloatLeOp -> condFltCode LE x y
1383 DoubleGtOp -> condFltCode GTT x y
1384 DoubleGeOp -> condFltCode GE x y
1385 DoubleEqOp -> condFltCode EQQ x y
1386 DoubleNeOp -> condFltCode NE x y
1387 DoubleLtOp -> condFltCode LTT x y
1388 DoubleLeOp -> condFltCode LE x y
1390 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1395 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1396 passed back up the tree.
1399 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1401 #if alpha_TARGET_ARCH
1402 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1403 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1404 #endif {- alpha_TARGET_ARCH -}
1406 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1407 #if i386_TARGET_ARCH
1409 condIntCode cond (StInd _ x) y
1411 = getAmode x `thenUs` \ amode ->
1413 code1 = amodeCode amode asmVoid
1414 y__2 = amodeAddr amode
1415 code__2 = asmParThen [code1] .
1416 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1418 returnUs (CondCode False cond code__2)
1421 imm__2 = case imm of Just x -> x
1423 condIntCode cond x (StInt 0)
1424 = getRegister x `thenUs` \ register1 ->
1425 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1427 code1 = registerCode register1 tmp1 asmVoid
1428 src1 = registerName register1 tmp1
1429 code__2 = asmParThen [code1] .
1430 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1432 returnUs (CondCode False cond code__2)
1434 condIntCode cond x y
1436 = getRegister x `thenUs` \ register1 ->
1437 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1439 code1 = registerCode register1 tmp1 asmVoid
1440 src1 = registerName register1 tmp1
1441 code__2 = asmParThen [code1] .
1442 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1444 returnUs (CondCode False cond code__2)
1447 imm__2 = case imm of Just x -> x
1449 condIntCode cond (StInd _ x) y
1450 = getAmode x `thenUs` \ amode ->
1451 getRegister y `thenUs` \ register2 ->
1452 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1454 code1 = amodeCode amode asmVoid
1455 src1 = amodeAddr amode
1456 code2 = registerCode register2 tmp2 asmVoid
1457 src2 = registerName register2 tmp2
1458 code__2 = asmParThen [code1, code2] .
1459 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1461 returnUs (CondCode False cond code__2)
1463 condIntCode cond y (StInd _ x)
1464 = getAmode x `thenUs` \ amode ->
1465 getRegister y `thenUs` \ register2 ->
1466 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1468 code1 = amodeCode amode asmVoid
1469 src1 = amodeAddr amode
1470 code2 = registerCode register2 tmp2 asmVoid
1471 src2 = registerName register2 tmp2
1472 code__2 = asmParThen [code1, code2] .
1473 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1475 returnUs (CondCode False cond code__2)
1477 condIntCode cond x y
1478 = getRegister x `thenUs` \ register1 ->
1479 getRegister y `thenUs` \ register2 ->
1480 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1481 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1483 code1 = registerCode register1 tmp1 asmVoid
1484 src1 = registerName register1 tmp1
1485 code2 = registerCode register2 tmp2 asmVoid
1486 src2 = registerName register2 tmp2
1487 code__2 = asmParThen [code1, code2] .
1488 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1490 returnUs (CondCode False cond code__2)
1494 condFltCode cond x (StDouble 0.0)
1495 = getRegister x `thenUs` \ register1 ->
1496 getNewRegNCG (registerRep register1)
1499 pk1 = registerRep register1
1500 code1 = registerCode register1 tmp1
1501 src1 = registerName register1 tmp1
1503 code__2 = asmParThen [code1 asmVoid] .
1504 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1506 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1507 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1511 returnUs (CondCode True (fix_FP_cond cond) code__2)
1513 condFltCode cond x y
1514 = getRegister x `thenUs` \ register1 ->
1515 getRegister y `thenUs` \ register2 ->
1516 getNewRegNCG (registerRep register1)
1518 getNewRegNCG (registerRep register2)
1521 pk1 = registerRep register1
1522 code1 = registerCode register1 tmp1
1523 src1 = registerName register1 tmp1
1525 code2 = registerCode register2 tmp2
1526 src2 = registerName register2 tmp2
1528 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1529 mkSeqInstrs [FUCOMPP,
1531 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1532 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1536 returnUs (CondCode True (fix_FP_cond cond) code__2)
1538 {- On the 486, the flags set by FP compare are the unsigned ones!
1539 (This looks like a HACK to me. WDP 96/03)
1542 fix_FP_cond :: Cond -> Cond
1544 fix_FP_cond GE = GEU
1545 fix_FP_cond GTT = GU
1546 fix_FP_cond LTT = LU
1547 fix_FP_cond LE = LEU
1548 fix_FP_cond any = any
1550 #endif {- i386_TARGET_ARCH -}
1551 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1552 #if sparc_TARGET_ARCH
1554 condIntCode cond x (StInt y)
1556 = getRegister x `thenUs` \ register ->
1557 getNewRegNCG IntRep `thenUs` \ tmp ->
1559 code = registerCode register tmp
1560 src1 = registerName register tmp
1561 src2 = ImmInt (fromInteger y)
1562 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1564 returnUs (CondCode False cond code__2)
1566 condIntCode cond x y
1567 = getRegister x `thenUs` \ register1 ->
1568 getRegister y `thenUs` \ register2 ->
1569 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1570 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1572 code1 = registerCode register1 tmp1 asmVoid
1573 src1 = registerName register1 tmp1
1574 code2 = registerCode register2 tmp2 asmVoid
1575 src2 = registerName register2 tmp2
1576 code__2 = asmParThen [code1, code2] .
1577 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1579 returnUs (CondCode False cond code__2)
1582 condFltCode cond x y
1583 = getRegister x `thenUs` \ register1 ->
1584 getRegister y `thenUs` \ register2 ->
1585 getNewRegNCG (registerRep register1)
1587 getNewRegNCG (registerRep register2)
1589 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1591 promote x = asmInstr (FxTOy F DF x tmp)
1593 pk1 = registerRep register1
1594 code1 = registerCode register1 tmp1
1595 src1 = registerName register1 tmp1
1597 pk2 = registerRep register2
1598 code2 = registerCode register2 tmp2
1599 src2 = registerName register2 tmp2
1603 asmParThen [code1 asmVoid, code2 asmVoid] .
1604 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1605 else if pk1 == FloatRep then
1606 asmParThen [code1 (promote src1), code2 asmVoid] .
1607 mkSeqInstr (FCMP True DF tmp src2)
1609 asmParThen [code1 asmVoid, code2 (promote src2)] .
1610 mkSeqInstr (FCMP True DF src1 tmp)
1612 returnUs (CondCode True cond code__2)
1614 #endif {- sparc_TARGET_ARCH -}
1617 %************************************************************************
1619 \subsection{Generating assignments}
1621 %************************************************************************
1623 Assignments are really at the heart of the whole code generation
1624 business. Almost all top-level nodes of any real importance are
1625 assignments, which correspond to loads, stores, or register transfers.
1626 If we're really lucky, some of the register transfers will go away,
1627 because we can use the destination register to complete the code
1628 generation for the right hand side. This only fails when the right
1629 hand side is forced into a fixed register (e.g. the result of a call).
1632 assignIntCode, assignFltCode
1633 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1635 #if alpha_TARGET_ARCH
1637 assignIntCode pk (StInd _ dst) src
1638 = getNewRegNCG IntRep `thenUs` \ tmp ->
1639 getAmode dst `thenUs` \ amode ->
1640 getRegister src `thenUs` \ register ->
1642 code1 = amodeCode amode asmVoid
1643 dst__2 = amodeAddr amode
1644 code2 = registerCode register tmp asmVoid
1645 src__2 = registerName register tmp
1646 sz = primRepToSize pk
1647 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1651 assignIntCode pk dst src
1652 = getRegister dst `thenUs` \ register1 ->
1653 getRegister src `thenUs` \ register2 ->
1655 dst__2 = registerName register1 zeroh
1656 code = registerCode register2 dst__2
1657 src__2 = registerName register2 dst__2
1658 code__2 = if isFixed register2
1659 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1664 #endif {- alpha_TARGET_ARCH -}
1665 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1666 #if i386_TARGET_ARCH
1668 assignIntCode pk (StInd _ dst) src
1669 = getAmode dst `thenUs` \ amode ->
1670 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1672 code1 = amodeCode amode asmVoid
1673 dst__2 = amodeAddr amode
1674 code__2 = asmParThen [code1, codesrc asmVoid] .
1675 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1681 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1685 = returnUs (asmParThen [], OpImm imm_op, L)
1688 imm_op = case imm of Just x -> x
1691 = getRegister op `thenUs` \ register ->
1692 getNewRegNCG (registerRep register)
1695 code = registerCode register tmp
1696 reg = registerName register tmp
1697 pk = registerRep register
1698 sz = primRepToSize pk
1700 returnUs (code, OpReg reg, sz)
1702 assignIntCode pk dst (StInd _ src)
1703 = getNewRegNCG IntRep `thenUs` \ tmp ->
1704 getAmode src `thenUs` \ amode ->
1705 getRegister dst `thenUs` \ register ->
1707 code1 = amodeCode amode asmVoid
1708 src__2 = amodeAddr amode
1709 code2 = registerCode register tmp asmVoid
1710 dst__2 = registerName register tmp
1711 sz = primRepToSize pk
1712 code__2 = asmParThen [code1, code2] .
1713 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1717 assignIntCode pk dst src
1718 = getRegister dst `thenUs` \ register1 ->
1719 getRegister src `thenUs` \ register2 ->
1720 getNewRegNCG IntRep `thenUs` \ tmp ->
1722 dst__2 = registerName register1 tmp
1723 code = registerCode register2 dst__2
1724 src__2 = registerName register2 dst__2
1725 code__2 = if isFixed register2 && dst__2 /= src__2
1726 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1731 #endif {- i386_TARGET_ARCH -}
1732 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1733 #if sparc_TARGET_ARCH
1735 assignIntCode pk (StInd _ dst) src
1736 = getNewRegNCG IntRep `thenUs` \ tmp ->
1737 getAmode dst `thenUs` \ amode ->
1738 getRegister src `thenUs` \ register ->
1740 code1 = amodeCode amode asmVoid
1741 dst__2 = amodeAddr amode
1742 code2 = registerCode register tmp asmVoid
1743 src__2 = registerName register tmp
1744 sz = primRepToSize pk
1745 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1749 assignIntCode pk dst src
1750 = getRegister dst `thenUs` \ register1 ->
1751 getRegister src `thenUs` \ register2 ->
1753 dst__2 = registerName register1 g0
1754 code = registerCode register2 dst__2
1755 src__2 = registerName register2 dst__2
1756 code__2 = if isFixed register2
1757 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1762 #endif {- sparc_TARGET_ARCH -}
1765 % --------------------------------
1766 Floating-point assignments:
1767 % --------------------------------
1769 #if alpha_TARGET_ARCH
1771 assignFltCode pk (StInd _ dst) src
1772 = getNewRegNCG pk `thenUs` \ tmp ->
1773 getAmode dst `thenUs` \ amode ->
1774 getRegister src `thenUs` \ register ->
1776 code1 = amodeCode amode asmVoid
1777 dst__2 = amodeAddr amode
1778 code2 = registerCode register tmp asmVoid
1779 src__2 = registerName register tmp
1780 sz = primRepToSize pk
1781 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1785 assignFltCode pk dst src
1786 = getRegister dst `thenUs` \ register1 ->
1787 getRegister src `thenUs` \ register2 ->
1789 dst__2 = registerName register1 zeroh
1790 code = registerCode register2 dst__2
1791 src__2 = registerName register2 dst__2
1792 code__2 = if isFixed register2
1793 then code . mkSeqInstr (FMOV src__2 dst__2)
1798 #endif {- alpha_TARGET_ARCH -}
1799 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1800 #if i386_TARGET_ARCH
1802 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1803 = getNewRegNCG IntRep `thenUs` \ tmp ->
1804 getAmode src `thenUs` \ amodesrc ->
1805 getAmode dst `thenUs` \ amodedst ->
1806 --getRegister src `thenUs` \ register ->
1808 codesrc1 = amodeCode amodesrc asmVoid
1809 addrsrc1 = amodeAddr amodesrc
1810 codedst1 = amodeCode amodedst asmVoid
1811 addrdst1 = amodeAddr amodedst
1812 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1813 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1815 code__2 = asmParThen [codesrc1, codedst1] .
1816 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1817 MOV L (OpReg tmp) (OpAddr addrdst1)]
1820 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1821 MOV L (OpReg tmp) (OpAddr addrdst2)]
1826 assignFltCode pk (StInd _ dst) src
1827 = --getNewRegNCG pk `thenUs` \ tmp ->
1828 getAmode dst `thenUs` \ amode ->
1829 getRegister src `thenUs` \ register ->
1831 sz = primRepToSize pk
1832 dst__2 = amodeAddr amode
1834 code1 = amodeCode amode asmVoid
1835 code2 = registerCode register {-tmp-}st0 asmVoid
1837 --src__2= registerName register tmp
1838 pk__2 = registerRep register
1839 sz__2 = primRepToSize pk__2
1841 code__2 = asmParThen [code1, code2] .
1842 mkSeqInstr (FSTP sz (OpAddr dst__2))
1846 assignFltCode pk dst src
1847 = getRegister dst `thenUs` \ register1 ->
1848 getRegister src `thenUs` \ register2 ->
1849 --getNewRegNCG (registerRep register2)
1850 -- `thenUs` \ tmp ->
1852 sz = primRepToSize pk
1853 dst__2 = registerName register1 st0 --tmp
1855 code = registerCode register2 dst__2
1856 src__2 = registerName register2 dst__2
1862 #endif {- i386_TARGET_ARCH -}
1863 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1864 #if sparc_TARGET_ARCH
1866 assignFltCode pk (StInd _ dst) src
1867 = getNewRegNCG pk `thenUs` \ tmp1 ->
1868 getAmode dst `thenUs` \ amode ->
1869 getRegister src `thenUs` \ register ->
1871 sz = primRepToSize pk
1872 dst__2 = amodeAddr amode
1874 code1 = amodeCode amode asmVoid
1875 code2 = registerCode register tmp1 asmVoid
1877 src__2 = registerName register tmp1
1878 pk__2 = registerRep register
1879 sz__2 = primRepToSize pk__2
1881 code__2 = asmParThen [code1, code2] .
1883 mkSeqInstr (ST sz src__2 dst__2)
1885 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1889 assignFltCode pk dst src
1890 = getRegister dst `thenUs` \ register1 ->
1891 getRegister src `thenUs` \ register2 ->
1893 pk__2 = registerRep register2
1894 sz__2 = primRepToSize pk__2
1896 getNewRegNCG pk__2 `thenUs` \ tmp ->
1898 sz = primRepToSize pk
1899 dst__2 = registerName register1 g0 -- must be Fixed
1902 reg__2 = if pk /= pk__2 then tmp else dst__2
1904 code = registerCode register2 reg__2
1906 src__2 = registerName register2 reg__2
1910 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1911 else if isFixed register2 then
1912 code . mkSeqInstr (FMOV sz src__2 dst__2)
1918 #endif {- sparc_TARGET_ARCH -}
1921 %************************************************************************
1923 \subsection{Generating an unconditional branch}
1925 %************************************************************************
1927 We accept two types of targets: an immediate CLabel or a tree that
1928 gets evaluated into a register. Any CLabels which are AsmTemporaries
1929 are assumed to be in the local block of code, close enough for a
1930 branch instruction. Other CLabels are assumed to be far away.
1932 (If applicable) Do not fill the delay slots here; you will confuse the
1936 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1938 #if alpha_TARGET_ARCH
1940 genJump (StCLbl lbl)
1941 | isAsmTemp lbl = returnInstr (BR target)
1942 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1944 target = ImmCLbl lbl
1947 = getRegister tree `thenUs` \ register ->
1948 getNewRegNCG PtrRep `thenUs` \ tmp ->
1950 dst = registerName register pv
1951 code = registerCode register pv
1952 target = registerName register pv
1954 if isFixed register then
1955 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1957 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1959 #endif {- alpha_TARGET_ARCH -}
1960 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1961 #if i386_TARGET_ARCH
1964 genJump (StCLbl lbl)
1965 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1966 | otherwise = returnInstrs [JMP (OpImm target)]
1968 target = ImmCLbl lbl
1971 genJump (StInd pk mem)
1972 = getAmode mem `thenUs` \ amode ->
1974 code = amodeCode amode
1975 target = amodeAddr amode
1977 returnSeq code [JMP (OpAddr target)]
1981 = returnInstr (JMP (OpImm target))
1984 = getRegister tree `thenUs` \ register ->
1985 getNewRegNCG PtrRep `thenUs` \ tmp ->
1987 code = registerCode register tmp
1988 target = registerName register tmp
1990 returnSeq code [JMP (OpReg target)]
1993 target = case imm of Just x -> x
1995 #endif {- i386_TARGET_ARCH -}
1996 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1997 #if sparc_TARGET_ARCH
1999 genJump (StCLbl lbl)
2000 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
2001 | otherwise = returnInstrs [CALL target 0 True, NOP]
2003 target = ImmCLbl lbl
2006 = getRegister tree `thenUs` \ register ->
2007 getNewRegNCG PtrRep `thenUs` \ tmp ->
2009 code = registerCode register tmp
2010 target = registerName register tmp
2012 returnSeq code [JMP (AddrRegReg target g0), NOP]
2014 #endif {- sparc_TARGET_ARCH -}
2017 %************************************************************************
2019 \subsection{Conditional jumps}
2021 %************************************************************************
2023 Conditional jumps are always to local labels, so we can use branch
2024 instructions. We peek at the arguments to decide what kind of
2027 ALPHA: For comparisons with 0, we're laughing, because we can just do
2028 the desired conditional branch.
2030 I386: First, we have to ensure that the condition
2031 codes are set according to the supplied comparison operation.
2033 SPARC: First, we have to ensure that the condition codes are set
2034 according to the supplied comparison operation. We generate slightly
2035 different code for floating point comparisons, because a floating
2036 point operation cannot directly precede a @BF@. We assume the worst
2037 and fill that slot with a @NOP@.
2039 SPARC: Do not fill the delay slots here; you will confuse the register
2044 :: CLabel -- the branch target
2045 -> StixTree -- the condition on which to branch
2046 -> UniqSM InstrBlock
2048 #if alpha_TARGET_ARCH
2050 genCondJump lbl (StPrim op [x, StInt 0])
2051 = getRegister x `thenUs` \ register ->
2052 getNewRegNCG (registerRep register)
2055 code = registerCode register tmp
2056 value = registerName register tmp
2057 pk = registerRep register
2058 target = ImmCLbl lbl
2060 returnSeq code [BI (cmpOp op) value target]
2062 cmpOp CharGtOp = GTT
2064 cmpOp CharEqOp = EQQ
2066 cmpOp CharLtOp = LTT
2075 cmpOp WordGeOp = ALWAYS
2076 cmpOp WordEqOp = EQQ
2078 cmpOp WordLtOp = NEVER
2079 cmpOp WordLeOp = EQQ
2081 cmpOp AddrGeOp = ALWAYS
2082 cmpOp AddrEqOp = EQQ
2084 cmpOp AddrLtOp = NEVER
2085 cmpOp AddrLeOp = EQQ
2087 genCondJump lbl (StPrim op [x, StDouble 0.0])
2088 = getRegister x `thenUs` \ register ->
2089 getNewRegNCG (registerRep register)
2092 code = registerCode register tmp
2093 value = registerName register tmp
2094 pk = registerRep register
2095 target = ImmCLbl lbl
2097 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2099 cmpOp FloatGtOp = GTT
2100 cmpOp FloatGeOp = GE
2101 cmpOp FloatEqOp = EQQ
2102 cmpOp FloatNeOp = NE
2103 cmpOp FloatLtOp = LTT
2104 cmpOp FloatLeOp = LE
2105 cmpOp DoubleGtOp = GTT
2106 cmpOp DoubleGeOp = GE
2107 cmpOp DoubleEqOp = EQQ
2108 cmpOp DoubleNeOp = NE
2109 cmpOp DoubleLtOp = LTT
2110 cmpOp DoubleLeOp = LE
2112 genCondJump lbl (StPrim op [x, y])
2114 = trivialFCode pr instr x y `thenUs` \ register ->
2115 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2117 code = registerCode register tmp
2118 result = registerName register tmp
2119 target = ImmCLbl lbl
2121 returnUs (code . mkSeqInstr (BF cond result target))
2123 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2125 fltCmpOp op = case op of
2139 (instr, cond) = case op of
2140 FloatGtOp -> (FCMP TF LE, EQQ)
2141 FloatGeOp -> (FCMP TF LTT, EQQ)
2142 FloatEqOp -> (FCMP TF EQQ, NE)
2143 FloatNeOp -> (FCMP TF EQQ, EQQ)
2144 FloatLtOp -> (FCMP TF LTT, NE)
2145 FloatLeOp -> (FCMP TF LE, NE)
2146 DoubleGtOp -> (FCMP TF LE, EQQ)
2147 DoubleGeOp -> (FCMP TF LTT, EQQ)
2148 DoubleEqOp -> (FCMP TF EQQ, NE)
2149 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2150 DoubleLtOp -> (FCMP TF LTT, NE)
2151 DoubleLeOp -> (FCMP TF LE, NE)
2153 genCondJump lbl (StPrim op [x, y])
2154 = trivialCode instr x y `thenUs` \ register ->
2155 getNewRegNCG IntRep `thenUs` \ tmp ->
2157 code = registerCode register tmp
2158 result = registerName register tmp
2159 target = ImmCLbl lbl
2161 returnUs (code . mkSeqInstr (BI cond result target))
2163 (instr, cond) = case op of
2164 CharGtOp -> (CMP LE, EQQ)
2165 CharGeOp -> (CMP LTT, EQQ)
2166 CharEqOp -> (CMP EQQ, NE)
2167 CharNeOp -> (CMP EQQ, EQQ)
2168 CharLtOp -> (CMP LTT, NE)
2169 CharLeOp -> (CMP LE, NE)
2170 IntGtOp -> (CMP LE, EQQ)
2171 IntGeOp -> (CMP LTT, EQQ)
2172 IntEqOp -> (CMP EQQ, NE)
2173 IntNeOp -> (CMP EQQ, EQQ)
2174 IntLtOp -> (CMP LTT, NE)
2175 IntLeOp -> (CMP LE, NE)
2176 WordGtOp -> (CMP ULE, EQQ)
2177 WordGeOp -> (CMP ULT, EQQ)
2178 WordEqOp -> (CMP EQQ, NE)
2179 WordNeOp -> (CMP EQQ, EQQ)
2180 WordLtOp -> (CMP ULT, NE)
2181 WordLeOp -> (CMP ULE, NE)
2182 AddrGtOp -> (CMP ULE, EQQ)
2183 AddrGeOp -> (CMP ULT, EQQ)
2184 AddrEqOp -> (CMP EQQ, NE)
2185 AddrNeOp -> (CMP EQQ, EQQ)
2186 AddrLtOp -> (CMP ULT, NE)
2187 AddrLeOp -> (CMP ULE, NE)
2189 #endif {- alpha_TARGET_ARCH -}
2190 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2191 #if i386_TARGET_ARCH
2193 genCondJump lbl bool
2194 = getCondCode bool `thenUs` \ condition ->
2196 code = condCode condition
2197 cond = condName condition
2198 target = ImmCLbl lbl
2200 returnSeq code [JXX cond lbl]
2202 #endif {- i386_TARGET_ARCH -}
2203 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2204 #if sparc_TARGET_ARCH
2206 genCondJump lbl bool
2207 = getCondCode bool `thenUs` \ condition ->
2209 code = condCode condition
2210 cond = condName condition
2211 target = ImmCLbl lbl
2214 if condFloat condition then
2215 [NOP, BF cond False target, NOP]
2217 [BI cond False target, NOP]
2220 #endif {- sparc_TARGET_ARCH -}
2223 %************************************************************************
2225 \subsection{Generating C calls}
2227 %************************************************************************
2229 Now the biggest nightmare---calls. Most of the nastiness is buried in
2230 @get_arg@, which moves the arguments to the correct registers/stack
2231 locations. Apart from that, the code is easy.
2233 (If applicable) Do not fill the delay slots here; you will confuse the
2238 :: FAST_STRING -- function to call
2239 -> PrimRep -- type of the result
2240 -> [StixTree] -- arguments (of mixed type)
2241 -> UniqSM InstrBlock
2243 #if alpha_TARGET_ARCH
2245 genCCall fn kind args
2246 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2247 `thenUs` \ ((unused,_), argCode) ->
2249 nRegs = length allArgRegs - length unused
2250 code = asmParThen (map ($ asmVoid) argCode)
2253 LDA pv (AddrImm (ImmLab (ptext fn))),
2254 JSR ra (AddrReg pv) nRegs,
2255 LDGP gp (AddrReg ra)]
2257 ------------------------
2258 {- Try to get a value into a specific register (or registers) for
2259 a call. The first 6 arguments go into the appropriate
2260 argument register (separate registers for integer and floating
2261 point arguments, but used in lock-step), and the remaining
2262 arguments are dumped to the stack, beginning at 0(sp). Our
2263 first argument is a pair of the list of remaining argument
2264 registers to be assigned for this call and the next stack
2265 offset to use for overflowing arguments. This way,
2266 @get_Arg@ can be applied to all of a call's arguments using
2270 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2271 -> StixTree -- Current argument
2272 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2274 -- We have to use up all of our argument registers first...
2276 get_arg ((iDst,fDst):dsts, offset) arg
2277 = getRegister arg `thenUs` \ register ->
2279 reg = if isFloatingRep pk then fDst else iDst
2280 code = registerCode register reg
2281 src = registerName register reg
2282 pk = registerRep register
2285 if isFloatingRep pk then
2286 ((dsts, offset), if isFixed register then
2287 code . mkSeqInstr (FMOV src fDst)
2290 ((dsts, offset), if isFixed register then
2291 code . mkSeqInstr (OR src (RIReg src) iDst)
2294 -- Once we have run out of argument registers, we move to the
2297 get_arg ([], offset) arg
2298 = getRegister arg `thenUs` \ register ->
2299 getNewRegNCG (registerRep register)
2302 code = registerCode register tmp
2303 src = registerName register tmp
2304 pk = registerRep register
2305 sz = primRepToSize pk
2307 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2309 #endif {- alpha_TARGET_ARCH -}
2310 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2311 #if i386_TARGET_ARCH
2313 genCCall fn kind [StInt i]
2314 | fn == SLIT ("PerformGC_wrapper")
2316 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2317 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2322 = getUniqLabelNCG `thenUs` \ lbl ->
2324 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2325 MOV L (OpImm (ImmCLbl lbl))
2326 -- this is hardwired
2327 (OpAddr (Address (Just ebx) Nothing (ImmInt 104))),
2328 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2334 genCCall fn kind args
2335 = mapUs get_call_arg args `thenUs` \ argCode ->
2338 {- OLD: Since there's no attempt at stealing %esp at the moment,
2339 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2340 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2341 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (Address (Just ebx) Nothing (ImmInt 80))),
2342 MOV L (OpAddr (Address (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2346 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2347 call = [CALL fn__2 ,
2348 -- pop args; all args word sized?
2349 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2351 -- Don't restore %esp (see above)
2352 -- MOV L (OpAddr (Address (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2355 returnSeq (code2) call
2357 -- function names that begin with '.' are assumed to be special
2358 -- internally generated names like '.mul,' which don't get an
2359 -- underscore prefix
2360 -- ToDo:needed (WDP 96/03) ???
2361 fn__2 = case (_HEAD_ fn) of
2362 '.' -> ImmLit (ptext fn)
2363 _ -> ImmLab (ptext fn)
2366 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2369 = get_op arg `thenUs` \ (code, op, sz) ->
2370 returnUs (code . mkSeqInstr (PUSH sz op))
2375 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2378 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2380 get_op (StInd pk mem)
2381 = getAmode mem `thenUs` \ amode ->
2383 code = amodeCode amode --asmVoid
2384 addr = amodeAddr amode
2385 sz = primRepToSize pk
2387 returnUs (code, OpAddr addr, sz)
2390 = getRegister op `thenUs` \ register ->
2391 getNewRegNCG (registerRep register)
2394 code = registerCode register tmp
2395 reg = registerName register tmp
2396 pk = registerRep register
2397 sz = primRepToSize pk
2399 returnUs (code, OpReg reg, sz)
2401 #endif {- i386_TARGET_ARCH -}
2402 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2403 #if sparc_TARGET_ARCH
2405 genCCall fn kind args
2406 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2407 `thenUs` \ ((unused,_), argCode) ->
2409 nRegs = length allArgRegs - length unused
2410 call = CALL fn__2 nRegs False
2411 code = asmParThen (map ($ asmVoid) argCode)
2413 returnSeq code [call, NOP]
2415 -- function names that begin with '.' are assumed to be special
2416 -- internally generated names like '.mul,' which don't get an
2417 -- underscore prefix
2418 -- ToDo:needed (WDP 96/03) ???
2419 fn__2 = case (_HEAD_ fn) of
2420 '.' -> ImmLit (ptext fn)
2421 _ -> ImmLab (ptext fn)
2423 ------------------------------------
2424 {- Try to get a value into a specific register (or registers) for
2425 a call. The SPARC calling convention is an absolute
2426 nightmare. The first 6x32 bits of arguments are mapped into
2427 %o0 through %o5, and the remaining arguments are dumped to the
2428 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2429 first argument is a pair of the list of remaining argument
2430 registers to be assigned for this call and the next stack
2431 offset to use for overflowing arguments. This way,
2432 @get_arg@ can be applied to all of a call's arguments using
2436 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2437 -> StixTree -- Current argument
2438 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2440 -- We have to use up all of our argument registers first...
2442 get_arg (dst:dsts, offset) arg
2443 = getRegister arg `thenUs` \ register ->
2444 getNewRegNCG (registerRep register)
2447 reg = if isFloatingRep pk then tmp else dst
2448 code = registerCode register reg
2449 src = registerName register reg
2450 pk = registerRep register
2452 returnUs (case pk of
2455 [] -> (([], offset + 1), code . mkSeqInstrs [
2456 -- conveniently put the second part in the right stack
2457 -- location, and load the first part into %o5
2458 ST DF src (spRel (offset - 1)),
2459 LD W (spRel (offset - 1)) dst])
2460 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2461 ST DF src (spRel (-2)),
2462 LD W (spRel (-2)) dst,
2463 LD W (spRel (-1)) dst__2])
2464 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2465 ST F src (spRel (-2)),
2466 LD W (spRel (-2)) dst])
2467 _ -> ((dsts, offset), if isFixed register then
2468 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2471 -- Once we have run out of argument registers, we move to the
2474 get_arg ([], offset) arg
2475 = getRegister arg `thenUs` \ register ->
2476 getNewRegNCG (registerRep register)
2479 code = registerCode register tmp
2480 src = registerName register tmp
2481 pk = registerRep register
2482 sz = primRepToSize pk
2483 words = if pk == DoubleRep then 2 else 1
2485 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2487 #endif {- sparc_TARGET_ARCH -}
2490 %************************************************************************
2492 \subsection{Support bits}
2494 %************************************************************************
2496 %************************************************************************
2498 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2500 %************************************************************************
2502 Turn those condition codes into integers now (when they appear on
2503 the right hand side of an assignment).
2505 (If applicable) Do not fill the delay slots here; you will confuse the
2509 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2511 #if alpha_TARGET_ARCH
2512 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2513 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2514 #endif {- alpha_TARGET_ARCH -}
2516 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2517 #if i386_TARGET_ARCH
2520 = condIntCode cond x y `thenUs` \ condition ->
2521 getNewRegNCG IntRep `thenUs` \ tmp ->
2522 --getRegister dst `thenUs` \ register ->
2524 --code2 = registerCode register tmp asmVoid
2525 --dst__2 = registerName register tmp
2526 code = condCode condition
2527 cond = condName condition
2528 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2529 code__2 dst = code . mkSeqInstrs [
2530 SETCC cond (OpReg tmp),
2531 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2532 MOV L (OpReg tmp) (OpReg dst)]
2534 returnUs (Any IntRep code__2)
2537 = getUniqLabelNCG `thenUs` \ lbl1 ->
2538 getUniqLabelNCG `thenUs` \ lbl2 ->
2539 condFltCode cond x y `thenUs` \ condition ->
2541 code = condCode condition
2542 cond = condName condition
2543 code__2 dst = code . mkSeqInstrs [
2545 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2548 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2551 returnUs (Any IntRep code__2)
2553 #endif {- i386_TARGET_ARCH -}
2554 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2555 #if sparc_TARGET_ARCH
2557 condIntReg EQQ x (StInt 0)
2558 = getRegister x `thenUs` \ register ->
2559 getNewRegNCG IntRep `thenUs` \ tmp ->
2561 code = registerCode register tmp
2562 src = registerName register tmp
2563 code__2 dst = code . mkSeqInstrs [
2564 SUB False True g0 (RIReg src) g0,
2565 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2567 returnUs (Any IntRep code__2)
2570 = getRegister x `thenUs` \ register1 ->
2571 getRegister y `thenUs` \ register2 ->
2572 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2573 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2575 code1 = registerCode register1 tmp1 asmVoid
2576 src1 = registerName register1 tmp1
2577 code2 = registerCode register2 tmp2 asmVoid
2578 src2 = registerName register2 tmp2
2579 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2580 XOR False src1 (RIReg src2) dst,
2581 SUB False True g0 (RIReg dst) g0,
2582 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2584 returnUs (Any IntRep code__2)
2586 condIntReg NE x (StInt 0)
2587 = getRegister x `thenUs` \ register ->
2588 getNewRegNCG IntRep `thenUs` \ tmp ->
2590 code = registerCode register tmp
2591 src = registerName register tmp
2592 code__2 dst = code . mkSeqInstrs [
2593 SUB False True g0 (RIReg src) g0,
2594 ADD True False g0 (RIImm (ImmInt 0)) dst]
2596 returnUs (Any IntRep code__2)
2599 = getRegister x `thenUs` \ register1 ->
2600 getRegister y `thenUs` \ register2 ->
2601 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2602 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2604 code1 = registerCode register1 tmp1 asmVoid
2605 src1 = registerName register1 tmp1
2606 code2 = registerCode register2 tmp2 asmVoid
2607 src2 = registerName register2 tmp2
2608 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2609 XOR False src1 (RIReg src2) dst,
2610 SUB False True g0 (RIReg dst) g0,
2611 ADD True False g0 (RIImm (ImmInt 0)) dst]
2613 returnUs (Any IntRep code__2)
2616 = getUniqLabelNCG `thenUs` \ lbl1 ->
2617 getUniqLabelNCG `thenUs` \ lbl2 ->
2618 condIntCode cond x y `thenUs` \ condition ->
2620 code = condCode condition
2621 cond = condName condition
2622 code__2 dst = code . mkSeqInstrs [
2623 BI cond False (ImmCLbl lbl1), NOP,
2624 OR False g0 (RIImm (ImmInt 0)) dst,
2625 BI ALWAYS False (ImmCLbl lbl2), NOP,
2627 OR False g0 (RIImm (ImmInt 1)) dst,
2630 returnUs (Any IntRep code__2)
2633 = getUniqLabelNCG `thenUs` \ lbl1 ->
2634 getUniqLabelNCG `thenUs` \ lbl2 ->
2635 condFltCode cond x y `thenUs` \ condition ->
2637 code = condCode condition
2638 cond = condName condition
2639 code__2 dst = code . mkSeqInstrs [
2641 BF cond False (ImmCLbl lbl1), NOP,
2642 OR False g0 (RIImm (ImmInt 0)) dst,
2643 BI ALWAYS False (ImmCLbl lbl2), NOP,
2645 OR False g0 (RIImm (ImmInt 1)) dst,
2648 returnUs (Any IntRep code__2)
2650 #endif {- sparc_TARGET_ARCH -}
2653 %************************************************************************
2655 \subsubsection{@trivial*Code@: deal with trivial instructions}
2657 %************************************************************************
2659 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2660 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2661 for constants on the right hand side, because that's where the generic
2662 optimizer will have put them.
2664 Similarly, for unary instructions, we don't have to worry about
2665 matching an StInt as the argument, because genericOpt will already
2666 have handled the constant-folding.
2670 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2671 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2672 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2674 -> StixTree -> StixTree -- the two arguments
2679 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2680 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2682 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2683 (Size -> Operand -> Instr)
2684 -> (Size -> Operand -> Instr) {-reversed instr-}
2686 -> Instr {-reversed instr: pop-}
2688 -> StixTree -> StixTree -- the two arguments
2692 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2693 ,IF_ARCH_i386 ((Operand -> Instr)
2694 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2696 -> StixTree -- the one argument
2701 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2702 ,IF_ARCH_i386 (Instr
2703 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2705 -> StixTree -- the one argument
2708 #if alpha_TARGET_ARCH
2710 trivialCode instr x (StInt y)
2712 = getRegister x `thenUs` \ register ->
2713 getNewRegNCG IntRep `thenUs` \ tmp ->
2715 code = registerCode register tmp
2716 src1 = registerName register tmp
2717 src2 = ImmInt (fromInteger y)
2718 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2720 returnUs (Any IntRep code__2)
2722 trivialCode instr x y
2723 = getRegister x `thenUs` \ register1 ->
2724 getRegister y `thenUs` \ register2 ->
2725 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2726 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2728 code1 = registerCode register1 tmp1 asmVoid
2729 src1 = registerName register1 tmp1
2730 code2 = registerCode register2 tmp2 asmVoid
2731 src2 = registerName register2 tmp2
2732 code__2 dst = asmParThen [code1, code2] .
2733 mkSeqInstr (instr src1 (RIReg src2) dst)
2735 returnUs (Any IntRep code__2)
2738 trivialUCode instr x
2739 = getRegister x `thenUs` \ register ->
2740 getNewRegNCG IntRep `thenUs` \ tmp ->
2742 code = registerCode register tmp
2743 src = registerName register tmp
2744 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2746 returnUs (Any IntRep code__2)
2749 trivialFCode _ instr x y
2750 = getRegister x `thenUs` \ register1 ->
2751 getRegister y `thenUs` \ register2 ->
2752 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2753 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2755 code1 = registerCode register1 tmp1
2756 src1 = registerName register1 tmp1
2758 code2 = registerCode register2 tmp2
2759 src2 = registerName register2 tmp2
2761 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2762 mkSeqInstr (instr src1 src2 dst)
2764 returnUs (Any DoubleRep code__2)
2766 trivialUFCode _ instr x
2767 = getRegister x `thenUs` \ register ->
2768 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2770 code = registerCode register tmp
2771 src = registerName register tmp
2772 code__2 dst = code . mkSeqInstr (instr src dst)
2774 returnUs (Any DoubleRep code__2)
2776 #endif {- alpha_TARGET_ARCH -}
2777 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2778 #if i386_TARGET_ARCH
2780 trivialCode instr x y
2782 = getRegister x `thenUs` \ register1 ->
2783 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2785 -- fixedname = registerName register1 eax
2786 code__2 dst = let code1 = registerCode register1 dst
2787 src1 = registerName register1 dst
2789 if isFixed register1 && src1 /= dst
2790 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2791 instr (OpImm imm__2) (OpReg dst)]
2793 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2795 returnUs (Any IntRep code__2)
2798 imm__2 = case imm of Just x -> x
2800 trivialCode instr x y
2802 = getRegister y `thenUs` \ register1 ->
2803 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2805 -- fixedname = registerName register1 eax
2806 code__2 dst = let code1 = registerCode register1 dst
2807 src1 = registerName register1 dst
2809 if isFixed register1 && src1 /= dst
2810 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2811 instr (OpImm imm__2) (OpReg dst)]
2813 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2815 returnUs (Any IntRep code__2)
2818 imm__2 = case imm of Just x -> x
2820 trivialCode instr x (StInd pk mem)
2821 = getRegister x `thenUs` \ register ->
2822 --getNewRegNCG IntRep `thenUs` \ tmp ->
2823 getAmode mem `thenUs` \ amode ->
2825 -- fixedname = registerName register eax
2826 code2 = amodeCode amode asmVoid
2827 src2 = amodeAddr amode
2828 code__2 dst = let code1 = registerCode register dst asmVoid
2829 src1 = registerName register dst
2830 in asmParThen [code1, code2] .
2831 if isFixed register && src1 /= dst
2832 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2833 instr (OpAddr src2) (OpReg dst)]
2835 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2837 returnUs (Any pk code__2)
2839 trivialCode instr (StInd pk mem) y
2840 = getRegister y `thenUs` \ register ->
2841 --getNewRegNCG IntRep `thenUs` \ tmp ->
2842 getAmode mem `thenUs` \ amode ->
2844 -- fixedname = registerName register eax
2845 code2 = amodeCode amode asmVoid
2846 src2 = amodeAddr amode
2848 code1 = registerCode register dst asmVoid
2849 src1 = registerName register dst
2850 in asmParThen [code1, code2] .
2851 if isFixed register && src1 /= dst
2852 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2853 instr (OpAddr src2) (OpReg dst)]
2855 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2857 returnUs (Any pk code__2)
2859 trivialCode instr x y
2860 = getRegister x `thenUs` \ register1 ->
2861 getRegister y `thenUs` \ register2 ->
2862 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2863 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2865 -- fixedname = registerName register1 eax
2866 code2 = registerCode register2 tmp2 asmVoid
2867 src2 = registerName register2 tmp2
2869 code1 = registerCode register1 dst asmVoid
2870 src1 = registerName register1 dst
2871 in asmParThen [code1, code2] .
2872 if isFixed register1 && src1 /= dst
2873 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2874 instr (OpReg src2) (OpReg dst)]
2876 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2878 returnUs (Any IntRep code__2)
2881 trivialUCode instr x
2882 = getRegister x `thenUs` \ register ->
2883 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2885 -- fixedname = registerName register eax
2887 code = registerCode register dst
2888 src = registerName register dst
2889 in code . if isFixed register && dst /= src
2890 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2892 else mkSeqInstr (instr (OpReg src))
2894 returnUs (Any IntRep code__2)
2897 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2898 = getRegister y `thenUs` \ register2 ->
2899 --getNewRegNCG (registerRep register2)
2900 -- `thenUs` \ tmp2 ->
2901 getAmode mem `thenUs` \ amode ->
2903 code1 = amodeCode amode
2904 src1 = amodeAddr amode
2907 code2 = registerCode register2 dst
2908 src2 = registerName register2 dst
2909 in asmParThen [code1 asmVoid,code2 asmVoid] .
2910 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2912 returnUs (Any pk code__2)
2914 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2915 = getRegister x `thenUs` \ register1 ->
2916 --getNewRegNCG (registerRep register1)
2917 -- `thenUs` \ tmp1 ->
2918 getAmode mem `thenUs` \ amode ->
2920 code2 = amodeCode amode
2921 src2 = amodeAddr amode
2924 code1 = registerCode register1 dst
2925 src1 = registerName register1 dst
2926 in asmParThen [code2 asmVoid,code1 asmVoid] .
2927 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2929 returnUs (Any pk code__2)
2931 trivialFCode pk _ _ _ instrpr x y
2932 = getRegister x `thenUs` \ register1 ->
2933 getRegister y `thenUs` \ register2 ->
2934 --getNewRegNCG (registerRep register1)
2935 -- `thenUs` \ tmp1 ->
2936 --getNewRegNCG (registerRep register2)
2937 -- `thenUs` \ tmp2 ->
2938 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2940 pk1 = registerRep register1
2941 code1 = registerCode register1 st0 --tmp1
2942 src1 = registerName register1 st0 --tmp1
2944 pk2 = registerRep register2
2947 code2 = registerCode register2 dst
2948 src2 = registerName register2 dst
2949 in asmParThen [code1 asmVoid, code2 asmVoid] .
2952 returnUs (Any pk1 code__2)
2955 trivialUFCode pk instr (StInd pk' mem)
2956 = getAmode mem `thenUs` \ amode ->
2958 code = amodeCode amode
2959 src = amodeAddr amode
2960 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2963 returnUs (Any pk code__2)
2965 trivialUFCode pk instr x
2966 = getRegister x `thenUs` \ register ->
2967 --getNewRegNCG pk `thenUs` \ tmp ->
2970 code = registerCode register dst
2971 src = registerName register dst
2972 in code . mkSeqInstrs [instr]
2974 returnUs (Any pk code__2)
2976 #endif {- i386_TARGET_ARCH -}
2977 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2978 #if sparc_TARGET_ARCH
2980 trivialCode instr x (StInt y)
2982 = getRegister x `thenUs` \ register ->
2983 getNewRegNCG IntRep `thenUs` \ tmp ->
2985 code = registerCode register tmp
2986 src1 = registerName register tmp
2987 src2 = ImmInt (fromInteger y)
2988 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2990 returnUs (Any IntRep code__2)
2992 trivialCode instr x y
2993 = getRegister x `thenUs` \ register1 ->
2994 getRegister y `thenUs` \ register2 ->
2995 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2996 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2998 code1 = registerCode register1 tmp1 asmVoid
2999 src1 = registerName register1 tmp1
3000 code2 = registerCode register2 tmp2 asmVoid
3001 src2 = registerName register2 tmp2
3002 code__2 dst = asmParThen [code1, code2] .
3003 mkSeqInstr (instr src1 (RIReg src2) dst)
3005 returnUs (Any IntRep code__2)
3008 trivialFCode pk instr x y
3009 = getRegister x `thenUs` \ register1 ->
3010 getRegister y `thenUs` \ register2 ->
3011 getNewRegNCG (registerRep register1)
3013 getNewRegNCG (registerRep register2)
3015 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3017 promote x = asmInstr (FxTOy F DF x tmp)
3019 pk1 = registerRep register1
3020 code1 = registerCode register1 tmp1
3021 src1 = registerName register1 tmp1
3023 pk2 = registerRep register2
3024 code2 = registerCode register2 tmp2
3025 src2 = registerName register2 tmp2
3029 asmParThen [code1 asmVoid, code2 asmVoid] .
3030 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3031 else if pk1 == FloatRep then
3032 asmParThen [code1 (promote src1), code2 asmVoid] .
3033 mkSeqInstr (instr DF tmp src2 dst)
3035 asmParThen [code1 asmVoid, code2 (promote src2)] .
3036 mkSeqInstr (instr DF src1 tmp dst)
3038 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3041 trivialUCode instr x
3042 = getRegister x `thenUs` \ register ->
3043 getNewRegNCG IntRep `thenUs` \ tmp ->
3045 code = registerCode register tmp
3046 src = registerName register tmp
3047 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3049 returnUs (Any IntRep code__2)
3052 trivialUFCode pk instr x
3053 = getRegister x `thenUs` \ register ->
3054 getNewRegNCG pk `thenUs` \ tmp ->
3056 code = registerCode register tmp
3057 src = registerName register tmp
3058 code__2 dst = code . mkSeqInstr (instr src dst)
3060 returnUs (Any pk code__2)
3062 #endif {- sparc_TARGET_ARCH -}
3065 %************************************************************************
3067 \subsubsection{Coercing to/from integer/floating-point...}
3069 %************************************************************************
3071 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3072 to be generated. Here we just change the type on the Register passed
3073 on up. The code is machine-independent.
3075 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3076 conversions. We have to store temporaries in memory to move
3077 between the integer and the floating point register sets.
3080 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3081 coerceFltCode :: StixTree -> UniqSM Register
3083 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3084 coerceFP2Int :: StixTree -> UniqSM Register
3087 = getRegister x `thenUs` \ register ->
3090 Fixed _ reg code -> Fixed pk reg code
3091 Any _ code -> Any pk code
3096 = getRegister x `thenUs` \ register ->
3099 Fixed _ reg code -> Fixed DoubleRep reg code
3100 Any _ code -> Any DoubleRep code
3105 #if alpha_TARGET_ARCH
3108 = getRegister x `thenUs` \ register ->
3109 getNewRegNCG IntRep `thenUs` \ reg ->
3111 code = registerCode register reg
3112 src = registerName register reg
3114 code__2 dst = code . mkSeqInstrs [
3116 LD TF dst (spRel 0),
3119 returnUs (Any DoubleRep code__2)
3123 = getRegister x `thenUs` \ register ->
3124 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3126 code = registerCode register tmp
3127 src = registerName register tmp
3129 code__2 dst = code . mkSeqInstrs [
3131 ST TF tmp (spRel 0),
3134 returnUs (Any IntRep code__2)
3136 #endif {- alpha_TARGET_ARCH -}
3137 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3138 #if i386_TARGET_ARCH
3141 = getRegister x `thenUs` \ register ->
3142 getNewRegNCG IntRep `thenUs` \ reg ->
3144 code = registerCode register reg
3145 src = registerName register reg
3147 code__2 dst = code . mkSeqInstrs [
3148 -- to fix: should spill instead of using R1
3149 MOV L (OpReg src) (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))),
3150 FILD (primRepToSize pk) (Address (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3152 returnUs (Any pk code__2)
3156 = getRegister x `thenUs` \ register ->
3157 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3159 code = registerCode register tmp
3160 src = registerName register tmp
3161 pk = registerRep register
3164 in code . mkSeqInstrs [
3166 FIST L (Address (Just ebx) Nothing (ImmInt OFFSET_R1)),
3167 MOV L (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3169 returnUs (Any IntRep code__2)
3171 #endif {- i386_TARGET_ARCH -}
3172 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3173 #if sparc_TARGET_ARCH
3176 = getRegister x `thenUs` \ register ->
3177 getNewRegNCG IntRep `thenUs` \ reg ->
3179 code = registerCode register reg
3180 src = registerName register reg
3182 code__2 dst = code . mkSeqInstrs [
3183 ST W src (spRel (-2)),
3184 LD W (spRel (-2)) dst,
3185 FxTOy W (primRepToSize pk) dst dst]
3187 returnUs (Any pk code__2)
3191 = getRegister x `thenUs` \ register ->
3192 getNewRegNCG IntRep `thenUs` \ reg ->
3193 getNewRegNCG FloatRep `thenUs` \ tmp ->
3195 code = registerCode register reg
3196 src = registerName register reg
3197 pk = registerRep register
3199 code__2 dst = code . mkSeqInstrs [
3200 FxTOy (primRepToSize pk) W src tmp,
3201 ST W tmp (spRel (-2)),
3202 LD W (spRel (-2)) dst]
3204 returnUs (Any IntRep code__2)
3206 #endif {- sparc_TARGET_ARCH -}
3209 %************************************************************************
3211 \subsubsection{Coercing integer to @Char@...}
3213 %************************************************************************
3215 Integer to character conversion. Where applicable, we try to do this
3216 in one step if the original object is in memory.
3219 chrCode :: StixTree -> UniqSM Register
3221 #if alpha_TARGET_ARCH
3224 = getRegister x `thenUs` \ register ->
3225 getNewRegNCG IntRep `thenUs` \ reg ->
3227 code = registerCode register reg
3228 src = registerName register reg
3229 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3231 returnUs (Any IntRep code__2)
3233 #endif {- alpha_TARGET_ARCH -}
3234 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3235 #if i386_TARGET_ARCH
3238 = getRegister x `thenUs` \ register ->
3239 --getNewRegNCG IntRep `thenUs` \ reg ->
3241 -- fixedname = registerName register eax
3243 code = registerCode register dst
3244 src = registerName register dst
3246 if isFixed register && src /= dst
3247 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3248 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3249 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3251 returnUs (Any IntRep code__2)
3253 #endif {- i386_TARGET_ARCH -}
3254 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3255 #if sparc_TARGET_ARCH
3257 chrCode (StInd pk mem)
3258 = getAmode mem `thenUs` \ amode ->
3260 code = amodeCode amode
3261 src = amodeAddr amode
3262 src_off = addrOffset src 3
3263 src__2 = case src_off of Just x -> x
3264 code__2 dst = if maybeToBool src_off then
3265 code . mkSeqInstr (LD BU src__2 dst)
3267 code . mkSeqInstrs [
3268 LD (primRepToSize pk) src dst,
3269 AND False dst (RIImm (ImmInt 255)) dst]
3271 returnUs (Any pk code__2)
3274 = getRegister x `thenUs` \ register ->
3275 getNewRegNCG IntRep `thenUs` \ reg ->
3277 code = registerCode register reg
3278 src = registerName register reg
3279 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3281 returnUs (Any IntRep code__2)
3283 #endif {- sparc_TARGET_ARCH -}
3286 %************************************************************************
3288 \subsubsection{Absolute value on integers}
3290 %************************************************************************
3292 Absolute value on integers, mostly for gmp size check macros. Again,
3293 the argument cannot be an StInt, because genericOpt already folded
3296 If applicable, do not fill the delay slots here; you will confuse the
3300 absIntCode :: StixTree -> UniqSM Register
3302 #if alpha_TARGET_ARCH
3303 absIntCode = panic "MachCode.absIntCode: not on Alphas"
3304 #endif {- alpha_TARGET_ARCH -}
3306 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3307 #if i386_TARGET_ARCH
3310 = getRegister x `thenUs` \ register ->
3311 --getNewRegNCG IntRep `thenUs` \ reg ->
3312 getUniqLabelNCG `thenUs` \ lbl ->
3314 code__2 dst = let code = registerCode register dst
3315 src = registerName register dst
3316 in code . if isFixed register && dst /= src
3317 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3318 TEST L (OpReg dst) (OpReg dst),
3322 else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
3327 returnUs (Any IntRep code__2)
3329 #endif {- i386_TARGET_ARCH -}
3330 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3331 #if sparc_TARGET_ARCH
3334 = getRegister x `thenUs` \ register ->
3335 getNewRegNCG IntRep `thenUs` \ reg ->
3336 getUniqLabelNCG `thenUs` \ lbl ->
3338 code = registerCode register reg
3339 src = registerName register reg
3340 code__2 dst = code . mkSeqInstrs [
3341 SUB False True g0 (RIReg src) dst,
3342 BI GE False (ImmCLbl lbl), NOP,
3343 OR False g0 (RIReg src) dst,
3346 returnUs (Any IntRep code__2)
3348 #endif {- sparc_TARGET_ARCH -}