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 (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
75 getData (StCLbl l) = returnUs (id, ImmCLbl l)
76 getData (StString s) =
77 getUniqLabelNCG `thenUs` \ lbl ->
78 returnUs (mkSeqInstrs [LABEL lbl,
79 ASCII True (_UNPK_ s)],
81 -- the linker can handle simple arithmetic...
82 getData (StIndex rep (StCLbl lbl) (StInt off)) =
83 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
86 %************************************************************************
88 \subsection{General things for putting together code sequences}
90 %************************************************************************
93 type InstrList = OrdList Instr
94 type InstrBlock = InstrList -> InstrList
99 asmInstr :: Instr -> InstrList
100 asmInstr i = mkUnitList i
102 asmSeq :: [Instr] -> InstrList
103 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
105 asmParThen :: [InstrList] -> InstrBlock
106 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
108 returnInstr :: Instr -> UniqSM InstrBlock
109 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
111 returnInstrs :: [Instr] -> UniqSM InstrBlock
112 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
114 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
115 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
117 mkSeqInstr :: Instr -> InstrBlock
118 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
120 mkSeqInstrs :: [Instr] -> InstrBlock
121 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
125 mangleIndexTree :: StixTree -> StixTree
127 mangleIndexTree (StIndex pk base (StInt i))
128 = StPrim IntAddOp [base, off]
130 off = StInt (i * sizeOf pk)
132 #ifndef i386_TARGET_ARCH
133 mangleIndexTree (StIndex pk base off)
134 = StPrim IntAddOp [base,
140 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
141 StPrim SllOp [off, StInt s]
144 shift DoubleRep = 3::Integer
145 shift _ = IF_ARCH_alpha(3,2)
147 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
148 -- that do include the size of the primitive kind we're addressing. When StIndex
149 -- is expanded to actual code, the index (in units) is by the above code approp.
150 -- shifted to get the no. of bytes. Since Address amodes do contain size info
151 -- explicitly, we disable the shifting for x86s.
152 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
158 maybeImm :: StixTree -> Maybe Imm
160 maybeImm (StLitLbl s) = Just (ImmLab s)
161 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
162 maybeImm (StCLbl l) = Just (ImmCLbl l)
164 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
165 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
168 | i >= toInteger minInt && i <= toInteger maxInt
169 = Just (ImmInt (fromInteger i))
171 = Just (ImmInteger i)
176 %************************************************************************
178 \subsection{The @Register@ type}
180 %************************************************************************
182 @Register@s passed up the tree. If the stix code forces the register
183 to live in a pre-decided machine register, it comes out as @Fixed@;
184 otherwise, it comes out as @Any@, and the parent can decide which
185 register to put it in.
189 = Fixed PrimRep Reg InstrBlock
190 | Any PrimRep (Reg -> InstrBlock)
192 registerCode :: Register -> Reg -> InstrBlock
193 registerCode (Fixed _ _ code) reg = code
194 registerCode (Any _ code) reg = code reg
196 registerName :: Register -> Reg -> Reg
197 registerName (Fixed _ reg _) _ = reg
198 registerName (Any _ _) reg = reg
200 registerRep :: Register -> PrimRep
201 registerRep (Fixed pk _ _) = pk
202 registerRep (Any pk _) = pk
204 isFixed :: Register -> Bool
205 isFixed (Fixed _ _ _) = True
206 isFixed (Any _ _) = False
209 Generate code to get a subtree into a @Register@:
211 getRegister :: StixTree -> UniqSM Register
213 getRegister (StReg (StixMagicId stgreg))
214 = case (magicIdRegMaybe stgreg) of
215 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
218 getRegister (StReg (StixTemp u pk))
219 = returnUs (Fixed pk (UnmappedReg u pk) id)
221 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
223 getRegister (StCall fn cconv kind args)
224 = genCCall fn cconv kind args `thenUs` \ call ->
225 returnUs (Fixed kind reg call)
227 reg = if isFloatingRep kind
228 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
229 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
231 getRegister (StString s)
232 = getUniqLabelNCG `thenUs` \ lbl ->
234 imm_lbl = ImmCLbl lbl
236 code dst = mkSeqInstrs [
239 ASCII True (_UNPK_ s),
241 #if alpha_TARGET_ARCH
242 LDA dst (AddrImm imm_lbl)
245 MOV L (OpImm imm_lbl) (OpReg dst)
247 #if sparc_TARGET_ARCH
248 SETHI (HI imm_lbl) dst,
249 OR False dst (RIImm (LO imm_lbl)) dst
253 returnUs (Any PtrRep code)
255 getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
256 = getUniqLabelNCG `thenUs` \ lbl ->
258 imm_lbl = ImmCLbl lbl
260 code dst = mkSeqInstrs [
263 ASCII False (init xs),
265 #if alpha_TARGET_ARCH
266 LDA dst (AddrImm imm_lbl)
269 MOV L (OpImm imm_lbl) (OpReg dst)
271 #if sparc_TARGET_ARCH
272 SETHI (HI imm_lbl) dst,
273 OR False dst (RIImm (LO imm_lbl)) dst
277 returnUs (Any PtrRep code)
279 xs = _UNPK_ (_TAIL_ s)
281 -- end of machine-"independent" bit; here we go on the rest...
283 #if alpha_TARGET_ARCH
285 getRegister (StDouble d)
286 = getUniqLabelNCG `thenUs` \ lbl ->
287 getNewRegNCG PtrRep `thenUs` \ tmp ->
288 let code dst = mkSeqInstrs [
291 DATA TF [ImmLab (rational d)],
293 LDA tmp (AddrImm (ImmCLbl lbl)),
294 LD TF dst (AddrReg tmp)]
296 returnUs (Any DoubleRep code)
298 getRegister (StPrim primop [x]) -- unary PrimOps
300 IntNegOp -> trivialUCode (NEG Q False) x
302 NotOp -> trivialUCode NOT x
304 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
305 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
307 OrdOp -> coerceIntCode IntRep x
310 Float2IntOp -> coerceFP2Int x
311 Int2FloatOp -> coerceInt2FP pr x
312 Double2IntOp -> coerceFP2Int x
313 Int2DoubleOp -> coerceInt2FP pr x
315 Double2FloatOp -> coerceFltCode x
316 Float2DoubleOp -> coerceFltCode x
318 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
320 fn = case other_op of
321 FloatExpOp -> SLIT("exp")
322 FloatLogOp -> SLIT("log")
323 FloatSqrtOp -> SLIT("sqrt")
324 FloatSinOp -> SLIT("sin")
325 FloatCosOp -> SLIT("cos")
326 FloatTanOp -> SLIT("tan")
327 FloatAsinOp -> SLIT("asin")
328 FloatAcosOp -> SLIT("acos")
329 FloatAtanOp -> SLIT("atan")
330 FloatSinhOp -> SLIT("sinh")
331 FloatCoshOp -> SLIT("cosh")
332 FloatTanhOp -> SLIT("tanh")
333 DoubleExpOp -> SLIT("exp")
334 DoubleLogOp -> SLIT("log")
335 DoubleSqrtOp -> SLIT("sqrt")
336 DoubleSinOp -> SLIT("sin")
337 DoubleCosOp -> SLIT("cos")
338 DoubleTanOp -> SLIT("tan")
339 DoubleAsinOp -> SLIT("asin")
340 DoubleAcosOp -> SLIT("acos")
341 DoubleAtanOp -> SLIT("atan")
342 DoubleSinhOp -> SLIT("sinh")
343 DoubleCoshOp -> SLIT("cosh")
344 DoubleTanhOp -> SLIT("tanh")
346 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
348 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
350 CharGtOp -> trivialCode (CMP LTT) y x
351 CharGeOp -> trivialCode (CMP LE) y x
352 CharEqOp -> trivialCode (CMP EQQ) x y
353 CharNeOp -> int_NE_code x y
354 CharLtOp -> trivialCode (CMP LTT) x y
355 CharLeOp -> trivialCode (CMP LE) x y
357 IntGtOp -> trivialCode (CMP LTT) y x
358 IntGeOp -> trivialCode (CMP LE) y x
359 IntEqOp -> trivialCode (CMP EQQ) x y
360 IntNeOp -> int_NE_code x y
361 IntLtOp -> trivialCode (CMP LTT) x y
362 IntLeOp -> trivialCode (CMP LE) x y
364 WordGtOp -> trivialCode (CMP ULT) y x
365 WordGeOp -> trivialCode (CMP ULE) x y
366 WordEqOp -> trivialCode (CMP EQQ) x y
367 WordNeOp -> int_NE_code x y
368 WordLtOp -> trivialCode (CMP ULT) x y
369 WordLeOp -> trivialCode (CMP ULE) x y
371 AddrGtOp -> trivialCode (CMP ULT) y x
372 AddrGeOp -> trivialCode (CMP ULE) y x
373 AddrEqOp -> trivialCode (CMP EQQ) x y
374 AddrNeOp -> int_NE_code x y
375 AddrLtOp -> trivialCode (CMP ULT) x y
376 AddrLeOp -> trivialCode (CMP ULE) x y
378 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
379 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
380 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
381 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
382 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
383 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
385 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
386 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
387 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
388 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
389 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
390 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
392 IntAddOp -> trivialCode (ADD Q False) x y
393 IntSubOp -> trivialCode (SUB Q False) x y
394 IntMulOp -> trivialCode (MUL Q False) x y
395 IntQuotOp -> trivialCode (DIV Q False) x y
396 IntRemOp -> trivialCode (REM Q False) x y
398 WordQuotOp -> trivialCode (DIV Q True) x y
399 WordRemOp -> trivialCode (REM Q True) x y
401 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
402 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
403 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
404 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
406 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
407 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
408 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
409 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
411 AndOp -> trivialCode AND x y
412 OrOp -> trivialCode OR x y
413 XorOp -> trivialCode XOR x y
414 SllOp -> trivialCode SLL x y
415 SrlOp -> trivialCode SRL x y
417 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
418 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
419 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
421 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
422 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
424 {- ------------------------------------------------------------
425 Some bizarre special code for getting condition codes into
426 registers. Integer non-equality is a test for equality
427 followed by an XOR with 1. (Integer comparisons always set
428 the result register to 0 or 1.) Floating point comparisons of
429 any kind leave the result in a floating point register, so we
430 need to wrangle an integer register out of things.
432 int_NE_code :: StixTree -> StixTree -> UniqSM Register
435 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
436 getNewRegNCG IntRep `thenUs` \ tmp ->
438 code = registerCode register tmp
439 src = registerName register tmp
440 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
442 returnUs (Any IntRep code__2)
444 {- ------------------------------------------------------------
445 Comments for int_NE_code also apply to cmpF_code
448 :: (Reg -> Reg -> Reg -> Instr)
450 -> StixTree -> StixTree
453 cmpF_code instr cond x y
454 = trivialFCode pr instr x y `thenUs` \ register ->
455 getNewRegNCG DoubleRep `thenUs` \ tmp ->
456 getUniqLabelNCG `thenUs` \ lbl ->
458 code = registerCode register tmp
459 result = registerName register tmp
461 code__2 dst = code . mkSeqInstrs [
462 OR zeroh (RIImm (ImmInt 1)) dst,
463 BF cond result (ImmCLbl lbl),
464 OR zeroh (RIReg zeroh) dst,
467 returnUs (Any IntRep code__2)
469 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
470 ------------------------------------------------------------
472 getRegister (StInd pk mem)
473 = getAmode mem `thenUs` \ amode ->
475 code = amodeCode amode
476 src = amodeAddr amode
477 size = primRepToSize pk
478 code__2 dst = code . mkSeqInstr (LD size dst src)
480 returnUs (Any pk code__2)
482 getRegister (StInt i)
485 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
487 returnUs (Any IntRep code)
490 code dst = mkSeqInstr (LDI Q dst src)
492 returnUs (Any IntRep code)
494 src = ImmInt (fromInteger i)
499 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
501 returnUs (Any PtrRep code)
504 imm__2 = case imm of Just x -> x
506 #endif {- alpha_TARGET_ARCH -}
507 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
510 getRegister (StDouble 0.0)
512 code dst = mkSeqInstrs [FLDZ]
514 returnUs (Any DoubleRep code)
516 getRegister (StDouble 1.0)
518 code dst = mkSeqInstrs [FLD1]
520 returnUs (Any DoubleRep code)
522 getRegister (StDouble d)
523 = getUniqLabelNCG `thenUs` \ lbl ->
524 --getNewRegNCG PtrRep `thenUs` \ tmp ->
525 let code dst = mkSeqInstrs [
528 DATA DF [dblImmLit d],
530 FLD DF (OpImm (ImmCLbl lbl))
533 returnUs (Any DoubleRep code)
535 getRegister (StPrim primop [x]) -- unary PrimOps
537 IntNegOp -> trivialUCode (NEGI L) x
539 NotOp -> trivialUCode (NOT L) x
541 FloatNegOp -> trivialUFCode FloatRep FCHS x
542 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
543 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
545 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
547 OrdOp -> coerceIntCode IntRep x
550 Float2IntOp -> coerceFP2Int x
551 Int2FloatOp -> coerceInt2FP FloatRep x
552 Double2IntOp -> coerceFP2Int x
553 Int2DoubleOp -> coerceInt2FP DoubleRep x
555 Double2FloatOp -> coerceFltCode x
556 Float2DoubleOp -> coerceFltCode x
560 fixed_x = if is_float_op -- promote to double
561 then StPrim Float2DoubleOp [x]
564 getRegister (StCall fn cCallConv DoubleRep [x])
568 FloatExpOp -> (True, SLIT("exp"))
569 FloatLogOp -> (True, SLIT("log"))
571 FloatSinOp -> (True, SLIT("sin"))
572 FloatCosOp -> (True, SLIT("cos"))
573 FloatTanOp -> (True, SLIT("tan"))
575 FloatAsinOp -> (True, SLIT("asin"))
576 FloatAcosOp -> (True, SLIT("acos"))
577 FloatAtanOp -> (True, SLIT("atan"))
579 FloatSinhOp -> (True, SLIT("sinh"))
580 FloatCoshOp -> (True, SLIT("cosh"))
581 FloatTanhOp -> (True, SLIT("tanh"))
583 DoubleExpOp -> (False, SLIT("exp"))
584 DoubleLogOp -> (False, SLIT("log"))
586 DoubleSinOp -> (False, SLIT("sin"))
587 DoubleCosOp -> (False, SLIT("cos"))
588 DoubleTanOp -> (False, SLIT("tan"))
590 DoubleAsinOp -> (False, SLIT("asin"))
591 DoubleAcosOp -> (False, SLIT("acos"))
592 DoubleAtanOp -> (False, SLIT("atan"))
594 DoubleSinhOp -> (False, SLIT("sinh"))
595 DoubleCoshOp -> (False, SLIT("cosh"))
596 DoubleTanhOp -> (False, SLIT("tanh"))
598 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
600 CharGtOp -> condIntReg GTT x y
601 CharGeOp -> condIntReg GE x y
602 CharEqOp -> condIntReg EQQ x y
603 CharNeOp -> condIntReg NE x y
604 CharLtOp -> condIntReg LTT x y
605 CharLeOp -> condIntReg LE x y
607 IntGtOp -> condIntReg GTT x y
608 IntGeOp -> condIntReg GE x y
609 IntEqOp -> condIntReg EQQ x y
610 IntNeOp -> condIntReg NE x y
611 IntLtOp -> condIntReg LTT x y
612 IntLeOp -> condIntReg LE x y
614 WordGtOp -> condIntReg GU x y
615 WordGeOp -> condIntReg GEU x y
616 WordEqOp -> condIntReg EQQ x y
617 WordNeOp -> condIntReg NE x y
618 WordLtOp -> condIntReg LU x y
619 WordLeOp -> condIntReg LEU x y
621 AddrGtOp -> condIntReg GU x y
622 AddrGeOp -> condIntReg GEU x y
623 AddrEqOp -> condIntReg EQQ x y
624 AddrNeOp -> condIntReg NE x y
625 AddrLtOp -> condIntReg LU x y
626 AddrLeOp -> condIntReg LEU x y
628 FloatGtOp -> condFltReg GTT x y
629 FloatGeOp -> condFltReg GE x y
630 FloatEqOp -> condFltReg EQQ x y
631 FloatNeOp -> condFltReg NE x y
632 FloatLtOp -> condFltReg LTT x y
633 FloatLeOp -> condFltReg LE x y
635 DoubleGtOp -> condFltReg GTT x y
636 DoubleGeOp -> condFltReg GE x y
637 DoubleEqOp -> condFltReg EQQ x y
638 DoubleNeOp -> condFltReg NE x y
639 DoubleLtOp -> condFltReg LTT x y
640 DoubleLeOp -> condFltReg LE x y
642 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
643 -- this should be optimised by the generic Opts,
644 -- I don't know why it is not (sometimes)!
646 [x, StInt 0] -> getRegister x
651 IntSubOp -> sub_code L x y
652 IntQuotOp -> quot_code L x y True{-division-}
653 IntRemOp -> quot_code L x y False{-remainder-}
654 IntMulOp -> trivialCode (IMUL L) x y {-True-}
656 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
657 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
658 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
659 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
661 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
662 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
663 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
664 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
666 AndOp -> trivialCode (AND L) x y {-True-}
667 OrOp -> trivialCode (OR L) x y {-True-}
668 XorOp -> trivialCode (XOR L) x y {-True-}
670 {- Shift ops on x86s have constraints on their source, it
671 either has to be Imm, CL or 1
672 => trivialCode's is not restrictive enough (sigh.)
675 SllOp -> shift_code (SHL L) x y {-False-}
676 SrlOp -> shift_code (SHR L) x y {-False-}
678 ISllOp -> shift_code (SHL L) x y {-False-} --was:panic "I386Gen:isll"
679 ISraOp -> shift_code (SAR L) x y {-False-} --was:panic "I386Gen:isra"
680 ISrlOp -> shift_code (SHR L) x y {-False-} --was:panic "I386Gen:isrl"
682 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
683 where promote x = StPrim Float2DoubleOp [x]
684 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
686 shift_code :: (Operand -> Operand -> Instr)
690 {- Case1: shift length as immediate -}
691 -- Code is the same as the first eq. for trivialCode -- sigh.
692 shift_code instr x y{-amount-}
694 = getRegister x `thenUs` \ register ->
696 op_imm = OpImm imm__2
699 code = registerCode register dst
700 src = registerName register dst
702 mkSeqInstr (COMMENT SLIT("shift_code")) .
704 if isFixed register && src /= dst
706 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
707 instr op_imm (OpReg dst)]
709 mkSeqInstr (instr op_imm (OpReg src))
711 returnUs (Any IntRep code__2)
714 imm__2 = case imm of Just x -> x
716 {- Case2: shift length is complex (non-immediate) -}
717 shift_code instr x y{-amount-}
718 = getRegister y `thenUs` \ register1 ->
719 getRegister x `thenUs` \ register2 ->
720 -- getNewRegNCG IntRep `thenUs` \ dst ->
722 -- Note: we force the shift length to be loaded
723 -- into ECX, so that we can use CL when shifting.
724 -- (only register location we are allowed
725 -- to put shift amounts.)
727 -- The shift instruction is fed ECX as src reg,
728 -- but we coerce this into CL when printing out.
729 src1 = registerName register1 ecx
730 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
731 registerCode register1 ecx .
732 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
734 registerCode register1 ecx
737 code2 = registerCode register2 eax
738 src2 = registerName register2 eax
741 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
743 returnUs (Fixed IntRep eax code__2)
745 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
747 add_code sz x (StInt y)
748 = getRegister x `thenUs` \ register ->
749 getNewRegNCG IntRep `thenUs` \ tmp ->
751 code = registerCode register tmp
752 src1 = registerName register tmp
753 src2 = ImmInt (fromInteger y)
755 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
757 returnUs (Any IntRep code__2)
759 add_code sz x (StInd _ mem)
760 = getRegister x `thenUs` \ register1 ->
761 --getNewRegNCG (registerRep register1)
762 -- `thenUs` \ tmp1 ->
763 getAmode mem `thenUs` \ amode ->
765 code2 = amodeCode amode
766 src2 = amodeAddr amode
768 code__2 dst = let code1 = registerCode register1 dst
769 src1 = registerName register1 dst
770 in asmParThen [code2 asmVoid,code1 asmVoid] .
771 if isFixed register1 && src1 /= dst
772 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
773 ADD sz (OpAddr src2) (OpReg dst)]
775 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
777 returnUs (Any IntRep code__2)
779 add_code sz (StInd _ mem) y
780 = getRegister y `thenUs` \ register2 ->
781 --getNewRegNCG (registerRep register2)
782 -- `thenUs` \ tmp2 ->
783 getAmode mem `thenUs` \ amode ->
785 code1 = amodeCode amode
786 src1 = amodeAddr amode
788 code__2 dst = let code2 = registerCode register2 dst
789 src2 = registerName register2 dst
790 in asmParThen [code1 asmVoid,code2 asmVoid] .
791 if isFixed register2 && src2 /= dst
792 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
793 ADD sz (OpAddr src1) (OpReg dst)]
795 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
797 returnUs (Any IntRep code__2)
800 = getRegister x `thenUs` \ register1 ->
801 getRegister y `thenUs` \ register2 ->
802 getNewRegNCG IntRep `thenUs` \ tmp1 ->
803 getNewRegNCG IntRep `thenUs` \ tmp2 ->
805 code1 = registerCode register1 tmp1 asmVoid
806 src1 = registerName register1 tmp1
807 code2 = registerCode register2 tmp2 asmVoid
808 src2 = registerName register2 tmp2
809 code__2 dst = asmParThen [code1, code2] .
810 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
812 returnUs (Any IntRep code__2)
815 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
817 sub_code sz x (StInt y)
818 = getRegister x `thenUs` \ register ->
819 getNewRegNCG IntRep `thenUs` \ tmp ->
821 code = registerCode register tmp
822 src1 = registerName register tmp
823 src2 = ImmInt (-(fromInteger y))
825 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
827 returnUs (Any IntRep code__2)
829 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
834 -> StixTree -> StixTree
835 -> Bool -- True => division, False => remainder operation
838 -- x must go into eax, edx must be a sign-extension of eax, and y
839 -- should go in some other register (or memory), so that we get
840 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
841 -- put y in memory (if it is not there already)
843 quot_code sz x (StInd pk mem) is_division
844 = getRegister x `thenUs` \ register1 ->
845 getNewRegNCG IntRep `thenUs` \ tmp1 ->
846 getAmode mem `thenUs` \ amode ->
848 code1 = registerCode register1 tmp1 asmVoid
849 src1 = registerName register1 tmp1
850 code2 = amodeCode amode asmVoid
851 src2 = amodeAddr amode
852 code__2 = asmParThen [code1, code2] .
853 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
855 IDIV sz (OpAddr src2)]
857 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
859 quot_code sz x (StInt i) is_division
860 = getRegister x `thenUs` \ register1 ->
861 getNewRegNCG IntRep `thenUs` \ tmp1 ->
863 code1 = registerCode register1 tmp1 asmVoid
864 src1 = registerName register1 tmp1
865 src2 = ImmInt (fromInteger i)
866 code__2 = asmParThen [code1] .
867 mkSeqInstrs [-- we put src2 in (ebx)
868 MOV L (OpImm src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
869 MOV L (OpReg src1) (OpReg eax),
871 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
873 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
875 quot_code sz x y is_division
876 = getRegister x `thenUs` \ register1 ->
877 getNewRegNCG IntRep `thenUs` \ tmp1 ->
878 getRegister y `thenUs` \ register2 ->
879 getNewRegNCG IntRep `thenUs` \ tmp2 ->
881 code1 = registerCode register1 tmp1 asmVoid
882 src1 = registerName register1 tmp1
883 code2 = registerCode register2 tmp2 asmVoid
884 src2 = registerName register2 tmp2
885 code__2 = asmParThen [code1, code2] .
886 if src2 == ecx || src2 == esi
887 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
889 IDIV sz (OpReg src2)]
890 else mkSeqInstrs [ -- we put src2 in (ebx)
891 MOV L (OpReg src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
892 MOV L (OpReg src1) (OpReg eax),
894 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
896 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
897 -----------------------
899 getRegister (StInd pk mem)
900 = getAmode mem `thenUs` \ amode ->
902 code = amodeCode amode
903 src = amodeAddr amode
904 size = primRepToSize pk
906 if pk == DoubleRep || pk == FloatRep
907 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
908 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
910 returnUs (Any pk code__2)
913 getRegister (StInt i)
915 src = ImmInt (fromInteger i)
916 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
918 returnUs (Any IntRep code)
923 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
925 returnUs (Any PtrRep code)
928 imm__2 = case imm of Just x -> x
930 #endif {- i386_TARGET_ARCH -}
931 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
932 #if sparc_TARGET_ARCH
934 getRegister (StDouble d)
935 = getUniqLabelNCG `thenUs` \ lbl ->
936 getNewRegNCG PtrRep `thenUs` \ tmp ->
937 let code dst = mkSeqInstrs [
940 DATA DF [dblImmLit d],
942 SETHI (HI (ImmCLbl lbl)) tmp,
943 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
945 returnUs (Any DoubleRep code)
947 getRegister (StPrim primop [x]) -- unary PrimOps
949 IntNegOp -> trivialUCode (SUB False False g0) x
950 NotOp -> trivialUCode (XNOR False g0) x
952 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
954 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
956 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
957 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
959 OrdOp -> coerceIntCode IntRep x
962 Float2IntOp -> coerceFP2Int x
963 Int2FloatOp -> coerceInt2FP FloatRep x
964 Double2IntOp -> coerceFP2Int x
965 Int2DoubleOp -> coerceInt2FP DoubleRep x
969 fixed_x = if is_float_op -- promote to double
970 then StPrim Float2DoubleOp [x]
973 getRegister (StCall fn cCallConv DoubleRep [x])
977 FloatExpOp -> (True, SLIT("exp"))
978 FloatLogOp -> (True, SLIT("log"))
979 FloatSqrtOp -> (True, SLIT("sqrt"))
981 FloatSinOp -> (True, SLIT("sin"))
982 FloatCosOp -> (True, SLIT("cos"))
983 FloatTanOp -> (True, SLIT("tan"))
985 FloatAsinOp -> (True, SLIT("asin"))
986 FloatAcosOp -> (True, SLIT("acos"))
987 FloatAtanOp -> (True, SLIT("atan"))
989 FloatSinhOp -> (True, SLIT("sinh"))
990 FloatCoshOp -> (True, SLIT("cosh"))
991 FloatTanhOp -> (True, SLIT("tanh"))
993 DoubleExpOp -> (False, SLIT("exp"))
994 DoubleLogOp -> (False, SLIT("log"))
995 DoubleSqrtOp -> (True, SLIT("sqrt"))
997 DoubleSinOp -> (False, SLIT("sin"))
998 DoubleCosOp -> (False, SLIT("cos"))
999 DoubleTanOp -> (False, SLIT("tan"))
1001 DoubleAsinOp -> (False, SLIT("asin"))
1002 DoubleAcosOp -> (False, SLIT("acos"))
1003 DoubleAtanOp -> (False, SLIT("atan"))
1005 DoubleSinhOp -> (False, SLIT("sinh"))
1006 DoubleCoshOp -> (False, SLIT("cosh"))
1007 DoubleTanhOp -> (False, SLIT("tanh"))
1008 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
1010 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1012 CharGtOp -> condIntReg GTT x y
1013 CharGeOp -> condIntReg GE x y
1014 CharEqOp -> condIntReg EQQ x y
1015 CharNeOp -> condIntReg NE x y
1016 CharLtOp -> condIntReg LTT x y
1017 CharLeOp -> condIntReg LE x y
1019 IntGtOp -> condIntReg GTT x y
1020 IntGeOp -> condIntReg GE x y
1021 IntEqOp -> condIntReg EQQ x y
1022 IntNeOp -> condIntReg NE x y
1023 IntLtOp -> condIntReg LTT x y
1024 IntLeOp -> condIntReg LE x y
1026 WordGtOp -> condIntReg GU x y
1027 WordGeOp -> condIntReg GEU x y
1028 WordEqOp -> condIntReg EQQ x y
1029 WordNeOp -> condIntReg NE x y
1030 WordLtOp -> condIntReg LU x y
1031 WordLeOp -> condIntReg LEU x y
1033 AddrGtOp -> condIntReg GU x y
1034 AddrGeOp -> condIntReg GEU x y
1035 AddrEqOp -> condIntReg EQQ x y
1036 AddrNeOp -> condIntReg NE x y
1037 AddrLtOp -> condIntReg LU x y
1038 AddrLeOp -> condIntReg LEU x y
1040 FloatGtOp -> condFltReg GTT x y
1041 FloatGeOp -> condFltReg GE x y
1042 FloatEqOp -> condFltReg EQQ x y
1043 FloatNeOp -> condFltReg NE x y
1044 FloatLtOp -> condFltReg LTT x y
1045 FloatLeOp -> condFltReg LE x y
1047 DoubleGtOp -> condFltReg GTT x y
1048 DoubleGeOp -> condFltReg GE x y
1049 DoubleEqOp -> condFltReg EQQ x y
1050 DoubleNeOp -> condFltReg NE x y
1051 DoubleLtOp -> condFltReg LTT x y
1052 DoubleLeOp -> condFltReg LE x y
1054 IntAddOp -> trivialCode (ADD False False) x y
1055 IntSubOp -> trivialCode (SUB False False) x y
1057 -- ToDo: teach about V8+ SPARC mul/div instructions
1058 IntMulOp -> imul_div SLIT(".umul") x y
1059 IntQuotOp -> imul_div SLIT(".div") x y
1060 IntRemOp -> imul_div SLIT(".rem") x y
1062 FloatAddOp -> trivialFCode FloatRep FADD x y
1063 FloatSubOp -> trivialFCode FloatRep FSUB x y
1064 FloatMulOp -> trivialFCode FloatRep FMUL x y
1065 FloatDivOp -> trivialFCode FloatRep FDIV x y
1067 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1068 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1069 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1070 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1072 AndOp -> trivialCode (AND False) x y
1073 OrOp -> trivialCode (OR False) x y
1074 XorOp -> trivialCode (XOR False) x y
1075 SllOp -> trivialCode SLL x y
1076 SrlOp -> trivialCode SRL x y
1078 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1079 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1080 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1082 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1083 where promote x = StPrim Float2DoubleOp [x]
1084 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1085 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1087 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1089 getRegister (StInd pk mem)
1090 = getAmode mem `thenUs` \ amode ->
1092 code = amodeCode amode
1093 src = amodeAddr amode
1094 size = primRepToSize pk
1095 code__2 dst = code . mkSeqInstr (LD size src dst)
1097 returnUs (Any pk code__2)
1099 getRegister (StInt i)
1102 src = ImmInt (fromInteger i)
1103 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1105 returnUs (Any IntRep code)
1110 code dst = mkSeqInstrs [
1111 SETHI (HI imm__2) dst,
1112 OR False dst (RIImm (LO imm__2)) dst]
1114 returnUs (Any PtrRep code)
1117 imm__2 = case imm of Just x -> x
1119 #endif {- sparc_TARGET_ARCH -}
1122 %************************************************************************
1124 \subsection{The @Amode@ type}
1126 %************************************************************************
1128 @Amode@s: Memory addressing modes passed up the tree.
1130 data Amode = Amode MachRegsAddr InstrBlock
1132 amodeAddr (Amode addr _) = addr
1133 amodeCode (Amode _ code) = code
1136 Now, given a tree (the argument to an StInd) that references memory,
1137 produce a suitable addressing mode.
1140 getAmode :: StixTree -> UniqSM Amode
1142 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1144 #if alpha_TARGET_ARCH
1146 getAmode (StPrim IntSubOp [x, StInt i])
1147 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1148 getRegister x `thenUs` \ register ->
1150 code = registerCode register tmp
1151 reg = registerName register tmp
1152 off = ImmInt (-(fromInteger i))
1154 returnUs (Amode (AddrRegImm reg off) code)
1156 getAmode (StPrim IntAddOp [x, StInt i])
1157 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1158 getRegister x `thenUs` \ register ->
1160 code = registerCode register tmp
1161 reg = registerName register tmp
1162 off = ImmInt (fromInteger i)
1164 returnUs (Amode (AddrRegImm reg off) code)
1168 = returnUs (Amode (AddrImm imm__2) id)
1171 imm__2 = case imm of Just x -> x
1174 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1175 getRegister other `thenUs` \ register ->
1177 code = registerCode register tmp
1178 reg = registerName register tmp
1180 returnUs (Amode (AddrReg reg) code)
1182 #endif {- alpha_TARGET_ARCH -}
1183 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1184 #if i386_TARGET_ARCH
1186 getAmode (StPrim IntSubOp [x, StInt i])
1187 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1188 getRegister x `thenUs` \ register ->
1190 code = registerCode register tmp
1191 reg = registerName register tmp
1192 off = ImmInt (-(fromInteger i))
1194 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1196 getAmode (StPrim IntAddOp [x, StInt i])
1199 code = mkSeqInstrs []
1201 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1204 imm__2 = case imm of Just x -> x
1206 getAmode (StPrim IntAddOp [x, StInt i])
1207 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1208 getRegister x `thenUs` \ register ->
1210 code = registerCode register tmp
1211 reg = registerName register tmp
1212 off = ImmInt (fromInteger i)
1214 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1216 getAmode (StPrim IntAddOp [x, y])
1217 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1218 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1219 getRegister x `thenUs` \ register1 ->
1220 getRegister y `thenUs` \ register2 ->
1222 code1 = registerCode register1 tmp1 asmVoid
1223 reg1 = registerName register1 tmp1
1224 code2 = registerCode register2 tmp2 asmVoid
1225 reg2 = registerName register2 tmp2
1226 code__2 = asmParThen [code1, code2]
1228 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1233 code = mkSeqInstrs []
1235 returnUs (Amode (ImmAddr imm__2 0) code)
1238 imm__2 = case imm of Just x -> x
1241 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1242 getRegister other `thenUs` \ register ->
1244 code = registerCode register tmp
1245 reg = registerName register tmp
1248 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1250 #endif {- i386_TARGET_ARCH -}
1251 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1252 #if sparc_TARGET_ARCH
1254 getAmode (StPrim IntSubOp [x, StInt i])
1256 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1257 getRegister x `thenUs` \ register ->
1259 code = registerCode register tmp
1260 reg = registerName register tmp
1261 off = ImmInt (-(fromInteger i))
1263 returnUs (Amode (AddrRegImm reg off) code)
1266 getAmode (StPrim IntAddOp [x, StInt i])
1268 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1269 getRegister x `thenUs` \ register ->
1271 code = registerCode register tmp
1272 reg = registerName register tmp
1273 off = ImmInt (fromInteger i)
1275 returnUs (Amode (AddrRegImm reg off) code)
1277 getAmode (StPrim IntAddOp [x, y])
1278 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1279 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1280 getRegister x `thenUs` \ register1 ->
1281 getRegister y `thenUs` \ register2 ->
1283 code1 = registerCode register1 tmp1 asmVoid
1284 reg1 = registerName register1 tmp1
1285 code2 = registerCode register2 tmp2 asmVoid
1286 reg2 = registerName register2 tmp2
1287 code__2 = asmParThen [code1, code2]
1289 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1293 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1295 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1297 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1300 imm__2 = case imm of Just x -> x
1303 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1304 getRegister other `thenUs` \ register ->
1306 code = registerCode register tmp
1307 reg = registerName register tmp
1310 returnUs (Amode (AddrRegImm reg off) code)
1312 #endif {- sparc_TARGET_ARCH -}
1315 %************************************************************************
1317 \subsection{The @CondCode@ type}
1319 %************************************************************************
1321 Condition codes passed up the tree.
1323 data CondCode = CondCode Bool Cond InstrBlock
1325 condName (CondCode _ cond _) = cond
1326 condFloat (CondCode is_float _ _) = is_float
1327 condCode (CondCode _ _ code) = code
1330 Set up a condition code for a conditional branch.
1333 getCondCode :: StixTree -> UniqSM CondCode
1335 #if alpha_TARGET_ARCH
1336 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1337 #endif {- alpha_TARGET_ARCH -}
1338 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1340 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1341 -- yes, they really do seem to want exactly the same!
1343 getCondCode (StPrim primop [x, y])
1345 CharGtOp -> condIntCode GTT x y
1346 CharGeOp -> condIntCode GE x y
1347 CharEqOp -> condIntCode EQQ x y
1348 CharNeOp -> condIntCode NE x y
1349 CharLtOp -> condIntCode LTT x y
1350 CharLeOp -> condIntCode LE x y
1352 IntGtOp -> condIntCode GTT x y
1353 IntGeOp -> condIntCode GE x y
1354 IntEqOp -> condIntCode EQQ x y
1355 IntNeOp -> condIntCode NE x y
1356 IntLtOp -> condIntCode LTT x y
1357 IntLeOp -> condIntCode LE x y
1359 WordGtOp -> condIntCode GU x y
1360 WordGeOp -> condIntCode GEU x y
1361 WordEqOp -> condIntCode EQQ x y
1362 WordNeOp -> condIntCode NE x y
1363 WordLtOp -> condIntCode LU x y
1364 WordLeOp -> condIntCode LEU x y
1366 AddrGtOp -> condIntCode GU x y
1367 AddrGeOp -> condIntCode GEU x y
1368 AddrEqOp -> condIntCode EQQ x y
1369 AddrNeOp -> condIntCode NE x y
1370 AddrLtOp -> condIntCode LU x y
1371 AddrLeOp -> condIntCode LEU x y
1373 FloatGtOp -> condFltCode GTT x y
1374 FloatGeOp -> condFltCode GE x y
1375 FloatEqOp -> condFltCode EQQ x y
1376 FloatNeOp -> condFltCode NE x y
1377 FloatLtOp -> condFltCode LTT x y
1378 FloatLeOp -> condFltCode LE x y
1380 DoubleGtOp -> condFltCode GTT x y
1381 DoubleGeOp -> condFltCode GE x y
1382 DoubleEqOp -> condFltCode EQQ x y
1383 DoubleNeOp -> condFltCode NE x y
1384 DoubleLtOp -> condFltCode LTT x y
1385 DoubleLeOp -> condFltCode LE x y
1387 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1392 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1393 passed back up the tree.
1396 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1398 #if alpha_TARGET_ARCH
1399 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1400 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1401 #endif {- alpha_TARGET_ARCH -}
1403 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1404 #if i386_TARGET_ARCH
1406 condIntCode cond (StInd _ x) y
1408 = getAmode x `thenUs` \ amode ->
1410 code1 = amodeCode amode asmVoid
1411 y__2 = amodeAddr amode
1412 code__2 = asmParThen [code1] .
1413 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1415 returnUs (CondCode False cond code__2)
1418 imm__2 = case imm of Just x -> x
1420 condIntCode cond x (StInt 0)
1421 = getRegister x `thenUs` \ register1 ->
1422 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1424 code1 = registerCode register1 tmp1 asmVoid
1425 src1 = registerName register1 tmp1
1426 code__2 = asmParThen [code1] .
1427 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1429 returnUs (CondCode False cond code__2)
1431 condIntCode cond x y
1433 = getRegister x `thenUs` \ register1 ->
1434 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1436 code1 = registerCode register1 tmp1 asmVoid
1437 src1 = registerName register1 tmp1
1438 code__2 = asmParThen [code1] .
1439 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1441 returnUs (CondCode False cond code__2)
1444 imm__2 = case imm of Just x -> x
1446 condIntCode cond (StInd _ x) y
1447 = getAmode x `thenUs` \ amode ->
1448 getRegister y `thenUs` \ register2 ->
1449 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1451 code1 = amodeCode amode asmVoid
1452 src1 = amodeAddr amode
1453 code2 = registerCode register2 tmp2 asmVoid
1454 src2 = registerName register2 tmp2
1455 code__2 = asmParThen [code1, code2] .
1456 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1458 returnUs (CondCode False cond code__2)
1460 condIntCode cond y (StInd _ x)
1461 = getAmode x `thenUs` \ amode ->
1462 getRegister y `thenUs` \ register2 ->
1463 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1465 code1 = amodeCode amode asmVoid
1466 src1 = amodeAddr amode
1467 code2 = registerCode register2 tmp2 asmVoid
1468 src2 = registerName register2 tmp2
1469 code__2 = asmParThen [code1, code2] .
1470 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1472 returnUs (CondCode False cond code__2)
1474 condIntCode cond x y
1475 = getRegister x `thenUs` \ register1 ->
1476 getRegister y `thenUs` \ register2 ->
1477 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1478 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1480 code1 = registerCode register1 tmp1 asmVoid
1481 src1 = registerName register1 tmp1
1482 code2 = registerCode register2 tmp2 asmVoid
1483 src2 = registerName register2 tmp2
1484 code__2 = asmParThen [code1, code2] .
1485 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1487 returnUs (CondCode False cond code__2)
1491 condFltCode cond x (StDouble 0.0)
1492 = getRegister x `thenUs` \ register1 ->
1493 getNewRegNCG (registerRep register1)
1496 pk1 = registerRep register1
1497 code1 = registerCode register1 tmp1
1498 src1 = registerName register1 tmp1
1500 code__2 = asmParThen [code1 asmVoid] .
1501 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1503 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1504 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1508 returnUs (CondCode True (fix_FP_cond cond) code__2)
1510 condFltCode cond x y
1511 = getRegister x `thenUs` \ register1 ->
1512 getRegister y `thenUs` \ register2 ->
1513 getNewRegNCG (registerRep register1)
1515 getNewRegNCG (registerRep register2)
1518 pk1 = registerRep register1
1519 code1 = registerCode register1 tmp1
1520 src1 = registerName register1 tmp1
1522 code2 = registerCode register2 tmp2
1523 src2 = registerName register2 tmp2
1525 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1526 mkSeqInstrs [FUCOMPP,
1528 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1529 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1533 returnUs (CondCode True (fix_FP_cond cond) code__2)
1535 {- On the 486, the flags set by FP compare are the unsigned ones!
1536 (This looks like a HACK to me. WDP 96/03)
1539 fix_FP_cond :: Cond -> Cond
1541 fix_FP_cond GE = GEU
1542 fix_FP_cond GTT = GU
1543 fix_FP_cond LTT = LU
1544 fix_FP_cond LE = LEU
1545 fix_FP_cond any = any
1547 #endif {- i386_TARGET_ARCH -}
1548 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1549 #if sparc_TARGET_ARCH
1551 condIntCode cond x (StInt y)
1553 = getRegister x `thenUs` \ register ->
1554 getNewRegNCG IntRep `thenUs` \ tmp ->
1556 code = registerCode register tmp
1557 src1 = registerName register tmp
1558 src2 = ImmInt (fromInteger y)
1559 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1561 returnUs (CondCode False cond code__2)
1563 condIntCode cond x y
1564 = getRegister x `thenUs` \ register1 ->
1565 getRegister y `thenUs` \ register2 ->
1566 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1567 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1569 code1 = registerCode register1 tmp1 asmVoid
1570 src1 = registerName register1 tmp1
1571 code2 = registerCode register2 tmp2 asmVoid
1572 src2 = registerName register2 tmp2
1573 code__2 = asmParThen [code1, code2] .
1574 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1576 returnUs (CondCode False cond code__2)
1579 condFltCode cond x y
1580 = getRegister x `thenUs` \ register1 ->
1581 getRegister y `thenUs` \ register2 ->
1582 getNewRegNCG (registerRep register1)
1584 getNewRegNCG (registerRep register2)
1586 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1588 promote x = asmInstr (FxTOy F DF x tmp)
1590 pk1 = registerRep register1
1591 code1 = registerCode register1 tmp1
1592 src1 = registerName register1 tmp1
1594 pk2 = registerRep register2
1595 code2 = registerCode register2 tmp2
1596 src2 = registerName register2 tmp2
1600 asmParThen [code1 asmVoid, code2 asmVoid] .
1601 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1602 else if pk1 == FloatRep then
1603 asmParThen [code1 (promote src1), code2 asmVoid] .
1604 mkSeqInstr (FCMP True DF tmp src2)
1606 asmParThen [code1 asmVoid, code2 (promote src2)] .
1607 mkSeqInstr (FCMP True DF src1 tmp)
1609 returnUs (CondCode True cond code__2)
1611 #endif {- sparc_TARGET_ARCH -}
1614 %************************************************************************
1616 \subsection{Generating assignments}
1618 %************************************************************************
1620 Assignments are really at the heart of the whole code generation
1621 business. Almost all top-level nodes of any real importance are
1622 assignments, which correspond to loads, stores, or register transfers.
1623 If we're really lucky, some of the register transfers will go away,
1624 because we can use the destination register to complete the code
1625 generation for the right hand side. This only fails when the right
1626 hand side is forced into a fixed register (e.g. the result of a call).
1629 assignIntCode, assignFltCode
1630 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1632 #if alpha_TARGET_ARCH
1634 assignIntCode pk (StInd _ dst) src
1635 = getNewRegNCG IntRep `thenUs` \ tmp ->
1636 getAmode dst `thenUs` \ amode ->
1637 getRegister src `thenUs` \ register ->
1639 code1 = amodeCode amode asmVoid
1640 dst__2 = amodeAddr amode
1641 code2 = registerCode register tmp asmVoid
1642 src__2 = registerName register tmp
1643 sz = primRepToSize pk
1644 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1648 assignIntCode pk dst src
1649 = getRegister dst `thenUs` \ register1 ->
1650 getRegister src `thenUs` \ register2 ->
1652 dst__2 = registerName register1 zeroh
1653 code = registerCode register2 dst__2
1654 src__2 = registerName register2 dst__2
1655 code__2 = if isFixed register2
1656 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1661 #endif {- alpha_TARGET_ARCH -}
1662 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1663 #if i386_TARGET_ARCH
1665 assignIntCode pk (StInd _ dst) src
1666 = getAmode dst `thenUs` \ amode ->
1667 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1669 code1 = amodeCode amode asmVoid
1670 dst__2 = amodeAddr amode
1671 code__2 = asmParThen [code1, codesrc asmVoid] .
1672 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1678 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1682 = returnUs (asmParThen [], OpImm imm_op, L)
1685 imm_op = case imm of Just x -> x
1688 = getRegister op `thenUs` \ register ->
1689 getNewRegNCG (registerRep register)
1692 code = registerCode register tmp
1693 reg = registerName register tmp
1694 pk = registerRep register
1695 sz = primRepToSize pk
1697 returnUs (code, OpReg reg, sz)
1699 assignIntCode pk dst (StInd _ src)
1700 = getNewRegNCG IntRep `thenUs` \ tmp ->
1701 getAmode src `thenUs` \ amode ->
1702 getRegister dst `thenUs` \ register ->
1704 code1 = amodeCode amode asmVoid
1705 src__2 = amodeAddr amode
1706 code2 = registerCode register tmp asmVoid
1707 dst__2 = registerName register tmp
1708 sz = primRepToSize pk
1709 code__2 = asmParThen [code1, code2] .
1710 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1714 assignIntCode pk dst src
1715 = getRegister dst `thenUs` \ register1 ->
1716 getRegister src `thenUs` \ register2 ->
1717 getNewRegNCG IntRep `thenUs` \ tmp ->
1719 dst__2 = registerName register1 tmp
1720 code = registerCode register2 dst__2
1721 src__2 = registerName register2 dst__2
1722 code__2 = if isFixed register2 && dst__2 /= src__2
1723 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1728 #endif {- i386_TARGET_ARCH -}
1729 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1730 #if sparc_TARGET_ARCH
1732 assignIntCode pk (StInd _ dst) src
1733 = getNewRegNCG IntRep `thenUs` \ tmp ->
1734 getAmode dst `thenUs` \ amode ->
1735 getRegister src `thenUs` \ register ->
1737 code1 = amodeCode amode asmVoid
1738 dst__2 = amodeAddr amode
1739 code2 = registerCode register tmp asmVoid
1740 src__2 = registerName register tmp
1741 sz = primRepToSize pk
1742 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1746 assignIntCode pk dst src
1747 = getRegister dst `thenUs` \ register1 ->
1748 getRegister src `thenUs` \ register2 ->
1750 dst__2 = registerName register1 g0
1751 code = registerCode register2 dst__2
1752 src__2 = registerName register2 dst__2
1753 code__2 = if isFixed register2
1754 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1759 #endif {- sparc_TARGET_ARCH -}
1762 % --------------------------------
1763 Floating-point assignments:
1764 % --------------------------------
1766 #if alpha_TARGET_ARCH
1768 assignFltCode pk (StInd _ dst) src
1769 = getNewRegNCG pk `thenUs` \ tmp ->
1770 getAmode dst `thenUs` \ amode ->
1771 getRegister src `thenUs` \ register ->
1773 code1 = amodeCode amode asmVoid
1774 dst__2 = amodeAddr amode
1775 code2 = registerCode register tmp asmVoid
1776 src__2 = registerName register tmp
1777 sz = primRepToSize pk
1778 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1782 assignFltCode pk dst src
1783 = getRegister dst `thenUs` \ register1 ->
1784 getRegister src `thenUs` \ register2 ->
1786 dst__2 = registerName register1 zeroh
1787 code = registerCode register2 dst__2
1788 src__2 = registerName register2 dst__2
1789 code__2 = if isFixed register2
1790 then code . mkSeqInstr (FMOV src__2 dst__2)
1795 #endif {- alpha_TARGET_ARCH -}
1796 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1797 #if i386_TARGET_ARCH
1799 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1800 = getNewRegNCG IntRep `thenUs` \ tmp ->
1801 getAmode src `thenUs` \ amodesrc ->
1802 getAmode dst `thenUs` \ amodedst ->
1803 --getRegister src `thenUs` \ register ->
1805 codesrc1 = amodeCode amodesrc asmVoid
1806 addrsrc1 = amodeAddr amodesrc
1807 codedst1 = amodeCode amodedst asmVoid
1808 addrdst1 = amodeAddr amodedst
1809 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1810 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1812 code__2 = asmParThen [codesrc1, codedst1] .
1813 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1814 MOV L (OpReg tmp) (OpAddr addrdst1)]
1817 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1818 MOV L (OpReg tmp) (OpAddr addrdst2)]
1823 assignFltCode pk (StInd _ dst) src
1824 = --getNewRegNCG pk `thenUs` \ tmp ->
1825 getAmode dst `thenUs` \ amode ->
1826 getRegister src `thenUs` \ register ->
1828 sz = primRepToSize pk
1829 dst__2 = amodeAddr amode
1831 code1 = amodeCode amode asmVoid
1832 code2 = registerCode register {-tmp-}st0 asmVoid
1834 --src__2= registerName register tmp
1835 pk__2 = registerRep register
1836 sz__2 = primRepToSize pk__2
1838 code__2 = asmParThen [code1, code2] .
1839 mkSeqInstr (FSTP sz (OpAddr dst__2))
1843 assignFltCode pk dst src
1844 = getRegister dst `thenUs` \ register1 ->
1845 getRegister src `thenUs` \ register2 ->
1846 --getNewRegNCG (registerRep register2)
1847 -- `thenUs` \ tmp ->
1849 sz = primRepToSize pk
1850 dst__2 = registerName register1 st0 --tmp
1852 code = registerCode register2 dst__2
1853 src__2 = registerName register2 dst__2
1859 #endif {- i386_TARGET_ARCH -}
1860 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1861 #if sparc_TARGET_ARCH
1863 assignFltCode pk (StInd _ dst) src
1864 = getNewRegNCG pk `thenUs` \ tmp1 ->
1865 getAmode dst `thenUs` \ amode ->
1866 getRegister src `thenUs` \ register ->
1868 sz = primRepToSize pk
1869 dst__2 = amodeAddr amode
1871 code1 = amodeCode amode asmVoid
1872 code2 = registerCode register tmp1 asmVoid
1874 src__2 = registerName register tmp1
1875 pk__2 = registerRep register
1876 sz__2 = primRepToSize pk__2
1878 code__2 = asmParThen [code1, code2] .
1880 mkSeqInstr (ST sz src__2 dst__2)
1882 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1886 assignFltCode pk dst src
1887 = getRegister dst `thenUs` \ register1 ->
1888 getRegister src `thenUs` \ register2 ->
1890 pk__2 = registerRep register2
1891 sz__2 = primRepToSize pk__2
1893 getNewRegNCG pk__2 `thenUs` \ tmp ->
1895 sz = primRepToSize pk
1896 dst__2 = registerName register1 g0 -- must be Fixed
1899 reg__2 = if pk /= pk__2 then tmp else dst__2
1901 code = registerCode register2 reg__2
1903 src__2 = registerName register2 reg__2
1907 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1908 else if isFixed register2 then
1909 code . mkSeqInstr (FMOV sz src__2 dst__2)
1915 #endif {- sparc_TARGET_ARCH -}
1918 %************************************************************************
1920 \subsection{Generating an unconditional branch}
1922 %************************************************************************
1924 We accept two types of targets: an immediate CLabel or a tree that
1925 gets evaluated into a register. Any CLabels which are AsmTemporaries
1926 are assumed to be in the local block of code, close enough for a
1927 branch instruction. Other CLabels are assumed to be far away.
1929 (If applicable) Do not fill the delay slots here; you will confuse the
1933 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1935 #if alpha_TARGET_ARCH
1937 genJump (StCLbl lbl)
1938 | isAsmTemp lbl = returnInstr (BR target)
1939 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1941 target = ImmCLbl lbl
1944 = getRegister tree `thenUs` \ register ->
1945 getNewRegNCG PtrRep `thenUs` \ tmp ->
1947 dst = registerName register pv
1948 code = registerCode register pv
1949 target = registerName register pv
1951 if isFixed register then
1952 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1954 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1956 #endif {- alpha_TARGET_ARCH -}
1957 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1958 #if i386_TARGET_ARCH
1961 genJump (StCLbl lbl)
1962 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1963 | otherwise = returnInstrs [JMP (OpImm target)]
1965 target = ImmCLbl lbl
1968 genJump (StInd pk mem)
1969 = getAmode mem `thenUs` \ amode ->
1971 code = amodeCode amode
1972 target = amodeAddr amode
1974 returnSeq code [JMP (OpAddr target)]
1978 = returnInstr (JMP (OpImm target))
1981 = getRegister tree `thenUs` \ register ->
1982 getNewRegNCG PtrRep `thenUs` \ tmp ->
1984 code = registerCode register tmp
1985 target = registerName register tmp
1987 returnSeq code [JMP (OpReg target)]
1990 target = case imm of Just x -> x
1992 #endif {- i386_TARGET_ARCH -}
1993 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1994 #if sparc_TARGET_ARCH
1996 genJump (StCLbl lbl)
1997 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1998 | otherwise = returnInstrs [CALL target 0 True, NOP]
2000 target = ImmCLbl lbl
2003 = getRegister tree `thenUs` \ register ->
2004 getNewRegNCG PtrRep `thenUs` \ tmp ->
2006 code = registerCode register tmp
2007 target = registerName register tmp
2009 returnSeq code [JMP (AddrRegReg target g0), NOP]
2011 #endif {- sparc_TARGET_ARCH -}
2014 %************************************************************************
2016 \subsection{Conditional jumps}
2018 %************************************************************************
2020 Conditional jumps are always to local labels, so we can use branch
2021 instructions. We peek at the arguments to decide what kind of
2024 ALPHA: For comparisons with 0, we're laughing, because we can just do
2025 the desired conditional branch.
2027 I386: First, we have to ensure that the condition
2028 codes are set according to the supplied comparison operation.
2030 SPARC: First, we have to ensure that the condition codes are set
2031 according to the supplied comparison operation. We generate slightly
2032 different code for floating point comparisons, because a floating
2033 point operation cannot directly precede a @BF@. We assume the worst
2034 and fill that slot with a @NOP@.
2036 SPARC: Do not fill the delay slots here; you will confuse the register
2041 :: CLabel -- the branch target
2042 -> StixTree -- the condition on which to branch
2043 -> UniqSM InstrBlock
2045 #if alpha_TARGET_ARCH
2047 genCondJump lbl (StPrim op [x, StInt 0])
2048 = getRegister x `thenUs` \ register ->
2049 getNewRegNCG (registerRep register)
2052 code = registerCode register tmp
2053 value = registerName register tmp
2054 pk = registerRep register
2055 target = ImmCLbl lbl
2057 returnSeq code [BI (cmpOp op) value target]
2059 cmpOp CharGtOp = GTT
2061 cmpOp CharEqOp = EQQ
2063 cmpOp CharLtOp = LTT
2072 cmpOp WordGeOp = ALWAYS
2073 cmpOp WordEqOp = EQQ
2075 cmpOp WordLtOp = NEVER
2076 cmpOp WordLeOp = EQQ
2078 cmpOp AddrGeOp = ALWAYS
2079 cmpOp AddrEqOp = EQQ
2081 cmpOp AddrLtOp = NEVER
2082 cmpOp AddrLeOp = EQQ
2084 genCondJump lbl (StPrim op [x, StDouble 0.0])
2085 = getRegister x `thenUs` \ register ->
2086 getNewRegNCG (registerRep register)
2089 code = registerCode register tmp
2090 value = registerName register tmp
2091 pk = registerRep register
2092 target = ImmCLbl lbl
2094 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2096 cmpOp FloatGtOp = GTT
2097 cmpOp FloatGeOp = GE
2098 cmpOp FloatEqOp = EQQ
2099 cmpOp FloatNeOp = NE
2100 cmpOp FloatLtOp = LTT
2101 cmpOp FloatLeOp = LE
2102 cmpOp DoubleGtOp = GTT
2103 cmpOp DoubleGeOp = GE
2104 cmpOp DoubleEqOp = EQQ
2105 cmpOp DoubleNeOp = NE
2106 cmpOp DoubleLtOp = LTT
2107 cmpOp DoubleLeOp = LE
2109 genCondJump lbl (StPrim op [x, y])
2111 = trivialFCode pr instr x y `thenUs` \ register ->
2112 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2114 code = registerCode register tmp
2115 result = registerName register tmp
2116 target = ImmCLbl lbl
2118 returnUs (code . mkSeqInstr (BF cond result target))
2120 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2122 fltCmpOp op = case op of
2136 (instr, cond) = case op of
2137 FloatGtOp -> (FCMP TF LE, EQQ)
2138 FloatGeOp -> (FCMP TF LTT, EQQ)
2139 FloatEqOp -> (FCMP TF EQQ, NE)
2140 FloatNeOp -> (FCMP TF EQQ, EQQ)
2141 FloatLtOp -> (FCMP TF LTT, NE)
2142 FloatLeOp -> (FCMP TF LE, NE)
2143 DoubleGtOp -> (FCMP TF LE, EQQ)
2144 DoubleGeOp -> (FCMP TF LTT, EQQ)
2145 DoubleEqOp -> (FCMP TF EQQ, NE)
2146 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2147 DoubleLtOp -> (FCMP TF LTT, NE)
2148 DoubleLeOp -> (FCMP TF LE, NE)
2150 genCondJump lbl (StPrim op [x, y])
2151 = trivialCode instr x y `thenUs` \ register ->
2152 getNewRegNCG IntRep `thenUs` \ tmp ->
2154 code = registerCode register tmp
2155 result = registerName register tmp
2156 target = ImmCLbl lbl
2158 returnUs (code . mkSeqInstr (BI cond result target))
2160 (instr, cond) = case op of
2161 CharGtOp -> (CMP LE, EQQ)
2162 CharGeOp -> (CMP LTT, EQQ)
2163 CharEqOp -> (CMP EQQ, NE)
2164 CharNeOp -> (CMP EQQ, EQQ)
2165 CharLtOp -> (CMP LTT, NE)
2166 CharLeOp -> (CMP LE, NE)
2167 IntGtOp -> (CMP LE, EQQ)
2168 IntGeOp -> (CMP LTT, EQQ)
2169 IntEqOp -> (CMP EQQ, NE)
2170 IntNeOp -> (CMP EQQ, EQQ)
2171 IntLtOp -> (CMP LTT, NE)
2172 IntLeOp -> (CMP LE, NE)
2173 WordGtOp -> (CMP ULE, EQQ)
2174 WordGeOp -> (CMP ULT, EQQ)
2175 WordEqOp -> (CMP EQQ, NE)
2176 WordNeOp -> (CMP EQQ, EQQ)
2177 WordLtOp -> (CMP ULT, NE)
2178 WordLeOp -> (CMP ULE, NE)
2179 AddrGtOp -> (CMP ULE, EQQ)
2180 AddrGeOp -> (CMP ULT, EQQ)
2181 AddrEqOp -> (CMP EQQ, NE)
2182 AddrNeOp -> (CMP EQQ, EQQ)
2183 AddrLtOp -> (CMP ULT, NE)
2184 AddrLeOp -> (CMP ULE, NE)
2186 #endif {- alpha_TARGET_ARCH -}
2187 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2188 #if i386_TARGET_ARCH
2190 genCondJump lbl bool
2191 = getCondCode bool `thenUs` \ condition ->
2193 code = condCode condition
2194 cond = condName condition
2195 target = ImmCLbl lbl
2197 returnSeq code [JXX cond lbl]
2199 #endif {- i386_TARGET_ARCH -}
2200 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2201 #if sparc_TARGET_ARCH
2203 genCondJump lbl bool
2204 = getCondCode bool `thenUs` \ condition ->
2206 code = condCode condition
2207 cond = condName condition
2208 target = ImmCLbl lbl
2211 if condFloat condition then
2212 [NOP, BF cond False target, NOP]
2214 [BI cond False target, NOP]
2217 #endif {- sparc_TARGET_ARCH -}
2220 %************************************************************************
2222 \subsection{Generating C calls}
2224 %************************************************************************
2226 Now the biggest nightmare---calls. Most of the nastiness is buried in
2227 @get_arg@, which moves the arguments to the correct registers/stack
2228 locations. Apart from that, the code is easy.
2230 (If applicable) Do not fill the delay slots here; you will confuse the
2235 :: FAST_STRING -- function to call
2237 -> PrimRep -- type of the result
2238 -> [StixTree] -- arguments (of mixed type)
2239 -> UniqSM InstrBlock
2241 #if alpha_TARGET_ARCH
2243 genCCall fn cconv kind args
2244 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2245 `thenUs` \ ((unused,_), argCode) ->
2247 nRegs = length allArgRegs - length unused
2248 code = asmParThen (map ($ asmVoid) argCode)
2251 LDA pv (AddrImm (ImmLab (ptext fn))),
2252 JSR ra (AddrReg pv) nRegs,
2253 LDGP gp (AddrReg ra)]
2255 ------------------------
2256 {- Try to get a value into a specific register (or registers) for
2257 a call. The first 6 arguments go into the appropriate
2258 argument register (separate registers for integer and floating
2259 point arguments, but used in lock-step), and the remaining
2260 arguments are dumped to the stack, beginning at 0(sp). Our
2261 first argument is a pair of the list of remaining argument
2262 registers to be assigned for this call and the next stack
2263 offset to use for overflowing arguments. This way,
2264 @get_Arg@ can be applied to all of a call's arguments using
2268 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2269 -> StixTree -- Current argument
2270 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2272 -- We have to use up all of our argument registers first...
2274 get_arg ((iDst,fDst):dsts, offset) arg
2275 = getRegister arg `thenUs` \ register ->
2277 reg = if isFloatingRep pk then fDst else iDst
2278 code = registerCode register reg
2279 src = registerName register reg
2280 pk = registerRep register
2283 if isFloatingRep pk then
2284 ((dsts, offset), if isFixed register then
2285 code . mkSeqInstr (FMOV src fDst)
2288 ((dsts, offset), if isFixed register then
2289 code . mkSeqInstr (OR src (RIReg src) iDst)
2292 -- Once we have run out of argument registers, we move to the
2295 get_arg ([], offset) arg
2296 = getRegister arg `thenUs` \ register ->
2297 getNewRegNCG (registerRep register)
2300 code = registerCode register tmp
2301 src = registerName register tmp
2302 pk = registerRep register
2303 sz = primRepToSize pk
2305 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2307 #endif {- alpha_TARGET_ARCH -}
2308 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2309 #if i386_TARGET_ARCH
2311 genCCall fn cconv kind [StInt i]
2312 | fn == SLIT ("PerformGC_wrapper")
2314 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2315 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2320 = getUniqLabelNCG `thenUs` \ lbl ->
2322 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2323 MOV L (OpImm (ImmCLbl lbl))
2324 -- this is hardwired
2325 (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 104))),
2326 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2332 genCCall fn cconv kind args
2333 = mapUs get_call_arg args `thenUs` \ argCode ->
2337 {- OLD: Since there's no attempt at stealing %esp at the moment,
2338 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2339 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2340 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))),
2341 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2345 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2346 call = [CALL fn__2 ,
2347 -- pop args; all args word sized?
2348 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2350 -- Don't restore %esp (see above)
2351 -- MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2354 returnSeq (code2) call
2356 -- function names that begin with '.' are assumed to be special
2357 -- internally generated names like '.mul,' which don't get an
2358 -- underscore prefix
2359 -- ToDo:needed (WDP 96/03) ???
2360 fn__2 = case (_HEAD_ fn) of
2361 '.' -> ImmLit (ptext fn)
2362 _ -> ImmLab (ptext fn)
2365 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2368 = get_op arg `thenUs` \ (code, op, sz) ->
2369 returnUs (code . mkSeqInstr (PUSH sz op))
2374 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2377 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2379 get_op (StInd pk mem)
2380 = getAmode mem `thenUs` \ amode ->
2382 code = amodeCode amode --asmVoid
2383 addr = amodeAddr amode
2384 sz = primRepToSize pk
2386 returnUs (code, OpAddr addr, sz)
2389 = getRegister op `thenUs` \ register ->
2390 getNewRegNCG (registerRep register)
2393 code = registerCode register tmp
2394 reg = registerName register tmp
2395 pk = registerRep register
2396 sz = primRepToSize pk
2398 returnUs (code, OpReg reg, sz)
2400 #endif {- i386_TARGET_ARCH -}
2401 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2402 #if sparc_TARGET_ARCH
2404 genCCall fn cconv kind args
2405 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2406 `thenUs` \ ((unused,_), argCode) ->
2408 nRegs = length allArgRegs - length unused
2409 call = CALL fn__2 nRegs False
2410 code = asmParThen (map ($ asmVoid) argCode)
2412 returnSeq code [call, NOP]
2414 -- function names that begin with '.' are assumed to be special
2415 -- internally generated names like '.mul,' which don't get an
2416 -- underscore prefix
2417 -- ToDo:needed (WDP 96/03) ???
2418 fn__2 = case (_HEAD_ fn) of
2419 '.' -> ImmLit (ptext fn)
2420 _ -> ImmLab (ptext fn)
2422 ------------------------------------
2423 {- Try to get a value into a specific register (or registers) for
2424 a call. The SPARC calling convention is an absolute
2425 nightmare. The first 6x32 bits of arguments are mapped into
2426 %o0 through %o5, and the remaining arguments are dumped to the
2427 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2428 first argument is a pair of the list of remaining argument
2429 registers to be assigned for this call and the next stack
2430 offset to use for overflowing arguments. This way,
2431 @get_arg@ can be applied to all of a call's arguments using
2435 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2436 -> StixTree -- Current argument
2437 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2439 -- We have to use up all of our argument registers first...
2441 get_arg (dst:dsts, offset) arg
2442 = getRegister arg `thenUs` \ register ->
2443 getNewRegNCG (registerRep register)
2446 reg = if isFloatingRep pk then tmp else dst
2447 code = registerCode register reg
2448 src = registerName register reg
2449 pk = registerRep register
2451 returnUs (case pk of
2454 [] -> (([], offset + 1), code . mkSeqInstrs [
2455 -- conveniently put the second part in the right stack
2456 -- location, and load the first part into %o5
2457 ST DF src (spRel (offset - 1)),
2458 LD W (spRel (offset - 1)) dst])
2459 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2460 ST DF src (spRel (-2)),
2461 LD W (spRel (-2)) dst,
2462 LD W (spRel (-1)) dst__2])
2463 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2464 ST F src (spRel (-2)),
2465 LD W (spRel (-2)) dst])
2466 _ -> ((dsts, offset), if isFixed register then
2467 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2470 -- Once we have run out of argument registers, we move to the
2473 get_arg ([], offset) arg
2474 = getRegister arg `thenUs` \ register ->
2475 getNewRegNCG (registerRep register)
2478 code = registerCode register tmp
2479 src = registerName register tmp
2480 pk = registerRep register
2481 sz = primRepToSize pk
2482 words = if pk == DoubleRep then 2 else 1
2484 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2486 #endif {- sparc_TARGET_ARCH -}
2489 %************************************************************************
2491 \subsection{Support bits}
2493 %************************************************************************
2495 %************************************************************************
2497 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2499 %************************************************************************
2501 Turn those condition codes into integers now (when they appear on
2502 the right hand side of an assignment).
2504 (If applicable) Do not fill the delay slots here; you will confuse the
2508 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2510 #if alpha_TARGET_ARCH
2511 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2512 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2513 #endif {- alpha_TARGET_ARCH -}
2515 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2516 #if i386_TARGET_ARCH
2519 = condIntCode cond x y `thenUs` \ condition ->
2520 getNewRegNCG IntRep `thenUs` \ tmp ->
2521 --getRegister dst `thenUs` \ register ->
2523 --code2 = registerCode register tmp asmVoid
2524 --dst__2 = registerName register tmp
2525 code = condCode condition
2526 cond = condName condition
2527 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2528 code__2 dst = code . mkSeqInstrs [
2529 SETCC cond (OpReg tmp),
2530 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2531 MOV L (OpReg tmp) (OpReg dst)]
2533 returnUs (Any IntRep code__2)
2536 = getUniqLabelNCG `thenUs` \ lbl1 ->
2537 getUniqLabelNCG `thenUs` \ lbl2 ->
2538 condFltCode cond x y `thenUs` \ condition ->
2540 code = condCode condition
2541 cond = condName condition
2542 code__2 dst = code . mkSeqInstrs [
2544 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2547 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2550 returnUs (Any IntRep code__2)
2552 #endif {- i386_TARGET_ARCH -}
2553 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2554 #if sparc_TARGET_ARCH
2556 condIntReg EQQ x (StInt 0)
2557 = getRegister x `thenUs` \ register ->
2558 getNewRegNCG IntRep `thenUs` \ tmp ->
2560 code = registerCode register tmp
2561 src = registerName register tmp
2562 code__2 dst = code . mkSeqInstrs [
2563 SUB False True g0 (RIReg src) g0,
2564 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2566 returnUs (Any IntRep code__2)
2569 = getRegister x `thenUs` \ register1 ->
2570 getRegister y `thenUs` \ register2 ->
2571 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2572 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2574 code1 = registerCode register1 tmp1 asmVoid
2575 src1 = registerName register1 tmp1
2576 code2 = registerCode register2 tmp2 asmVoid
2577 src2 = registerName register2 tmp2
2578 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2579 XOR False src1 (RIReg src2) dst,
2580 SUB False True g0 (RIReg dst) g0,
2581 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2583 returnUs (Any IntRep code__2)
2585 condIntReg NE x (StInt 0)
2586 = getRegister x `thenUs` \ register ->
2587 getNewRegNCG IntRep `thenUs` \ tmp ->
2589 code = registerCode register tmp
2590 src = registerName register tmp
2591 code__2 dst = code . mkSeqInstrs [
2592 SUB False True g0 (RIReg src) g0,
2593 ADD True False g0 (RIImm (ImmInt 0)) dst]
2595 returnUs (Any IntRep code__2)
2598 = getRegister x `thenUs` \ register1 ->
2599 getRegister y `thenUs` \ register2 ->
2600 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2601 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2603 code1 = registerCode register1 tmp1 asmVoid
2604 src1 = registerName register1 tmp1
2605 code2 = registerCode register2 tmp2 asmVoid
2606 src2 = registerName register2 tmp2
2607 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2608 XOR False src1 (RIReg src2) dst,
2609 SUB False True g0 (RIReg dst) g0,
2610 ADD True False g0 (RIImm (ImmInt 0)) dst]
2612 returnUs (Any IntRep code__2)
2615 = getUniqLabelNCG `thenUs` \ lbl1 ->
2616 getUniqLabelNCG `thenUs` \ lbl2 ->
2617 condIntCode cond x y `thenUs` \ condition ->
2619 code = condCode condition
2620 cond = condName condition
2621 code__2 dst = code . mkSeqInstrs [
2622 BI cond False (ImmCLbl lbl1), NOP,
2623 OR False g0 (RIImm (ImmInt 0)) dst,
2624 BI ALWAYS False (ImmCLbl lbl2), NOP,
2626 OR False g0 (RIImm (ImmInt 1)) dst,
2629 returnUs (Any IntRep code__2)
2632 = getUniqLabelNCG `thenUs` \ lbl1 ->
2633 getUniqLabelNCG `thenUs` \ lbl2 ->
2634 condFltCode cond x y `thenUs` \ condition ->
2636 code = condCode condition
2637 cond = condName condition
2638 code__2 dst = code . mkSeqInstrs [
2640 BF cond False (ImmCLbl lbl1), NOP,
2641 OR False g0 (RIImm (ImmInt 0)) dst,
2642 BI ALWAYS False (ImmCLbl lbl2), NOP,
2644 OR False g0 (RIImm (ImmInt 1)) dst,
2647 returnUs (Any IntRep code__2)
2649 #endif {- sparc_TARGET_ARCH -}
2652 %************************************************************************
2654 \subsubsection{@trivial*Code@: deal with trivial instructions}
2656 %************************************************************************
2658 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2659 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2660 for constants on the right hand side, because that's where the generic
2661 optimizer will have put them.
2663 Similarly, for unary instructions, we don't have to worry about
2664 matching an StInt as the argument, because genericOpt will already
2665 have handled the constant-folding.
2669 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2670 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2671 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2673 -> StixTree -> StixTree -- the two arguments
2678 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2679 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2681 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2682 (Size -> Operand -> Instr)
2683 -> (Size -> Operand -> Instr) {-reversed instr-}
2685 -> Instr {-reversed instr: pop-}
2687 -> StixTree -> StixTree -- the two arguments
2691 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2692 ,IF_ARCH_i386 ((Operand -> Instr)
2693 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2695 -> StixTree -- the one argument
2700 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2701 ,IF_ARCH_i386 (Instr
2702 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2704 -> StixTree -- the one argument
2707 #if alpha_TARGET_ARCH
2709 trivialCode instr x (StInt y)
2711 = getRegister x `thenUs` \ register ->
2712 getNewRegNCG IntRep `thenUs` \ tmp ->
2714 code = registerCode register tmp
2715 src1 = registerName register tmp
2716 src2 = ImmInt (fromInteger y)
2717 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2719 returnUs (Any IntRep code__2)
2721 trivialCode instr x y
2722 = getRegister x `thenUs` \ register1 ->
2723 getRegister y `thenUs` \ register2 ->
2724 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2725 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2727 code1 = registerCode register1 tmp1 asmVoid
2728 src1 = registerName register1 tmp1
2729 code2 = registerCode register2 tmp2 asmVoid
2730 src2 = registerName register2 tmp2
2731 code__2 dst = asmParThen [code1, code2] .
2732 mkSeqInstr (instr src1 (RIReg src2) dst)
2734 returnUs (Any IntRep code__2)
2737 trivialUCode instr x
2738 = getRegister x `thenUs` \ register ->
2739 getNewRegNCG IntRep `thenUs` \ tmp ->
2741 code = registerCode register tmp
2742 src = registerName register tmp
2743 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2745 returnUs (Any IntRep code__2)
2748 trivialFCode _ instr x y
2749 = getRegister x `thenUs` \ register1 ->
2750 getRegister y `thenUs` \ register2 ->
2751 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2752 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2754 code1 = registerCode register1 tmp1
2755 src1 = registerName register1 tmp1
2757 code2 = registerCode register2 tmp2
2758 src2 = registerName register2 tmp2
2760 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2761 mkSeqInstr (instr src1 src2 dst)
2763 returnUs (Any DoubleRep code__2)
2765 trivialUFCode _ instr x
2766 = getRegister x `thenUs` \ register ->
2767 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2769 code = registerCode register tmp
2770 src = registerName register tmp
2771 code__2 dst = code . mkSeqInstr (instr src dst)
2773 returnUs (Any DoubleRep code__2)
2775 #endif {- alpha_TARGET_ARCH -}
2776 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2777 #if i386_TARGET_ARCH
2779 trivialCode instr x y
2781 = getRegister x `thenUs` \ register1 ->
2782 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2784 code__2 dst = let code1 = registerCode register1 dst
2785 src1 = registerName register1 dst
2787 if isFixed register1 && src1 /= dst
2788 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2789 instr (OpImm imm__2) (OpReg dst)]
2791 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2793 returnUs (Any IntRep code__2)
2796 imm__2 = case imm of Just x -> x
2798 trivialCode instr x y
2800 = getRegister y `thenUs` \ register1 ->
2801 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2803 code__2 dst = let code1 = registerCode register1 dst
2804 src1 = registerName register1 dst
2806 if isFixed register1 && src1 /= dst
2807 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2808 instr (OpImm imm__2) (OpReg dst)]
2810 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2812 returnUs (Any IntRep code__2)
2815 imm__2 = case imm of Just x -> x
2817 trivialCode instr x (StInd pk mem)
2818 = getRegister x `thenUs` \ register ->
2819 --getNewRegNCG IntRep `thenUs` \ tmp ->
2820 getAmode mem `thenUs` \ amode ->
2822 code2 = amodeCode amode asmVoid
2823 src2 = amodeAddr amode
2824 code__2 dst = let code1 = registerCode register dst asmVoid
2825 src1 = registerName register dst
2826 in asmParThen [code1, code2] .
2827 if isFixed register && src1 /= dst
2828 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2829 instr (OpAddr src2) (OpReg dst)]
2831 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2833 returnUs (Any pk code__2)
2835 trivialCode instr (StInd pk mem) y
2836 = getRegister y `thenUs` \ register ->
2837 --getNewRegNCG IntRep `thenUs` \ tmp ->
2838 getAmode mem `thenUs` \ amode ->
2840 code2 = amodeCode amode asmVoid
2841 src2 = amodeAddr amode
2843 code1 = registerCode register dst asmVoid
2844 src1 = registerName register dst
2845 in asmParThen [code1, code2] .
2846 if isFixed register && src1 /= dst
2847 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2848 instr (OpAddr src2) (OpReg dst)]
2850 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2852 returnUs (Any pk code__2)
2854 trivialCode instr x y
2855 = getRegister x `thenUs` \ register1 ->
2856 getRegister y `thenUs` \ register2 ->
2857 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2858 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2860 code2 = registerCode register2 tmp2 asmVoid
2861 src2 = registerName register2 tmp2
2863 code1 = registerCode register1 dst asmVoid
2864 src1 = registerName register1 dst
2865 in asmParThen [code1, code2] .
2866 if isFixed register1 && src1 /= dst
2867 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2868 instr (OpReg src2) (OpReg dst)]
2870 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2872 returnUs (Any IntRep code__2)
2875 trivialUCode instr x
2876 = getRegister x `thenUs` \ register ->
2877 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2880 code = registerCode register dst
2881 src = registerName register dst
2882 in code . if isFixed register && dst /= src
2883 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2885 else mkSeqInstr (instr (OpReg src))
2887 returnUs (Any IntRep code__2)
2890 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2891 = getRegister y `thenUs` \ register2 ->
2892 --getNewRegNCG (registerRep register2)
2893 -- `thenUs` \ tmp2 ->
2894 getAmode mem `thenUs` \ amode ->
2896 code1 = amodeCode amode
2897 src1 = amodeAddr amode
2900 code2 = registerCode register2 dst
2901 src2 = registerName register2 dst
2902 in asmParThen [code1 asmVoid,code2 asmVoid] .
2903 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2905 returnUs (Any pk code__2)
2907 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2908 = getRegister x `thenUs` \ register1 ->
2909 --getNewRegNCG (registerRep register1)
2910 -- `thenUs` \ tmp1 ->
2911 getAmode mem `thenUs` \ amode ->
2913 code2 = amodeCode amode
2914 src2 = amodeAddr amode
2917 code1 = registerCode register1 dst
2918 src1 = registerName register1 dst
2919 in asmParThen [code2 asmVoid,code1 asmVoid] .
2920 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2922 returnUs (Any pk code__2)
2924 trivialFCode pk _ _ _ instrpr x y
2925 = getRegister x `thenUs` \ register1 ->
2926 getRegister y `thenUs` \ register2 ->
2927 --getNewRegNCG (registerRep register1)
2928 -- `thenUs` \ tmp1 ->
2929 --getNewRegNCG (registerRep register2)
2930 -- `thenUs` \ tmp2 ->
2931 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2933 pk1 = registerRep register1
2934 code1 = registerCode register1 st0 --tmp1
2935 src1 = registerName register1 st0 --tmp1
2937 pk2 = registerRep register2
2940 code2 = registerCode register2 dst
2941 src2 = registerName register2 dst
2942 in asmParThen [code1 asmVoid, code2 asmVoid] .
2945 returnUs (Any pk1 code__2)
2948 trivialUFCode pk instr (StInd pk' mem)
2949 = getAmode mem `thenUs` \ amode ->
2951 code = amodeCode amode
2952 src = amodeAddr amode
2953 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2956 returnUs (Any pk code__2)
2958 trivialUFCode pk instr x
2959 = getRegister x `thenUs` \ register ->
2960 --getNewRegNCG pk `thenUs` \ tmp ->
2963 code = registerCode register dst
2964 src = registerName register dst
2965 in code . mkSeqInstrs [instr]
2967 returnUs (Any pk code__2)
2969 #endif {- i386_TARGET_ARCH -}
2970 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2971 #if sparc_TARGET_ARCH
2973 trivialCode instr x (StInt y)
2975 = getRegister x `thenUs` \ register ->
2976 getNewRegNCG IntRep `thenUs` \ tmp ->
2978 code = registerCode register tmp
2979 src1 = registerName register tmp
2980 src2 = ImmInt (fromInteger y)
2981 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2983 returnUs (Any IntRep code__2)
2985 trivialCode instr x y
2986 = getRegister x `thenUs` \ register1 ->
2987 getRegister y `thenUs` \ register2 ->
2988 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2989 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2991 code1 = registerCode register1 tmp1 asmVoid
2992 src1 = registerName register1 tmp1
2993 code2 = registerCode register2 tmp2 asmVoid
2994 src2 = registerName register2 tmp2
2995 code__2 dst = asmParThen [code1, code2] .
2996 mkSeqInstr (instr src1 (RIReg src2) dst)
2998 returnUs (Any IntRep code__2)
3001 trivialFCode pk instr x y
3002 = getRegister x `thenUs` \ register1 ->
3003 getRegister y `thenUs` \ register2 ->
3004 getNewRegNCG (registerRep register1)
3006 getNewRegNCG (registerRep register2)
3008 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3010 promote x = asmInstr (FxTOy F DF x tmp)
3012 pk1 = registerRep register1
3013 code1 = registerCode register1 tmp1
3014 src1 = registerName register1 tmp1
3016 pk2 = registerRep register2
3017 code2 = registerCode register2 tmp2
3018 src2 = registerName register2 tmp2
3022 asmParThen [code1 asmVoid, code2 asmVoid] .
3023 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3024 else if pk1 == FloatRep then
3025 asmParThen [code1 (promote src1), code2 asmVoid] .
3026 mkSeqInstr (instr DF tmp src2 dst)
3028 asmParThen [code1 asmVoid, code2 (promote src2)] .
3029 mkSeqInstr (instr DF src1 tmp dst)
3031 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3034 trivialUCode instr x
3035 = getRegister x `thenUs` \ register ->
3036 getNewRegNCG IntRep `thenUs` \ tmp ->
3038 code = registerCode register tmp
3039 src = registerName register tmp
3040 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3042 returnUs (Any IntRep code__2)
3045 trivialUFCode pk instr x
3046 = getRegister x `thenUs` \ register ->
3047 getNewRegNCG pk `thenUs` \ tmp ->
3049 code = registerCode register tmp
3050 src = registerName register tmp
3051 code__2 dst = code . mkSeqInstr (instr src dst)
3053 returnUs (Any pk code__2)
3055 #endif {- sparc_TARGET_ARCH -}
3058 %************************************************************************
3060 \subsubsection{Coercing to/from integer/floating-point...}
3062 %************************************************************************
3064 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3065 to be generated. Here we just change the type on the Register passed
3066 on up. The code is machine-independent.
3068 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3069 conversions. We have to store temporaries in memory to move
3070 between the integer and the floating point register sets.
3073 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3074 coerceFltCode :: StixTree -> UniqSM Register
3076 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3077 coerceFP2Int :: StixTree -> UniqSM Register
3080 = getRegister x `thenUs` \ register ->
3083 Fixed _ reg code -> Fixed pk reg code
3084 Any _ code -> Any pk code
3089 = getRegister x `thenUs` \ register ->
3092 Fixed _ reg code -> Fixed DoubleRep reg code
3093 Any _ code -> Any DoubleRep code
3098 #if alpha_TARGET_ARCH
3101 = getRegister x `thenUs` \ register ->
3102 getNewRegNCG IntRep `thenUs` \ reg ->
3104 code = registerCode register reg
3105 src = registerName register reg
3107 code__2 dst = code . mkSeqInstrs [
3109 LD TF dst (spRel 0),
3112 returnUs (Any DoubleRep code__2)
3116 = getRegister x `thenUs` \ register ->
3117 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3119 code = registerCode register tmp
3120 src = registerName register tmp
3122 code__2 dst = code . mkSeqInstrs [
3124 ST TF tmp (spRel 0),
3127 returnUs (Any IntRep code__2)
3129 #endif {- alpha_TARGET_ARCH -}
3130 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3131 #if i386_TARGET_ARCH
3134 = getRegister x `thenUs` \ register ->
3135 getNewRegNCG IntRep `thenUs` \ reg ->
3137 code = registerCode register reg
3138 src = registerName register reg
3140 code__2 dst = code . mkSeqInstrs [
3141 -- to fix: should spill instead of using R1
3142 MOV L (OpReg src) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
3143 FILD (primRepToSize pk) (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3145 returnUs (Any pk code__2)
3149 = getRegister x `thenUs` \ register ->
3150 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3152 code = registerCode register tmp
3153 src = registerName register tmp
3154 pk = registerRep register
3156 code__2 dst = code . mkSeqInstrs [
3158 FIST L (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)),
3159 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3161 returnUs (Any IntRep code__2)
3163 #endif {- i386_TARGET_ARCH -}
3164 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3165 #if sparc_TARGET_ARCH
3168 = getRegister x `thenUs` \ register ->
3169 getNewRegNCG IntRep `thenUs` \ reg ->
3171 code = registerCode register reg
3172 src = registerName register reg
3174 code__2 dst = code . mkSeqInstrs [
3175 ST W src (spRel (-2)),
3176 LD W (spRel (-2)) dst,
3177 FxTOy W (primRepToSize pk) dst dst]
3179 returnUs (Any pk code__2)
3183 = getRegister x `thenUs` \ register ->
3184 getNewRegNCG IntRep `thenUs` \ reg ->
3185 getNewRegNCG FloatRep `thenUs` \ tmp ->
3187 code = registerCode register reg
3188 src = registerName register reg
3189 pk = registerRep register
3191 code__2 dst = code . mkSeqInstrs [
3192 FxTOy (primRepToSize pk) W src tmp,
3193 ST W tmp (spRel (-2)),
3194 LD W (spRel (-2)) dst]
3196 returnUs (Any IntRep code__2)
3198 #endif {- sparc_TARGET_ARCH -}
3201 %************************************************************************
3203 \subsubsection{Coercing integer to @Char@...}
3205 %************************************************************************
3207 Integer to character conversion. Where applicable, we try to do this
3208 in one step if the original object is in memory.
3211 chrCode :: StixTree -> UniqSM Register
3213 #if alpha_TARGET_ARCH
3216 = getRegister x `thenUs` \ register ->
3217 getNewRegNCG IntRep `thenUs` \ reg ->
3219 code = registerCode register reg
3220 src = registerName register reg
3221 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3223 returnUs (Any IntRep code__2)
3225 #endif {- alpha_TARGET_ARCH -}
3226 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3227 #if i386_TARGET_ARCH
3230 = getRegister x `thenUs` \ register ->
3231 --getNewRegNCG IntRep `thenUs` \ reg ->
3234 code = registerCode register dst
3235 src = registerName register dst
3237 if isFixed register && src /= dst
3238 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3239 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3240 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3242 returnUs (Any IntRep code__2)
3244 #endif {- i386_TARGET_ARCH -}
3245 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3246 #if sparc_TARGET_ARCH
3248 chrCode (StInd pk mem)
3249 = getAmode mem `thenUs` \ amode ->
3251 code = amodeCode amode
3252 src = amodeAddr amode
3253 src_off = addrOffset src 3
3254 src__2 = case src_off of Just x -> x
3255 code__2 dst = if maybeToBool src_off then
3256 code . mkSeqInstr (LD BU src__2 dst)
3258 code . mkSeqInstrs [
3259 LD (primRepToSize pk) src dst,
3260 AND False dst (RIImm (ImmInt 255)) dst]
3262 returnUs (Any pk code__2)
3265 = getRegister x `thenUs` \ register ->
3266 getNewRegNCG IntRep `thenUs` \ reg ->
3268 code = registerCode register reg
3269 src = registerName register reg
3270 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3272 returnUs (Any IntRep code__2)
3274 #endif {- sparc_TARGET_ARCH -}