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, InstrBlock ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
19 import OrdList ( OrdList, nilOL, isNilOL, unitOL, appOL, toOL,
20 snocOL, consOL, concatOL )
21 import AbsCSyn ( MagicId )
22 import AbsCUtils ( magicIdPrimRep )
23 import CallConv ( CallConv )
24 import CLabel ( isAsmTemp, CLabel, pprCLabel_asm )
25 import Maybes ( maybeToBool, expectJust )
26 import PrimRep ( isFloatingRep, PrimRep(..) )
27 import PrimOp ( PrimOp(..) )
28 import CallConv ( cCallConv )
29 import Stix ( getNatLabelNCG, StixTree(..),
30 StixReg(..), CodeSegment(..),
31 pprStixTrees, ppStixReg,
32 NatM, thenNat, returnNat, mapNat,
33 mapAndUnzipNat, mapAccumLNat,
34 getDeltaNat, setDeltaNat
42 @InstrBlock@s are the insn sequences generated by the insn selectors.
43 They are really trees of insns to facilitate fast appending, where a
44 left-to-right traversal (pre-order?) yields the insns in the correct
49 type InstrBlock = OrdList Instr
55 Code extractor for an entire stix tree---stix statement level.
58 stmt2Instrs :: StixTree {- a stix statement -} -> NatM InstrBlock
60 stmt2Instrs stmt = case stmt of
61 StComment s -> returnNat (unitOL (COMMENT s))
62 StSegment seg -> returnNat (unitOL (SEGMENT seg))
64 StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
66 StFunEnd lab -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
69 StLabel lab -> returnNat (unitOL (LABEL lab))
71 StJump arg -> genJump arg
72 StCondJump lab arg -> genCondJump lab arg
73 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
76 | isFloatingRep pk -> assignFltCode pk dst src
77 | otherwise -> assignIntCode pk dst src
80 -- When falling through on the Alpha, we still have to load pv
81 -- with the address of the next routine, so that it can load gp.
82 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
86 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
87 returnNat (DATA (primRepToSize kind) imms
88 `consOL` concatOL codes)
90 getData :: StixTree -> NatM (InstrBlock, Imm)
92 getData (StInt i) = returnNat (nilOL, ImmInteger i)
93 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
94 getData (StLitLbl s) = returnNat (nilOL, ImmLab s)
95 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
96 getData (StString s) =
97 getNatLabelNCG `thenNat` \ lbl ->
98 returnNat (toOL [LABEL lbl,
99 ASCII True (_UNPK_ s)],
101 -- the linker can handle simple arithmetic...
102 getData (StIndex rep (StCLbl lbl) (StInt off)) =
104 ImmIndex lbl (fromInteger (off * sizeOf rep)))
107 %************************************************************************
109 \subsection{General things for putting together code sequences}
111 %************************************************************************
114 mangleIndexTree :: StixTree -> StixTree
116 mangleIndexTree (StIndex pk base (StInt i))
117 = StPrim IntAddOp [base, off]
119 off = StInt (i * sizeOf pk)
121 mangleIndexTree (StIndex pk base off)
125 in ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
126 if s == 0 then off else StPrim SllOp [off, StInt s]
129 shift DoubleRep = 3::Integer
130 shift CharRep = 0::Integer
131 shift _ = IF_ARCH_alpha(3,2)
135 maybeImm :: StixTree -> Maybe Imm
137 maybeImm (StLitLbl s) = Just (ImmLab s)
138 maybeImm (StCLbl l) = Just (ImmCLbl l)
140 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
141 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
144 | i >= toInteger minInt && i <= toInteger maxInt
145 = Just (ImmInt (fromInteger i))
147 = Just (ImmInteger i)
152 %************************************************************************
154 \subsection{The @Register@ type}
156 %************************************************************************
158 @Register@s passed up the tree. If the stix code forces the register
159 to live in a pre-decided machine register, it comes out as @Fixed@;
160 otherwise, it comes out as @Any@, and the parent can decide which
161 register to put it in.
165 = Fixed PrimRep Reg InstrBlock
166 | Any PrimRep (Reg -> InstrBlock)
168 registerCode :: Register -> Reg -> InstrBlock
169 registerCode (Fixed _ _ code) reg = code
170 registerCode (Any _ code) reg = code reg
172 registerCodeF (Fixed _ _ code) = code
173 registerCodeF (Any _ _) = pprPanic "registerCodeF" empty
175 registerCodeA (Any _ code) = code
176 registerCodeA (Fixed _ _ _) = pprPanic "registerCodeA" empty
178 registerName :: Register -> Reg -> Reg
179 registerName (Fixed _ reg _) _ = reg
180 registerName (Any _ _) reg = reg
182 registerNameF (Fixed _ reg _) = reg
183 registerNameF (Any _ _) = pprPanic "registerNameF" empty
185 registerRep :: Register -> PrimRep
186 registerRep (Fixed pk _ _) = pk
187 registerRep (Any pk _) = pk
189 {-# INLINE registerCode #-}
190 {-# INLINE registerCodeF #-}
191 {-# INLINE registerName #-}
192 {-# INLINE registerNameF #-}
193 {-# INLINE registerRep #-}
194 {-# INLINE isFixed #-}
197 isFixed, isAny :: Register -> Bool
198 isFixed (Fixed _ _ _) = True
199 isFixed (Any _ _) = False
201 isAny = not . isFixed
204 Generate code to get a subtree into a @Register@:
206 getRegister :: StixTree -> NatM Register
208 getRegister (StReg (StixMagicId stgreg))
209 = case (magicIdRegMaybe stgreg) of
210 Just reg -> returnNat (Fixed (magicIdPrimRep stgreg) reg nilOL)
213 getRegister (StReg (StixTemp u pk))
214 = returnNat (Fixed pk (UnmappedReg u pk) nilOL)
216 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
218 getRegister (StCall fn cconv kind args)
219 = genCCall fn cconv kind args `thenNat` \ call ->
220 returnNat (Fixed kind reg call)
222 reg = if isFloatingRep kind
223 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
224 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
226 getRegister (StString s)
227 = getNatLabelNCG `thenNat` \ lbl ->
229 imm_lbl = ImmCLbl lbl
234 ASCII True (_UNPK_ s),
236 #if alpha_TARGET_ARCH
237 LDA dst (AddrImm imm_lbl)
240 MOV L (OpImm imm_lbl) (OpReg dst)
242 #if sparc_TARGET_ARCH
243 SETHI (HI imm_lbl) dst,
244 OR False dst (RIImm (LO imm_lbl)) dst
248 returnNat (Any PtrRep code)
252 -- end of machine-"independent" bit; here we go on the rest...
254 #if alpha_TARGET_ARCH
256 getRegister (StDouble d)
257 = getNatLabelNCG `thenNat` \ lbl ->
258 getNewRegNCG PtrRep `thenNat` \ tmp ->
259 let code dst = mkSeqInstrs [
262 DATA TF [ImmLab (rational d)],
264 LDA tmp (AddrImm (ImmCLbl lbl)),
265 LD TF dst (AddrReg tmp)]
267 returnNat (Any DoubleRep code)
269 getRegister (StPrim primop [x]) -- unary PrimOps
271 IntNegOp -> trivialUCode (NEG Q False) x
273 NotOp -> trivialUCode NOT x
275 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
276 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
278 OrdOp -> coerceIntCode IntRep x
281 Float2IntOp -> coerceFP2Int x
282 Int2FloatOp -> coerceInt2FP pr x
283 Double2IntOp -> coerceFP2Int x
284 Int2DoubleOp -> coerceInt2FP pr x
286 Double2FloatOp -> coerceFltCode x
287 Float2DoubleOp -> coerceFltCode x
289 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
291 fn = case other_op of
292 FloatExpOp -> SLIT("exp")
293 FloatLogOp -> SLIT("log")
294 FloatSqrtOp -> SLIT("sqrt")
295 FloatSinOp -> SLIT("sin")
296 FloatCosOp -> SLIT("cos")
297 FloatTanOp -> SLIT("tan")
298 FloatAsinOp -> SLIT("asin")
299 FloatAcosOp -> SLIT("acos")
300 FloatAtanOp -> SLIT("atan")
301 FloatSinhOp -> SLIT("sinh")
302 FloatCoshOp -> SLIT("cosh")
303 FloatTanhOp -> SLIT("tanh")
304 DoubleExpOp -> SLIT("exp")
305 DoubleLogOp -> SLIT("log")
306 DoubleSqrtOp -> SLIT("sqrt")
307 DoubleSinOp -> SLIT("sin")
308 DoubleCosOp -> SLIT("cos")
309 DoubleTanOp -> SLIT("tan")
310 DoubleAsinOp -> SLIT("asin")
311 DoubleAcosOp -> SLIT("acos")
312 DoubleAtanOp -> SLIT("atan")
313 DoubleSinhOp -> SLIT("sinh")
314 DoubleCoshOp -> SLIT("cosh")
315 DoubleTanhOp -> SLIT("tanh")
317 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
319 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
321 CharGtOp -> trivialCode (CMP LTT) y x
322 CharGeOp -> trivialCode (CMP LE) y x
323 CharEqOp -> trivialCode (CMP EQQ) x y
324 CharNeOp -> int_NE_code x y
325 CharLtOp -> trivialCode (CMP LTT) x y
326 CharLeOp -> trivialCode (CMP LE) x y
328 IntGtOp -> trivialCode (CMP LTT) y x
329 IntGeOp -> trivialCode (CMP LE) y x
330 IntEqOp -> trivialCode (CMP EQQ) x y
331 IntNeOp -> int_NE_code x y
332 IntLtOp -> trivialCode (CMP LTT) x y
333 IntLeOp -> trivialCode (CMP LE) x y
335 WordGtOp -> trivialCode (CMP ULT) y x
336 WordGeOp -> trivialCode (CMP ULE) x y
337 WordEqOp -> trivialCode (CMP EQQ) x y
338 WordNeOp -> int_NE_code x y
339 WordLtOp -> trivialCode (CMP ULT) x y
340 WordLeOp -> trivialCode (CMP ULE) x y
342 AddrGtOp -> trivialCode (CMP ULT) y x
343 AddrGeOp -> trivialCode (CMP ULE) y x
344 AddrEqOp -> trivialCode (CMP EQQ) x y
345 AddrNeOp -> int_NE_code x y
346 AddrLtOp -> trivialCode (CMP ULT) x y
347 AddrLeOp -> trivialCode (CMP ULE) x y
349 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
350 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
351 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
352 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
353 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
354 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
356 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
357 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
358 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
359 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
360 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
361 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
363 IntAddOp -> trivialCode (ADD Q False) x y
364 IntSubOp -> trivialCode (SUB Q False) x y
365 IntMulOp -> trivialCode (MUL Q False) x y
366 IntQuotOp -> trivialCode (DIV Q False) x y
367 IntRemOp -> trivialCode (REM Q False) x y
369 WordQuotOp -> trivialCode (DIV Q True) x y
370 WordRemOp -> trivialCode (REM Q True) x y
372 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
373 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
374 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
375 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
377 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
378 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
379 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
380 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
382 AndOp -> trivialCode AND x y
383 OrOp -> trivialCode OR x y
384 XorOp -> trivialCode XOR x y
385 SllOp -> trivialCode SLL x y
386 SrlOp -> trivialCode SRL x y
388 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
389 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
390 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
392 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
393 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
395 {- ------------------------------------------------------------
396 Some bizarre special code for getting condition codes into
397 registers. Integer non-equality is a test for equality
398 followed by an XOR with 1. (Integer comparisons always set
399 the result register to 0 or 1.) Floating point comparisons of
400 any kind leave the result in a floating point register, so we
401 need to wrangle an integer register out of things.
403 int_NE_code :: StixTree -> StixTree -> NatM Register
406 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
407 getNewRegNCG IntRep `thenNat` \ tmp ->
409 code = registerCode register tmp
410 src = registerName register tmp
411 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
413 returnNat (Any IntRep code__2)
415 {- ------------------------------------------------------------
416 Comments for int_NE_code also apply to cmpF_code
419 :: (Reg -> Reg -> Reg -> Instr)
421 -> StixTree -> StixTree
424 cmpF_code instr cond x y
425 = trivialFCode pr instr x y `thenNat` \ register ->
426 getNewRegNCG DoubleRep `thenNat` \ tmp ->
427 getNatLabelNCG `thenNat` \ lbl ->
429 code = registerCode register tmp
430 result = registerName register tmp
432 code__2 dst = code . mkSeqInstrs [
433 OR zeroh (RIImm (ImmInt 1)) dst,
434 BF cond result (ImmCLbl lbl),
435 OR zeroh (RIReg zeroh) dst,
438 returnNat (Any IntRep code__2)
440 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
441 ------------------------------------------------------------
443 getRegister (StInd pk mem)
444 = getAmode mem `thenNat` \ amode ->
446 code = amodeCode amode
447 src = amodeAddr amode
448 size = primRepToSize pk
449 code__2 dst = code . mkSeqInstr (LD size dst src)
451 returnNat (Any pk code__2)
453 getRegister (StInt i)
456 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
458 returnNat (Any IntRep code)
461 code dst = mkSeqInstr (LDI Q dst src)
463 returnNat (Any IntRep code)
465 src = ImmInt (fromInteger i)
470 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
472 returnNat (Any PtrRep code)
475 imm__2 = case imm of Just x -> x
477 #endif {- alpha_TARGET_ARCH -}
478 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
481 getRegister (StDouble d)
484 = let code dst = unitOL (GLDZ dst)
485 in trace "nativeGen: GLDZ"
486 (returnNat (Any DoubleRep code))
489 = let code dst = unitOL (GLD1 dst)
490 in trace "nativeGen: GLD1"
491 returnNat (Any DoubleRep code)
494 = getNatLabelNCG `thenNat` \ lbl ->
495 let code dst = toOL [
498 DATA DF [ImmDouble d],
500 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
503 returnNat (Any DoubleRep code)
505 -- Calculate the offset for (i+1) words above the _initial_
506 -- %esp value by first determining the current offset of it.
507 getRegister (StScratchWord i)
509 = getDeltaNat `thenNat` \ current_stack_offset ->
510 let j = i+1 - (current_stack_offset `div` 4)
512 = unitOL (LEA L (OpAddr (spRel (j+1))) (OpReg dst))
514 returnNat (Any PtrRep code)
516 getRegister (StPrim primop [x]) -- unary PrimOps
518 IntNegOp -> trivialUCode (NEGI L) x
519 NotOp -> trivialUCode (NOT L) x
521 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
522 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
524 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
525 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
527 FloatSinOp -> trivialUFCode FloatRep (GSIN F) x
528 DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
530 FloatCosOp -> trivialUFCode FloatRep (GCOS F) x
531 DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
533 FloatTanOp -> trivialUFCode FloatRep (GTAN F) x
534 DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
536 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
537 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
539 OrdOp -> coerceIntCode IntRep x
542 Float2IntOp -> coerceFP2Int x
543 Int2FloatOp -> coerceInt2FP FloatRep x
544 Double2IntOp -> coerceFP2Int x
545 Int2DoubleOp -> coerceInt2FP DoubleRep x
549 fixed_x = if is_float_op -- promote to double
550 then StPrim Float2DoubleOp [x]
553 getRegister (StCall fn cCallConv DoubleRep [x])
557 FloatExpOp -> (True, SLIT("exp"))
558 FloatLogOp -> (True, SLIT("log"))
560 FloatAsinOp -> (True, SLIT("asin"))
561 FloatAcosOp -> (True, SLIT("acos"))
562 FloatAtanOp -> (True, SLIT("atan"))
564 FloatSinhOp -> (True, SLIT("sinh"))
565 FloatCoshOp -> (True, SLIT("cosh"))
566 FloatTanhOp -> (True, SLIT("tanh"))
568 DoubleExpOp -> (False, SLIT("exp"))
569 DoubleLogOp -> (False, SLIT("log"))
571 DoubleAsinOp -> (False, SLIT("asin"))
572 DoubleAcosOp -> (False, SLIT("acos"))
573 DoubleAtanOp -> (False, SLIT("atan"))
575 DoubleSinhOp -> (False, SLIT("sinh"))
576 DoubleCoshOp -> (False, SLIT("cosh"))
577 DoubleTanhOp -> (False, SLIT("tanh"))
580 -> pprPanic "getRegister(x86,unary primop)"
581 (pprStixTrees [StPrim primop [x]])
583 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
585 CharGtOp -> condIntReg GTT x y
586 CharGeOp -> condIntReg GE x y
587 CharEqOp -> condIntReg EQQ x y
588 CharNeOp -> condIntReg NE x y
589 CharLtOp -> condIntReg LTT x y
590 CharLeOp -> condIntReg LE x y
592 IntGtOp -> condIntReg GTT x y
593 IntGeOp -> condIntReg GE x y
594 IntEqOp -> condIntReg EQQ x y
595 IntNeOp -> condIntReg NE x y
596 IntLtOp -> condIntReg LTT x y
597 IntLeOp -> condIntReg LE x y
599 WordGtOp -> condIntReg GU x y
600 WordGeOp -> condIntReg GEU x y
601 WordEqOp -> condIntReg EQQ x y
602 WordNeOp -> condIntReg NE x y
603 WordLtOp -> condIntReg LU x y
604 WordLeOp -> condIntReg LEU x y
606 AddrGtOp -> condIntReg GU x y
607 AddrGeOp -> condIntReg GEU x y
608 AddrEqOp -> condIntReg EQQ x y
609 AddrNeOp -> condIntReg NE x y
610 AddrLtOp -> condIntReg LU x y
611 AddrLeOp -> condIntReg LEU x y
613 FloatGtOp -> condFltReg GTT x y
614 FloatGeOp -> condFltReg GE x y
615 FloatEqOp -> condFltReg EQQ x y
616 FloatNeOp -> condFltReg NE x y
617 FloatLtOp -> condFltReg LTT x y
618 FloatLeOp -> condFltReg LE x y
620 DoubleGtOp -> condFltReg GTT x y
621 DoubleGeOp -> condFltReg GE x y
622 DoubleEqOp -> condFltReg EQQ x y
623 DoubleNeOp -> condFltReg NE x y
624 DoubleLtOp -> condFltReg LTT x y
625 DoubleLeOp -> condFltReg LE x y
627 IntAddOp -> add_code L x y
628 IntSubOp -> sub_code L x y
629 IntQuotOp -> quot_code L x y True{-division-}
630 IntRemOp -> quot_code L x y False{-remainder-}
631 IntMulOp -> let op = IMUL L in trivialCode op (Just op) x y
633 FloatAddOp -> trivialFCode FloatRep GADD x y
634 FloatSubOp -> trivialFCode FloatRep GSUB x y
635 FloatMulOp -> trivialFCode FloatRep GMUL x y
636 FloatDivOp -> trivialFCode FloatRep GDIV x y
638 DoubleAddOp -> trivialFCode DoubleRep GADD x y
639 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
640 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
641 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
643 AndOp -> let op = AND L in trivialCode op (Just op) x y
644 OrOp -> let op = OR L in trivialCode op (Just op) x y
645 XorOp -> let op = XOR L in trivialCode op (Just op) x y
647 {- Shift ops on x86s have constraints on their source, it
648 either has to be Imm, CL or 1
649 => trivialCode's is not restrictive enough (sigh.)
652 SllOp -> shift_code (SHL L) x y {-False-}
653 SrlOp -> shift_code (SHR L) x y {-False-}
654 ISllOp -> shift_code (SHL L) x y {-False-}
655 ISraOp -> shift_code (SAR L) x y {-False-}
656 ISrlOp -> shift_code (SHR L) x y {-False-}
658 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
659 [promote x, promote y])
660 where promote x = StPrim Float2DoubleOp [x]
661 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
664 -> pprPanic "getRegister(x86,dyadic primop)"
665 (pprStixTrees [StPrim primop [x, y]])
669 shift_code :: (Imm -> Operand -> Instr)
674 {- Case1: shift length as immediate -}
675 -- Code is the same as the first eq. for trivialCode -- sigh.
676 shift_code instr x y{-amount-}
678 = getRegister x `thenNat` \ regx ->
681 then registerCodeA regx dst `bind` \ code_x ->
683 instr imm__2 (OpReg dst)
684 else registerCodeF regx `bind` \ code_x ->
685 registerNameF regx `bind` \ r_x ->
687 MOV L (OpReg r_x) (OpReg dst) `snocOL`
688 instr imm__2 (OpReg dst)
690 returnNat (Any IntRep mkcode)
693 imm__2 = case imm of Just x -> x
695 {- Case2: shift length is complex (non-immediate) -}
696 -- Since ECX is always used as a spill temporary, we can't
697 -- use it here to do non-immediate shifts. No big deal --
698 -- they are only very rare, and we can use an equivalent
699 -- test-and-jump sequence which doesn't use ECX.
700 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
701 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
702 shift_code instr x y{-amount-}
703 = getRegister x `thenNat` \ register1 ->
704 getRegister y `thenNat` \ register2 ->
705 getNatLabelNCG `thenNat` \ lbl_test3 ->
706 getNatLabelNCG `thenNat` \ lbl_test2 ->
707 getNatLabelNCG `thenNat` \ lbl_test1 ->
708 getNatLabelNCG `thenNat` \ lbl_test0 ->
709 getNatLabelNCG `thenNat` \ lbl_after ->
710 getNewRegNCG IntRep `thenNat` \ tmp ->
712 = let src_val = registerName register1 dst
713 code_val = registerCode register1 dst
714 src_amt = registerName register2 tmp
715 code_amt = registerCode register2 tmp
720 MOV L (OpReg src_amt) r_tmp `appOL`
722 MOV L (OpReg src_val) r_dst `appOL`
724 COMMENT (_PK_ "begin shift sequence"),
725 MOV L (OpReg src_val) r_dst,
726 MOV L (OpReg src_amt) r_tmp,
728 BT L (ImmInt 4) r_tmp,
730 instr (ImmInt 16) r_dst,
733 BT L (ImmInt 3) r_tmp,
735 instr (ImmInt 8) r_dst,
738 BT L (ImmInt 2) r_tmp,
740 instr (ImmInt 4) r_dst,
743 BT L (ImmInt 1) r_tmp,
745 instr (ImmInt 2) r_dst,
748 BT L (ImmInt 0) r_tmp,
750 instr (ImmInt 1) r_dst,
753 COMMENT (_PK_ "end shift sequence")
756 returnNat (Any IntRep code__2)
759 add_code :: Size -> StixTree -> StixTree -> NatM Register
761 add_code sz x (StInt y)
762 = getRegister x `thenNat` \ register ->
763 getNewRegNCG IntRep `thenNat` \ tmp ->
765 code = registerCode register tmp
766 src1 = registerName register tmp
767 src2 = ImmInt (fromInteger y)
770 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
773 returnNat (Any IntRep code__2)
775 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
778 sub_code :: Size -> StixTree -> StixTree -> NatM Register
780 sub_code sz x (StInt y)
781 = getRegister x `thenNat` \ register ->
782 getNewRegNCG IntRep `thenNat` \ tmp ->
784 code = registerCode register tmp
785 src1 = registerName register tmp
786 src2 = ImmInt (-(fromInteger y))
789 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
792 returnNat (Any IntRep code__2)
794 sub_code sz x y = trivialCode (SUB sz) Nothing x y
799 -> StixTree -> StixTree
800 -> Bool -- True => division, False => remainder operation
803 -- x must go into eax, edx must be a sign-extension of eax, and y
804 -- should go in some other register (or memory), so that we get
805 -- edx:eax / reg -> eax (remainder in edx). Currently we choose
806 -- to put y on the C stack, since that avoids tying up yet another
807 -- precious register.
809 quot_code sz x y is_division
810 = getRegister x `thenNat` \ register1 ->
811 getRegister y `thenNat` \ register2 ->
812 getNewRegNCG IntRep `thenNat` \ tmp ->
813 getDeltaNat `thenNat` \ delta ->
815 code1 = registerCode register1 tmp
816 src1 = registerName register1 tmp
817 code2 = registerCode register2 tmp
818 src2 = registerName register2 tmp
819 code__2 = code2 `snocOL` -- src2 := y
820 PUSH L (OpReg src2) `snocOL` -- -4(%esp) := y
821 DELTA (delta-4) `appOL`
822 code1 `snocOL` -- src1 := x
823 MOV L (OpReg src1) (OpReg eax) `snocOL` -- eax := x
825 IDIV sz (OpAddr (spRel 0)) `snocOL`
826 ADD L (OpImm (ImmInt 4)) (OpReg esp) `snocOL`
829 returnNat (Fixed IntRep (if is_division then eax else edx) code__2)
830 -----------------------
832 getRegister (StInd pk mem)
833 = getAmode mem `thenNat` \ amode ->
835 code = amodeCode amode
836 src = amodeAddr amode
837 size = primRepToSize pk
838 code__2 dst = code `snocOL`
839 if pk == DoubleRep || pk == FloatRep
840 then GLD size src dst
842 L -> MOV L (OpAddr src) (OpReg dst)
843 B -> MOVZxL B (OpAddr src) (OpReg dst)
845 returnNat (Any pk code__2)
847 getRegister (StInt i)
849 src = ImmInt (fromInteger i)
852 = unitOL (XOR L (OpReg dst) (OpReg dst))
854 = unitOL (MOV L (OpImm src) (OpReg dst))
856 returnNat (Any IntRep code)
860 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
862 returnNat (Any PtrRep code)
864 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
867 imm__2 = case imm of Just x -> x
869 #endif {- i386_TARGET_ARCH -}
870 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
871 #if sparc_TARGET_ARCH
873 getRegister (StDouble d)
874 = getNatLabelNCG `thenNat` \ lbl ->
875 getNewRegNCG PtrRep `thenNat` \ tmp ->
876 let code dst = toOL [
879 DATA DF [ImmDouble d],
881 SETHI (HI (ImmCLbl lbl)) tmp,
882 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
884 returnNat (Any DoubleRep code)
886 getRegister (StPrim primop [x]) -- unary PrimOps
888 IntNegOp -> trivialUCode (SUB False False g0) x
889 NotOp -> trivialUCode (XNOR False g0) x
891 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
893 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
895 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
896 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
898 OrdOp -> coerceIntCode IntRep x
901 Float2IntOp -> coerceFP2Int x
902 Int2FloatOp -> coerceInt2FP FloatRep x
903 Double2IntOp -> coerceFP2Int x
904 Int2DoubleOp -> coerceInt2FP DoubleRep x
908 fixed_x = if is_float_op -- promote to double
909 then StPrim Float2DoubleOp [x]
912 getRegister (StCall fn cCallConv DoubleRep [x])
916 FloatExpOp -> (True, SLIT("exp"))
917 FloatLogOp -> (True, SLIT("log"))
918 FloatSqrtOp -> (True, SLIT("sqrt"))
920 FloatSinOp -> (True, SLIT("sin"))
921 FloatCosOp -> (True, SLIT("cos"))
922 FloatTanOp -> (True, SLIT("tan"))
924 FloatAsinOp -> (True, SLIT("asin"))
925 FloatAcosOp -> (True, SLIT("acos"))
926 FloatAtanOp -> (True, SLIT("atan"))
928 FloatSinhOp -> (True, SLIT("sinh"))
929 FloatCoshOp -> (True, SLIT("cosh"))
930 FloatTanhOp -> (True, SLIT("tanh"))
932 DoubleExpOp -> (False, SLIT("exp"))
933 DoubleLogOp -> (False, SLIT("log"))
934 DoubleSqrtOp -> (True, SLIT("sqrt"))
936 DoubleSinOp -> (False, SLIT("sin"))
937 DoubleCosOp -> (False, SLIT("cos"))
938 DoubleTanOp -> (False, SLIT("tan"))
940 DoubleAsinOp -> (False, SLIT("asin"))
941 DoubleAcosOp -> (False, SLIT("acos"))
942 DoubleAtanOp -> (False, SLIT("atan"))
944 DoubleSinhOp -> (False, SLIT("sinh"))
945 DoubleCoshOp -> (False, SLIT("cosh"))
946 DoubleTanhOp -> (False, SLIT("tanh"))
947 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
949 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
951 CharGtOp -> condIntReg GTT x y
952 CharGeOp -> condIntReg GE x y
953 CharEqOp -> condIntReg EQQ x y
954 CharNeOp -> condIntReg NE x y
955 CharLtOp -> condIntReg LTT x y
956 CharLeOp -> condIntReg LE x y
958 IntGtOp -> condIntReg GTT x y
959 IntGeOp -> condIntReg GE x y
960 IntEqOp -> condIntReg EQQ x y
961 IntNeOp -> condIntReg NE x y
962 IntLtOp -> condIntReg LTT x y
963 IntLeOp -> condIntReg LE x y
965 WordGtOp -> condIntReg GU x y
966 WordGeOp -> condIntReg GEU x y
967 WordEqOp -> condIntReg EQQ x y
968 WordNeOp -> condIntReg NE x y
969 WordLtOp -> condIntReg LU x y
970 WordLeOp -> condIntReg LEU x y
972 AddrGtOp -> condIntReg GU x y
973 AddrGeOp -> condIntReg GEU x y
974 AddrEqOp -> condIntReg EQQ x y
975 AddrNeOp -> condIntReg NE x y
976 AddrLtOp -> condIntReg LU x y
977 AddrLeOp -> condIntReg LEU x y
979 FloatGtOp -> condFltReg GTT x y
980 FloatGeOp -> condFltReg GE x y
981 FloatEqOp -> condFltReg EQQ x y
982 FloatNeOp -> condFltReg NE x y
983 FloatLtOp -> condFltReg LTT x y
984 FloatLeOp -> condFltReg LE x y
986 DoubleGtOp -> condFltReg GTT x y
987 DoubleGeOp -> condFltReg GE x y
988 DoubleEqOp -> condFltReg EQQ x y
989 DoubleNeOp -> condFltReg NE x y
990 DoubleLtOp -> condFltReg LTT x y
991 DoubleLeOp -> condFltReg LE x y
993 IntAddOp -> trivialCode (ADD False False) x y
994 IntSubOp -> trivialCode (SUB False False) x y
996 -- ToDo: teach about V8+ SPARC mul/div instructions
997 IntMulOp -> imul_div SLIT(".umul") x y
998 IntQuotOp -> imul_div SLIT(".div") x y
999 IntRemOp -> imul_div SLIT(".rem") x y
1001 FloatAddOp -> trivialFCode FloatRep FADD x y
1002 FloatSubOp -> trivialFCode FloatRep FSUB x y
1003 FloatMulOp -> trivialFCode FloatRep FMUL x y
1004 FloatDivOp -> trivialFCode FloatRep FDIV x y
1006 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1007 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1008 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1009 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1011 AndOp -> trivialCode (AND False) x y
1012 OrOp -> trivialCode (OR False) x y
1013 XorOp -> trivialCode (XOR False) x y
1014 SllOp -> trivialCode SLL x y
1015 SrlOp -> trivialCode SRL x y
1017 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1018 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1019 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1021 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1022 where promote x = StPrim Float2DoubleOp [x]
1023 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1024 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1026 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1028 getRegister (StInd pk mem)
1029 = getAmode mem `thenNat` \ amode ->
1031 code = amodeCode amode
1032 src = amodeAddr amode
1033 size = primRepToSize pk
1034 code__2 dst = code `snocOL` LD size src dst
1036 returnNat (Any pk code__2)
1038 getRegister (StInt i)
1041 src = ImmInt (fromInteger i)
1042 code dst = unitOL (OR False g0 (RIImm src) dst)
1044 returnNat (Any IntRep code)
1050 SETHI (HI imm__2) dst,
1051 OR False dst (RIImm (LO imm__2)) dst]
1053 returnNat (Any PtrRep code)
1056 imm__2 = case imm of Just x -> x
1058 #endif {- sparc_TARGET_ARCH -}
1061 %************************************************************************
1063 \subsection{The @Amode@ type}
1065 %************************************************************************
1067 @Amode@s: Memory addressing modes passed up the tree.
1069 data Amode = Amode MachRegsAddr InstrBlock
1071 amodeAddr (Amode addr _) = addr
1072 amodeCode (Amode _ code) = code
1075 Now, given a tree (the argument to an StInd) that references memory,
1076 produce a suitable addressing mode.
1078 A Rule of the Game (tm) for Amodes: use of the addr bit must
1079 immediately follow use of the code part, since the code part puts
1080 values in registers which the addr then refers to. So you can't put
1081 anything in between, lest it overwrite some of those registers. If
1082 you need to do some other computation between the code part and use of
1083 the addr bit, first store the effective address from the amode in a
1084 temporary, then do the other computation, and then use the temporary:
1088 ... other computation ...
1092 getAmode :: StixTree -> NatM Amode
1094 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1096 #if alpha_TARGET_ARCH
1098 getAmode (StPrim IntSubOp [x, StInt i])
1099 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1100 getRegister x `thenNat` \ register ->
1102 code = registerCode register tmp
1103 reg = registerName register tmp
1104 off = ImmInt (-(fromInteger i))
1106 returnNat (Amode (AddrRegImm reg off) code)
1108 getAmode (StPrim IntAddOp [x, StInt i])
1109 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1110 getRegister x `thenNat` \ register ->
1112 code = registerCode register tmp
1113 reg = registerName register tmp
1114 off = ImmInt (fromInteger i)
1116 returnNat (Amode (AddrRegImm reg off) code)
1120 = returnNat (Amode (AddrImm imm__2) id)
1123 imm__2 = case imm of Just x -> x
1126 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1127 getRegister other `thenNat` \ register ->
1129 code = registerCode register tmp
1130 reg = registerName register tmp
1132 returnNat (Amode (AddrReg reg) code)
1134 #endif {- alpha_TARGET_ARCH -}
1135 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1136 #if i386_TARGET_ARCH
1138 getAmode (StPrim IntSubOp [x, StInt i])
1139 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1140 getRegister x `thenNat` \ register ->
1142 code = registerCode register tmp
1143 reg = registerName register tmp
1144 off = ImmInt (-(fromInteger i))
1146 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1148 getAmode (StPrim IntAddOp [x, StInt i])
1150 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1153 imm__2 = case imm of Just x -> x
1155 getAmode (StPrim IntAddOp [x, StInt i])
1156 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1157 getRegister x `thenNat` \ register ->
1159 code = registerCode register tmp
1160 reg = registerName register tmp
1161 off = ImmInt (fromInteger i)
1163 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1165 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1166 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1167 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1168 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1169 getRegister x `thenNat` \ register1 ->
1170 getRegister y `thenNat` \ register2 ->
1172 code1 = registerCode register1 tmp1
1173 reg1 = registerName register1 tmp1
1174 code2 = registerCode register2 tmp2
1175 reg2 = registerName register2 tmp2
1176 code__2 = code1 `appOL` code2
1177 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1179 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1184 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1187 imm__2 = case imm of Just x -> x
1190 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1191 getRegister other `thenNat` \ register ->
1193 code = registerCode register tmp
1194 reg = registerName register tmp
1196 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1198 #endif {- i386_TARGET_ARCH -}
1199 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1200 #if sparc_TARGET_ARCH
1202 getAmode (StPrim IntSubOp [x, StInt i])
1204 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1205 getRegister x `thenNat` \ register ->
1207 code = registerCode register tmp
1208 reg = registerName register tmp
1209 off = ImmInt (-(fromInteger i))
1211 returnNat (Amode (AddrRegImm reg off) code)
1214 getAmode (StPrim IntAddOp [x, StInt i])
1216 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1217 getRegister x `thenNat` \ register ->
1219 code = registerCode register tmp
1220 reg = registerName register tmp
1221 off = ImmInt (fromInteger i)
1223 returnNat (Amode (AddrRegImm reg off) code)
1225 getAmode (StPrim IntAddOp [x, y])
1226 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1227 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1228 getRegister x `thenNat` \ register1 ->
1229 getRegister y `thenNat` \ register2 ->
1231 code1 = registerCode register1 tmp1
1232 reg1 = registerName register1 tmp1
1233 code2 = registerCode register2 tmp2
1234 reg2 = registerName register2 tmp2
1235 code__2 = code1 `appOL` code2
1237 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1241 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1243 code = unitOL (SETHI (HI imm__2) tmp)
1245 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1248 imm__2 = case imm of Just x -> x
1251 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1252 getRegister other `thenNat` \ register ->
1254 code = registerCode register tmp
1255 reg = registerName register tmp
1258 returnNat (Amode (AddrRegImm reg off) code)
1260 #endif {- sparc_TARGET_ARCH -}
1263 %************************************************************************
1265 \subsection{The @CondCode@ type}
1267 %************************************************************************
1269 Condition codes passed up the tree.
1271 data CondCode = CondCode Bool Cond InstrBlock
1273 condName (CondCode _ cond _) = cond
1274 condFloat (CondCode is_float _ _) = is_float
1275 condCode (CondCode _ _ code) = code
1278 Set up a condition code for a conditional branch.
1281 getCondCode :: StixTree -> NatM CondCode
1283 #if alpha_TARGET_ARCH
1284 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1285 #endif {- alpha_TARGET_ARCH -}
1286 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1288 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1289 -- yes, they really do seem to want exactly the same!
1291 getCondCode (StPrim primop [x, y])
1293 CharGtOp -> condIntCode GTT x y
1294 CharGeOp -> condIntCode GE x y
1295 CharEqOp -> condIntCode EQQ x y
1296 CharNeOp -> condIntCode NE x y
1297 CharLtOp -> condIntCode LTT x y
1298 CharLeOp -> condIntCode LE x y
1300 IntGtOp -> condIntCode GTT x y
1301 IntGeOp -> condIntCode GE x y
1302 IntEqOp -> condIntCode EQQ x y
1303 IntNeOp -> condIntCode NE x y
1304 IntLtOp -> condIntCode LTT x y
1305 IntLeOp -> condIntCode LE x y
1307 WordGtOp -> condIntCode GU x y
1308 WordGeOp -> condIntCode GEU x y
1309 WordEqOp -> condIntCode EQQ x y
1310 WordNeOp -> condIntCode NE x y
1311 WordLtOp -> condIntCode LU x y
1312 WordLeOp -> condIntCode LEU x y
1314 AddrGtOp -> condIntCode GU x y
1315 AddrGeOp -> condIntCode GEU x y
1316 AddrEqOp -> condIntCode EQQ x y
1317 AddrNeOp -> condIntCode NE x y
1318 AddrLtOp -> condIntCode LU x y
1319 AddrLeOp -> condIntCode LEU x y
1321 FloatGtOp -> condFltCode GTT x y
1322 FloatGeOp -> condFltCode GE x y
1323 FloatEqOp -> condFltCode EQQ x y
1324 FloatNeOp -> condFltCode NE x y
1325 FloatLtOp -> condFltCode LTT x y
1326 FloatLeOp -> condFltCode LE x y
1328 DoubleGtOp -> condFltCode GTT x y
1329 DoubleGeOp -> condFltCode GE x y
1330 DoubleEqOp -> condFltCode EQQ x y
1331 DoubleNeOp -> condFltCode NE x y
1332 DoubleLtOp -> condFltCode LTT x y
1333 DoubleLeOp -> condFltCode LE x y
1335 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1340 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1341 passed back up the tree.
1344 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> NatM CondCode
1346 #if alpha_TARGET_ARCH
1347 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1348 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1349 #endif {- alpha_TARGET_ARCH -}
1351 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1352 #if i386_TARGET_ARCH
1354 -- memory vs immediate
1355 condIntCode cond (StInd pk x) y
1357 = getAmode x `thenNat` \ amode ->
1359 code1 = amodeCode amode
1360 x__2 = amodeAddr amode
1361 sz = primRepToSize pk
1362 code__2 = code1 `snocOL`
1363 CMP sz (OpImm imm__2) (OpAddr x__2)
1365 returnNat (CondCode False cond code__2)
1368 imm__2 = case imm of Just x -> x
1371 condIntCode cond x (StInt 0)
1372 = getRegister x `thenNat` \ register1 ->
1373 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1375 code1 = registerCode register1 tmp1
1376 src1 = registerName register1 tmp1
1377 code__2 = code1 `snocOL`
1378 TEST L (OpReg src1) (OpReg src1)
1380 returnNat (CondCode False cond code__2)
1382 -- anything vs immediate
1383 condIntCode cond x y
1385 = getRegister x `thenNat` \ register1 ->
1386 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1388 code1 = registerCode register1 tmp1
1389 src1 = registerName register1 tmp1
1390 code__2 = code1 `snocOL`
1391 CMP L (OpImm imm__2) (OpReg src1)
1393 returnNat (CondCode False cond code__2)
1396 imm__2 = case imm of Just x -> x
1398 -- memory vs anything
1399 condIntCode cond (StInd pk x) y
1400 = getAmode x `thenNat` \ amode_x ->
1401 getRegister y `thenNat` \ reg_y ->
1402 getNewRegNCG IntRep `thenNat` \ tmp ->
1404 c_x = amodeCode amode_x
1405 am_x = amodeAddr amode_x
1406 c_y = registerCode reg_y tmp
1407 r_y = registerName reg_y tmp
1408 sz = primRepToSize pk
1410 -- optimisation: if there's no code for x, just an amode,
1411 -- use whatever reg y winds up in. Assumes that c_y doesn't
1412 -- clobber any regs in the amode am_x, which I'm not sure is
1413 -- justified. The otherwise clause makes the same assumption.
1414 code__2 | isNilOL c_x
1416 CMP sz (OpReg r_y) (OpAddr am_x)
1420 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1422 CMP sz (OpReg tmp) (OpAddr am_x)
1424 returnNat (CondCode False cond code__2)
1426 -- anything vs memory
1428 condIntCode cond y (StInd pk x)
1429 = getAmode x `thenNat` \ amode_x ->
1430 getRegister y `thenNat` \ reg_y ->
1431 getNewRegNCG IntRep `thenNat` \ tmp ->
1433 c_x = amodeCode amode_x
1434 am_x = amodeAddr amode_x
1435 c_y = registerCode reg_y tmp
1436 r_y = registerName reg_y tmp
1437 sz = primRepToSize pk
1438 -- same optimisation and nagging doubts as previous clause
1439 code__2 | isNilOL c_x
1441 CMP sz (OpAddr am_x) (OpReg r_y)
1445 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1447 CMP sz (OpAddr am_x) (OpReg tmp)
1449 returnNat (CondCode False cond code__2)
1451 -- anything vs anything
1452 condIntCode cond x y
1453 = getRegister x `thenNat` \ register1 ->
1454 getRegister y `thenNat` \ register2 ->
1455 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1456 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1458 code1 = registerCode register1 tmp1
1459 src1 = registerName register1 tmp1
1460 code2 = registerCode register2 tmp2
1461 src2 = registerName register2 tmp2
1462 code__2 = code1 `snocOL`
1463 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1465 CMP L (OpReg src2) (OpReg tmp1)
1467 returnNat (CondCode False cond code__2)
1470 condFltCode cond x y
1471 = getRegister x `thenNat` \ register1 ->
1472 getRegister y `thenNat` \ register2 ->
1473 getNewRegNCG (registerRep register1)
1475 getNewRegNCG (registerRep register2)
1477 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1479 pk1 = registerRep register1
1480 code1 = registerCode register1 tmp1
1481 src1 = registerName register1 tmp1
1483 pk2 = registerRep register2
1484 code2 = registerCode register2 tmp2
1485 src2 = registerName register2 tmp2
1487 code__2 | isAny register1
1488 = code1 `appOL` -- result in tmp1
1490 GCMP (primRepToSize pk1) tmp1 src2
1494 GMOV src1 tmp1 `appOL`
1496 GCMP (primRepToSize pk1) tmp1 src2
1498 {- On the 486, the flags set by FP compare are the unsigned ones!
1499 (This looks like a HACK to me. WDP 96/03)
1501 fix_FP_cond :: Cond -> Cond
1503 fix_FP_cond GE = GEU
1504 fix_FP_cond GTT = GU
1505 fix_FP_cond LTT = LU
1506 fix_FP_cond LE = LEU
1507 fix_FP_cond any = any
1509 returnNat (CondCode True (fix_FP_cond cond) code__2)
1513 #endif {- i386_TARGET_ARCH -}
1514 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1515 #if sparc_TARGET_ARCH
1517 condIntCode cond x (StInt y)
1519 = getRegister x `thenNat` \ register ->
1520 getNewRegNCG IntRep `thenNat` \ tmp ->
1522 code = registerCode register tmp
1523 src1 = registerName register tmp
1524 src2 = ImmInt (fromInteger y)
1525 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1527 returnNat (CondCode False cond code__2)
1529 condIntCode cond x y
1530 = getRegister x `thenNat` \ register1 ->
1531 getRegister y `thenNat` \ register2 ->
1532 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1533 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1535 code1 = registerCode register1 tmp1
1536 src1 = registerName register1 tmp1
1537 code2 = registerCode register2 tmp2
1538 src2 = registerName register2 tmp2
1539 code__2 = code1 `appOL` code2 `snocOL`
1540 SUB False True src1 (RIReg src2) g0
1542 returnNat (CondCode False cond code__2)
1545 condFltCode cond x y
1546 = getRegister x `thenNat` \ register1 ->
1547 getRegister y `thenNat` \ register2 ->
1548 getNewRegNCG (registerRep register1)
1550 getNewRegNCG (registerRep register2)
1552 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1554 promote x = FxTOy F DF x tmp
1556 pk1 = registerRep register1
1557 code1 = registerCode register1 tmp1
1558 src1 = registerName register1 tmp1
1560 pk2 = registerRep register2
1561 code2 = registerCode register2 tmp2
1562 src2 = registerName register2 tmp2
1566 code1 `appOL` code2 `snocOL`
1567 FCMP True (primRepToSize pk1) src1 src2
1568 else if pk1 == FloatRep then
1569 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1570 FCMP True DF tmp src2
1572 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1573 FCMP True DF src1 tmp
1575 returnNat (CondCode True cond code__2)
1577 #endif {- sparc_TARGET_ARCH -}
1580 %************************************************************************
1582 \subsection{Generating assignments}
1584 %************************************************************************
1586 Assignments are really at the heart of the whole code generation
1587 business. Almost all top-level nodes of any real importance are
1588 assignments, which correspond to loads, stores, or register transfers.
1589 If we're really lucky, some of the register transfers will go away,
1590 because we can use the destination register to complete the code
1591 generation for the right hand side. This only fails when the right
1592 hand side is forced into a fixed register (e.g. the result of a call).
1595 assignIntCode, assignFltCode
1596 :: PrimRep -> StixTree -> StixTree -> NatM InstrBlock
1598 #if alpha_TARGET_ARCH
1600 assignIntCode pk (StInd _ dst) src
1601 = getNewRegNCG IntRep `thenNat` \ tmp ->
1602 getAmode dst `thenNat` \ amode ->
1603 getRegister src `thenNat` \ register ->
1605 code1 = amodeCode amode []
1606 dst__2 = amodeAddr amode
1607 code2 = registerCode register tmp []
1608 src__2 = registerName register tmp
1609 sz = primRepToSize pk
1610 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1614 assignIntCode pk dst src
1615 = getRegister dst `thenNat` \ register1 ->
1616 getRegister src `thenNat` \ register2 ->
1618 dst__2 = registerName register1 zeroh
1619 code = registerCode register2 dst__2
1620 src__2 = registerName register2 dst__2
1621 code__2 = if isFixed register2
1622 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1627 #endif {- alpha_TARGET_ARCH -}
1628 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1629 #if i386_TARGET_ARCH
1631 -- Destination of an assignment can only be reg or mem.
1632 -- This is the mem case.
1633 assignIntCode pk (StInd _ dst) src
1634 = getAmode dst `thenNat` \ amode ->
1635 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
1636 getNewRegNCG PtrRep `thenNat` \ tmp ->
1638 -- In general, if the address computation for dst may require
1639 -- some insns preceding the addressing mode itself. So there's
1640 -- no guarantee that the code for dst and the code for src won't
1641 -- write the same register. This means either the address or
1642 -- the value needs to be copied into a temporary. We detect the
1643 -- common case where the amode has no code, and elide the copy.
1644 codea = amodeCode amode
1645 dst__a = amodeAddr amode
1647 code | isNilOL codea
1649 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
1653 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
1655 MOV (primRepToSize pk) opsrc
1656 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
1662 -> NatM (InstrBlock,Operand) -- code, operator
1666 = returnNat (nilOL, OpImm imm_op)
1669 imm_op = case imm of Just x -> x
1672 = getRegister op `thenNat` \ register ->
1673 getNewRegNCG (registerRep register)
1675 let code = registerCode register tmp
1676 reg = registerName register tmp
1678 returnNat (code, OpReg reg)
1680 -- Assign; dst is a reg, rhs is mem
1681 assignIntCode pk dst (StInd pks src)
1682 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1683 getAmode src `thenNat` \ amode ->
1684 getRegister dst `thenNat` \ reg_dst ->
1686 c_addr = amodeCode amode
1687 am_addr = amodeAddr amode
1689 c_dst = registerCode reg_dst tmp -- should be empty
1690 r_dst = registerName reg_dst tmp
1691 szs = primRepToSize pks
1692 opc = case szs of L -> MOV L ; B -> MOVZxL B
1694 code | isNilOL c_dst
1696 opc (OpAddr am_addr) (OpReg r_dst)
1698 = pprPanic "assignIntCode(x86): bad dst(2)" empty
1702 -- dst is a reg, but src could be anything
1703 assignIntCode pk dst src
1704 = getRegister dst `thenNat` \ registerd ->
1705 getRegister src `thenNat` \ registers ->
1706 getNewRegNCG IntRep `thenNat` \ tmp ->
1708 r_dst = registerName registerd tmp
1709 c_dst = registerCode registerd tmp -- should be empty
1710 r_src = registerName registers r_dst
1711 c_src = registerCode registers r_dst
1713 code | isNilOL c_dst
1715 MOV L (OpReg r_src) (OpReg r_dst)
1717 = pprPanic "assignIntCode(x86): bad dst(3)" empty
1721 #endif {- i386_TARGET_ARCH -}
1722 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1723 #if sparc_TARGET_ARCH
1725 assignIntCode pk (StInd _ dst) src
1726 = getNewRegNCG IntRep `thenNat` \ tmp ->
1727 getAmode dst `thenNat` \ amode ->
1728 getRegister src `thenNat` \ register ->
1730 code1 = amodeCode amode
1731 dst__2 = amodeAddr amode
1732 code2 = registerCode register tmp
1733 src__2 = registerName register tmp
1734 sz = primRepToSize pk
1735 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
1739 assignIntCode pk dst src
1740 = getRegister dst `thenNat` \ register1 ->
1741 getRegister src `thenNat` \ register2 ->
1743 dst__2 = registerName register1 g0
1744 code = registerCode register2 dst__2
1745 src__2 = registerName register2 dst__2
1746 code__2 = if isFixed register2
1747 then code `snocOL` OR False g0 (RIReg src__2) dst__2
1752 #endif {- sparc_TARGET_ARCH -}
1755 % --------------------------------
1756 Floating-point assignments:
1757 % --------------------------------
1759 #if alpha_TARGET_ARCH
1761 assignFltCode pk (StInd _ dst) src
1762 = getNewRegNCG pk `thenNat` \ tmp ->
1763 getAmode dst `thenNat` \ amode ->
1764 getRegister src `thenNat` \ register ->
1766 code1 = amodeCode amode []
1767 dst__2 = amodeAddr amode
1768 code2 = registerCode register tmp []
1769 src__2 = registerName register tmp
1770 sz = primRepToSize pk
1771 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1775 assignFltCode pk dst src
1776 = getRegister dst `thenNat` \ register1 ->
1777 getRegister src `thenNat` \ register2 ->
1779 dst__2 = registerName register1 zeroh
1780 code = registerCode register2 dst__2
1781 src__2 = registerName register2 dst__2
1782 code__2 = if isFixed register2
1783 then code . mkSeqInstr (FMOV src__2 dst__2)
1788 #endif {- alpha_TARGET_ARCH -}
1789 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1790 #if i386_TARGET_ARCH
1793 assignFltCode pk (StInd pk_dst addr) src
1795 = pprPanic "assignFltCode(x86): src/ind sz mismatch" empty
1797 = getRegister src `thenNat` \ reg_src ->
1798 getRegister addr `thenNat` \ reg_addr ->
1799 getNewRegNCG pk `thenNat` \ tmp_src ->
1800 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
1801 let r_src = registerName reg_src tmp_src
1802 c_src = registerCode reg_src tmp_src
1803 r_addr = registerName reg_addr tmp_addr
1804 c_addr = registerCode reg_addr tmp_addr
1805 sz = primRepToSize pk
1807 code = c_src `appOL`
1808 -- no need to preserve r_src across the addr computation,
1809 -- since r_src must be a float reg
1810 -- whilst r_addr is an int reg
1813 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
1817 -- dst must be a (FP) register
1818 assignFltCode pk dst src
1819 = getRegister dst `thenNat` \ reg_dst ->
1820 getRegister src `thenNat` \ reg_src ->
1821 getNewRegNCG pk `thenNat` \ tmp ->
1823 r_dst = registerName reg_dst tmp
1824 c_dst = registerCode reg_dst tmp -- should be empty
1826 r_src = registerName reg_src r_dst
1827 c_src = registerCode reg_src r_dst
1829 code | isNilOL c_dst
1830 = if isFixed reg_src
1831 then c_src `snocOL` GMOV r_src r_dst
1834 = pprPanic "assignFltCode(x86): lhs is not mem or reg"
1840 #endif {- i386_TARGET_ARCH -}
1841 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1842 #if sparc_TARGET_ARCH
1844 assignFltCode pk (StInd _ dst) src
1845 = getNewRegNCG pk `thenNat` \ tmp1 ->
1846 getAmode dst `thenNat` \ amode ->
1847 getRegister src `thenNat` \ register ->
1849 sz = primRepToSize pk
1850 dst__2 = amodeAddr amode
1852 code1 = amodeCode amode
1853 code2 = registerCode register tmp1
1855 src__2 = registerName register tmp1
1856 pk__2 = registerRep register
1857 sz__2 = primRepToSize pk__2
1859 code__2 = code1 `appOL` code2 `appOL`
1861 then unitOL (ST sz src__2 dst__2)
1862 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1866 assignFltCode pk dst src
1867 = getRegister dst `thenNat` \ register1 ->
1868 getRegister src `thenNat` \ register2 ->
1870 pk__2 = registerRep register2
1871 sz__2 = primRepToSize pk__2
1873 getNewRegNCG pk__2 `thenNat` \ tmp ->
1875 sz = primRepToSize pk
1876 dst__2 = registerName register1 g0 -- must be Fixed
1879 reg__2 = if pk /= pk__2 then tmp else dst__2
1881 code = registerCode register2 reg__2
1883 src__2 = registerName register2 reg__2
1887 code `snocOL` FxTOy sz__2 sz src__2 dst__2
1888 else if isFixed register2 then
1889 code `snocOL` FMOV sz src__2 dst__2
1895 #endif {- sparc_TARGET_ARCH -}
1898 %************************************************************************
1900 \subsection{Generating an unconditional branch}
1902 %************************************************************************
1904 We accept two types of targets: an immediate CLabel or a tree that
1905 gets evaluated into a register. Any CLabels which are AsmTemporaries
1906 are assumed to be in the local block of code, close enough for a
1907 branch instruction. Other CLabels are assumed to be far away.
1909 (If applicable) Do not fill the delay slots here; you will confuse the
1913 genJump :: StixTree{-the branch target-} -> NatM InstrBlock
1915 #if alpha_TARGET_ARCH
1917 genJump (StCLbl lbl)
1918 | isAsmTemp lbl = returnInstr (BR target)
1919 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1921 target = ImmCLbl lbl
1924 = getRegister tree `thenNat` \ register ->
1925 getNewRegNCG PtrRep `thenNat` \ tmp ->
1927 dst = registerName register pv
1928 code = registerCode register pv
1929 target = registerName register pv
1931 if isFixed register then
1932 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1934 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1936 #endif {- alpha_TARGET_ARCH -}
1937 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1938 #if i386_TARGET_ARCH
1940 genJump (StInd pk mem)
1941 = getAmode mem `thenNat` \ amode ->
1943 code = amodeCode amode
1944 target = amodeAddr amode
1946 returnNat (code `snocOL` JMP (OpAddr target))
1950 = returnNat (unitOL (JMP (OpImm target)))
1953 = getRegister tree `thenNat` \ register ->
1954 getNewRegNCG PtrRep `thenNat` \ tmp ->
1956 code = registerCode register tmp
1957 target = registerName register tmp
1959 returnNat (code `snocOL` JMP (OpReg target))
1962 target = case imm of Just x -> x
1964 #endif {- i386_TARGET_ARCH -}
1965 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1966 #if sparc_TARGET_ARCH
1968 genJump (StCLbl lbl)
1969 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
1970 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
1972 target = ImmCLbl lbl
1975 = getRegister tree `thenNat` \ register ->
1976 getNewRegNCG PtrRep `thenNat` \ tmp ->
1978 code = registerCode register tmp
1979 target = registerName register tmp
1981 returnNat (code `snocOL` JMP (AddrRegReg target g0) `snocOL` NOP)
1983 #endif {- sparc_TARGET_ARCH -}
1986 %************************************************************************
1988 \subsection{Conditional jumps}
1990 %************************************************************************
1992 Conditional jumps are always to local labels, so we can use branch
1993 instructions. We peek at the arguments to decide what kind of
1996 ALPHA: For comparisons with 0, we're laughing, because we can just do
1997 the desired conditional branch.
1999 I386: First, we have to ensure that the condition
2000 codes are set according to the supplied comparison operation.
2002 SPARC: First, we have to ensure that the condition codes are set
2003 according to the supplied comparison operation. We generate slightly
2004 different code for floating point comparisons, because a floating
2005 point operation cannot directly precede a @BF@. We assume the worst
2006 and fill that slot with a @NOP@.
2008 SPARC: Do not fill the delay slots here; you will confuse the register
2013 :: CLabel -- the branch target
2014 -> StixTree -- the condition on which to branch
2017 #if alpha_TARGET_ARCH
2019 genCondJump lbl (StPrim op [x, StInt 0])
2020 = getRegister x `thenNat` \ register ->
2021 getNewRegNCG (registerRep register)
2024 code = registerCode register tmp
2025 value = registerName register tmp
2026 pk = registerRep register
2027 target = ImmCLbl lbl
2029 returnSeq code [BI (cmpOp op) value target]
2031 cmpOp CharGtOp = GTT
2033 cmpOp CharEqOp = EQQ
2035 cmpOp CharLtOp = LTT
2044 cmpOp WordGeOp = ALWAYS
2045 cmpOp WordEqOp = EQQ
2047 cmpOp WordLtOp = NEVER
2048 cmpOp WordLeOp = EQQ
2050 cmpOp AddrGeOp = ALWAYS
2051 cmpOp AddrEqOp = EQQ
2053 cmpOp AddrLtOp = NEVER
2054 cmpOp AddrLeOp = EQQ
2056 genCondJump lbl (StPrim op [x, StDouble 0.0])
2057 = getRegister x `thenNat` \ register ->
2058 getNewRegNCG (registerRep register)
2061 code = registerCode register tmp
2062 value = registerName register tmp
2063 pk = registerRep register
2064 target = ImmCLbl lbl
2066 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2068 cmpOp FloatGtOp = GTT
2069 cmpOp FloatGeOp = GE
2070 cmpOp FloatEqOp = EQQ
2071 cmpOp FloatNeOp = NE
2072 cmpOp FloatLtOp = LTT
2073 cmpOp FloatLeOp = LE
2074 cmpOp DoubleGtOp = GTT
2075 cmpOp DoubleGeOp = GE
2076 cmpOp DoubleEqOp = EQQ
2077 cmpOp DoubleNeOp = NE
2078 cmpOp DoubleLtOp = LTT
2079 cmpOp DoubleLeOp = LE
2081 genCondJump lbl (StPrim op [x, y])
2083 = trivialFCode pr instr x y `thenNat` \ register ->
2084 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2086 code = registerCode register tmp
2087 result = registerName register tmp
2088 target = ImmCLbl lbl
2090 returnNat (code . mkSeqInstr (BF cond result target))
2092 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2094 fltCmpOp op = case op of
2108 (instr, cond) = case op of
2109 FloatGtOp -> (FCMP TF LE, EQQ)
2110 FloatGeOp -> (FCMP TF LTT, EQQ)
2111 FloatEqOp -> (FCMP TF EQQ, NE)
2112 FloatNeOp -> (FCMP TF EQQ, EQQ)
2113 FloatLtOp -> (FCMP TF LTT, NE)
2114 FloatLeOp -> (FCMP TF LE, NE)
2115 DoubleGtOp -> (FCMP TF LE, EQQ)
2116 DoubleGeOp -> (FCMP TF LTT, EQQ)
2117 DoubleEqOp -> (FCMP TF EQQ, NE)
2118 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2119 DoubleLtOp -> (FCMP TF LTT, NE)
2120 DoubleLeOp -> (FCMP TF LE, NE)
2122 genCondJump lbl (StPrim op [x, y])
2123 = trivialCode instr x y `thenNat` \ register ->
2124 getNewRegNCG IntRep `thenNat` \ tmp ->
2126 code = registerCode register tmp
2127 result = registerName register tmp
2128 target = ImmCLbl lbl
2130 returnNat (code . mkSeqInstr (BI cond result target))
2132 (instr, cond) = case op of
2133 CharGtOp -> (CMP LE, EQQ)
2134 CharGeOp -> (CMP LTT, EQQ)
2135 CharEqOp -> (CMP EQQ, NE)
2136 CharNeOp -> (CMP EQQ, EQQ)
2137 CharLtOp -> (CMP LTT, NE)
2138 CharLeOp -> (CMP LE, NE)
2139 IntGtOp -> (CMP LE, EQQ)
2140 IntGeOp -> (CMP LTT, EQQ)
2141 IntEqOp -> (CMP EQQ, NE)
2142 IntNeOp -> (CMP EQQ, EQQ)
2143 IntLtOp -> (CMP LTT, NE)
2144 IntLeOp -> (CMP LE, NE)
2145 WordGtOp -> (CMP ULE, EQQ)
2146 WordGeOp -> (CMP ULT, EQQ)
2147 WordEqOp -> (CMP EQQ, NE)
2148 WordNeOp -> (CMP EQQ, EQQ)
2149 WordLtOp -> (CMP ULT, NE)
2150 WordLeOp -> (CMP ULE, NE)
2151 AddrGtOp -> (CMP ULE, EQQ)
2152 AddrGeOp -> (CMP ULT, EQQ)
2153 AddrEqOp -> (CMP EQQ, NE)
2154 AddrNeOp -> (CMP EQQ, EQQ)
2155 AddrLtOp -> (CMP ULT, NE)
2156 AddrLeOp -> (CMP ULE, NE)
2158 #endif {- alpha_TARGET_ARCH -}
2159 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2160 #if i386_TARGET_ARCH
2162 genCondJump lbl bool
2163 = getCondCode bool `thenNat` \ condition ->
2165 code = condCode condition
2166 cond = condName condition
2167 target = ImmCLbl lbl
2169 returnNat (code `snocOL` JXX cond lbl)
2171 #endif {- i386_TARGET_ARCH -}
2172 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2173 #if sparc_TARGET_ARCH
2175 genCondJump lbl bool
2176 = getCondCode bool `thenNat` \ condition ->
2178 code = condCode condition
2179 cond = condName condition
2180 target = ImmCLbl lbl
2185 if condFloat condition
2186 then [NOP, BF cond False target, NOP]
2187 else [BI cond False target, NOP]
2191 #endif {- sparc_TARGET_ARCH -}
2194 %************************************************************************
2196 \subsection{Generating C calls}
2198 %************************************************************************
2200 Now the biggest nightmare---calls. Most of the nastiness is buried in
2201 @get_arg@, which moves the arguments to the correct registers/stack
2202 locations. Apart from that, the code is easy.
2204 (If applicable) Do not fill the delay slots here; you will confuse the
2209 :: FAST_STRING -- function to call
2211 -> PrimRep -- type of the result
2212 -> [StixTree] -- arguments (of mixed type)
2215 #if alpha_TARGET_ARCH
2217 genCCall fn cconv kind args
2218 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2219 `thenNat` \ ((unused,_), argCode) ->
2221 nRegs = length allArgRegs - length unused
2222 code = asmSeqThen (map ($ []) argCode)
2225 LDA pv (AddrImm (ImmLab (ptext fn))),
2226 JSR ra (AddrReg pv) nRegs,
2227 LDGP gp (AddrReg ra)]
2229 ------------------------
2230 {- Try to get a value into a specific register (or registers) for
2231 a call. The first 6 arguments go into the appropriate
2232 argument register (separate registers for integer and floating
2233 point arguments, but used in lock-step), and the remaining
2234 arguments are dumped to the stack, beginning at 0(sp). Our
2235 first argument is a pair of the list of remaining argument
2236 registers to be assigned for this call and the next stack
2237 offset to use for overflowing arguments. This way,
2238 @get_Arg@ can be applied to all of a call's arguments using
2242 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2243 -> StixTree -- Current argument
2244 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2246 -- We have to use up all of our argument registers first...
2248 get_arg ((iDst,fDst):dsts, offset) arg
2249 = getRegister arg `thenNat` \ register ->
2251 reg = if isFloatingRep pk then fDst else iDst
2252 code = registerCode register reg
2253 src = registerName register reg
2254 pk = registerRep register
2257 if isFloatingRep pk then
2258 ((dsts, offset), if isFixed register then
2259 code . mkSeqInstr (FMOV src fDst)
2262 ((dsts, offset), if isFixed register then
2263 code . mkSeqInstr (OR src (RIReg src) iDst)
2266 -- Once we have run out of argument registers, we move to the
2269 get_arg ([], offset) arg
2270 = getRegister arg `thenNat` \ register ->
2271 getNewRegNCG (registerRep register)
2274 code = registerCode register tmp
2275 src = registerName register tmp
2276 pk = registerRep register
2277 sz = primRepToSize pk
2279 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2281 #endif {- alpha_TARGET_ARCH -}
2282 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2283 #if i386_TARGET_ARCH
2285 genCCall fn cconv kind [StInt i]
2286 | fn == SLIT ("PerformGC_wrapper")
2288 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2289 CALL (ImmLit (ptext (if underscorePrefix
2290 then (SLIT ("_PerformGC_wrapper"))
2291 else (SLIT ("PerformGC_wrapper")))))
2297 genCCall fn cconv kind args
2298 = mapNat get_call_arg
2299 (reverse args) `thenNat` \ sizes_n_codes ->
2300 getDeltaNat `thenNat` \ delta ->
2301 let (sizes, codes) = unzip sizes_n_codes
2302 tot_arg_size = sum sizes
2303 code2 = concatOL codes
2306 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2307 DELTA (delta + tot_arg_size)
2310 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2311 returnNat (code2 `appOL` call)
2314 -- function names that begin with '.' are assumed to be special
2315 -- internally generated names like '.mul,' which don't get an
2316 -- underscore prefix
2317 -- ToDo:needed (WDP 96/03) ???
2318 fn__2 = case (_HEAD_ fn) of
2319 '.' -> ImmLit (ptext fn)
2320 _ -> ImmLab (ptext fn)
2327 get_call_arg :: StixTree{-current argument-}
2328 -> NatM (Int, InstrBlock) -- argsz, code
2331 = get_op arg `thenNat` \ (code, reg, sz) ->
2332 getDeltaNat `thenNat` \ delta ->
2333 arg_size sz `bind` \ size ->
2334 setDeltaNat (delta-size) `thenNat` \ _ ->
2335 if (case sz of DF -> True; F -> True; _ -> False)
2336 then returnNat (size,
2338 toOL [SUB L (OpImm (ImmInt 8)) (OpReg esp),
2340 GST DF reg (AddrBaseIndex (Just esp)
2344 else returnNat (size,
2346 PUSH L (OpReg reg) `snocOL`
2352 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2355 = getRegister op `thenNat` \ register ->
2356 getNewRegNCG (registerRep register)
2359 code = registerCode register tmp
2360 reg = registerName register tmp
2361 pk = registerRep register
2362 sz = primRepToSize pk
2364 returnNat (code, reg, sz)
2366 #endif {- i386_TARGET_ARCH -}
2367 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2368 #if sparc_TARGET_ARCH
2370 genCCall fn cconv kind args
2371 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2372 `thenNat` \ ((unused,_), argCode) ->
2374 nRegs = length allArgRegs - length unused
2375 call = CALL fn__2 nRegs False
2376 code = concatOL argCode
2378 returnNat (code `snocOL` call `snocOL` NOP)
2380 -- function names that begin with '.' are assumed to be special
2381 -- internally generated names like '.mul,' which don't get an
2382 -- underscore prefix
2383 -- ToDo:needed (WDP 96/03) ???
2384 fn__2 = case (_HEAD_ fn) of
2385 '.' -> ImmLit (ptext fn)
2386 _ -> ImmLab (ptext fn)
2388 ------------------------------------
2389 {- Try to get a value into a specific register (or registers) for
2390 a call. The SPARC calling convention is an absolute
2391 nightmare. The first 6x32 bits of arguments are mapped into
2392 %o0 through %o5, and the remaining arguments are dumped to the
2393 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2394 first argument is a pair of the list of remaining argument
2395 registers to be assigned for this call and the next stack
2396 offset to use for overflowing arguments. This way,
2397 @get_arg@ can be applied to all of a call's arguments using
2401 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2402 -> StixTree -- Current argument
2403 -> NatM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2405 -- We have to use up all of our argument registers first...
2407 get_arg (dst:dsts, offset) arg
2408 = getRegister arg `thenNat` \ register ->
2409 getNewRegNCG (registerRep register)
2412 reg = if isFloatingRep pk then tmp else dst
2413 code = registerCode register reg
2414 src = registerName register reg
2415 pk = registerRep register
2421 [] -> ( ([], offset + 1),
2423 -- conveniently put the second part in the right stack
2424 -- location, and load the first part into %o5
2425 ST DF src (spRel (offset - 1)) `snocOL`
2426 LD W (spRel (offset - 1)) dst
2429 -> ( (dsts__2, offset),
2431 ST DF src (spRel (-2)) `snocOL`
2432 LD W (spRel (-2)) dst `snocOL`
2433 LD W (spRel (-1)) dst__2
2436 -> ( (dsts, offset),
2438 ST F src (spRel (-2)) `snocOL`
2439 LD W (spRel (-2)) dst
2441 _ -> ( (dsts, offset),
2443 then code `snocOL` OR False g0 (RIReg src) dst
2447 -- Once we have run out of argument registers, we move to the
2450 get_arg ([], offset) arg
2451 = getRegister arg `thenNat` \ register ->
2452 getNewRegNCG (registerRep register)
2455 code = registerCode register tmp
2456 src = registerName register tmp
2457 pk = registerRep register
2458 sz = primRepToSize pk
2459 words = if pk == DoubleRep then 2 else 1
2461 returnNat ( ([], offset + words),
2462 code `snocOL` ST sz src (spRel offset) )
2464 #endif {- sparc_TARGET_ARCH -}
2467 %************************************************************************
2469 \subsection{Support bits}
2471 %************************************************************************
2473 %************************************************************************
2475 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2477 %************************************************************************
2479 Turn those condition codes into integers now (when they appear on
2480 the right hand side of an assignment).
2482 (If applicable) Do not fill the delay slots here; you will confuse the
2486 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> NatM Register
2488 #if alpha_TARGET_ARCH
2489 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2490 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2491 #endif {- alpha_TARGET_ARCH -}
2493 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2494 #if i386_TARGET_ARCH
2497 = condIntCode cond x y `thenNat` \ condition ->
2498 getNewRegNCG IntRep `thenNat` \ tmp ->
2500 code = condCode condition
2501 cond = condName condition
2502 code__2 dst = code `appOL` toOL [
2503 SETCC cond (OpReg tmp),
2504 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2505 MOV L (OpReg tmp) (OpReg dst)]
2507 returnNat (Any IntRep code__2)
2510 = getNatLabelNCG `thenNat` \ lbl1 ->
2511 getNatLabelNCG `thenNat` \ lbl2 ->
2512 condFltCode cond x y `thenNat` \ condition ->
2514 code = condCode condition
2515 cond = condName condition
2516 code__2 dst = code `appOL` toOL [
2518 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2521 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2524 returnNat (Any IntRep code__2)
2526 #endif {- i386_TARGET_ARCH -}
2527 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2528 #if sparc_TARGET_ARCH
2530 condIntReg EQQ x (StInt 0)
2531 = getRegister x `thenNat` \ register ->
2532 getNewRegNCG IntRep `thenNat` \ tmp ->
2534 code = registerCode register tmp
2535 src = registerName register tmp
2536 code__2 dst = code `appOL` toOL [
2537 SUB False True g0 (RIReg src) g0,
2538 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2540 returnNat (Any IntRep code__2)
2543 = getRegister x `thenNat` \ register1 ->
2544 getRegister y `thenNat` \ register2 ->
2545 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2546 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2548 code1 = registerCode register1 tmp1
2549 src1 = registerName register1 tmp1
2550 code2 = registerCode register2 tmp2
2551 src2 = registerName register2 tmp2
2552 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2553 XOR False src1 (RIReg src2) dst,
2554 SUB False True g0 (RIReg dst) g0,
2555 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2557 returnNat (Any IntRep code__2)
2559 condIntReg NE x (StInt 0)
2560 = getRegister x `thenNat` \ register ->
2561 getNewRegNCG IntRep `thenNat` \ tmp ->
2563 code = registerCode register tmp
2564 src = registerName register tmp
2565 code__2 dst = code `appOL` toOL [
2566 SUB False True g0 (RIReg src) g0,
2567 ADD True False g0 (RIImm (ImmInt 0)) dst]
2569 returnNat (Any IntRep code__2)
2572 = getRegister x `thenNat` \ register1 ->
2573 getRegister y `thenNat` \ register2 ->
2574 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2575 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2577 code1 = registerCode register1 tmp1
2578 src1 = registerName register1 tmp1
2579 code2 = registerCode register2 tmp2
2580 src2 = registerName register2 tmp2
2581 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2582 XOR False src1 (RIReg src2) dst,
2583 SUB False True g0 (RIReg dst) g0,
2584 ADD True False g0 (RIImm (ImmInt 0)) dst]
2586 returnNat (Any IntRep code__2)
2589 = getNatLabelNCG `thenNat` \ lbl1 ->
2590 getNatLabelNCG `thenNat` \ lbl2 ->
2591 condIntCode cond x y `thenNat` \ condition ->
2593 code = condCode condition
2594 cond = condName condition
2595 code__2 dst = code `appOL` toOL [
2596 BI cond False (ImmCLbl lbl1), NOP,
2597 OR False g0 (RIImm (ImmInt 0)) dst,
2598 BI ALWAYS False (ImmCLbl lbl2), NOP,
2600 OR False g0 (RIImm (ImmInt 1)) dst,
2603 returnNat (Any IntRep code__2)
2606 = getNatLabelNCG `thenNat` \ lbl1 ->
2607 getNatLabelNCG `thenNat` \ lbl2 ->
2608 condFltCode cond x y `thenNat` \ condition ->
2610 code = condCode condition
2611 cond = condName condition
2612 code__2 dst = code `appOL` toOL [
2614 BF cond False (ImmCLbl lbl1), NOP,
2615 OR False g0 (RIImm (ImmInt 0)) dst,
2616 BI ALWAYS False (ImmCLbl lbl2), NOP,
2618 OR False g0 (RIImm (ImmInt 1)) dst,
2621 returnNat (Any IntRep code__2)
2623 #endif {- sparc_TARGET_ARCH -}
2626 %************************************************************************
2628 \subsubsection{@trivial*Code@: deal with trivial instructions}
2630 %************************************************************************
2632 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2633 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2634 for constants on the right hand side, because that's where the generic
2635 optimizer will have put them.
2637 Similarly, for unary instructions, we don't have to worry about
2638 matching an StInt as the argument, because genericOpt will already
2639 have handled the constant-folding.
2643 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2644 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2645 -> Maybe (Operand -> Operand -> Instr)
2646 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2648 -> StixTree -> StixTree -- the two arguments
2653 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2654 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2655 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2657 -> StixTree -> StixTree -- the two arguments
2661 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2662 ,IF_ARCH_i386 ((Operand -> Instr)
2663 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2665 -> StixTree -- the one argument
2670 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2671 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2672 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2674 -> StixTree -- the one argument
2677 #if alpha_TARGET_ARCH
2679 trivialCode instr x (StInt y)
2681 = getRegister x `thenNat` \ register ->
2682 getNewRegNCG IntRep `thenNat` \ tmp ->
2684 code = registerCode register tmp
2685 src1 = registerName register tmp
2686 src2 = ImmInt (fromInteger y)
2687 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2689 returnNat (Any IntRep code__2)
2691 trivialCode instr x y
2692 = getRegister x `thenNat` \ register1 ->
2693 getRegister y `thenNat` \ register2 ->
2694 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2695 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2697 code1 = registerCode register1 tmp1 []
2698 src1 = registerName register1 tmp1
2699 code2 = registerCode register2 tmp2 []
2700 src2 = registerName register2 tmp2
2701 code__2 dst = asmSeqThen [code1, code2] .
2702 mkSeqInstr (instr src1 (RIReg src2) dst)
2704 returnNat (Any IntRep code__2)
2707 trivialUCode instr x
2708 = getRegister x `thenNat` \ register ->
2709 getNewRegNCG IntRep `thenNat` \ tmp ->
2711 code = registerCode register tmp
2712 src = registerName register tmp
2713 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2715 returnNat (Any IntRep code__2)
2718 trivialFCode _ instr x y
2719 = getRegister x `thenNat` \ register1 ->
2720 getRegister y `thenNat` \ register2 ->
2721 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2722 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2724 code1 = registerCode register1 tmp1
2725 src1 = registerName register1 tmp1
2727 code2 = registerCode register2 tmp2
2728 src2 = registerName register2 tmp2
2730 code__2 dst = asmSeqThen [code1 [], code2 []] .
2731 mkSeqInstr (instr src1 src2 dst)
2733 returnNat (Any DoubleRep code__2)
2735 trivialUFCode _ instr x
2736 = getRegister x `thenNat` \ register ->
2737 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2739 code = registerCode register tmp
2740 src = registerName register tmp
2741 code__2 dst = code . mkSeqInstr (instr src dst)
2743 returnNat (Any DoubleRep code__2)
2745 #endif {- alpha_TARGET_ARCH -}
2746 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2747 #if i386_TARGET_ARCH
2749 The Rules of the Game are:
2751 * You cannot assume anything about the destination register dst;
2752 it may be anything, including a fixed reg.
2754 * You may compute an operand into a fixed reg, but you may not
2755 subsequently change the contents of that fixed reg. If you
2756 want to do so, first copy the value either to a temporary
2757 or into dst. You are free to modify dst even if it happens
2758 to be a fixed reg -- that's not your problem.
2760 * You cannot assume that a fixed reg will stay live over an
2761 arbitrary computation. The same applies to the dst reg.
2763 * Temporary regs obtained from getNewRegNCG are distinct from
2764 each other and from all other regs, and stay live over
2765 arbitrary computations.
2769 trivialCode instr maybe_revinstr a b
2772 = getRegister a `thenNat` \ rega ->
2775 then registerCode rega dst `bind` \ code_a ->
2777 instr (OpImm imm_b) (OpReg dst)
2778 else registerCodeF rega `bind` \ code_a ->
2779 registerNameF rega `bind` \ r_a ->
2781 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2782 instr (OpImm imm_b) (OpReg dst)
2784 returnNat (Any IntRep mkcode)
2787 = getRegister b `thenNat` \ regb ->
2788 getNewRegNCG IntRep `thenNat` \ tmp ->
2789 let revinstr_avail = maybeToBool maybe_revinstr
2790 revinstr = case maybe_revinstr of Just ri -> ri
2794 then registerCode regb dst `bind` \ code_b ->
2796 revinstr (OpImm imm_a) (OpReg dst)
2797 else registerCodeF regb `bind` \ code_b ->
2798 registerNameF regb `bind` \ r_b ->
2800 MOV L (OpReg r_b) (OpReg dst) `snocOL`
2801 revinstr (OpImm imm_a) (OpReg dst)
2805 then registerCode regb tmp `bind` \ code_b ->
2807 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2808 instr (OpReg tmp) (OpReg dst)
2809 else registerCodeF regb `bind` \ code_b ->
2810 registerNameF regb `bind` \ r_b ->
2812 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
2813 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2814 instr (OpReg tmp) (OpReg dst)
2816 returnNat (Any IntRep mkcode)
2819 = getRegister a `thenNat` \ rega ->
2820 getRegister b `thenNat` \ regb ->
2821 getNewRegNCG IntRep `thenNat` \ tmp ->
2823 = case (isAny rega, isAny regb) of
2825 -> registerCode regb tmp `bind` \ code_b ->
2826 registerCode rega dst `bind` \ code_a ->
2829 instr (OpReg tmp) (OpReg dst)
2831 -> registerCode rega tmp `bind` \ code_a ->
2832 registerCodeF regb `bind` \ code_b ->
2833 registerNameF regb `bind` \ r_b ->
2836 instr (OpReg r_b) (OpReg tmp) `snocOL`
2837 MOV L (OpReg tmp) (OpReg dst)
2839 -> registerCode regb tmp `bind` \ code_b ->
2840 registerCodeF rega `bind` \ code_a ->
2841 registerNameF rega `bind` \ r_a ->
2844 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2845 instr (OpReg tmp) (OpReg dst)
2847 -> registerCodeF rega `bind` \ code_a ->
2848 registerNameF rega `bind` \ r_a ->
2849 registerCodeF regb `bind` \ code_b ->
2850 registerNameF regb `bind` \ r_b ->
2852 MOV L (OpReg r_a) (OpReg tmp) `appOL`
2854 instr (OpReg r_b) (OpReg tmp) `snocOL`
2855 MOV L (OpReg tmp) (OpReg dst)
2857 returnNat (Any IntRep mkcode)
2860 maybe_imm_a = maybeImm a
2861 is_imm_a = maybeToBool maybe_imm_a
2862 imm_a = case maybe_imm_a of Just imm -> imm
2864 maybe_imm_b = maybeImm b
2865 is_imm_b = maybeToBool maybe_imm_b
2866 imm_b = case maybe_imm_b of Just imm -> imm
2870 trivialUCode instr x
2871 = getRegister x `thenNat` \ register ->
2873 code__2 dst = let code = registerCode register dst
2874 src = registerName register dst
2876 if isFixed register && dst /= src
2877 then toOL [MOV L (OpReg src) (OpReg dst),
2879 else unitOL (instr (OpReg src))
2881 returnNat (Any IntRep code__2)
2884 trivialFCode pk instr x y
2885 = getRegister x `thenNat` \ register1 ->
2886 getRegister y `thenNat` \ register2 ->
2887 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2888 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2890 code1 = registerCode register1 tmp1
2891 src1 = registerName register1 tmp1
2893 code2 = registerCode register2 tmp2
2894 src2 = registerName register2 tmp2
2897 -- treat the common case specially: both operands in
2899 | isAny register1 && isAny register2
2902 instr (primRepToSize pk) src1 src2 dst
2904 -- be paranoid (and inefficient)
2906 = code1 `snocOL` GMOV src1 tmp1 `appOL`
2908 instr (primRepToSize pk) tmp1 src2 dst
2910 returnNat (Any DoubleRep code__2)
2914 trivialUFCode pk instr x
2915 = getRegister x `thenNat` \ register ->
2916 getNewRegNCG pk `thenNat` \ tmp ->
2918 code = registerCode register tmp
2919 src = registerName register tmp
2920 code__2 dst = code `snocOL` instr src dst
2922 returnNat (Any pk code__2)
2924 #endif {- i386_TARGET_ARCH -}
2925 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2926 #if sparc_TARGET_ARCH
2928 trivialCode instr x (StInt y)
2930 = getRegister x `thenNat` \ register ->
2931 getNewRegNCG IntRep `thenNat` \ tmp ->
2933 code = registerCode register tmp
2934 src1 = registerName register tmp
2935 src2 = ImmInt (fromInteger y)
2936 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
2938 returnNat (Any IntRep code__2)
2940 trivialCode instr x y
2941 = getRegister x `thenNat` \ register1 ->
2942 getRegister y `thenNat` \ register2 ->
2943 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2944 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2946 code1 = registerCode register1 tmp1
2947 src1 = registerName register1 tmp1
2948 code2 = registerCode register2 tmp2
2949 src2 = registerName register2 tmp2
2950 code__2 dst = code1 `appOL` code2 `snocOL`
2951 instr src1 (RIReg src2) dst
2953 returnNat (Any IntRep code__2)
2956 trivialFCode pk instr x y
2957 = getRegister x `thenNat` \ register1 ->
2958 getRegister y `thenNat` \ register2 ->
2959 getNewRegNCG (registerRep register1)
2961 getNewRegNCG (registerRep register2)
2963 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2965 promote x = FxTOy F DF x tmp
2967 pk1 = registerRep register1
2968 code1 = registerCode register1 tmp1
2969 src1 = registerName register1 tmp1
2971 pk2 = registerRep register2
2972 code2 = registerCode register2 tmp2
2973 src2 = registerName register2 tmp2
2977 code1 `appOL` code2 `snocOL`
2978 instr (primRepToSize pk) src1 src2 dst
2979 else if pk1 == FloatRep then
2980 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
2981 instr DF tmp src2 dst
2983 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
2984 instr DF src1 tmp dst
2986 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2989 trivialUCode instr x
2990 = getRegister x `thenNat` \ register ->
2991 getNewRegNCG IntRep `thenNat` \ tmp ->
2993 code = registerCode register tmp
2994 src = registerName register tmp
2995 code__2 dst = code `snocOL` instr (RIReg src) dst
2997 returnNat (Any IntRep code__2)
3000 trivialUFCode pk instr x
3001 = getRegister x `thenNat` \ register ->
3002 getNewRegNCG pk `thenNat` \ tmp ->
3004 code = registerCode register tmp
3005 src = registerName register tmp
3006 code__2 dst = code `snocOL` instr src dst
3008 returnNat (Any pk code__2)
3010 #endif {- sparc_TARGET_ARCH -}
3013 %************************************************************************
3015 \subsubsection{Coercing to/from integer/floating-point...}
3017 %************************************************************************
3019 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3020 to be generated. Here we just change the type on the Register passed
3021 on up. The code is machine-independent.
3023 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3024 conversions. We have to store temporaries in memory to move
3025 between the integer and the floating point register sets.
3028 coerceIntCode :: PrimRep -> StixTree -> NatM Register
3029 coerceFltCode :: StixTree -> NatM Register
3031 coerceInt2FP :: PrimRep -> StixTree -> NatM Register
3032 coerceFP2Int :: StixTree -> NatM Register
3035 = getRegister x `thenNat` \ register ->
3038 Fixed _ reg code -> Fixed pk reg code
3039 Any _ code -> Any pk code
3044 = getRegister x `thenNat` \ register ->
3047 Fixed _ reg code -> Fixed DoubleRep reg code
3048 Any _ code -> Any DoubleRep code
3053 #if alpha_TARGET_ARCH
3056 = getRegister x `thenNat` \ register ->
3057 getNewRegNCG IntRep `thenNat` \ reg ->
3059 code = registerCode register reg
3060 src = registerName register reg
3062 code__2 dst = code . mkSeqInstrs [
3064 LD TF dst (spRel 0),
3067 returnNat (Any DoubleRep code__2)
3071 = getRegister x `thenNat` \ register ->
3072 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3074 code = registerCode register tmp
3075 src = registerName register tmp
3077 code__2 dst = code . mkSeqInstrs [
3079 ST TF tmp (spRel 0),
3082 returnNat (Any IntRep code__2)
3084 #endif {- alpha_TARGET_ARCH -}
3085 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3086 #if i386_TARGET_ARCH
3089 = getRegister x `thenNat` \ register ->
3090 getNewRegNCG IntRep `thenNat` \ reg ->
3092 code = registerCode register reg
3093 src = registerName register reg
3094 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3095 code__2 dst = code `snocOL` opc src dst
3097 returnNat (Any pk code__2)
3101 = getRegister x `thenNat` \ register ->
3102 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3104 code = registerCode register tmp
3105 src = registerName register tmp
3106 pk = registerRep register
3108 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3109 code__2 dst = code `snocOL` opc src dst
3111 returnNat (Any IntRep code__2)
3113 #endif {- i386_TARGET_ARCH -}
3114 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3115 #if sparc_TARGET_ARCH
3118 = getRegister x `thenNat` \ register ->
3119 getNewRegNCG IntRep `thenNat` \ reg ->
3121 code = registerCode register reg
3122 src = registerName register reg
3124 code__2 dst = code `appOL` toOL [
3125 ST W src (spRel (-2)),
3126 LD W (spRel (-2)) dst,
3127 FxTOy W (primRepToSize pk) dst dst]
3129 returnNat (Any pk code__2)
3133 = getRegister x `thenNat` \ register ->
3134 getNewRegNCG IntRep `thenNat` \ reg ->
3135 getNewRegNCG FloatRep `thenNat` \ tmp ->
3137 code = registerCode register reg
3138 src = registerName register reg
3139 pk = registerRep register
3141 code__2 dst = code `appOL` toOL [
3142 FxTOy (primRepToSize pk) W src tmp,
3143 ST W tmp (spRel (-2)),
3144 LD W (spRel (-2)) dst]
3146 returnNat (Any IntRep code__2)
3148 #endif {- sparc_TARGET_ARCH -}
3151 %************************************************************************
3153 \subsubsection{Coercing integer to @Char@...}
3155 %************************************************************************
3157 Integer to character conversion. Where applicable, we try to do this
3158 in one step if the original object is in memory.
3161 chrCode :: StixTree -> NatM Register
3163 #if alpha_TARGET_ARCH
3166 = getRegister x `thenNat` \ register ->
3167 getNewRegNCG IntRep `thenNat` \ reg ->
3169 code = registerCode register reg
3170 src = registerName register reg
3171 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3173 returnNat (Any IntRep code__2)
3175 #endif {- alpha_TARGET_ARCH -}
3176 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3177 #if i386_TARGET_ARCH
3180 = getRegister x `thenNat` \ register ->
3183 code = registerCode register dst
3184 src = registerName register dst
3186 if isFixed register && src /= dst
3187 then toOL [MOV L (OpReg src) (OpReg dst),
3188 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3189 else unitOL (AND L (OpImm (ImmInt 255)) (OpReg src))
3191 returnNat (Any IntRep code__2)
3193 #endif {- i386_TARGET_ARCH -}
3194 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3195 #if sparc_TARGET_ARCH
3197 chrCode (StInd pk mem)
3198 = getAmode mem `thenNat` \ amode ->
3200 code = amodeCode amode
3201 src = amodeAddr amode
3202 src_off = addrOffset src 3
3203 src__2 = case src_off of Just x -> x
3204 code__2 dst = if maybeToBool src_off then
3205 code `snocOL` LD BU src__2 dst
3208 LD (primRepToSize pk) src dst `snocOL`
3209 AND False dst (RIImm (ImmInt 255)) dst
3211 returnNat (Any pk code__2)
3214 = getRegister x `thenNat` \ register ->
3215 getNewRegNCG IntRep `thenNat` \ reg ->
3217 code = registerCode register reg
3218 src = registerName register reg
3219 code__2 dst = code `snocOL` AND False src (RIImm (ImmInt 255)) dst
3221 returnNat (Any IntRep code__2)
3223 #endif {- sparc_TARGET_ARCH -}