2 % (c) The AQUA Project, Glasgow University, 1996-1998
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 module MachCode ( stmt2Instrs, asmVoid, InstrList ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
20 import AbsCSyn ( MagicId )
21 import AbsCUtils ( magicIdPrimRep )
22 import CallConv ( CallConv )
23 import CLabel ( isAsmTemp, CLabel )
24 import Maybes ( maybeToBool, expectJust )
25 import OrdList -- quite a bit of it
26 import PrimRep ( isFloatingRep, PrimRep(..) )
27 import PrimOp ( PrimOp(..) )
28 import CallConv ( cCallConv )
29 import Stix ( getUniqLabelNCG, StixTree(..),
30 StixReg(..), CodeSegment(..)
32 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
38 Code extractor for an entire stix tree---stix statement level.
41 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
43 stmt2Instrs stmt = case stmt of
44 StComment s -> returnInstr (COMMENT s)
45 StSegment seg -> returnInstr (SEGMENT seg)
46 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
47 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
48 StLabel lab -> returnInstr (LABEL lab)
50 StJump arg -> genJump arg
51 StCondJump lab arg -> genCondJump lab arg
52 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
55 | isFloatingRep pk -> assignFltCode pk dst src
56 | otherwise -> assignIntCode pk dst src
59 -- When falling through on the Alpha, we still have to load pv
60 -- with the address of the next routine, so that it can load gp.
61 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
65 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
66 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
67 (foldr1 (.) codes xs))
69 getData :: StixTree -> UniqSM (InstrBlock, Imm)
71 getData (StInt i) = returnUs (id, ImmInteger i)
72 getData (StDouble d) = returnUs (id, dblImmLit d)
73 getData (StLitLbl s) = returnUs (id, ImmLab s)
74 getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
75 getData (StCLbl l) = returnUs (id, ImmCLbl l)
76 getData (StString s) =
77 getUniqLabelNCG `thenUs` \ lbl ->
78 returnUs (mkSeqInstrs [LABEL lbl,
79 ASCII True (_UNPK_ s)],
81 -- the linker can handle simple arithmetic...
82 getData (StIndex rep (StCLbl lbl) (StInt off)) =
83 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
86 %************************************************************************
88 \subsection{General things for putting together code sequences}
90 %************************************************************************
93 type InstrList = OrdList Instr
94 type InstrBlock = InstrList -> InstrList
99 asmInstr :: Instr -> InstrList
100 asmInstr i = mkUnitList i
102 asmSeq :: [Instr] -> InstrList
103 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
105 asmParThen :: [InstrList] -> InstrBlock
106 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
108 returnInstr :: Instr -> UniqSM InstrBlock
109 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
111 returnInstrs :: [Instr] -> UniqSM InstrBlock
112 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
114 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
115 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
117 mkSeqInstr :: Instr -> InstrBlock
118 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
120 mkSeqInstrs :: [Instr] -> InstrBlock
121 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
125 mangleIndexTree :: StixTree -> StixTree
127 mangleIndexTree (StIndex pk base (StInt i))
128 = StPrim IntAddOp [base, off]
130 off = StInt (i * sizeOf pk)
132 #ifndef i386_TARGET_ARCH
133 mangleIndexTree (StIndex pk base off)
134 = StPrim IntAddOp [base,
140 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
141 StPrim SllOp [off, StInt s]
144 shift DoubleRep = 3::Integer
145 shift _ = IF_ARCH_alpha(3,2)
147 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
148 -- that do include the size of the primitive kind we're addressing. When StIndex
149 -- is expanded to actual code, the index (in units) is by the above code approp.
150 -- shifted to get the no. of bytes. Since Address amodes do contain size info
151 -- explicitly, we disable the shifting for x86s.
152 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
158 maybeImm :: StixTree -> Maybe Imm
160 maybeImm (StLitLbl s) = Just (ImmLab s)
161 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
162 maybeImm (StCLbl l) = Just (ImmCLbl l)
164 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
165 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
168 | i >= toInteger minInt && i <= toInteger maxInt
169 = Just (ImmInt (fromInteger i))
171 = Just (ImmInteger i)
176 %************************************************************************
178 \subsection{The @Register@ type}
180 %************************************************************************
182 @Register@s passed up the tree. If the stix code forces the register
183 to live in a pre-decided machine register, it comes out as @Fixed@;
184 otherwise, it comes out as @Any@, and the parent can decide which
185 register to put it in.
189 = Fixed PrimRep Reg InstrBlock
190 | Any PrimRep (Reg -> InstrBlock)
192 registerCode :: Register -> Reg -> InstrBlock
193 registerCode (Fixed _ _ code) reg = code
194 registerCode (Any _ code) reg = code reg
196 registerName :: Register -> Reg -> Reg
197 registerName (Fixed _ reg _) _ = reg
198 registerName (Any _ _) reg = reg
200 registerRep :: Register -> PrimRep
201 registerRep (Fixed pk _ _) = pk
202 registerRep (Any pk _) = pk
204 isFixed :: Register -> Bool
205 isFixed (Fixed _ _ _) = True
206 isFixed (Any _ _) = False
209 Generate code to get a subtree into a @Register@:
211 getRegister :: StixTree -> UniqSM Register
213 getRegister (StReg (StixMagicId stgreg))
214 = case (magicIdRegMaybe stgreg) of
215 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
218 getRegister (StReg (StixTemp u pk))
219 = returnUs (Fixed pk (UnmappedReg u pk) id)
221 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
223 getRegister (StCall fn cconv kind args)
224 = genCCall fn cconv kind args `thenUs` \ call ->
225 returnUs (Fixed kind reg call)
227 reg = if isFloatingRep kind
228 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
229 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
231 getRegister (StString s)
232 = getUniqLabelNCG `thenUs` \ lbl ->
234 imm_lbl = ImmCLbl lbl
236 code dst = mkSeqInstrs [
239 ASCII True (_UNPK_ s),
241 #if alpha_TARGET_ARCH
242 LDA dst (AddrImm imm_lbl)
245 MOV L (OpImm imm_lbl) (OpReg dst)
247 #if sparc_TARGET_ARCH
248 SETHI (HI imm_lbl) dst,
249 OR False dst (RIImm (LO imm_lbl)) dst
253 returnUs (Any PtrRep code)
255 getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
256 = getUniqLabelNCG `thenUs` \ lbl ->
258 imm_lbl = ImmCLbl lbl
260 code dst = mkSeqInstrs [
263 ASCII False (init xs),
265 #if alpha_TARGET_ARCH
266 LDA dst (AddrImm imm_lbl)
269 MOV L (OpImm imm_lbl) (OpReg dst)
271 #if sparc_TARGET_ARCH
272 SETHI (HI imm_lbl) dst,
273 OR False dst (RIImm (LO imm_lbl)) dst
277 returnUs (Any PtrRep code)
279 xs = _UNPK_ (_TAIL_ s)
281 -- end of machine-"independent" bit; here we go on the rest...
283 #if alpha_TARGET_ARCH
285 getRegister (StDouble d)
286 = getUniqLabelNCG `thenUs` \ lbl ->
287 getNewRegNCG PtrRep `thenUs` \ tmp ->
288 let code dst = mkSeqInstrs [
291 DATA TF [ImmLab (rational d)],
293 LDA tmp (AddrImm (ImmCLbl lbl)),
294 LD TF dst (AddrReg tmp)]
296 returnUs (Any DoubleRep code)
298 getRegister (StPrim primop [x]) -- unary PrimOps
300 IntNegOp -> trivialUCode (NEG Q False) x
301 IntAbsOp -> trivialUCode (ABS Q) x
303 NotOp -> trivialUCode NOT x
305 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
306 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
308 OrdOp -> coerceIntCode IntRep x
311 Float2IntOp -> coerceFP2Int x
312 Int2FloatOp -> coerceInt2FP pr x
313 Double2IntOp -> coerceFP2Int x
314 Int2DoubleOp -> coerceInt2FP pr x
316 Double2FloatOp -> coerceFltCode x
317 Float2DoubleOp -> coerceFltCode x
319 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
321 fn = case other_op of
322 FloatExpOp -> SLIT("exp")
323 FloatLogOp -> SLIT("log")
324 FloatSqrtOp -> SLIT("sqrt")
325 FloatSinOp -> SLIT("sin")
326 FloatCosOp -> SLIT("cos")
327 FloatTanOp -> SLIT("tan")
328 FloatAsinOp -> SLIT("asin")
329 FloatAcosOp -> SLIT("acos")
330 FloatAtanOp -> SLIT("atan")
331 FloatSinhOp -> SLIT("sinh")
332 FloatCoshOp -> SLIT("cosh")
333 FloatTanhOp -> SLIT("tanh")
334 DoubleExpOp -> SLIT("exp")
335 DoubleLogOp -> SLIT("log")
336 DoubleSqrtOp -> SLIT("sqrt")
337 DoubleSinOp -> SLIT("sin")
338 DoubleCosOp -> SLIT("cos")
339 DoubleTanOp -> SLIT("tan")
340 DoubleAsinOp -> SLIT("asin")
341 DoubleAcosOp -> SLIT("acos")
342 DoubleAtanOp -> SLIT("atan")
343 DoubleSinhOp -> SLIT("sinh")
344 DoubleCoshOp -> SLIT("cosh")
345 DoubleTanhOp -> SLIT("tanh")
347 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
349 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
351 CharGtOp -> trivialCode (CMP LTT) y x
352 CharGeOp -> trivialCode (CMP LE) y x
353 CharEqOp -> trivialCode (CMP EQQ) x y
354 CharNeOp -> int_NE_code x y
355 CharLtOp -> trivialCode (CMP LTT) x y
356 CharLeOp -> trivialCode (CMP LE) x y
358 IntGtOp -> trivialCode (CMP LTT) y x
359 IntGeOp -> trivialCode (CMP LE) y x
360 IntEqOp -> trivialCode (CMP EQQ) x y
361 IntNeOp -> int_NE_code x y
362 IntLtOp -> trivialCode (CMP LTT) x y
363 IntLeOp -> trivialCode (CMP LE) x y
365 WordGtOp -> trivialCode (CMP ULT) y x
366 WordGeOp -> trivialCode (CMP ULE) x y
367 WordEqOp -> trivialCode (CMP EQQ) x y
368 WordNeOp -> int_NE_code x y
369 WordLtOp -> trivialCode (CMP ULT) x y
370 WordLeOp -> trivialCode (CMP ULE) x y
372 AddrGtOp -> trivialCode (CMP ULT) y x
373 AddrGeOp -> trivialCode (CMP ULE) y x
374 AddrEqOp -> trivialCode (CMP EQQ) x y
375 AddrNeOp -> int_NE_code x y
376 AddrLtOp -> trivialCode (CMP ULT) x y
377 AddrLeOp -> trivialCode (CMP ULE) x y
379 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
380 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
381 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
382 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
383 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
384 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
386 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
387 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
388 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
389 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
390 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
391 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
393 IntAddOp -> trivialCode (ADD Q False) x y
394 IntSubOp -> trivialCode (SUB Q False) x y
395 IntMulOp -> trivialCode (MUL Q False) x y
396 IntQuotOp -> trivialCode (DIV Q False) x y
397 IntRemOp -> trivialCode (REM Q False) x y
399 WordQuotOp -> trivialCode (DIV Q True) x y
400 WordRemOp -> trivialCode (REM Q True) x y
402 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
403 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
404 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
405 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
407 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
408 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
409 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
410 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
412 AndOp -> trivialCode AND x y
413 OrOp -> trivialCode OR x y
414 XorOp -> trivialCode XOR x y
415 SllOp -> trivialCode SLL x y
416 SrlOp -> trivialCode SRL x y
418 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
419 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
420 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
422 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
423 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
425 {- ------------------------------------------------------------
426 Some bizarre special code for getting condition codes into
427 registers. Integer non-equality is a test for equality
428 followed by an XOR with 1. (Integer comparisons always set
429 the result register to 0 or 1.) Floating point comparisons of
430 any kind leave the result in a floating point register, so we
431 need to wrangle an integer register out of things.
433 int_NE_code :: StixTree -> StixTree -> UniqSM Register
436 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
437 getNewRegNCG IntRep `thenUs` \ tmp ->
439 code = registerCode register tmp
440 src = registerName register tmp
441 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
443 returnUs (Any IntRep code__2)
445 {- ------------------------------------------------------------
446 Comments for int_NE_code also apply to cmpF_code
449 :: (Reg -> Reg -> Reg -> Instr)
451 -> StixTree -> StixTree
454 cmpF_code instr cond x y
455 = trivialFCode pr instr x y `thenUs` \ register ->
456 getNewRegNCG DoubleRep `thenUs` \ tmp ->
457 getUniqLabelNCG `thenUs` \ lbl ->
459 code = registerCode register tmp
460 result = registerName register tmp
462 code__2 dst = code . mkSeqInstrs [
463 OR zeroh (RIImm (ImmInt 1)) dst,
464 BF cond result (ImmCLbl lbl),
465 OR zeroh (RIReg zeroh) dst,
468 returnUs (Any IntRep code__2)
470 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
471 ------------------------------------------------------------
473 getRegister (StInd pk mem)
474 = getAmode mem `thenUs` \ amode ->
476 code = amodeCode amode
477 src = amodeAddr amode
478 size = primRepToSize pk
479 code__2 dst = code . mkSeqInstr (LD size dst src)
481 returnUs (Any pk code__2)
483 getRegister (StInt i)
486 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
488 returnUs (Any IntRep code)
491 code dst = mkSeqInstr (LDI Q dst src)
493 returnUs (Any IntRep code)
495 src = ImmInt (fromInteger i)
500 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
502 returnUs (Any PtrRep code)
505 imm__2 = case imm of Just x -> x
507 #endif {- alpha_TARGET_ARCH -}
508 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511 getRegister (StDouble 0.0)
513 code dst = mkSeqInstrs [FLDZ]
515 returnUs (Any DoubleRep code)
517 getRegister (StDouble 1.0)
519 code dst = mkSeqInstrs [FLD1]
521 returnUs (Any DoubleRep code)
523 getRegister (StDouble d)
524 = getUniqLabelNCG `thenUs` \ lbl ->
525 --getNewRegNCG PtrRep `thenUs` \ tmp ->
526 let code dst = mkSeqInstrs [
529 DATA DF [dblImmLit d],
531 FLD DF (OpImm (ImmCLbl lbl))
534 returnUs (Any DoubleRep code)
536 getRegister (StPrim primop [x]) -- unary PrimOps
538 IntNegOp -> trivialUCode (NEGI L) x
539 IntAbsOp -> absIntCode x
541 NotOp -> trivialUCode (NOT L) x
543 FloatNegOp -> trivialUFCode FloatRep FCHS x
544 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
545 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
547 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
549 OrdOp -> coerceIntCode IntRep x
552 Float2IntOp -> coerceFP2Int x
553 Int2FloatOp -> coerceInt2FP FloatRep x
554 Double2IntOp -> coerceFP2Int x
555 Int2DoubleOp -> coerceInt2FP DoubleRep x
557 Double2FloatOp -> coerceFltCode x
558 Float2DoubleOp -> coerceFltCode x
562 fixed_x = if is_float_op -- promote to double
563 then StPrim Float2DoubleOp [x]
566 getRegister (StCall fn cCallConv DoubleRep [x])
570 FloatExpOp -> (True, SLIT("exp"))
571 FloatLogOp -> (True, SLIT("log"))
573 FloatSinOp -> (True, SLIT("sin"))
574 FloatCosOp -> (True, SLIT("cos"))
575 FloatTanOp -> (True, SLIT("tan"))
577 FloatAsinOp -> (True, SLIT("asin"))
578 FloatAcosOp -> (True, SLIT("acos"))
579 FloatAtanOp -> (True, SLIT("atan"))
581 FloatSinhOp -> (True, SLIT("sinh"))
582 FloatCoshOp -> (True, SLIT("cosh"))
583 FloatTanhOp -> (True, SLIT("tanh"))
585 DoubleExpOp -> (False, SLIT("exp"))
586 DoubleLogOp -> (False, SLIT("log"))
588 DoubleSinOp -> (False, SLIT("sin"))
589 DoubleCosOp -> (False, SLIT("cos"))
590 DoubleTanOp -> (False, SLIT("tan"))
592 DoubleAsinOp -> (False, SLIT("asin"))
593 DoubleAcosOp -> (False, SLIT("acos"))
594 DoubleAtanOp -> (False, SLIT("atan"))
596 DoubleSinhOp -> (False, SLIT("sinh"))
597 DoubleCoshOp -> (False, SLIT("cosh"))
598 DoubleTanhOp -> (False, SLIT("tanh"))
600 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
602 CharGtOp -> condIntReg GTT x y
603 CharGeOp -> condIntReg GE x y
604 CharEqOp -> condIntReg EQQ x y
605 CharNeOp -> condIntReg NE x y
606 CharLtOp -> condIntReg LTT x y
607 CharLeOp -> condIntReg LE x y
609 IntGtOp -> condIntReg GTT x y
610 IntGeOp -> condIntReg GE x y
611 IntEqOp -> condIntReg EQQ x y
612 IntNeOp -> condIntReg NE x y
613 IntLtOp -> condIntReg LTT x y
614 IntLeOp -> condIntReg LE x y
616 WordGtOp -> condIntReg GU x y
617 WordGeOp -> condIntReg GEU x y
618 WordEqOp -> condIntReg EQQ x y
619 WordNeOp -> condIntReg NE x y
620 WordLtOp -> condIntReg LU x y
621 WordLeOp -> condIntReg LEU x y
623 AddrGtOp -> condIntReg GU x y
624 AddrGeOp -> condIntReg GEU x y
625 AddrEqOp -> condIntReg EQQ x y
626 AddrNeOp -> condIntReg NE x y
627 AddrLtOp -> condIntReg LU x y
628 AddrLeOp -> condIntReg LEU x y
630 FloatGtOp -> condFltReg GTT x y
631 FloatGeOp -> condFltReg GE x y
632 FloatEqOp -> condFltReg EQQ x y
633 FloatNeOp -> condFltReg NE x y
634 FloatLtOp -> condFltReg LTT x y
635 FloatLeOp -> condFltReg LE x y
637 DoubleGtOp -> condFltReg GTT x y
638 DoubleGeOp -> condFltReg GE x y
639 DoubleEqOp -> condFltReg EQQ x y
640 DoubleNeOp -> condFltReg NE x y
641 DoubleLtOp -> condFltReg LTT x y
642 DoubleLeOp -> condFltReg LE x y
644 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
645 -- this should be optimised by the generic Opts,
646 -- I don't know why it is not (sometimes)!
648 [x, StInt 0] -> getRegister x
653 IntSubOp -> sub_code L x y
654 IntQuotOp -> quot_code L x y True{-division-}
655 IntRemOp -> quot_code L x y False{-remainder-}
656 IntMulOp -> trivialCode (IMUL L) x y {-True-}
658 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
659 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
660 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
661 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
663 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
664 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
665 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
666 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
668 AndOp -> trivialCode (AND L) x y {-True-}
669 OrOp -> trivialCode (OR L) x y {-True-}
670 XorOp -> trivialCode (XOR L) x y {-True-}
672 {- Shift ops on x86s have constraints on their source, it
673 either has to be Imm, CL or 1
674 => trivialCode's is not restrictive enough (sigh.)
677 SllOp -> shift_code (SHL L) x y {-False-}
678 SrlOp -> shift_code (SHR L) x y {-False-}
680 ISllOp -> shift_code (SHL L) x y {-False-} --was:panic "I386Gen:isll"
681 ISraOp -> shift_code (SAR L) x y {-False-} --was:panic "I386Gen:isra"
682 ISrlOp -> shift_code (SHR L) x y {-False-} --was:panic "I386Gen:isrl"
684 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
685 where promote x = StPrim Float2DoubleOp [x]
686 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
688 shift_code :: (Operand -> Operand -> Instr)
692 {- Case1: shift length as immediate -}
693 -- Code is the same as the first eq. for trivialCode -- sigh.
694 shift_code instr x y{-amount-}
696 = getRegister x `thenUs` \ register ->
698 op_imm = OpImm imm__2
701 code = registerCode register dst
702 src = registerName register dst
704 mkSeqInstr (COMMENT SLIT("shift_code")) .
706 if isFixed register && src /= dst
708 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
709 instr op_imm (OpReg dst)]
711 mkSeqInstr (instr op_imm (OpReg src))
713 returnUs (Any IntRep code__2)
716 imm__2 = case imm of Just x -> x
718 {- Case2: shift length is complex (non-immediate) -}
719 shift_code instr x y{-amount-}
720 = getRegister y `thenUs` \ register1 ->
721 getRegister x `thenUs` \ register2 ->
722 -- getNewRegNCG IntRep `thenUs` \ dst ->
724 -- Note: we force the shift length to be loaded
725 -- into ECX, so that we can use CL when shifting.
726 -- (only register location we are allowed
727 -- to put shift amounts.)
729 -- The shift instruction is fed ECX as src reg,
730 -- but we coerce this into CL when printing out.
731 src1 = registerName register1 ecx
732 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
733 registerCode register1 ecx .
734 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
736 registerCode register1 ecx
739 code2 = registerCode register2 eax
740 src2 = registerName register2 eax
743 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
745 returnUs (Fixed IntRep eax code__2)
747 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
749 add_code sz x (StInt y)
750 = getRegister x `thenUs` \ register ->
751 getNewRegNCG IntRep `thenUs` \ tmp ->
753 code = registerCode register tmp
754 src1 = registerName register tmp
755 src2 = ImmInt (fromInteger y)
757 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
759 returnUs (Any IntRep code__2)
761 add_code sz x (StInd _ mem)
762 = getRegister x `thenUs` \ register1 ->
763 --getNewRegNCG (registerRep register1)
764 -- `thenUs` \ tmp1 ->
765 getAmode mem `thenUs` \ amode ->
767 code2 = amodeCode amode
768 src2 = amodeAddr amode
770 code__2 dst = let code1 = registerCode register1 dst
771 src1 = registerName register1 dst
772 in asmParThen [code2 asmVoid,code1 asmVoid] .
773 if isFixed register1 && src1 /= dst
774 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
775 ADD sz (OpAddr src2) (OpReg dst)]
777 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
779 returnUs (Any IntRep code__2)
781 add_code sz (StInd _ mem) y
782 = getRegister y `thenUs` \ register2 ->
783 --getNewRegNCG (registerRep register2)
784 -- `thenUs` \ tmp2 ->
785 getAmode mem `thenUs` \ amode ->
787 code1 = amodeCode amode
788 src1 = amodeAddr amode
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 (AddrBaseIndex (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 (AddrBaseIndex (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 (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
871 MOV L (OpReg src1) (OpReg eax),
873 IDIV sz (OpAddr (AddrBaseIndex (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 (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
894 MOV L (OpReg src1) (OpReg eax),
896 IDIV sz (OpAddr (AddrBaseIndex (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 cCallConv 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: " ++ show 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 SrlOp -> trivialCode SRL x y
1081 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1082 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1083 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1085 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1086 where promote x = StPrim Float2DoubleOp [x]
1087 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1088 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1090 imul_div fn x y = getRegister (StCall fn cCallConv 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 MachRegsAddr 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 (AddrBaseIndex (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 (AddrBaseIndex (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 (AddrBaseIndex (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 (AddrBaseIndex (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
2240 -> PrimRep -- type of the result
2241 -> [StixTree] -- arguments (of mixed type)
2242 -> UniqSM InstrBlock
2244 #if alpha_TARGET_ARCH
2246 genCCall fn cconv kind args
2247 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2248 `thenUs` \ ((unused,_), argCode) ->
2250 nRegs = length allArgRegs - length unused
2251 code = asmParThen (map ($ asmVoid) argCode)
2254 LDA pv (AddrImm (ImmLab (ptext fn))),
2255 JSR ra (AddrReg pv) nRegs,
2256 LDGP gp (AddrReg ra)]
2258 ------------------------
2259 {- Try to get a value into a specific register (or registers) for
2260 a call. The first 6 arguments go into the appropriate
2261 argument register (separate registers for integer and floating
2262 point arguments, but used in lock-step), and the remaining
2263 arguments are dumped to the stack, beginning at 0(sp). Our
2264 first argument is a pair of the list of remaining argument
2265 registers to be assigned for this call and the next stack
2266 offset to use for overflowing arguments. This way,
2267 @get_Arg@ can be applied to all of a call's arguments using
2271 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2272 -> StixTree -- Current argument
2273 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2275 -- We have to use up all of our argument registers first...
2277 get_arg ((iDst,fDst):dsts, offset) arg
2278 = getRegister arg `thenUs` \ register ->
2280 reg = if isFloatingRep pk then fDst else iDst
2281 code = registerCode register reg
2282 src = registerName register reg
2283 pk = registerRep register
2286 if isFloatingRep pk then
2287 ((dsts, offset), if isFixed register then
2288 code . mkSeqInstr (FMOV src fDst)
2291 ((dsts, offset), if isFixed register then
2292 code . mkSeqInstr (OR src (RIReg src) iDst)
2295 -- Once we have run out of argument registers, we move to the
2298 get_arg ([], offset) arg
2299 = getRegister arg `thenUs` \ register ->
2300 getNewRegNCG (registerRep register)
2303 code = registerCode register tmp
2304 src = registerName register tmp
2305 pk = registerRep register
2306 sz = primRepToSize pk
2308 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2310 #endif {- alpha_TARGET_ARCH -}
2311 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2312 #if i386_TARGET_ARCH
2314 genCCall fn cconv kind [StInt i]
2315 | fn == SLIT ("PerformGC_wrapper")
2317 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2318 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2323 = getUniqLabelNCG `thenUs` \ lbl ->
2325 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2326 MOV L (OpImm (ImmCLbl lbl))
2327 -- this is hardwired
2328 (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 104))),
2329 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2335 genCCall fn cconv kind args
2336 = mapUs get_call_arg args `thenUs` \ argCode ->
2340 {- OLD: Since there's no attempt at stealing %esp at the moment,
2341 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2342 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2343 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))),
2344 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2348 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2349 call = [CALL fn__2 ,
2350 -- pop args; all args word sized?
2351 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2353 -- Don't restore %esp (see above)
2354 -- MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2357 returnSeq (code2) call
2359 -- function names that begin with '.' are assumed to be special
2360 -- internally generated names like '.mul,' which don't get an
2361 -- underscore prefix
2362 -- ToDo:needed (WDP 96/03) ???
2363 fn__2 = case (_HEAD_ fn) of
2364 '.' -> ImmLit (ptext fn)
2365 _ -> ImmLab (ptext fn)
2368 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2371 = get_op arg `thenUs` \ (code, op, sz) ->
2372 returnUs (code . mkSeqInstr (PUSH sz op))
2377 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2380 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2382 get_op (StInd pk mem)
2383 = getAmode mem `thenUs` \ amode ->
2385 code = amodeCode amode --asmVoid
2386 addr = amodeAddr amode
2387 sz = primRepToSize pk
2389 returnUs (code, OpAddr addr, sz)
2392 = getRegister op `thenUs` \ register ->
2393 getNewRegNCG (registerRep register)
2396 code = registerCode register tmp
2397 reg = registerName register tmp
2398 pk = registerRep register
2399 sz = primRepToSize pk
2401 returnUs (code, OpReg reg, sz)
2403 #endif {- i386_TARGET_ARCH -}
2404 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2405 #if sparc_TARGET_ARCH
2407 genCCall fn cconv kind args
2408 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2409 `thenUs` \ ((unused,_), argCode) ->
2411 nRegs = length allArgRegs - length unused
2412 call = CALL fn__2 nRegs False
2413 code = asmParThen (map ($ asmVoid) argCode)
2415 returnSeq code [call, NOP]
2417 -- function names that begin with '.' are assumed to be special
2418 -- internally generated names like '.mul,' which don't get an
2419 -- underscore prefix
2420 -- ToDo:needed (WDP 96/03) ???
2421 fn__2 = case (_HEAD_ fn) of
2422 '.' -> ImmLit (ptext fn)
2423 _ -> ImmLab (ptext fn)
2425 ------------------------------------
2426 {- Try to get a value into a specific register (or registers) for
2427 a call. The SPARC calling convention is an absolute
2428 nightmare. The first 6x32 bits of arguments are mapped into
2429 %o0 through %o5, and the remaining arguments are dumped to the
2430 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2431 first argument is a pair of the list of remaining argument
2432 registers to be assigned for this call and the next stack
2433 offset to use for overflowing arguments. This way,
2434 @get_arg@ can be applied to all of a call's arguments using
2438 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2439 -> StixTree -- Current argument
2440 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2442 -- We have to use up all of our argument registers first...
2444 get_arg (dst:dsts, offset) arg
2445 = getRegister arg `thenUs` \ register ->
2446 getNewRegNCG (registerRep register)
2449 reg = if isFloatingRep pk then tmp else dst
2450 code = registerCode register reg
2451 src = registerName register reg
2452 pk = registerRep register
2454 returnUs (case pk of
2457 [] -> (([], offset + 1), code . mkSeqInstrs [
2458 -- conveniently put the second part in the right stack
2459 -- location, and load the first part into %o5
2460 ST DF src (spRel (offset - 1)),
2461 LD W (spRel (offset - 1)) dst])
2462 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2463 ST DF src (spRel (-2)),
2464 LD W (spRel (-2)) dst,
2465 LD W (spRel (-1)) dst__2])
2466 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2467 ST F src (spRel (-2)),
2468 LD W (spRel (-2)) dst])
2469 _ -> ((dsts, offset), if isFixed register then
2470 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2473 -- Once we have run out of argument registers, we move to the
2476 get_arg ([], offset) arg
2477 = getRegister arg `thenUs` \ register ->
2478 getNewRegNCG (registerRep register)
2481 code = registerCode register tmp
2482 src = registerName register tmp
2483 pk = registerRep register
2484 sz = primRepToSize pk
2485 words = if pk == DoubleRep then 2 else 1
2487 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2489 #endif {- sparc_TARGET_ARCH -}
2492 %************************************************************************
2494 \subsection{Support bits}
2496 %************************************************************************
2498 %************************************************************************
2500 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2502 %************************************************************************
2504 Turn those condition codes into integers now (when they appear on
2505 the right hand side of an assignment).
2507 (If applicable) Do not fill the delay slots here; you will confuse the
2511 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2513 #if alpha_TARGET_ARCH
2514 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2515 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2516 #endif {- alpha_TARGET_ARCH -}
2518 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2519 #if i386_TARGET_ARCH
2522 = condIntCode cond x y `thenUs` \ condition ->
2523 getNewRegNCG IntRep `thenUs` \ tmp ->
2524 --getRegister dst `thenUs` \ register ->
2526 --code2 = registerCode register tmp asmVoid
2527 --dst__2 = registerName register tmp
2528 code = condCode condition
2529 cond = condName condition
2530 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2531 code__2 dst = code . mkSeqInstrs [
2532 SETCC cond (OpReg tmp),
2533 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2534 MOV L (OpReg tmp) (OpReg dst)]
2536 returnUs (Any IntRep code__2)
2539 = getUniqLabelNCG `thenUs` \ lbl1 ->
2540 getUniqLabelNCG `thenUs` \ lbl2 ->
2541 condFltCode cond x y `thenUs` \ condition ->
2543 code = condCode condition
2544 cond = condName condition
2545 code__2 dst = code . mkSeqInstrs [
2547 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2550 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2553 returnUs (Any IntRep code__2)
2555 #endif {- i386_TARGET_ARCH -}
2556 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2557 #if sparc_TARGET_ARCH
2559 condIntReg EQQ x (StInt 0)
2560 = getRegister x `thenUs` \ register ->
2561 getNewRegNCG IntRep `thenUs` \ tmp ->
2563 code = registerCode register tmp
2564 src = registerName register tmp
2565 code__2 dst = code . mkSeqInstrs [
2566 SUB False True g0 (RIReg src) g0,
2567 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2569 returnUs (Any IntRep code__2)
2572 = getRegister x `thenUs` \ register1 ->
2573 getRegister y `thenUs` \ register2 ->
2574 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2575 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2577 code1 = registerCode register1 tmp1 asmVoid
2578 src1 = registerName register1 tmp1
2579 code2 = registerCode register2 tmp2 asmVoid
2580 src2 = registerName register2 tmp2
2581 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2582 XOR False src1 (RIReg src2) dst,
2583 SUB False True g0 (RIReg dst) g0,
2584 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2586 returnUs (Any IntRep code__2)
2588 condIntReg NE x (StInt 0)
2589 = getRegister x `thenUs` \ register ->
2590 getNewRegNCG IntRep `thenUs` \ tmp ->
2592 code = registerCode register tmp
2593 src = registerName register tmp
2594 code__2 dst = code . mkSeqInstrs [
2595 SUB False True g0 (RIReg src) g0,
2596 ADD True False g0 (RIImm (ImmInt 0)) dst]
2598 returnUs (Any IntRep code__2)
2601 = getRegister x `thenUs` \ register1 ->
2602 getRegister y `thenUs` \ register2 ->
2603 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2604 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2606 code1 = registerCode register1 tmp1 asmVoid
2607 src1 = registerName register1 tmp1
2608 code2 = registerCode register2 tmp2 asmVoid
2609 src2 = registerName register2 tmp2
2610 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2611 XOR False src1 (RIReg src2) dst,
2612 SUB False True g0 (RIReg dst) g0,
2613 ADD True False g0 (RIImm (ImmInt 0)) dst]
2615 returnUs (Any IntRep code__2)
2618 = getUniqLabelNCG `thenUs` \ lbl1 ->
2619 getUniqLabelNCG `thenUs` \ lbl2 ->
2620 condIntCode cond x y `thenUs` \ condition ->
2622 code = condCode condition
2623 cond = condName condition
2624 code__2 dst = code . mkSeqInstrs [
2625 BI cond False (ImmCLbl lbl1), NOP,
2626 OR False g0 (RIImm (ImmInt 0)) dst,
2627 BI ALWAYS False (ImmCLbl lbl2), NOP,
2629 OR False g0 (RIImm (ImmInt 1)) dst,
2632 returnUs (Any IntRep code__2)
2635 = getUniqLabelNCG `thenUs` \ lbl1 ->
2636 getUniqLabelNCG `thenUs` \ lbl2 ->
2637 condFltCode cond x y `thenUs` \ condition ->
2639 code = condCode condition
2640 cond = condName condition
2641 code__2 dst = code . mkSeqInstrs [
2643 BF cond False (ImmCLbl lbl1), NOP,
2644 OR False g0 (RIImm (ImmInt 0)) dst,
2645 BI ALWAYS False (ImmCLbl lbl2), NOP,
2647 OR False g0 (RIImm (ImmInt 1)) dst,
2650 returnUs (Any IntRep code__2)
2652 #endif {- sparc_TARGET_ARCH -}
2655 %************************************************************************
2657 \subsubsection{@trivial*Code@: deal with trivial instructions}
2659 %************************************************************************
2661 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2662 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2663 for constants on the right hand side, because that's where the generic
2664 optimizer will have put them.
2666 Similarly, for unary instructions, we don't have to worry about
2667 matching an StInt as the argument, because genericOpt will already
2668 have handled the constant-folding.
2672 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2673 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2674 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2676 -> StixTree -> StixTree -- the two arguments
2681 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2682 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2684 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2685 (Size -> Operand -> Instr)
2686 -> (Size -> Operand -> Instr) {-reversed instr-}
2688 -> Instr {-reversed instr: pop-}
2690 -> StixTree -> StixTree -- the two arguments
2694 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2695 ,IF_ARCH_i386 ((Operand -> Instr)
2696 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2698 -> StixTree -- the one argument
2703 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2704 ,IF_ARCH_i386 (Instr
2705 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2707 -> StixTree -- the one argument
2710 #if alpha_TARGET_ARCH
2712 trivialCode instr x (StInt y)
2714 = getRegister x `thenUs` \ register ->
2715 getNewRegNCG IntRep `thenUs` \ tmp ->
2717 code = registerCode register tmp
2718 src1 = registerName register tmp
2719 src2 = ImmInt (fromInteger y)
2720 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2722 returnUs (Any IntRep code__2)
2724 trivialCode instr x y
2725 = getRegister x `thenUs` \ register1 ->
2726 getRegister y `thenUs` \ register2 ->
2727 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2728 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2730 code1 = registerCode register1 tmp1 asmVoid
2731 src1 = registerName register1 tmp1
2732 code2 = registerCode register2 tmp2 asmVoid
2733 src2 = registerName register2 tmp2
2734 code__2 dst = asmParThen [code1, code2] .
2735 mkSeqInstr (instr src1 (RIReg src2) dst)
2737 returnUs (Any IntRep code__2)
2740 trivialUCode instr x
2741 = getRegister x `thenUs` \ register ->
2742 getNewRegNCG IntRep `thenUs` \ tmp ->
2744 code = registerCode register tmp
2745 src = registerName register tmp
2746 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2748 returnUs (Any IntRep code__2)
2751 trivialFCode _ instr x y
2752 = getRegister x `thenUs` \ register1 ->
2753 getRegister y `thenUs` \ register2 ->
2754 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2755 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2757 code1 = registerCode register1 tmp1
2758 src1 = registerName register1 tmp1
2760 code2 = registerCode register2 tmp2
2761 src2 = registerName register2 tmp2
2763 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2764 mkSeqInstr (instr src1 src2 dst)
2766 returnUs (Any DoubleRep code__2)
2768 trivialUFCode _ instr x
2769 = getRegister x `thenUs` \ register ->
2770 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2772 code = registerCode register tmp
2773 src = registerName register tmp
2774 code__2 dst = code . mkSeqInstr (instr src dst)
2776 returnUs (Any DoubleRep code__2)
2778 #endif {- alpha_TARGET_ARCH -}
2779 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2780 #if i386_TARGET_ARCH
2782 trivialCode instr x y
2784 = getRegister x `thenUs` \ register1 ->
2785 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2787 code__2 dst = let code1 = registerCode register1 dst
2788 src1 = registerName register1 dst
2790 if isFixed register1 && src1 /= dst
2791 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2792 instr (OpImm imm__2) (OpReg dst)]
2794 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2796 returnUs (Any IntRep code__2)
2799 imm__2 = case imm of Just x -> x
2801 trivialCode instr x y
2803 = getRegister y `thenUs` \ register1 ->
2804 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
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 code2 = amodeCode amode asmVoid
2826 src2 = amodeAddr amode
2827 code__2 dst = let code1 = registerCode register dst asmVoid
2828 src1 = registerName register dst
2829 in asmParThen [code1, code2] .
2830 if isFixed register && src1 /= dst
2831 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2832 instr (OpAddr src2) (OpReg dst)]
2834 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2836 returnUs (Any pk code__2)
2838 trivialCode instr (StInd pk mem) y
2839 = getRegister y `thenUs` \ register ->
2840 --getNewRegNCG IntRep `thenUs` \ tmp ->
2841 getAmode mem `thenUs` \ amode ->
2843 code2 = amodeCode amode asmVoid
2844 src2 = amodeAddr amode
2846 code1 = registerCode register dst asmVoid
2847 src1 = registerName register dst
2848 in asmParThen [code1, code2] .
2849 if isFixed register && src1 /= dst
2850 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2851 instr (OpAddr src2) (OpReg dst)]
2853 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2855 returnUs (Any pk code__2)
2857 trivialCode instr x y
2858 = getRegister x `thenUs` \ register1 ->
2859 getRegister y `thenUs` \ register2 ->
2860 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2861 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2863 code2 = registerCode register2 tmp2 asmVoid
2864 src2 = registerName register2 tmp2
2866 code1 = registerCode register1 dst asmVoid
2867 src1 = registerName register1 dst
2868 in asmParThen [code1, code2] .
2869 if isFixed register1 && src1 /= dst
2870 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2871 instr (OpReg src2) (OpReg dst)]
2873 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2875 returnUs (Any IntRep code__2)
2878 trivialUCode instr x
2879 = getRegister x `thenUs` \ register ->
2880 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2883 code = registerCode register dst
2884 src = registerName register dst
2885 in code . if isFixed register && dst /= src
2886 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2888 else mkSeqInstr (instr (OpReg src))
2890 returnUs (Any IntRep code__2)
2893 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2894 = getRegister y `thenUs` \ register2 ->
2895 --getNewRegNCG (registerRep register2)
2896 -- `thenUs` \ tmp2 ->
2897 getAmode mem `thenUs` \ amode ->
2899 code1 = amodeCode amode
2900 src1 = amodeAddr amode
2903 code2 = registerCode register2 dst
2904 src2 = registerName register2 dst
2905 in asmParThen [code1 asmVoid,code2 asmVoid] .
2906 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2908 returnUs (Any pk code__2)
2910 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2911 = getRegister x `thenUs` \ register1 ->
2912 --getNewRegNCG (registerRep register1)
2913 -- `thenUs` \ tmp1 ->
2914 getAmode mem `thenUs` \ amode ->
2916 code2 = amodeCode amode
2917 src2 = amodeAddr amode
2920 code1 = registerCode register1 dst
2921 src1 = registerName register1 dst
2922 in asmParThen [code2 asmVoid,code1 asmVoid] .
2923 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2925 returnUs (Any pk code__2)
2927 trivialFCode pk _ _ _ instrpr x y
2928 = getRegister x `thenUs` \ register1 ->
2929 getRegister y `thenUs` \ register2 ->
2930 --getNewRegNCG (registerRep register1)
2931 -- `thenUs` \ tmp1 ->
2932 --getNewRegNCG (registerRep register2)
2933 -- `thenUs` \ tmp2 ->
2934 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2936 pk1 = registerRep register1
2937 code1 = registerCode register1 st0 --tmp1
2938 src1 = registerName register1 st0 --tmp1
2940 pk2 = registerRep register2
2943 code2 = registerCode register2 dst
2944 src2 = registerName register2 dst
2945 in asmParThen [code1 asmVoid, code2 asmVoid] .
2948 returnUs (Any pk1 code__2)
2951 trivialUFCode pk instr (StInd pk' mem)
2952 = getAmode mem `thenUs` \ amode ->
2954 code = amodeCode amode
2955 src = amodeAddr amode
2956 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2959 returnUs (Any pk code__2)
2961 trivialUFCode pk instr x
2962 = getRegister x `thenUs` \ register ->
2963 --getNewRegNCG pk `thenUs` \ tmp ->
2966 code = registerCode register dst
2967 src = registerName register dst
2968 in code . mkSeqInstrs [instr]
2970 returnUs (Any pk code__2)
2972 #endif {- i386_TARGET_ARCH -}
2973 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2974 #if sparc_TARGET_ARCH
2976 trivialCode instr x (StInt y)
2978 = getRegister x `thenUs` \ register ->
2979 getNewRegNCG IntRep `thenUs` \ tmp ->
2981 code = registerCode register tmp
2982 src1 = registerName register tmp
2983 src2 = ImmInt (fromInteger y)
2984 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2986 returnUs (Any IntRep code__2)
2988 trivialCode instr x y
2989 = getRegister x `thenUs` \ register1 ->
2990 getRegister y `thenUs` \ register2 ->
2991 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2992 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2994 code1 = registerCode register1 tmp1 asmVoid
2995 src1 = registerName register1 tmp1
2996 code2 = registerCode register2 tmp2 asmVoid
2997 src2 = registerName register2 tmp2
2998 code__2 dst = asmParThen [code1, code2] .
2999 mkSeqInstr (instr src1 (RIReg src2) dst)
3001 returnUs (Any IntRep code__2)
3004 trivialFCode pk instr x y
3005 = getRegister x `thenUs` \ register1 ->
3006 getRegister y `thenUs` \ register2 ->
3007 getNewRegNCG (registerRep register1)
3009 getNewRegNCG (registerRep register2)
3011 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3013 promote x = asmInstr (FxTOy F DF x tmp)
3015 pk1 = registerRep register1
3016 code1 = registerCode register1 tmp1
3017 src1 = registerName register1 tmp1
3019 pk2 = registerRep register2
3020 code2 = registerCode register2 tmp2
3021 src2 = registerName register2 tmp2
3025 asmParThen [code1 asmVoid, code2 asmVoid] .
3026 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3027 else if pk1 == FloatRep then
3028 asmParThen [code1 (promote src1), code2 asmVoid] .
3029 mkSeqInstr (instr DF tmp src2 dst)
3031 asmParThen [code1 asmVoid, code2 (promote src2)] .
3032 mkSeqInstr (instr DF src1 tmp dst)
3034 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3037 trivialUCode instr x
3038 = getRegister x `thenUs` \ register ->
3039 getNewRegNCG IntRep `thenUs` \ tmp ->
3041 code = registerCode register tmp
3042 src = registerName register tmp
3043 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3045 returnUs (Any IntRep code__2)
3048 trivialUFCode pk instr x
3049 = getRegister x `thenUs` \ register ->
3050 getNewRegNCG pk `thenUs` \ tmp ->
3052 code = registerCode register tmp
3053 src = registerName register tmp
3054 code__2 dst = code . mkSeqInstr (instr src dst)
3056 returnUs (Any pk code__2)
3058 #endif {- sparc_TARGET_ARCH -}
3061 %************************************************************************
3063 \subsubsection{Coercing to/from integer/floating-point...}
3065 %************************************************************************
3067 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3068 to be generated. Here we just change the type on the Register passed
3069 on up. The code is machine-independent.
3071 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3072 conversions. We have to store temporaries in memory to move
3073 between the integer and the floating point register sets.
3076 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3077 coerceFltCode :: StixTree -> UniqSM Register
3079 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3080 coerceFP2Int :: StixTree -> UniqSM Register
3083 = getRegister x `thenUs` \ register ->
3086 Fixed _ reg code -> Fixed pk reg code
3087 Any _ code -> Any pk code
3092 = getRegister x `thenUs` \ register ->
3095 Fixed _ reg code -> Fixed DoubleRep reg code
3096 Any _ code -> Any DoubleRep code
3101 #if alpha_TARGET_ARCH
3104 = getRegister x `thenUs` \ register ->
3105 getNewRegNCG IntRep `thenUs` \ reg ->
3107 code = registerCode register reg
3108 src = registerName register reg
3110 code__2 dst = code . mkSeqInstrs [
3112 LD TF dst (spRel 0),
3115 returnUs (Any DoubleRep code__2)
3119 = getRegister x `thenUs` \ register ->
3120 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3122 code = registerCode register tmp
3123 src = registerName register tmp
3125 code__2 dst = code . mkSeqInstrs [
3127 ST TF tmp (spRel 0),
3130 returnUs (Any IntRep code__2)
3132 #endif {- alpha_TARGET_ARCH -}
3133 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3134 #if i386_TARGET_ARCH
3137 = getRegister x `thenUs` \ register ->
3138 getNewRegNCG IntRep `thenUs` \ reg ->
3140 code = registerCode register reg
3141 src = registerName register reg
3143 code__2 dst = code . mkSeqInstrs [
3144 -- to fix: should spill instead of using R1
3145 MOV L (OpReg src) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
3146 FILD (primRepToSize pk) (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3148 returnUs (Any pk code__2)
3152 = getRegister x `thenUs` \ register ->
3153 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3155 code = registerCode register tmp
3156 src = registerName register tmp
3157 pk = registerRep register
3159 code__2 dst = code . mkSeqInstrs [
3161 FIST L (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)),
3162 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3164 returnUs (Any IntRep code__2)
3166 #endif {- i386_TARGET_ARCH -}
3167 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3168 #if sparc_TARGET_ARCH
3171 = getRegister x `thenUs` \ register ->
3172 getNewRegNCG IntRep `thenUs` \ reg ->
3174 code = registerCode register reg
3175 src = registerName register reg
3177 code__2 dst = code . mkSeqInstrs [
3178 ST W src (spRel (-2)),
3179 LD W (spRel (-2)) dst,
3180 FxTOy W (primRepToSize pk) dst dst]
3182 returnUs (Any pk code__2)
3186 = getRegister x `thenUs` \ register ->
3187 getNewRegNCG IntRep `thenUs` \ reg ->
3188 getNewRegNCG FloatRep `thenUs` \ tmp ->
3190 code = registerCode register reg
3191 src = registerName register reg
3192 pk = registerRep register
3194 code__2 dst = code . mkSeqInstrs [
3195 FxTOy (primRepToSize pk) W src tmp,
3196 ST W tmp (spRel (-2)),
3197 LD W (spRel (-2)) dst]
3199 returnUs (Any IntRep code__2)
3201 #endif {- sparc_TARGET_ARCH -}
3204 %************************************************************************
3206 \subsubsection{Coercing integer to @Char@...}
3208 %************************************************************************
3210 Integer to character conversion. Where applicable, we try to do this
3211 in one step if the original object is in memory.
3214 chrCode :: StixTree -> UniqSM Register
3216 #if alpha_TARGET_ARCH
3219 = getRegister x `thenUs` \ register ->
3220 getNewRegNCG IntRep `thenUs` \ reg ->
3222 code = registerCode register reg
3223 src = registerName register reg
3224 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3226 returnUs (Any IntRep code__2)
3228 #endif {- alpha_TARGET_ARCH -}
3229 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3230 #if i386_TARGET_ARCH
3233 = getRegister x `thenUs` \ register ->
3234 --getNewRegNCG IntRep `thenUs` \ reg ->
3237 code = registerCode register dst
3238 src = registerName register dst
3240 if isFixed register && src /= dst
3241 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3242 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3243 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3245 returnUs (Any IntRep code__2)
3247 #endif {- i386_TARGET_ARCH -}
3248 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3249 #if sparc_TARGET_ARCH
3251 chrCode (StInd pk mem)
3252 = getAmode mem `thenUs` \ amode ->
3254 code = amodeCode amode
3255 src = amodeAddr amode
3256 src_off = addrOffset src 3
3257 src__2 = case src_off of Just x -> x
3258 code__2 dst = if maybeToBool src_off then
3259 code . mkSeqInstr (LD BU src__2 dst)
3261 code . mkSeqInstrs [
3262 LD (primRepToSize pk) src dst,
3263 AND False dst (RIImm (ImmInt 255)) dst]
3265 returnUs (Any pk code__2)
3268 = getRegister x `thenUs` \ register ->
3269 getNewRegNCG IntRep `thenUs` \ reg ->
3271 code = registerCode register reg
3272 src = registerName register reg
3273 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3275 returnUs (Any IntRep code__2)
3277 #endif {- sparc_TARGET_ARCH -}
3280 %************************************************************************
3282 \subsubsection{Absolute value on integers}
3284 %************************************************************************
3286 Absolute value on integers, mostly for gmp size check macros. Again,
3287 the argument cannot be an StInt, because genericOpt already folded
3290 If applicable, do not fill the delay slots here; you will confuse the
3294 absIntCode :: StixTree -> UniqSM Register
3296 #if alpha_TARGET_ARCH
3297 absIntCode = panic "MachCode.absIntCode: not on Alphas"
3298 #endif {- alpha_TARGET_ARCH -}
3300 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3301 #if i386_TARGET_ARCH
3304 = getRegister x `thenUs` \ register ->
3305 --getNewRegNCG IntRep `thenUs` \ reg ->
3306 getUniqLabelNCG `thenUs` \ lbl ->
3308 code__2 dst = let code = registerCode register dst
3309 src = registerName register dst
3310 in code . if isFixed register && dst /= src
3311 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3312 TEST L (OpReg dst) (OpReg dst),
3316 else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
3321 returnUs (Any IntRep code__2)
3323 #endif {- i386_TARGET_ARCH -}
3324 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3325 #if sparc_TARGET_ARCH
3328 = getRegister x `thenUs` \ register ->
3329 getNewRegNCG IntRep `thenUs` \ reg ->
3330 getUniqLabelNCG `thenUs` \ lbl ->
3332 code = registerCode register reg
3333 src = registerName register reg
3334 code__2 dst = code . mkSeqInstrs [
3335 SUB False True g0 (RIReg src) dst,
3336 BI GE False (ImmCLbl lbl), NOP,
3337 OR False g0 (RIReg src) dst,
3340 returnUs (Any IntRep code__2)
3342 #endif {- sparc_TARGET_ARCH -}