2 % (c) The AQUA Project, Glasgow University, 1996-1998
4 \section[MachCode]{Generating machine code}
6 This is a big module, but, if you pay attention to
7 (a) the sectioning, (b) the type signatures, and
8 (c) the \tr{#if blah_TARGET_ARCH} things, the
9 structure should not be too overwhelming.
12 module MachCode ( stmt2Instrs, asmVoid, InstrList ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
20 import AbsCSyn ( MagicId )
21 import AbsCUtils ( magicIdPrimRep )
22 import CallConv ( CallConv )
23 import CLabel ( isAsmTemp, CLabel )
24 import Maybes ( maybeToBool, expectJust )
25 import OrdList -- quite a bit of it
26 import PrimRep ( isFloatingRep, PrimRep(..) )
27 import PrimOp ( PrimOp(..) )
28 import CallConv ( cCallConv )
29 import Stix ( getUniqLabelNCG, StixTree(..),
30 StixReg(..), CodeSegment(..)
32 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
38 Code extractor for an entire stix tree---stix statement level.
41 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
43 stmt2Instrs stmt = case stmt of
44 StComment s -> returnInstr (COMMENT s)
45 StSegment seg -> returnInstr (SEGMENT seg)
46 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
47 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
48 StLabel lab -> returnInstr (LABEL lab)
50 StJump arg -> genJump arg
51 StCondJump lab arg -> genCondJump lab arg
52 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
55 | isFloatingRep pk -> assignFltCode pk dst src
56 | otherwise -> assignIntCode pk dst src
59 -- When falling through on the Alpha, we still have to load pv
60 -- with the address of the next routine, so that it can load gp.
61 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
65 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
66 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
67 (foldr (.) id codes xs))
69 getData :: StixTree -> UniqSM (InstrBlock, Imm)
71 getData (StInt i) = returnUs (id, ImmInteger i)
72 getData (StDouble d) = returnUs (id, dblImmLit d)
73 getData (StLitLbl s) = returnUs (id, ImmLab s)
74 getData (StCLbl l) = returnUs (id, ImmCLbl l)
75 getData (StString s) =
76 getUniqLabelNCG `thenUs` \ lbl ->
77 returnUs (mkSeqInstrs [LABEL lbl,
78 ASCII True (_UNPK_ s)],
80 -- the linker can handle simple arithmetic...
81 getData (StIndex rep (StCLbl lbl) (StInt off)) =
82 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
85 %************************************************************************
87 \subsection{General things for putting together code sequences}
89 %************************************************************************
92 type InstrList = OrdList Instr
93 type InstrBlock = InstrList -> InstrList
98 asmInstr :: Instr -> InstrList
99 asmInstr i = mkUnitList i
101 asmSeq :: [Instr] -> InstrList
102 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
104 asmParThen :: [InstrList] -> InstrBlock
105 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
107 returnInstr :: Instr -> UniqSM InstrBlock
108 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
110 returnInstrs :: [Instr] -> UniqSM InstrBlock
111 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
113 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
114 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
116 mkSeqInstr :: Instr -> InstrBlock
117 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
119 mkSeqInstrs :: [Instr] -> InstrBlock
120 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
124 mangleIndexTree :: StixTree -> StixTree
126 mangleIndexTree (StIndex pk base (StInt i))
127 = StPrim IntAddOp [base, off]
129 off = StInt (i * sizeOf pk)
131 #ifndef i386_TARGET_ARCH
132 mangleIndexTree (StIndex pk base off)
133 = StPrim IntAddOp [base,
139 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
140 StPrim SllOp [off, StInt s]
143 shift DoubleRep = 3::Integer
144 shift _ = IF_ARCH_alpha(3,2)
146 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
147 -- that do include the size of the primitive kind we're addressing. When StIndex
148 -- is expanded to actual code, the index (in units) is by the above code approp.
149 -- shifted to get the no. of bytes. Since Address amodes do contain size info
150 -- explicitly, we disable the shifting for x86s.
151 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
157 maybeImm :: StixTree -> Maybe Imm
159 maybeImm (StLitLbl s) = Just (ImmLab s)
160 maybeImm (StCLbl l) = Just (ImmCLbl l)
162 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
163 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
166 | i >= toInteger minInt && i <= toInteger maxInt
167 = Just (ImmInt (fromInteger i))
169 = Just (ImmInteger i)
174 %************************************************************************
176 \subsection{The @Register@ type}
178 %************************************************************************
180 @Register@s passed up the tree. If the stix code forces the register
181 to live in a pre-decided machine register, it comes out as @Fixed@;
182 otherwise, it comes out as @Any@, and the parent can decide which
183 register to put it in.
187 = Fixed PrimRep Reg InstrBlock
188 | Any PrimRep (Reg -> InstrBlock)
190 registerCode :: Register -> Reg -> InstrBlock
191 registerCode (Fixed _ _ code) reg = code
192 registerCode (Any _ code) reg = code reg
194 registerName :: Register -> Reg -> Reg
195 registerName (Fixed _ reg _) _ = reg
196 registerName (Any _ _) reg = reg
198 registerRep :: Register -> PrimRep
199 registerRep (Fixed pk _ _) = pk
200 registerRep (Any pk _) = pk
202 isFixed :: Register -> Bool
203 isFixed (Fixed _ _ _) = True
204 isFixed (Any _ _) = False
207 Generate code to get a subtree into a @Register@:
209 getRegister :: StixTree -> UniqSM Register
211 getRegister (StReg (StixMagicId stgreg))
212 = case (magicIdRegMaybe stgreg) of
213 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
216 getRegister (StReg (StixTemp u pk))
217 = returnUs (Fixed pk (UnmappedReg u pk) id)
219 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
221 getRegister (StCall fn cconv kind args)
222 = genCCall fn cconv kind args `thenUs` \ call ->
223 returnUs (Fixed kind reg call)
225 reg = if isFloatingRep kind
226 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
227 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
229 getRegister (StString s)
230 = getUniqLabelNCG `thenUs` \ lbl ->
232 imm_lbl = ImmCLbl lbl
234 code dst = mkSeqInstrs [
237 ASCII True (_UNPK_ s),
239 #if alpha_TARGET_ARCH
240 LDA dst (AddrImm imm_lbl)
243 MOV L (OpImm imm_lbl) (OpReg dst)
245 #if sparc_TARGET_ARCH
246 SETHI (HI imm_lbl) dst,
247 OR False dst (RIImm (LO imm_lbl)) dst
251 returnUs (Any PtrRep code)
255 -- end of machine-"independent" bit; here we go on the rest...
257 #if alpha_TARGET_ARCH
259 getRegister (StDouble d)
260 = getUniqLabelNCG `thenUs` \ lbl ->
261 getNewRegNCG PtrRep `thenUs` \ tmp ->
262 let code dst = mkSeqInstrs [
265 DATA TF [ImmLab (rational d)],
267 LDA tmp (AddrImm (ImmCLbl lbl)),
268 LD TF dst (AddrReg tmp)]
270 returnUs (Any DoubleRep code)
272 getRegister (StPrim primop [x]) -- unary PrimOps
274 IntNegOp -> trivialUCode (NEG Q False) x
276 NotOp -> trivialUCode NOT x
278 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
279 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
281 OrdOp -> coerceIntCode IntRep x
284 Float2IntOp -> coerceFP2Int x
285 Int2FloatOp -> coerceInt2FP pr x
286 Double2IntOp -> coerceFP2Int x
287 Int2DoubleOp -> coerceInt2FP pr x
289 Double2FloatOp -> coerceFltCode x
290 Float2DoubleOp -> coerceFltCode x
292 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
294 fn = case other_op of
295 FloatExpOp -> SLIT("exp")
296 FloatLogOp -> SLIT("log")
297 FloatSqrtOp -> SLIT("sqrt")
298 FloatSinOp -> SLIT("sin")
299 FloatCosOp -> SLIT("cos")
300 FloatTanOp -> SLIT("tan")
301 FloatAsinOp -> SLIT("asin")
302 FloatAcosOp -> SLIT("acos")
303 FloatAtanOp -> SLIT("atan")
304 FloatSinhOp -> SLIT("sinh")
305 FloatCoshOp -> SLIT("cosh")
306 FloatTanhOp -> SLIT("tanh")
307 DoubleExpOp -> SLIT("exp")
308 DoubleLogOp -> SLIT("log")
309 DoubleSqrtOp -> SLIT("sqrt")
310 DoubleSinOp -> SLIT("sin")
311 DoubleCosOp -> SLIT("cos")
312 DoubleTanOp -> SLIT("tan")
313 DoubleAsinOp -> SLIT("asin")
314 DoubleAcosOp -> SLIT("acos")
315 DoubleAtanOp -> SLIT("atan")
316 DoubleSinhOp -> SLIT("sinh")
317 DoubleCoshOp -> SLIT("cosh")
318 DoubleTanhOp -> SLIT("tanh")
320 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
322 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
324 CharGtOp -> trivialCode (CMP LTT) y x
325 CharGeOp -> trivialCode (CMP LE) y x
326 CharEqOp -> trivialCode (CMP EQQ) x y
327 CharNeOp -> int_NE_code x y
328 CharLtOp -> trivialCode (CMP LTT) x y
329 CharLeOp -> trivialCode (CMP LE) x y
331 IntGtOp -> trivialCode (CMP LTT) y x
332 IntGeOp -> trivialCode (CMP LE) y x
333 IntEqOp -> trivialCode (CMP EQQ) x y
334 IntNeOp -> int_NE_code x y
335 IntLtOp -> trivialCode (CMP LTT) x y
336 IntLeOp -> trivialCode (CMP LE) x y
338 WordGtOp -> trivialCode (CMP ULT) y x
339 WordGeOp -> trivialCode (CMP ULE) x y
340 WordEqOp -> trivialCode (CMP EQQ) x y
341 WordNeOp -> int_NE_code x y
342 WordLtOp -> trivialCode (CMP ULT) x y
343 WordLeOp -> trivialCode (CMP ULE) x y
345 AddrGtOp -> trivialCode (CMP ULT) y x
346 AddrGeOp -> trivialCode (CMP ULE) y x
347 AddrEqOp -> trivialCode (CMP EQQ) x y
348 AddrNeOp -> int_NE_code x y
349 AddrLtOp -> trivialCode (CMP ULT) x y
350 AddrLeOp -> trivialCode (CMP ULE) x y
352 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
353 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
354 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
355 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
356 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
357 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
359 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
360 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
361 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
362 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
363 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
364 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
366 IntAddOp -> trivialCode (ADD Q False) x y
367 IntSubOp -> trivialCode (SUB Q False) x y
368 IntMulOp -> trivialCode (MUL Q False) x y
369 IntQuotOp -> trivialCode (DIV Q False) x y
370 IntRemOp -> trivialCode (REM Q False) x y
372 WordQuotOp -> trivialCode (DIV Q True) x y
373 WordRemOp -> trivialCode (REM Q True) x y
375 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
376 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
377 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
378 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
380 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
381 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
382 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
383 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
385 AndOp -> trivialCode AND x y
386 OrOp -> trivialCode OR x y
387 XorOp -> trivialCode XOR x y
388 SllOp -> trivialCode SLL x y
389 SrlOp -> trivialCode SRL x y
391 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
392 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
393 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
395 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
396 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
398 {- ------------------------------------------------------------
399 Some bizarre special code for getting condition codes into
400 registers. Integer non-equality is a test for equality
401 followed by an XOR with 1. (Integer comparisons always set
402 the result register to 0 or 1.) Floating point comparisons of
403 any kind leave the result in a floating point register, so we
404 need to wrangle an integer register out of things.
406 int_NE_code :: StixTree -> StixTree -> UniqSM Register
409 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
410 getNewRegNCG IntRep `thenUs` \ tmp ->
412 code = registerCode register tmp
413 src = registerName register tmp
414 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
416 returnUs (Any IntRep code__2)
418 {- ------------------------------------------------------------
419 Comments for int_NE_code also apply to cmpF_code
422 :: (Reg -> Reg -> Reg -> Instr)
424 -> StixTree -> StixTree
427 cmpF_code instr cond x y
428 = trivialFCode pr instr x y `thenUs` \ register ->
429 getNewRegNCG DoubleRep `thenUs` \ tmp ->
430 getUniqLabelNCG `thenUs` \ lbl ->
432 code = registerCode register tmp
433 result = registerName register tmp
435 code__2 dst = code . mkSeqInstrs [
436 OR zeroh (RIImm (ImmInt 1)) dst,
437 BF cond result (ImmCLbl lbl),
438 OR zeroh (RIReg zeroh) dst,
441 returnUs (Any IntRep code__2)
443 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
444 ------------------------------------------------------------
446 getRegister (StInd pk mem)
447 = getAmode mem `thenUs` \ amode ->
449 code = amodeCode amode
450 src = amodeAddr amode
451 size = primRepToSize pk
452 code__2 dst = code . mkSeqInstr (LD size dst src)
454 returnUs (Any pk code__2)
456 getRegister (StInt i)
459 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
461 returnUs (Any IntRep code)
464 code dst = mkSeqInstr (LDI Q dst src)
466 returnUs (Any IntRep code)
468 src = ImmInt (fromInteger i)
473 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
475 returnUs (Any PtrRep code)
478 imm__2 = case imm of Just x -> x
480 #endif {- alpha_TARGET_ARCH -}
481 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
484 getRegister (StDouble 0.0)
486 code dst = mkSeqInstrs [FLDZ]
488 returnUs (Any DoubleRep code)
490 getRegister (StDouble 1.0)
492 code dst = mkSeqInstrs [FLD1]
494 returnUs (Any DoubleRep code)
496 getRegister (StDouble d)
497 = getUniqLabelNCG `thenUs` \ lbl ->
498 --getNewRegNCG PtrRep `thenUs` \ tmp ->
499 let code dst = mkSeqInstrs [
502 DATA DF [dblImmLit d],
504 FLD DF (OpImm (ImmCLbl lbl))
507 returnUs (Any DoubleRep code)
509 getRegister (StPrim primop [x]) -- unary PrimOps
511 IntNegOp -> trivialUCode (NEGI L) x
513 NotOp -> trivialUCode (NOT L) x
515 FloatNegOp -> trivialUFCode FloatRep FCHS x
516 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
517 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
519 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
521 OrdOp -> coerceIntCode IntRep x
524 Float2IntOp -> coerceFP2Int x
525 Int2FloatOp -> coerceInt2FP FloatRep x
526 Double2IntOp -> coerceFP2Int x
527 Int2DoubleOp -> coerceInt2FP DoubleRep x
529 Double2FloatOp -> coerceFltCode x
530 Float2DoubleOp -> coerceFltCode x
534 fixed_x = if is_float_op -- promote to double
535 then StPrim Float2DoubleOp [x]
538 getRegister (StCall fn cCallConv DoubleRep [x])
542 FloatExpOp -> (True, SLIT("exp"))
543 FloatLogOp -> (True, SLIT("log"))
545 FloatSinOp -> (True, SLIT("sin"))
546 FloatCosOp -> (True, SLIT("cos"))
547 FloatTanOp -> (True, SLIT("tan"))
549 FloatAsinOp -> (True, SLIT("asin"))
550 FloatAcosOp -> (True, SLIT("acos"))
551 FloatAtanOp -> (True, SLIT("atan"))
553 FloatSinhOp -> (True, SLIT("sinh"))
554 FloatCoshOp -> (True, SLIT("cosh"))
555 FloatTanhOp -> (True, SLIT("tanh"))
557 DoubleExpOp -> (False, SLIT("exp"))
558 DoubleLogOp -> (False, SLIT("log"))
560 DoubleSinOp -> (False, SLIT("sin"))
561 DoubleCosOp -> (False, SLIT("cos"))
562 DoubleTanOp -> (False, SLIT("tan"))
564 DoubleAsinOp -> (False, SLIT("asin"))
565 DoubleAcosOp -> (False, SLIT("acos"))
566 DoubleAtanOp -> (False, SLIT("atan"))
568 DoubleSinhOp -> (False, SLIT("sinh"))
569 DoubleCoshOp -> (False, SLIT("cosh"))
570 DoubleTanhOp -> (False, SLIT("tanh"))
572 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
574 CharGtOp -> condIntReg GTT x y
575 CharGeOp -> condIntReg GE x y
576 CharEqOp -> condIntReg EQQ x y
577 CharNeOp -> condIntReg NE x y
578 CharLtOp -> condIntReg LTT x y
579 CharLeOp -> condIntReg LE x y
581 IntGtOp -> condIntReg GTT x y
582 IntGeOp -> condIntReg GE x y
583 IntEqOp -> condIntReg EQQ x y
584 IntNeOp -> condIntReg NE x y
585 IntLtOp -> condIntReg LTT x y
586 IntLeOp -> condIntReg LE x y
588 WordGtOp -> condIntReg GU x y
589 WordGeOp -> condIntReg GEU x y
590 WordEqOp -> condIntReg EQQ x y
591 WordNeOp -> condIntReg NE x y
592 WordLtOp -> condIntReg LU x y
593 WordLeOp -> condIntReg LEU x y
595 AddrGtOp -> condIntReg GU x y
596 AddrGeOp -> condIntReg GEU x y
597 AddrEqOp -> condIntReg EQQ x y
598 AddrNeOp -> condIntReg NE x y
599 AddrLtOp -> condIntReg LU x y
600 AddrLeOp -> condIntReg LEU x y
602 FloatGtOp -> condFltReg GTT x y
603 FloatGeOp -> condFltReg GE x y
604 FloatEqOp -> condFltReg EQQ x y
605 FloatNeOp -> condFltReg NE x y
606 FloatLtOp -> condFltReg LTT x y
607 FloatLeOp -> condFltReg LE x y
609 DoubleGtOp -> condFltReg GTT x y
610 DoubleGeOp -> condFltReg GE x y
611 DoubleEqOp -> condFltReg EQQ x y
612 DoubleNeOp -> condFltReg NE x y
613 DoubleLtOp -> condFltReg LTT x y
614 DoubleLeOp -> condFltReg LE x y
616 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
617 -- this should be optimised by the generic Opts,
618 -- I don't know why it is not (sometimes)!
620 [x, StInt 0] -> getRegister x
625 IntSubOp -> sub_code L x y
626 IntQuotOp -> quot_code L x y True{-division-}
627 IntRemOp -> quot_code L x y False{-remainder-}
628 IntMulOp -> trivialCode (IMUL L) x y {-True-}
630 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
631 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
632 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
633 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
635 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
636 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
637 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
638 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
640 AndOp -> trivialCode (AND L) x y {-True-}
641 OrOp -> trivialCode (OR L) x y {-True-}
642 XorOp -> trivialCode (XOR L) x y {-True-}
644 {- Shift ops on x86s have constraints on their source, it
645 either has to be Imm, CL or 1
646 => trivialCode's is not restrictive enough (sigh.)
649 SllOp -> shift_code (SHL L) x y {-False-}
650 SrlOp -> shift_code (SHR L) x y {-False-}
652 ISllOp -> shift_code (SHL L) x y {-False-} --was:panic "I386Gen:isll"
653 ISraOp -> shift_code (SAR L) x y {-False-} --was:panic "I386Gen:isra"
654 ISrlOp -> shift_code (SHR L) x y {-False-} --was:panic "I386Gen:isrl"
656 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
657 where promote x = StPrim Float2DoubleOp [x]
658 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
660 shift_code :: (Operand -> Operand -> Instr)
664 {- Case1: shift length as immediate -}
665 -- Code is the same as the first eq. for trivialCode -- sigh.
666 shift_code instr x y{-amount-}
668 = getRegister x `thenUs` \ register ->
670 op_imm = OpImm imm__2
673 code = registerCode register dst
674 src = registerName register dst
676 mkSeqInstr (COMMENT SLIT("shift_code")) .
678 if isFixed register && src /= dst
680 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
681 instr op_imm (OpReg dst)]
683 mkSeqInstr (instr op_imm (OpReg src))
685 returnUs (Any IntRep code__2)
688 imm__2 = case imm of Just x -> x
690 {- Case2: shift length is complex (non-immediate) -}
691 shift_code instr x y{-amount-}
692 = getRegister y `thenUs` \ register1 ->
693 getRegister x `thenUs` \ register2 ->
694 -- getNewRegNCG IntRep `thenUs` \ dst ->
696 -- Note: we force the shift length to be loaded
697 -- into ECX, so that we can use CL when shifting.
698 -- (only register location we are allowed
699 -- to put shift amounts.)
701 -- The shift instruction is fed ECX as src reg,
702 -- but we coerce this into CL when printing out.
703 src1 = registerName register1 ecx
704 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
705 registerCode register1 ecx .
706 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
708 registerCode register1 ecx
711 code2 = registerCode register2 eax
712 src2 = registerName register2 eax
715 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
717 returnUs (Fixed IntRep eax code__2)
719 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
721 add_code sz x (StInt y)
722 = getRegister x `thenUs` \ register ->
723 getNewRegNCG IntRep `thenUs` \ tmp ->
725 code = registerCode register tmp
726 src1 = registerName register tmp
727 src2 = ImmInt (fromInteger y)
729 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
731 returnUs (Any IntRep code__2)
733 add_code sz x (StInd _ mem)
734 = getRegister x `thenUs` \ register1 ->
735 --getNewRegNCG (registerRep register1)
736 -- `thenUs` \ tmp1 ->
737 getAmode mem `thenUs` \ amode ->
739 code2 = amodeCode amode
740 src2 = amodeAddr amode
742 code__2 dst = let code1 = registerCode register1 dst
743 src1 = registerName register1 dst
744 in asmParThen [code2 asmVoid,code1 asmVoid] .
745 if isFixed register1 && src1 /= dst
746 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
747 ADD sz (OpAddr src2) (OpReg dst)]
749 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
751 returnUs (Any IntRep code__2)
753 add_code sz (StInd _ mem) y
754 = getRegister y `thenUs` \ register2 ->
755 --getNewRegNCG (registerRep register2)
756 -- `thenUs` \ tmp2 ->
757 getAmode mem `thenUs` \ amode ->
759 code1 = amodeCode amode
760 src1 = amodeAddr amode
762 code__2 dst = let code2 = registerCode register2 dst
763 src2 = registerName register2 dst
764 in asmParThen [code1 asmVoid,code2 asmVoid] .
765 if isFixed register2 && src2 /= dst
766 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
767 ADD sz (OpAddr src1) (OpReg dst)]
769 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
771 returnUs (Any IntRep code__2)
774 = getRegister x `thenUs` \ register1 ->
775 getRegister y `thenUs` \ register2 ->
776 getNewRegNCG IntRep `thenUs` \ tmp1 ->
777 getNewRegNCG IntRep `thenUs` \ tmp2 ->
779 code1 = registerCode register1 tmp1 asmVoid
780 src1 = registerName register1 tmp1
781 code2 = registerCode register2 tmp2 asmVoid
782 src2 = registerName register2 tmp2
783 code__2 dst = asmParThen [code1, code2] .
784 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
786 returnUs (Any IntRep code__2)
789 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
791 sub_code sz x (StInt y)
792 = getRegister x `thenUs` \ register ->
793 getNewRegNCG IntRep `thenUs` \ tmp ->
795 code = registerCode register tmp
796 src1 = registerName register tmp
797 src2 = ImmInt (-(fromInteger y))
799 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
801 returnUs (Any IntRep code__2)
803 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
808 -> StixTree -> StixTree
809 -> Bool -- True => division, False => remainder operation
812 -- x must go into eax, edx must be a sign-extension of eax, and y
813 -- should go in some other register (or memory), so that we get
814 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
815 -- put y in memory (if it is not there already)
817 quot_code sz x (StInd pk mem) is_division
818 = getRegister x `thenUs` \ register1 ->
819 getNewRegNCG IntRep `thenUs` \ tmp1 ->
820 getAmode mem `thenUs` \ amode ->
822 code1 = registerCode register1 tmp1 asmVoid
823 src1 = registerName register1 tmp1
824 code2 = amodeCode amode asmVoid
825 src2 = amodeAddr amode
826 code__2 = asmParThen [code1, code2] .
827 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
829 IDIV sz (OpAddr src2)]
831 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
833 quot_code sz x (StInt i) is_division
834 = getRegister x `thenUs` \ register1 ->
835 getNewRegNCG IntRep `thenUs` \ tmp1 ->
837 code1 = registerCode register1 tmp1 asmVoid
838 src1 = registerName register1 tmp1
839 src2 = ImmInt (fromInteger i)
840 code__2 = asmParThen [code1] .
841 mkSeqInstrs [-- we put src2 in (ebx)
842 MOV L (OpImm src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
843 MOV L (OpReg src1) (OpReg eax),
845 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
847 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
849 quot_code sz x y is_division
850 = getRegister x `thenUs` \ register1 ->
851 getNewRegNCG IntRep `thenUs` \ tmp1 ->
852 getRegister y `thenUs` \ register2 ->
853 getNewRegNCG IntRep `thenUs` \ tmp2 ->
855 code1 = registerCode register1 tmp1 asmVoid
856 src1 = registerName register1 tmp1
857 code2 = registerCode register2 tmp2 asmVoid
858 src2 = registerName register2 tmp2
859 code__2 = asmParThen [code1, code2] .
860 if src2 == ecx || src2 == esi
861 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
863 IDIV sz (OpReg src2)]
864 else mkSeqInstrs [ -- we put src2 in (ebx)
865 MOV L (OpReg src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
866 MOV L (OpReg src1) (OpReg eax),
868 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
870 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
871 -----------------------
873 getRegister (StInd pk mem)
874 = getAmode mem `thenUs` \ amode ->
876 code = amodeCode amode
877 src = amodeAddr amode
878 size = primRepToSize pk
880 if pk == DoubleRep || pk == FloatRep
881 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
882 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
884 returnUs (Any pk code__2)
887 getRegister (StInt i)
889 src = ImmInt (fromInteger i)
890 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
892 returnUs (Any IntRep code)
897 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
899 returnUs (Any PtrRep code)
902 imm__2 = case imm of Just x -> x
904 #endif {- i386_TARGET_ARCH -}
905 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
906 #if sparc_TARGET_ARCH
908 getRegister (StDouble d)
909 = getUniqLabelNCG `thenUs` \ lbl ->
910 getNewRegNCG PtrRep `thenUs` \ tmp ->
911 let code dst = mkSeqInstrs [
914 DATA DF [dblImmLit d],
916 SETHI (HI (ImmCLbl lbl)) tmp,
917 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
919 returnUs (Any DoubleRep code)
921 getRegister (StPrim primop [x]) -- unary PrimOps
923 IntNegOp -> trivialUCode (SUB False False g0) x
924 NotOp -> trivialUCode (XNOR False g0) x
926 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
928 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
930 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
931 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
933 OrdOp -> coerceIntCode IntRep x
936 Float2IntOp -> coerceFP2Int x
937 Int2FloatOp -> coerceInt2FP FloatRep x
938 Double2IntOp -> coerceFP2Int x
939 Int2DoubleOp -> coerceInt2FP DoubleRep x
943 fixed_x = if is_float_op -- promote to double
944 then StPrim Float2DoubleOp [x]
947 getRegister (StCall fn cCallConv DoubleRep [x])
951 FloatExpOp -> (True, SLIT("exp"))
952 FloatLogOp -> (True, SLIT("log"))
953 FloatSqrtOp -> (True, SLIT("sqrt"))
955 FloatSinOp -> (True, SLIT("sin"))
956 FloatCosOp -> (True, SLIT("cos"))
957 FloatTanOp -> (True, SLIT("tan"))
959 FloatAsinOp -> (True, SLIT("asin"))
960 FloatAcosOp -> (True, SLIT("acos"))
961 FloatAtanOp -> (True, SLIT("atan"))
963 FloatSinhOp -> (True, SLIT("sinh"))
964 FloatCoshOp -> (True, SLIT("cosh"))
965 FloatTanhOp -> (True, SLIT("tanh"))
967 DoubleExpOp -> (False, SLIT("exp"))
968 DoubleLogOp -> (False, SLIT("log"))
969 DoubleSqrtOp -> (True, SLIT("sqrt"))
971 DoubleSinOp -> (False, SLIT("sin"))
972 DoubleCosOp -> (False, SLIT("cos"))
973 DoubleTanOp -> (False, SLIT("tan"))
975 DoubleAsinOp -> (False, SLIT("asin"))
976 DoubleAcosOp -> (False, SLIT("acos"))
977 DoubleAtanOp -> (False, SLIT("atan"))
979 DoubleSinhOp -> (False, SLIT("sinh"))
980 DoubleCoshOp -> (False, SLIT("cosh"))
981 DoubleTanhOp -> (False, SLIT("tanh"))
982 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
984 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
986 CharGtOp -> condIntReg GTT x y
987 CharGeOp -> condIntReg GE x y
988 CharEqOp -> condIntReg EQQ x y
989 CharNeOp -> condIntReg NE x y
990 CharLtOp -> condIntReg LTT x y
991 CharLeOp -> condIntReg LE x y
993 IntGtOp -> condIntReg GTT x y
994 IntGeOp -> condIntReg GE x y
995 IntEqOp -> condIntReg EQQ x y
996 IntNeOp -> condIntReg NE x y
997 IntLtOp -> condIntReg LTT x y
998 IntLeOp -> condIntReg LE x y
1000 WordGtOp -> condIntReg GU x y
1001 WordGeOp -> condIntReg GEU x y
1002 WordEqOp -> condIntReg EQQ x y
1003 WordNeOp -> condIntReg NE x y
1004 WordLtOp -> condIntReg LU x y
1005 WordLeOp -> condIntReg LEU x y
1007 AddrGtOp -> condIntReg GU x y
1008 AddrGeOp -> condIntReg GEU x y
1009 AddrEqOp -> condIntReg EQQ x y
1010 AddrNeOp -> condIntReg NE x y
1011 AddrLtOp -> condIntReg LU x y
1012 AddrLeOp -> condIntReg LEU x y
1014 FloatGtOp -> condFltReg GTT x y
1015 FloatGeOp -> condFltReg GE x y
1016 FloatEqOp -> condFltReg EQQ x y
1017 FloatNeOp -> condFltReg NE x y
1018 FloatLtOp -> condFltReg LTT x y
1019 FloatLeOp -> condFltReg LE x y
1021 DoubleGtOp -> condFltReg GTT x y
1022 DoubleGeOp -> condFltReg GE x y
1023 DoubleEqOp -> condFltReg EQQ x y
1024 DoubleNeOp -> condFltReg NE x y
1025 DoubleLtOp -> condFltReg LTT x y
1026 DoubleLeOp -> condFltReg LE x y
1028 IntAddOp -> trivialCode (ADD False False) x y
1029 IntSubOp -> trivialCode (SUB False False) x y
1031 -- ToDo: teach about V8+ SPARC mul/div instructions
1032 IntMulOp -> imul_div SLIT(".umul") x y
1033 IntQuotOp -> imul_div SLIT(".div") x y
1034 IntRemOp -> imul_div SLIT(".rem") x y
1036 FloatAddOp -> trivialFCode FloatRep FADD x y
1037 FloatSubOp -> trivialFCode FloatRep FSUB x y
1038 FloatMulOp -> trivialFCode FloatRep FMUL x y
1039 FloatDivOp -> trivialFCode FloatRep FDIV x y
1041 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1042 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1043 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1044 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1046 AndOp -> trivialCode (AND False) x y
1047 OrOp -> trivialCode (OR False) x y
1048 XorOp -> trivialCode (XOR False) x y
1049 SllOp -> trivialCode SLL x y
1050 SrlOp -> trivialCode SRL x y
1052 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1053 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1054 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1056 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1057 where promote x = StPrim Float2DoubleOp [x]
1058 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1059 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1061 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1063 getRegister (StInd pk mem)
1064 = getAmode mem `thenUs` \ amode ->
1066 code = amodeCode amode
1067 src = amodeAddr amode
1068 size = primRepToSize pk
1069 code__2 dst = code . mkSeqInstr (LD size src dst)
1071 returnUs (Any pk code__2)
1073 getRegister (StInt i)
1076 src = ImmInt (fromInteger i)
1077 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1079 returnUs (Any IntRep code)
1084 code dst = mkSeqInstrs [
1085 SETHI (HI imm__2) dst,
1086 OR False dst (RIImm (LO imm__2)) dst]
1088 returnUs (Any PtrRep code)
1091 imm__2 = case imm of Just x -> x
1093 #endif {- sparc_TARGET_ARCH -}
1096 %************************************************************************
1098 \subsection{The @Amode@ type}
1100 %************************************************************************
1102 @Amode@s: Memory addressing modes passed up the tree.
1104 data Amode = Amode MachRegsAddr InstrBlock
1106 amodeAddr (Amode addr _) = addr
1107 amodeCode (Amode _ code) = code
1110 Now, given a tree (the argument to an StInd) that references memory,
1111 produce a suitable addressing mode.
1114 getAmode :: StixTree -> UniqSM Amode
1116 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1118 #if alpha_TARGET_ARCH
1120 getAmode (StPrim IntSubOp [x, StInt i])
1121 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1122 getRegister x `thenUs` \ register ->
1124 code = registerCode register tmp
1125 reg = registerName register tmp
1126 off = ImmInt (-(fromInteger i))
1128 returnUs (Amode (AddrRegImm reg off) code)
1130 getAmode (StPrim IntAddOp [x, StInt i])
1131 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1132 getRegister x `thenUs` \ register ->
1134 code = registerCode register tmp
1135 reg = registerName register tmp
1136 off = ImmInt (fromInteger i)
1138 returnUs (Amode (AddrRegImm reg off) code)
1142 = returnUs (Amode (AddrImm imm__2) id)
1145 imm__2 = case imm of Just x -> x
1148 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1149 getRegister other `thenUs` \ register ->
1151 code = registerCode register tmp
1152 reg = registerName register tmp
1154 returnUs (Amode (AddrReg reg) code)
1156 #endif {- alpha_TARGET_ARCH -}
1157 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1158 #if i386_TARGET_ARCH
1160 getAmode (StPrim IntSubOp [x, StInt i])
1161 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1162 getRegister x `thenUs` \ register ->
1164 code = registerCode register tmp
1165 reg = registerName register tmp
1166 off = ImmInt (-(fromInteger i))
1168 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1170 getAmode (StPrim IntAddOp [x, StInt i])
1173 code = mkSeqInstrs []
1175 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1178 imm__2 = case imm of Just x -> x
1180 getAmode (StPrim IntAddOp [x, StInt i])
1181 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1182 getRegister x `thenUs` \ register ->
1184 code = registerCode register tmp
1185 reg = registerName register tmp
1186 off = ImmInt (fromInteger i)
1188 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1190 getAmode (StPrim IntAddOp [x, y])
1191 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1192 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1193 getRegister x `thenUs` \ register1 ->
1194 getRegister y `thenUs` \ register2 ->
1196 code1 = registerCode register1 tmp1 asmVoid
1197 reg1 = registerName register1 tmp1
1198 code2 = registerCode register2 tmp2 asmVoid
1199 reg2 = registerName register2 tmp2
1200 code__2 = asmParThen [code1, code2]
1202 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1207 code = mkSeqInstrs []
1209 returnUs (Amode (ImmAddr imm__2 0) code)
1212 imm__2 = case imm of Just x -> x
1215 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1216 getRegister other `thenUs` \ register ->
1218 code = registerCode register tmp
1219 reg = registerName register tmp
1222 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1224 #endif {- i386_TARGET_ARCH -}
1225 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1226 #if sparc_TARGET_ARCH
1228 getAmode (StPrim IntSubOp [x, StInt i])
1230 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1231 getRegister x `thenUs` \ register ->
1233 code = registerCode register tmp
1234 reg = registerName register tmp
1235 off = ImmInt (-(fromInteger i))
1237 returnUs (Amode (AddrRegImm reg off) code)
1240 getAmode (StPrim IntAddOp [x, StInt i])
1242 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1243 getRegister x `thenUs` \ register ->
1245 code = registerCode register tmp
1246 reg = registerName register tmp
1247 off = ImmInt (fromInteger i)
1249 returnUs (Amode (AddrRegImm reg off) code)
1251 getAmode (StPrim IntAddOp [x, y])
1252 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1253 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1254 getRegister x `thenUs` \ register1 ->
1255 getRegister y `thenUs` \ register2 ->
1257 code1 = registerCode register1 tmp1 asmVoid
1258 reg1 = registerName register1 tmp1
1259 code2 = registerCode register2 tmp2 asmVoid
1260 reg2 = registerName register2 tmp2
1261 code__2 = asmParThen [code1, code2]
1263 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1267 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1269 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1271 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1274 imm__2 = case imm of Just x -> x
1277 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1278 getRegister other `thenUs` \ register ->
1280 code = registerCode register tmp
1281 reg = registerName register tmp
1284 returnUs (Amode (AddrRegImm reg off) code)
1286 #endif {- sparc_TARGET_ARCH -}
1289 %************************************************************************
1291 \subsection{The @CondCode@ type}
1293 %************************************************************************
1295 Condition codes passed up the tree.
1297 data CondCode = CondCode Bool Cond InstrBlock
1299 condName (CondCode _ cond _) = cond
1300 condFloat (CondCode is_float _ _) = is_float
1301 condCode (CondCode _ _ code) = code
1304 Set up a condition code for a conditional branch.
1307 getCondCode :: StixTree -> UniqSM CondCode
1309 #if alpha_TARGET_ARCH
1310 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1311 #endif {- alpha_TARGET_ARCH -}
1312 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1314 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1315 -- yes, they really do seem to want exactly the same!
1317 getCondCode (StPrim primop [x, y])
1319 CharGtOp -> condIntCode GTT x y
1320 CharGeOp -> condIntCode GE x y
1321 CharEqOp -> condIntCode EQQ x y
1322 CharNeOp -> condIntCode NE x y
1323 CharLtOp -> condIntCode LTT x y
1324 CharLeOp -> condIntCode LE x y
1326 IntGtOp -> condIntCode GTT x y
1327 IntGeOp -> condIntCode GE x y
1328 IntEqOp -> condIntCode EQQ x y
1329 IntNeOp -> condIntCode NE x y
1330 IntLtOp -> condIntCode LTT x y
1331 IntLeOp -> condIntCode LE x y
1333 WordGtOp -> condIntCode GU x y
1334 WordGeOp -> condIntCode GEU x y
1335 WordEqOp -> condIntCode EQQ x y
1336 WordNeOp -> condIntCode NE x y
1337 WordLtOp -> condIntCode LU x y
1338 WordLeOp -> condIntCode LEU x y
1340 AddrGtOp -> condIntCode GU x y
1341 AddrGeOp -> condIntCode GEU x y
1342 AddrEqOp -> condIntCode EQQ x y
1343 AddrNeOp -> condIntCode NE x y
1344 AddrLtOp -> condIntCode LU x y
1345 AddrLeOp -> condIntCode LEU x y
1347 FloatGtOp -> condFltCode GTT x y
1348 FloatGeOp -> condFltCode GE x y
1349 FloatEqOp -> condFltCode EQQ x y
1350 FloatNeOp -> condFltCode NE x y
1351 FloatLtOp -> condFltCode LTT x y
1352 FloatLeOp -> condFltCode LE x y
1354 DoubleGtOp -> condFltCode GTT x y
1355 DoubleGeOp -> condFltCode GE x y
1356 DoubleEqOp -> condFltCode EQQ x y
1357 DoubleNeOp -> condFltCode NE x y
1358 DoubleLtOp -> condFltCode LTT x y
1359 DoubleLeOp -> condFltCode LE x y
1361 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1366 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1367 passed back up the tree.
1370 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1372 #if alpha_TARGET_ARCH
1373 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1374 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1375 #endif {- alpha_TARGET_ARCH -}
1377 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1378 #if i386_TARGET_ARCH
1380 condIntCode cond (StInd _ x) y
1382 = getAmode x `thenUs` \ amode ->
1384 code1 = amodeCode amode asmVoid
1385 y__2 = amodeAddr amode
1386 code__2 = asmParThen [code1] .
1387 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1389 returnUs (CondCode False cond code__2)
1392 imm__2 = case imm of Just x -> x
1394 condIntCode cond x (StInt 0)
1395 = getRegister x `thenUs` \ register1 ->
1396 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1398 code1 = registerCode register1 tmp1 asmVoid
1399 src1 = registerName register1 tmp1
1400 code__2 = asmParThen [code1] .
1401 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1403 returnUs (CondCode False cond code__2)
1405 condIntCode cond x y
1407 = getRegister x `thenUs` \ register1 ->
1408 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1410 code1 = registerCode register1 tmp1 asmVoid
1411 src1 = registerName register1 tmp1
1412 code__2 = asmParThen [code1] .
1413 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1415 returnUs (CondCode False cond code__2)
1418 imm__2 = case imm of Just x -> x
1420 condIntCode cond (StInd _ x) y
1421 = getAmode x `thenUs` \ amode ->
1422 getRegister y `thenUs` \ register2 ->
1423 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1425 code1 = amodeCode amode asmVoid
1426 src1 = amodeAddr amode
1427 code2 = registerCode register2 tmp2 asmVoid
1428 src2 = registerName register2 tmp2
1429 code__2 = asmParThen [code1, code2] .
1430 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1432 returnUs (CondCode False cond code__2)
1434 condIntCode cond y (StInd _ x)
1435 = getAmode x `thenUs` \ amode ->
1436 getRegister y `thenUs` \ register2 ->
1437 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1439 code1 = amodeCode amode asmVoid
1440 src1 = amodeAddr amode
1441 code2 = registerCode register2 tmp2 asmVoid
1442 src2 = registerName register2 tmp2
1443 code__2 = asmParThen [code1, code2] .
1444 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1446 returnUs (CondCode False cond code__2)
1448 condIntCode cond x y
1449 = getRegister x `thenUs` \ register1 ->
1450 getRegister y `thenUs` \ register2 ->
1451 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1452 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1454 code1 = registerCode register1 tmp1 asmVoid
1455 src1 = registerName register1 tmp1
1456 code2 = registerCode register2 tmp2 asmVoid
1457 src2 = registerName register2 tmp2
1458 code__2 = asmParThen [code1, code2] .
1459 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1461 returnUs (CondCode False cond code__2)
1465 condFltCode cond x (StDouble 0.0)
1466 = getRegister x `thenUs` \ register1 ->
1467 getNewRegNCG (registerRep register1)
1470 pk1 = registerRep register1
1471 code1 = registerCode register1 tmp1
1472 src1 = registerName register1 tmp1
1474 code__2 = asmParThen [code1 asmVoid] .
1475 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1477 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1478 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1482 returnUs (CondCode True (fix_FP_cond cond) code__2)
1484 condFltCode cond x y
1485 = getRegister x `thenUs` \ register1 ->
1486 getRegister y `thenUs` \ register2 ->
1487 getNewRegNCG (registerRep register1)
1489 getNewRegNCG (registerRep register2)
1492 pk1 = registerRep register1
1493 code1 = registerCode register1 tmp1
1494 src1 = registerName register1 tmp1
1496 code2 = registerCode register2 tmp2
1497 src2 = registerName register2 tmp2
1499 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1500 mkSeqInstrs [FUCOMPP,
1502 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1503 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1507 returnUs (CondCode True (fix_FP_cond cond) code__2)
1509 {- On the 486, the flags set by FP compare are the unsigned ones!
1510 (This looks like a HACK to me. WDP 96/03)
1513 fix_FP_cond :: Cond -> Cond
1515 fix_FP_cond GE = GEU
1516 fix_FP_cond GTT = GU
1517 fix_FP_cond LTT = LU
1518 fix_FP_cond LE = LEU
1519 fix_FP_cond any = any
1521 #endif {- i386_TARGET_ARCH -}
1522 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1523 #if sparc_TARGET_ARCH
1525 condIntCode cond x (StInt y)
1527 = getRegister x `thenUs` \ register ->
1528 getNewRegNCG IntRep `thenUs` \ tmp ->
1530 code = registerCode register tmp
1531 src1 = registerName register tmp
1532 src2 = ImmInt (fromInteger y)
1533 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1535 returnUs (CondCode False cond code__2)
1537 condIntCode cond x y
1538 = getRegister x `thenUs` \ register1 ->
1539 getRegister y `thenUs` \ register2 ->
1540 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1541 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1543 code1 = registerCode register1 tmp1 asmVoid
1544 src1 = registerName register1 tmp1
1545 code2 = registerCode register2 tmp2 asmVoid
1546 src2 = registerName register2 tmp2
1547 code__2 = asmParThen [code1, code2] .
1548 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1550 returnUs (CondCode False cond code__2)
1553 condFltCode cond x y
1554 = getRegister x `thenUs` \ register1 ->
1555 getRegister y `thenUs` \ register2 ->
1556 getNewRegNCG (registerRep register1)
1558 getNewRegNCG (registerRep register2)
1560 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1562 promote x = asmInstr (FxTOy F DF x tmp)
1564 pk1 = registerRep register1
1565 code1 = registerCode register1 tmp1
1566 src1 = registerName register1 tmp1
1568 pk2 = registerRep register2
1569 code2 = registerCode register2 tmp2
1570 src2 = registerName register2 tmp2
1574 asmParThen [code1 asmVoid, code2 asmVoid] .
1575 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1576 else if pk1 == FloatRep then
1577 asmParThen [code1 (promote src1), code2 asmVoid] .
1578 mkSeqInstr (FCMP True DF tmp src2)
1580 asmParThen [code1 asmVoid, code2 (promote src2)] .
1581 mkSeqInstr (FCMP True DF src1 tmp)
1583 returnUs (CondCode True cond code__2)
1585 #endif {- sparc_TARGET_ARCH -}
1588 %************************************************************************
1590 \subsection{Generating assignments}
1592 %************************************************************************
1594 Assignments are really at the heart of the whole code generation
1595 business. Almost all top-level nodes of any real importance are
1596 assignments, which correspond to loads, stores, or register transfers.
1597 If we're really lucky, some of the register transfers will go away,
1598 because we can use the destination register to complete the code
1599 generation for the right hand side. This only fails when the right
1600 hand side is forced into a fixed register (e.g. the result of a call).
1603 assignIntCode, assignFltCode
1604 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1606 #if alpha_TARGET_ARCH
1608 assignIntCode pk (StInd _ dst) src
1609 = getNewRegNCG IntRep `thenUs` \ tmp ->
1610 getAmode dst `thenUs` \ amode ->
1611 getRegister src `thenUs` \ register ->
1613 code1 = amodeCode amode asmVoid
1614 dst__2 = amodeAddr amode
1615 code2 = registerCode register tmp asmVoid
1616 src__2 = registerName register tmp
1617 sz = primRepToSize pk
1618 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1622 assignIntCode pk dst src
1623 = getRegister dst `thenUs` \ register1 ->
1624 getRegister src `thenUs` \ register2 ->
1626 dst__2 = registerName register1 zeroh
1627 code = registerCode register2 dst__2
1628 src__2 = registerName register2 dst__2
1629 code__2 = if isFixed register2
1630 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1635 #endif {- alpha_TARGET_ARCH -}
1636 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1637 #if i386_TARGET_ARCH
1639 assignIntCode pk (StInd _ dst) src
1640 = getAmode dst `thenUs` \ amode ->
1641 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1643 code1 = amodeCode amode asmVoid
1644 dst__2 = amodeAddr amode
1645 code__2 = asmParThen [code1, codesrc asmVoid] .
1646 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1652 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1656 = returnUs (asmParThen [], OpImm imm_op, L)
1659 imm_op = case imm of Just x -> x
1662 = getRegister op `thenUs` \ register ->
1663 getNewRegNCG (registerRep register)
1666 code = registerCode register tmp
1667 reg = registerName register tmp
1668 pk = registerRep register
1669 sz = primRepToSize pk
1671 returnUs (code, OpReg reg, sz)
1673 assignIntCode pk dst (StInd _ src)
1674 = getNewRegNCG IntRep `thenUs` \ tmp ->
1675 getAmode src `thenUs` \ amode ->
1676 getRegister dst `thenUs` \ register ->
1678 code1 = amodeCode amode asmVoid
1679 src__2 = amodeAddr amode
1680 code2 = registerCode register tmp asmVoid
1681 dst__2 = registerName register tmp
1682 sz = primRepToSize pk
1683 code__2 = asmParThen [code1, code2] .
1684 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1688 assignIntCode pk dst src
1689 = getRegister dst `thenUs` \ register1 ->
1690 getRegister src `thenUs` \ register2 ->
1691 getNewRegNCG IntRep `thenUs` \ tmp ->
1693 dst__2 = registerName register1 tmp
1694 code = registerCode register2 dst__2
1695 src__2 = registerName register2 dst__2
1696 code__2 = if isFixed register2 && dst__2 /= src__2
1697 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1702 #endif {- i386_TARGET_ARCH -}
1703 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1704 #if sparc_TARGET_ARCH
1706 assignIntCode pk (StInd _ dst) src
1707 = getNewRegNCG IntRep `thenUs` \ tmp ->
1708 getAmode dst `thenUs` \ amode ->
1709 getRegister src `thenUs` \ register ->
1711 code1 = amodeCode amode asmVoid
1712 dst__2 = amodeAddr amode
1713 code2 = registerCode register tmp asmVoid
1714 src__2 = registerName register tmp
1715 sz = primRepToSize pk
1716 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1720 assignIntCode pk dst src
1721 = getRegister dst `thenUs` \ register1 ->
1722 getRegister src `thenUs` \ register2 ->
1724 dst__2 = registerName register1 g0
1725 code = registerCode register2 dst__2
1726 src__2 = registerName register2 dst__2
1727 code__2 = if isFixed register2
1728 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1733 #endif {- sparc_TARGET_ARCH -}
1736 % --------------------------------
1737 Floating-point assignments:
1738 % --------------------------------
1740 #if alpha_TARGET_ARCH
1742 assignFltCode pk (StInd _ dst) src
1743 = getNewRegNCG pk `thenUs` \ tmp ->
1744 getAmode dst `thenUs` \ amode ->
1745 getRegister src `thenUs` \ register ->
1747 code1 = amodeCode amode asmVoid
1748 dst__2 = amodeAddr amode
1749 code2 = registerCode register tmp asmVoid
1750 src__2 = registerName register tmp
1751 sz = primRepToSize pk
1752 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1756 assignFltCode pk dst src
1757 = getRegister dst `thenUs` \ register1 ->
1758 getRegister src `thenUs` \ register2 ->
1760 dst__2 = registerName register1 zeroh
1761 code = registerCode register2 dst__2
1762 src__2 = registerName register2 dst__2
1763 code__2 = if isFixed register2
1764 then code . mkSeqInstr (FMOV src__2 dst__2)
1769 #endif {- alpha_TARGET_ARCH -}
1770 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1771 #if i386_TARGET_ARCH
1773 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1774 = getNewRegNCG IntRep `thenUs` \ tmp ->
1775 getAmode src `thenUs` \ amodesrc ->
1776 getAmode dst `thenUs` \ amodedst ->
1777 --getRegister src `thenUs` \ register ->
1779 codesrc1 = amodeCode amodesrc asmVoid
1780 addrsrc1 = amodeAddr amodesrc
1781 codedst1 = amodeCode amodedst asmVoid
1782 addrdst1 = amodeAddr amodedst
1783 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1784 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1786 code__2 = asmParThen [codesrc1, codedst1] .
1787 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1788 MOV L (OpReg tmp) (OpAddr addrdst1)]
1791 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1792 MOV L (OpReg tmp) (OpAddr addrdst2)]
1797 assignFltCode pk (StInd _ dst) src
1798 = --getNewRegNCG pk `thenUs` \ tmp ->
1799 getAmode dst `thenUs` \ amode ->
1800 getRegister src `thenUs` \ register ->
1802 sz = primRepToSize pk
1803 dst__2 = amodeAddr amode
1805 code1 = amodeCode amode asmVoid
1806 code2 = registerCode register {-tmp-}st0 asmVoid
1808 --src__2= registerName register tmp
1809 pk__2 = registerRep register
1810 sz__2 = primRepToSize pk__2
1812 code__2 = asmParThen [code1, code2] .
1813 mkSeqInstr (FSTP sz (OpAddr dst__2))
1817 assignFltCode pk dst src
1818 = getRegister dst `thenUs` \ register1 ->
1819 getRegister src `thenUs` \ register2 ->
1820 --getNewRegNCG (registerRep register2)
1821 -- `thenUs` \ tmp ->
1823 sz = primRepToSize pk
1824 dst__2 = registerName register1 st0 --tmp
1826 code = registerCode register2 dst__2
1827 src__2 = registerName register2 dst__2
1833 #endif {- i386_TARGET_ARCH -}
1834 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1835 #if sparc_TARGET_ARCH
1837 assignFltCode pk (StInd _ dst) src
1838 = getNewRegNCG pk `thenUs` \ tmp1 ->
1839 getAmode dst `thenUs` \ amode ->
1840 getRegister src `thenUs` \ register ->
1842 sz = primRepToSize pk
1843 dst__2 = amodeAddr amode
1845 code1 = amodeCode amode asmVoid
1846 code2 = registerCode register tmp1 asmVoid
1848 src__2 = registerName register tmp1
1849 pk__2 = registerRep register
1850 sz__2 = primRepToSize pk__2
1852 code__2 = asmParThen [code1, code2] .
1854 mkSeqInstr (ST sz src__2 dst__2)
1856 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1860 assignFltCode pk dst src
1861 = getRegister dst `thenUs` \ register1 ->
1862 getRegister src `thenUs` \ register2 ->
1864 pk__2 = registerRep register2
1865 sz__2 = primRepToSize pk__2
1867 getNewRegNCG pk__2 `thenUs` \ tmp ->
1869 sz = primRepToSize pk
1870 dst__2 = registerName register1 g0 -- must be Fixed
1873 reg__2 = if pk /= pk__2 then tmp else dst__2
1875 code = registerCode register2 reg__2
1877 src__2 = registerName register2 reg__2
1881 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1882 else if isFixed register2 then
1883 code . mkSeqInstr (FMOV sz src__2 dst__2)
1889 #endif {- sparc_TARGET_ARCH -}
1892 %************************************************************************
1894 \subsection{Generating an unconditional branch}
1896 %************************************************************************
1898 We accept two types of targets: an immediate CLabel or a tree that
1899 gets evaluated into a register. Any CLabels which are AsmTemporaries
1900 are assumed to be in the local block of code, close enough for a
1901 branch instruction. Other CLabels are assumed to be far away.
1903 (If applicable) Do not fill the delay slots here; you will confuse the
1907 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1909 #if alpha_TARGET_ARCH
1911 genJump (StCLbl lbl)
1912 | isAsmTemp lbl = returnInstr (BR target)
1913 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1915 target = ImmCLbl lbl
1918 = getRegister tree `thenUs` \ register ->
1919 getNewRegNCG PtrRep `thenUs` \ tmp ->
1921 dst = registerName register pv
1922 code = registerCode register pv
1923 target = registerName register pv
1925 if isFixed register then
1926 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1928 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1930 #endif {- alpha_TARGET_ARCH -}
1931 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1932 #if i386_TARGET_ARCH
1935 genJump (StCLbl lbl)
1936 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1937 | otherwise = returnInstrs [JMP (OpImm target)]
1939 target = ImmCLbl lbl
1942 genJump (StInd pk mem)
1943 = getAmode mem `thenUs` \ amode ->
1945 code = amodeCode amode
1946 target = amodeAddr amode
1948 returnSeq code [JMP (OpAddr target)]
1952 = returnInstr (JMP (OpImm target))
1955 = getRegister tree `thenUs` \ register ->
1956 getNewRegNCG PtrRep `thenUs` \ tmp ->
1958 code = registerCode register tmp
1959 target = registerName register tmp
1961 returnSeq code [JMP (OpReg target)]
1964 target = case imm of Just x -> x
1966 #endif {- i386_TARGET_ARCH -}
1967 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1968 #if sparc_TARGET_ARCH
1970 genJump (StCLbl lbl)
1971 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1972 | otherwise = returnInstrs [CALL target 0 True, NOP]
1974 target = ImmCLbl lbl
1977 = getRegister tree `thenUs` \ register ->
1978 getNewRegNCG PtrRep `thenUs` \ tmp ->
1980 code = registerCode register tmp
1981 target = registerName register tmp
1983 returnSeq code [JMP (AddrRegReg target g0), NOP]
1985 #endif {- sparc_TARGET_ARCH -}
1988 %************************************************************************
1990 \subsection{Conditional jumps}
1992 %************************************************************************
1994 Conditional jumps are always to local labels, so we can use branch
1995 instructions. We peek at the arguments to decide what kind of
1998 ALPHA: For comparisons with 0, we're laughing, because we can just do
1999 the desired conditional branch.
2001 I386: First, we have to ensure that the condition
2002 codes are set according to the supplied comparison operation.
2004 SPARC: First, we have to ensure that the condition codes are set
2005 according to the supplied comparison operation. We generate slightly
2006 different code for floating point comparisons, because a floating
2007 point operation cannot directly precede a @BF@. We assume the worst
2008 and fill that slot with a @NOP@.
2010 SPARC: Do not fill the delay slots here; you will confuse the register
2015 :: CLabel -- the branch target
2016 -> StixTree -- the condition on which to branch
2017 -> UniqSM InstrBlock
2019 #if alpha_TARGET_ARCH
2021 genCondJump lbl (StPrim op [x, StInt 0])
2022 = getRegister x `thenUs` \ register ->
2023 getNewRegNCG (registerRep register)
2026 code = registerCode register tmp
2027 value = registerName register tmp
2028 pk = registerRep register
2029 target = ImmCLbl lbl
2031 returnSeq code [BI (cmpOp op) value target]
2033 cmpOp CharGtOp = GTT
2035 cmpOp CharEqOp = EQQ
2037 cmpOp CharLtOp = LTT
2046 cmpOp WordGeOp = ALWAYS
2047 cmpOp WordEqOp = EQQ
2049 cmpOp WordLtOp = NEVER
2050 cmpOp WordLeOp = EQQ
2052 cmpOp AddrGeOp = ALWAYS
2053 cmpOp AddrEqOp = EQQ
2055 cmpOp AddrLtOp = NEVER
2056 cmpOp AddrLeOp = EQQ
2058 genCondJump lbl (StPrim op [x, StDouble 0.0])
2059 = getRegister x `thenUs` \ register ->
2060 getNewRegNCG (registerRep register)
2063 code = registerCode register tmp
2064 value = registerName register tmp
2065 pk = registerRep register
2066 target = ImmCLbl lbl
2068 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2070 cmpOp FloatGtOp = GTT
2071 cmpOp FloatGeOp = GE
2072 cmpOp FloatEqOp = EQQ
2073 cmpOp FloatNeOp = NE
2074 cmpOp FloatLtOp = LTT
2075 cmpOp FloatLeOp = LE
2076 cmpOp DoubleGtOp = GTT
2077 cmpOp DoubleGeOp = GE
2078 cmpOp DoubleEqOp = EQQ
2079 cmpOp DoubleNeOp = NE
2080 cmpOp DoubleLtOp = LTT
2081 cmpOp DoubleLeOp = LE
2083 genCondJump lbl (StPrim op [x, y])
2085 = trivialFCode pr instr x y `thenUs` \ register ->
2086 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2088 code = registerCode register tmp
2089 result = registerName register tmp
2090 target = ImmCLbl lbl
2092 returnUs (code . mkSeqInstr (BF cond result target))
2094 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2096 fltCmpOp op = case op of
2110 (instr, cond) = case op of
2111 FloatGtOp -> (FCMP TF LE, EQQ)
2112 FloatGeOp -> (FCMP TF LTT, EQQ)
2113 FloatEqOp -> (FCMP TF EQQ, NE)
2114 FloatNeOp -> (FCMP TF EQQ, EQQ)
2115 FloatLtOp -> (FCMP TF LTT, NE)
2116 FloatLeOp -> (FCMP TF LE, NE)
2117 DoubleGtOp -> (FCMP TF LE, EQQ)
2118 DoubleGeOp -> (FCMP TF LTT, EQQ)
2119 DoubleEqOp -> (FCMP TF EQQ, NE)
2120 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2121 DoubleLtOp -> (FCMP TF LTT, NE)
2122 DoubleLeOp -> (FCMP TF LE, NE)
2124 genCondJump lbl (StPrim op [x, y])
2125 = trivialCode instr x y `thenUs` \ register ->
2126 getNewRegNCG IntRep `thenUs` \ tmp ->
2128 code = registerCode register tmp
2129 result = registerName register tmp
2130 target = ImmCLbl lbl
2132 returnUs (code . mkSeqInstr (BI cond result target))
2134 (instr, cond) = case op of
2135 CharGtOp -> (CMP LE, EQQ)
2136 CharGeOp -> (CMP LTT, EQQ)
2137 CharEqOp -> (CMP EQQ, NE)
2138 CharNeOp -> (CMP EQQ, EQQ)
2139 CharLtOp -> (CMP LTT, NE)
2140 CharLeOp -> (CMP LE, NE)
2141 IntGtOp -> (CMP LE, EQQ)
2142 IntGeOp -> (CMP LTT, EQQ)
2143 IntEqOp -> (CMP EQQ, NE)
2144 IntNeOp -> (CMP EQQ, EQQ)
2145 IntLtOp -> (CMP LTT, NE)
2146 IntLeOp -> (CMP LE, NE)
2147 WordGtOp -> (CMP ULE, EQQ)
2148 WordGeOp -> (CMP ULT, EQQ)
2149 WordEqOp -> (CMP EQQ, NE)
2150 WordNeOp -> (CMP EQQ, EQQ)
2151 WordLtOp -> (CMP ULT, NE)
2152 WordLeOp -> (CMP ULE, NE)
2153 AddrGtOp -> (CMP ULE, EQQ)
2154 AddrGeOp -> (CMP ULT, EQQ)
2155 AddrEqOp -> (CMP EQQ, NE)
2156 AddrNeOp -> (CMP EQQ, EQQ)
2157 AddrLtOp -> (CMP ULT, NE)
2158 AddrLeOp -> (CMP ULE, NE)
2160 #endif {- alpha_TARGET_ARCH -}
2161 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2162 #if i386_TARGET_ARCH
2164 genCondJump lbl bool
2165 = getCondCode bool `thenUs` \ condition ->
2167 code = condCode condition
2168 cond = condName condition
2169 target = ImmCLbl lbl
2171 returnSeq code [JXX cond lbl]
2173 #endif {- i386_TARGET_ARCH -}
2174 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2175 #if sparc_TARGET_ARCH
2177 genCondJump lbl bool
2178 = getCondCode bool `thenUs` \ condition ->
2180 code = condCode condition
2181 cond = condName condition
2182 target = ImmCLbl lbl
2185 if condFloat condition then
2186 [NOP, BF cond False target, NOP]
2188 [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)
2213 -> UniqSM InstrBlock
2215 #if alpha_TARGET_ARCH
2217 genCCall fn cconv kind args
2218 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2219 `thenUs` \ ((unused,_), argCode) ->
2221 nRegs = length allArgRegs - length unused
2222 code = asmParThen (map ($ asmVoid) 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 -> UniqSM (([(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 `thenUs` \ 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 `thenUs` \ register ->
2271 getNewRegNCG (registerRep register)
2274 code = registerCode register tmp
2275 src = registerName register tmp
2276 pk = registerRep register
2277 sz = primRepToSize pk
2279 returnUs (([], 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 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2289 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2294 = getUniqLabelNCG `thenUs` \ lbl ->
2296 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2297 MOV L (OpImm (ImmCLbl lbl))
2298 -- this is hardwired
2299 (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 104))),
2300 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2306 genCCall fn cconv kind args
2307 = mapUs get_call_arg args `thenUs` \ argCode ->
2311 {- OLD: Since there's no attempt at stealing %esp at the moment,
2312 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2313 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2314 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))),
2315 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2319 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2320 call = [CALL fn__2 ,
2321 -- pop args; all args word sized?
2322 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2324 -- Don't restore %esp (see above)
2325 -- MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2328 returnSeq (code2) call
2330 -- function names that begin with '.' are assumed to be special
2331 -- internally generated names like '.mul,' which don't get an
2332 -- underscore prefix
2333 -- ToDo:needed (WDP 96/03) ???
2334 fn__2 = case (_HEAD_ fn) of
2335 '.' -> ImmLit (ptext fn)
2336 _ -> ImmLab (ptext fn)
2339 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2342 = get_op arg `thenUs` \ (code, op, sz) ->
2343 returnUs (code . mkSeqInstr (PUSH sz op))
2348 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2351 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2353 get_op (StInd pk mem)
2354 = getAmode mem `thenUs` \ amode ->
2356 code = amodeCode amode --asmVoid
2357 addr = amodeAddr amode
2358 sz = primRepToSize pk
2360 returnUs (code, OpAddr addr, sz)
2363 = getRegister op `thenUs` \ register ->
2364 getNewRegNCG (registerRep register)
2367 code = registerCode register tmp
2368 reg = registerName register tmp
2369 pk = registerRep register
2370 sz = primRepToSize pk
2372 returnUs (code, OpReg reg, sz)
2374 #endif {- i386_TARGET_ARCH -}
2375 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2376 #if sparc_TARGET_ARCH
2378 genCCall fn cconv kind args
2379 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2380 `thenUs` \ ((unused,_), argCode) ->
2382 nRegs = length allArgRegs - length unused
2383 call = CALL fn__2 nRegs False
2384 code = asmParThen (map ($ asmVoid) argCode)
2386 returnSeq code [call, NOP]
2388 -- function names that begin with '.' are assumed to be special
2389 -- internally generated names like '.mul,' which don't get an
2390 -- underscore prefix
2391 -- ToDo:needed (WDP 96/03) ???
2392 fn__2 = case (_HEAD_ fn) of
2393 '.' -> ImmLit (ptext fn)
2394 _ -> ImmLab (ptext fn)
2396 ------------------------------------
2397 {- Try to get a value into a specific register (or registers) for
2398 a call. The SPARC calling convention is an absolute
2399 nightmare. The first 6x32 bits of arguments are mapped into
2400 %o0 through %o5, and the remaining arguments are dumped to the
2401 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2402 first argument is a pair of the list of remaining argument
2403 registers to be assigned for this call and the next stack
2404 offset to use for overflowing arguments. This way,
2405 @get_arg@ can be applied to all of a call's arguments using
2409 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2410 -> StixTree -- Current argument
2411 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2413 -- We have to use up all of our argument registers first...
2415 get_arg (dst:dsts, offset) arg
2416 = getRegister arg `thenUs` \ register ->
2417 getNewRegNCG (registerRep register)
2420 reg = if isFloatingRep pk then tmp else dst
2421 code = registerCode register reg
2422 src = registerName register reg
2423 pk = registerRep register
2425 returnUs (case pk of
2428 [] -> (([], offset + 1), code . mkSeqInstrs [
2429 -- conveniently put the second part in the right stack
2430 -- location, and load the first part into %o5
2431 ST DF src (spRel (offset - 1)),
2432 LD W (spRel (offset - 1)) dst])
2433 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2434 ST DF src (spRel (-2)),
2435 LD W (spRel (-2)) dst,
2436 LD W (spRel (-1)) dst__2])
2437 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2438 ST F src (spRel (-2)),
2439 LD W (spRel (-2)) dst])
2440 _ -> ((dsts, offset), if isFixed register then
2441 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2444 -- Once we have run out of argument registers, we move to the
2447 get_arg ([], offset) arg
2448 = getRegister arg `thenUs` \ register ->
2449 getNewRegNCG (registerRep register)
2452 code = registerCode register tmp
2453 src = registerName register tmp
2454 pk = registerRep register
2455 sz = primRepToSize pk
2456 words = if pk == DoubleRep then 2 else 1
2458 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2460 #endif {- sparc_TARGET_ARCH -}
2463 %************************************************************************
2465 \subsection{Support bits}
2467 %************************************************************************
2469 %************************************************************************
2471 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2473 %************************************************************************
2475 Turn those condition codes into integers now (when they appear on
2476 the right hand side of an assignment).
2478 (If applicable) Do not fill the delay slots here; you will confuse the
2482 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2484 #if alpha_TARGET_ARCH
2485 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2486 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2487 #endif {- alpha_TARGET_ARCH -}
2489 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2490 #if i386_TARGET_ARCH
2493 = condIntCode cond x y `thenUs` \ condition ->
2494 getNewRegNCG IntRep `thenUs` \ tmp ->
2495 --getRegister dst `thenUs` \ register ->
2497 --code2 = registerCode register tmp asmVoid
2498 --dst__2 = registerName register tmp
2499 code = condCode condition
2500 cond = condName condition
2501 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2502 code__2 dst = code . mkSeqInstrs [
2503 SETCC cond (OpReg tmp),
2504 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2505 MOV L (OpReg tmp) (OpReg dst)]
2507 returnUs (Any IntRep code__2)
2510 = getUniqLabelNCG `thenUs` \ lbl1 ->
2511 getUniqLabelNCG `thenUs` \ lbl2 ->
2512 condFltCode cond x y `thenUs` \ condition ->
2514 code = condCode condition
2515 cond = condName condition
2516 code__2 dst = code . mkSeqInstrs [
2518 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2521 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2524 returnUs (Any IntRep code__2)
2526 #endif {- i386_TARGET_ARCH -}
2527 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2528 #if sparc_TARGET_ARCH
2530 condIntReg EQQ x (StInt 0)
2531 = getRegister x `thenUs` \ register ->
2532 getNewRegNCG IntRep `thenUs` \ tmp ->
2534 code = registerCode register tmp
2535 src = registerName register tmp
2536 code__2 dst = code . mkSeqInstrs [
2537 SUB False True g0 (RIReg src) g0,
2538 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2540 returnUs (Any IntRep code__2)
2543 = getRegister x `thenUs` \ register1 ->
2544 getRegister y `thenUs` \ register2 ->
2545 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2546 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2548 code1 = registerCode register1 tmp1 asmVoid
2549 src1 = registerName register1 tmp1
2550 code2 = registerCode register2 tmp2 asmVoid
2551 src2 = registerName register2 tmp2
2552 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
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 returnUs (Any IntRep code__2)
2559 condIntReg NE x (StInt 0)
2560 = getRegister x `thenUs` \ register ->
2561 getNewRegNCG IntRep `thenUs` \ tmp ->
2563 code = registerCode register tmp
2564 src = registerName register tmp
2565 code__2 dst = code . mkSeqInstrs [
2566 SUB False True g0 (RIReg src) g0,
2567 ADD True False g0 (RIImm (ImmInt 0)) dst]
2569 returnUs (Any IntRep code__2)
2572 = getRegister x `thenUs` \ register1 ->
2573 getRegister y `thenUs` \ register2 ->
2574 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2575 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2577 code1 = registerCode register1 tmp1 asmVoid
2578 src1 = registerName register1 tmp1
2579 code2 = registerCode register2 tmp2 asmVoid
2580 src2 = registerName register2 tmp2
2581 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2582 XOR False src1 (RIReg src2) dst,
2583 SUB False True g0 (RIReg dst) g0,
2584 ADD True False g0 (RIImm (ImmInt 0)) dst]
2586 returnUs (Any IntRep code__2)
2589 = getUniqLabelNCG `thenUs` \ lbl1 ->
2590 getUniqLabelNCG `thenUs` \ lbl2 ->
2591 condIntCode cond x y `thenUs` \ condition ->
2593 code = condCode condition
2594 cond = condName condition
2595 code__2 dst = code . mkSeqInstrs [
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 returnUs (Any IntRep code__2)
2606 = getUniqLabelNCG `thenUs` \ lbl1 ->
2607 getUniqLabelNCG `thenUs` \ lbl2 ->
2608 condFltCode cond x y `thenUs` \ condition ->
2610 code = condCode condition
2611 cond = condName condition
2612 code__2 dst = code . mkSeqInstrs [
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 returnUs (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 ,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)
2655 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2656 (Size -> Operand -> Instr)
2657 -> (Size -> Operand -> Instr) {-reversed instr-}
2659 -> Instr {-reversed instr: pop-}
2661 -> StixTree -> StixTree -- the two arguments
2665 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2666 ,IF_ARCH_i386 ((Operand -> Instr)
2667 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2669 -> StixTree -- the one argument
2674 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2675 ,IF_ARCH_i386 (Instr
2676 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2678 -> StixTree -- the one argument
2681 #if alpha_TARGET_ARCH
2683 trivialCode instr x (StInt y)
2685 = getRegister x `thenUs` \ register ->
2686 getNewRegNCG IntRep `thenUs` \ tmp ->
2688 code = registerCode register tmp
2689 src1 = registerName register tmp
2690 src2 = ImmInt (fromInteger y)
2691 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2693 returnUs (Any IntRep code__2)
2695 trivialCode instr x y
2696 = getRegister x `thenUs` \ register1 ->
2697 getRegister y `thenUs` \ register2 ->
2698 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2699 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2701 code1 = registerCode register1 tmp1 asmVoid
2702 src1 = registerName register1 tmp1
2703 code2 = registerCode register2 tmp2 asmVoid
2704 src2 = registerName register2 tmp2
2705 code__2 dst = asmParThen [code1, code2] .
2706 mkSeqInstr (instr src1 (RIReg src2) dst)
2708 returnUs (Any IntRep code__2)
2711 trivialUCode instr x
2712 = getRegister x `thenUs` \ register ->
2713 getNewRegNCG IntRep `thenUs` \ tmp ->
2715 code = registerCode register tmp
2716 src = registerName register tmp
2717 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2719 returnUs (Any IntRep code__2)
2722 trivialFCode _ instr x y
2723 = getRegister x `thenUs` \ register1 ->
2724 getRegister y `thenUs` \ register2 ->
2725 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2726 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2728 code1 = registerCode register1 tmp1
2729 src1 = registerName register1 tmp1
2731 code2 = registerCode register2 tmp2
2732 src2 = registerName register2 tmp2
2734 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2735 mkSeqInstr (instr src1 src2 dst)
2737 returnUs (Any DoubleRep code__2)
2739 trivialUFCode _ instr x
2740 = getRegister x `thenUs` \ register ->
2741 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2743 code = registerCode register tmp
2744 src = registerName register tmp
2745 code__2 dst = code . mkSeqInstr (instr src dst)
2747 returnUs (Any DoubleRep code__2)
2749 #endif {- alpha_TARGET_ARCH -}
2750 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2751 #if i386_TARGET_ARCH
2753 trivialCode instr x y
2755 = getRegister x `thenUs` \ register1 ->
2756 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2758 code__2 dst = let code1 = registerCode register1 dst
2759 src1 = registerName register1 dst
2761 if isFixed register1 && src1 /= dst
2762 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2763 instr (OpImm imm__2) (OpReg dst)]
2765 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2767 returnUs (Any IntRep code__2)
2770 imm__2 = case imm of Just x -> x
2772 trivialCode instr x y
2774 = getRegister y `thenUs` \ register1 ->
2775 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2777 code__2 dst = let code1 = registerCode register1 dst
2778 src1 = registerName register1 dst
2780 if isFixed register1 && src1 /= dst
2781 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2782 instr (OpImm imm__2) (OpReg dst)]
2784 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2786 returnUs (Any IntRep code__2)
2789 imm__2 = case imm of Just x -> x
2791 trivialCode instr x (StInd pk mem)
2792 = getRegister x `thenUs` \ register ->
2793 --getNewRegNCG IntRep `thenUs` \ tmp ->
2794 getAmode mem `thenUs` \ amode ->
2796 code2 = amodeCode amode asmVoid
2797 src2 = amodeAddr amode
2798 code__2 dst = let code1 = registerCode register dst asmVoid
2799 src1 = registerName register dst
2800 in asmParThen [code1, code2] .
2801 if isFixed register && src1 /= dst
2802 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2803 instr (OpAddr src2) (OpReg dst)]
2805 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2807 returnUs (Any pk code__2)
2809 trivialCode instr (StInd pk mem) y
2810 = getRegister y `thenUs` \ register ->
2811 --getNewRegNCG IntRep `thenUs` \ tmp ->
2812 getAmode mem `thenUs` \ amode ->
2814 code2 = amodeCode amode asmVoid
2815 src2 = amodeAddr amode
2817 code1 = registerCode register dst asmVoid
2818 src1 = registerName register dst
2819 in asmParThen [code1, code2] .
2820 if isFixed register && src1 /= dst
2821 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2822 instr (OpAddr src2) (OpReg dst)]
2824 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2826 returnUs (Any pk code__2)
2828 trivialCode instr x y
2829 = getRegister x `thenUs` \ register1 ->
2830 getRegister y `thenUs` \ register2 ->
2831 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2832 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2834 code2 = registerCode register2 tmp2 asmVoid
2835 src2 = registerName register2 tmp2
2837 code1 = registerCode register1 dst asmVoid
2838 src1 = registerName register1 dst
2839 in asmParThen [code1, code2] .
2840 if isFixed register1 && src1 /= dst
2841 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2842 instr (OpReg src2) (OpReg dst)]
2844 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2846 returnUs (Any IntRep code__2)
2849 trivialUCode instr x
2850 = getRegister x `thenUs` \ register ->
2851 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2854 code = registerCode register dst
2855 src = registerName register dst
2856 in code . if isFixed register && dst /= src
2857 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2859 else mkSeqInstr (instr (OpReg src))
2861 returnUs (Any IntRep code__2)
2864 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2865 = getRegister y `thenUs` \ register2 ->
2866 --getNewRegNCG (registerRep register2)
2867 -- `thenUs` \ tmp2 ->
2868 getAmode mem `thenUs` \ amode ->
2870 code1 = amodeCode amode
2871 src1 = amodeAddr amode
2874 code2 = registerCode register2 dst
2875 src2 = registerName register2 dst
2876 in asmParThen [code1 asmVoid,code2 asmVoid] .
2877 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2879 returnUs (Any pk code__2)
2881 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2882 = getRegister x `thenUs` \ register1 ->
2883 --getNewRegNCG (registerRep register1)
2884 -- `thenUs` \ tmp1 ->
2885 getAmode mem `thenUs` \ amode ->
2887 code2 = amodeCode amode
2888 src2 = amodeAddr amode
2891 code1 = registerCode register1 dst
2892 src1 = registerName register1 dst
2893 in asmParThen [code2 asmVoid,code1 asmVoid] .
2894 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2896 returnUs (Any pk code__2)
2898 trivialFCode pk _ _ _ instrpr x y
2899 = getRegister x `thenUs` \ register1 ->
2900 getRegister y `thenUs` \ register2 ->
2901 --getNewRegNCG (registerRep register1)
2902 -- `thenUs` \ tmp1 ->
2903 --getNewRegNCG (registerRep register2)
2904 -- `thenUs` \ tmp2 ->
2905 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2907 pk1 = registerRep register1
2908 code1 = registerCode register1 st0 --tmp1
2909 src1 = registerName register1 st0 --tmp1
2911 pk2 = registerRep register2
2914 code2 = registerCode register2 dst
2915 src2 = registerName register2 dst
2916 in asmParThen [code1 asmVoid, code2 asmVoid] .
2919 returnUs (Any pk1 code__2)
2922 trivialUFCode pk instr (StInd pk' mem)
2923 = getAmode mem `thenUs` \ amode ->
2925 code = amodeCode amode
2926 src = amodeAddr amode
2927 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2930 returnUs (Any pk code__2)
2932 trivialUFCode pk instr x
2933 = getRegister x `thenUs` \ register ->
2934 --getNewRegNCG pk `thenUs` \ tmp ->
2937 code = registerCode register dst
2938 src = registerName register dst
2939 in code . mkSeqInstrs [instr]
2941 returnUs (Any pk code__2)
2943 #endif {- i386_TARGET_ARCH -}
2944 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2945 #if sparc_TARGET_ARCH
2947 trivialCode instr x (StInt y)
2949 = getRegister x `thenUs` \ register ->
2950 getNewRegNCG IntRep `thenUs` \ tmp ->
2952 code = registerCode register tmp
2953 src1 = registerName register tmp
2954 src2 = ImmInt (fromInteger y)
2955 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2957 returnUs (Any IntRep code__2)
2959 trivialCode instr x y
2960 = getRegister x `thenUs` \ register1 ->
2961 getRegister y `thenUs` \ register2 ->
2962 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2963 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2965 code1 = registerCode register1 tmp1 asmVoid
2966 src1 = registerName register1 tmp1
2967 code2 = registerCode register2 tmp2 asmVoid
2968 src2 = registerName register2 tmp2
2969 code__2 dst = asmParThen [code1, code2] .
2970 mkSeqInstr (instr src1 (RIReg src2) dst)
2972 returnUs (Any IntRep code__2)
2975 trivialFCode pk instr x y
2976 = getRegister x `thenUs` \ register1 ->
2977 getRegister y `thenUs` \ register2 ->
2978 getNewRegNCG (registerRep register1)
2980 getNewRegNCG (registerRep register2)
2982 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2984 promote x = asmInstr (FxTOy F DF x tmp)
2986 pk1 = registerRep register1
2987 code1 = registerCode register1 tmp1
2988 src1 = registerName register1 tmp1
2990 pk2 = registerRep register2
2991 code2 = registerCode register2 tmp2
2992 src2 = registerName register2 tmp2
2996 asmParThen [code1 asmVoid, code2 asmVoid] .
2997 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2998 else if pk1 == FloatRep then
2999 asmParThen [code1 (promote src1), code2 asmVoid] .
3000 mkSeqInstr (instr DF tmp src2 dst)
3002 asmParThen [code1 asmVoid, code2 (promote src2)] .
3003 mkSeqInstr (instr DF src1 tmp dst)
3005 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3008 trivialUCode instr x
3009 = getRegister x `thenUs` \ register ->
3010 getNewRegNCG IntRep `thenUs` \ tmp ->
3012 code = registerCode register tmp
3013 src = registerName register tmp
3014 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3016 returnUs (Any IntRep code__2)
3019 trivialUFCode pk instr x
3020 = getRegister x `thenUs` \ register ->
3021 getNewRegNCG pk `thenUs` \ tmp ->
3023 code = registerCode register tmp
3024 src = registerName register tmp
3025 code__2 dst = code . mkSeqInstr (instr src dst)
3027 returnUs (Any pk code__2)
3029 #endif {- sparc_TARGET_ARCH -}
3032 %************************************************************************
3034 \subsubsection{Coercing to/from integer/floating-point...}
3036 %************************************************************************
3038 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3039 to be generated. Here we just change the type on the Register passed
3040 on up. The code is machine-independent.
3042 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3043 conversions. We have to store temporaries in memory to move
3044 between the integer and the floating point register sets.
3047 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3048 coerceFltCode :: StixTree -> UniqSM Register
3050 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3051 coerceFP2Int :: StixTree -> UniqSM Register
3054 = getRegister x `thenUs` \ register ->
3057 Fixed _ reg code -> Fixed pk reg code
3058 Any _ code -> Any pk code
3063 = getRegister x `thenUs` \ register ->
3066 Fixed _ reg code -> Fixed DoubleRep reg code
3067 Any _ code -> Any DoubleRep code
3072 #if alpha_TARGET_ARCH
3075 = getRegister x `thenUs` \ register ->
3076 getNewRegNCG IntRep `thenUs` \ reg ->
3078 code = registerCode register reg
3079 src = registerName register reg
3081 code__2 dst = code . mkSeqInstrs [
3083 LD TF dst (spRel 0),
3086 returnUs (Any DoubleRep code__2)
3090 = getRegister x `thenUs` \ register ->
3091 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3093 code = registerCode register tmp
3094 src = registerName register tmp
3096 code__2 dst = code . mkSeqInstrs [
3098 ST TF tmp (spRel 0),
3101 returnUs (Any IntRep code__2)
3103 #endif {- alpha_TARGET_ARCH -}
3104 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3105 #if i386_TARGET_ARCH
3108 = getRegister x `thenUs` \ register ->
3109 getNewRegNCG IntRep `thenUs` \ reg ->
3111 code = registerCode register reg
3112 src = registerName register reg
3114 code__2 dst = code . mkSeqInstrs [
3115 -- to fix: should spill instead of using R1
3116 MOV L (OpReg src) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
3117 FILD (primRepToSize pk) (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3119 returnUs (Any pk code__2)
3123 = getRegister x `thenUs` \ register ->
3124 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3126 code = registerCode register tmp
3127 src = registerName register tmp
3128 pk = registerRep register
3130 code__2 dst = code . mkSeqInstrs [
3132 FIST L (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)),
3133 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3135 returnUs (Any IntRep code__2)
3137 #endif {- i386_TARGET_ARCH -}
3138 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3139 #if sparc_TARGET_ARCH
3142 = getRegister x `thenUs` \ register ->
3143 getNewRegNCG IntRep `thenUs` \ reg ->
3145 code = registerCode register reg
3146 src = registerName register reg
3148 code__2 dst = code . mkSeqInstrs [
3149 ST W src (spRel (-2)),
3150 LD W (spRel (-2)) dst,
3151 FxTOy W (primRepToSize pk) dst dst]
3153 returnUs (Any pk code__2)
3157 = getRegister x `thenUs` \ register ->
3158 getNewRegNCG IntRep `thenUs` \ reg ->
3159 getNewRegNCG FloatRep `thenUs` \ tmp ->
3161 code = registerCode register reg
3162 src = registerName register reg
3163 pk = registerRep register
3165 code__2 dst = code . mkSeqInstrs [
3166 FxTOy (primRepToSize pk) W src tmp,
3167 ST W tmp (spRel (-2)),
3168 LD W (spRel (-2)) dst]
3170 returnUs (Any IntRep code__2)
3172 #endif {- sparc_TARGET_ARCH -}
3175 %************************************************************************
3177 \subsubsection{Coercing integer to @Char@...}
3179 %************************************************************************
3181 Integer to character conversion. Where applicable, we try to do this
3182 in one step if the original object is in memory.
3185 chrCode :: StixTree -> UniqSM Register
3187 #if alpha_TARGET_ARCH
3190 = getRegister x `thenUs` \ register ->
3191 getNewRegNCG IntRep `thenUs` \ reg ->
3193 code = registerCode register reg
3194 src = registerName register reg
3195 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3197 returnUs (Any IntRep code__2)
3199 #endif {- alpha_TARGET_ARCH -}
3200 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3201 #if i386_TARGET_ARCH
3204 = getRegister x `thenUs` \ register ->
3205 --getNewRegNCG IntRep `thenUs` \ reg ->
3208 code = registerCode register dst
3209 src = registerName register dst
3211 if isFixed register && src /= dst
3212 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3213 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3214 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3216 returnUs (Any IntRep code__2)
3218 #endif {- i386_TARGET_ARCH -}
3219 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3220 #if sparc_TARGET_ARCH
3222 chrCode (StInd pk mem)
3223 = getAmode mem `thenUs` \ amode ->
3225 code = amodeCode amode
3226 src = amodeAddr amode
3227 src_off = addrOffset src 3
3228 src__2 = case src_off of Just x -> x
3229 code__2 dst = if maybeToBool src_off then
3230 code . mkSeqInstr (LD BU src__2 dst)
3232 code . mkSeqInstrs [
3233 LD (primRepToSize pk) src dst,
3234 AND False dst (RIImm (ImmInt 255)) dst]
3236 returnUs (Any pk code__2)
3239 = getRegister x `thenUs` \ register ->
3240 getNewRegNCG IntRep `thenUs` \ reg ->
3242 code = registerCode register reg
3243 src = registerName register reg
3244 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3246 returnUs (Any IntRep code__2)
3248 #endif {- sparc_TARGET_ARCH -}