2 % (c) The AQUA Project, Glasgow University, 1996-1998
4 \section[MachCode]{Generating machine code}
6 This is a big module, but, if you pay attention to
7 (a) the sectioning, (b) the type signatures, and
8 (c) the \tr{#if blah_TARGET_ARCH} things, the
9 structure should not be too overwhelming.
12 module MachCode ( stmt2Instrs, asmVoid, InstrList ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
20 import AbsCSyn ( MagicId )
21 import AbsCUtils ( magicIdPrimRep )
22 import CallConv ( CallConv )
23 import CLabel ( isAsmTemp, CLabel )
24 import Maybes ( maybeToBool, expectJust )
25 import OrdList -- quite a bit of it
26 import PrimRep ( isFloatingRep, PrimRep(..) )
27 import PrimOp ( PrimOp(..) )
28 import CallConv ( cCallConv )
29 import Stix ( getUniqLabelNCG, StixTree(..),
30 StixReg(..), CodeSegment(..)
32 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
38 Code extractor for an entire stix tree---stix statement level.
41 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
43 stmt2Instrs stmt = case stmt of
44 StComment s -> returnInstr (COMMENT s)
45 StSegment seg -> returnInstr (SEGMENT seg)
46 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
47 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
48 StLabel lab -> returnInstr (LABEL lab)
50 StJump arg -> genJump arg
51 StCondJump lab arg -> genCondJump lab arg
52 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
55 | isFloatingRep pk -> assignFltCode pk dst src
56 | otherwise -> assignIntCode pk dst src
59 -- When falling through on the Alpha, we still have to load pv
60 -- with the address of the next routine, so that it can load gp.
61 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
65 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
66 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
67 (foldr1 (.) codes xs))
69 getData :: StixTree -> UniqSM (InstrBlock, Imm)
71 getData (StInt i) = returnUs (id, ImmInteger i)
72 getData (StDouble d) = returnUs (id, dblImmLit d)
73 getData (StLitLbl s) = returnUs (id, ImmLab s)
74 getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
75 getData (StCLbl l) = returnUs (id, ImmCLbl l)
76 getData (StString s) =
77 getUniqLabelNCG `thenUs` \ lbl ->
78 returnUs (mkSeqInstrs [LABEL lbl,
79 ASCII True (_UNPK_ s)],
81 -- the linker can handle simple arithmetic...
82 getData (StIndex rep (StCLbl lbl) (StInt off)) =
83 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
86 %************************************************************************
88 \subsection{General things for putting together code sequences}
90 %************************************************************************
93 type InstrList = OrdList Instr
94 type InstrBlock = InstrList -> InstrList
99 asmInstr :: Instr -> InstrList
100 asmInstr i = mkUnitList i
102 asmSeq :: [Instr] -> InstrList
103 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
105 asmParThen :: [InstrList] -> InstrBlock
106 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
108 returnInstr :: Instr -> UniqSM InstrBlock
109 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
111 returnInstrs :: [Instr] -> UniqSM InstrBlock
112 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
114 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
115 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
117 mkSeqInstr :: Instr -> InstrBlock
118 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
120 mkSeqInstrs :: [Instr] -> InstrBlock
121 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
125 mangleIndexTree :: StixTree -> StixTree
127 mangleIndexTree (StIndex pk base (StInt i))
128 = StPrim IntAddOp [base, off]
130 off = StInt (i * sizeOf pk)
132 #ifndef i386_TARGET_ARCH
133 mangleIndexTree (StIndex pk base off)
134 = StPrim IntAddOp [base,
140 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
141 StPrim SllOp [off, StInt s]
144 shift DoubleRep = 3::Integer
145 shift _ = IF_ARCH_alpha(3,2)
147 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
148 -- that do include the size of the primitive kind we're addressing. When StIndex
149 -- is expanded to actual code, the index (in units) is by the above code approp.
150 -- shifted to get the no. of bytes. Since Address amodes do contain size info
151 -- explicitly, we disable the shifting for x86s.
152 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
158 maybeImm :: StixTree -> Maybe Imm
160 maybeImm (StLitLbl s) = Just (ImmLab s)
161 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
162 maybeImm (StCLbl l) = Just (ImmCLbl l)
164 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
165 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
168 | i >= toInteger minInt && i <= toInteger maxInt
169 = Just (ImmInt (fromInteger i))
171 = Just (ImmInteger i)
176 %************************************************************************
178 \subsection{The @Register@ type}
180 %************************************************************************
182 @Register@s passed up the tree. If the stix code forces the register
183 to live in a pre-decided machine register, it comes out as @Fixed@;
184 otherwise, it comes out as @Any@, and the parent can decide which
185 register to put it in.
189 = Fixed PrimRep Reg InstrBlock
190 | Any PrimRep (Reg -> InstrBlock)
192 registerCode :: Register -> Reg -> InstrBlock
193 registerCode (Fixed _ _ code) reg = code
194 registerCode (Any _ code) reg = code reg
196 registerName :: Register -> Reg -> Reg
197 registerName (Fixed _ reg _) _ = reg
198 registerName (Any _ _) reg = reg
200 registerRep :: Register -> PrimRep
201 registerRep (Fixed pk _ _) = pk
202 registerRep (Any pk _) = pk
204 isFixed :: Register -> Bool
205 isFixed (Fixed _ _ _) = True
206 isFixed (Any _ _) = False
209 Generate code to get a subtree into a @Register@:
211 getRegister :: StixTree -> UniqSM Register
213 getRegister (StReg (StixMagicId stgreg))
214 = case (magicIdRegMaybe stgreg) of
215 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
218 getRegister (StReg (StixTemp u pk))
219 = returnUs (Fixed pk (UnmappedReg u pk) id)
221 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
223 getRegister (StCall fn cconv kind args)
224 = genCCall fn cconv kind args `thenUs` \ call ->
225 returnUs (Fixed kind reg call)
227 reg = if isFloatingRep kind
228 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
229 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
231 getRegister (StString s)
232 = getUniqLabelNCG `thenUs` \ lbl ->
234 imm_lbl = ImmCLbl lbl
236 code dst = mkSeqInstrs [
239 ASCII True (_UNPK_ s),
241 #if alpha_TARGET_ARCH
242 LDA dst (AddrImm imm_lbl)
245 MOV L (OpImm imm_lbl) (OpReg dst)
247 #if sparc_TARGET_ARCH
248 SETHI (HI imm_lbl) dst,
249 OR False dst (RIImm (LO imm_lbl)) dst
253 returnUs (Any PtrRep code)
255 getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
256 = getUniqLabelNCG `thenUs` \ lbl ->
258 imm_lbl = ImmCLbl lbl
260 code dst = mkSeqInstrs [
263 ASCII False (init xs),
265 #if alpha_TARGET_ARCH
266 LDA dst (AddrImm imm_lbl)
269 MOV L (OpImm imm_lbl) (OpReg dst)
271 #if sparc_TARGET_ARCH
272 SETHI (HI imm_lbl) dst,
273 OR False dst (RIImm (LO imm_lbl)) dst
277 returnUs (Any PtrRep code)
279 xs = _UNPK_ (_TAIL_ s)
281 -- end of machine-"independent" bit; here we go on the rest...
283 #if alpha_TARGET_ARCH
285 getRegister (StDouble d)
286 = getUniqLabelNCG `thenUs` \ lbl ->
287 getNewRegNCG PtrRep `thenUs` \ tmp ->
288 let code dst = mkSeqInstrs [
291 DATA TF [ImmLab (rational d)],
293 LDA tmp (AddrImm (ImmCLbl lbl)),
294 LD TF dst (AddrReg tmp)]
296 returnUs (Any DoubleRep code)
298 getRegister (StPrim primop [x]) -- unary PrimOps
300 IntNegOp -> trivialUCode (NEG Q False) x
301 IntAbsOp -> trivialUCode (ABS Q) x
303 NotOp -> trivialUCode NOT x
305 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
306 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
308 OrdOp -> coerceIntCode IntRep x
311 Float2IntOp -> coerceFP2Int x
312 Int2FloatOp -> coerceInt2FP pr x
313 Double2IntOp -> coerceFP2Int x
314 Int2DoubleOp -> coerceInt2FP pr x
316 Double2FloatOp -> coerceFltCode x
317 Float2DoubleOp -> coerceFltCode x
319 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
321 fn = case other_op of
322 FloatExpOp -> SLIT("exp")
323 FloatLogOp -> SLIT("log")
324 FloatSqrtOp -> SLIT("sqrt")
325 FloatSinOp -> SLIT("sin")
326 FloatCosOp -> SLIT("cos")
327 FloatTanOp -> SLIT("tan")
328 FloatAsinOp -> SLIT("asin")
329 FloatAcosOp -> SLIT("acos")
330 FloatAtanOp -> SLIT("atan")
331 FloatSinhOp -> SLIT("sinh")
332 FloatCoshOp -> SLIT("cosh")
333 FloatTanhOp -> SLIT("tanh")
334 DoubleExpOp -> SLIT("exp")
335 DoubleLogOp -> SLIT("log")
336 DoubleSqrtOp -> SLIT("sqrt")
337 DoubleSinOp -> SLIT("sin")
338 DoubleCosOp -> SLIT("cos")
339 DoubleTanOp -> SLIT("tan")
340 DoubleAsinOp -> SLIT("asin")
341 DoubleAcosOp -> SLIT("acos")
342 DoubleAtanOp -> SLIT("atan")
343 DoubleSinhOp -> SLIT("sinh")
344 DoubleCoshOp -> SLIT("cosh")
345 DoubleTanhOp -> SLIT("tanh")
347 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
349 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
351 CharGtOp -> trivialCode (CMP LTT) y x
352 CharGeOp -> trivialCode (CMP LE) y x
353 CharEqOp -> trivialCode (CMP EQQ) x y
354 CharNeOp -> int_NE_code x y
355 CharLtOp -> trivialCode (CMP LTT) x y
356 CharLeOp -> trivialCode (CMP LE) x y
358 IntGtOp -> trivialCode (CMP LTT) y x
359 IntGeOp -> trivialCode (CMP LE) y x
360 IntEqOp -> trivialCode (CMP EQQ) x y
361 IntNeOp -> int_NE_code x y
362 IntLtOp -> trivialCode (CMP LTT) x y
363 IntLeOp -> trivialCode (CMP LE) x y
365 WordGtOp -> trivialCode (CMP ULT) y x
366 WordGeOp -> trivialCode (CMP ULE) x y
367 WordEqOp -> trivialCode (CMP EQQ) x y
368 WordNeOp -> int_NE_code x y
369 WordLtOp -> trivialCode (CMP ULT) x y
370 WordLeOp -> trivialCode (CMP ULE) x y
372 AddrGtOp -> trivialCode (CMP ULT) y x
373 AddrGeOp -> trivialCode (CMP ULE) y x
374 AddrEqOp -> trivialCode (CMP EQQ) x y
375 AddrNeOp -> int_NE_code x y
376 AddrLtOp -> trivialCode (CMP ULT) x y
377 AddrLeOp -> trivialCode (CMP ULE) x y
379 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
380 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
381 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
382 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
383 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
384 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
386 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
387 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
388 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
389 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
390 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
391 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
393 IntAddOp -> trivialCode (ADD Q False) x y
394 IntSubOp -> trivialCode (SUB Q False) x y
395 IntMulOp -> trivialCode (MUL Q False) x y
396 IntQuotOp -> trivialCode (DIV Q False) x y
397 IntRemOp -> trivialCode (REM Q False) x y
399 WordQuotOp -> trivialCode (DIV Q True) x y
400 WordRemOp -> trivialCode (REM Q True) x y
402 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
403 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
404 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
405 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
407 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
408 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
409 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
410 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
412 AndOp -> trivialCode AND x y
413 OrOp -> trivialCode OR x y
414 XorOp -> trivialCode XOR x y
415 SllOp -> trivialCode SLL x y
416 SrlOp -> trivialCode SRL x y
418 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
419 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
420 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
422 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
423 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
425 {- ------------------------------------------------------------
426 Some bizarre special code for getting condition codes into
427 registers. Integer non-equality is a test for equality
428 followed by an XOR with 1. (Integer comparisons always set
429 the result register to 0 or 1.) Floating point comparisons of
430 any kind leave the result in a floating point register, so we
431 need to wrangle an integer register out of things.
433 int_NE_code :: StixTree -> StixTree -> UniqSM Register
436 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
437 getNewRegNCG IntRep `thenUs` \ tmp ->
439 code = registerCode register tmp
440 src = registerName register tmp
441 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
443 returnUs (Any IntRep code__2)
445 {- ------------------------------------------------------------
446 Comments for int_NE_code also apply to cmpF_code
449 :: (Reg -> Reg -> Reg -> Instr)
451 -> StixTree -> StixTree
454 cmpF_code instr cond x y
455 = trivialFCode pr instr x y `thenUs` \ register ->
456 getNewRegNCG DoubleRep `thenUs` \ tmp ->
457 getUniqLabelNCG `thenUs` \ lbl ->
459 code = registerCode register tmp
460 result = registerName register tmp
462 code__2 dst = code . mkSeqInstrs [
463 OR zeroh (RIImm (ImmInt 1)) dst,
464 BF cond result (ImmCLbl lbl),
465 OR zeroh (RIReg zeroh) dst,
468 returnUs (Any IntRep code__2)
470 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
471 ------------------------------------------------------------
473 getRegister (StInd pk mem)
474 = getAmode mem `thenUs` \ amode ->
476 code = amodeCode amode
477 src = amodeAddr amode
478 size = primRepToSize pk
479 code__2 dst = code . mkSeqInstr (LD size dst src)
481 returnUs (Any pk code__2)
483 getRegister (StInt i)
486 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
488 returnUs (Any IntRep code)
491 code dst = mkSeqInstr (LDI Q dst src)
493 returnUs (Any IntRep code)
495 src = ImmInt (fromInteger i)
500 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
502 returnUs (Any PtrRep code)
505 imm__2 = case imm of Just x -> x
507 #endif {- alpha_TARGET_ARCH -}
508 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
511 getRegister (StDouble 0.0)
513 code dst = mkSeqInstrs [FLDZ]
515 returnUs (Any DoubleRep code)
517 getRegister (StDouble 1.0)
519 code dst = mkSeqInstrs [FLD1]
521 returnUs (Any DoubleRep code)
523 getRegister (StDouble d)
524 = getUniqLabelNCG `thenUs` \ lbl ->
525 --getNewRegNCG PtrRep `thenUs` \ tmp ->
526 let code dst = mkSeqInstrs [
529 DATA DF [dblImmLit d],
531 FLD DF (OpImm (ImmCLbl lbl))
534 returnUs (Any DoubleRep code)
536 getRegister (StPrim primop [x]) -- unary PrimOps
538 IntNegOp -> trivialUCode (NEGI L) x
539 IntAbsOp -> absIntCode x
541 NotOp -> trivialUCode (NOT L) x
543 FloatNegOp -> trivialUFCode FloatRep FCHS x
544 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
545 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
547 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
549 OrdOp -> coerceIntCode IntRep x
552 Float2IntOp -> coerceFP2Int x
553 Int2FloatOp -> coerceInt2FP FloatRep x
554 Double2IntOp -> coerceFP2Int x
555 Int2DoubleOp -> coerceInt2FP DoubleRep x
557 Double2FloatOp -> coerceFltCode x
558 Float2DoubleOp -> coerceFltCode x
562 fixed_x = if is_float_op -- promote to double
563 then StPrim Float2DoubleOp [x]
566 getRegister (StCall fn cCallConv DoubleRep [x])
570 FloatExpOp -> (True, SLIT("exp"))
571 FloatLogOp -> (True, SLIT("log"))
573 FloatSinOp -> (True, SLIT("sin"))
574 FloatCosOp -> (True, SLIT("cos"))
575 FloatTanOp -> (True, SLIT("tan"))
577 FloatAsinOp -> (True, SLIT("asin"))
578 FloatAcosOp -> (True, SLIT("acos"))
579 FloatAtanOp -> (True, SLIT("atan"))
581 FloatSinhOp -> (True, SLIT("sinh"))
582 FloatCoshOp -> (True, SLIT("cosh"))
583 FloatTanhOp -> (True, SLIT("tanh"))
585 DoubleExpOp -> (False, SLIT("exp"))
586 DoubleLogOp -> (False, SLIT("log"))
588 DoubleSinOp -> (False, SLIT("sin"))
589 DoubleCosOp -> (False, SLIT("cos"))
590 DoubleTanOp -> (False, SLIT("tan"))
592 DoubleAsinOp -> (False, SLIT("asin"))
593 DoubleAcosOp -> (False, SLIT("acos"))
594 DoubleAtanOp -> (False, SLIT("atan"))
596 DoubleSinhOp -> (False, SLIT("sinh"))
597 DoubleCoshOp -> (False, SLIT("cosh"))
598 DoubleTanhOp -> (False, SLIT("tanh"))
600 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
602 CharGtOp -> condIntReg GTT x y
603 CharGeOp -> condIntReg GE x y
604 CharEqOp -> condIntReg EQQ x y
605 CharNeOp -> condIntReg NE x y
606 CharLtOp -> condIntReg LTT x y
607 CharLeOp -> condIntReg LE x y
609 IntGtOp -> condIntReg GTT x y
610 IntGeOp -> condIntReg GE x y
611 IntEqOp -> condIntReg EQQ x y
612 IntNeOp -> condIntReg NE x y
613 IntLtOp -> condIntReg LTT x y
614 IntLeOp -> condIntReg LE x y
616 WordGtOp -> condIntReg GU x y
617 WordGeOp -> condIntReg GEU x y
618 WordEqOp -> condIntReg EQQ x y
619 WordNeOp -> condIntReg NE x y
620 WordLtOp -> condIntReg LU x y
621 WordLeOp -> condIntReg LEU x y
623 AddrGtOp -> condIntReg GU x y
624 AddrGeOp -> condIntReg GEU x y
625 AddrEqOp -> condIntReg EQQ x y
626 AddrNeOp -> condIntReg NE x y
627 AddrLtOp -> condIntReg LU x y
628 AddrLeOp -> condIntReg LEU x y
630 FloatGtOp -> condFltReg GTT x y
631 FloatGeOp -> condFltReg GE x y
632 FloatEqOp -> condFltReg EQQ x y
633 FloatNeOp -> condFltReg NE x y
634 FloatLtOp -> condFltReg LTT x y
635 FloatLeOp -> condFltReg LE x y
637 DoubleGtOp -> condFltReg GTT x y
638 DoubleGeOp -> condFltReg GE x y
639 DoubleEqOp -> condFltReg EQQ x y
640 DoubleNeOp -> condFltReg NE x y
641 DoubleLtOp -> condFltReg LTT x y
642 DoubleLeOp -> condFltReg LE x y
644 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
645 -- this should be optimised by the generic Opts,
646 -- I don't know why it is not (sometimes)!
648 [x, StInt 0] -> getRegister x
653 IntSubOp -> sub_code L x y
654 IntQuotOp -> quot_code L x y True{-division-}
655 IntRemOp -> quot_code L x y False{-remainder-}
656 IntMulOp -> trivialCode (IMUL L) x y {-True-}
658 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
659 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
660 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
661 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
663 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
664 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
665 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
666 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
668 AndOp -> trivialCode (AND L) x y {-True-}
669 OrOp -> trivialCode (OR L) x y {-True-}
670 XorOp -> trivialCode (XOR L) x y {-True-}
672 {- Shift ops on x86s have constraints on their source, it
673 either has to be Imm, CL or 1
674 => trivialCode's is not restrictive enough (sigh.)
677 SllOp -> shift_code (SHL L) x y {-False-}
678 SrlOp -> shift_code (SHR L) x y {-False-}
680 ISllOp -> shift_code (SHL L) x y {-False-} --was:panic "I386Gen:isll"
681 ISraOp -> shift_code (SAR L) x y {-False-} --was:panic "I386Gen:isra"
682 ISrlOp -> shift_code (SHR L) x y {-False-} --was:panic "I386Gen:isrl"
684 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
685 where promote x = StPrim Float2DoubleOp [x]
686 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
688 shift_code :: (Operand -> Operand -> Instr)
692 {- Case1: shift length as immediate -}
693 -- Code is the same as the first eq. for trivialCode -- sigh.
694 shift_code instr x y{-amount-}
696 = getRegister x `thenUs` \ register ->
698 op_imm = OpImm imm__2
701 code = registerCode register dst
702 src = registerName register dst
704 mkSeqInstr (COMMENT SLIT("shift_code")) .
706 if isFixed register && src /= dst
708 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
709 instr op_imm (OpReg dst)]
711 mkSeqInstr (instr op_imm (OpReg src))
713 returnUs (Any IntRep code__2)
716 imm__2 = case imm of Just x -> x
718 {- Case2: shift length is complex (non-immediate) -}
719 shift_code instr x y{-amount-}
720 = getRegister y `thenUs` \ register1 ->
721 getRegister x `thenUs` \ register2 ->
722 -- getNewRegNCG IntRep `thenUs` \ dst ->
724 -- Note: we force the shift length to be loaded
725 -- into ECX, so that we can use CL when shifting.
726 -- (only register location we are allowed
727 -- to put shift amounts.)
729 -- The shift instruction is fed ECX as src reg,
730 -- but we coerce this into CL when printing out.
731 src1 = registerName register1 ecx
732 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
733 registerCode register1 ecx .
734 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
736 registerCode register1 ecx
739 code2 = registerCode register2 eax
740 src2 = registerName register2 eax
743 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
745 returnUs (Fixed IntRep eax code__2)
747 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
749 add_code sz x (StInt y)
750 = getRegister x `thenUs` \ register ->
751 getNewRegNCG IntRep `thenUs` \ tmp ->
753 code = registerCode register tmp
754 src1 = registerName register tmp
755 src2 = ImmInt (fromInteger y)
757 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
759 returnUs (Any IntRep code__2)
761 add_code sz x (StInd _ mem)
762 = getRegister x `thenUs` \ register1 ->
763 --getNewRegNCG (registerRep register1)
764 -- `thenUs` \ tmp1 ->
765 getAmode mem `thenUs` \ amode ->
767 code2 = amodeCode amode
768 src2 = amodeAddr amode
770 -- fixedname = registerName register1 eax
771 code__2 dst = let code1 = registerCode register1 dst
772 src1 = registerName register1 dst
773 in asmParThen [code2 asmVoid,code1 asmVoid] .
774 if isFixed register1 && src1 /= dst
775 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
776 ADD sz (OpAddr src2) (OpReg dst)]
778 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
780 returnUs (Any IntRep code__2)
782 add_code sz (StInd _ mem) y
783 = getRegister y `thenUs` \ register2 ->
784 --getNewRegNCG (registerRep register2)
785 -- `thenUs` \ tmp2 ->
786 getAmode mem `thenUs` \ amode ->
788 code1 = amodeCode amode
789 src1 = amodeAddr amode
791 -- fixedname = registerName register2 eax
792 code__2 dst = let code2 = registerCode register2 dst
793 src2 = registerName register2 dst
794 in asmParThen [code1 asmVoid,code2 asmVoid] .
795 if isFixed register2 && src2 /= dst
796 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
797 ADD sz (OpAddr src1) (OpReg dst)]
799 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
801 returnUs (Any IntRep code__2)
804 = getRegister x `thenUs` \ register1 ->
805 getRegister y `thenUs` \ register2 ->
806 getNewRegNCG IntRep `thenUs` \ tmp1 ->
807 getNewRegNCG IntRep `thenUs` \ tmp2 ->
809 code1 = registerCode register1 tmp1 asmVoid
810 src1 = registerName register1 tmp1
811 code2 = registerCode register2 tmp2 asmVoid
812 src2 = registerName register2 tmp2
813 code__2 dst = asmParThen [code1, code2] .
814 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
816 returnUs (Any IntRep code__2)
819 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
821 sub_code sz x (StInt y)
822 = getRegister x `thenUs` \ register ->
823 getNewRegNCG IntRep `thenUs` \ tmp ->
825 code = registerCode register tmp
826 src1 = registerName register tmp
827 src2 = ImmInt (-(fromInteger y))
829 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
831 returnUs (Any IntRep code__2)
833 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
838 -> StixTree -> StixTree
839 -> Bool -- True => division, False => remainder operation
842 -- x must go into eax, edx must be a sign-extension of eax, and y
843 -- should go in some other register (or memory), so that we get
844 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
845 -- put y in memory (if it is not there already)
847 quot_code sz x (StInd pk mem) is_division
848 = getRegister x `thenUs` \ register1 ->
849 getNewRegNCG IntRep `thenUs` \ tmp1 ->
850 getAmode mem `thenUs` \ amode ->
852 code1 = registerCode register1 tmp1 asmVoid
853 src1 = registerName register1 tmp1
854 code2 = amodeCode amode asmVoid
855 src2 = amodeAddr amode
856 code__2 = asmParThen [code1, code2] .
857 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
859 IDIV sz (OpAddr src2)]
861 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
863 quot_code sz x (StInt i) is_division
864 = getRegister x `thenUs` \ register1 ->
865 getNewRegNCG IntRep `thenUs` \ tmp1 ->
867 code1 = registerCode register1 tmp1 asmVoid
868 src1 = registerName register1 tmp1
869 src2 = ImmInt (fromInteger i)
870 code__2 = asmParThen [code1] .
871 mkSeqInstrs [-- we put src2 in (ebx)
872 MOV L (OpImm src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
873 MOV L (OpReg src1) (OpReg eax),
875 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
877 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
879 quot_code sz x y is_division
880 = getRegister x `thenUs` \ register1 ->
881 getNewRegNCG IntRep `thenUs` \ tmp1 ->
882 getRegister y `thenUs` \ register2 ->
883 getNewRegNCG IntRep `thenUs` \ tmp2 ->
885 code1 = registerCode register1 tmp1 asmVoid
886 src1 = registerName register1 tmp1
887 code2 = registerCode register2 tmp2 asmVoid
888 src2 = registerName register2 tmp2
889 code__2 = asmParThen [code1, code2] .
890 if src2 == ecx || src2 == esi
891 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
893 IDIV sz (OpReg src2)]
894 else mkSeqInstrs [ -- we put src2 in (ebx)
895 MOV L (OpReg src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
896 MOV L (OpReg src1) (OpReg eax),
898 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
900 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
901 -----------------------
903 getRegister (StInd pk mem)
904 = getAmode mem `thenUs` \ amode ->
906 code = amodeCode amode
907 src = amodeAddr amode
908 size = primRepToSize pk
910 if pk == DoubleRep || pk == FloatRep
911 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
912 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
914 returnUs (Any pk code__2)
917 getRegister (StInt i)
919 src = ImmInt (fromInteger i)
920 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
922 returnUs (Any IntRep code)
927 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
929 returnUs (Any PtrRep code)
932 imm__2 = case imm of Just x -> x
934 #endif {- i386_TARGET_ARCH -}
935 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
936 #if sparc_TARGET_ARCH
938 getRegister (StDouble d)
939 = getUniqLabelNCG `thenUs` \ lbl ->
940 getNewRegNCG PtrRep `thenUs` \ tmp ->
941 let code dst = mkSeqInstrs [
944 DATA DF [dblImmLit d],
946 SETHI (HI (ImmCLbl lbl)) tmp,
947 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
949 returnUs (Any DoubleRep code)
951 getRegister (StPrim primop [x]) -- unary PrimOps
953 IntNegOp -> trivialUCode (SUB False False g0) x
954 IntAbsOp -> absIntCode x
955 NotOp -> trivialUCode (XNOR False g0) x
957 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
959 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
961 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
962 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
964 OrdOp -> coerceIntCode IntRep x
967 Float2IntOp -> coerceFP2Int x
968 Int2FloatOp -> coerceInt2FP FloatRep x
969 Double2IntOp -> coerceFP2Int x
970 Int2DoubleOp -> coerceInt2FP DoubleRep x
974 fixed_x = if is_float_op -- promote to double
975 then StPrim Float2DoubleOp [x]
978 getRegister (StCall fn cCallConv DoubleRep [x])
982 FloatExpOp -> (True, SLIT("exp"))
983 FloatLogOp -> (True, SLIT("log"))
984 FloatSqrtOp -> (True, SLIT("sqrt"))
986 FloatSinOp -> (True, SLIT("sin"))
987 FloatCosOp -> (True, SLIT("cos"))
988 FloatTanOp -> (True, SLIT("tan"))
990 FloatAsinOp -> (True, SLIT("asin"))
991 FloatAcosOp -> (True, SLIT("acos"))
992 FloatAtanOp -> (True, SLIT("atan"))
994 FloatSinhOp -> (True, SLIT("sinh"))
995 FloatCoshOp -> (True, SLIT("cosh"))
996 FloatTanhOp -> (True, SLIT("tanh"))
998 DoubleExpOp -> (False, SLIT("exp"))
999 DoubleLogOp -> (False, SLIT("log"))
1000 DoubleSqrtOp -> (True, SLIT("sqrt"))
1002 DoubleSinOp -> (False, SLIT("sin"))
1003 DoubleCosOp -> (False, SLIT("cos"))
1004 DoubleTanOp -> (False, SLIT("tan"))
1006 DoubleAsinOp -> (False, SLIT("asin"))
1007 DoubleAcosOp -> (False, SLIT("acos"))
1008 DoubleAtanOp -> (False, SLIT("atan"))
1010 DoubleSinhOp -> (False, SLIT("sinh"))
1011 DoubleCoshOp -> (False, SLIT("cosh"))
1012 DoubleTanhOp -> (False, SLIT("tanh"))
1013 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
1015 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1017 CharGtOp -> condIntReg GTT x y
1018 CharGeOp -> condIntReg GE x y
1019 CharEqOp -> condIntReg EQQ x y
1020 CharNeOp -> condIntReg NE x y
1021 CharLtOp -> condIntReg LTT x y
1022 CharLeOp -> condIntReg LE x y
1024 IntGtOp -> condIntReg GTT x y
1025 IntGeOp -> condIntReg GE x y
1026 IntEqOp -> condIntReg EQQ x y
1027 IntNeOp -> condIntReg NE x y
1028 IntLtOp -> condIntReg LTT x y
1029 IntLeOp -> condIntReg LE x y
1031 WordGtOp -> condIntReg GU x y
1032 WordGeOp -> condIntReg GEU x y
1033 WordEqOp -> condIntReg EQQ x y
1034 WordNeOp -> condIntReg NE x y
1035 WordLtOp -> condIntReg LU x y
1036 WordLeOp -> condIntReg LEU x y
1038 AddrGtOp -> condIntReg GU x y
1039 AddrGeOp -> condIntReg GEU x y
1040 AddrEqOp -> condIntReg EQQ x y
1041 AddrNeOp -> condIntReg NE x y
1042 AddrLtOp -> condIntReg LU x y
1043 AddrLeOp -> condIntReg LEU x y
1045 FloatGtOp -> condFltReg GTT x y
1046 FloatGeOp -> condFltReg GE x y
1047 FloatEqOp -> condFltReg EQQ x y
1048 FloatNeOp -> condFltReg NE x y
1049 FloatLtOp -> condFltReg LTT x y
1050 FloatLeOp -> condFltReg LE x y
1052 DoubleGtOp -> condFltReg GTT x y
1053 DoubleGeOp -> condFltReg GE x y
1054 DoubleEqOp -> condFltReg EQQ x y
1055 DoubleNeOp -> condFltReg NE x y
1056 DoubleLtOp -> condFltReg LTT x y
1057 DoubleLeOp -> condFltReg LE x y
1059 IntAddOp -> trivialCode (ADD False False) x y
1060 IntSubOp -> trivialCode (SUB False False) x y
1062 -- ToDo: teach about V8+ SPARC mul/div instructions
1063 IntMulOp -> imul_div SLIT(".umul") x y
1064 IntQuotOp -> imul_div SLIT(".div") x y
1065 IntRemOp -> imul_div SLIT(".rem") x y
1067 FloatAddOp -> trivialFCode FloatRep FADD x y
1068 FloatSubOp -> trivialFCode FloatRep FSUB x y
1069 FloatMulOp -> trivialFCode FloatRep FMUL x y
1070 FloatDivOp -> trivialFCode FloatRep FDIV x y
1072 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1073 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1074 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1075 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1077 AndOp -> trivialCode (AND False) x y
1078 OrOp -> trivialCode (OR False) x y
1079 XorOp -> trivialCode (XOR False) x y
1080 SllOp -> trivialCode SLL x y
1081 SrlOp -> trivialCode SRL x y
1083 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1084 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1085 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1087 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1088 where promote x = StPrim Float2DoubleOp [x]
1089 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1090 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1092 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1094 getRegister (StInd pk mem)
1095 = getAmode mem `thenUs` \ amode ->
1097 code = amodeCode amode
1098 src = amodeAddr amode
1099 size = primRepToSize pk
1100 code__2 dst = code . mkSeqInstr (LD size src dst)
1102 returnUs (Any pk code__2)
1104 getRegister (StInt i)
1107 src = ImmInt (fromInteger i)
1108 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1110 returnUs (Any IntRep code)
1115 code dst = mkSeqInstrs [
1116 SETHI (HI imm__2) dst,
1117 OR False dst (RIImm (LO imm__2)) dst]
1119 returnUs (Any PtrRep code)
1122 imm__2 = case imm of Just x -> x
1124 #endif {- sparc_TARGET_ARCH -}
1127 %************************************************************************
1129 \subsection{The @Amode@ type}
1131 %************************************************************************
1133 @Amode@s: Memory addressing modes passed up the tree.
1135 data Amode = Amode MachRegsAddr InstrBlock
1137 amodeAddr (Amode addr _) = addr
1138 amodeCode (Amode _ code) = code
1141 Now, given a tree (the argument to an StInd) that references memory,
1142 produce a suitable addressing mode.
1145 getAmode :: StixTree -> UniqSM Amode
1147 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1149 #if alpha_TARGET_ARCH
1151 getAmode (StPrim IntSubOp [x, StInt i])
1152 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1153 getRegister x `thenUs` \ register ->
1155 code = registerCode register tmp
1156 reg = registerName register tmp
1157 off = ImmInt (-(fromInteger i))
1159 returnUs (Amode (AddrRegImm reg off) code)
1161 getAmode (StPrim IntAddOp [x, StInt i])
1162 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1163 getRegister x `thenUs` \ register ->
1165 code = registerCode register tmp
1166 reg = registerName register tmp
1167 off = ImmInt (fromInteger i)
1169 returnUs (Amode (AddrRegImm reg off) code)
1173 = returnUs (Amode (AddrImm imm__2) id)
1176 imm__2 = case imm of Just x -> x
1179 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1180 getRegister other `thenUs` \ register ->
1182 code = registerCode register tmp
1183 reg = registerName register tmp
1185 returnUs (Amode (AddrReg reg) code)
1187 #endif {- alpha_TARGET_ARCH -}
1188 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1189 #if i386_TARGET_ARCH
1191 getAmode (StPrim IntSubOp [x, StInt i])
1192 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1193 getRegister x `thenUs` \ register ->
1195 code = registerCode register tmp
1196 reg = registerName register tmp
1197 off = ImmInt (-(fromInteger i))
1199 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1201 getAmode (StPrim IntAddOp [x, StInt i])
1204 code = mkSeqInstrs []
1206 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1209 imm__2 = case imm of Just x -> x
1211 getAmode (StPrim IntAddOp [x, StInt i])
1212 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1213 getRegister x `thenUs` \ register ->
1215 code = registerCode register tmp
1216 reg = registerName register tmp
1217 off = ImmInt (fromInteger i)
1219 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1221 getAmode (StPrim IntAddOp [x, y])
1222 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1223 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1224 getRegister x `thenUs` \ register1 ->
1225 getRegister y `thenUs` \ register2 ->
1227 code1 = registerCode register1 tmp1 asmVoid
1228 reg1 = registerName register1 tmp1
1229 code2 = registerCode register2 tmp2 asmVoid
1230 reg2 = registerName register2 tmp2
1231 code__2 = asmParThen [code1, code2]
1233 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1238 code = mkSeqInstrs []
1240 returnUs (Amode (ImmAddr imm__2 0) code)
1243 imm__2 = case imm of Just x -> x
1246 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1247 getRegister other `thenUs` \ register ->
1249 code = registerCode register tmp
1250 reg = registerName register tmp
1253 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1255 #endif {- i386_TARGET_ARCH -}
1256 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1257 #if sparc_TARGET_ARCH
1259 getAmode (StPrim IntSubOp [x, StInt i])
1261 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1262 getRegister x `thenUs` \ register ->
1264 code = registerCode register tmp
1265 reg = registerName register tmp
1266 off = ImmInt (-(fromInteger i))
1268 returnUs (Amode (AddrRegImm reg off) code)
1271 getAmode (StPrim IntAddOp [x, StInt i])
1273 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1274 getRegister x `thenUs` \ register ->
1276 code = registerCode register tmp
1277 reg = registerName register tmp
1278 off = ImmInt (fromInteger i)
1280 returnUs (Amode (AddrRegImm reg off) code)
1282 getAmode (StPrim IntAddOp [x, y])
1283 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1284 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1285 getRegister x `thenUs` \ register1 ->
1286 getRegister y `thenUs` \ register2 ->
1288 code1 = registerCode register1 tmp1 asmVoid
1289 reg1 = registerName register1 tmp1
1290 code2 = registerCode register2 tmp2 asmVoid
1291 reg2 = registerName register2 tmp2
1292 code__2 = asmParThen [code1, code2]
1294 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1298 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1300 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1302 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1305 imm__2 = case imm of Just x -> x
1308 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1309 getRegister other `thenUs` \ register ->
1311 code = registerCode register tmp
1312 reg = registerName register tmp
1315 returnUs (Amode (AddrRegImm reg off) code)
1317 #endif {- sparc_TARGET_ARCH -}
1320 %************************************************************************
1322 \subsection{The @CondCode@ type}
1324 %************************************************************************
1326 Condition codes passed up the tree.
1328 data CondCode = CondCode Bool Cond InstrBlock
1330 condName (CondCode _ cond _) = cond
1331 condFloat (CondCode is_float _ _) = is_float
1332 condCode (CondCode _ _ code) = code
1335 Set up a condition code for a conditional branch.
1338 getCondCode :: StixTree -> UniqSM CondCode
1340 #if alpha_TARGET_ARCH
1341 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1342 #endif {- alpha_TARGET_ARCH -}
1343 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1345 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1346 -- yes, they really do seem to want exactly the same!
1348 getCondCode (StPrim primop [x, y])
1350 CharGtOp -> condIntCode GTT x y
1351 CharGeOp -> condIntCode GE x y
1352 CharEqOp -> condIntCode EQQ x y
1353 CharNeOp -> condIntCode NE x y
1354 CharLtOp -> condIntCode LTT x y
1355 CharLeOp -> condIntCode LE x y
1357 IntGtOp -> condIntCode GTT x y
1358 IntGeOp -> condIntCode GE x y
1359 IntEqOp -> condIntCode EQQ x y
1360 IntNeOp -> condIntCode NE x y
1361 IntLtOp -> condIntCode LTT x y
1362 IntLeOp -> condIntCode LE x y
1364 WordGtOp -> condIntCode GU x y
1365 WordGeOp -> condIntCode GEU x y
1366 WordEqOp -> condIntCode EQQ x y
1367 WordNeOp -> condIntCode NE x y
1368 WordLtOp -> condIntCode LU x y
1369 WordLeOp -> condIntCode LEU x y
1371 AddrGtOp -> condIntCode GU x y
1372 AddrGeOp -> condIntCode GEU x y
1373 AddrEqOp -> condIntCode EQQ x y
1374 AddrNeOp -> condIntCode NE x y
1375 AddrLtOp -> condIntCode LU x y
1376 AddrLeOp -> condIntCode LEU x y
1378 FloatGtOp -> condFltCode GTT x y
1379 FloatGeOp -> condFltCode GE x y
1380 FloatEqOp -> condFltCode EQQ x y
1381 FloatNeOp -> condFltCode NE x y
1382 FloatLtOp -> condFltCode LTT x y
1383 FloatLeOp -> condFltCode LE x y
1385 DoubleGtOp -> condFltCode GTT x y
1386 DoubleGeOp -> condFltCode GE x y
1387 DoubleEqOp -> condFltCode EQQ x y
1388 DoubleNeOp -> condFltCode NE x y
1389 DoubleLtOp -> condFltCode LTT x y
1390 DoubleLeOp -> condFltCode LE x y
1392 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1397 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1398 passed back up the tree.
1401 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1403 #if alpha_TARGET_ARCH
1404 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1405 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1406 #endif {- alpha_TARGET_ARCH -}
1408 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1409 #if i386_TARGET_ARCH
1411 condIntCode cond (StInd _ x) y
1413 = getAmode x `thenUs` \ amode ->
1415 code1 = amodeCode amode asmVoid
1416 y__2 = amodeAddr amode
1417 code__2 = asmParThen [code1] .
1418 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1420 returnUs (CondCode False cond code__2)
1423 imm__2 = case imm of Just x -> x
1425 condIntCode cond x (StInt 0)
1426 = getRegister x `thenUs` \ register1 ->
1427 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1429 code1 = registerCode register1 tmp1 asmVoid
1430 src1 = registerName register1 tmp1
1431 code__2 = asmParThen [code1] .
1432 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1434 returnUs (CondCode False cond code__2)
1436 condIntCode cond x y
1438 = getRegister x `thenUs` \ register1 ->
1439 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1441 code1 = registerCode register1 tmp1 asmVoid
1442 src1 = registerName register1 tmp1
1443 code__2 = asmParThen [code1] .
1444 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1446 returnUs (CondCode False cond code__2)
1449 imm__2 = case imm of Just x -> x
1451 condIntCode cond (StInd _ x) y
1452 = getAmode x `thenUs` \ amode ->
1453 getRegister y `thenUs` \ register2 ->
1454 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1456 code1 = amodeCode amode asmVoid
1457 src1 = amodeAddr amode
1458 code2 = registerCode register2 tmp2 asmVoid
1459 src2 = registerName register2 tmp2
1460 code__2 = asmParThen [code1, code2] .
1461 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1463 returnUs (CondCode False cond code__2)
1465 condIntCode cond y (StInd _ x)
1466 = getAmode x `thenUs` \ amode ->
1467 getRegister y `thenUs` \ register2 ->
1468 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1470 code1 = amodeCode amode asmVoid
1471 src1 = amodeAddr amode
1472 code2 = registerCode register2 tmp2 asmVoid
1473 src2 = registerName register2 tmp2
1474 code__2 = asmParThen [code1, code2] .
1475 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1477 returnUs (CondCode False cond code__2)
1479 condIntCode cond x y
1480 = getRegister x `thenUs` \ register1 ->
1481 getRegister y `thenUs` \ register2 ->
1482 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1483 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1485 code1 = registerCode register1 tmp1 asmVoid
1486 src1 = registerName register1 tmp1
1487 code2 = registerCode register2 tmp2 asmVoid
1488 src2 = registerName register2 tmp2
1489 code__2 = asmParThen [code1, code2] .
1490 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1492 returnUs (CondCode False cond code__2)
1496 condFltCode cond x (StDouble 0.0)
1497 = getRegister x `thenUs` \ register1 ->
1498 getNewRegNCG (registerRep register1)
1501 pk1 = registerRep register1
1502 code1 = registerCode register1 tmp1
1503 src1 = registerName register1 tmp1
1505 code__2 = asmParThen [code1 asmVoid] .
1506 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1508 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1509 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1513 returnUs (CondCode True (fix_FP_cond cond) code__2)
1515 condFltCode cond x y
1516 = getRegister x `thenUs` \ register1 ->
1517 getRegister y `thenUs` \ register2 ->
1518 getNewRegNCG (registerRep register1)
1520 getNewRegNCG (registerRep register2)
1523 pk1 = registerRep register1
1524 code1 = registerCode register1 tmp1
1525 src1 = registerName register1 tmp1
1527 code2 = registerCode register2 tmp2
1528 src2 = registerName register2 tmp2
1530 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1531 mkSeqInstrs [FUCOMPP,
1533 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1534 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1538 returnUs (CondCode True (fix_FP_cond cond) code__2)
1540 {- On the 486, the flags set by FP compare are the unsigned ones!
1541 (This looks like a HACK to me. WDP 96/03)
1544 fix_FP_cond :: Cond -> Cond
1546 fix_FP_cond GE = GEU
1547 fix_FP_cond GTT = GU
1548 fix_FP_cond LTT = LU
1549 fix_FP_cond LE = LEU
1550 fix_FP_cond any = any
1552 #endif {- i386_TARGET_ARCH -}
1553 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1554 #if sparc_TARGET_ARCH
1556 condIntCode cond x (StInt y)
1558 = getRegister x `thenUs` \ register ->
1559 getNewRegNCG IntRep `thenUs` \ tmp ->
1561 code = registerCode register tmp
1562 src1 = registerName register tmp
1563 src2 = ImmInt (fromInteger y)
1564 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1566 returnUs (CondCode False cond code__2)
1568 condIntCode cond x y
1569 = getRegister x `thenUs` \ register1 ->
1570 getRegister y `thenUs` \ register2 ->
1571 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1572 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1574 code1 = registerCode register1 tmp1 asmVoid
1575 src1 = registerName register1 tmp1
1576 code2 = registerCode register2 tmp2 asmVoid
1577 src2 = registerName register2 tmp2
1578 code__2 = asmParThen [code1, code2] .
1579 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1581 returnUs (CondCode False cond code__2)
1584 condFltCode cond x y
1585 = getRegister x `thenUs` \ register1 ->
1586 getRegister y `thenUs` \ register2 ->
1587 getNewRegNCG (registerRep register1)
1589 getNewRegNCG (registerRep register2)
1591 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1593 promote x = asmInstr (FxTOy F DF x tmp)
1595 pk1 = registerRep register1
1596 code1 = registerCode register1 tmp1
1597 src1 = registerName register1 tmp1
1599 pk2 = registerRep register2
1600 code2 = registerCode register2 tmp2
1601 src2 = registerName register2 tmp2
1605 asmParThen [code1 asmVoid, code2 asmVoid] .
1606 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1607 else if pk1 == FloatRep then
1608 asmParThen [code1 (promote src1), code2 asmVoid] .
1609 mkSeqInstr (FCMP True DF tmp src2)
1611 asmParThen [code1 asmVoid, code2 (promote src2)] .
1612 mkSeqInstr (FCMP True DF src1 tmp)
1614 returnUs (CondCode True cond code__2)
1616 #endif {- sparc_TARGET_ARCH -}
1619 %************************************************************************
1621 \subsection{Generating assignments}
1623 %************************************************************************
1625 Assignments are really at the heart of the whole code generation
1626 business. Almost all top-level nodes of any real importance are
1627 assignments, which correspond to loads, stores, or register transfers.
1628 If we're really lucky, some of the register transfers will go away,
1629 because we can use the destination register to complete the code
1630 generation for the right hand side. This only fails when the right
1631 hand side is forced into a fixed register (e.g. the result of a call).
1634 assignIntCode, assignFltCode
1635 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1637 #if alpha_TARGET_ARCH
1639 assignIntCode pk (StInd _ dst) src
1640 = getNewRegNCG IntRep `thenUs` \ tmp ->
1641 getAmode dst `thenUs` \ amode ->
1642 getRegister src `thenUs` \ register ->
1644 code1 = amodeCode amode asmVoid
1645 dst__2 = amodeAddr amode
1646 code2 = registerCode register tmp asmVoid
1647 src__2 = registerName register tmp
1648 sz = primRepToSize pk
1649 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1653 assignIntCode pk dst src
1654 = getRegister dst `thenUs` \ register1 ->
1655 getRegister src `thenUs` \ register2 ->
1657 dst__2 = registerName register1 zeroh
1658 code = registerCode register2 dst__2
1659 src__2 = registerName register2 dst__2
1660 code__2 = if isFixed register2
1661 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1666 #endif {- alpha_TARGET_ARCH -}
1667 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1668 #if i386_TARGET_ARCH
1670 assignIntCode pk (StInd _ dst) src
1671 = getAmode dst `thenUs` \ amode ->
1672 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1674 code1 = amodeCode amode asmVoid
1675 dst__2 = amodeAddr amode
1676 code__2 = asmParThen [code1, codesrc asmVoid] .
1677 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1683 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1687 = returnUs (asmParThen [], OpImm imm_op, L)
1690 imm_op = case imm of Just x -> x
1693 = getRegister op `thenUs` \ register ->
1694 getNewRegNCG (registerRep register)
1697 code = registerCode register tmp
1698 reg = registerName register tmp
1699 pk = registerRep register
1700 sz = primRepToSize pk
1702 returnUs (code, OpReg reg, sz)
1704 assignIntCode pk dst (StInd _ src)
1705 = getNewRegNCG IntRep `thenUs` \ tmp ->
1706 getAmode src `thenUs` \ amode ->
1707 getRegister dst `thenUs` \ register ->
1709 code1 = amodeCode amode asmVoid
1710 src__2 = amodeAddr amode
1711 code2 = registerCode register tmp asmVoid
1712 dst__2 = registerName register tmp
1713 sz = primRepToSize pk
1714 code__2 = asmParThen [code1, code2] .
1715 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1719 assignIntCode pk dst src
1720 = getRegister dst `thenUs` \ register1 ->
1721 getRegister src `thenUs` \ register2 ->
1722 getNewRegNCG IntRep `thenUs` \ tmp ->
1724 dst__2 = registerName register1 tmp
1725 code = registerCode register2 dst__2
1726 src__2 = registerName register2 dst__2
1727 code__2 = if isFixed register2 && dst__2 /= src__2
1728 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1733 #endif {- i386_TARGET_ARCH -}
1734 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1735 #if sparc_TARGET_ARCH
1737 assignIntCode pk (StInd _ dst) src
1738 = getNewRegNCG IntRep `thenUs` \ tmp ->
1739 getAmode dst `thenUs` \ amode ->
1740 getRegister src `thenUs` \ register ->
1742 code1 = amodeCode amode asmVoid
1743 dst__2 = amodeAddr amode
1744 code2 = registerCode register tmp asmVoid
1745 src__2 = registerName register tmp
1746 sz = primRepToSize pk
1747 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1751 assignIntCode pk dst src
1752 = getRegister dst `thenUs` \ register1 ->
1753 getRegister src `thenUs` \ register2 ->
1755 dst__2 = registerName register1 g0
1756 code = registerCode register2 dst__2
1757 src__2 = registerName register2 dst__2
1758 code__2 = if isFixed register2
1759 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1764 #endif {- sparc_TARGET_ARCH -}
1767 % --------------------------------
1768 Floating-point assignments:
1769 % --------------------------------
1771 #if alpha_TARGET_ARCH
1773 assignFltCode pk (StInd _ dst) src
1774 = getNewRegNCG pk `thenUs` \ tmp ->
1775 getAmode dst `thenUs` \ amode ->
1776 getRegister src `thenUs` \ register ->
1778 code1 = amodeCode amode asmVoid
1779 dst__2 = amodeAddr amode
1780 code2 = registerCode register tmp asmVoid
1781 src__2 = registerName register tmp
1782 sz = primRepToSize pk
1783 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1787 assignFltCode pk dst src
1788 = getRegister dst `thenUs` \ register1 ->
1789 getRegister src `thenUs` \ register2 ->
1791 dst__2 = registerName register1 zeroh
1792 code = registerCode register2 dst__2
1793 src__2 = registerName register2 dst__2
1794 code__2 = if isFixed register2
1795 then code . mkSeqInstr (FMOV src__2 dst__2)
1800 #endif {- alpha_TARGET_ARCH -}
1801 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1802 #if i386_TARGET_ARCH
1804 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1805 = getNewRegNCG IntRep `thenUs` \ tmp ->
1806 getAmode src `thenUs` \ amodesrc ->
1807 getAmode dst `thenUs` \ amodedst ->
1808 --getRegister src `thenUs` \ register ->
1810 codesrc1 = amodeCode amodesrc asmVoid
1811 addrsrc1 = amodeAddr amodesrc
1812 codedst1 = amodeCode amodedst asmVoid
1813 addrdst1 = amodeAddr amodedst
1814 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1815 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1817 code__2 = asmParThen [codesrc1, codedst1] .
1818 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1819 MOV L (OpReg tmp) (OpAddr addrdst1)]
1822 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1823 MOV L (OpReg tmp) (OpAddr addrdst2)]
1828 assignFltCode pk (StInd _ dst) src
1829 = --getNewRegNCG pk `thenUs` \ tmp ->
1830 getAmode dst `thenUs` \ amode ->
1831 getRegister src `thenUs` \ register ->
1833 sz = primRepToSize pk
1834 dst__2 = amodeAddr amode
1836 code1 = amodeCode amode asmVoid
1837 code2 = registerCode register {-tmp-}st0 asmVoid
1839 --src__2= registerName register tmp
1840 pk__2 = registerRep register
1841 sz__2 = primRepToSize pk__2
1843 code__2 = asmParThen [code1, code2] .
1844 mkSeqInstr (FSTP sz (OpAddr dst__2))
1848 assignFltCode pk dst src
1849 = getRegister dst `thenUs` \ register1 ->
1850 getRegister src `thenUs` \ register2 ->
1851 --getNewRegNCG (registerRep register2)
1852 -- `thenUs` \ tmp ->
1854 sz = primRepToSize pk
1855 dst__2 = registerName register1 st0 --tmp
1857 code = registerCode register2 dst__2
1858 src__2 = registerName register2 dst__2
1864 #endif {- i386_TARGET_ARCH -}
1865 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1866 #if sparc_TARGET_ARCH
1868 assignFltCode pk (StInd _ dst) src
1869 = getNewRegNCG pk `thenUs` \ tmp1 ->
1870 getAmode dst `thenUs` \ amode ->
1871 getRegister src `thenUs` \ register ->
1873 sz = primRepToSize pk
1874 dst__2 = amodeAddr amode
1876 code1 = amodeCode amode asmVoid
1877 code2 = registerCode register tmp1 asmVoid
1879 src__2 = registerName register tmp1
1880 pk__2 = registerRep register
1881 sz__2 = primRepToSize pk__2
1883 code__2 = asmParThen [code1, code2] .
1885 mkSeqInstr (ST sz src__2 dst__2)
1887 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1891 assignFltCode pk dst src
1892 = getRegister dst `thenUs` \ register1 ->
1893 getRegister src `thenUs` \ register2 ->
1895 pk__2 = registerRep register2
1896 sz__2 = primRepToSize pk__2
1898 getNewRegNCG pk__2 `thenUs` \ tmp ->
1900 sz = primRepToSize pk
1901 dst__2 = registerName register1 g0 -- must be Fixed
1904 reg__2 = if pk /= pk__2 then tmp else dst__2
1906 code = registerCode register2 reg__2
1908 src__2 = registerName register2 reg__2
1912 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1913 else if isFixed register2 then
1914 code . mkSeqInstr (FMOV sz src__2 dst__2)
1920 #endif {- sparc_TARGET_ARCH -}
1923 %************************************************************************
1925 \subsection{Generating an unconditional branch}
1927 %************************************************************************
1929 We accept two types of targets: an immediate CLabel or a tree that
1930 gets evaluated into a register. Any CLabels which are AsmTemporaries
1931 are assumed to be in the local block of code, close enough for a
1932 branch instruction. Other CLabels are assumed to be far away.
1934 (If applicable) Do not fill the delay slots here; you will confuse the
1938 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1940 #if alpha_TARGET_ARCH
1942 genJump (StCLbl lbl)
1943 | isAsmTemp lbl = returnInstr (BR target)
1944 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1946 target = ImmCLbl lbl
1949 = getRegister tree `thenUs` \ register ->
1950 getNewRegNCG PtrRep `thenUs` \ tmp ->
1952 dst = registerName register pv
1953 code = registerCode register pv
1954 target = registerName register pv
1956 if isFixed register then
1957 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1959 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1961 #endif {- alpha_TARGET_ARCH -}
1962 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1963 #if i386_TARGET_ARCH
1966 genJump (StCLbl lbl)
1967 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1968 | otherwise = returnInstrs [JMP (OpImm target)]
1970 target = ImmCLbl lbl
1973 genJump (StInd pk mem)
1974 = getAmode mem `thenUs` \ amode ->
1976 code = amodeCode amode
1977 target = amodeAddr amode
1979 returnSeq code [JMP (OpAddr target)]
1983 = returnInstr (JMP (OpImm target))
1986 = getRegister tree `thenUs` \ register ->
1987 getNewRegNCG PtrRep `thenUs` \ tmp ->
1989 code = registerCode register tmp
1990 target = registerName register tmp
1992 returnSeq code [JMP (OpReg target)]
1995 target = case imm of Just x -> x
1997 #endif {- i386_TARGET_ARCH -}
1998 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1999 #if sparc_TARGET_ARCH
2001 genJump (StCLbl lbl)
2002 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
2003 | otherwise = returnInstrs [CALL target 0 True, NOP]
2005 target = ImmCLbl lbl
2008 = getRegister tree `thenUs` \ register ->
2009 getNewRegNCG PtrRep `thenUs` \ tmp ->
2011 code = registerCode register tmp
2012 target = registerName register tmp
2014 returnSeq code [JMP (AddrRegReg target g0), NOP]
2016 #endif {- sparc_TARGET_ARCH -}
2019 %************************************************************************
2021 \subsection{Conditional jumps}
2023 %************************************************************************
2025 Conditional jumps are always to local labels, so we can use branch
2026 instructions. We peek at the arguments to decide what kind of
2029 ALPHA: For comparisons with 0, we're laughing, because we can just do
2030 the desired conditional branch.
2032 I386: First, we have to ensure that the condition
2033 codes are set according to the supplied comparison operation.
2035 SPARC: First, we have to ensure that the condition codes are set
2036 according to the supplied comparison operation. We generate slightly
2037 different code for floating point comparisons, because a floating
2038 point operation cannot directly precede a @BF@. We assume the worst
2039 and fill that slot with a @NOP@.
2041 SPARC: Do not fill the delay slots here; you will confuse the register
2046 :: CLabel -- the branch target
2047 -> StixTree -- the condition on which to branch
2048 -> UniqSM InstrBlock
2050 #if alpha_TARGET_ARCH
2052 genCondJump lbl (StPrim op [x, StInt 0])
2053 = getRegister x `thenUs` \ register ->
2054 getNewRegNCG (registerRep register)
2057 code = registerCode register tmp
2058 value = registerName register tmp
2059 pk = registerRep register
2060 target = ImmCLbl lbl
2062 returnSeq code [BI (cmpOp op) value target]
2064 cmpOp CharGtOp = GTT
2066 cmpOp CharEqOp = EQQ
2068 cmpOp CharLtOp = LTT
2077 cmpOp WordGeOp = ALWAYS
2078 cmpOp WordEqOp = EQQ
2080 cmpOp WordLtOp = NEVER
2081 cmpOp WordLeOp = EQQ
2083 cmpOp AddrGeOp = ALWAYS
2084 cmpOp AddrEqOp = EQQ
2086 cmpOp AddrLtOp = NEVER
2087 cmpOp AddrLeOp = EQQ
2089 genCondJump lbl (StPrim op [x, StDouble 0.0])
2090 = getRegister x `thenUs` \ register ->
2091 getNewRegNCG (registerRep register)
2094 code = registerCode register tmp
2095 value = registerName register tmp
2096 pk = registerRep register
2097 target = ImmCLbl lbl
2099 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2101 cmpOp FloatGtOp = GTT
2102 cmpOp FloatGeOp = GE
2103 cmpOp FloatEqOp = EQQ
2104 cmpOp FloatNeOp = NE
2105 cmpOp FloatLtOp = LTT
2106 cmpOp FloatLeOp = LE
2107 cmpOp DoubleGtOp = GTT
2108 cmpOp DoubleGeOp = GE
2109 cmpOp DoubleEqOp = EQQ
2110 cmpOp DoubleNeOp = NE
2111 cmpOp DoubleLtOp = LTT
2112 cmpOp DoubleLeOp = LE
2114 genCondJump lbl (StPrim op [x, y])
2116 = trivialFCode pr instr x y `thenUs` \ register ->
2117 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2119 code = registerCode register tmp
2120 result = registerName register tmp
2121 target = ImmCLbl lbl
2123 returnUs (code . mkSeqInstr (BF cond result target))
2125 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2127 fltCmpOp op = case op of
2141 (instr, cond) = case op of
2142 FloatGtOp -> (FCMP TF LE, EQQ)
2143 FloatGeOp -> (FCMP TF LTT, EQQ)
2144 FloatEqOp -> (FCMP TF EQQ, NE)
2145 FloatNeOp -> (FCMP TF EQQ, EQQ)
2146 FloatLtOp -> (FCMP TF LTT, NE)
2147 FloatLeOp -> (FCMP TF LE, NE)
2148 DoubleGtOp -> (FCMP TF LE, EQQ)
2149 DoubleGeOp -> (FCMP TF LTT, EQQ)
2150 DoubleEqOp -> (FCMP TF EQQ, NE)
2151 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2152 DoubleLtOp -> (FCMP TF LTT, NE)
2153 DoubleLeOp -> (FCMP TF LE, NE)
2155 genCondJump lbl (StPrim op [x, y])
2156 = trivialCode instr x y `thenUs` \ register ->
2157 getNewRegNCG IntRep `thenUs` \ tmp ->
2159 code = registerCode register tmp
2160 result = registerName register tmp
2161 target = ImmCLbl lbl
2163 returnUs (code . mkSeqInstr (BI cond result target))
2165 (instr, cond) = case op of
2166 CharGtOp -> (CMP LE, EQQ)
2167 CharGeOp -> (CMP LTT, EQQ)
2168 CharEqOp -> (CMP EQQ, NE)
2169 CharNeOp -> (CMP EQQ, EQQ)
2170 CharLtOp -> (CMP LTT, NE)
2171 CharLeOp -> (CMP LE, NE)
2172 IntGtOp -> (CMP LE, EQQ)
2173 IntGeOp -> (CMP LTT, EQQ)
2174 IntEqOp -> (CMP EQQ, NE)
2175 IntNeOp -> (CMP EQQ, EQQ)
2176 IntLtOp -> (CMP LTT, NE)
2177 IntLeOp -> (CMP LE, NE)
2178 WordGtOp -> (CMP ULE, EQQ)
2179 WordGeOp -> (CMP ULT, EQQ)
2180 WordEqOp -> (CMP EQQ, NE)
2181 WordNeOp -> (CMP EQQ, EQQ)
2182 WordLtOp -> (CMP ULT, NE)
2183 WordLeOp -> (CMP ULE, NE)
2184 AddrGtOp -> (CMP ULE, EQQ)
2185 AddrGeOp -> (CMP ULT, EQQ)
2186 AddrEqOp -> (CMP EQQ, NE)
2187 AddrNeOp -> (CMP EQQ, EQQ)
2188 AddrLtOp -> (CMP ULT, NE)
2189 AddrLeOp -> (CMP ULE, NE)
2191 #endif {- alpha_TARGET_ARCH -}
2192 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2193 #if i386_TARGET_ARCH
2195 genCondJump lbl bool
2196 = getCondCode bool `thenUs` \ condition ->
2198 code = condCode condition
2199 cond = condName condition
2200 target = ImmCLbl lbl
2202 returnSeq code [JXX cond lbl]
2204 #endif {- i386_TARGET_ARCH -}
2205 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2206 #if sparc_TARGET_ARCH
2208 genCondJump lbl bool
2209 = getCondCode bool `thenUs` \ condition ->
2211 code = condCode condition
2212 cond = condName condition
2213 target = ImmCLbl lbl
2216 if condFloat condition then
2217 [NOP, BF cond False target, NOP]
2219 [BI cond False target, NOP]
2222 #endif {- sparc_TARGET_ARCH -}
2225 %************************************************************************
2227 \subsection{Generating C calls}
2229 %************************************************************************
2231 Now the biggest nightmare---calls. Most of the nastiness is buried in
2232 @get_arg@, which moves the arguments to the correct registers/stack
2233 locations. Apart from that, the code is easy.
2235 (If applicable) Do not fill the delay slots here; you will confuse the
2240 :: FAST_STRING -- function to call
2242 -> PrimRep -- type of the result
2243 -> [StixTree] -- arguments (of mixed type)
2244 -> UniqSM InstrBlock
2246 #if alpha_TARGET_ARCH
2248 genCCall fn cconv kind args
2249 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2250 `thenUs` \ ((unused,_), argCode) ->
2252 nRegs = length allArgRegs - length unused
2253 code = asmParThen (map ($ asmVoid) argCode)
2256 LDA pv (AddrImm (ImmLab (ptext fn))),
2257 JSR ra (AddrReg pv) nRegs,
2258 LDGP gp (AddrReg ra)]
2260 ------------------------
2261 {- Try to get a value into a specific register (or registers) for
2262 a call. The first 6 arguments go into the appropriate
2263 argument register (separate registers for integer and floating
2264 point arguments, but used in lock-step), and the remaining
2265 arguments are dumped to the stack, beginning at 0(sp). Our
2266 first argument is a pair of the list of remaining argument
2267 registers to be assigned for this call and the next stack
2268 offset to use for overflowing arguments. This way,
2269 @get_Arg@ can be applied to all of a call's arguments using
2273 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2274 -> StixTree -- Current argument
2275 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2277 -- We have to use up all of our argument registers first...
2279 get_arg ((iDst,fDst):dsts, offset) arg
2280 = getRegister arg `thenUs` \ register ->
2282 reg = if isFloatingRep pk then fDst else iDst
2283 code = registerCode register reg
2284 src = registerName register reg
2285 pk = registerRep register
2288 if isFloatingRep pk then
2289 ((dsts, offset), if isFixed register then
2290 code . mkSeqInstr (FMOV src fDst)
2293 ((dsts, offset), if isFixed register then
2294 code . mkSeqInstr (OR src (RIReg src) iDst)
2297 -- Once we have run out of argument registers, we move to the
2300 get_arg ([], offset) arg
2301 = getRegister arg `thenUs` \ register ->
2302 getNewRegNCG (registerRep register)
2305 code = registerCode register tmp
2306 src = registerName register tmp
2307 pk = registerRep register
2308 sz = primRepToSize pk
2310 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2312 #endif {- alpha_TARGET_ARCH -}
2313 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2314 #if i386_TARGET_ARCH
2316 genCCall fn cconv kind [StInt i]
2317 | fn == SLIT ("PerformGC_wrapper")
2319 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2320 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2325 = getUniqLabelNCG `thenUs` \ lbl ->
2327 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2328 MOV L (OpImm (ImmCLbl lbl))
2329 -- this is hardwired
2330 (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 104))),
2331 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2337 genCCall fn cconv kind args
2338 = mapUs get_call_arg args `thenUs` \ argCode ->
2342 {- OLD: Since there's no attempt at stealing %esp at the moment,
2343 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2344 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2345 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))),
2346 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2350 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2351 call = [CALL fn__2 ,
2352 -- pop args; all args word sized?
2353 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2355 -- Don't restore %esp (see above)
2356 -- MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2359 returnSeq (code2) call
2361 -- function names that begin with '.' are assumed to be special
2362 -- internally generated names like '.mul,' which don't get an
2363 -- underscore prefix
2364 -- ToDo:needed (WDP 96/03) ???
2365 fn__2 = case (_HEAD_ fn) of
2366 '.' -> ImmLit (ptext fn)
2367 _ -> ImmLab (ptext fn)
2370 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2373 = get_op arg `thenUs` \ (code, op, sz) ->
2374 returnUs (code . mkSeqInstr (PUSH sz op))
2379 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2382 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2384 get_op (StInd pk mem)
2385 = getAmode mem `thenUs` \ amode ->
2387 code = amodeCode amode --asmVoid
2388 addr = amodeAddr amode
2389 sz = primRepToSize pk
2391 returnUs (code, OpAddr addr, sz)
2394 = getRegister op `thenUs` \ register ->
2395 getNewRegNCG (registerRep register)
2398 code = registerCode register tmp
2399 reg = registerName register tmp
2400 pk = registerRep register
2401 sz = primRepToSize pk
2403 returnUs (code, OpReg reg, sz)
2405 #endif {- i386_TARGET_ARCH -}
2406 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2407 #if sparc_TARGET_ARCH
2409 genCCall fn cconv kind args
2410 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2411 `thenUs` \ ((unused,_), argCode) ->
2413 nRegs = length allArgRegs - length unused
2414 call = CALL fn__2 nRegs False
2415 code = asmParThen (map ($ asmVoid) argCode)
2417 returnSeq code [call, NOP]
2419 -- function names that begin with '.' are assumed to be special
2420 -- internally generated names like '.mul,' which don't get an
2421 -- underscore prefix
2422 -- ToDo:needed (WDP 96/03) ???
2423 fn__2 = case (_HEAD_ fn) of
2424 '.' -> ImmLit (ptext fn)
2425 _ -> ImmLab (ptext fn)
2427 ------------------------------------
2428 {- Try to get a value into a specific register (or registers) for
2429 a call. The SPARC calling convention is an absolute
2430 nightmare. The first 6x32 bits of arguments are mapped into
2431 %o0 through %o5, and the remaining arguments are dumped to the
2432 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2433 first argument is a pair of the list of remaining argument
2434 registers to be assigned for this call and the next stack
2435 offset to use for overflowing arguments. This way,
2436 @get_arg@ can be applied to all of a call's arguments using
2440 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2441 -> StixTree -- Current argument
2442 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2444 -- We have to use up all of our argument registers first...
2446 get_arg (dst:dsts, offset) arg
2447 = getRegister arg `thenUs` \ register ->
2448 getNewRegNCG (registerRep register)
2451 reg = if isFloatingRep pk then tmp else dst
2452 code = registerCode register reg
2453 src = registerName register reg
2454 pk = registerRep register
2456 returnUs (case pk of
2459 [] -> (([], offset + 1), code . mkSeqInstrs [
2460 -- conveniently put the second part in the right stack
2461 -- location, and load the first part into %o5
2462 ST DF src (spRel (offset - 1)),
2463 LD W (spRel (offset - 1)) dst])
2464 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2465 ST DF src (spRel (-2)),
2466 LD W (spRel (-2)) dst,
2467 LD W (spRel (-1)) dst__2])
2468 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2469 ST F src (spRel (-2)),
2470 LD W (spRel (-2)) dst])
2471 _ -> ((dsts, offset), if isFixed register then
2472 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2475 -- Once we have run out of argument registers, we move to the
2478 get_arg ([], offset) arg
2479 = getRegister arg `thenUs` \ register ->
2480 getNewRegNCG (registerRep register)
2483 code = registerCode register tmp
2484 src = registerName register tmp
2485 pk = registerRep register
2486 sz = primRepToSize pk
2487 words = if pk == DoubleRep then 2 else 1
2489 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2491 #endif {- sparc_TARGET_ARCH -}
2494 %************************************************************************
2496 \subsection{Support bits}
2498 %************************************************************************
2500 %************************************************************************
2502 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2504 %************************************************************************
2506 Turn those condition codes into integers now (when they appear on
2507 the right hand side of an assignment).
2509 (If applicable) Do not fill the delay slots here; you will confuse the
2513 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2515 #if alpha_TARGET_ARCH
2516 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2517 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2518 #endif {- alpha_TARGET_ARCH -}
2520 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2521 #if i386_TARGET_ARCH
2524 = condIntCode cond x y `thenUs` \ condition ->
2525 getNewRegNCG IntRep `thenUs` \ tmp ->
2526 --getRegister dst `thenUs` \ register ->
2528 --code2 = registerCode register tmp asmVoid
2529 --dst__2 = registerName register tmp
2530 code = condCode condition
2531 cond = condName condition
2532 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2533 code__2 dst = code . mkSeqInstrs [
2534 SETCC cond (OpReg tmp),
2535 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2536 MOV L (OpReg tmp) (OpReg dst)]
2538 returnUs (Any IntRep code__2)
2541 = getUniqLabelNCG `thenUs` \ lbl1 ->
2542 getUniqLabelNCG `thenUs` \ lbl2 ->
2543 condFltCode cond x y `thenUs` \ condition ->
2545 code = condCode condition
2546 cond = condName condition
2547 code__2 dst = code . mkSeqInstrs [
2549 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2552 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2555 returnUs (Any IntRep code__2)
2557 #endif {- i386_TARGET_ARCH -}
2558 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2559 #if sparc_TARGET_ARCH
2561 condIntReg EQQ x (StInt 0)
2562 = getRegister x `thenUs` \ register ->
2563 getNewRegNCG IntRep `thenUs` \ tmp ->
2565 code = registerCode register tmp
2566 src = registerName register tmp
2567 code__2 dst = code . mkSeqInstrs [
2568 SUB False True g0 (RIReg src) g0,
2569 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2571 returnUs (Any IntRep code__2)
2574 = getRegister x `thenUs` \ register1 ->
2575 getRegister y `thenUs` \ register2 ->
2576 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2577 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2579 code1 = registerCode register1 tmp1 asmVoid
2580 src1 = registerName register1 tmp1
2581 code2 = registerCode register2 tmp2 asmVoid
2582 src2 = registerName register2 tmp2
2583 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2584 XOR False src1 (RIReg src2) dst,
2585 SUB False True g0 (RIReg dst) g0,
2586 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2588 returnUs (Any IntRep code__2)
2590 condIntReg NE x (StInt 0)
2591 = getRegister x `thenUs` \ register ->
2592 getNewRegNCG IntRep `thenUs` \ tmp ->
2594 code = registerCode register tmp
2595 src = registerName register tmp
2596 code__2 dst = code . mkSeqInstrs [
2597 SUB False True g0 (RIReg src) g0,
2598 ADD True False g0 (RIImm (ImmInt 0)) dst]
2600 returnUs (Any IntRep code__2)
2603 = getRegister x `thenUs` \ register1 ->
2604 getRegister y `thenUs` \ register2 ->
2605 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2606 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2608 code1 = registerCode register1 tmp1 asmVoid
2609 src1 = registerName register1 tmp1
2610 code2 = registerCode register2 tmp2 asmVoid
2611 src2 = registerName register2 tmp2
2612 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2613 XOR False src1 (RIReg src2) dst,
2614 SUB False True g0 (RIReg dst) g0,
2615 ADD True False g0 (RIImm (ImmInt 0)) dst]
2617 returnUs (Any IntRep code__2)
2620 = getUniqLabelNCG `thenUs` \ lbl1 ->
2621 getUniqLabelNCG `thenUs` \ lbl2 ->
2622 condIntCode cond x y `thenUs` \ condition ->
2624 code = condCode condition
2625 cond = condName condition
2626 code__2 dst = code . mkSeqInstrs [
2627 BI cond False (ImmCLbl lbl1), NOP,
2628 OR False g0 (RIImm (ImmInt 0)) dst,
2629 BI ALWAYS False (ImmCLbl lbl2), NOP,
2631 OR False g0 (RIImm (ImmInt 1)) dst,
2634 returnUs (Any IntRep code__2)
2637 = getUniqLabelNCG `thenUs` \ lbl1 ->
2638 getUniqLabelNCG `thenUs` \ lbl2 ->
2639 condFltCode cond x y `thenUs` \ condition ->
2641 code = condCode condition
2642 cond = condName condition
2643 code__2 dst = code . mkSeqInstrs [
2645 BF cond False (ImmCLbl lbl1), NOP,
2646 OR False g0 (RIImm (ImmInt 0)) dst,
2647 BI ALWAYS False (ImmCLbl lbl2), NOP,
2649 OR False g0 (RIImm (ImmInt 1)) dst,
2652 returnUs (Any IntRep code__2)
2654 #endif {- sparc_TARGET_ARCH -}
2657 %************************************************************************
2659 \subsubsection{@trivial*Code@: deal with trivial instructions}
2661 %************************************************************************
2663 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2664 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2665 for constants on the right hand side, because that's where the generic
2666 optimizer will have put them.
2668 Similarly, for unary instructions, we don't have to worry about
2669 matching an StInt as the argument, because genericOpt will already
2670 have handled the constant-folding.
2674 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2675 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2676 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2678 -> StixTree -> StixTree -- the two arguments
2683 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2684 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2686 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2687 (Size -> Operand -> Instr)
2688 -> (Size -> Operand -> Instr) {-reversed instr-}
2690 -> Instr {-reversed instr: pop-}
2692 -> StixTree -> StixTree -- the two arguments
2696 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2697 ,IF_ARCH_i386 ((Operand -> Instr)
2698 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2700 -> StixTree -- the one argument
2705 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2706 ,IF_ARCH_i386 (Instr
2707 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2709 -> StixTree -- the one argument
2712 #if alpha_TARGET_ARCH
2714 trivialCode instr x (StInt y)
2716 = getRegister x `thenUs` \ register ->
2717 getNewRegNCG IntRep `thenUs` \ tmp ->
2719 code = registerCode register tmp
2720 src1 = registerName register tmp
2721 src2 = ImmInt (fromInteger y)
2722 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2724 returnUs (Any IntRep code__2)
2726 trivialCode instr x y
2727 = getRegister x `thenUs` \ register1 ->
2728 getRegister y `thenUs` \ register2 ->
2729 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2730 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2732 code1 = registerCode register1 tmp1 asmVoid
2733 src1 = registerName register1 tmp1
2734 code2 = registerCode register2 tmp2 asmVoid
2735 src2 = registerName register2 tmp2
2736 code__2 dst = asmParThen [code1, code2] .
2737 mkSeqInstr (instr src1 (RIReg src2) dst)
2739 returnUs (Any IntRep code__2)
2742 trivialUCode instr x
2743 = getRegister x `thenUs` \ register ->
2744 getNewRegNCG IntRep `thenUs` \ tmp ->
2746 code = registerCode register tmp
2747 src = registerName register tmp
2748 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2750 returnUs (Any IntRep code__2)
2753 trivialFCode _ instr x y
2754 = getRegister x `thenUs` \ register1 ->
2755 getRegister y `thenUs` \ register2 ->
2756 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2757 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2759 code1 = registerCode register1 tmp1
2760 src1 = registerName register1 tmp1
2762 code2 = registerCode register2 tmp2
2763 src2 = registerName register2 tmp2
2765 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2766 mkSeqInstr (instr src1 src2 dst)
2768 returnUs (Any DoubleRep code__2)
2770 trivialUFCode _ instr x
2771 = getRegister x `thenUs` \ register ->
2772 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2774 code = registerCode register tmp
2775 src = registerName register tmp
2776 code__2 dst = code . mkSeqInstr (instr src dst)
2778 returnUs (Any DoubleRep code__2)
2780 #endif {- alpha_TARGET_ARCH -}
2781 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2782 #if i386_TARGET_ARCH
2784 trivialCode instr x y
2786 = getRegister x `thenUs` \ register1 ->
2787 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2789 -- fixedname = registerName register1 eax
2790 code__2 dst = let code1 = registerCode register1 dst
2791 src1 = registerName register1 dst
2793 if isFixed register1 && src1 /= dst
2794 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2795 instr (OpImm imm__2) (OpReg dst)]
2797 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2799 returnUs (Any IntRep code__2)
2802 imm__2 = case imm of Just x -> x
2804 trivialCode instr x y
2806 = getRegister y `thenUs` \ register1 ->
2807 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2809 -- fixedname = registerName register1 eax
2810 code__2 dst = let code1 = registerCode register1 dst
2811 src1 = registerName register1 dst
2813 if isFixed register1 && src1 /= dst
2814 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2815 instr (OpImm imm__2) (OpReg dst)]
2817 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2819 returnUs (Any IntRep code__2)
2822 imm__2 = case imm of Just x -> x
2824 trivialCode instr x (StInd pk mem)
2825 = getRegister x `thenUs` \ register ->
2826 --getNewRegNCG IntRep `thenUs` \ tmp ->
2827 getAmode mem `thenUs` \ amode ->
2829 -- fixedname = registerName register eax
2830 code2 = amodeCode amode asmVoid
2831 src2 = amodeAddr amode
2832 code__2 dst = let code1 = registerCode register dst asmVoid
2833 src1 = registerName register dst
2834 in asmParThen [code1, code2] .
2835 if isFixed register && src1 /= dst
2836 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2837 instr (OpAddr src2) (OpReg dst)]
2839 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2841 returnUs (Any pk code__2)
2843 trivialCode instr (StInd pk mem) y
2844 = getRegister y `thenUs` \ register ->
2845 --getNewRegNCG IntRep `thenUs` \ tmp ->
2846 getAmode mem `thenUs` \ amode ->
2848 -- fixedname = registerName register eax
2849 code2 = amodeCode amode asmVoid
2850 src2 = amodeAddr amode
2852 code1 = registerCode register dst asmVoid
2853 src1 = registerName register dst
2854 in asmParThen [code1, code2] .
2855 if isFixed register && src1 /= dst
2856 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2857 instr (OpAddr src2) (OpReg dst)]
2859 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2861 returnUs (Any pk code__2)
2863 trivialCode instr x y
2864 = getRegister x `thenUs` \ register1 ->
2865 getRegister y `thenUs` \ register2 ->
2866 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2867 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2869 -- fixedname = registerName register1 eax
2870 code2 = registerCode register2 tmp2 asmVoid
2871 src2 = registerName register2 tmp2
2873 code1 = registerCode register1 dst asmVoid
2874 src1 = registerName register1 dst
2875 in asmParThen [code1, code2] .
2876 if isFixed register1 && src1 /= dst
2877 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2878 instr (OpReg src2) (OpReg dst)]
2880 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2882 returnUs (Any IntRep code__2)
2885 trivialUCode instr x
2886 = getRegister x `thenUs` \ register ->
2887 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2889 -- fixedname = registerName register eax
2891 code = registerCode register dst
2892 src = registerName register dst
2893 in code . if isFixed register && dst /= src
2894 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2896 else mkSeqInstr (instr (OpReg src))
2898 returnUs (Any IntRep code__2)
2901 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2902 = getRegister y `thenUs` \ register2 ->
2903 --getNewRegNCG (registerRep register2)
2904 -- `thenUs` \ tmp2 ->
2905 getAmode mem `thenUs` \ amode ->
2907 code1 = amodeCode amode
2908 src1 = amodeAddr amode
2911 code2 = registerCode register2 dst
2912 src2 = registerName register2 dst
2913 in asmParThen [code1 asmVoid,code2 asmVoid] .
2914 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2916 returnUs (Any pk code__2)
2918 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2919 = getRegister x `thenUs` \ register1 ->
2920 --getNewRegNCG (registerRep register1)
2921 -- `thenUs` \ tmp1 ->
2922 getAmode mem `thenUs` \ amode ->
2924 code2 = amodeCode amode
2925 src2 = amodeAddr amode
2928 code1 = registerCode register1 dst
2929 src1 = registerName register1 dst
2930 in asmParThen [code2 asmVoid,code1 asmVoid] .
2931 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2933 returnUs (Any pk code__2)
2935 trivialFCode pk _ _ _ instrpr x y
2936 = getRegister x `thenUs` \ register1 ->
2937 getRegister y `thenUs` \ register2 ->
2938 --getNewRegNCG (registerRep register1)
2939 -- `thenUs` \ tmp1 ->
2940 --getNewRegNCG (registerRep register2)
2941 -- `thenUs` \ tmp2 ->
2942 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2944 pk1 = registerRep register1
2945 code1 = registerCode register1 st0 --tmp1
2946 src1 = registerName register1 st0 --tmp1
2948 pk2 = registerRep register2
2951 code2 = registerCode register2 dst
2952 src2 = registerName register2 dst
2953 in asmParThen [code1 asmVoid, code2 asmVoid] .
2956 returnUs (Any pk1 code__2)
2959 trivialUFCode pk instr (StInd pk' mem)
2960 = getAmode mem `thenUs` \ amode ->
2962 code = amodeCode amode
2963 src = amodeAddr amode
2964 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2967 returnUs (Any pk code__2)
2969 trivialUFCode pk instr x
2970 = getRegister x `thenUs` \ register ->
2971 --getNewRegNCG pk `thenUs` \ tmp ->
2974 code = registerCode register dst
2975 src = registerName register dst
2976 in code . mkSeqInstrs [instr]
2978 returnUs (Any pk code__2)
2980 #endif {- i386_TARGET_ARCH -}
2981 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2982 #if sparc_TARGET_ARCH
2984 trivialCode instr x (StInt y)
2986 = getRegister x `thenUs` \ register ->
2987 getNewRegNCG IntRep `thenUs` \ tmp ->
2989 code = registerCode register tmp
2990 src1 = registerName register tmp
2991 src2 = ImmInt (fromInteger y)
2992 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2994 returnUs (Any IntRep code__2)
2996 trivialCode instr x y
2997 = getRegister x `thenUs` \ register1 ->
2998 getRegister y `thenUs` \ register2 ->
2999 getNewRegNCG IntRep `thenUs` \ tmp1 ->
3000 getNewRegNCG IntRep `thenUs` \ tmp2 ->
3002 code1 = registerCode register1 tmp1 asmVoid
3003 src1 = registerName register1 tmp1
3004 code2 = registerCode register2 tmp2 asmVoid
3005 src2 = registerName register2 tmp2
3006 code__2 dst = asmParThen [code1, code2] .
3007 mkSeqInstr (instr src1 (RIReg src2) dst)
3009 returnUs (Any IntRep code__2)
3012 trivialFCode pk instr x y
3013 = getRegister x `thenUs` \ register1 ->
3014 getRegister y `thenUs` \ register2 ->
3015 getNewRegNCG (registerRep register1)
3017 getNewRegNCG (registerRep register2)
3019 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3021 promote x = asmInstr (FxTOy F DF x tmp)
3023 pk1 = registerRep register1
3024 code1 = registerCode register1 tmp1
3025 src1 = registerName register1 tmp1
3027 pk2 = registerRep register2
3028 code2 = registerCode register2 tmp2
3029 src2 = registerName register2 tmp2
3033 asmParThen [code1 asmVoid, code2 asmVoid] .
3034 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3035 else if pk1 == FloatRep then
3036 asmParThen [code1 (promote src1), code2 asmVoid] .
3037 mkSeqInstr (instr DF tmp src2 dst)
3039 asmParThen [code1 asmVoid, code2 (promote src2)] .
3040 mkSeqInstr (instr DF src1 tmp dst)
3042 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3045 trivialUCode instr x
3046 = getRegister x `thenUs` \ register ->
3047 getNewRegNCG IntRep `thenUs` \ tmp ->
3049 code = registerCode register tmp
3050 src = registerName register tmp
3051 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3053 returnUs (Any IntRep code__2)
3056 trivialUFCode pk instr x
3057 = getRegister x `thenUs` \ register ->
3058 getNewRegNCG pk `thenUs` \ tmp ->
3060 code = registerCode register tmp
3061 src = registerName register tmp
3062 code__2 dst = code . mkSeqInstr (instr src dst)
3064 returnUs (Any pk code__2)
3066 #endif {- sparc_TARGET_ARCH -}
3069 %************************************************************************
3071 \subsubsection{Coercing to/from integer/floating-point...}
3073 %************************************************************************
3075 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3076 to be generated. Here we just change the type on the Register passed
3077 on up. The code is machine-independent.
3079 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3080 conversions. We have to store temporaries in memory to move
3081 between the integer and the floating point register sets.
3084 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3085 coerceFltCode :: StixTree -> UniqSM Register
3087 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3088 coerceFP2Int :: StixTree -> UniqSM Register
3091 = getRegister x `thenUs` \ register ->
3094 Fixed _ reg code -> Fixed pk reg code
3095 Any _ code -> Any pk code
3100 = getRegister x `thenUs` \ register ->
3103 Fixed _ reg code -> Fixed DoubleRep reg code
3104 Any _ code -> Any DoubleRep code
3109 #if alpha_TARGET_ARCH
3112 = getRegister x `thenUs` \ register ->
3113 getNewRegNCG IntRep `thenUs` \ reg ->
3115 code = registerCode register reg
3116 src = registerName register reg
3118 code__2 dst = code . mkSeqInstrs [
3120 LD TF dst (spRel 0),
3123 returnUs (Any DoubleRep code__2)
3127 = getRegister x `thenUs` \ register ->
3128 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3130 code = registerCode register tmp
3131 src = registerName register tmp
3133 code__2 dst = code . mkSeqInstrs [
3135 ST TF tmp (spRel 0),
3138 returnUs (Any IntRep code__2)
3140 #endif {- alpha_TARGET_ARCH -}
3141 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3142 #if i386_TARGET_ARCH
3145 = getRegister x `thenUs` \ register ->
3146 getNewRegNCG IntRep `thenUs` \ reg ->
3148 code = registerCode register reg
3149 src = registerName register reg
3151 code__2 dst = code . mkSeqInstrs [
3152 -- to fix: should spill instead of using R1
3153 MOV L (OpReg src) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
3154 FILD (primRepToSize pk) (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3156 returnUs (Any pk code__2)
3160 = getRegister x `thenUs` \ register ->
3161 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3163 code = registerCode register tmp
3164 src = registerName register tmp
3165 pk = registerRep register
3167 code__2 dst = code . mkSeqInstrs [
3169 FIST L (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)),
3170 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3172 returnUs (Any IntRep code__2)
3174 #endif {- i386_TARGET_ARCH -}
3175 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3176 #if sparc_TARGET_ARCH
3179 = getRegister x `thenUs` \ register ->
3180 getNewRegNCG IntRep `thenUs` \ reg ->
3182 code = registerCode register reg
3183 src = registerName register reg
3185 code__2 dst = code . mkSeqInstrs [
3186 ST W src (spRel (-2)),
3187 LD W (spRel (-2)) dst,
3188 FxTOy W (primRepToSize pk) dst dst]
3190 returnUs (Any pk code__2)
3194 = getRegister x `thenUs` \ register ->
3195 getNewRegNCG IntRep `thenUs` \ reg ->
3196 getNewRegNCG FloatRep `thenUs` \ tmp ->
3198 code = registerCode register reg
3199 src = registerName register reg
3200 pk = registerRep register
3202 code__2 dst = code . mkSeqInstrs [
3203 FxTOy (primRepToSize pk) W src tmp,
3204 ST W tmp (spRel (-2)),
3205 LD W (spRel (-2)) dst]
3207 returnUs (Any IntRep code__2)
3209 #endif {- sparc_TARGET_ARCH -}
3212 %************************************************************************
3214 \subsubsection{Coercing integer to @Char@...}
3216 %************************************************************************
3218 Integer to character conversion. Where applicable, we try to do this
3219 in one step if the original object is in memory.
3222 chrCode :: StixTree -> UniqSM Register
3224 #if alpha_TARGET_ARCH
3227 = getRegister x `thenUs` \ register ->
3228 getNewRegNCG IntRep `thenUs` \ reg ->
3230 code = registerCode register reg
3231 src = registerName register reg
3232 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3234 returnUs (Any IntRep code__2)
3236 #endif {- alpha_TARGET_ARCH -}
3237 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3238 #if i386_TARGET_ARCH
3241 = getRegister x `thenUs` \ register ->
3242 --getNewRegNCG IntRep `thenUs` \ reg ->
3244 -- fixedname = registerName register eax
3246 code = registerCode register dst
3247 src = registerName register dst
3249 if isFixed register && src /= dst
3250 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3251 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3252 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3254 returnUs (Any IntRep code__2)
3256 #endif {- i386_TARGET_ARCH -}
3257 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3258 #if sparc_TARGET_ARCH
3260 chrCode (StInd pk mem)
3261 = getAmode mem `thenUs` \ amode ->
3263 code = amodeCode amode
3264 src = amodeAddr amode
3265 src_off = addrOffset src 3
3266 src__2 = case src_off of Just x -> x
3267 code__2 dst = if maybeToBool src_off then
3268 code . mkSeqInstr (LD BU src__2 dst)
3270 code . mkSeqInstrs [
3271 LD (primRepToSize pk) src dst,
3272 AND False dst (RIImm (ImmInt 255)) dst]
3274 returnUs (Any pk code__2)
3277 = getRegister x `thenUs` \ register ->
3278 getNewRegNCG IntRep `thenUs` \ reg ->
3280 code = registerCode register reg
3281 src = registerName register reg
3282 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3284 returnUs (Any IntRep code__2)
3286 #endif {- sparc_TARGET_ARCH -}
3289 %************************************************************************
3291 \subsubsection{Absolute value on integers}
3293 %************************************************************************
3295 Absolute value on integers, mostly for gmp size check macros. Again,
3296 the argument cannot be an StInt, because genericOpt already folded
3299 If applicable, do not fill the delay slots here; you will confuse the
3303 absIntCode :: StixTree -> UniqSM Register
3305 #if alpha_TARGET_ARCH
3306 absIntCode = panic "MachCode.absIntCode: not on Alphas"
3307 #endif {- alpha_TARGET_ARCH -}
3309 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3310 #if i386_TARGET_ARCH
3313 = getRegister x `thenUs` \ register ->
3314 --getNewRegNCG IntRep `thenUs` \ reg ->
3315 getUniqLabelNCG `thenUs` \ lbl ->
3317 code__2 dst = let code = registerCode register dst
3318 src = registerName register dst
3319 in code . if isFixed register && dst /= src
3320 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3321 TEST L (OpReg dst) (OpReg dst),
3325 else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
3330 returnUs (Any IntRep code__2)
3332 #endif {- i386_TARGET_ARCH -}
3333 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3334 #if sparc_TARGET_ARCH
3337 = getRegister x `thenUs` \ register ->
3338 getNewRegNCG IntRep `thenUs` \ reg ->
3339 getUniqLabelNCG `thenUs` \ lbl ->
3341 code = registerCode register reg
3342 src = registerName register reg
3343 code__2 dst = code . mkSeqInstrs [
3344 SUB False True g0 (RIReg src) dst,
3345 BI GE False (ImmCLbl lbl), NOP,
3346 OR False g0 (RIReg src) dst,
3349 returnUs (Any IntRep code__2)
3351 #endif {- sparc_TARGET_ARCH -}