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 ( stmtsToInstrs, InstrBlock ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
19 import OrdList ( OrdList, nilOL, isNilOL, unitOL, appOL, toOL,
20 snocOL, consOL, concatOL )
21 import AbsCUtils ( magicIdPrimRep )
22 import ForeignCall ( CCallConv(..) )
23 import CLabel ( CLabel, labelDynamic )
24 import Maybes ( maybeToBool )
25 import PrimRep ( isFloatingRep, PrimRep(..) )
26 import PrimOp ( PrimOp(..) )
27 import Stix ( getNatLabelNCG, StixTree(..),
28 StixReg(..), CodeSegment(..),
29 DestInfo, hasDestInfo,
31 NatM, thenNat, returnNat, mapNat,
32 mapAndUnzipNat, mapAccumLNat,
33 getDeltaNat, setDeltaNat
36 import CmdLineOpts ( opt_Static )
42 @InstrBlock@s are the insn sequences generated by the insn selectors.
43 They are really trees of insns to facilitate fast appending, where a
44 left-to-right traversal (pre-order?) yields the insns in the correct
49 type InstrBlock = OrdList Instr
55 Code extractor for an entire stix tree---stix statement level.
58 stmtsToInstrs :: [StixTree] -> NatM InstrBlock
60 = liftStrings stmts [] [] `thenNat` \ lifted ->
61 mapNat stmtToInstrs lifted `thenNat` \ instrss ->
62 returnNat (concatOL instrss)
65 -- Lift StStrings out of top-level StDatas, putting them at the end of
66 -- the block, and replacing them with StCLbls which refer to the lifted-out strings.
67 {- Motivation for this hackery provided by the following bug:
71 (Data P_ Addr.A#_static_info)
72 (Data StgAddr (Str `alalal'))
77 .global Bogon_ping_closure
79 .long Addr_Azh_static_info
90 ie, the Str is planted in-line, when what we really meant was to place
91 a _reference_ to the string there. liftStrings will lift out all such
92 strings in top-level data and place them at the end of the block.
94 This is still a rather half-baked solution -- to do the job entirely right
95 would mean a complete traversal of all the Stixes, but there's currently no
96 real need for it, and it would be slow. Also, potentially there could be
97 literal types other than strings which need lifting out?
100 liftStrings :: [StixTree] -- originals
101 -> [StixTree] -- (reverse) originals with strings lifted out
102 -> [(CLabel, FAST_STRING)] -- lifted strs, and their new labels
105 -- First, examine the original trees and lift out strings in top-level StDatas.
106 liftStrings (st:sts) acc_stix acc_strs
109 -> lift datas acc_strs `thenNat` \ (datas_done, acc_strs1) ->
110 liftStrings sts ((StData sz datas_done):acc_stix) acc_strs1
112 -> liftStrings sts (other:acc_stix) acc_strs
114 -- Handle a top-level StData
115 lift [] acc_strs = returnNat ([], acc_strs)
117 = lift ds acc_strs `thenNat` \ (ds_done, acc_strs1) ->
120 -> getNatLabelNCG `thenNat` \ lbl ->
121 returnNat ((StCLbl lbl):ds_done, ((lbl,s):acc_strs1))
123 -> returnNat (other:ds_done, acc_strs1)
125 -- When we've run out of original trees, emit the lifted strings.
126 liftStrings [] acc_stix acc_strs
127 = returnNat (reverse acc_stix ++ concatMap f acc_strs)
129 f (lbl,str) = [StSegment RoDataSegment,
132 StSegment TextSegment]
135 stmtToInstrs :: StixTree {- a stix statement -} -> NatM InstrBlock
136 stmtToInstrs stmt = case stmt of
137 StComment s -> returnNat (unitOL (COMMENT s))
138 StSegment seg -> returnNat (unitOL (SEGMENT seg))
140 StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
142 StFunEnd lab -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
145 StLabel lab -> returnNat (unitOL (LABEL lab))
147 StJump dsts arg -> genJump dsts (derefDLL arg)
148 StCondJump lab arg -> genCondJump lab (derefDLL arg)
150 -- A call returning void, ie one done for its side-effects
151 StCall fn cconv VoidRep args -> genCCall fn
152 cconv VoidRep (map derefDLL args)
155 | isFloatingRep pk -> assignFltCode pk (derefDLL dst) (derefDLL src)
156 | otherwise -> assignIntCode pk (derefDLL dst) (derefDLL src)
159 -- When falling through on the Alpha, we still have to load pv
160 -- with the address of the next routine, so that it can load gp.
161 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
165 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
166 returnNat (DATA (primRepToSize kind) imms
167 `consOL` concatOL codes)
169 getData :: StixTree -> NatM (InstrBlock, Imm)
170 getData (StInt i) = returnNat (nilOL, ImmInteger i)
171 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
172 getData (StFloat d) = returnNat (nilOL, ImmFloat d)
173 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
174 getData (StString s) = panic "MachCode.stmtToInstrs: unlifted StString"
175 -- the linker can handle simple arithmetic...
176 getData (StIndex rep (StCLbl lbl) (StInt off)) =
178 ImmIndex lbl (fromInteger off * sizeOf rep))
180 -- Top-level lifted-out string. The segment will already have been set
181 -- (see liftStrings above).
183 -> returnNat (unitOL (ASCII True (_UNPK_ str)))
186 -- Walk a Stix tree, and insert dereferences to CLabels which are marked
187 -- as labelDynamic. stmt2Instrs calls derefDLL selectively, because
188 -- not all such CLabel occurrences need this dereferencing -- SRTs don't
190 derefDLL :: StixTree -> StixTree
192 | opt_Static -- short out the entire deal if not doing DLLs
199 StCLbl lbl -> if labelDynamic lbl
200 then StInd PtrRep (StCLbl lbl)
202 -- all the rest are boring
203 StIndex pk base offset -> StIndex pk (qq base) (qq offset)
204 StPrim pk args -> StPrim pk (map qq args)
205 StInd pk addr -> StInd pk (qq addr)
206 StCall who cc pk args -> StCall who cc pk (map qq args)
213 _ -> pprPanic "derefDLL: unhandled case"
217 %************************************************************************
219 \subsection{General things for putting together code sequences}
221 %************************************************************************
224 mangleIndexTree :: StixTree -> StixTree
226 mangleIndexTree (StIndex pk base (StInt i))
227 = StPrim IntAddOp [base, off]
229 off = StInt (i * toInteger (sizeOf pk))
231 mangleIndexTree (StIndex pk base off)
235 in if s == 0 then off else StPrim SllOp [off, StInt (toInteger s)]
238 shift :: PrimRep -> Int
239 shift rep = case sizeOf rep of
244 other -> pprPanic "MachCode.mangleIndexTree.shift: unhandled rep size"
249 maybeImm :: StixTree -> Maybe Imm
253 maybeImm (StIndex rep (StCLbl l) (StInt off))
254 = Just (ImmIndex l (fromInteger off * sizeOf rep))
256 | i >= toInteger minInt && i <= toInteger maxInt
257 = Just (ImmInt (fromInteger i))
259 = Just (ImmInteger i)
264 %************************************************************************
266 \subsection{The @Register@ type}
268 %************************************************************************
270 @Register@s passed up the tree. If the stix code forces the register
271 to live in a pre-decided machine register, it comes out as @Fixed@;
272 otherwise, it comes out as @Any@, and the parent can decide which
273 register to put it in.
277 = Fixed PrimRep Reg InstrBlock
278 | Any PrimRep (Reg -> InstrBlock)
280 registerCode :: Register -> Reg -> InstrBlock
281 registerCode (Fixed _ _ code) reg = code
282 registerCode (Any _ code) reg = code reg
284 registerCodeF (Fixed _ _ code) = code
285 registerCodeF (Any _ _) = pprPanic "registerCodeF" empty
287 registerCodeA (Any _ code) = code
288 registerCodeA (Fixed _ _ _) = pprPanic "registerCodeA" empty
290 registerName :: Register -> Reg -> Reg
291 registerName (Fixed _ reg _) _ = reg
292 registerName (Any _ _) reg = reg
294 registerNameF (Fixed _ reg _) = reg
295 registerNameF (Any _ _) = pprPanic "registerNameF" empty
297 registerRep :: Register -> PrimRep
298 registerRep (Fixed pk _ _) = pk
299 registerRep (Any pk _) = pk
301 {-# INLINE registerCode #-}
302 {-# INLINE registerCodeF #-}
303 {-# INLINE registerName #-}
304 {-# INLINE registerNameF #-}
305 {-# INLINE registerRep #-}
306 {-# INLINE isFixed #-}
309 isFixed, isAny :: Register -> Bool
310 isFixed (Fixed _ _ _) = True
311 isFixed (Any _ _) = False
313 isAny = not . isFixed
316 Generate code to get a subtree into a @Register@:
318 getRegister :: StixTree -> NatM Register
320 getRegister (StReg (StixMagicId stgreg))
321 = case (magicIdRegMaybe stgreg) of
322 Just reg -> returnNat (Fixed (magicIdPrimRep stgreg) reg nilOL)
325 getRegister (StReg (StixTemp u pk))
326 = returnNat (Fixed pk (mkVReg u pk) nilOL)
328 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
330 getRegister (StCall fn cconv kind args)
331 = genCCall fn cconv kind args `thenNat` \ call ->
332 returnNat (Fixed kind reg call)
334 reg = if isFloatingRep kind
335 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
336 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
338 getRegister (StString s)
339 = getNatLabelNCG `thenNat` \ lbl ->
341 imm_lbl = ImmCLbl lbl
344 SEGMENT RoDataSegment,
346 ASCII True (_UNPK_ s),
348 #if alpha_TARGET_ARCH
349 LDA dst (AddrImm imm_lbl)
352 MOV L (OpImm imm_lbl) (OpReg dst)
354 #if sparc_TARGET_ARCH
355 SETHI (HI imm_lbl) dst,
356 OR False dst (RIImm (LO imm_lbl)) dst
360 returnNat (Any PtrRep code)
364 -- end of machine-"independent" bit; here we go on the rest...
366 #if alpha_TARGET_ARCH
368 getRegister (StDouble d)
369 = getNatLabelNCG `thenNat` \ lbl ->
370 getNewRegNCG PtrRep `thenNat` \ tmp ->
371 let code dst = mkSeqInstrs [
374 DATA TF [ImmLab (rational d)],
376 LDA tmp (AddrImm (ImmCLbl lbl)),
377 LD TF dst (AddrReg tmp)]
379 returnNat (Any DoubleRep code)
381 getRegister (StPrim primop [x]) -- unary PrimOps
383 IntNegOp -> trivialUCode (NEG Q False) x
385 NotOp -> trivialUCode NOT x
387 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
388 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
390 OrdOp -> coerceIntCode IntRep x
393 Float2IntOp -> coerceFP2Int x
394 Int2FloatOp -> coerceInt2FP pr x
395 Double2IntOp -> coerceFP2Int x
396 Int2DoubleOp -> coerceInt2FP pr x
398 Double2FloatOp -> coerceFltCode x
399 Float2DoubleOp -> coerceFltCode x
401 other_op -> getRegister (StCall fn CCallConv DoubleRep [x])
403 fn = case other_op of
404 FloatExpOp -> SLIT("exp")
405 FloatLogOp -> SLIT("log")
406 FloatSqrtOp -> SLIT("sqrt")
407 FloatSinOp -> SLIT("sin")
408 FloatCosOp -> SLIT("cos")
409 FloatTanOp -> SLIT("tan")
410 FloatAsinOp -> SLIT("asin")
411 FloatAcosOp -> SLIT("acos")
412 FloatAtanOp -> SLIT("atan")
413 FloatSinhOp -> SLIT("sinh")
414 FloatCoshOp -> SLIT("cosh")
415 FloatTanhOp -> SLIT("tanh")
416 DoubleExpOp -> SLIT("exp")
417 DoubleLogOp -> SLIT("log")
418 DoubleSqrtOp -> SLIT("sqrt")
419 DoubleSinOp -> SLIT("sin")
420 DoubleCosOp -> SLIT("cos")
421 DoubleTanOp -> SLIT("tan")
422 DoubleAsinOp -> SLIT("asin")
423 DoubleAcosOp -> SLIT("acos")
424 DoubleAtanOp -> SLIT("atan")
425 DoubleSinhOp -> SLIT("sinh")
426 DoubleCoshOp -> SLIT("cosh")
427 DoubleTanhOp -> SLIT("tanh")
429 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
431 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
433 CharGtOp -> trivialCode (CMP LTT) y x
434 CharGeOp -> trivialCode (CMP LE) y x
435 CharEqOp -> trivialCode (CMP EQQ) x y
436 CharNeOp -> int_NE_code x y
437 CharLtOp -> trivialCode (CMP LTT) x y
438 CharLeOp -> trivialCode (CMP LE) x y
440 IntGtOp -> trivialCode (CMP LTT) y x
441 IntGeOp -> trivialCode (CMP LE) y x
442 IntEqOp -> trivialCode (CMP EQQ) x y
443 IntNeOp -> int_NE_code x y
444 IntLtOp -> trivialCode (CMP LTT) x y
445 IntLeOp -> trivialCode (CMP LE) x y
447 WordGtOp -> trivialCode (CMP ULT) y x
448 WordGeOp -> trivialCode (CMP ULE) x y
449 WordEqOp -> trivialCode (CMP EQQ) x y
450 WordNeOp -> int_NE_code x y
451 WordLtOp -> trivialCode (CMP ULT) x y
452 WordLeOp -> trivialCode (CMP ULE) x y
454 AddrGtOp -> trivialCode (CMP ULT) y x
455 AddrGeOp -> trivialCode (CMP ULE) y x
456 AddrEqOp -> trivialCode (CMP EQQ) x y
457 AddrNeOp -> int_NE_code x y
458 AddrLtOp -> trivialCode (CMP ULT) x y
459 AddrLeOp -> trivialCode (CMP ULE) x y
461 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
462 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
463 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
464 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
465 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
466 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
468 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
469 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
470 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
471 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
472 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
473 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
475 IntAddOp -> trivialCode (ADD Q False) x y
476 IntSubOp -> trivialCode (SUB Q False) x y
477 IntMulOp -> trivialCode (MUL Q False) x y
478 IntQuotOp -> trivialCode (DIV Q False) x y
479 IntRemOp -> trivialCode (REM Q False) x y
481 WordAddOp -> trivialCode (ADD Q False) x y
482 WordSubOp -> trivialCode (SUB Q False) x y
483 WordMulOp -> trivialCode (MUL Q False) x y
484 WordQuotOp -> trivialCode (DIV Q True) x y
485 WordRemOp -> trivialCode (REM Q True) x y
487 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
488 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
489 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
490 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
492 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
493 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
494 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
495 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
497 AddrAddOp -> trivialCode (ADD Q False) x y
498 AddrSubOp -> trivialCode (SUB Q False) x y
499 AddrRemOp -> trivialCode (REM Q True) x y
501 AndOp -> trivialCode AND x y
502 OrOp -> trivialCode OR x y
503 XorOp -> trivialCode XOR x y
504 SllOp -> trivialCode SLL x y
505 SrlOp -> trivialCode SRL x y
507 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
508 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
509 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
511 FloatPowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
512 DoublePowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep [x,y])
514 {- ------------------------------------------------------------
515 Some bizarre special code for getting condition codes into
516 registers. Integer non-equality is a test for equality
517 followed by an XOR with 1. (Integer comparisons always set
518 the result register to 0 or 1.) Floating point comparisons of
519 any kind leave the result in a floating point register, so we
520 need to wrangle an integer register out of things.
522 int_NE_code :: StixTree -> StixTree -> NatM Register
525 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
526 getNewRegNCG IntRep `thenNat` \ tmp ->
528 code = registerCode register tmp
529 src = registerName register tmp
530 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
532 returnNat (Any IntRep code__2)
534 {- ------------------------------------------------------------
535 Comments for int_NE_code also apply to cmpF_code
538 :: (Reg -> Reg -> Reg -> Instr)
540 -> StixTree -> StixTree
543 cmpF_code instr cond x y
544 = trivialFCode pr instr x y `thenNat` \ register ->
545 getNewRegNCG DoubleRep `thenNat` \ tmp ->
546 getNatLabelNCG `thenNat` \ lbl ->
548 code = registerCode register tmp
549 result = registerName register tmp
551 code__2 dst = code . mkSeqInstrs [
552 OR zeroh (RIImm (ImmInt 1)) dst,
553 BF cond result (ImmCLbl lbl),
554 OR zeroh (RIReg zeroh) dst,
557 returnNat (Any IntRep code__2)
559 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
560 ------------------------------------------------------------
562 getRegister (StInd pk mem)
563 = getAmode mem `thenNat` \ amode ->
565 code = amodeCode amode
566 src = amodeAddr amode
567 size = primRepToSize pk
568 code__2 dst = code . mkSeqInstr (LD size dst src)
570 returnNat (Any pk code__2)
572 getRegister (StInt i)
575 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
577 returnNat (Any IntRep code)
580 code dst = mkSeqInstr (LDI Q dst src)
582 returnNat (Any IntRep code)
584 src = ImmInt (fromInteger i)
589 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
591 returnNat (Any PtrRep code)
594 imm__2 = case imm of Just x -> x
596 #endif {- alpha_TARGET_ARCH -}
597 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
600 getRegister (StFloat f)
601 = getNatLabelNCG `thenNat` \ lbl ->
602 let code dst = toOL [
607 GLD F (ImmAddr (ImmCLbl lbl) 0) dst
610 returnNat (Any FloatRep code)
613 getRegister (StDouble d)
616 = let code dst = unitOL (GLDZ dst)
617 in returnNat (Any DoubleRep code)
620 = let code dst = unitOL (GLD1 dst)
621 in returnNat (Any DoubleRep code)
624 = getNatLabelNCG `thenNat` \ lbl ->
625 let code dst = toOL [
628 DATA DF [ImmDouble d],
630 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
633 returnNat (Any DoubleRep code)
635 -- Calculate the offset for (i+1) words above the _initial_
636 -- %esp value by first determining the current offset of it.
637 getRegister (StScratchWord i)
639 = getDeltaNat `thenNat` \ current_stack_offset ->
640 let j = i+1 - (current_stack_offset `div` 4)
642 = unitOL (LEA L (OpAddr (spRel j)) (OpReg dst))
644 returnNat (Any PtrRep code)
646 getRegister (StPrim primop [x]) -- unary PrimOps
648 IntNegOp -> trivialUCode (NEGI L) x
649 NotOp -> trivialUCode (NOT L) x
651 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
652 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
654 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
655 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
657 FloatSinOp -> trivialUFCode FloatRep (GSIN F) x
658 DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
660 FloatCosOp -> trivialUFCode FloatRep (GCOS F) x
661 DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
663 FloatTanOp -> trivialUFCode FloatRep (GTAN F) x
664 DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
666 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
667 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
669 OrdOp -> coerceIntCode IntRep x
672 Float2IntOp -> coerceFP2Int x
673 Int2FloatOp -> coerceInt2FP FloatRep x
674 Double2IntOp -> coerceFP2Int x
675 Int2DoubleOp -> coerceInt2FP DoubleRep x
678 getRegister (StCall fn CCallConv DoubleRep [x])
682 FloatExpOp -> (True, SLIT("exp"))
683 FloatLogOp -> (True, SLIT("log"))
685 FloatAsinOp -> (True, SLIT("asin"))
686 FloatAcosOp -> (True, SLIT("acos"))
687 FloatAtanOp -> (True, SLIT("atan"))
689 FloatSinhOp -> (True, SLIT("sinh"))
690 FloatCoshOp -> (True, SLIT("cosh"))
691 FloatTanhOp -> (True, SLIT("tanh"))
693 DoubleExpOp -> (False, SLIT("exp"))
694 DoubleLogOp -> (False, SLIT("log"))
696 DoubleAsinOp -> (False, SLIT("asin"))
697 DoubleAcosOp -> (False, SLIT("acos"))
698 DoubleAtanOp -> (False, SLIT("atan"))
700 DoubleSinhOp -> (False, SLIT("sinh"))
701 DoubleCoshOp -> (False, SLIT("cosh"))
702 DoubleTanhOp -> (False, SLIT("tanh"))
705 -> pprPanic "getRegister(x86,unary primop)"
706 (pprStixTree (StPrim primop [x]))
708 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
710 CharGtOp -> condIntReg GTT x y
711 CharGeOp -> condIntReg GE x y
712 CharEqOp -> condIntReg EQQ x y
713 CharNeOp -> condIntReg NE x y
714 CharLtOp -> condIntReg LTT x y
715 CharLeOp -> condIntReg LE x y
717 IntGtOp -> condIntReg GTT x y
718 IntGeOp -> condIntReg GE x y
719 IntEqOp -> condIntReg EQQ x y
720 IntNeOp -> condIntReg NE x y
721 IntLtOp -> condIntReg LTT x y
722 IntLeOp -> condIntReg LE x y
724 WordGtOp -> condIntReg GU x y
725 WordGeOp -> condIntReg GEU x y
726 WordEqOp -> condIntReg EQQ x y
727 WordNeOp -> condIntReg NE x y
728 WordLtOp -> condIntReg LU x y
729 WordLeOp -> condIntReg LEU x y
731 AddrGtOp -> condIntReg GU x y
732 AddrGeOp -> condIntReg GEU x y
733 AddrEqOp -> condIntReg EQQ x y
734 AddrNeOp -> condIntReg NE x y
735 AddrLtOp -> condIntReg LU x y
736 AddrLeOp -> condIntReg LEU x y
738 FloatGtOp -> condFltReg GTT x y
739 FloatGeOp -> condFltReg GE x y
740 FloatEqOp -> condFltReg EQQ x y
741 FloatNeOp -> condFltReg NE x y
742 FloatLtOp -> condFltReg LTT x y
743 FloatLeOp -> condFltReg LE x y
745 DoubleGtOp -> condFltReg GTT x y
746 DoubleGeOp -> condFltReg GE x y
747 DoubleEqOp -> condFltReg EQQ x y
748 DoubleNeOp -> condFltReg NE x y
749 DoubleLtOp -> condFltReg LTT x y
750 DoubleLeOp -> condFltReg LE x y
752 IntAddOp -> add_code L x y
753 IntSubOp -> sub_code L x y
754 IntQuotOp -> trivialCode (IQUOT L) Nothing x y
755 IntRemOp -> trivialCode (IREM L) Nothing x y
756 IntMulOp -> let op = IMUL L in trivialCode op (Just op) x y
758 WordAddOp -> add_code L x y
759 WordSubOp -> sub_code L x y
760 WordMulOp -> let op = IMUL L in trivialCode op (Just op) x y
762 FloatAddOp -> trivialFCode FloatRep GADD x y
763 FloatSubOp -> trivialFCode FloatRep GSUB x y
764 FloatMulOp -> trivialFCode FloatRep GMUL x y
765 FloatDivOp -> trivialFCode FloatRep GDIV x y
767 DoubleAddOp -> trivialFCode DoubleRep GADD x y
768 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
769 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
770 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
772 AddrAddOp -> add_code L x y
773 AddrSubOp -> sub_code L x y
774 AddrRemOp -> trivialCode (IREM L) Nothing x y
776 AndOp -> let op = AND L in trivialCode op (Just op) x y
777 OrOp -> let op = OR L in trivialCode op (Just op) x y
778 XorOp -> let op = XOR L in trivialCode op (Just op) x y
780 {- Shift ops on x86s have constraints on their source, it
781 either has to be Imm, CL or 1
782 => trivialCode's is not restrictive enough (sigh.)
785 SllOp -> shift_code (SHL L) x y {-False-}
786 SrlOp -> shift_code (SHR L) x y {-False-}
787 ISllOp -> shift_code (SHL L) x y {-False-}
788 ISraOp -> shift_code (SAR L) x y {-False-}
789 ISrlOp -> shift_code (SHR L) x y {-False-}
791 FloatPowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
792 [promote x, promote y])
793 where promote x = StPrim Float2DoubleOp [x]
794 DoublePowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
797 -> pprPanic "getRegister(x86,dyadic primop)"
798 (pprStixTree (StPrim primop [x, y]))
802 shift_code :: (Imm -> Operand -> Instr)
807 {- Case1: shift length as immediate -}
808 -- Code is the same as the first eq. for trivialCode -- sigh.
809 shift_code instr x y{-amount-}
811 = getRegister x `thenNat` \ regx ->
814 then registerCodeA regx dst `bind` \ code_x ->
816 instr imm__2 (OpReg dst)
817 else registerCodeF regx `bind` \ code_x ->
818 registerNameF regx `bind` \ r_x ->
820 MOV L (OpReg r_x) (OpReg dst) `snocOL`
821 instr imm__2 (OpReg dst)
823 returnNat (Any IntRep mkcode)
826 imm__2 = case imm of Just x -> x
828 {- Case2: shift length is complex (non-immediate) -}
829 -- Since ECX is always used as a spill temporary, we can't
830 -- use it here to do non-immediate shifts. No big deal --
831 -- they are only very rare, and we can use an equivalent
832 -- test-and-jump sequence which doesn't use ECX.
833 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
834 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
835 shift_code instr x y{-amount-}
836 = getRegister x `thenNat` \ register1 ->
837 getRegister y `thenNat` \ register2 ->
838 getNatLabelNCG `thenNat` \ lbl_test3 ->
839 getNatLabelNCG `thenNat` \ lbl_test2 ->
840 getNatLabelNCG `thenNat` \ lbl_test1 ->
841 getNatLabelNCG `thenNat` \ lbl_test0 ->
842 getNatLabelNCG `thenNat` \ lbl_after ->
843 getNewRegNCG IntRep `thenNat` \ tmp ->
845 = let src_val = registerName register1 dst
846 code_val = registerCode register1 dst
847 src_amt = registerName register2 tmp
848 code_amt = registerCode register2 tmp
853 MOV L (OpReg src_amt) r_tmp `appOL`
855 MOV L (OpReg src_val) r_dst `appOL`
857 COMMENT (_PK_ "begin shift sequence"),
858 MOV L (OpReg src_val) r_dst,
859 MOV L (OpReg src_amt) r_tmp,
861 BT L (ImmInt 4) r_tmp,
863 instr (ImmInt 16) r_dst,
866 BT L (ImmInt 3) r_tmp,
868 instr (ImmInt 8) r_dst,
871 BT L (ImmInt 2) r_tmp,
873 instr (ImmInt 4) r_dst,
876 BT L (ImmInt 1) r_tmp,
878 instr (ImmInt 2) r_dst,
881 BT L (ImmInt 0) r_tmp,
883 instr (ImmInt 1) r_dst,
886 COMMENT (_PK_ "end shift sequence")
889 returnNat (Any IntRep code__2)
892 add_code :: Size -> StixTree -> StixTree -> NatM Register
894 add_code sz x (StInt y)
895 = getRegister x `thenNat` \ register ->
896 getNewRegNCG IntRep `thenNat` \ tmp ->
898 code = registerCode register tmp
899 src1 = registerName register tmp
900 src2 = ImmInt (fromInteger y)
903 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
906 returnNat (Any IntRep code__2)
908 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
911 sub_code :: Size -> StixTree -> StixTree -> NatM Register
913 sub_code sz x (StInt y)
914 = getRegister x `thenNat` \ register ->
915 getNewRegNCG IntRep `thenNat` \ tmp ->
917 code = registerCode register tmp
918 src1 = registerName register tmp
919 src2 = ImmInt (-(fromInteger y))
922 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
925 returnNat (Any IntRep code__2)
927 sub_code sz x y = trivialCode (SUB sz) Nothing x y
930 getRegister (StInd pk mem)
931 = getAmode mem `thenNat` \ amode ->
933 code = amodeCode amode
934 src = amodeAddr amode
935 size = primRepToSize pk
936 code__2 dst = code `snocOL`
937 if pk == DoubleRep || pk == FloatRep
938 then GLD size src dst
946 (OpAddr src) (OpReg dst)
948 returnNat (Any pk code__2)
950 getRegister (StInt i)
952 src = ImmInt (fromInteger i)
955 = unitOL (XOR L (OpReg dst) (OpReg dst))
957 = unitOL (MOV L (OpImm src) (OpReg dst))
959 returnNat (Any IntRep code)
963 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
965 returnNat (Any PtrRep code)
967 = pprPanic "getRegister(x86)" (pprStixTree leaf)
970 imm__2 = case imm of Just x -> x
972 #endif {- i386_TARGET_ARCH -}
973 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
974 #if sparc_TARGET_ARCH
976 getRegister (StFloat d)
977 = getNatLabelNCG `thenNat` \ lbl ->
978 getNewRegNCG PtrRep `thenNat` \ tmp ->
979 let code dst = toOL [
984 SETHI (HI (ImmCLbl lbl)) tmp,
985 LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
987 returnNat (Any FloatRep code)
989 getRegister (StDouble d)
990 = getNatLabelNCG `thenNat` \ lbl ->
991 getNewRegNCG PtrRep `thenNat` \ tmp ->
992 let code dst = toOL [
995 DATA DF [ImmDouble d],
997 SETHI (HI (ImmCLbl lbl)) tmp,
998 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
1000 returnNat (Any DoubleRep code)
1002 -- The 6-word scratch area is immediately below the frame pointer.
1003 -- Below that is the spill area.
1004 getRegister (StScratchWord i)
1007 code dst = unitOL (fpRelEA (i-6) dst)
1009 returnNat (Any PtrRep code)
1012 getRegister (StPrim primop [x]) -- unary PrimOps
1014 IntNegOp -> trivialUCode (SUB False False g0) x
1015 NotOp -> trivialUCode (XNOR False g0) x
1017 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
1018 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
1020 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
1021 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
1023 OrdOp -> coerceIntCode IntRep x
1026 Float2IntOp -> coerceFP2Int x
1027 Int2FloatOp -> coerceInt2FP FloatRep x
1028 Double2IntOp -> coerceFP2Int x
1029 Int2DoubleOp -> coerceInt2FP DoubleRep x
1033 fixed_x = if is_float_op -- promote to double
1034 then StPrim Float2DoubleOp [x]
1037 getRegister (StCall fn CCallConv DoubleRep [fixed_x])
1041 FloatExpOp -> (True, SLIT("exp"))
1042 FloatLogOp -> (True, SLIT("log"))
1043 FloatSqrtOp -> (True, SLIT("sqrt"))
1045 FloatSinOp -> (True, SLIT("sin"))
1046 FloatCosOp -> (True, SLIT("cos"))
1047 FloatTanOp -> (True, SLIT("tan"))
1049 FloatAsinOp -> (True, SLIT("asin"))
1050 FloatAcosOp -> (True, SLIT("acos"))
1051 FloatAtanOp -> (True, SLIT("atan"))
1053 FloatSinhOp -> (True, SLIT("sinh"))
1054 FloatCoshOp -> (True, SLIT("cosh"))
1055 FloatTanhOp -> (True, SLIT("tanh"))
1057 DoubleExpOp -> (False, SLIT("exp"))
1058 DoubleLogOp -> (False, SLIT("log"))
1059 DoubleSqrtOp -> (False, SLIT("sqrt"))
1061 DoubleSinOp -> (False, SLIT("sin"))
1062 DoubleCosOp -> (False, SLIT("cos"))
1063 DoubleTanOp -> (False, SLIT("tan"))
1065 DoubleAsinOp -> (False, SLIT("asin"))
1066 DoubleAcosOp -> (False, SLIT("acos"))
1067 DoubleAtanOp -> (False, SLIT("atan"))
1069 DoubleSinhOp -> (False, SLIT("sinh"))
1070 DoubleCoshOp -> (False, SLIT("cosh"))
1071 DoubleTanhOp -> (False, SLIT("tanh"))
1074 -> pprPanic "getRegister(sparc,monadicprimop)"
1075 (pprStixTree (StPrim primop [x]))
1077 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1079 CharGtOp -> condIntReg GTT x y
1080 CharGeOp -> condIntReg GE x y
1081 CharEqOp -> condIntReg EQQ x y
1082 CharNeOp -> condIntReg NE x y
1083 CharLtOp -> condIntReg LTT x y
1084 CharLeOp -> condIntReg LE x y
1086 IntGtOp -> condIntReg GTT x y
1087 IntGeOp -> condIntReg GE x y
1088 IntEqOp -> condIntReg EQQ x y
1089 IntNeOp -> condIntReg NE x y
1090 IntLtOp -> condIntReg LTT x y
1091 IntLeOp -> condIntReg LE x y
1093 WordGtOp -> condIntReg GU x y
1094 WordGeOp -> condIntReg GEU x y
1095 WordEqOp -> condIntReg EQQ x y
1096 WordNeOp -> condIntReg NE x y
1097 WordLtOp -> condIntReg LU x y
1098 WordLeOp -> condIntReg LEU x y
1100 AddrGtOp -> condIntReg GU x y
1101 AddrGeOp -> condIntReg GEU x y
1102 AddrEqOp -> condIntReg EQQ x y
1103 AddrNeOp -> condIntReg NE x y
1104 AddrLtOp -> condIntReg LU x y
1105 AddrLeOp -> condIntReg LEU x y
1107 FloatGtOp -> condFltReg GTT x y
1108 FloatGeOp -> condFltReg GE x y
1109 FloatEqOp -> condFltReg EQQ x y
1110 FloatNeOp -> condFltReg NE x y
1111 FloatLtOp -> condFltReg LTT x y
1112 FloatLeOp -> condFltReg LE x y
1114 DoubleGtOp -> condFltReg GTT x y
1115 DoubleGeOp -> condFltReg GE x y
1116 DoubleEqOp -> condFltReg EQQ x y
1117 DoubleNeOp -> condFltReg NE x y
1118 DoubleLtOp -> condFltReg LTT x y
1119 DoubleLeOp -> condFltReg LE x y
1121 IntAddOp -> trivialCode (ADD False False) x y
1122 IntSubOp -> trivialCode (SUB False False) x y
1124 -- ToDo: teach about V8+ SPARC mul/div instructions
1125 IntMulOp -> imul_div SLIT(".umul") x y
1126 IntQuotOp -> imul_div SLIT(".div") x y
1127 IntRemOp -> imul_div SLIT(".rem") x y
1129 WordAddOp -> trivialCode (ADD False False) x y
1130 WordSubOp -> trivialCode (SUB False False) x y
1131 WordMulOp -> imul_div SLIT(".umul") x y
1133 FloatAddOp -> trivialFCode FloatRep FADD x y
1134 FloatSubOp -> trivialFCode FloatRep FSUB x y
1135 FloatMulOp -> trivialFCode FloatRep FMUL x y
1136 FloatDivOp -> trivialFCode FloatRep FDIV x y
1138 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1139 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1140 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1141 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1143 AddrAddOp -> trivialCode (ADD False False) x y
1144 AddrSubOp -> trivialCode (SUB False False) x y
1145 AddrRemOp -> imul_div SLIT(".rem") x y
1147 AndOp -> trivialCode (AND False) x y
1148 OrOp -> trivialCode (OR False) x y
1149 XorOp -> trivialCode (XOR False) x y
1150 SllOp -> trivialCode SLL x y
1151 SrlOp -> trivialCode SRL x y
1153 ISllOp -> trivialCode SLL x y
1154 ISraOp -> trivialCode SRA x y
1155 ISrlOp -> trivialCode SRL x y
1157 FloatPowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1158 [promote x, promote y])
1159 where promote x = StPrim Float2DoubleOp [x]
1160 DoublePowerOp -> getRegister (StCall SLIT("pow") CCallConv DoubleRep
1164 -> pprPanic "getRegister(sparc,dyadic primop)"
1165 (pprStixTree (StPrim primop [x, y]))
1168 imul_div fn x y = getRegister (StCall fn CCallConv IntRep [x, y])
1170 getRegister (StInd pk mem)
1171 = getAmode mem `thenNat` \ amode ->
1173 code = amodeCode amode
1174 src = amodeAddr amode
1175 size = primRepToSize pk
1176 code__2 dst = code `snocOL` LD size src dst
1178 returnNat (Any pk code__2)
1180 getRegister (StInt i)
1183 src = ImmInt (fromInteger i)
1184 code dst = unitOL (OR False g0 (RIImm src) dst)
1186 returnNat (Any IntRep code)
1192 SETHI (HI imm__2) dst,
1193 OR False dst (RIImm (LO imm__2)) dst]
1195 returnNat (Any PtrRep code)
1197 = pprPanic "getRegister(sparc)" (pprStixTree leaf)
1200 imm__2 = case imm of Just x -> x
1202 #endif {- sparc_TARGET_ARCH -}
1205 %************************************************************************
1207 \subsection{The @Amode@ type}
1209 %************************************************************************
1211 @Amode@s: Memory addressing modes passed up the tree.
1213 data Amode = Amode MachRegsAddr InstrBlock
1215 amodeAddr (Amode addr _) = addr
1216 amodeCode (Amode _ code) = code
1219 Now, given a tree (the argument to an StInd) that references memory,
1220 produce a suitable addressing mode.
1222 A Rule of the Game (tm) for Amodes: use of the addr bit must
1223 immediately follow use of the code part, since the code part puts
1224 values in registers which the addr then refers to. So you can't put
1225 anything in between, lest it overwrite some of those registers. If
1226 you need to do some other computation between the code part and use of
1227 the addr bit, first store the effective address from the amode in a
1228 temporary, then do the other computation, and then use the temporary:
1232 ... other computation ...
1236 getAmode :: StixTree -> NatM Amode
1238 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1240 #if alpha_TARGET_ARCH
1242 getAmode (StPrim IntSubOp [x, StInt i])
1243 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1244 getRegister x `thenNat` \ register ->
1246 code = registerCode register tmp
1247 reg = registerName register tmp
1248 off = ImmInt (-(fromInteger i))
1250 returnNat (Amode (AddrRegImm reg off) code)
1252 getAmode (StPrim IntAddOp [x, StInt i])
1253 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1254 getRegister x `thenNat` \ register ->
1256 code = registerCode register tmp
1257 reg = registerName register tmp
1258 off = ImmInt (fromInteger i)
1260 returnNat (Amode (AddrRegImm reg off) code)
1264 = returnNat (Amode (AddrImm imm__2) id)
1267 imm__2 = case imm of Just x -> x
1270 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1271 getRegister other `thenNat` \ register ->
1273 code = registerCode register tmp
1274 reg = registerName register tmp
1276 returnNat (Amode (AddrReg reg) code)
1278 #endif {- alpha_TARGET_ARCH -}
1279 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1280 #if i386_TARGET_ARCH
1282 getAmode (StPrim IntSubOp [x, StInt i])
1283 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1284 getRegister x `thenNat` \ register ->
1286 code = registerCode register tmp
1287 reg = registerName register tmp
1288 off = ImmInt (-(fromInteger i))
1290 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1292 getAmode (StPrim IntAddOp [x, StInt i])
1294 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1297 imm__2 = case imm of Just x -> x
1299 getAmode (StPrim IntAddOp [x, StInt i])
1300 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1301 getRegister x `thenNat` \ register ->
1303 code = registerCode register tmp
1304 reg = registerName register tmp
1305 off = ImmInt (fromInteger i)
1307 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1309 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1310 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1311 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1312 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1313 getRegister x `thenNat` \ register1 ->
1314 getRegister y `thenNat` \ register2 ->
1316 code1 = registerCode register1 tmp1
1317 reg1 = registerName register1 tmp1
1318 code2 = registerCode register2 tmp2
1319 reg2 = registerName register2 tmp2
1320 code__2 = code1 `appOL` code2
1321 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1323 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1328 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1331 imm__2 = case imm of Just x -> x
1334 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1335 getRegister other `thenNat` \ register ->
1337 code = registerCode register tmp
1338 reg = registerName register tmp
1340 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1342 #endif {- i386_TARGET_ARCH -}
1343 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1344 #if sparc_TARGET_ARCH
1346 getAmode (StPrim IntSubOp [x, StInt i])
1348 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1349 getRegister x `thenNat` \ register ->
1351 code = registerCode register tmp
1352 reg = registerName register tmp
1353 off = ImmInt (-(fromInteger i))
1355 returnNat (Amode (AddrRegImm reg off) code)
1358 getAmode (StPrim IntAddOp [x, StInt i])
1360 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1361 getRegister x `thenNat` \ register ->
1363 code = registerCode register tmp
1364 reg = registerName register tmp
1365 off = ImmInt (fromInteger i)
1367 returnNat (Amode (AddrRegImm reg off) code)
1369 getAmode (StPrim IntAddOp [x, y])
1370 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1371 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1372 getRegister x `thenNat` \ register1 ->
1373 getRegister y `thenNat` \ register2 ->
1375 code1 = registerCode register1 tmp1
1376 reg1 = registerName register1 tmp1
1377 code2 = registerCode register2 tmp2
1378 reg2 = registerName register2 tmp2
1379 code__2 = code1 `appOL` code2
1381 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1385 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1387 code = unitOL (SETHI (HI imm__2) tmp)
1389 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1392 imm__2 = case imm of Just x -> x
1395 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1396 getRegister other `thenNat` \ register ->
1398 code = registerCode register tmp
1399 reg = registerName register tmp
1402 returnNat (Amode (AddrRegImm reg off) code)
1404 #endif {- sparc_TARGET_ARCH -}
1407 %************************************************************************
1409 \subsection{The @CondCode@ type}
1411 %************************************************************************
1413 Condition codes passed up the tree.
1415 data CondCode = CondCode Bool Cond InstrBlock
1417 condName (CondCode _ cond _) = cond
1418 condFloat (CondCode is_float _ _) = is_float
1419 condCode (CondCode _ _ code) = code
1422 Set up a condition code for a conditional branch.
1425 getCondCode :: StixTree -> NatM CondCode
1427 #if alpha_TARGET_ARCH
1428 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1429 #endif {- alpha_TARGET_ARCH -}
1430 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1432 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1433 -- yes, they really do seem to want exactly the same!
1435 getCondCode (StPrim primop [x, y])
1437 CharGtOp -> condIntCode GTT x y
1438 CharGeOp -> condIntCode GE x y
1439 CharEqOp -> condIntCode EQQ x y
1440 CharNeOp -> condIntCode NE x y
1441 CharLtOp -> condIntCode LTT x y
1442 CharLeOp -> condIntCode LE x y
1444 IntGtOp -> condIntCode GTT x y
1445 IntGeOp -> condIntCode GE x y
1446 IntEqOp -> condIntCode EQQ x y
1447 IntNeOp -> condIntCode NE x y
1448 IntLtOp -> condIntCode LTT x y
1449 IntLeOp -> condIntCode LE x y
1451 WordGtOp -> condIntCode GU x y
1452 WordGeOp -> condIntCode GEU x y
1453 WordEqOp -> condIntCode EQQ x y
1454 WordNeOp -> condIntCode NE x y
1455 WordLtOp -> condIntCode LU x y
1456 WordLeOp -> condIntCode LEU x y
1458 AddrGtOp -> condIntCode GU x y
1459 AddrGeOp -> condIntCode GEU x y
1460 AddrEqOp -> condIntCode EQQ x y
1461 AddrNeOp -> condIntCode NE x y
1462 AddrLtOp -> condIntCode LU x y
1463 AddrLeOp -> condIntCode LEU x y
1465 FloatGtOp -> condFltCode GTT x y
1466 FloatGeOp -> condFltCode GE x y
1467 FloatEqOp -> condFltCode EQQ x y
1468 FloatNeOp -> condFltCode NE x y
1469 FloatLtOp -> condFltCode LTT x y
1470 FloatLeOp -> condFltCode LE x y
1472 DoubleGtOp -> condFltCode GTT x y
1473 DoubleGeOp -> condFltCode GE x y
1474 DoubleEqOp -> condFltCode EQQ x y
1475 DoubleNeOp -> condFltCode NE x y
1476 DoubleLtOp -> condFltCode LTT x y
1477 DoubleLeOp -> condFltCode LE x y
1479 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1484 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1485 passed back up the tree.
1488 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> NatM CondCode
1490 #if alpha_TARGET_ARCH
1491 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1492 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1493 #endif {- alpha_TARGET_ARCH -}
1495 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1496 #if i386_TARGET_ARCH
1498 -- memory vs immediate
1499 condIntCode cond (StInd pk x) y
1501 = getAmode x `thenNat` \ amode ->
1503 code1 = amodeCode amode
1504 x__2 = amodeAddr amode
1505 sz = primRepToSize pk
1506 code__2 = code1 `snocOL`
1507 CMP sz (OpImm imm__2) (OpAddr x__2)
1509 returnNat (CondCode False cond code__2)
1512 imm__2 = case imm of Just x -> x
1515 condIntCode cond x (StInt 0)
1516 = getRegister x `thenNat` \ register1 ->
1517 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1519 code1 = registerCode register1 tmp1
1520 src1 = registerName register1 tmp1
1521 code__2 = code1 `snocOL`
1522 TEST L (OpReg src1) (OpReg src1)
1524 returnNat (CondCode False cond code__2)
1526 -- anything vs immediate
1527 condIntCode cond x y
1529 = getRegister x `thenNat` \ register1 ->
1530 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1532 code1 = registerCode register1 tmp1
1533 src1 = registerName register1 tmp1
1534 code__2 = code1 `snocOL`
1535 CMP L (OpImm imm__2) (OpReg src1)
1537 returnNat (CondCode False cond code__2)
1540 imm__2 = case imm of Just x -> x
1542 -- memory vs anything
1543 condIntCode cond (StInd pk x) y
1544 = getAmode x `thenNat` \ amode_x ->
1545 getRegister y `thenNat` \ reg_y ->
1546 getNewRegNCG IntRep `thenNat` \ tmp ->
1548 c_x = amodeCode amode_x
1549 am_x = amodeAddr amode_x
1550 c_y = registerCode reg_y tmp
1551 r_y = registerName reg_y tmp
1552 sz = primRepToSize pk
1554 -- optimisation: if there's no code for x, just an amode,
1555 -- use whatever reg y winds up in. Assumes that c_y doesn't
1556 -- clobber any regs in the amode am_x, which I'm not sure is
1557 -- justified. The otherwise clause makes the same assumption.
1558 code__2 | isNilOL c_x
1560 CMP sz (OpReg r_y) (OpAddr am_x)
1564 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1566 CMP sz (OpReg tmp) (OpAddr am_x)
1568 returnNat (CondCode False cond code__2)
1570 -- anything vs memory
1572 condIntCode cond y (StInd pk x)
1573 = getAmode x `thenNat` \ amode_x ->
1574 getRegister y `thenNat` \ reg_y ->
1575 getNewRegNCG IntRep `thenNat` \ tmp ->
1577 c_x = amodeCode amode_x
1578 am_x = amodeAddr amode_x
1579 c_y = registerCode reg_y tmp
1580 r_y = registerName reg_y tmp
1581 sz = primRepToSize pk
1582 -- same optimisation and nagging doubts as previous clause
1583 code__2 | isNilOL c_x
1585 CMP sz (OpAddr am_x) (OpReg r_y)
1589 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1591 CMP sz (OpAddr am_x) (OpReg tmp)
1593 returnNat (CondCode False cond code__2)
1595 -- anything vs anything
1596 condIntCode cond x y
1597 = getRegister x `thenNat` \ register1 ->
1598 getRegister y `thenNat` \ register2 ->
1599 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1600 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1602 code1 = registerCode register1 tmp1
1603 src1 = registerName register1 tmp1
1604 code2 = registerCode register2 tmp2
1605 src2 = registerName register2 tmp2
1606 code__2 = code1 `snocOL`
1607 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1609 CMP L (OpReg src2) (OpReg tmp1)
1611 returnNat (CondCode False cond code__2)
1614 condFltCode cond x y
1615 = getRegister x `thenNat` \ register1 ->
1616 getRegister y `thenNat` \ register2 ->
1617 getNewRegNCG (registerRep register1)
1619 getNewRegNCG (registerRep register2)
1621 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1623 pk1 = registerRep register1
1624 code1 = registerCode register1 tmp1
1625 src1 = registerName register1 tmp1
1627 code2 = registerCode register2 tmp2
1628 src2 = registerName register2 tmp2
1630 code__2 | isAny register1
1631 = code1 `appOL` -- result in tmp1
1633 GCMP (primRepToSize pk1) tmp1 src2
1637 GMOV src1 tmp1 `appOL`
1639 GCMP (primRepToSize pk1) tmp1 src2
1641 {- On the 486, the flags set by FP compare are the unsigned ones!
1642 (This looks like a HACK to me. WDP 96/03)
1644 fix_FP_cond :: Cond -> Cond
1646 fix_FP_cond GE = GEU
1647 fix_FP_cond GTT = GU
1648 fix_FP_cond LTT = LU
1649 fix_FP_cond LE = LEU
1650 fix_FP_cond any = any
1652 returnNat (CondCode True (fix_FP_cond cond) code__2)
1656 #endif {- i386_TARGET_ARCH -}
1657 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1658 #if sparc_TARGET_ARCH
1660 condIntCode cond x (StInt y)
1662 = getRegister x `thenNat` \ register ->
1663 getNewRegNCG IntRep `thenNat` \ tmp ->
1665 code = registerCode register tmp
1666 src1 = registerName register tmp
1667 src2 = ImmInt (fromInteger y)
1668 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1670 returnNat (CondCode False cond code__2)
1672 condIntCode cond x y
1673 = getRegister x `thenNat` \ register1 ->
1674 getRegister y `thenNat` \ register2 ->
1675 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1676 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1678 code1 = registerCode register1 tmp1
1679 src1 = registerName register1 tmp1
1680 code2 = registerCode register2 tmp2
1681 src2 = registerName register2 tmp2
1682 code__2 = code1 `appOL` code2 `snocOL`
1683 SUB False True src1 (RIReg src2) g0
1685 returnNat (CondCode False cond code__2)
1688 condFltCode cond x y
1689 = getRegister x `thenNat` \ register1 ->
1690 getRegister y `thenNat` \ register2 ->
1691 getNewRegNCG (registerRep register1)
1693 getNewRegNCG (registerRep register2)
1695 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1697 promote x = FxTOy F DF x tmp
1699 pk1 = registerRep register1
1700 code1 = registerCode register1 tmp1
1701 src1 = registerName register1 tmp1
1703 pk2 = registerRep register2
1704 code2 = registerCode register2 tmp2
1705 src2 = registerName register2 tmp2
1709 code1 `appOL` code2 `snocOL`
1710 FCMP True (primRepToSize pk1) src1 src2
1711 else if pk1 == FloatRep then
1712 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1713 FCMP True DF tmp src2
1715 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1716 FCMP True DF src1 tmp
1718 returnNat (CondCode True cond code__2)
1720 #endif {- sparc_TARGET_ARCH -}
1723 %************************************************************************
1725 \subsection{Generating assignments}
1727 %************************************************************************
1729 Assignments are really at the heart of the whole code generation
1730 business. Almost all top-level nodes of any real importance are
1731 assignments, which correspond to loads, stores, or register transfers.
1732 If we're really lucky, some of the register transfers will go away,
1733 because we can use the destination register to complete the code
1734 generation for the right hand side. This only fails when the right
1735 hand side is forced into a fixed register (e.g. the result of a call).
1738 assignIntCode, assignFltCode
1739 :: PrimRep -> StixTree -> StixTree -> NatM InstrBlock
1741 #if alpha_TARGET_ARCH
1743 assignIntCode pk (StInd _ dst) src
1744 = getNewRegNCG IntRep `thenNat` \ tmp ->
1745 getAmode dst `thenNat` \ amode ->
1746 getRegister src `thenNat` \ register ->
1748 code1 = amodeCode amode []
1749 dst__2 = amodeAddr amode
1750 code2 = registerCode register tmp []
1751 src__2 = registerName register tmp
1752 sz = primRepToSize pk
1753 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1757 assignIntCode pk dst src
1758 = getRegister dst `thenNat` \ register1 ->
1759 getRegister src `thenNat` \ register2 ->
1761 dst__2 = registerName register1 zeroh
1762 code = registerCode register2 dst__2
1763 src__2 = registerName register2 dst__2
1764 code__2 = if isFixed register2
1765 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1770 #endif {- alpha_TARGET_ARCH -}
1771 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1772 #if i386_TARGET_ARCH
1774 -- Destination of an assignment can only be reg or mem.
1775 -- This is the mem case.
1776 assignIntCode pk (StInd _ dst) src
1777 = getAmode dst `thenNat` \ amode ->
1778 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
1779 getNewRegNCG PtrRep `thenNat` \ tmp ->
1781 -- In general, if the address computation for dst may require
1782 -- some insns preceding the addressing mode itself. So there's
1783 -- no guarantee that the code for dst and the code for src won't
1784 -- write the same register. This means either the address or
1785 -- the value needs to be copied into a temporary. We detect the
1786 -- common case where the amode has no code, and elide the copy.
1787 codea = amodeCode amode
1788 dst__a = amodeAddr amode
1790 code | isNilOL codea
1792 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
1796 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
1798 MOV (primRepToSize pk) opsrc
1799 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
1805 -> NatM (InstrBlock,Operand) -- code, operator
1809 = returnNat (nilOL, OpImm imm_op)
1812 imm_op = case imm of Just x -> x
1815 = getRegister op `thenNat` \ register ->
1816 getNewRegNCG (registerRep register)
1818 let code = registerCode register tmp
1819 reg = registerName register tmp
1821 returnNat (code, OpReg reg)
1823 -- Assign; dst is a reg, rhs is mem
1824 assignIntCode pk dst (StInd pks src)
1825 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1826 getAmode src `thenNat` \ amode ->
1827 getRegister dst `thenNat` \ reg_dst ->
1829 c_addr = amodeCode amode
1830 am_addr = amodeAddr amode
1832 c_dst = registerCode reg_dst tmp -- should be empty
1833 r_dst = registerName reg_dst tmp
1834 szs = primRepToSize pks
1843 code | isNilOL c_dst
1845 opc (OpAddr am_addr) (OpReg r_dst)
1847 = pprPanic "assignIntCode(x86): bad dst(2)" empty
1851 -- dst is a reg, but src could be anything
1852 assignIntCode pk dst src
1853 = getRegister dst `thenNat` \ registerd ->
1854 getRegister src `thenNat` \ registers ->
1855 getNewRegNCG IntRep `thenNat` \ tmp ->
1857 r_dst = registerName registerd tmp
1858 c_dst = registerCode registerd tmp -- should be empty
1859 r_src = registerName registers r_dst
1860 c_src = registerCode registers r_dst
1862 code | isNilOL c_dst
1864 MOV L (OpReg r_src) (OpReg r_dst)
1866 = pprPanic "assignIntCode(x86): bad dst(3)" empty
1870 #endif {- i386_TARGET_ARCH -}
1871 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1872 #if sparc_TARGET_ARCH
1874 assignIntCode pk (StInd _ dst) src
1875 = getNewRegNCG IntRep `thenNat` \ tmp ->
1876 getAmode dst `thenNat` \ amode ->
1877 getRegister src `thenNat` \ register ->
1879 code1 = amodeCode amode
1880 dst__2 = amodeAddr amode
1881 code2 = registerCode register tmp
1882 src__2 = registerName register tmp
1883 sz = primRepToSize pk
1884 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
1888 assignIntCode pk dst src
1889 = getRegister dst `thenNat` \ register1 ->
1890 getRegister src `thenNat` \ register2 ->
1892 dst__2 = registerName register1 g0
1893 code = registerCode register2 dst__2
1894 src__2 = registerName register2 dst__2
1895 code__2 = if isFixed register2
1896 then code `snocOL` OR False g0 (RIReg src__2) dst__2
1901 #endif {- sparc_TARGET_ARCH -}
1904 % --------------------------------
1905 Floating-point assignments:
1906 % --------------------------------
1908 #if alpha_TARGET_ARCH
1910 assignFltCode pk (StInd _ dst) src
1911 = getNewRegNCG pk `thenNat` \ tmp ->
1912 getAmode dst `thenNat` \ amode ->
1913 getRegister src `thenNat` \ register ->
1915 code1 = amodeCode amode []
1916 dst__2 = amodeAddr amode
1917 code2 = registerCode register tmp []
1918 src__2 = registerName register tmp
1919 sz = primRepToSize pk
1920 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1924 assignFltCode pk dst src
1925 = getRegister dst `thenNat` \ register1 ->
1926 getRegister src `thenNat` \ register2 ->
1928 dst__2 = registerName register1 zeroh
1929 code = registerCode register2 dst__2
1930 src__2 = registerName register2 dst__2
1931 code__2 = if isFixed register2
1932 then code . mkSeqInstr (FMOV src__2 dst__2)
1937 #endif {- alpha_TARGET_ARCH -}
1938 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1939 #if i386_TARGET_ARCH
1942 assignFltCode pk (StInd pk_dst addr) src
1944 = pprPanic "assignFltCode(x86): src/ind sz mismatch" empty
1946 = getRegister src `thenNat` \ reg_src ->
1947 getRegister addr `thenNat` \ reg_addr ->
1948 getNewRegNCG pk `thenNat` \ tmp_src ->
1949 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
1950 let r_src = registerName reg_src tmp_src
1951 c_src = registerCode reg_src tmp_src
1952 r_addr = registerName reg_addr tmp_addr
1953 c_addr = registerCode reg_addr tmp_addr
1954 sz = primRepToSize pk
1956 code = c_src `appOL`
1957 -- no need to preserve r_src across the addr computation,
1958 -- since r_src must be a float reg
1959 -- whilst r_addr is an int reg
1962 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
1966 -- dst must be a (FP) register
1967 assignFltCode pk dst src
1968 = getRegister dst `thenNat` \ reg_dst ->
1969 getRegister src `thenNat` \ reg_src ->
1970 getNewRegNCG pk `thenNat` \ tmp ->
1972 r_dst = registerName reg_dst tmp
1973 c_dst = registerCode reg_dst tmp -- should be empty
1975 r_src = registerName reg_src r_dst
1976 c_src = registerCode reg_src r_dst
1978 code | isNilOL c_dst
1979 = if isFixed reg_src
1980 then c_src `snocOL` GMOV r_src r_dst
1983 = pprPanic "assignFltCode(x86): lhs is not mem or reg"
1989 #endif {- i386_TARGET_ARCH -}
1990 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1991 #if sparc_TARGET_ARCH
1993 assignFltCode pk (StInd _ dst) src
1994 = getNewRegNCG pk `thenNat` \ tmp1 ->
1995 getAmode dst `thenNat` \ amode ->
1996 getRegister src `thenNat` \ register ->
1998 sz = primRepToSize pk
1999 dst__2 = amodeAddr amode
2001 code1 = amodeCode amode
2002 code2 = registerCode register tmp1
2004 src__2 = registerName register tmp1
2005 pk__2 = registerRep register
2006 sz__2 = primRepToSize pk__2
2008 code__2 = code1 `appOL` code2 `appOL`
2010 then unitOL (ST sz src__2 dst__2)
2011 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
2015 assignFltCode pk dst src
2016 = getRegister dst `thenNat` \ register1 ->
2017 getRegister src `thenNat` \ register2 ->
2019 pk__2 = registerRep register2
2020 sz__2 = primRepToSize pk__2
2022 getNewRegNCG pk__2 `thenNat` \ tmp ->
2024 sz = primRepToSize pk
2025 dst__2 = registerName register1 g0 -- must be Fixed
2028 reg__2 = if pk /= pk__2 then tmp else dst__2
2030 code = registerCode register2 reg__2
2032 src__2 = registerName register2 reg__2
2036 code `snocOL` FxTOy sz__2 sz src__2 dst__2
2037 else if isFixed register2 then
2038 code `snocOL` FMOV sz src__2 dst__2
2044 #endif {- sparc_TARGET_ARCH -}
2047 %************************************************************************
2049 \subsection{Generating an unconditional branch}
2051 %************************************************************************
2053 We accept two types of targets: an immediate CLabel or a tree that
2054 gets evaluated into a register. Any CLabels which are AsmTemporaries
2055 are assumed to be in the local block of code, close enough for a
2056 branch instruction. Other CLabels are assumed to be far away.
2058 (If applicable) Do not fill the delay slots here; you will confuse the
2062 genJump :: DestInfo -> StixTree{-the branch target-} -> NatM InstrBlock
2064 #if alpha_TARGET_ARCH
2066 genJump (StCLbl lbl)
2067 | isAsmTemp lbl = returnInstr (BR target)
2068 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
2070 target = ImmCLbl lbl
2073 = getRegister tree `thenNat` \ register ->
2074 getNewRegNCG PtrRep `thenNat` \ tmp ->
2076 dst = registerName register pv
2077 code = registerCode register pv
2078 target = registerName register pv
2080 if isFixed register then
2081 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2083 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2085 #endif {- alpha_TARGET_ARCH -}
2086 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2087 #if i386_TARGET_ARCH
2089 genJump dsts (StInd pk mem)
2090 = getAmode mem `thenNat` \ amode ->
2092 code = amodeCode amode
2093 target = amodeAddr amode
2095 returnNat (code `snocOL` JMP dsts (OpAddr target))
2099 = returnNat (unitOL (JMP dsts (OpImm target)))
2102 = getRegister tree `thenNat` \ register ->
2103 getNewRegNCG PtrRep `thenNat` \ tmp ->
2105 code = registerCode register tmp
2106 target = registerName register tmp
2108 returnNat (code `snocOL` JMP dsts (OpReg target))
2111 target = case imm of Just x -> x
2113 #endif {- i386_TARGET_ARCH -}
2114 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2115 #if sparc_TARGET_ARCH
2117 genJump dsts (StCLbl lbl)
2118 | hasDestInfo dsts = panic "genJump(sparc): CLbl and dsts"
2119 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
2120 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
2122 target = ImmCLbl lbl
2125 = getRegister tree `thenNat` \ register ->
2126 getNewRegNCG PtrRep `thenNat` \ tmp ->
2128 code = registerCode register tmp
2129 target = registerName register tmp
2131 returnNat (code `snocOL` JMP dsts (AddrRegReg target g0) `snocOL` NOP)
2133 #endif {- sparc_TARGET_ARCH -}
2136 %************************************************************************
2138 \subsection{Conditional jumps}
2140 %************************************************************************
2142 Conditional jumps are always to local labels, so we can use branch
2143 instructions. We peek at the arguments to decide what kind of
2146 ALPHA: For comparisons with 0, we're laughing, because we can just do
2147 the desired conditional branch.
2149 I386: First, we have to ensure that the condition
2150 codes are set according to the supplied comparison operation.
2152 SPARC: First, we have to ensure that the condition codes are set
2153 according to the supplied comparison operation. We generate slightly
2154 different code for floating point comparisons, because a floating
2155 point operation cannot directly precede a @BF@. We assume the worst
2156 and fill that slot with a @NOP@.
2158 SPARC: Do not fill the delay slots here; you will confuse the register
2163 :: CLabel -- the branch target
2164 -> StixTree -- the condition on which to branch
2167 #if alpha_TARGET_ARCH
2169 genCondJump lbl (StPrim op [x, StInt 0])
2170 = getRegister x `thenNat` \ register ->
2171 getNewRegNCG (registerRep register)
2174 code = registerCode register tmp
2175 value = registerName register tmp
2176 pk = registerRep register
2177 target = ImmCLbl lbl
2179 returnSeq code [BI (cmpOp op) value target]
2181 cmpOp CharGtOp = GTT
2183 cmpOp CharEqOp = EQQ
2185 cmpOp CharLtOp = LTT
2194 cmpOp WordGeOp = ALWAYS
2195 cmpOp WordEqOp = EQQ
2197 cmpOp WordLtOp = NEVER
2198 cmpOp WordLeOp = EQQ
2200 cmpOp AddrGeOp = ALWAYS
2201 cmpOp AddrEqOp = EQQ
2203 cmpOp AddrLtOp = NEVER
2204 cmpOp AddrLeOp = EQQ
2206 genCondJump lbl (StPrim op [x, StDouble 0.0])
2207 = getRegister x `thenNat` \ register ->
2208 getNewRegNCG (registerRep register)
2211 code = registerCode register tmp
2212 value = registerName register tmp
2213 pk = registerRep register
2214 target = ImmCLbl lbl
2216 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2218 cmpOp FloatGtOp = GTT
2219 cmpOp FloatGeOp = GE
2220 cmpOp FloatEqOp = EQQ
2221 cmpOp FloatNeOp = NE
2222 cmpOp FloatLtOp = LTT
2223 cmpOp FloatLeOp = LE
2224 cmpOp DoubleGtOp = GTT
2225 cmpOp DoubleGeOp = GE
2226 cmpOp DoubleEqOp = EQQ
2227 cmpOp DoubleNeOp = NE
2228 cmpOp DoubleLtOp = LTT
2229 cmpOp DoubleLeOp = LE
2231 genCondJump lbl (StPrim op [x, y])
2233 = trivialFCode pr instr x y `thenNat` \ register ->
2234 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2236 code = registerCode register tmp
2237 result = registerName register tmp
2238 target = ImmCLbl lbl
2240 returnNat (code . mkSeqInstr (BF cond result target))
2242 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2244 fltCmpOp op = case op of
2258 (instr, cond) = case op of
2259 FloatGtOp -> (FCMP TF LE, EQQ)
2260 FloatGeOp -> (FCMP TF LTT, EQQ)
2261 FloatEqOp -> (FCMP TF EQQ, NE)
2262 FloatNeOp -> (FCMP TF EQQ, EQQ)
2263 FloatLtOp -> (FCMP TF LTT, NE)
2264 FloatLeOp -> (FCMP TF LE, NE)
2265 DoubleGtOp -> (FCMP TF LE, EQQ)
2266 DoubleGeOp -> (FCMP TF LTT, EQQ)
2267 DoubleEqOp -> (FCMP TF EQQ, NE)
2268 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2269 DoubleLtOp -> (FCMP TF LTT, NE)
2270 DoubleLeOp -> (FCMP TF LE, NE)
2272 genCondJump lbl (StPrim op [x, y])
2273 = trivialCode instr x y `thenNat` \ register ->
2274 getNewRegNCG IntRep `thenNat` \ tmp ->
2276 code = registerCode register tmp
2277 result = registerName register tmp
2278 target = ImmCLbl lbl
2280 returnNat (code . mkSeqInstr (BI cond result target))
2282 (instr, cond) = case op of
2283 CharGtOp -> (CMP LE, EQQ)
2284 CharGeOp -> (CMP LTT, EQQ)
2285 CharEqOp -> (CMP EQQ, NE)
2286 CharNeOp -> (CMP EQQ, EQQ)
2287 CharLtOp -> (CMP LTT, NE)
2288 CharLeOp -> (CMP LE, NE)
2289 IntGtOp -> (CMP LE, EQQ)
2290 IntGeOp -> (CMP LTT, EQQ)
2291 IntEqOp -> (CMP EQQ, NE)
2292 IntNeOp -> (CMP EQQ, EQQ)
2293 IntLtOp -> (CMP LTT, NE)
2294 IntLeOp -> (CMP LE, NE)
2295 WordGtOp -> (CMP ULE, EQQ)
2296 WordGeOp -> (CMP ULT, EQQ)
2297 WordEqOp -> (CMP EQQ, NE)
2298 WordNeOp -> (CMP EQQ, EQQ)
2299 WordLtOp -> (CMP ULT, NE)
2300 WordLeOp -> (CMP ULE, NE)
2301 AddrGtOp -> (CMP ULE, EQQ)
2302 AddrGeOp -> (CMP ULT, EQQ)
2303 AddrEqOp -> (CMP EQQ, NE)
2304 AddrNeOp -> (CMP EQQ, EQQ)
2305 AddrLtOp -> (CMP ULT, NE)
2306 AddrLeOp -> (CMP ULE, NE)
2308 #endif {- alpha_TARGET_ARCH -}
2309 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2310 #if i386_TARGET_ARCH
2312 genCondJump lbl bool
2313 = getCondCode bool `thenNat` \ condition ->
2315 code = condCode condition
2316 cond = condName condition
2318 returnNat (code `snocOL` JXX cond lbl)
2320 #endif {- i386_TARGET_ARCH -}
2321 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2322 #if sparc_TARGET_ARCH
2324 genCondJump lbl bool
2325 = getCondCode bool `thenNat` \ condition ->
2327 code = condCode condition
2328 cond = condName condition
2329 target = ImmCLbl lbl
2334 if condFloat condition
2335 then [NOP, BF cond False target, NOP]
2336 else [BI cond False target, NOP]
2340 #endif {- sparc_TARGET_ARCH -}
2343 %************************************************************************
2345 \subsection{Generating C calls}
2347 %************************************************************************
2349 Now the biggest nightmare---calls. Most of the nastiness is buried in
2350 @get_arg@, which moves the arguments to the correct registers/stack
2351 locations. Apart from that, the code is easy.
2353 (If applicable) Do not fill the delay slots here; you will confuse the
2358 :: FAST_STRING -- function to call
2360 -> PrimRep -- type of the result
2361 -> [StixTree] -- arguments (of mixed type)
2364 #if alpha_TARGET_ARCH
2366 genCCall fn cconv kind args
2367 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2368 `thenNat` \ ((unused,_), argCode) ->
2370 nRegs = length allArgRegs - length unused
2371 code = asmSeqThen (map ($ []) argCode)
2374 LDA pv (AddrImm (ImmLab (ptext fn))),
2375 JSR ra (AddrReg pv) nRegs,
2376 LDGP gp (AddrReg ra)]
2378 ------------------------
2379 {- Try to get a value into a specific register (or registers) for
2380 a call. The first 6 arguments go into the appropriate
2381 argument register (separate registers for integer and floating
2382 point arguments, but used in lock-step), and the remaining
2383 arguments are dumped to the stack, beginning at 0(sp). Our
2384 first argument is a pair of the list of remaining argument
2385 registers to be assigned for this call and the next stack
2386 offset to use for overflowing arguments. This way,
2387 @get_Arg@ can be applied to all of a call's arguments using
2391 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2392 -> StixTree -- Current argument
2393 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2395 -- We have to use up all of our argument registers first...
2397 get_arg ((iDst,fDst):dsts, offset) arg
2398 = getRegister arg `thenNat` \ register ->
2400 reg = if isFloatingRep pk then fDst else iDst
2401 code = registerCode register reg
2402 src = registerName register reg
2403 pk = registerRep register
2406 if isFloatingRep pk then
2407 ((dsts, offset), if isFixed register then
2408 code . mkSeqInstr (FMOV src fDst)
2411 ((dsts, offset), if isFixed register then
2412 code . mkSeqInstr (OR src (RIReg src) iDst)
2415 -- Once we have run out of argument registers, we move to the
2418 get_arg ([], offset) arg
2419 = getRegister arg `thenNat` \ register ->
2420 getNewRegNCG (registerRep register)
2423 code = registerCode register tmp
2424 src = registerName register tmp
2425 pk = registerRep register
2426 sz = primRepToSize pk
2428 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2430 #endif {- alpha_TARGET_ARCH -}
2431 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2432 #if i386_TARGET_ARCH
2434 genCCall fn cconv kind [StInt i]
2435 | fn == SLIT ("PerformGC_wrapper")
2437 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2438 CALL (ImmLit (ptext (if underscorePrefix
2439 then (SLIT ("_PerformGC_wrapper"))
2440 else (SLIT ("PerformGC_wrapper")))))
2446 genCCall fn cconv kind args
2447 = mapNat get_call_arg
2448 (reverse args) `thenNat` \ sizes_n_codes ->
2449 getDeltaNat `thenNat` \ delta ->
2450 let (sizes, codes) = unzip sizes_n_codes
2451 tot_arg_size = sum sizes
2452 code2 = concatOL codes
2454 [CALL (fn__2 tot_arg_size)]
2456 -- Deallocate parameters after call for ccall;
2457 -- but not for stdcall (callee does it)
2458 (if cconv == StdCallConv then [] else
2459 [ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)])
2462 [DELTA (delta + tot_arg_size)]
2465 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2466 returnNat (code2 `appOL` call)
2469 -- function names that begin with '.' are assumed to be special
2470 -- internally generated names like '.mul,' which don't get an
2471 -- underscore prefix
2472 -- ToDo:needed (WDP 96/03) ???
2476 = ImmLit (text (fn_u ++ stdcallsize tot_arg_size))
2477 | otherwise -- General case
2478 = ImmLab False (text (fn_u ++ stdcallsize tot_arg_size))
2480 stdcallsize tot_arg_size
2481 | cconv == StdCallConv = '@':show tot_arg_size
2489 get_call_arg :: StixTree{-current argument-}
2490 -> NatM (Int, InstrBlock) -- argsz, code
2493 = get_op arg `thenNat` \ (code, reg, sz) ->
2494 getDeltaNat `thenNat` \ delta ->
2495 arg_size sz `bind` \ size ->
2496 setDeltaNat (delta-size) `thenNat` \ _ ->
2497 if (case sz of DF -> True; F -> True; _ -> False)
2498 then returnNat (size,
2500 toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
2502 GST sz reg (AddrBaseIndex (Just esp)
2506 else returnNat (size,
2508 PUSH L (OpReg reg) `snocOL`
2514 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2517 = getRegister op `thenNat` \ register ->
2518 getNewRegNCG (registerRep register)
2521 code = registerCode register tmp
2522 reg = registerName register tmp
2523 pk = registerRep register
2524 sz = primRepToSize pk
2526 returnNat (code, reg, sz)
2528 #endif {- i386_TARGET_ARCH -}
2529 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2530 #if sparc_TARGET_ARCH
2532 The SPARC calling convention is an absolute
2533 nightmare. The first 6x32 bits of arguments are mapped into
2534 %o0 through %o5, and the remaining arguments are dumped to the
2535 stack, beginning at [%sp+92]. (Note that %o6 == %sp.)
2537 If we have to put args on the stack, move %o6==%sp down by
2538 the number of words to go on the stack, to ensure there's enough space.
2540 According to Fraser and Hanson's lcc book, page 478, fig 17.2,
2541 16 words above the stack pointer is a word for the address of
2542 a structure return value. I use this as a temporary location
2543 for moving values from float to int regs. Certainly it isn't
2544 safe to put anything in the 16 words starting at %sp, since
2545 this area can get trashed at any time due to window overflows
2546 caused by signal handlers.
2548 A final complication (if the above isn't enough) is that
2549 we can't blithely calculate the arguments one by one into
2550 %o0 .. %o5. Consider the following nested calls:
2554 Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately
2555 the inner call will itself use %o0, which trashes the value put there
2556 in preparation for the outer call. Upshot: we need to calculate the
2557 args into temporary regs, and move those to arg regs or onto the
2558 stack only immediately prior to the call proper. Sigh.
2561 genCCall fn cconv kind args
2562 = mapNat arg_to_int_vregs args `thenNat` \ argcode_and_vregs ->
2563 let (argcodes, vregss) = unzip argcode_and_vregs
2564 argcode = concatOL argcodes
2565 vregs = concat vregss
2566 n_argRegs = length allArgRegs
2567 n_argRegs_used = min (length vregs) n_argRegs
2568 (move_sp_down, move_sp_up)
2569 = let nn = length vregs - n_argRegs
2570 + 1 -- (for the road)
2573 else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))
2575 = toOL (move_final vregs allArgRegs eXTRA_STK_ARGS_HERE)
2577 = unitOL (CALL fn__2 n_argRegs_used False)
2579 returnNat (argcode `appOL`
2580 move_sp_down `appOL`
2581 transfer_code `appOL`
2586 -- function names that begin with '.' are assumed to be special
2587 -- internally generated names like '.mul,' which don't get an
2588 -- underscore prefix
2589 -- ToDo:needed (WDP 96/03) ???
2590 fn__2 = case (_HEAD_ fn) of
2591 '.' -> ImmLit (ptext fn)
2592 _ -> ImmLab False (ptext fn)
2594 -- move args from the integer vregs into which they have been
2595 -- marshalled, into %o0 .. %o5, and the rest onto the stack.
2596 move_final :: [Reg] -> [Reg] -> Int -> [Instr]
2598 move_final [] _ offset -- all args done
2601 move_final (v:vs) [] offset -- out of aregs; move to stack
2602 = ST W v (spRel offset)
2603 : move_final vs [] (offset+1)
2605 move_final (v:vs) (a:az) offset -- move into an arg (%o[0..5]) reg
2606 = OR False g0 (RIReg v) a
2607 : move_final vs az offset
2609 -- generate code to calculate an argument, and move it into one
2610 -- or two integer vregs.
2611 arg_to_int_vregs :: StixTree -> NatM (OrdList Instr, [Reg])
2612 arg_to_int_vregs arg
2613 = getRegister arg `thenNat` \ register ->
2614 getNewRegNCG (registerRep register) `thenNat` \ tmp ->
2615 let code = registerCode register tmp
2616 src = registerName register tmp
2617 pk = registerRep register
2619 -- the value is in src. Get it into 1 or 2 int vregs.
2622 getNewRegNCG WordRep `thenNat` \ v1 ->
2623 getNewRegNCG WordRep `thenNat` \ v2 ->
2626 FMOV DF src f0 `snocOL`
2627 ST F f0 (spRel 16) `snocOL`
2628 LD W (spRel 16) v1 `snocOL`
2629 ST F (fPair f0) (spRel 16) `snocOL`
2635 getNewRegNCG WordRep `thenNat` \ v1 ->
2638 ST F src (spRel 16) `snocOL`
2644 getNewRegNCG WordRep `thenNat` \ v1 ->
2646 code `snocOL` OR False g0 (RIReg src) v1
2650 #endif {- sparc_TARGET_ARCH -}
2653 %************************************************************************
2655 \subsection{Support bits}
2657 %************************************************************************
2659 %************************************************************************
2661 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2663 %************************************************************************
2665 Turn those condition codes into integers now (when they appear on
2666 the right hand side of an assignment).
2668 (If applicable) Do not fill the delay slots here; you will confuse the
2672 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> NatM Register
2674 #if alpha_TARGET_ARCH
2675 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2676 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2677 #endif {- alpha_TARGET_ARCH -}
2679 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2680 #if i386_TARGET_ARCH
2683 = condIntCode cond x y `thenNat` \ condition ->
2684 getNewRegNCG IntRep `thenNat` \ tmp ->
2686 code = condCode condition
2687 cond = condName condition
2688 code__2 dst = code `appOL` toOL [
2689 SETCC cond (OpReg tmp),
2690 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2691 MOV L (OpReg tmp) (OpReg dst)]
2693 returnNat (Any IntRep code__2)
2696 = getNatLabelNCG `thenNat` \ lbl1 ->
2697 getNatLabelNCG `thenNat` \ lbl2 ->
2698 condFltCode cond x y `thenNat` \ condition ->
2700 code = condCode condition
2701 cond = condName condition
2702 code__2 dst = code `appOL` toOL [
2704 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2707 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2710 returnNat (Any IntRep code__2)
2712 #endif {- i386_TARGET_ARCH -}
2713 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2714 #if sparc_TARGET_ARCH
2716 condIntReg EQQ x (StInt 0)
2717 = getRegister x `thenNat` \ register ->
2718 getNewRegNCG IntRep `thenNat` \ tmp ->
2720 code = registerCode register tmp
2721 src = registerName register tmp
2722 code__2 dst = code `appOL` toOL [
2723 SUB False True g0 (RIReg src) g0,
2724 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2726 returnNat (Any IntRep code__2)
2729 = getRegister x `thenNat` \ register1 ->
2730 getRegister y `thenNat` \ register2 ->
2731 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2732 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2734 code1 = registerCode register1 tmp1
2735 src1 = registerName register1 tmp1
2736 code2 = registerCode register2 tmp2
2737 src2 = registerName register2 tmp2
2738 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2739 XOR False src1 (RIReg src2) dst,
2740 SUB False True g0 (RIReg dst) g0,
2741 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2743 returnNat (Any IntRep code__2)
2745 condIntReg NE x (StInt 0)
2746 = getRegister x `thenNat` \ register ->
2747 getNewRegNCG IntRep `thenNat` \ tmp ->
2749 code = registerCode register tmp
2750 src = registerName register tmp
2751 code__2 dst = code `appOL` toOL [
2752 SUB False True g0 (RIReg src) g0,
2753 ADD True False g0 (RIImm (ImmInt 0)) dst]
2755 returnNat (Any IntRep code__2)
2758 = getRegister x `thenNat` \ register1 ->
2759 getRegister y `thenNat` \ register2 ->
2760 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2761 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2763 code1 = registerCode register1 tmp1
2764 src1 = registerName register1 tmp1
2765 code2 = registerCode register2 tmp2
2766 src2 = registerName register2 tmp2
2767 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2768 XOR False src1 (RIReg src2) dst,
2769 SUB False True g0 (RIReg dst) g0,
2770 ADD True False g0 (RIImm (ImmInt 0)) dst]
2772 returnNat (Any IntRep code__2)
2775 = getNatLabelNCG `thenNat` \ lbl1 ->
2776 getNatLabelNCG `thenNat` \ lbl2 ->
2777 condIntCode cond x y `thenNat` \ condition ->
2779 code = condCode condition
2780 cond = condName condition
2781 code__2 dst = code `appOL` toOL [
2782 BI cond False (ImmCLbl lbl1), NOP,
2783 OR False g0 (RIImm (ImmInt 0)) dst,
2784 BI ALWAYS False (ImmCLbl lbl2), NOP,
2786 OR False g0 (RIImm (ImmInt 1)) dst,
2789 returnNat (Any IntRep code__2)
2792 = getNatLabelNCG `thenNat` \ lbl1 ->
2793 getNatLabelNCG `thenNat` \ lbl2 ->
2794 condFltCode cond x y `thenNat` \ condition ->
2796 code = condCode condition
2797 cond = condName condition
2798 code__2 dst = code `appOL` toOL [
2800 BF cond False (ImmCLbl lbl1), NOP,
2801 OR False g0 (RIImm (ImmInt 0)) dst,
2802 BI ALWAYS False (ImmCLbl lbl2), NOP,
2804 OR False g0 (RIImm (ImmInt 1)) dst,
2807 returnNat (Any IntRep code__2)
2809 #endif {- sparc_TARGET_ARCH -}
2812 %************************************************************************
2814 \subsubsection{@trivial*Code@: deal with trivial instructions}
2816 %************************************************************************
2818 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2819 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2820 for constants on the right hand side, because that's where the generic
2821 optimizer will have put them.
2823 Similarly, for unary instructions, we don't have to worry about
2824 matching an StInt as the argument, because genericOpt will already
2825 have handled the constant-folding.
2829 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2830 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2831 -> Maybe (Operand -> Operand -> Instr)
2832 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2834 -> StixTree -> StixTree -- the two arguments
2839 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2840 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2841 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2843 -> StixTree -> StixTree -- the two arguments
2847 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2848 ,IF_ARCH_i386 ((Operand -> Instr)
2849 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2851 -> StixTree -- the one argument
2856 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2857 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2858 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2860 -> StixTree -- the one argument
2863 #if alpha_TARGET_ARCH
2865 trivialCode instr x (StInt y)
2867 = getRegister x `thenNat` \ register ->
2868 getNewRegNCG IntRep `thenNat` \ tmp ->
2870 code = registerCode register tmp
2871 src1 = registerName register tmp
2872 src2 = ImmInt (fromInteger y)
2873 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2875 returnNat (Any IntRep code__2)
2877 trivialCode instr x y
2878 = getRegister x `thenNat` \ register1 ->
2879 getRegister y `thenNat` \ register2 ->
2880 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2881 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2883 code1 = registerCode register1 tmp1 []
2884 src1 = registerName register1 tmp1
2885 code2 = registerCode register2 tmp2 []
2886 src2 = registerName register2 tmp2
2887 code__2 dst = asmSeqThen [code1, code2] .
2888 mkSeqInstr (instr src1 (RIReg src2) dst)
2890 returnNat (Any IntRep code__2)
2893 trivialUCode instr x
2894 = getRegister x `thenNat` \ register ->
2895 getNewRegNCG IntRep `thenNat` \ tmp ->
2897 code = registerCode register tmp
2898 src = registerName register tmp
2899 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2901 returnNat (Any IntRep code__2)
2904 trivialFCode _ instr x y
2905 = getRegister x `thenNat` \ register1 ->
2906 getRegister y `thenNat` \ register2 ->
2907 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2908 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2910 code1 = registerCode register1 tmp1
2911 src1 = registerName register1 tmp1
2913 code2 = registerCode register2 tmp2
2914 src2 = registerName register2 tmp2
2916 code__2 dst = asmSeqThen [code1 [], code2 []] .
2917 mkSeqInstr (instr src1 src2 dst)
2919 returnNat (Any DoubleRep code__2)
2921 trivialUFCode _ instr x
2922 = getRegister x `thenNat` \ register ->
2923 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2925 code = registerCode register tmp
2926 src = registerName register tmp
2927 code__2 dst = code . mkSeqInstr (instr src dst)
2929 returnNat (Any DoubleRep code__2)
2931 #endif {- alpha_TARGET_ARCH -}
2932 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2933 #if i386_TARGET_ARCH
2935 The Rules of the Game are:
2937 * You cannot assume anything about the destination register dst;
2938 it may be anything, including a fixed reg.
2940 * You may compute an operand into a fixed reg, but you may not
2941 subsequently change the contents of that fixed reg. If you
2942 want to do so, first copy the value either to a temporary
2943 or into dst. You are free to modify dst even if it happens
2944 to be a fixed reg -- that's not your problem.
2946 * You cannot assume that a fixed reg will stay live over an
2947 arbitrary computation. The same applies to the dst reg.
2949 * Temporary regs obtained from getNewRegNCG are distinct from
2950 each other and from all other regs, and stay live over
2951 arbitrary computations.
2955 trivialCode instr maybe_revinstr a b
2958 = getRegister a `thenNat` \ rega ->
2961 then registerCode rega dst `bind` \ code_a ->
2963 instr (OpImm imm_b) (OpReg dst)
2964 else registerCodeF rega `bind` \ code_a ->
2965 registerNameF rega `bind` \ r_a ->
2967 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2968 instr (OpImm imm_b) (OpReg dst)
2970 returnNat (Any IntRep mkcode)
2973 = getRegister b `thenNat` \ regb ->
2974 getNewRegNCG IntRep `thenNat` \ tmp ->
2975 let revinstr_avail = maybeToBool maybe_revinstr
2976 revinstr = case maybe_revinstr of Just ri -> ri
2980 then registerCode regb dst `bind` \ code_b ->
2982 revinstr (OpImm imm_a) (OpReg dst)
2983 else registerCodeF regb `bind` \ code_b ->
2984 registerNameF regb `bind` \ r_b ->
2986 MOV L (OpReg r_b) (OpReg dst) `snocOL`
2987 revinstr (OpImm imm_a) (OpReg dst)
2991 then registerCode regb tmp `bind` \ code_b ->
2993 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2994 instr (OpReg tmp) (OpReg dst)
2995 else registerCodeF regb `bind` \ code_b ->
2996 registerNameF regb `bind` \ r_b ->
2998 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
2999 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
3000 instr (OpReg tmp) (OpReg dst)
3002 returnNat (Any IntRep mkcode)
3005 = getRegister a `thenNat` \ rega ->
3006 getRegister b `thenNat` \ regb ->
3007 getNewRegNCG IntRep `thenNat` \ tmp ->
3009 = case (isAny rega, isAny regb) of
3011 -> registerCode regb tmp `bind` \ code_b ->
3012 registerCode rega dst `bind` \ code_a ->
3015 instr (OpReg tmp) (OpReg dst)
3017 -> registerCode rega tmp `bind` \ code_a ->
3018 registerCodeF regb `bind` \ code_b ->
3019 registerNameF regb `bind` \ r_b ->
3022 instr (OpReg r_b) (OpReg tmp) `snocOL`
3023 MOV L (OpReg tmp) (OpReg dst)
3025 -> registerCode regb tmp `bind` \ code_b ->
3026 registerCodeF rega `bind` \ code_a ->
3027 registerNameF rega `bind` \ r_a ->
3030 MOV L (OpReg r_a) (OpReg dst) `snocOL`
3031 instr (OpReg tmp) (OpReg dst)
3033 -> registerCodeF rega `bind` \ code_a ->
3034 registerNameF rega `bind` \ r_a ->
3035 registerCodeF regb `bind` \ code_b ->
3036 registerNameF regb `bind` \ r_b ->
3038 MOV L (OpReg r_a) (OpReg tmp) `appOL`
3040 instr (OpReg r_b) (OpReg tmp) `snocOL`
3041 MOV L (OpReg tmp) (OpReg dst)
3043 returnNat (Any IntRep mkcode)
3046 maybe_imm_a = maybeImm a
3047 is_imm_a = maybeToBool maybe_imm_a
3048 imm_a = case maybe_imm_a of Just imm -> imm
3050 maybe_imm_b = maybeImm b
3051 is_imm_b = maybeToBool maybe_imm_b
3052 imm_b = case maybe_imm_b of Just imm -> imm
3056 trivialUCode instr x
3057 = getRegister x `thenNat` \ register ->
3059 code__2 dst = let code = registerCode register dst
3060 src = registerName register dst
3062 if isFixed register && dst /= src
3063 then toOL [MOV L (OpReg src) (OpReg dst),
3065 else unitOL (instr (OpReg src))
3067 returnNat (Any IntRep code__2)
3070 trivialFCode pk instr x y
3071 = getRegister x `thenNat` \ register1 ->
3072 getRegister y `thenNat` \ register2 ->
3073 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
3074 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
3076 code1 = registerCode register1 tmp1
3077 src1 = registerName register1 tmp1
3079 code2 = registerCode register2 tmp2
3080 src2 = registerName register2 tmp2
3083 -- treat the common case specially: both operands in
3085 | isAny register1 && isAny register2
3088 instr (primRepToSize pk) src1 src2 dst
3090 -- be paranoid (and inefficient)
3092 = code1 `snocOL` GMOV src1 tmp1 `appOL`
3094 instr (primRepToSize pk) tmp1 src2 dst
3096 returnNat (Any pk code__2)
3100 trivialUFCode pk instr x
3101 = getRegister x `thenNat` \ register ->
3102 getNewRegNCG pk `thenNat` \ tmp ->
3104 code = registerCode register tmp
3105 src = registerName register tmp
3106 code__2 dst = code `snocOL` instr src dst
3108 returnNat (Any pk code__2)
3110 #endif {- i386_TARGET_ARCH -}
3111 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3112 #if sparc_TARGET_ARCH
3114 trivialCode instr x (StInt y)
3116 = getRegister x `thenNat` \ register ->
3117 getNewRegNCG IntRep `thenNat` \ tmp ->
3119 code = registerCode register tmp
3120 src1 = registerName register tmp
3121 src2 = ImmInt (fromInteger y)
3122 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
3124 returnNat (Any IntRep code__2)
3126 trivialCode instr x y
3127 = getRegister x `thenNat` \ register1 ->
3128 getRegister y `thenNat` \ register2 ->
3129 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3130 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3132 code1 = registerCode register1 tmp1
3133 src1 = registerName register1 tmp1
3134 code2 = registerCode register2 tmp2
3135 src2 = registerName register2 tmp2
3136 code__2 dst = code1 `appOL` code2 `snocOL`
3137 instr src1 (RIReg src2) dst
3139 returnNat (Any IntRep code__2)
3142 trivialFCode pk instr x y
3143 = getRegister x `thenNat` \ register1 ->
3144 getRegister y `thenNat` \ register2 ->
3145 getNewRegNCG (registerRep register1)
3147 getNewRegNCG (registerRep register2)
3149 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3151 promote x = FxTOy F DF x tmp
3153 pk1 = registerRep register1
3154 code1 = registerCode register1 tmp1
3155 src1 = registerName register1 tmp1
3157 pk2 = registerRep register2
3158 code2 = registerCode register2 tmp2
3159 src2 = registerName register2 tmp2
3163 code1 `appOL` code2 `snocOL`
3164 instr (primRepToSize pk) src1 src2 dst
3165 else if pk1 == FloatRep then
3166 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
3167 instr DF tmp src2 dst
3169 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
3170 instr DF src1 tmp dst
3172 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3175 trivialUCode instr x
3176 = getRegister x `thenNat` \ register ->
3177 getNewRegNCG IntRep `thenNat` \ tmp ->
3179 code = registerCode register tmp
3180 src = registerName register tmp
3181 code__2 dst = code `snocOL` instr (RIReg src) dst
3183 returnNat (Any IntRep code__2)
3186 trivialUFCode pk instr x
3187 = getRegister x `thenNat` \ register ->
3188 getNewRegNCG pk `thenNat` \ tmp ->
3190 code = registerCode register tmp
3191 src = registerName register tmp
3192 code__2 dst = code `snocOL` instr src dst
3194 returnNat (Any pk code__2)
3196 #endif {- sparc_TARGET_ARCH -}
3199 %************************************************************************
3201 \subsubsection{Coercing to/from integer/floating-point...}
3203 %************************************************************************
3205 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3206 to be generated. Here we just change the type on the Register passed
3207 on up. The code is machine-independent.
3209 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3210 conversions. We have to store temporaries in memory to move
3211 between the integer and the floating point register sets.
3214 coerceIntCode :: PrimRep -> StixTree -> NatM Register
3215 coerceFltCode :: StixTree -> NatM Register
3217 coerceInt2FP :: PrimRep -> StixTree -> NatM Register
3218 coerceFP2Int :: StixTree -> NatM Register
3221 = getRegister x `thenNat` \ register ->
3224 Fixed _ reg code -> Fixed pk reg code
3225 Any _ code -> Any pk code
3230 = getRegister x `thenNat` \ register ->
3233 Fixed _ reg code -> Fixed DoubleRep reg code
3234 Any _ code -> Any DoubleRep code
3239 #if alpha_TARGET_ARCH
3242 = getRegister x `thenNat` \ register ->
3243 getNewRegNCG IntRep `thenNat` \ reg ->
3245 code = registerCode register reg
3246 src = registerName register reg
3248 code__2 dst = code . mkSeqInstrs [
3250 LD TF dst (spRel 0),
3253 returnNat (Any DoubleRep code__2)
3257 = getRegister x `thenNat` \ register ->
3258 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3260 code = registerCode register tmp
3261 src = registerName register tmp
3263 code__2 dst = code . mkSeqInstrs [
3265 ST TF tmp (spRel 0),
3268 returnNat (Any IntRep code__2)
3270 #endif {- alpha_TARGET_ARCH -}
3271 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3272 #if i386_TARGET_ARCH
3275 = getRegister x `thenNat` \ register ->
3276 getNewRegNCG IntRep `thenNat` \ reg ->
3278 code = registerCode register reg
3279 src = registerName register reg
3280 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3281 code__2 dst = code `snocOL` opc src dst
3283 returnNat (Any pk code__2)
3287 = getRegister x `thenNat` \ register ->
3288 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3290 code = registerCode register tmp
3291 src = registerName register tmp
3292 pk = registerRep register
3294 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3295 code__2 dst = code `snocOL` opc src dst
3297 returnNat (Any IntRep code__2)
3299 #endif {- i386_TARGET_ARCH -}
3300 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3301 #if sparc_TARGET_ARCH
3304 = getRegister x `thenNat` \ register ->
3305 getNewRegNCG IntRep `thenNat` \ reg ->
3307 code = registerCode register reg
3308 src = registerName register reg
3310 code__2 dst = code `appOL` toOL [
3311 ST W src (spRel (-2)),
3312 LD W (spRel (-2)) dst,
3313 FxTOy W (primRepToSize pk) dst dst]
3315 returnNat (Any pk code__2)
3319 = getRegister x `thenNat` \ register ->
3320 getNewRegNCG IntRep `thenNat` \ reg ->
3321 getNewRegNCG FloatRep `thenNat` \ tmp ->
3323 code = registerCode register reg
3324 src = registerName register reg
3325 pk = registerRep register
3327 code__2 dst = code `appOL` toOL [
3328 FxTOy (primRepToSize pk) W src tmp,
3329 ST W tmp (spRel (-2)),
3330 LD W (spRel (-2)) dst]
3332 returnNat (Any IntRep code__2)
3334 #endif {- sparc_TARGET_ARCH -}
3337 %************************************************************************
3339 \subsubsection{Coercing integer to @Char@...}
3341 %************************************************************************
3343 Integer to character conversion.
3346 chrCode :: StixTree -> NatM Register
3348 #if alpha_TARGET_ARCH
3350 -- TODO: This is probably wrong, but I don't know Alpha assembler.
3351 -- It should coerce a 64-bit value to a 32-bit value.
3354 = getRegister x `thenNat` \ register ->
3355 getNewRegNCG IntRep `thenNat` \ reg ->
3357 code = registerCode register reg
3358 src = registerName register reg
3359 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3361 returnNat (Any IntRep code__2)
3363 #endif {- alpha_TARGET_ARCH -}
3364 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3365 #if i386_TARGET_ARCH
3368 = getRegister x `thenNat` \ register ->
3371 Fixed _ reg code -> Fixed IntRep reg code
3372 Any _ code -> Any IntRep code
3375 #endif {- i386_TARGET_ARCH -}
3376 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3377 #if sparc_TARGET_ARCH
3380 = getRegister x `thenNat` \ register ->
3383 Fixed _ reg code -> Fixed IntRep reg code
3384 Any _ code -> Any IntRep code
3387 #endif {- sparc_TARGET_ARCH -}