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)),
68 StLabel lab -> returnNat (unitOL (LABEL lab))
70 StJump arg -> genJump arg
71 StCondJump lab arg -> genCondJump lab arg
72 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
75 | isFloatingRep pk -> assignFltCode pk dst src
76 | otherwise -> assignIntCode pk dst src
79 -- When falling through on the Alpha, we still have to load pv
80 -- with the address of the next routine, so that it can load gp.
81 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
85 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
86 returnNat (DATA (primRepToSize kind) imms
87 `consOL` concatOL codes)
89 getData :: StixTree -> NatM (InstrBlock, Imm)
91 getData (StInt i) = returnNat (nilOL, ImmInteger i)
92 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
93 getData (StLitLbl s) = returnNat (nilOL, ImmLab s)
94 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
95 getData (StString s) =
96 getNatLabelNCG `thenNat` \ lbl ->
97 returnNat (toOL [LABEL lbl,
98 ASCII True (_UNPK_ s)],
100 -- the linker can handle simple arithmetic...
101 getData (StIndex rep (StCLbl lbl) (StInt off)) =
103 ImmIndex lbl (fromInteger (off * sizeOf rep)))
106 %************************************************************************
108 \subsection{General things for putting together code sequences}
110 %************************************************************************
113 mangleIndexTree :: StixTree -> StixTree
115 mangleIndexTree (StIndex pk base (StInt i))
116 = StPrim IntAddOp [base, off]
118 off = StInt (i * sizeOf pk)
120 mangleIndexTree (StIndex pk base off)
124 in ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
125 if s == 0 then off else StPrim SllOp [off, StInt s]
128 shift DoubleRep = 3::Integer
129 shift CharRep = 0::Integer
130 shift _ = IF_ARCH_alpha(3,2)
134 maybeImm :: StixTree -> Maybe Imm
136 maybeImm (StLitLbl s) = Just (ImmLab s)
137 maybeImm (StCLbl l) = Just (ImmCLbl l)
139 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
140 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
143 | i >= toInteger minInt && i <= toInteger maxInt
144 = Just (ImmInt (fromInteger i))
146 = Just (ImmInteger i)
151 %************************************************************************
153 \subsection{The @Register@ type}
155 %************************************************************************
157 @Register@s passed up the tree. If the stix code forces the register
158 to live in a pre-decided machine register, it comes out as @Fixed@;
159 otherwise, it comes out as @Any@, and the parent can decide which
160 register to put it in.
164 = Fixed PrimRep Reg InstrBlock
165 | Any PrimRep (Reg -> InstrBlock)
167 registerCode :: Register -> Reg -> InstrBlock
168 registerCode (Fixed _ _ code) reg = code
169 registerCode (Any _ code) reg = code reg
171 registerCodeF (Fixed _ _ code) = code
172 registerCodeF (Any _ _) = pprPanic "registerCodeF" empty
174 registerCodeA (Any _ code) = code
175 registerCodeA (Fixed _ _ _) = pprPanic "registerCodeA" empty
177 registerName :: Register -> Reg -> Reg
178 registerName (Fixed _ reg _) _ = reg
179 registerName (Any _ _) reg = reg
181 registerNameF (Fixed _ reg _) = reg
182 registerNameF (Any _ _) = pprPanic "registerNameF" empty
184 registerRep :: Register -> PrimRep
185 registerRep (Fixed pk _ _) = pk
186 registerRep (Any pk _) = pk
188 {-# INLINE registerCode #-}
189 {-# INLINE registerCodeF #-}
190 {-# INLINE registerName #-}
191 {-# INLINE registerNameF #-}
192 {-# INLINE registerRep #-}
193 {-# INLINE isFixed #-}
196 isFixed, isAny :: Register -> Bool
197 isFixed (Fixed _ _ _) = True
198 isFixed (Any _ _) = False
200 isAny = not . isFixed
203 Generate code to get a subtree into a @Register@:
205 getRegister :: StixTree -> NatM Register
207 getRegister (StReg (StixMagicId stgreg))
208 = case (magicIdRegMaybe stgreg) of
209 Just reg -> returnNat (Fixed (magicIdPrimRep stgreg) reg nilOL)
212 getRegister (StReg (StixTemp u pk))
213 = returnNat (Fixed pk (UnmappedReg u pk) nilOL)
215 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
217 getRegister (StCall fn cconv kind args)
218 = genCCall fn cconv kind args `thenNat` \ call ->
219 returnNat (Fixed kind reg call)
221 reg = if isFloatingRep kind
222 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
223 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
225 getRegister (StString s)
226 = getNatLabelNCG `thenNat` \ lbl ->
228 imm_lbl = ImmCLbl lbl
233 ASCII True (_UNPK_ s),
235 #if alpha_TARGET_ARCH
236 LDA dst (AddrImm imm_lbl)
239 MOV L (OpImm imm_lbl) (OpReg dst)
241 #if sparc_TARGET_ARCH
242 SETHI (HI imm_lbl) dst,
243 OR False dst (RIImm (LO imm_lbl)) dst
247 returnNat (Any PtrRep code)
251 -- end of machine-"independent" bit; here we go on the rest...
253 #if alpha_TARGET_ARCH
255 getRegister (StDouble d)
256 = getNatLabelNCG `thenNat` \ lbl ->
257 getNewRegNCG PtrRep `thenNat` \ tmp ->
258 let code dst = mkSeqInstrs [
261 DATA TF [ImmLab (rational d)],
263 LDA tmp (AddrImm (ImmCLbl lbl)),
264 LD TF dst (AddrReg tmp)]
266 returnNat (Any DoubleRep code)
268 getRegister (StPrim primop [x]) -- unary PrimOps
270 IntNegOp -> trivialUCode (NEG Q False) x
272 NotOp -> trivialUCode NOT x
274 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
275 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
277 OrdOp -> coerceIntCode IntRep x
280 Float2IntOp -> coerceFP2Int x
281 Int2FloatOp -> coerceInt2FP pr x
282 Double2IntOp -> coerceFP2Int x
283 Int2DoubleOp -> coerceInt2FP pr x
285 Double2FloatOp -> coerceFltCode x
286 Float2DoubleOp -> coerceFltCode x
288 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
290 fn = case other_op of
291 FloatExpOp -> SLIT("exp")
292 FloatLogOp -> SLIT("log")
293 FloatSqrtOp -> SLIT("sqrt")
294 FloatSinOp -> SLIT("sin")
295 FloatCosOp -> SLIT("cos")
296 FloatTanOp -> SLIT("tan")
297 FloatAsinOp -> SLIT("asin")
298 FloatAcosOp -> SLIT("acos")
299 FloatAtanOp -> SLIT("atan")
300 FloatSinhOp -> SLIT("sinh")
301 FloatCoshOp -> SLIT("cosh")
302 FloatTanhOp -> SLIT("tanh")
303 DoubleExpOp -> SLIT("exp")
304 DoubleLogOp -> SLIT("log")
305 DoubleSqrtOp -> SLIT("sqrt")
306 DoubleSinOp -> SLIT("sin")
307 DoubleCosOp -> SLIT("cos")
308 DoubleTanOp -> SLIT("tan")
309 DoubleAsinOp -> SLIT("asin")
310 DoubleAcosOp -> SLIT("acos")
311 DoubleAtanOp -> SLIT("atan")
312 DoubleSinhOp -> SLIT("sinh")
313 DoubleCoshOp -> SLIT("cosh")
314 DoubleTanhOp -> SLIT("tanh")
316 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
318 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
320 CharGtOp -> trivialCode (CMP LTT) y x
321 CharGeOp -> trivialCode (CMP LE) y x
322 CharEqOp -> trivialCode (CMP EQQ) x y
323 CharNeOp -> int_NE_code x y
324 CharLtOp -> trivialCode (CMP LTT) x y
325 CharLeOp -> trivialCode (CMP LE) x y
327 IntGtOp -> trivialCode (CMP LTT) y x
328 IntGeOp -> trivialCode (CMP LE) y x
329 IntEqOp -> trivialCode (CMP EQQ) x y
330 IntNeOp -> int_NE_code x y
331 IntLtOp -> trivialCode (CMP LTT) x y
332 IntLeOp -> trivialCode (CMP LE) x y
334 WordGtOp -> trivialCode (CMP ULT) y x
335 WordGeOp -> trivialCode (CMP ULE) x y
336 WordEqOp -> trivialCode (CMP EQQ) x y
337 WordNeOp -> int_NE_code x y
338 WordLtOp -> trivialCode (CMP ULT) x y
339 WordLeOp -> trivialCode (CMP ULE) x y
341 AddrGtOp -> trivialCode (CMP ULT) y x
342 AddrGeOp -> trivialCode (CMP ULE) y x
343 AddrEqOp -> trivialCode (CMP EQQ) x y
344 AddrNeOp -> int_NE_code x y
345 AddrLtOp -> trivialCode (CMP ULT) x y
346 AddrLeOp -> trivialCode (CMP ULE) x y
348 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
349 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
350 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
351 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
352 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
353 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
355 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
356 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
357 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
358 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
359 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
360 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
362 IntAddOp -> trivialCode (ADD Q False) x y
363 IntSubOp -> trivialCode (SUB Q False) x y
364 IntMulOp -> trivialCode (MUL Q False) x y
365 IntQuotOp -> trivialCode (DIV Q False) x y
366 IntRemOp -> trivialCode (REM Q False) x y
368 WordQuotOp -> trivialCode (DIV Q True) x y
369 WordRemOp -> trivialCode (REM Q True) x y
371 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
372 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
373 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
374 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
376 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
377 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
378 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
379 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
381 AndOp -> trivialCode AND x y
382 OrOp -> trivialCode OR x y
383 XorOp -> trivialCode XOR x y
384 SllOp -> trivialCode SLL x y
385 SrlOp -> trivialCode SRL x y
387 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
388 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
389 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
391 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
392 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
394 {- ------------------------------------------------------------
395 Some bizarre special code for getting condition codes into
396 registers. Integer non-equality is a test for equality
397 followed by an XOR with 1. (Integer comparisons always set
398 the result register to 0 or 1.) Floating point comparisons of
399 any kind leave the result in a floating point register, so we
400 need to wrangle an integer register out of things.
402 int_NE_code :: StixTree -> StixTree -> NatM Register
405 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
406 getNewRegNCG IntRep `thenNat` \ tmp ->
408 code = registerCode register tmp
409 src = registerName register tmp
410 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
412 returnNat (Any IntRep code__2)
414 {- ------------------------------------------------------------
415 Comments for int_NE_code also apply to cmpF_code
418 :: (Reg -> Reg -> Reg -> Instr)
420 -> StixTree -> StixTree
423 cmpF_code instr cond x y
424 = trivialFCode pr instr x y `thenNat` \ register ->
425 getNewRegNCG DoubleRep `thenNat` \ tmp ->
426 getNatLabelNCG `thenNat` \ lbl ->
428 code = registerCode register tmp
429 result = registerName register tmp
431 code__2 dst = code . mkSeqInstrs [
432 OR zeroh (RIImm (ImmInt 1)) dst,
433 BF cond result (ImmCLbl lbl),
434 OR zeroh (RIReg zeroh) dst,
437 returnNat (Any IntRep code__2)
439 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
440 ------------------------------------------------------------
442 getRegister (StInd pk mem)
443 = getAmode mem `thenNat` \ amode ->
445 code = amodeCode amode
446 src = amodeAddr amode
447 size = primRepToSize pk
448 code__2 dst = code . mkSeqInstr (LD size dst src)
450 returnNat (Any pk code__2)
452 getRegister (StInt i)
455 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
457 returnNat (Any IntRep code)
460 code dst = mkSeqInstr (LDI Q dst src)
462 returnNat (Any IntRep code)
464 src = ImmInt (fromInteger i)
469 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
471 returnNat (Any PtrRep code)
474 imm__2 = case imm of Just x -> x
476 #endif {- alpha_TARGET_ARCH -}
477 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
480 getRegister (StDouble d)
483 = let code dst = unitOL (GLDZ dst)
484 in trace "nativeGen: GLDZ"
485 (returnNat (Any DoubleRep code))
488 = let code dst = unitOL (GLD1 dst)
489 in trace "nativeGen: GLD1"
490 returnNat (Any DoubleRep code)
493 = getNatLabelNCG `thenNat` \ lbl ->
494 let code dst = toOL [
497 DATA DF [ImmDouble d],
499 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
502 returnNat (Any DoubleRep code)
504 -- Calculate the offset for (i+1) words above the _initial_
505 -- %esp value by first determining the current offset of it.
506 getRegister (StScratchWord i)
508 = getDeltaNat `thenNat` \ current_stack_offset ->
509 let j = i+1 - (current_stack_offset `div` 4)
511 = unitOL (LEA L (OpAddr (spRel (j+1))) (OpReg dst))
513 returnNat (Any PtrRep code)
515 getRegister (StPrim primop [x]) -- unary PrimOps
517 IntNegOp -> trivialUCode (NEGI L) x
518 NotOp -> trivialUCode (NOT L) x
520 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
521 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
523 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
524 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
526 FloatSinOp -> trivialUFCode FloatRep (GSIN F) x
527 DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
529 FloatCosOp -> trivialUFCode FloatRep (GCOS F) x
530 DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
532 FloatTanOp -> trivialUFCode FloatRep (GTAN F) x
533 DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
535 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
536 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
538 OrdOp -> coerceIntCode IntRep x
541 Float2IntOp -> coerceFP2Int x
542 Int2FloatOp -> coerceInt2FP FloatRep x
543 Double2IntOp -> coerceFP2Int x
544 Int2DoubleOp -> coerceInt2FP DoubleRep x
548 fixed_x = if is_float_op -- promote to double
549 then StPrim Float2DoubleOp [x]
552 getRegister (StCall fn cCallConv DoubleRep [x])
556 FloatExpOp -> (True, SLIT("exp"))
557 FloatLogOp -> (True, SLIT("log"))
559 FloatAsinOp -> (True, SLIT("asin"))
560 FloatAcosOp -> (True, SLIT("acos"))
561 FloatAtanOp -> (True, SLIT("atan"))
563 FloatSinhOp -> (True, SLIT("sinh"))
564 FloatCoshOp -> (True, SLIT("cosh"))
565 FloatTanhOp -> (True, SLIT("tanh"))
567 DoubleExpOp -> (False, SLIT("exp"))
568 DoubleLogOp -> (False, SLIT("log"))
570 DoubleAsinOp -> (False, SLIT("asin"))
571 DoubleAcosOp -> (False, SLIT("acos"))
572 DoubleAtanOp -> (False, SLIT("atan"))
574 DoubleSinhOp -> (False, SLIT("sinh"))
575 DoubleCoshOp -> (False, SLIT("cosh"))
576 DoubleTanhOp -> (False, SLIT("tanh"))
579 -> pprPanic "getRegister(x86,unary primop)"
580 (pprStixTrees [StPrim primop [x]])
582 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
584 CharGtOp -> condIntReg GTT x y
585 CharGeOp -> condIntReg GE x y
586 CharEqOp -> condIntReg EQQ x y
587 CharNeOp -> condIntReg NE x y
588 CharLtOp -> condIntReg LTT x y
589 CharLeOp -> condIntReg LE x y
591 IntGtOp -> condIntReg GTT x y
592 IntGeOp -> condIntReg GE x y
593 IntEqOp -> condIntReg EQQ x y
594 IntNeOp -> condIntReg NE x y
595 IntLtOp -> condIntReg LTT x y
596 IntLeOp -> condIntReg LE x y
598 WordGtOp -> condIntReg GU x y
599 WordGeOp -> condIntReg GEU x y
600 WordEqOp -> condIntReg EQQ x y
601 WordNeOp -> condIntReg NE x y
602 WordLtOp -> condIntReg LU x y
603 WordLeOp -> condIntReg LEU x y
605 AddrGtOp -> condIntReg GU x y
606 AddrGeOp -> condIntReg GEU x y
607 AddrEqOp -> condIntReg EQQ x y
608 AddrNeOp -> condIntReg NE x y
609 AddrLtOp -> condIntReg LU x y
610 AddrLeOp -> condIntReg LEU x y
612 FloatGtOp -> condFltReg GTT x y
613 FloatGeOp -> condFltReg GE x y
614 FloatEqOp -> condFltReg EQQ x y
615 FloatNeOp -> condFltReg NE x y
616 FloatLtOp -> condFltReg LTT x y
617 FloatLeOp -> condFltReg LE x y
619 DoubleGtOp -> condFltReg GTT x y
620 DoubleGeOp -> condFltReg GE x y
621 DoubleEqOp -> condFltReg EQQ x y
622 DoubleNeOp -> condFltReg NE x y
623 DoubleLtOp -> condFltReg LTT x y
624 DoubleLeOp -> condFltReg LE x y
626 IntAddOp -> add_code L x y
627 IntSubOp -> sub_code L x y
628 IntQuotOp -> quot_code L x y True{-division-}
629 IntRemOp -> quot_code L x y False{-remainder-}
630 IntMulOp -> let op = IMUL L in trivialCode op (Just op) x y
632 FloatAddOp -> trivialFCode FloatRep GADD x y
633 FloatSubOp -> trivialFCode FloatRep GSUB x y
634 FloatMulOp -> trivialFCode FloatRep GMUL x y
635 FloatDivOp -> trivialFCode FloatRep GDIV x y
637 DoubleAddOp -> trivialFCode DoubleRep GADD x y
638 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
639 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
640 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
642 AndOp -> let op = AND L in trivialCode op (Just op) x y
643 OrOp -> let op = OR L in trivialCode op (Just op) x y
644 XorOp -> let op = XOR L in trivialCode op (Just op) x y
646 {- Shift ops on x86s have constraints on their source, it
647 either has to be Imm, CL or 1
648 => trivialCode's is not restrictive enough (sigh.)
651 SllOp -> shift_code (SHL L) x y {-False-}
652 SrlOp -> shift_code (SHR L) x y {-False-}
653 ISllOp -> shift_code (SHL L) x y {-False-}
654 ISraOp -> shift_code (SAR L) x y {-False-}
655 ISrlOp -> shift_code (SHR L) x y {-False-}
657 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
658 [promote x, promote y])
659 where promote x = StPrim Float2DoubleOp [x]
660 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
663 -> pprPanic "getRegister(x86,dyadic primop)"
664 (pprStixTrees [StPrim primop [x, y]])
668 shift_code :: (Imm -> Operand -> Instr)
673 {- Case1: shift length as immediate -}
674 -- Code is the same as the first eq. for trivialCode -- sigh.
675 shift_code instr x y{-amount-}
677 = getRegister x `thenNat` \ regx ->
680 then registerCodeA regx dst `bind` \ code_x ->
682 instr imm__2 (OpReg dst)
683 else registerCodeF regx `bind` \ code_x ->
684 registerNameF regx `bind` \ r_x ->
686 MOV L (OpReg r_x) (OpReg dst) `snocOL`
687 instr imm__2 (OpReg dst)
689 returnNat (Any IntRep mkcode)
692 imm__2 = case imm of Just x -> x
694 {- Case2: shift length is complex (non-immediate) -}
695 -- Since ECX is always used as a spill temporary, we can't
696 -- use it here to do non-immediate shifts. No big deal --
697 -- they are only very rare, and we can use an equivalent
698 -- test-and-jump sequence which doesn't use ECX.
699 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
700 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
701 shift_code instr x y{-amount-}
702 = getRegister x `thenNat` \ register1 ->
703 getRegister y `thenNat` \ register2 ->
704 getNatLabelNCG `thenNat` \ lbl_test3 ->
705 getNatLabelNCG `thenNat` \ lbl_test2 ->
706 getNatLabelNCG `thenNat` \ lbl_test1 ->
707 getNatLabelNCG `thenNat` \ lbl_test0 ->
708 getNatLabelNCG `thenNat` \ lbl_after ->
709 getNewRegNCG IntRep `thenNat` \ tmp ->
711 = let src_val = registerName register1 dst
712 code_val = registerCode register1 dst
713 src_amt = registerName register2 tmp
714 code_amt = registerCode register2 tmp
719 MOV L (OpReg src_amt) r_tmp `appOL`
721 MOV L (OpReg src_val) r_dst `appOL`
723 COMMENT (_PK_ "begin shift sequence"),
724 MOV L (OpReg src_val) r_dst,
725 MOV L (OpReg src_amt) r_tmp,
727 BT L (ImmInt 4) r_tmp,
729 instr (ImmInt 16) r_dst,
732 BT L (ImmInt 3) r_tmp,
734 instr (ImmInt 8) r_dst,
737 BT L (ImmInt 2) r_tmp,
739 instr (ImmInt 4) r_dst,
742 BT L (ImmInt 1) r_tmp,
744 instr (ImmInt 2) r_dst,
747 BT L (ImmInt 0) r_tmp,
749 instr (ImmInt 1) r_dst,
752 COMMENT (_PK_ "end shift sequence")
755 returnNat (Any IntRep code__2)
758 add_code :: Size -> StixTree -> StixTree -> NatM Register
760 add_code sz x (StInt y)
761 = getRegister x `thenNat` \ register ->
762 getNewRegNCG IntRep `thenNat` \ tmp ->
764 code = registerCode register tmp
765 src1 = registerName register tmp
766 src2 = ImmInt (fromInteger y)
769 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
772 returnNat (Any IntRep code__2)
774 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
777 sub_code :: Size -> StixTree -> StixTree -> NatM Register
779 sub_code sz x (StInt y)
780 = getRegister x `thenNat` \ register ->
781 getNewRegNCG IntRep `thenNat` \ tmp ->
783 code = registerCode register tmp
784 src1 = registerName register tmp
785 src2 = ImmInt (-(fromInteger y))
788 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
791 returnNat (Any IntRep code__2)
793 sub_code sz x y = trivialCode (SUB sz) Nothing x y
798 -> StixTree -> StixTree
799 -> Bool -- True => division, False => remainder operation
802 -- x must go into eax, edx must be a sign-extension of eax, and y
803 -- should go in some other register (or memory), so that we get
804 -- edx:eax / reg -> eax (remainder in edx). Currently we choose
805 -- to put y on the C stack, since that avoids tying up yet another
806 -- precious register.
808 quot_code sz x y is_division
809 = getRegister x `thenNat` \ register1 ->
810 getRegister y `thenNat` \ register2 ->
811 getNewRegNCG IntRep `thenNat` \ tmp ->
812 getDeltaNat `thenNat` \ delta ->
814 code1 = registerCode register1 tmp
815 src1 = registerName register1 tmp
816 code2 = registerCode register2 tmp
817 src2 = registerName register2 tmp
818 code__2 = code2 `snocOL` -- src2 := y
819 PUSH L (OpReg src2) `snocOL` -- -4(%esp) := y
820 DELTA (delta-4) `appOL`
821 code1 `snocOL` -- src1 := x
822 MOV L (OpReg src1) (OpReg eax) `snocOL` -- eax := x
824 IDIV sz (OpAddr (spRel 0)) `snocOL`
825 ADD L (OpImm (ImmInt 4)) (OpReg esp) `snocOL`
828 returnNat (Fixed IntRep (if is_division then eax else edx) code__2)
829 -----------------------
831 getRegister (StInd pk mem)
832 = getAmode mem `thenNat` \ amode ->
834 code = amodeCode amode
835 src = amodeAddr amode
836 size = primRepToSize pk
837 code__2 dst = code `snocOL`
838 if pk == DoubleRep || pk == FloatRep
839 then GLD size src dst
841 L -> MOV L (OpAddr src) (OpReg dst)
842 B -> MOVZxL B (OpAddr src) (OpReg dst)
844 returnNat (Any pk code__2)
846 getRegister (StInt i)
848 src = ImmInt (fromInteger i)
851 = unitOL (XOR L (OpReg dst) (OpReg dst))
853 = unitOL (MOV L (OpImm src) (OpReg dst))
855 returnNat (Any IntRep code)
859 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
861 returnNat (Any PtrRep code)
863 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
866 imm__2 = case imm of Just x -> x
868 #endif {- i386_TARGET_ARCH -}
869 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
870 #if sparc_TARGET_ARCH
872 getRegister (StDouble d)
873 = getNatLabelNCG `thenNat` \ lbl ->
874 getNewRegNCG PtrRep `thenNat` \ tmp ->
875 let code dst = toOL [
878 DATA DF [ImmDouble d],
880 SETHI (HI (ImmCLbl lbl)) tmp,
881 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
883 returnNat (Any DoubleRep code)
885 getRegister (StPrim primop [x]) -- unary PrimOps
887 IntNegOp -> trivialUCode (SUB False False g0) x
888 NotOp -> trivialUCode (XNOR False g0) x
890 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
892 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
894 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
895 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
897 OrdOp -> coerceIntCode IntRep x
900 Float2IntOp -> coerceFP2Int x
901 Int2FloatOp -> coerceInt2FP FloatRep x
902 Double2IntOp -> coerceFP2Int x
903 Int2DoubleOp -> coerceInt2FP DoubleRep x
907 fixed_x = if is_float_op -- promote to double
908 then StPrim Float2DoubleOp [x]
911 getRegister (StCall fn cCallConv DoubleRep [x])
915 FloatExpOp -> (True, SLIT("exp"))
916 FloatLogOp -> (True, SLIT("log"))
917 FloatSqrtOp -> (True, SLIT("sqrt"))
919 FloatSinOp -> (True, SLIT("sin"))
920 FloatCosOp -> (True, SLIT("cos"))
921 FloatTanOp -> (True, SLIT("tan"))
923 FloatAsinOp -> (True, SLIT("asin"))
924 FloatAcosOp -> (True, SLIT("acos"))
925 FloatAtanOp -> (True, SLIT("atan"))
927 FloatSinhOp -> (True, SLIT("sinh"))
928 FloatCoshOp -> (True, SLIT("cosh"))
929 FloatTanhOp -> (True, SLIT("tanh"))
931 DoubleExpOp -> (False, SLIT("exp"))
932 DoubleLogOp -> (False, SLIT("log"))
933 DoubleSqrtOp -> (True, SLIT("sqrt"))
935 DoubleSinOp -> (False, SLIT("sin"))
936 DoubleCosOp -> (False, SLIT("cos"))
937 DoubleTanOp -> (False, SLIT("tan"))
939 DoubleAsinOp -> (False, SLIT("asin"))
940 DoubleAcosOp -> (False, SLIT("acos"))
941 DoubleAtanOp -> (False, SLIT("atan"))
943 DoubleSinhOp -> (False, SLIT("sinh"))
944 DoubleCoshOp -> (False, SLIT("cosh"))
945 DoubleTanhOp -> (False, SLIT("tanh"))
946 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
948 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
950 CharGtOp -> condIntReg GTT x y
951 CharGeOp -> condIntReg GE x y
952 CharEqOp -> condIntReg EQQ x y
953 CharNeOp -> condIntReg NE x y
954 CharLtOp -> condIntReg LTT x y
955 CharLeOp -> condIntReg LE x y
957 IntGtOp -> condIntReg GTT x y
958 IntGeOp -> condIntReg GE x y
959 IntEqOp -> condIntReg EQQ x y
960 IntNeOp -> condIntReg NE x y
961 IntLtOp -> condIntReg LTT x y
962 IntLeOp -> condIntReg LE x y
964 WordGtOp -> condIntReg GU x y
965 WordGeOp -> condIntReg GEU x y
966 WordEqOp -> condIntReg EQQ x y
967 WordNeOp -> condIntReg NE x y
968 WordLtOp -> condIntReg LU x y
969 WordLeOp -> condIntReg LEU x y
971 AddrGtOp -> condIntReg GU x y
972 AddrGeOp -> condIntReg GEU x y
973 AddrEqOp -> condIntReg EQQ x y
974 AddrNeOp -> condIntReg NE x y
975 AddrLtOp -> condIntReg LU x y
976 AddrLeOp -> condIntReg LEU x y
978 FloatGtOp -> condFltReg GTT x y
979 FloatGeOp -> condFltReg GE x y
980 FloatEqOp -> condFltReg EQQ x y
981 FloatNeOp -> condFltReg NE x y
982 FloatLtOp -> condFltReg LTT x y
983 FloatLeOp -> condFltReg LE x y
985 DoubleGtOp -> condFltReg GTT x y
986 DoubleGeOp -> condFltReg GE x y
987 DoubleEqOp -> condFltReg EQQ x y
988 DoubleNeOp -> condFltReg NE x y
989 DoubleLtOp -> condFltReg LTT x y
990 DoubleLeOp -> condFltReg LE x y
992 IntAddOp -> trivialCode (ADD False False) x y
993 IntSubOp -> trivialCode (SUB False False) x y
995 -- ToDo: teach about V8+ SPARC mul/div instructions
996 IntMulOp -> imul_div SLIT(".umul") x y
997 IntQuotOp -> imul_div SLIT(".div") x y
998 IntRemOp -> imul_div SLIT(".rem") x y
1000 FloatAddOp -> trivialFCode FloatRep FADD x y
1001 FloatSubOp -> trivialFCode FloatRep FSUB x y
1002 FloatMulOp -> trivialFCode FloatRep FMUL x y
1003 FloatDivOp -> trivialFCode FloatRep FDIV x y
1005 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1006 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1007 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1008 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1010 AndOp -> trivialCode (AND False) x y
1011 OrOp -> trivialCode (OR False) x y
1012 XorOp -> trivialCode (XOR False) x y
1013 SllOp -> trivialCode SLL x y
1014 SrlOp -> trivialCode SRL x y
1016 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1017 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1018 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1020 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1021 where promote x = StPrim Float2DoubleOp [x]
1022 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1023 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1025 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1027 getRegister (StInd pk mem)
1028 = getAmode mem `thenNat` \ amode ->
1030 code = amodeCode amode
1031 src = amodeAddr amode
1032 size = primRepToSize pk
1033 code__2 dst = code `snocOL` LD size src dst
1035 returnNat (Any pk code__2)
1037 getRegister (StInt i)
1040 src = ImmInt (fromInteger i)
1041 code dst = unitOL (OR False g0 (RIImm src) dst)
1043 returnNat (Any IntRep code)
1049 SETHI (HI imm__2) dst,
1050 OR False dst (RIImm (LO imm__2)) dst]
1052 returnNat (Any PtrRep code)
1055 imm__2 = case imm of Just x -> x
1057 #endif {- sparc_TARGET_ARCH -}
1060 %************************************************************************
1062 \subsection{The @Amode@ type}
1064 %************************************************************************
1066 @Amode@s: Memory addressing modes passed up the tree.
1068 data Amode = Amode MachRegsAddr InstrBlock
1070 amodeAddr (Amode addr _) = addr
1071 amodeCode (Amode _ code) = code
1074 Now, given a tree (the argument to an StInd) that references memory,
1075 produce a suitable addressing mode.
1077 A Rule of the Game (tm) for Amodes: use of the addr bit must
1078 immediately follow use of the code part, since the code part puts
1079 values in registers which the addr then refers to. So you can't put
1080 anything in between, lest it overwrite some of those registers. If
1081 you need to do some other computation between the code part and use of
1082 the addr bit, first store the effective address from the amode in a
1083 temporary, then do the other computation, and then use the temporary:
1087 ... other computation ...
1091 getAmode :: StixTree -> NatM Amode
1093 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1095 #if alpha_TARGET_ARCH
1097 getAmode (StPrim IntSubOp [x, StInt i])
1098 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1099 getRegister x `thenNat` \ register ->
1101 code = registerCode register tmp
1102 reg = registerName register tmp
1103 off = ImmInt (-(fromInteger i))
1105 returnNat (Amode (AddrRegImm reg off) code)
1107 getAmode (StPrim IntAddOp [x, StInt i])
1108 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1109 getRegister x `thenNat` \ register ->
1111 code = registerCode register tmp
1112 reg = registerName register tmp
1113 off = ImmInt (fromInteger i)
1115 returnNat (Amode (AddrRegImm reg off) code)
1119 = returnNat (Amode (AddrImm imm__2) id)
1122 imm__2 = case imm of Just x -> x
1125 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1126 getRegister other `thenNat` \ register ->
1128 code = registerCode register tmp
1129 reg = registerName register tmp
1131 returnNat (Amode (AddrReg reg) code)
1133 #endif {- alpha_TARGET_ARCH -}
1134 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1135 #if i386_TARGET_ARCH
1137 getAmode (StPrim IntSubOp [x, StInt i])
1138 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1139 getRegister x `thenNat` \ register ->
1141 code = registerCode register tmp
1142 reg = registerName register tmp
1143 off = ImmInt (-(fromInteger i))
1145 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1147 getAmode (StPrim IntAddOp [x, StInt i])
1149 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1152 imm__2 = case imm of Just x -> x
1154 getAmode (StPrim IntAddOp [x, StInt i])
1155 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1156 getRegister x `thenNat` \ register ->
1158 code = registerCode register tmp
1159 reg = registerName register tmp
1160 off = ImmInt (fromInteger i)
1162 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1164 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1165 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1166 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1167 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1168 getRegister x `thenNat` \ register1 ->
1169 getRegister y `thenNat` \ register2 ->
1171 code1 = registerCode register1 tmp1
1172 reg1 = registerName register1 tmp1
1173 code2 = registerCode register2 tmp2
1174 reg2 = registerName register2 tmp2
1175 code__2 = code1 `appOL` code2
1176 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1178 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1183 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1186 imm__2 = case imm of Just x -> x
1189 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1190 getRegister other `thenNat` \ register ->
1192 code = registerCode register tmp
1193 reg = registerName register tmp
1195 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1197 #endif {- i386_TARGET_ARCH -}
1198 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1199 #if sparc_TARGET_ARCH
1201 getAmode (StPrim IntSubOp [x, StInt i])
1203 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1204 getRegister x `thenNat` \ register ->
1206 code = registerCode register tmp
1207 reg = registerName register tmp
1208 off = ImmInt (-(fromInteger i))
1210 returnNat (Amode (AddrRegImm reg off) code)
1213 getAmode (StPrim IntAddOp [x, StInt i])
1215 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1216 getRegister x `thenNat` \ register ->
1218 code = registerCode register tmp
1219 reg = registerName register tmp
1220 off = ImmInt (fromInteger i)
1222 returnNat (Amode (AddrRegImm reg off) code)
1224 getAmode (StPrim IntAddOp [x, y])
1225 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1226 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1227 getRegister x `thenNat` \ register1 ->
1228 getRegister y `thenNat` \ register2 ->
1230 code1 = registerCode register1 tmp1
1231 reg1 = registerName register1 tmp1
1232 code2 = registerCode register2 tmp2
1233 reg2 = registerName register2 tmp2
1234 code__2 = code1 `appOL` code2
1236 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1240 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1242 code = unitOL (SETHI (HI imm__2) tmp)
1244 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1247 imm__2 = case imm of Just x -> x
1250 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1251 getRegister other `thenNat` \ register ->
1253 code = registerCode register tmp
1254 reg = registerName register tmp
1257 returnNat (Amode (AddrRegImm reg off) code)
1259 #endif {- sparc_TARGET_ARCH -}
1262 %************************************************************************
1264 \subsection{The @CondCode@ type}
1266 %************************************************************************
1268 Condition codes passed up the tree.
1270 data CondCode = CondCode Bool Cond InstrBlock
1272 condName (CondCode _ cond _) = cond
1273 condFloat (CondCode is_float _ _) = is_float
1274 condCode (CondCode _ _ code) = code
1277 Set up a condition code for a conditional branch.
1280 getCondCode :: StixTree -> NatM CondCode
1282 #if alpha_TARGET_ARCH
1283 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1284 #endif {- alpha_TARGET_ARCH -}
1285 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1287 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1288 -- yes, they really do seem to want exactly the same!
1290 getCondCode (StPrim primop [x, y])
1292 CharGtOp -> condIntCode GTT x y
1293 CharGeOp -> condIntCode GE x y
1294 CharEqOp -> condIntCode EQQ x y
1295 CharNeOp -> condIntCode NE x y
1296 CharLtOp -> condIntCode LTT x y
1297 CharLeOp -> condIntCode LE x y
1299 IntGtOp -> condIntCode GTT x y
1300 IntGeOp -> condIntCode GE x y
1301 IntEqOp -> condIntCode EQQ x y
1302 IntNeOp -> condIntCode NE x y
1303 IntLtOp -> condIntCode LTT x y
1304 IntLeOp -> condIntCode LE x y
1306 WordGtOp -> condIntCode GU x y
1307 WordGeOp -> condIntCode GEU x y
1308 WordEqOp -> condIntCode EQQ x y
1309 WordNeOp -> condIntCode NE x y
1310 WordLtOp -> condIntCode LU x y
1311 WordLeOp -> condIntCode LEU x y
1313 AddrGtOp -> condIntCode GU x y
1314 AddrGeOp -> condIntCode GEU x y
1315 AddrEqOp -> condIntCode EQQ x y
1316 AddrNeOp -> condIntCode NE x y
1317 AddrLtOp -> condIntCode LU x y
1318 AddrLeOp -> condIntCode LEU x y
1320 FloatGtOp -> condFltCode GTT x y
1321 FloatGeOp -> condFltCode GE x y
1322 FloatEqOp -> condFltCode EQQ x y
1323 FloatNeOp -> condFltCode NE x y
1324 FloatLtOp -> condFltCode LTT x y
1325 FloatLeOp -> condFltCode LE x y
1327 DoubleGtOp -> condFltCode GTT x y
1328 DoubleGeOp -> condFltCode GE x y
1329 DoubleEqOp -> condFltCode EQQ x y
1330 DoubleNeOp -> condFltCode NE x y
1331 DoubleLtOp -> condFltCode LTT x y
1332 DoubleLeOp -> condFltCode LE x y
1334 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1339 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1340 passed back up the tree.
1343 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> NatM CondCode
1345 #if alpha_TARGET_ARCH
1346 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1347 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1348 #endif {- alpha_TARGET_ARCH -}
1350 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1351 #if i386_TARGET_ARCH
1353 -- memory vs immediate
1354 condIntCode cond (StInd pk x) y
1356 = getAmode x `thenNat` \ amode ->
1358 code1 = amodeCode amode
1359 x__2 = amodeAddr amode
1360 sz = primRepToSize pk
1361 code__2 = code1 `snocOL`
1362 CMP sz (OpImm imm__2) (OpAddr x__2)
1364 returnNat (CondCode False cond code__2)
1367 imm__2 = case imm of Just x -> x
1370 condIntCode cond x (StInt 0)
1371 = getRegister x `thenNat` \ register1 ->
1372 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1374 code1 = registerCode register1 tmp1
1375 src1 = registerName register1 tmp1
1376 code__2 = code1 `snocOL`
1377 TEST L (OpReg src1) (OpReg src1)
1379 returnNat (CondCode False cond code__2)
1381 -- anything vs immediate
1382 condIntCode cond x y
1384 = getRegister x `thenNat` \ register1 ->
1385 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1387 code1 = registerCode register1 tmp1
1388 src1 = registerName register1 tmp1
1389 code__2 = code1 `snocOL`
1390 CMP L (OpImm imm__2) (OpReg src1)
1392 returnNat (CondCode False cond code__2)
1395 imm__2 = case imm of Just x -> x
1397 -- memory vs anything
1398 condIntCode cond (StInd pk x) y
1399 = getAmode x `thenNat` \ amode_x ->
1400 getRegister y `thenNat` \ reg_y ->
1401 getNewRegNCG IntRep `thenNat` \ tmp ->
1403 c_x = amodeCode amode_x
1404 am_x = amodeAddr amode_x
1405 c_y = registerCode reg_y tmp
1406 r_y = registerName reg_y tmp
1407 sz = primRepToSize pk
1409 -- optimisation: if there's no code for x, just an amode,
1410 -- use whatever reg y winds up in. Assumes that c_y doesn't
1411 -- clobber any regs in the amode am_x, which I'm not sure is
1412 -- justified. The otherwise clause makes the same assumption.
1413 code__2 | isNilOL c_x
1415 CMP sz (OpReg r_y) (OpAddr am_x)
1419 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1421 CMP sz (OpReg tmp) (OpAddr am_x)
1423 returnNat (CondCode False cond code__2)
1425 -- anything vs memory
1427 condIntCode cond y (StInd pk x)
1428 = getAmode x `thenNat` \ amode_x ->
1429 getRegister y `thenNat` \ reg_y ->
1430 getNewRegNCG IntRep `thenNat` \ tmp ->
1432 c_x = amodeCode amode_x
1433 am_x = amodeAddr amode_x
1434 c_y = registerCode reg_y tmp
1435 r_y = registerName reg_y tmp
1436 sz = primRepToSize pk
1437 -- same optimisation and nagging doubts as previous clause
1438 code__2 | isNilOL c_x
1440 CMP sz (OpAddr am_x) (OpReg r_y)
1444 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1446 CMP sz (OpAddr am_x) (OpReg tmp)
1448 returnNat (CondCode False cond code__2)
1450 -- anything vs anything
1451 condIntCode cond x y
1452 = getRegister x `thenNat` \ register1 ->
1453 getRegister y `thenNat` \ register2 ->
1454 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1455 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1457 code1 = registerCode register1 tmp1
1458 src1 = registerName register1 tmp1
1459 code2 = registerCode register2 tmp2
1460 src2 = registerName register2 tmp2
1461 code__2 = code1 `snocOL`
1462 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1464 CMP L (OpReg src2) (OpReg tmp1)
1466 returnNat (CondCode False cond code__2)
1469 condFltCode cond x y
1470 = getRegister x `thenNat` \ register1 ->
1471 getRegister y `thenNat` \ register2 ->
1472 getNewRegNCG (registerRep register1)
1474 getNewRegNCG (registerRep register2)
1476 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1478 pk1 = registerRep register1
1479 code1 = registerCode register1 tmp1
1480 src1 = registerName register1 tmp1
1482 pk2 = registerRep register2
1483 code2 = registerCode register2 tmp2
1484 src2 = registerName register2 tmp2
1486 code__2 | isAny register1
1487 = code1 `appOL` -- result in tmp1
1489 GCMP (primRepToSize pk1) tmp1 src2
1493 GMOV src1 tmp1 `appOL`
1495 GCMP (primRepToSize pk1) tmp1 src2
1497 {- On the 486, the flags set by FP compare are the unsigned ones!
1498 (This looks like a HACK to me. WDP 96/03)
1500 fix_FP_cond :: Cond -> Cond
1502 fix_FP_cond GE = GEU
1503 fix_FP_cond GTT = GU
1504 fix_FP_cond LTT = LU
1505 fix_FP_cond LE = LEU
1506 fix_FP_cond any = any
1508 returnNat (CondCode True (fix_FP_cond cond) code__2)
1512 #endif {- i386_TARGET_ARCH -}
1513 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1514 #if sparc_TARGET_ARCH
1516 condIntCode cond x (StInt y)
1518 = getRegister x `thenNat` \ register ->
1519 getNewRegNCG IntRep `thenNat` \ tmp ->
1521 code = registerCode register tmp
1522 src1 = registerName register tmp
1523 src2 = ImmInt (fromInteger y)
1524 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1526 returnNat (CondCode False cond code__2)
1528 condIntCode cond x y
1529 = getRegister x `thenNat` \ register1 ->
1530 getRegister y `thenNat` \ register2 ->
1531 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1532 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1534 code1 = registerCode register1 tmp1
1535 src1 = registerName register1 tmp1
1536 code2 = registerCode register2 tmp2
1537 src2 = registerName register2 tmp2
1538 code__2 = code1 `appOL` code2 `snocOL`
1539 SUB False True src1 (RIReg src2) g0
1541 returnNat (CondCode False cond code__2)
1544 condFltCode cond x y
1545 = getRegister x `thenNat` \ register1 ->
1546 getRegister y `thenNat` \ register2 ->
1547 getNewRegNCG (registerRep register1)
1549 getNewRegNCG (registerRep register2)
1551 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1553 promote x = FxTOy F DF x tmp
1555 pk1 = registerRep register1
1556 code1 = registerCode register1 tmp1
1557 src1 = registerName register1 tmp1
1559 pk2 = registerRep register2
1560 code2 = registerCode register2 tmp2
1561 src2 = registerName register2 tmp2
1565 code1 `appOL` code2 `snocOL`
1566 FCMP True (primRepToSize pk1) src1 src2
1567 else if pk1 == FloatRep then
1568 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1569 FCMP True DF tmp src2
1571 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1572 FCMP True DF src1 tmp
1574 returnNat (CondCode True cond code__2)
1576 #endif {- sparc_TARGET_ARCH -}
1579 %************************************************************************
1581 \subsection{Generating assignments}
1583 %************************************************************************
1585 Assignments are really at the heart of the whole code generation
1586 business. Almost all top-level nodes of any real importance are
1587 assignments, which correspond to loads, stores, or register transfers.
1588 If we're really lucky, some of the register transfers will go away,
1589 because we can use the destination register to complete the code
1590 generation for the right hand side. This only fails when the right
1591 hand side is forced into a fixed register (e.g. the result of a call).
1594 assignIntCode, assignFltCode
1595 :: PrimRep -> StixTree -> StixTree -> NatM InstrBlock
1597 #if alpha_TARGET_ARCH
1599 assignIntCode pk (StInd _ dst) src
1600 = getNewRegNCG IntRep `thenNat` \ tmp ->
1601 getAmode dst `thenNat` \ amode ->
1602 getRegister src `thenNat` \ register ->
1604 code1 = amodeCode amode []
1605 dst__2 = amodeAddr amode
1606 code2 = registerCode register tmp []
1607 src__2 = registerName register tmp
1608 sz = primRepToSize pk
1609 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1613 assignIntCode pk dst src
1614 = getRegister dst `thenNat` \ register1 ->
1615 getRegister src `thenNat` \ register2 ->
1617 dst__2 = registerName register1 zeroh
1618 code = registerCode register2 dst__2
1619 src__2 = registerName register2 dst__2
1620 code__2 = if isFixed register2
1621 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1626 #endif {- alpha_TARGET_ARCH -}
1627 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1628 #if i386_TARGET_ARCH
1630 -- Destination of an assignment can only be reg or mem.
1631 -- This is the mem case.
1632 assignIntCode pk (StInd _ dst) src
1633 = getAmode dst `thenNat` \ amode ->
1634 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
1635 getNewRegNCG PtrRep `thenNat` \ tmp ->
1637 -- In general, if the address computation for dst may require
1638 -- some insns preceding the addressing mode itself. So there's
1639 -- no guarantee that the code for dst and the code for src won't
1640 -- write the same register. This means either the address or
1641 -- the value needs to be copied into a temporary. We detect the
1642 -- common case where the amode has no code, and elide the copy.
1643 codea = amodeCode amode
1644 dst__a = amodeAddr amode
1646 code | isNilOL codea
1648 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
1652 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
1654 MOV (primRepToSize pk) opsrc
1655 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
1661 -> NatM (InstrBlock,Operand) -- code, operator
1665 = returnNat (nilOL, OpImm imm_op)
1668 imm_op = case imm of Just x -> x
1671 = getRegister op `thenNat` \ register ->
1672 getNewRegNCG (registerRep register)
1674 let code = registerCode register tmp
1675 reg = registerName register tmp
1677 returnNat (code, OpReg reg)
1679 -- Assign; dst is a reg, rhs is mem
1680 assignIntCode pk dst (StInd pks src)
1681 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1682 getAmode src `thenNat` \ amode ->
1683 getRegister dst `thenNat` \ reg_dst ->
1685 c_addr = amodeCode amode
1686 am_addr = amodeAddr amode
1688 c_dst = registerCode reg_dst tmp -- should be empty
1689 r_dst = registerName reg_dst tmp
1690 szs = primRepToSize pks
1691 opc = case szs of L -> MOV L ; B -> MOVZxL B
1693 code | isNilOL c_dst
1695 opc (OpAddr am_addr) (OpReg r_dst)
1697 = pprPanic "assignIntCode(x86): bad dst(2)" empty
1701 -- dst is a reg, but src could be anything
1702 assignIntCode pk dst src
1703 = getRegister dst `thenNat` \ registerd ->
1704 getRegister src `thenNat` \ registers ->
1705 getNewRegNCG IntRep `thenNat` \ tmp ->
1707 r_dst = registerName registerd tmp
1708 c_dst = registerCode registerd tmp -- should be empty
1709 r_src = registerName registers r_dst
1710 c_src = registerCode registers r_dst
1712 code | isNilOL c_dst
1714 MOV L (OpReg r_src) (OpReg r_dst)
1716 = pprPanic "assignIntCode(x86): bad dst(3)" empty
1720 #endif {- i386_TARGET_ARCH -}
1721 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1722 #if sparc_TARGET_ARCH
1724 assignIntCode pk (StInd _ dst) src
1725 = getNewRegNCG IntRep `thenNat` \ tmp ->
1726 getAmode dst `thenNat` \ amode ->
1727 getRegister src `thenNat` \ register ->
1729 code1 = amodeCode amode
1730 dst__2 = amodeAddr amode
1731 code2 = registerCode register tmp
1732 src__2 = registerName register tmp
1733 sz = primRepToSize pk
1734 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
1738 assignIntCode pk dst src
1739 = getRegister dst `thenNat` \ register1 ->
1740 getRegister src `thenNat` \ register2 ->
1742 dst__2 = registerName register1 g0
1743 code = registerCode register2 dst__2
1744 src__2 = registerName register2 dst__2
1745 code__2 = if isFixed register2
1746 then code `snocOL` OR False g0 (RIReg src__2) dst__2
1751 #endif {- sparc_TARGET_ARCH -}
1754 % --------------------------------
1755 Floating-point assignments:
1756 % --------------------------------
1758 #if alpha_TARGET_ARCH
1760 assignFltCode pk (StInd _ dst) src
1761 = getNewRegNCG pk `thenNat` \ tmp ->
1762 getAmode dst `thenNat` \ amode ->
1763 getRegister src `thenNat` \ register ->
1765 code1 = amodeCode amode []
1766 dst__2 = amodeAddr amode
1767 code2 = registerCode register tmp []
1768 src__2 = registerName register tmp
1769 sz = primRepToSize pk
1770 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1774 assignFltCode pk dst src
1775 = getRegister dst `thenNat` \ register1 ->
1776 getRegister src `thenNat` \ register2 ->
1778 dst__2 = registerName register1 zeroh
1779 code = registerCode register2 dst__2
1780 src__2 = registerName register2 dst__2
1781 code__2 = if isFixed register2
1782 then code . mkSeqInstr (FMOV src__2 dst__2)
1787 #endif {- alpha_TARGET_ARCH -}
1788 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1789 #if i386_TARGET_ARCH
1792 assignFltCode pk (StInd pk_dst addr) src
1794 = pprPanic "assignFltCode(x86): src/ind sz mismatch" empty
1796 = getRegister src `thenNat` \ reg_src ->
1797 getRegister addr `thenNat` \ reg_addr ->
1798 getNewRegNCG pk `thenNat` \ tmp_src ->
1799 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
1800 let r_src = registerName reg_src tmp_src
1801 c_src = registerCode reg_src tmp_src
1802 r_addr = registerName reg_addr tmp_addr
1803 c_addr = registerCode reg_addr tmp_addr
1804 sz = primRepToSize pk
1806 code = c_src `appOL`
1807 -- no need to preserve r_src across the addr computation,
1808 -- since r_src must be a float reg
1809 -- whilst r_addr is an int reg
1812 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
1816 -- dst must be a (FP) register
1817 assignFltCode pk dst src
1818 = getRegister dst `thenNat` \ reg_dst ->
1819 getRegister src `thenNat` \ reg_src ->
1820 getNewRegNCG pk `thenNat` \ tmp ->
1822 r_dst = registerName reg_dst tmp
1823 c_dst = registerCode reg_dst tmp -- should be empty
1825 r_src = registerName reg_src r_dst
1826 c_src = registerCode reg_src r_dst
1828 code | isNilOL c_dst
1829 = if isFixed reg_src
1830 then c_src `snocOL` GMOV r_src r_dst
1833 = pprPanic "assignFltCode(x86): lhs is not mem or reg"
1839 #endif {- i386_TARGET_ARCH -}
1840 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1841 #if sparc_TARGET_ARCH
1843 assignFltCode pk (StInd _ dst) src
1844 = getNewRegNCG pk `thenNat` \ tmp1 ->
1845 getAmode dst `thenNat` \ amode ->
1846 getRegister src `thenNat` \ register ->
1848 sz = primRepToSize pk
1849 dst__2 = amodeAddr amode
1851 code1 = amodeCode amode
1852 code2 = registerCode register tmp1
1854 src__2 = registerName register tmp1
1855 pk__2 = registerRep register
1856 sz__2 = primRepToSize pk__2
1858 code__2 = code1 `appOL` code2 `appOL`
1860 then unitOL (ST sz src__2 dst__2)
1861 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1865 assignFltCode pk dst src
1866 = getRegister dst `thenNat` \ register1 ->
1867 getRegister src `thenNat` \ register2 ->
1869 pk__2 = registerRep register2
1870 sz__2 = primRepToSize pk__2
1872 getNewRegNCG pk__2 `thenNat` \ tmp ->
1874 sz = primRepToSize pk
1875 dst__2 = registerName register1 g0 -- must be Fixed
1878 reg__2 = if pk /= pk__2 then tmp else dst__2
1880 code = registerCode register2 reg__2
1882 src__2 = registerName register2 reg__2
1886 code `snocOL` FxTOy sz__2 sz src__2 dst__2
1887 else if isFixed register2 then
1888 code `snocOL` FMOV sz src__2 dst__2
1894 #endif {- sparc_TARGET_ARCH -}
1897 %************************************************************************
1899 \subsection{Generating an unconditional branch}
1901 %************************************************************************
1903 We accept two types of targets: an immediate CLabel or a tree that
1904 gets evaluated into a register. Any CLabels which are AsmTemporaries
1905 are assumed to be in the local block of code, close enough for a
1906 branch instruction. Other CLabels are assumed to be far away.
1908 (If applicable) Do not fill the delay slots here; you will confuse the
1912 genJump :: StixTree{-the branch target-} -> NatM InstrBlock
1914 #if alpha_TARGET_ARCH
1916 genJump (StCLbl lbl)
1917 | isAsmTemp lbl = returnInstr (BR target)
1918 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1920 target = ImmCLbl lbl
1923 = getRegister tree `thenNat` \ register ->
1924 getNewRegNCG PtrRep `thenNat` \ tmp ->
1926 dst = registerName register pv
1927 code = registerCode register pv
1928 target = registerName register pv
1930 if isFixed register then
1931 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1933 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1935 #endif {- alpha_TARGET_ARCH -}
1936 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1937 #if i386_TARGET_ARCH
1939 genJump (StInd pk mem)
1940 = getAmode mem `thenNat` \ amode ->
1942 code = amodeCode amode
1943 target = amodeAddr amode
1945 returnNat (code `snocOL` JMP (OpAddr target))
1949 = returnNat (unitOL (JMP (OpImm target)))
1952 = getRegister tree `thenNat` \ register ->
1953 getNewRegNCG PtrRep `thenNat` \ tmp ->
1955 code = registerCode register tmp
1956 target = registerName register tmp
1958 returnNat (code `snocOL` JMP (OpReg target))
1961 target = case imm of Just x -> x
1963 #endif {- i386_TARGET_ARCH -}
1964 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1965 #if sparc_TARGET_ARCH
1967 genJump (StCLbl lbl)
1968 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
1969 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
1971 target = ImmCLbl lbl
1974 = getRegister tree `thenNat` \ register ->
1975 getNewRegNCG PtrRep `thenNat` \ tmp ->
1977 code = registerCode register tmp
1978 target = registerName register tmp
1980 returnNat (code `snocOL` JMP (AddrRegReg target g0) `snocOL` NOP)
1982 #endif {- sparc_TARGET_ARCH -}
1985 %************************************************************************
1987 \subsection{Conditional jumps}
1989 %************************************************************************
1991 Conditional jumps are always to local labels, so we can use branch
1992 instructions. We peek at the arguments to decide what kind of
1995 ALPHA: For comparisons with 0, we're laughing, because we can just do
1996 the desired conditional branch.
1998 I386: First, we have to ensure that the condition
1999 codes are set according to the supplied comparison operation.
2001 SPARC: First, we have to ensure that the condition codes are set
2002 according to the supplied comparison operation. We generate slightly
2003 different code for floating point comparisons, because a floating
2004 point operation cannot directly precede a @BF@. We assume the worst
2005 and fill that slot with a @NOP@.
2007 SPARC: Do not fill the delay slots here; you will confuse the register
2012 :: CLabel -- the branch target
2013 -> StixTree -- the condition on which to branch
2016 #if alpha_TARGET_ARCH
2018 genCondJump lbl (StPrim op [x, StInt 0])
2019 = getRegister x `thenNat` \ register ->
2020 getNewRegNCG (registerRep register)
2023 code = registerCode register tmp
2024 value = registerName register tmp
2025 pk = registerRep register
2026 target = ImmCLbl lbl
2028 returnSeq code [BI (cmpOp op) value target]
2030 cmpOp CharGtOp = GTT
2032 cmpOp CharEqOp = EQQ
2034 cmpOp CharLtOp = LTT
2043 cmpOp WordGeOp = ALWAYS
2044 cmpOp WordEqOp = EQQ
2046 cmpOp WordLtOp = NEVER
2047 cmpOp WordLeOp = EQQ
2049 cmpOp AddrGeOp = ALWAYS
2050 cmpOp AddrEqOp = EQQ
2052 cmpOp AddrLtOp = NEVER
2053 cmpOp AddrLeOp = EQQ
2055 genCondJump lbl (StPrim op [x, StDouble 0.0])
2056 = getRegister x `thenNat` \ register ->
2057 getNewRegNCG (registerRep register)
2060 code = registerCode register tmp
2061 value = registerName register tmp
2062 pk = registerRep register
2063 target = ImmCLbl lbl
2065 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2067 cmpOp FloatGtOp = GTT
2068 cmpOp FloatGeOp = GE
2069 cmpOp FloatEqOp = EQQ
2070 cmpOp FloatNeOp = NE
2071 cmpOp FloatLtOp = LTT
2072 cmpOp FloatLeOp = LE
2073 cmpOp DoubleGtOp = GTT
2074 cmpOp DoubleGeOp = GE
2075 cmpOp DoubleEqOp = EQQ
2076 cmpOp DoubleNeOp = NE
2077 cmpOp DoubleLtOp = LTT
2078 cmpOp DoubleLeOp = LE
2080 genCondJump lbl (StPrim op [x, y])
2082 = trivialFCode pr instr x y `thenNat` \ register ->
2083 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2085 code = registerCode register tmp
2086 result = registerName register tmp
2087 target = ImmCLbl lbl
2089 returnNat (code . mkSeqInstr (BF cond result target))
2091 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2093 fltCmpOp op = case op of
2107 (instr, cond) = case op of
2108 FloatGtOp -> (FCMP TF LE, EQQ)
2109 FloatGeOp -> (FCMP TF LTT, EQQ)
2110 FloatEqOp -> (FCMP TF EQQ, NE)
2111 FloatNeOp -> (FCMP TF EQQ, EQQ)
2112 FloatLtOp -> (FCMP TF LTT, NE)
2113 FloatLeOp -> (FCMP TF LE, NE)
2114 DoubleGtOp -> (FCMP TF LE, EQQ)
2115 DoubleGeOp -> (FCMP TF LTT, EQQ)
2116 DoubleEqOp -> (FCMP TF EQQ, NE)
2117 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2118 DoubleLtOp -> (FCMP TF LTT, NE)
2119 DoubleLeOp -> (FCMP TF LE, NE)
2121 genCondJump lbl (StPrim op [x, y])
2122 = trivialCode instr x y `thenNat` \ register ->
2123 getNewRegNCG IntRep `thenNat` \ tmp ->
2125 code = registerCode register tmp
2126 result = registerName register tmp
2127 target = ImmCLbl lbl
2129 returnNat (code . mkSeqInstr (BI cond result target))
2131 (instr, cond) = case op of
2132 CharGtOp -> (CMP LE, EQQ)
2133 CharGeOp -> (CMP LTT, EQQ)
2134 CharEqOp -> (CMP EQQ, NE)
2135 CharNeOp -> (CMP EQQ, EQQ)
2136 CharLtOp -> (CMP LTT, NE)
2137 CharLeOp -> (CMP LE, NE)
2138 IntGtOp -> (CMP LE, EQQ)
2139 IntGeOp -> (CMP LTT, EQQ)
2140 IntEqOp -> (CMP EQQ, NE)
2141 IntNeOp -> (CMP EQQ, EQQ)
2142 IntLtOp -> (CMP LTT, NE)
2143 IntLeOp -> (CMP LE, NE)
2144 WordGtOp -> (CMP ULE, EQQ)
2145 WordGeOp -> (CMP ULT, EQQ)
2146 WordEqOp -> (CMP EQQ, NE)
2147 WordNeOp -> (CMP EQQ, EQQ)
2148 WordLtOp -> (CMP ULT, NE)
2149 WordLeOp -> (CMP ULE, NE)
2150 AddrGtOp -> (CMP ULE, EQQ)
2151 AddrGeOp -> (CMP ULT, EQQ)
2152 AddrEqOp -> (CMP EQQ, NE)
2153 AddrNeOp -> (CMP EQQ, EQQ)
2154 AddrLtOp -> (CMP ULT, NE)
2155 AddrLeOp -> (CMP ULE, NE)
2157 #endif {- alpha_TARGET_ARCH -}
2158 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2159 #if i386_TARGET_ARCH
2161 genCondJump lbl bool
2162 = getCondCode bool `thenNat` \ condition ->
2164 code = condCode condition
2165 cond = condName condition
2166 target = ImmCLbl lbl
2168 returnNat (code `snocOL` JXX cond lbl)
2170 #endif {- i386_TARGET_ARCH -}
2171 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2172 #if sparc_TARGET_ARCH
2174 genCondJump lbl bool
2175 = getCondCode bool `thenNat` \ condition ->
2177 code = condCode condition
2178 cond = condName condition
2179 target = ImmCLbl lbl
2184 if condFloat condition
2185 then [NOP, BF cond False target, NOP]
2186 else [BI cond False target, NOP]
2190 #endif {- sparc_TARGET_ARCH -}
2193 %************************************************************************
2195 \subsection{Generating C calls}
2197 %************************************************************************
2199 Now the biggest nightmare---calls. Most of the nastiness is buried in
2200 @get_arg@, which moves the arguments to the correct registers/stack
2201 locations. Apart from that, the code is easy.
2203 (If applicable) Do not fill the delay slots here; you will confuse the
2208 :: FAST_STRING -- function to call
2210 -> PrimRep -- type of the result
2211 -> [StixTree] -- arguments (of mixed type)
2214 #if alpha_TARGET_ARCH
2216 genCCall fn cconv kind args
2217 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2218 `thenNat` \ ((unused,_), argCode) ->
2220 nRegs = length allArgRegs - length unused
2221 code = asmSeqThen (map ($ []) argCode)
2224 LDA pv (AddrImm (ImmLab (ptext fn))),
2225 JSR ra (AddrReg pv) nRegs,
2226 LDGP gp (AddrReg ra)]
2228 ------------------------
2229 {- Try to get a value into a specific register (or registers) for
2230 a call. The first 6 arguments go into the appropriate
2231 argument register (separate registers for integer and floating
2232 point arguments, but used in lock-step), and the remaining
2233 arguments are dumped to the stack, beginning at 0(sp). Our
2234 first argument is a pair of the list of remaining argument
2235 registers to be assigned for this call and the next stack
2236 offset to use for overflowing arguments. This way,
2237 @get_Arg@ can be applied to all of a call's arguments using
2241 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2242 -> StixTree -- Current argument
2243 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2245 -- We have to use up all of our argument registers first...
2247 get_arg ((iDst,fDst):dsts, offset) arg
2248 = getRegister arg `thenNat` \ register ->
2250 reg = if isFloatingRep pk then fDst else iDst
2251 code = registerCode register reg
2252 src = registerName register reg
2253 pk = registerRep register
2256 if isFloatingRep pk then
2257 ((dsts, offset), if isFixed register then
2258 code . mkSeqInstr (FMOV src fDst)
2261 ((dsts, offset), if isFixed register then
2262 code . mkSeqInstr (OR src (RIReg src) iDst)
2265 -- Once we have run out of argument registers, we move to the
2268 get_arg ([], offset) arg
2269 = getRegister arg `thenNat` \ register ->
2270 getNewRegNCG (registerRep register)
2273 code = registerCode register tmp
2274 src = registerName register tmp
2275 pk = registerRep register
2276 sz = primRepToSize pk
2278 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2280 #endif {- alpha_TARGET_ARCH -}
2281 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2282 #if i386_TARGET_ARCH
2284 genCCall fn cconv kind [StInt i]
2285 | fn == SLIT ("PerformGC_wrapper")
2287 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2288 CALL (ImmLit (ptext (if underscorePrefix
2289 then (SLIT ("_PerformGC_wrapper"))
2290 else (SLIT ("PerformGC_wrapper")))))
2296 genCCall fn cconv kind args
2297 = mapNat get_call_arg
2298 (reverse args) `thenNat` \ sizes_n_codes ->
2299 getDeltaNat `thenNat` \ delta ->
2300 let (sizes, codes) = unzip sizes_n_codes
2301 tot_arg_size = sum sizes
2302 code2 = concatOL codes
2305 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2306 DELTA (delta + tot_arg_size)
2309 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2310 returnNat (code2 `appOL` call)
2313 -- function names that begin with '.' are assumed to be special
2314 -- internally generated names like '.mul,' which don't get an
2315 -- underscore prefix
2316 -- ToDo:needed (WDP 96/03) ???
2317 fn__2 = case (_HEAD_ fn) of
2318 '.' -> ImmLit (ptext fn)
2319 _ -> ImmLab (ptext fn)
2326 get_call_arg :: StixTree{-current argument-}
2327 -> NatM (Int, InstrBlock) -- argsz, code
2330 = get_op arg `thenNat` \ (code, reg, sz) ->
2331 getDeltaNat `thenNat` \ delta ->
2332 arg_size sz `bind` \ size ->
2333 setDeltaNat (delta-size) `thenNat` \ _ ->
2334 if (case sz of DF -> True; F -> True; _ -> False)
2335 then returnNat (size,
2337 toOL [SUB L (OpImm (ImmInt 8)) (OpReg esp),
2339 GST DF reg (AddrBaseIndex (Just esp)
2343 else returnNat (size,
2345 PUSH L (OpReg reg) `snocOL`
2351 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2354 = getRegister op `thenNat` \ register ->
2355 getNewRegNCG (registerRep register)
2358 code = registerCode register tmp
2359 reg = registerName register tmp
2360 pk = registerRep register
2361 sz = primRepToSize pk
2363 returnNat (code, reg, sz)
2365 #endif {- i386_TARGET_ARCH -}
2366 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2367 #if sparc_TARGET_ARCH
2369 genCCall fn cconv kind args
2370 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2371 `thenNat` \ ((unused,_), argCode) ->
2373 nRegs = length allArgRegs - length unused
2374 call = CALL fn__2 nRegs False
2375 code = concatOL argCode
2377 returnNat (code `snocOL` call `snocOL` NOP)
2379 -- function names that begin with '.' are assumed to be special
2380 -- internally generated names like '.mul,' which don't get an
2381 -- underscore prefix
2382 -- ToDo:needed (WDP 96/03) ???
2383 fn__2 = case (_HEAD_ fn) of
2384 '.' -> ImmLit (ptext fn)
2385 _ -> ImmLab (ptext fn)
2387 ------------------------------------
2388 {- Try to get a value into a specific register (or registers) for
2389 a call. The SPARC calling convention is an absolute
2390 nightmare. The first 6x32 bits of arguments are mapped into
2391 %o0 through %o5, and the remaining arguments are dumped to the
2392 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2393 first argument is a pair of the list of remaining argument
2394 registers to be assigned for this call and the next stack
2395 offset to use for overflowing arguments. This way,
2396 @get_arg@ can be applied to all of a call's arguments using
2400 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2401 -> StixTree -- Current argument
2402 -> NatM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2404 -- We have to use up all of our argument registers first...
2406 get_arg (dst:dsts, offset) arg
2407 = getRegister arg `thenNat` \ register ->
2408 getNewRegNCG (registerRep register)
2411 reg = if isFloatingRep pk then tmp else dst
2412 code = registerCode register reg
2413 src = registerName register reg
2414 pk = registerRep register
2420 [] -> ( ([], offset + 1),
2422 -- conveniently put the second part in the right stack
2423 -- location, and load the first part into %o5
2424 ST DF src (spRel (offset - 1)) `snocOL`
2425 LD W (spRel (offset - 1)) dst
2428 -> ( (dsts__2, offset),
2430 ST DF src (spRel (-2)) `snocOL`
2431 LD W (spRel (-2)) dst `snocOL`
2432 LD W (spRel (-1)) dst__2
2435 -> ( (dsts, offset),
2437 ST F src (spRel (-2)) `snocOL`
2438 LD W (spRel (-2)) dst
2440 _ -> ( (dsts, offset),
2442 then code `snocOL` OR False g0 (RIReg src) dst
2446 -- Once we have run out of argument registers, we move to the
2449 get_arg ([], offset) arg
2450 = getRegister arg `thenNat` \ register ->
2451 getNewRegNCG (registerRep register)
2454 code = registerCode register tmp
2455 src = registerName register tmp
2456 pk = registerRep register
2457 sz = primRepToSize pk
2458 words = if pk == DoubleRep then 2 else 1
2460 returnNat ( ([], offset + words),
2461 code `snocOL` ST sz src (spRel offset) )
2463 #endif {- sparc_TARGET_ARCH -}
2466 %************************************************************************
2468 \subsection{Support bits}
2470 %************************************************************************
2472 %************************************************************************
2474 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2476 %************************************************************************
2478 Turn those condition codes into integers now (when they appear on
2479 the right hand side of an assignment).
2481 (If applicable) Do not fill the delay slots here; you will confuse the
2485 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> NatM Register
2487 #if alpha_TARGET_ARCH
2488 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2489 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2490 #endif {- alpha_TARGET_ARCH -}
2492 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2493 #if i386_TARGET_ARCH
2496 = condIntCode cond x y `thenNat` \ condition ->
2497 getNewRegNCG IntRep `thenNat` \ tmp ->
2499 code = condCode condition
2500 cond = condName condition
2501 code__2 dst = code `appOL` toOL [
2502 SETCC cond (OpReg tmp),
2503 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2504 MOV L (OpReg tmp) (OpReg dst)]
2506 returnNat (Any IntRep code__2)
2509 = getNatLabelNCG `thenNat` \ lbl1 ->
2510 getNatLabelNCG `thenNat` \ lbl2 ->
2511 condFltCode cond x y `thenNat` \ condition ->
2513 code = condCode condition
2514 cond = condName condition
2515 code__2 dst = code `appOL` toOL [
2517 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2520 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2523 returnNat (Any IntRep code__2)
2525 #endif {- i386_TARGET_ARCH -}
2526 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2527 #if sparc_TARGET_ARCH
2529 condIntReg EQQ x (StInt 0)
2530 = getRegister x `thenNat` \ register ->
2531 getNewRegNCG IntRep `thenNat` \ tmp ->
2533 code = registerCode register tmp
2534 src = registerName register tmp
2535 code__2 dst = code `appOL` toOL [
2536 SUB False True g0 (RIReg src) g0,
2537 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2539 returnNat (Any IntRep code__2)
2542 = getRegister x `thenNat` \ register1 ->
2543 getRegister y `thenNat` \ register2 ->
2544 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2545 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2547 code1 = registerCode register1 tmp1
2548 src1 = registerName register1 tmp1
2549 code2 = registerCode register2 tmp2
2550 src2 = registerName register2 tmp2
2551 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2552 XOR False src1 (RIReg src2) dst,
2553 SUB False True g0 (RIReg dst) g0,
2554 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2556 returnNat (Any IntRep code__2)
2558 condIntReg NE x (StInt 0)
2559 = getRegister x `thenNat` \ register ->
2560 getNewRegNCG IntRep `thenNat` \ tmp ->
2562 code = registerCode register tmp
2563 src = registerName register tmp
2564 code__2 dst = code `appOL` toOL [
2565 SUB False True g0 (RIReg src) g0,
2566 ADD True False g0 (RIImm (ImmInt 0)) dst]
2568 returnNat (Any IntRep code__2)
2571 = getRegister x `thenNat` \ register1 ->
2572 getRegister y `thenNat` \ register2 ->
2573 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2574 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2576 code1 = registerCode register1 tmp1
2577 src1 = registerName register1 tmp1
2578 code2 = registerCode register2 tmp2
2579 src2 = registerName register2 tmp2
2580 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2581 XOR False src1 (RIReg src2) dst,
2582 SUB False True g0 (RIReg dst) g0,
2583 ADD True False g0 (RIImm (ImmInt 0)) dst]
2585 returnNat (Any IntRep code__2)
2588 = getNatLabelNCG `thenNat` \ lbl1 ->
2589 getNatLabelNCG `thenNat` \ lbl2 ->
2590 condIntCode cond x y `thenNat` \ condition ->
2592 code = condCode condition
2593 cond = condName condition
2594 code__2 dst = code `appOL` toOL [
2595 BI cond False (ImmCLbl lbl1), NOP,
2596 OR False g0 (RIImm (ImmInt 0)) dst,
2597 BI ALWAYS False (ImmCLbl lbl2), NOP,
2599 OR False g0 (RIImm (ImmInt 1)) dst,
2602 returnNat (Any IntRep code__2)
2605 = getNatLabelNCG `thenNat` \ lbl1 ->
2606 getNatLabelNCG `thenNat` \ lbl2 ->
2607 condFltCode cond x y `thenNat` \ condition ->
2609 code = condCode condition
2610 cond = condName condition
2611 code__2 dst = code `appOL` toOL [
2613 BF cond False (ImmCLbl lbl1), NOP,
2614 OR False g0 (RIImm (ImmInt 0)) dst,
2615 BI ALWAYS False (ImmCLbl lbl2), NOP,
2617 OR False g0 (RIImm (ImmInt 1)) dst,
2620 returnNat (Any IntRep code__2)
2622 #endif {- sparc_TARGET_ARCH -}
2625 %************************************************************************
2627 \subsubsection{@trivial*Code@: deal with trivial instructions}
2629 %************************************************************************
2631 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2632 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2633 for constants on the right hand side, because that's where the generic
2634 optimizer will have put them.
2636 Similarly, for unary instructions, we don't have to worry about
2637 matching an StInt as the argument, because genericOpt will already
2638 have handled the constant-folding.
2642 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2643 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2644 -> Maybe (Operand -> Operand -> Instr)
2645 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2647 -> StixTree -> StixTree -- the two arguments
2652 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2653 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2654 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2656 -> StixTree -> StixTree -- the two arguments
2660 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2661 ,IF_ARCH_i386 ((Operand -> Instr)
2662 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2664 -> StixTree -- the one argument
2669 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2670 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2671 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2673 -> StixTree -- the one argument
2676 #if alpha_TARGET_ARCH
2678 trivialCode instr x (StInt y)
2680 = getRegister x `thenNat` \ register ->
2681 getNewRegNCG IntRep `thenNat` \ tmp ->
2683 code = registerCode register tmp
2684 src1 = registerName register tmp
2685 src2 = ImmInt (fromInteger y)
2686 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2688 returnNat (Any IntRep code__2)
2690 trivialCode instr x y
2691 = getRegister x `thenNat` \ register1 ->
2692 getRegister y `thenNat` \ register2 ->
2693 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2694 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2696 code1 = registerCode register1 tmp1 []
2697 src1 = registerName register1 tmp1
2698 code2 = registerCode register2 tmp2 []
2699 src2 = registerName register2 tmp2
2700 code__2 dst = asmSeqThen [code1, code2] .
2701 mkSeqInstr (instr src1 (RIReg src2) dst)
2703 returnNat (Any IntRep code__2)
2706 trivialUCode instr x
2707 = getRegister x `thenNat` \ register ->
2708 getNewRegNCG IntRep `thenNat` \ tmp ->
2710 code = registerCode register tmp
2711 src = registerName register tmp
2712 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2714 returnNat (Any IntRep code__2)
2717 trivialFCode _ instr x y
2718 = getRegister x `thenNat` \ register1 ->
2719 getRegister y `thenNat` \ register2 ->
2720 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2721 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2723 code1 = registerCode register1 tmp1
2724 src1 = registerName register1 tmp1
2726 code2 = registerCode register2 tmp2
2727 src2 = registerName register2 tmp2
2729 code__2 dst = asmSeqThen [code1 [], code2 []] .
2730 mkSeqInstr (instr src1 src2 dst)
2732 returnNat (Any DoubleRep code__2)
2734 trivialUFCode _ instr x
2735 = getRegister x `thenNat` \ register ->
2736 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2738 code = registerCode register tmp
2739 src = registerName register tmp
2740 code__2 dst = code . mkSeqInstr (instr src dst)
2742 returnNat (Any DoubleRep code__2)
2744 #endif {- alpha_TARGET_ARCH -}
2745 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2746 #if i386_TARGET_ARCH
2748 The Rules of the Game are:
2750 * You cannot assume anything about the destination register dst;
2751 it may be anything, including a fixed reg.
2753 * You may compute an operand into a fixed reg, but you may not
2754 subsequently change the contents of that fixed reg. If you
2755 want to do so, first copy the value either to a temporary
2756 or into dst. You are free to modify dst even if it happens
2757 to be a fixed reg -- that's not your problem.
2759 * You cannot assume that a fixed reg will stay live over an
2760 arbitrary computation. The same applies to the dst reg.
2762 * Temporary regs obtained from getNewRegNCG are distinct from
2763 each other and from all other regs, and stay live over
2764 arbitrary computations.
2768 trivialCode instr maybe_revinstr a b
2771 = getRegister a `thenNat` \ rega ->
2774 then registerCode rega dst `bind` \ code_a ->
2776 instr (OpImm imm_b) (OpReg dst)
2777 else registerCodeF rega `bind` \ code_a ->
2778 registerNameF rega `bind` \ r_a ->
2780 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2781 instr (OpImm imm_b) (OpReg dst)
2783 returnNat (Any IntRep mkcode)
2786 = getRegister b `thenNat` \ regb ->
2787 getNewRegNCG IntRep `thenNat` \ tmp ->
2788 let revinstr_avail = maybeToBool maybe_revinstr
2789 revinstr = case maybe_revinstr of Just ri -> ri
2793 then registerCode regb dst `bind` \ code_b ->
2795 revinstr (OpImm imm_a) (OpReg dst)
2796 else registerCodeF regb `bind` \ code_b ->
2797 registerNameF regb `bind` \ r_b ->
2799 MOV L (OpReg r_b) (OpReg dst) `snocOL`
2800 revinstr (OpImm imm_a) (OpReg dst)
2804 then registerCode regb tmp `bind` \ code_b ->
2806 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2807 instr (OpReg tmp) (OpReg dst)
2808 else registerCodeF regb `bind` \ code_b ->
2809 registerNameF regb `bind` \ r_b ->
2811 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
2812 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2813 instr (OpReg tmp) (OpReg dst)
2815 returnNat (Any IntRep mkcode)
2818 = getRegister a `thenNat` \ rega ->
2819 getRegister b `thenNat` \ regb ->
2820 getNewRegNCG IntRep `thenNat` \ tmp ->
2822 = case (isAny rega, isAny regb) of
2824 -> registerCode regb tmp `bind` \ code_b ->
2825 registerCode rega dst `bind` \ code_a ->
2828 instr (OpReg tmp) (OpReg dst)
2830 -> registerCode rega tmp `bind` \ code_a ->
2831 registerCodeF regb `bind` \ code_b ->
2832 registerNameF regb `bind` \ r_b ->
2835 instr (OpReg r_b) (OpReg tmp) `snocOL`
2836 MOV L (OpReg tmp) (OpReg dst)
2838 -> registerCode regb tmp `bind` \ code_b ->
2839 registerCodeF rega `bind` \ code_a ->
2840 registerNameF rega `bind` \ r_a ->
2843 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2844 instr (OpReg tmp) (OpReg dst)
2846 -> registerCodeF rega `bind` \ code_a ->
2847 registerNameF rega `bind` \ r_a ->
2848 registerCodeF regb `bind` \ code_b ->
2849 registerNameF regb `bind` \ r_b ->
2851 MOV L (OpReg r_a) (OpReg tmp) `appOL`
2853 instr (OpReg r_b) (OpReg tmp) `snocOL`
2854 MOV L (OpReg tmp) (OpReg dst)
2856 returnNat (Any IntRep mkcode)
2859 maybe_imm_a = maybeImm a
2860 is_imm_a = maybeToBool maybe_imm_a
2861 imm_a = case maybe_imm_a of Just imm -> imm
2863 maybe_imm_b = maybeImm b
2864 is_imm_b = maybeToBool maybe_imm_b
2865 imm_b = case maybe_imm_b of Just imm -> imm
2869 trivialUCode instr x
2870 = getRegister x `thenNat` \ register ->
2872 code__2 dst = let code = registerCode register dst
2873 src = registerName register dst
2875 if isFixed register && dst /= src
2876 then toOL [MOV L (OpReg src) (OpReg dst),
2878 else unitOL (instr (OpReg src))
2880 returnNat (Any IntRep code__2)
2883 trivialFCode pk instr x y
2884 = getRegister x `thenNat` \ register1 ->
2885 getRegister y `thenNat` \ register2 ->
2886 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2887 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2889 code1 = registerCode register1 tmp1
2890 src1 = registerName register1 tmp1
2892 code2 = registerCode register2 tmp2
2893 src2 = registerName register2 tmp2
2896 -- treat the common case specially: both operands in
2898 | isAny register1 && isAny register2
2901 instr (primRepToSize pk) src1 src2 dst
2903 -- be paranoid (and inefficient)
2905 = code1 `snocOL` GMOV src1 tmp1 `appOL`
2907 instr (primRepToSize pk) tmp1 src2 dst
2909 returnNat (Any DoubleRep code__2)
2913 trivialUFCode pk instr x
2914 = getRegister x `thenNat` \ register ->
2915 getNewRegNCG pk `thenNat` \ tmp ->
2917 code = registerCode register tmp
2918 src = registerName register tmp
2919 code__2 dst = code `snocOL` instr src dst
2921 returnNat (Any pk code__2)
2923 #endif {- i386_TARGET_ARCH -}
2924 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2925 #if sparc_TARGET_ARCH
2927 trivialCode instr x (StInt y)
2929 = getRegister x `thenNat` \ register ->
2930 getNewRegNCG IntRep `thenNat` \ tmp ->
2932 code = registerCode register tmp
2933 src1 = registerName register tmp
2934 src2 = ImmInt (fromInteger y)
2935 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
2937 returnNat (Any IntRep code__2)
2939 trivialCode instr x y
2940 = getRegister x `thenNat` \ register1 ->
2941 getRegister y `thenNat` \ register2 ->
2942 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2943 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2945 code1 = registerCode register1 tmp1
2946 src1 = registerName register1 tmp1
2947 code2 = registerCode register2 tmp2
2948 src2 = registerName register2 tmp2
2949 code__2 dst = code1 `appOL` code2 `snocOL`
2950 instr src1 (RIReg src2) dst
2952 returnNat (Any IntRep code__2)
2955 trivialFCode pk instr x y
2956 = getRegister x `thenNat` \ register1 ->
2957 getRegister y `thenNat` \ register2 ->
2958 getNewRegNCG (registerRep register1)
2960 getNewRegNCG (registerRep register2)
2962 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2964 promote x = FxTOy F DF x tmp
2966 pk1 = registerRep register1
2967 code1 = registerCode register1 tmp1
2968 src1 = registerName register1 tmp1
2970 pk2 = registerRep register2
2971 code2 = registerCode register2 tmp2
2972 src2 = registerName register2 tmp2
2976 code1 `appOL` code2 `snocOL`
2977 instr (primRepToSize pk) src1 src2 dst
2978 else if pk1 == FloatRep then
2979 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
2980 instr DF tmp src2 dst
2982 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
2983 instr DF src1 tmp dst
2985 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2988 trivialUCode instr x
2989 = getRegister x `thenNat` \ register ->
2990 getNewRegNCG IntRep `thenNat` \ tmp ->
2992 code = registerCode register tmp
2993 src = registerName register tmp
2994 code__2 dst = code `snocOL` instr (RIReg src) dst
2996 returnNat (Any IntRep code__2)
2999 trivialUFCode pk instr x
3000 = getRegister x `thenNat` \ register ->
3001 getNewRegNCG pk `thenNat` \ tmp ->
3003 code = registerCode register tmp
3004 src = registerName register tmp
3005 code__2 dst = code `snocOL` instr src dst
3007 returnNat (Any pk code__2)
3009 #endif {- sparc_TARGET_ARCH -}
3012 %************************************************************************
3014 \subsubsection{Coercing to/from integer/floating-point...}
3016 %************************************************************************
3018 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3019 to be generated. Here we just change the type on the Register passed
3020 on up. The code is machine-independent.
3022 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3023 conversions. We have to store temporaries in memory to move
3024 between the integer and the floating point register sets.
3027 coerceIntCode :: PrimRep -> StixTree -> NatM Register
3028 coerceFltCode :: StixTree -> NatM Register
3030 coerceInt2FP :: PrimRep -> StixTree -> NatM Register
3031 coerceFP2Int :: StixTree -> NatM Register
3034 = getRegister x `thenNat` \ register ->
3037 Fixed _ reg code -> Fixed pk reg code
3038 Any _ code -> Any pk code
3043 = getRegister x `thenNat` \ register ->
3046 Fixed _ reg code -> Fixed DoubleRep reg code
3047 Any _ code -> Any DoubleRep code
3052 #if alpha_TARGET_ARCH
3055 = getRegister x `thenNat` \ register ->
3056 getNewRegNCG IntRep `thenNat` \ reg ->
3058 code = registerCode register reg
3059 src = registerName register reg
3061 code__2 dst = code . mkSeqInstrs [
3063 LD TF dst (spRel 0),
3066 returnNat (Any DoubleRep code__2)
3070 = getRegister x `thenNat` \ register ->
3071 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3073 code = registerCode register tmp
3074 src = registerName register tmp
3076 code__2 dst = code . mkSeqInstrs [
3078 ST TF tmp (spRel 0),
3081 returnNat (Any IntRep code__2)
3083 #endif {- alpha_TARGET_ARCH -}
3084 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3085 #if i386_TARGET_ARCH
3088 = getRegister x `thenNat` \ register ->
3089 getNewRegNCG IntRep `thenNat` \ reg ->
3091 code = registerCode register reg
3092 src = registerName register reg
3093 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3094 code__2 dst = code `snocOL` opc src dst
3096 returnNat (Any pk code__2)
3100 = getRegister x `thenNat` \ register ->
3101 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3103 code = registerCode register tmp
3104 src = registerName register tmp
3105 pk = registerRep register
3107 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3108 code__2 dst = code `snocOL` opc src dst
3110 returnNat (Any IntRep code__2)
3112 #endif {- i386_TARGET_ARCH -}
3113 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3114 #if sparc_TARGET_ARCH
3117 = getRegister x `thenNat` \ register ->
3118 getNewRegNCG IntRep `thenNat` \ reg ->
3120 code = registerCode register reg
3121 src = registerName register reg
3123 code__2 dst = code `appOL` toOL [
3124 ST W src (spRel (-2)),
3125 LD W (spRel (-2)) dst,
3126 FxTOy W (primRepToSize pk) dst dst]
3128 returnNat (Any pk code__2)
3132 = getRegister x `thenNat` \ register ->
3133 getNewRegNCG IntRep `thenNat` \ reg ->
3134 getNewRegNCG FloatRep `thenNat` \ tmp ->
3136 code = registerCode register reg
3137 src = registerName register reg
3138 pk = registerRep register
3140 code__2 dst = code `appOL` toOL [
3141 FxTOy (primRepToSize pk) W src tmp,
3142 ST W tmp (spRel (-2)),
3143 LD W (spRel (-2)) dst]
3145 returnNat (Any IntRep code__2)
3147 #endif {- sparc_TARGET_ARCH -}
3150 %************************************************************************
3152 \subsubsection{Coercing integer to @Char@...}
3154 %************************************************************************
3156 Integer to character conversion. Where applicable, we try to do this
3157 in one step if the original object is in memory.
3160 chrCode :: StixTree -> NatM Register
3162 #if alpha_TARGET_ARCH
3165 = getRegister x `thenNat` \ register ->
3166 getNewRegNCG IntRep `thenNat` \ reg ->
3168 code = registerCode register reg
3169 src = registerName register reg
3170 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3172 returnNat (Any IntRep code__2)
3174 #endif {- alpha_TARGET_ARCH -}
3175 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3176 #if i386_TARGET_ARCH
3179 = getRegister x `thenNat` \ register ->
3182 code = registerCode register dst
3183 src = registerName register dst
3185 if isFixed register && src /= dst
3186 then toOL [MOV L (OpReg src) (OpReg dst),
3187 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3188 else unitOL (AND L (OpImm (ImmInt 255)) (OpReg src))
3190 returnNat (Any IntRep code__2)
3192 #endif {- i386_TARGET_ARCH -}
3193 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3194 #if sparc_TARGET_ARCH
3196 chrCode (StInd pk mem)
3197 = getAmode mem `thenNat` \ amode ->
3199 code = amodeCode amode
3200 src = amodeAddr amode
3201 src_off = addrOffset src 3
3202 src__2 = case src_off of Just x -> x
3203 code__2 dst = if maybeToBool src_off then
3204 code `snocOL` LD BU src__2 dst
3207 LD (primRepToSize pk) src dst `snocOL`
3208 AND False dst (RIImm (ImmInt 255)) dst
3210 returnNat (Any pk code__2)
3213 = getRegister x `thenNat` \ register ->
3214 getNewRegNCG IntRep `thenNat` \ reg ->
3216 code = registerCode register reg
3217 src = registerName register reg
3218 code__2 dst = code `snocOL` AND False src (RIImm (ImmInt 255)) dst
3220 returnNat (Any IntRep code__2)
3222 #endif {- sparc_TARGET_ARCH -}