2 % (c) The AQUA Project, Glasgow University, 1996-1998
4 \section[MachCode]{Generating machine code}
6 This is a big module, but, if you pay attention to
7 (a) the sectioning, (b) the type signatures, and
8 (c) the \tr{#if blah_TARGET_ARCH} things, the
9 structure should not be too overwhelming.
12 module MachCode ( stmt2Instrs, InstrBlock ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
19 import OrdList ( OrdList, nilOL, isNilOL, unitOL, appOL, toOL,
20 snocOL, consOL, concatOL )
21 import AbsCUtils ( magicIdPrimRep )
22 import CallConv ( CallConv )
23 import CLabel ( isAsmTemp, CLabel, pprCLabel_asm, labelDynamic )
24 import Maybes ( maybeToBool, expectJust )
25 import PrimRep ( isFloatingRep, PrimRep(..) )
26 import PrimOp ( PrimOp(..) )
27 import CallConv ( cCallConv )
28 import Stix ( getNatLabelNCG, StixTree(..),
29 StixReg(..), CodeSegment(..),
30 pprStixTree, ppStixReg,
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 stmt2Instrs :: StixTree {- a stix statement -} -> NatM InstrBlock
60 stmt2Instrs stmt = case stmt of
61 StComment s -> returnNat (unitOL (COMMENT s))
62 StSegment seg -> returnNat (unitOL (SEGMENT seg))
64 StFunBegin lab -> returnNat (unitOL (IF_ARCH_alpha(FUNBEGIN lab,
66 StFunEnd lab -> IF_ARCH_alpha(returnNat (unitOL (FUNEND lab)),
69 StLabel lab -> returnNat (unitOL (LABEL lab))
71 StJump arg -> genJump (derefDLL arg)
72 StCondJump lab arg -> genCondJump lab (derefDLL arg)
74 -- A call returning void, ie one done for its side-effects
75 StCall fn cconv VoidRep args -> genCCall fn
76 cconv VoidRep (map derefDLL args)
79 | isFloatingRep pk -> assignFltCode pk (derefDLL dst) (derefDLL src)
80 | otherwise -> assignIntCode pk (derefDLL dst) (derefDLL src)
83 -- When falling through on the Alpha, we still have to load pv
84 -- with the address of the next routine, so that it can load gp.
85 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
89 -> mapAndUnzipNat getData args `thenNat` \ (codes, imms) ->
90 returnNat (DATA (primRepToSize kind) imms
91 `consOL` concatOL codes)
93 getData :: StixTree -> NatM (InstrBlock, Imm)
95 getData (StInt i) = returnNat (nilOL, ImmInteger i)
96 getData (StDouble d) = returnNat (nilOL, ImmDouble d)
97 getData (StFloat d) = returnNat (nilOL, ImmFloat d)
98 getData (StCLbl l) = returnNat (nilOL, ImmCLbl l)
99 getData (StString s) =
100 getNatLabelNCG `thenNat` \ lbl ->
101 returnNat (toOL [LABEL lbl,
102 ASCII True (_UNPK_ s)],
104 -- the linker can handle simple arithmetic...
105 getData (StIndex rep (StCLbl lbl) (StInt off)) =
107 ImmIndex lbl (fromInteger (off * sizeOf rep)))
109 -- Walk a Stix tree, and insert dereferences to CLabels which are marked
110 -- as labelDynamic. stmt2Instrs calls derefDLL selectively, because
111 -- not all such CLabel occurrences need this dereferencing -- SRTs don't
113 derefDLL :: StixTree -> StixTree
115 | opt_Static -- short out the entire deal if not doing DLLs
122 StCLbl lbl -> if labelDynamic lbl
123 then StInd PtrRep (StCLbl lbl)
125 -- all the rest are boring
126 StIndex pk base offset -> StIndex pk (qq base) (qq offset)
127 StPrim pk args -> StPrim pk (map qq args)
128 StInd pk addr -> StInd pk (qq addr)
129 StCall who cc pk args -> StCall who cc pk (map qq args)
136 _ -> pprPanic "derefDLL: unhandled case"
140 %************************************************************************
142 \subsection{General things for putting together code sequences}
144 %************************************************************************
147 mangleIndexTree :: StixTree -> StixTree
149 mangleIndexTree (StIndex pk base (StInt i))
150 = StPrim IntAddOp [base, off]
152 off = StInt (i * sizeOf pk)
154 mangleIndexTree (StIndex pk base off)
158 in ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
159 if s == 0 then off else StPrim SllOp [off, StInt s]
162 shift DoubleRep = 3::Integer
163 shift CharRep = 0::Integer
164 shift _ = IF_ARCH_alpha(3,2)
168 maybeImm :: StixTree -> Maybe Imm
172 maybeImm (StIndex rep (StCLbl l) (StInt off))
173 = Just (ImmIndex l (fromInteger (off * sizeOf rep)))
175 | i >= toInteger minInt && i <= toInteger maxInt
176 = Just (ImmInt (fromInteger i))
178 = Just (ImmInteger i)
183 %************************************************************************
185 \subsection{The @Register@ type}
187 %************************************************************************
189 @Register@s passed up the tree. If the stix code forces the register
190 to live in a pre-decided machine register, it comes out as @Fixed@;
191 otherwise, it comes out as @Any@, and the parent can decide which
192 register to put it in.
196 = Fixed PrimRep Reg InstrBlock
197 | Any PrimRep (Reg -> InstrBlock)
199 registerCode :: Register -> Reg -> InstrBlock
200 registerCode (Fixed _ _ code) reg = code
201 registerCode (Any _ code) reg = code reg
203 registerCodeF (Fixed _ _ code) = code
204 registerCodeF (Any _ _) = pprPanic "registerCodeF" empty
206 registerCodeA (Any _ code) = code
207 registerCodeA (Fixed _ _ _) = pprPanic "registerCodeA" empty
209 registerName :: Register -> Reg -> Reg
210 registerName (Fixed _ reg _) _ = reg
211 registerName (Any _ _) reg = reg
213 registerNameF (Fixed _ reg _) = reg
214 registerNameF (Any _ _) = pprPanic "registerNameF" empty
216 registerRep :: Register -> PrimRep
217 registerRep (Fixed pk _ _) = pk
218 registerRep (Any pk _) = pk
220 {-# INLINE registerCode #-}
221 {-# INLINE registerCodeF #-}
222 {-# INLINE registerName #-}
223 {-# INLINE registerNameF #-}
224 {-# INLINE registerRep #-}
225 {-# INLINE isFixed #-}
228 isFixed, isAny :: Register -> Bool
229 isFixed (Fixed _ _ _) = True
230 isFixed (Any _ _) = False
232 isAny = not . isFixed
235 Generate code to get a subtree into a @Register@:
237 getRegister :: StixTree -> NatM Register
239 getRegister (StReg (StixMagicId stgreg))
240 = case (magicIdRegMaybe stgreg) of
241 Just reg -> returnNat (Fixed (magicIdPrimRep stgreg) reg nilOL)
244 getRegister (StReg (StixTemp u pk))
245 = returnNat (Fixed pk (mkVReg u pk) nilOL)
247 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
249 getRegister (StCall fn cconv kind args)
250 = genCCall fn cconv kind args `thenNat` \ call ->
251 returnNat (Fixed kind reg call)
253 reg = if isFloatingRep kind
254 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
255 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
257 getRegister (StString s)
258 = getNatLabelNCG `thenNat` \ lbl ->
260 imm_lbl = ImmCLbl lbl
265 ASCII True (_UNPK_ s),
267 #if alpha_TARGET_ARCH
268 LDA dst (AddrImm imm_lbl)
271 MOV L (OpImm imm_lbl) (OpReg dst)
273 #if sparc_TARGET_ARCH
274 SETHI (HI imm_lbl) dst,
275 OR False dst (RIImm (LO imm_lbl)) dst
279 returnNat (Any PtrRep code)
283 -- end of machine-"independent" bit; here we go on the rest...
285 #if alpha_TARGET_ARCH
287 getRegister (StDouble d)
288 = getNatLabelNCG `thenNat` \ lbl ->
289 getNewRegNCG PtrRep `thenNat` \ tmp ->
290 let code dst = mkSeqInstrs [
293 DATA TF [ImmLab (rational d)],
295 LDA tmp (AddrImm (ImmCLbl lbl)),
296 LD TF dst (AddrReg tmp)]
298 returnNat (Any DoubleRep code)
300 getRegister (StPrim primop [x]) -- unary PrimOps
302 IntNegOp -> trivialUCode (NEG Q False) x
304 NotOp -> trivialUCode NOT x
306 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
307 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
309 OrdOp -> coerceIntCode IntRep x
312 Float2IntOp -> coerceFP2Int x
313 Int2FloatOp -> coerceInt2FP pr x
314 Double2IntOp -> coerceFP2Int x
315 Int2DoubleOp -> coerceInt2FP pr x
317 Double2FloatOp -> coerceFltCode x
318 Float2DoubleOp -> coerceFltCode x
320 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
322 fn = case other_op of
323 FloatExpOp -> SLIT("exp")
324 FloatLogOp -> SLIT("log")
325 FloatSqrtOp -> SLIT("sqrt")
326 FloatSinOp -> SLIT("sin")
327 FloatCosOp -> SLIT("cos")
328 FloatTanOp -> SLIT("tan")
329 FloatAsinOp -> SLIT("asin")
330 FloatAcosOp -> SLIT("acos")
331 FloatAtanOp -> SLIT("atan")
332 FloatSinhOp -> SLIT("sinh")
333 FloatCoshOp -> SLIT("cosh")
334 FloatTanhOp -> SLIT("tanh")
335 DoubleExpOp -> SLIT("exp")
336 DoubleLogOp -> SLIT("log")
337 DoubleSqrtOp -> SLIT("sqrt")
338 DoubleSinOp -> SLIT("sin")
339 DoubleCosOp -> SLIT("cos")
340 DoubleTanOp -> SLIT("tan")
341 DoubleAsinOp -> SLIT("asin")
342 DoubleAcosOp -> SLIT("acos")
343 DoubleAtanOp -> SLIT("atan")
344 DoubleSinhOp -> SLIT("sinh")
345 DoubleCoshOp -> SLIT("cosh")
346 DoubleTanhOp -> SLIT("tanh")
348 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
350 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
352 CharGtOp -> trivialCode (CMP LTT) y x
353 CharGeOp -> trivialCode (CMP LE) y x
354 CharEqOp -> trivialCode (CMP EQQ) x y
355 CharNeOp -> int_NE_code x y
356 CharLtOp -> trivialCode (CMP LTT) x y
357 CharLeOp -> trivialCode (CMP LE) x y
359 IntGtOp -> trivialCode (CMP LTT) y x
360 IntGeOp -> trivialCode (CMP LE) y x
361 IntEqOp -> trivialCode (CMP EQQ) x y
362 IntNeOp -> int_NE_code x y
363 IntLtOp -> trivialCode (CMP LTT) x y
364 IntLeOp -> trivialCode (CMP LE) x y
366 WordGtOp -> trivialCode (CMP ULT) y x
367 WordGeOp -> trivialCode (CMP ULE) x y
368 WordEqOp -> trivialCode (CMP EQQ) x y
369 WordNeOp -> int_NE_code x y
370 WordLtOp -> trivialCode (CMP ULT) x y
371 WordLeOp -> trivialCode (CMP ULE) x y
373 AddrGtOp -> trivialCode (CMP ULT) y x
374 AddrGeOp -> trivialCode (CMP ULE) y x
375 AddrEqOp -> trivialCode (CMP EQQ) x y
376 AddrNeOp -> int_NE_code x y
377 AddrLtOp -> trivialCode (CMP ULT) x y
378 AddrLeOp -> trivialCode (CMP ULE) x y
380 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
381 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
382 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
383 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
384 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
385 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
387 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
388 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
389 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
390 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
391 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
392 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
394 IntAddOp -> trivialCode (ADD Q False) x y
395 IntSubOp -> trivialCode (SUB Q False) x y
396 IntMulOp -> trivialCode (MUL Q False) x y
397 IntQuotOp -> trivialCode (DIV Q False) x y
398 IntRemOp -> trivialCode (REM Q False) x y
400 WordQuotOp -> trivialCode (DIV Q True) x y
401 WordRemOp -> trivialCode (REM Q True) x y
403 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
404 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
405 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
406 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
408 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
409 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
410 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
411 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
413 AndOp -> trivialCode AND x y
414 OrOp -> trivialCode OR x y
415 XorOp -> trivialCode XOR x y
416 SllOp -> trivialCode SLL x y
417 SrlOp -> trivialCode SRL x y
419 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
420 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
421 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
423 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
424 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
426 {- ------------------------------------------------------------
427 Some bizarre special code for getting condition codes into
428 registers. Integer non-equality is a test for equality
429 followed by an XOR with 1. (Integer comparisons always set
430 the result register to 0 or 1.) Floating point comparisons of
431 any kind leave the result in a floating point register, so we
432 need to wrangle an integer register out of things.
434 int_NE_code :: StixTree -> StixTree -> NatM Register
437 = trivialCode (CMP EQQ) x y `thenNat` \ register ->
438 getNewRegNCG IntRep `thenNat` \ tmp ->
440 code = registerCode register tmp
441 src = registerName register tmp
442 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
444 returnNat (Any IntRep code__2)
446 {- ------------------------------------------------------------
447 Comments for int_NE_code also apply to cmpF_code
450 :: (Reg -> Reg -> Reg -> Instr)
452 -> StixTree -> StixTree
455 cmpF_code instr cond x y
456 = trivialFCode pr instr x y `thenNat` \ register ->
457 getNewRegNCG DoubleRep `thenNat` \ tmp ->
458 getNatLabelNCG `thenNat` \ lbl ->
460 code = registerCode register tmp
461 result = registerName register tmp
463 code__2 dst = code . mkSeqInstrs [
464 OR zeroh (RIImm (ImmInt 1)) dst,
465 BF cond result (ImmCLbl lbl),
466 OR zeroh (RIReg zeroh) dst,
469 returnNat (Any IntRep code__2)
471 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
472 ------------------------------------------------------------
474 getRegister (StInd pk mem)
475 = getAmode mem `thenNat` \ amode ->
477 code = amodeCode amode
478 src = amodeAddr amode
479 size = primRepToSize pk
480 code__2 dst = code . mkSeqInstr (LD size dst src)
482 returnNat (Any pk code__2)
484 getRegister (StInt i)
487 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
489 returnNat (Any IntRep code)
492 code dst = mkSeqInstr (LDI Q dst src)
494 returnNat (Any IntRep code)
496 src = ImmInt (fromInteger i)
501 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
503 returnNat (Any PtrRep code)
506 imm__2 = case imm of Just x -> x
508 #endif {- alpha_TARGET_ARCH -}
509 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
512 getRegister (StFloat f)
513 = getNatLabelNCG `thenNat` \ lbl ->
514 let code dst = toOL [
519 GLD F (ImmAddr (ImmCLbl lbl) 0) dst
522 returnNat (Any FloatRep code)
525 getRegister (StDouble d)
528 = let code dst = unitOL (GLDZ dst)
529 in returnNat (Any DoubleRep code)
532 = let code dst = unitOL (GLD1 dst)
533 in returnNat (Any DoubleRep code)
536 = getNatLabelNCG `thenNat` \ lbl ->
537 let code dst = toOL [
540 DATA DF [ImmDouble d],
542 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
545 returnNat (Any DoubleRep code)
547 -- Calculate the offset for (i+1) words above the _initial_
548 -- %esp value by first determining the current offset of it.
549 getRegister (StScratchWord i)
551 = getDeltaNat `thenNat` \ current_stack_offset ->
552 let j = i+1 - (current_stack_offset `div` 4)
554 = unitOL (LEA L (OpAddr (spRel (j+1))) (OpReg dst))
556 returnNat (Any PtrRep code)
558 getRegister (StPrim primop [x]) -- unary PrimOps
560 IntNegOp -> trivialUCode (NEGI L) x
561 NotOp -> trivialUCode (NOT L) x
563 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
564 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
566 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
567 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
569 FloatSinOp -> trivialUFCode FloatRep (GSIN F) x
570 DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
572 FloatCosOp -> trivialUFCode FloatRep (GCOS F) x
573 DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
575 FloatTanOp -> trivialUFCode FloatRep (GTAN F) x
576 DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
578 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
579 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
581 OrdOp -> coerceIntCode IntRep x
584 Float2IntOp -> coerceFP2Int x
585 Int2FloatOp -> coerceInt2FP FloatRep x
586 Double2IntOp -> coerceFP2Int x
587 Int2DoubleOp -> coerceInt2FP DoubleRep x
591 fixed_x = if is_float_op -- promote to double
592 then StPrim Float2DoubleOp [x]
595 getRegister (StCall fn cCallConv DoubleRep [x])
599 FloatExpOp -> (True, SLIT("exp"))
600 FloatLogOp -> (True, SLIT("log"))
602 FloatAsinOp -> (True, SLIT("asin"))
603 FloatAcosOp -> (True, SLIT("acos"))
604 FloatAtanOp -> (True, SLIT("atan"))
606 FloatSinhOp -> (True, SLIT("sinh"))
607 FloatCoshOp -> (True, SLIT("cosh"))
608 FloatTanhOp -> (True, SLIT("tanh"))
610 DoubleExpOp -> (False, SLIT("exp"))
611 DoubleLogOp -> (False, SLIT("log"))
613 DoubleAsinOp -> (False, SLIT("asin"))
614 DoubleAcosOp -> (False, SLIT("acos"))
615 DoubleAtanOp -> (False, SLIT("atan"))
617 DoubleSinhOp -> (False, SLIT("sinh"))
618 DoubleCoshOp -> (False, SLIT("cosh"))
619 DoubleTanhOp -> (False, SLIT("tanh"))
622 -> pprPanic "getRegister(x86,unary primop)"
623 (pprStixTree (StPrim primop [x]))
625 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
627 CharGtOp -> condIntReg GTT x y
628 CharGeOp -> condIntReg GE x y
629 CharEqOp -> condIntReg EQQ x y
630 CharNeOp -> condIntReg NE x y
631 CharLtOp -> condIntReg LTT x y
632 CharLeOp -> condIntReg LE x y
634 IntGtOp -> condIntReg GTT x y
635 IntGeOp -> condIntReg GE x y
636 IntEqOp -> condIntReg EQQ x y
637 IntNeOp -> condIntReg NE x y
638 IntLtOp -> condIntReg LTT x y
639 IntLeOp -> condIntReg LE x y
641 WordGtOp -> condIntReg GU x y
642 WordGeOp -> condIntReg GEU x y
643 WordEqOp -> condIntReg EQQ x y
644 WordNeOp -> condIntReg NE x y
645 WordLtOp -> condIntReg LU x y
646 WordLeOp -> condIntReg LEU x y
648 AddrGtOp -> condIntReg GU x y
649 AddrGeOp -> condIntReg GEU x y
650 AddrEqOp -> condIntReg EQQ x y
651 AddrNeOp -> condIntReg NE x y
652 AddrLtOp -> condIntReg LU x y
653 AddrLeOp -> condIntReg LEU x y
655 FloatGtOp -> condFltReg GTT x y
656 FloatGeOp -> condFltReg GE x y
657 FloatEqOp -> condFltReg EQQ x y
658 FloatNeOp -> condFltReg NE x y
659 FloatLtOp -> condFltReg LTT x y
660 FloatLeOp -> condFltReg LE x y
662 DoubleGtOp -> condFltReg GTT x y
663 DoubleGeOp -> condFltReg GE x y
664 DoubleEqOp -> condFltReg EQQ x y
665 DoubleNeOp -> condFltReg NE x y
666 DoubleLtOp -> condFltReg LTT x y
667 DoubleLeOp -> condFltReg LE x y
669 IntAddOp -> add_code L x y
670 IntSubOp -> sub_code L x y
671 IntQuotOp -> quot_code L x y True{-division-}
672 IntRemOp -> quot_code L x y False{-remainder-}
673 IntMulOp -> let op = IMUL L in trivialCode op (Just op) x y
675 FloatAddOp -> trivialFCode FloatRep GADD x y
676 FloatSubOp -> trivialFCode FloatRep GSUB x y
677 FloatMulOp -> trivialFCode FloatRep GMUL x y
678 FloatDivOp -> trivialFCode FloatRep GDIV x y
680 DoubleAddOp -> trivialFCode DoubleRep GADD x y
681 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
682 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
683 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
685 AndOp -> let op = AND L in trivialCode op (Just op) x y
686 OrOp -> let op = OR L in trivialCode op (Just op) x y
687 XorOp -> let op = XOR L in trivialCode op (Just op) x y
689 {- Shift ops on x86s have constraints on their source, it
690 either has to be Imm, CL or 1
691 => trivialCode's is not restrictive enough (sigh.)
694 SllOp -> shift_code (SHL L) x y {-False-}
695 SrlOp -> shift_code (SHR L) x y {-False-}
696 ISllOp -> shift_code (SHL L) x y {-False-}
697 ISraOp -> shift_code (SAR L) x y {-False-}
698 ISrlOp -> shift_code (SHR L) x y {-False-}
700 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
701 [promote x, promote y])
702 where promote x = StPrim Float2DoubleOp [x]
703 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
706 -> pprPanic "getRegister(x86,dyadic primop)"
707 (pprStixTree (StPrim primop [x, y]))
711 shift_code :: (Imm -> Operand -> Instr)
716 {- Case1: shift length as immediate -}
717 -- Code is the same as the first eq. for trivialCode -- sigh.
718 shift_code instr x y{-amount-}
720 = getRegister x `thenNat` \ regx ->
723 then registerCodeA regx dst `bind` \ code_x ->
725 instr imm__2 (OpReg dst)
726 else registerCodeF regx `bind` \ code_x ->
727 registerNameF regx `bind` \ r_x ->
729 MOV L (OpReg r_x) (OpReg dst) `snocOL`
730 instr imm__2 (OpReg dst)
732 returnNat (Any IntRep mkcode)
735 imm__2 = case imm of Just x -> x
737 {- Case2: shift length is complex (non-immediate) -}
738 -- Since ECX is always used as a spill temporary, we can't
739 -- use it here to do non-immediate shifts. No big deal --
740 -- they are only very rare, and we can use an equivalent
741 -- test-and-jump sequence which doesn't use ECX.
742 -- DO NOT REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
743 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
744 shift_code instr x y{-amount-}
745 = getRegister x `thenNat` \ register1 ->
746 getRegister y `thenNat` \ register2 ->
747 getNatLabelNCG `thenNat` \ lbl_test3 ->
748 getNatLabelNCG `thenNat` \ lbl_test2 ->
749 getNatLabelNCG `thenNat` \ lbl_test1 ->
750 getNatLabelNCG `thenNat` \ lbl_test0 ->
751 getNatLabelNCG `thenNat` \ lbl_after ->
752 getNewRegNCG IntRep `thenNat` \ tmp ->
754 = let src_val = registerName register1 dst
755 code_val = registerCode register1 dst
756 src_amt = registerName register2 tmp
757 code_amt = registerCode register2 tmp
762 MOV L (OpReg src_amt) r_tmp `appOL`
764 MOV L (OpReg src_val) r_dst `appOL`
766 COMMENT (_PK_ "begin shift sequence"),
767 MOV L (OpReg src_val) r_dst,
768 MOV L (OpReg src_amt) r_tmp,
770 BT L (ImmInt 4) r_tmp,
772 instr (ImmInt 16) r_dst,
775 BT L (ImmInt 3) r_tmp,
777 instr (ImmInt 8) r_dst,
780 BT L (ImmInt 2) r_tmp,
782 instr (ImmInt 4) r_dst,
785 BT L (ImmInt 1) r_tmp,
787 instr (ImmInt 2) r_dst,
790 BT L (ImmInt 0) r_tmp,
792 instr (ImmInt 1) r_dst,
795 COMMENT (_PK_ "end shift sequence")
798 returnNat (Any IntRep code__2)
801 add_code :: Size -> StixTree -> StixTree -> NatM Register
803 add_code sz x (StInt y)
804 = getRegister x `thenNat` \ register ->
805 getNewRegNCG IntRep `thenNat` \ tmp ->
807 code = registerCode register tmp
808 src1 = registerName register tmp
809 src2 = ImmInt (fromInteger y)
812 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
815 returnNat (Any IntRep code__2)
817 add_code sz x y = trivialCode (ADD sz) (Just (ADD sz)) x y
820 sub_code :: Size -> StixTree -> StixTree -> NatM Register
822 sub_code sz x (StInt y)
823 = getRegister x `thenNat` \ register ->
824 getNewRegNCG IntRep `thenNat` \ tmp ->
826 code = registerCode register tmp
827 src1 = registerName register tmp
828 src2 = ImmInt (-(fromInteger y))
831 LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
834 returnNat (Any IntRep code__2)
836 sub_code sz x y = trivialCode (SUB sz) Nothing x y
841 -> StixTree -> StixTree
842 -> Bool -- True => division, False => remainder operation
845 -- x must go into eax, edx must be a sign-extension of eax, and y
846 -- should go in some other register (or memory), so that we get
847 -- edx:eax / reg -> eax (remainder in edx). Currently we choose
848 -- to put y on the C stack, since that avoids tying up yet another
849 -- precious register.
851 quot_code sz x y is_division
852 = getRegister x `thenNat` \ register1 ->
853 getRegister y `thenNat` \ register2 ->
854 getNewRegNCG IntRep `thenNat` \ tmp ->
855 getDeltaNat `thenNat` \ delta ->
857 code1 = registerCode register1 tmp
858 src1 = registerName register1 tmp
859 code2 = registerCode register2 tmp
860 src2 = registerName register2 tmp
861 code__2 = code2 `snocOL` -- src2 := y
862 PUSH L (OpReg src2) `snocOL` -- -4(%esp) := y
863 DELTA (delta-4) `appOL`
864 code1 `snocOL` -- src1 := x
865 MOV L (OpReg src1) (OpReg eax) `snocOL` -- eax := x
867 IDIV sz (OpAddr (spRel 0)) `snocOL`
868 ADD L (OpImm (ImmInt 4)) (OpReg esp) `snocOL`
871 returnNat (Fixed IntRep (if is_division then eax else edx) code__2)
872 -----------------------
874 getRegister (StInd pk mem)
875 = getAmode mem `thenNat` \ amode ->
877 code = amodeCode amode
878 src = amodeAddr amode
879 size = primRepToSize pk
880 code__2 dst = code `snocOL`
881 if pk == DoubleRep || pk == FloatRep
882 then GLD size src dst
884 L -> MOV L (OpAddr src) (OpReg dst)
885 B -> MOVZxL B (OpAddr src) (OpReg dst)
887 returnNat (Any pk code__2)
889 getRegister (StInt i)
891 src = ImmInt (fromInteger i)
894 = unitOL (XOR L (OpReg dst) (OpReg dst))
896 = unitOL (MOV L (OpImm src) (OpReg dst))
898 returnNat (Any IntRep code)
902 = let code dst = unitOL (MOV L (OpImm imm__2) (OpReg dst))
904 returnNat (Any PtrRep code)
906 = pprPanic "getRegister(x86)" (pprStixTree leaf)
909 imm__2 = case imm of Just x -> x
911 #endif {- i386_TARGET_ARCH -}
912 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
913 #if sparc_TARGET_ARCH
915 getRegister (StFloat d)
916 = getNatLabelNCG `thenNat` \ lbl ->
917 getNewRegNCG PtrRep `thenNat` \ tmp ->
918 let code dst = toOL [
923 SETHI (HI (ImmCLbl lbl)) tmp,
924 LD F (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
926 returnNat (Any FloatRep code)
928 getRegister (StDouble d)
929 = getNatLabelNCG `thenNat` \ lbl ->
930 getNewRegNCG PtrRep `thenNat` \ tmp ->
931 let code dst = toOL [
934 DATA DF [ImmDouble d],
936 SETHI (HI (ImmCLbl lbl)) tmp,
937 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
939 returnNat (Any DoubleRep code)
941 -- The 6-word scratch area is immediately below the frame pointer.
942 -- Below that is the spill area.
943 getRegister (StScratchWord i)
946 code dst = unitOL (fpRelEA j dst)
948 returnNat (Any PtrRep code)
951 getRegister (StPrim primop [x]) -- unary PrimOps
953 IntNegOp -> trivialUCode (SUB False False g0) x
954 NotOp -> trivialUCode (XNOR False g0) x
956 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
957 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
959 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
960 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
962 OrdOp -> coerceIntCode IntRep x
965 Float2IntOp -> coerceFP2Int x
966 Int2FloatOp -> coerceInt2FP FloatRep x
967 Double2IntOp -> coerceFP2Int x
968 Int2DoubleOp -> coerceInt2FP DoubleRep x
972 fixed_x = if is_float_op -- promote to double
973 then StPrim Float2DoubleOp [x]
976 getRegister (StCall fn cCallConv DoubleRep [fixed_x])
980 FloatExpOp -> (True, SLIT("exp"))
981 FloatLogOp -> (True, SLIT("log"))
982 FloatSqrtOp -> (True, SLIT("sqrt"))
984 FloatSinOp -> (True, SLIT("sin"))
985 FloatCosOp -> (True, SLIT("cos"))
986 FloatTanOp -> (True, SLIT("tan"))
988 FloatAsinOp -> (True, SLIT("asin"))
989 FloatAcosOp -> (True, SLIT("acos"))
990 FloatAtanOp -> (True, SLIT("atan"))
992 FloatSinhOp -> (True, SLIT("sinh"))
993 FloatCoshOp -> (True, SLIT("cosh"))
994 FloatTanhOp -> (True, SLIT("tanh"))
996 DoubleExpOp -> (False, SLIT("exp"))
997 DoubleLogOp -> (False, SLIT("log"))
998 DoubleSqrtOp -> (False, SLIT("sqrt"))
1000 DoubleSinOp -> (False, SLIT("sin"))
1001 DoubleCosOp -> (False, SLIT("cos"))
1002 DoubleTanOp -> (False, SLIT("tan"))
1004 DoubleAsinOp -> (False, SLIT("asin"))
1005 DoubleAcosOp -> (False, SLIT("acos"))
1006 DoubleAtanOp -> (False, SLIT("atan"))
1008 DoubleSinhOp -> (False, SLIT("sinh"))
1009 DoubleCoshOp -> (False, SLIT("cosh"))
1010 DoubleTanhOp -> (False, SLIT("tanh"))
1013 -> pprPanic "getRegister(sparc,monadicprimop)"
1014 (pprStixTree (StPrim primop [x]))
1016 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1018 CharGtOp -> condIntReg GTT x y
1019 CharGeOp -> condIntReg GE x y
1020 CharEqOp -> condIntReg EQQ x y
1021 CharNeOp -> condIntReg NE x y
1022 CharLtOp -> condIntReg LTT x y
1023 CharLeOp -> condIntReg LE x y
1025 IntGtOp -> condIntReg GTT x y
1026 IntGeOp -> condIntReg GE x y
1027 IntEqOp -> condIntReg EQQ x y
1028 IntNeOp -> condIntReg NE x y
1029 IntLtOp -> condIntReg LTT x y
1030 IntLeOp -> condIntReg LE x y
1032 WordGtOp -> condIntReg GU x y
1033 WordGeOp -> condIntReg GEU x y
1034 WordEqOp -> condIntReg EQQ x y
1035 WordNeOp -> condIntReg NE x y
1036 WordLtOp -> condIntReg LU x y
1037 WordLeOp -> condIntReg LEU x y
1039 AddrGtOp -> condIntReg GU x y
1040 AddrGeOp -> condIntReg GEU x y
1041 AddrEqOp -> condIntReg EQQ x y
1042 AddrNeOp -> condIntReg NE x y
1043 AddrLtOp -> condIntReg LU x y
1044 AddrLeOp -> condIntReg LEU x y
1046 FloatGtOp -> condFltReg GTT x y
1047 FloatGeOp -> condFltReg GE x y
1048 FloatEqOp -> condFltReg EQQ x y
1049 FloatNeOp -> condFltReg NE x y
1050 FloatLtOp -> condFltReg LTT x y
1051 FloatLeOp -> condFltReg LE x y
1053 DoubleGtOp -> condFltReg GTT x y
1054 DoubleGeOp -> condFltReg GE x y
1055 DoubleEqOp -> condFltReg EQQ x y
1056 DoubleNeOp -> condFltReg NE x y
1057 DoubleLtOp -> condFltReg LTT x y
1058 DoubleLeOp -> condFltReg LE x y
1060 IntAddOp -> trivialCode (ADD False False) x y
1061 IntSubOp -> trivialCode (SUB False False) x y
1063 -- ToDo: teach about V8+ SPARC mul/div instructions
1064 IntMulOp -> imul_div SLIT(".umul") x y
1065 IntQuotOp -> imul_div SLIT(".div") x y
1066 IntRemOp -> imul_div SLIT(".rem") x y
1068 FloatAddOp -> trivialFCode FloatRep FADD x y
1069 FloatSubOp -> trivialFCode FloatRep FSUB x y
1070 FloatMulOp -> trivialFCode FloatRep FMUL x y
1071 FloatDivOp -> trivialFCode FloatRep FDIV x y
1073 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1074 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1075 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1076 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1078 AndOp -> trivialCode (AND False) x y
1079 OrOp -> trivialCode (OR False) x y
1080 XorOp -> trivialCode (XOR False) x y
1081 SllOp -> trivialCode SLL x y
1082 SrlOp -> trivialCode SRL x y
1084 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1085 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1086 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1088 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
1089 [promote x, promote y])
1090 where promote x = StPrim Float2DoubleOp [x]
1091 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
1095 -> pprPanic "getRegister(sparc,dyadic primop)"
1096 (pprStixTree (StPrim primop [x, y]))
1099 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1101 getRegister (StInd pk mem)
1102 = getAmode mem `thenNat` \ amode ->
1104 code = amodeCode amode
1105 src = amodeAddr amode
1106 size = primRepToSize pk
1107 code__2 dst = code `snocOL` LD size src dst
1109 returnNat (Any pk code__2)
1111 getRegister (StInt i)
1114 src = ImmInt (fromInteger i)
1115 code dst = unitOL (OR False g0 (RIImm src) dst)
1117 returnNat (Any IntRep code)
1123 SETHI (HI imm__2) dst,
1124 OR False dst (RIImm (LO imm__2)) dst]
1126 returnNat (Any PtrRep code)
1128 = pprPanic "getRegister(sparc)" (pprStixTree leaf)
1131 imm__2 = case imm of Just x -> x
1133 #endif {- sparc_TARGET_ARCH -}
1136 %************************************************************************
1138 \subsection{The @Amode@ type}
1140 %************************************************************************
1142 @Amode@s: Memory addressing modes passed up the tree.
1144 data Amode = Amode MachRegsAddr InstrBlock
1146 amodeAddr (Amode addr _) = addr
1147 amodeCode (Amode _ code) = code
1150 Now, given a tree (the argument to an StInd) that references memory,
1151 produce a suitable addressing mode.
1153 A Rule of the Game (tm) for Amodes: use of the addr bit must
1154 immediately follow use of the code part, since the code part puts
1155 values in registers which the addr then refers to. So you can't put
1156 anything in between, lest it overwrite some of those registers. If
1157 you need to do some other computation between the code part and use of
1158 the addr bit, first store the effective address from the amode in a
1159 temporary, then do the other computation, and then use the temporary:
1163 ... other computation ...
1167 getAmode :: StixTree -> NatM Amode
1169 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1171 #if alpha_TARGET_ARCH
1173 getAmode (StPrim IntSubOp [x, StInt i])
1174 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1175 getRegister x `thenNat` \ register ->
1177 code = registerCode register tmp
1178 reg = registerName register tmp
1179 off = ImmInt (-(fromInteger i))
1181 returnNat (Amode (AddrRegImm reg off) code)
1183 getAmode (StPrim IntAddOp [x, StInt i])
1184 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1185 getRegister x `thenNat` \ register ->
1187 code = registerCode register tmp
1188 reg = registerName register tmp
1189 off = ImmInt (fromInteger i)
1191 returnNat (Amode (AddrRegImm reg off) code)
1195 = returnNat (Amode (AddrImm imm__2) id)
1198 imm__2 = case imm of Just x -> x
1201 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1202 getRegister other `thenNat` \ register ->
1204 code = registerCode register tmp
1205 reg = registerName register tmp
1207 returnNat (Amode (AddrReg reg) code)
1209 #endif {- alpha_TARGET_ARCH -}
1210 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1211 #if i386_TARGET_ARCH
1213 getAmode (StPrim IntSubOp [x, StInt i])
1214 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1215 getRegister x `thenNat` \ register ->
1217 code = registerCode register tmp
1218 reg = registerName register tmp
1219 off = ImmInt (-(fromInteger i))
1221 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1223 getAmode (StPrim IntAddOp [x, StInt i])
1225 = returnNat (Amode (ImmAddr imm__2 (fromInteger i)) nilOL)
1228 imm__2 = case imm of Just x -> x
1230 getAmode (StPrim IntAddOp [x, StInt i])
1231 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1232 getRegister x `thenNat` \ register ->
1234 code = registerCode register tmp
1235 reg = registerName register tmp
1236 off = ImmInt (fromInteger i)
1238 returnNat (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1240 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1241 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1242 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1243 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1244 getRegister x `thenNat` \ register1 ->
1245 getRegister y `thenNat` \ register2 ->
1247 code1 = registerCode register1 tmp1
1248 reg1 = registerName register1 tmp1
1249 code2 = registerCode register2 tmp2
1250 reg2 = registerName register2 tmp2
1251 code__2 = code1 `appOL` code2
1252 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1254 returnNat (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1259 = returnNat (Amode (ImmAddr imm__2 0) nilOL)
1262 imm__2 = case imm of Just x -> x
1265 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1266 getRegister other `thenNat` \ register ->
1268 code = registerCode register tmp
1269 reg = registerName register tmp
1271 returnNat (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1273 #endif {- i386_TARGET_ARCH -}
1274 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1275 #if sparc_TARGET_ARCH
1277 getAmode (StPrim IntSubOp [x, StInt i])
1279 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1280 getRegister x `thenNat` \ register ->
1282 code = registerCode register tmp
1283 reg = registerName register tmp
1284 off = ImmInt (-(fromInteger i))
1286 returnNat (Amode (AddrRegImm reg off) code)
1289 getAmode (StPrim IntAddOp [x, StInt i])
1291 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1292 getRegister x `thenNat` \ register ->
1294 code = registerCode register tmp
1295 reg = registerName register tmp
1296 off = ImmInt (fromInteger i)
1298 returnNat (Amode (AddrRegImm reg off) code)
1300 getAmode (StPrim IntAddOp [x, y])
1301 = getNewRegNCG PtrRep `thenNat` \ tmp1 ->
1302 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1303 getRegister x `thenNat` \ register1 ->
1304 getRegister y `thenNat` \ register2 ->
1306 code1 = registerCode register1 tmp1
1307 reg1 = registerName register1 tmp1
1308 code2 = registerCode register2 tmp2
1309 reg2 = registerName register2 tmp2
1310 code__2 = code1 `appOL` code2
1312 returnNat (Amode (AddrRegReg reg1 reg2) code__2)
1316 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1318 code = unitOL (SETHI (HI imm__2) tmp)
1320 returnNat (Amode (AddrRegImm tmp (LO imm__2)) code)
1323 imm__2 = case imm of Just x -> x
1326 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1327 getRegister other `thenNat` \ register ->
1329 code = registerCode register tmp
1330 reg = registerName register tmp
1333 returnNat (Amode (AddrRegImm reg off) code)
1335 #endif {- sparc_TARGET_ARCH -}
1338 %************************************************************************
1340 \subsection{The @CondCode@ type}
1342 %************************************************************************
1344 Condition codes passed up the tree.
1346 data CondCode = CondCode Bool Cond InstrBlock
1348 condName (CondCode _ cond _) = cond
1349 condFloat (CondCode is_float _ _) = is_float
1350 condCode (CondCode _ _ code) = code
1353 Set up a condition code for a conditional branch.
1356 getCondCode :: StixTree -> NatM CondCode
1358 #if alpha_TARGET_ARCH
1359 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1360 #endif {- alpha_TARGET_ARCH -}
1361 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1363 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1364 -- yes, they really do seem to want exactly the same!
1366 getCondCode (StPrim primop [x, y])
1368 CharGtOp -> condIntCode GTT x y
1369 CharGeOp -> condIntCode GE x y
1370 CharEqOp -> condIntCode EQQ x y
1371 CharNeOp -> condIntCode NE x y
1372 CharLtOp -> condIntCode LTT x y
1373 CharLeOp -> condIntCode LE x y
1375 IntGtOp -> condIntCode GTT x y
1376 IntGeOp -> condIntCode GE x y
1377 IntEqOp -> condIntCode EQQ x y
1378 IntNeOp -> condIntCode NE x y
1379 IntLtOp -> condIntCode LTT x y
1380 IntLeOp -> condIntCode LE x y
1382 WordGtOp -> condIntCode GU x y
1383 WordGeOp -> condIntCode GEU x y
1384 WordEqOp -> condIntCode EQQ x y
1385 WordNeOp -> condIntCode NE x y
1386 WordLtOp -> condIntCode LU x y
1387 WordLeOp -> condIntCode LEU x y
1389 AddrGtOp -> condIntCode GU x y
1390 AddrGeOp -> condIntCode GEU x y
1391 AddrEqOp -> condIntCode EQQ x y
1392 AddrNeOp -> condIntCode NE x y
1393 AddrLtOp -> condIntCode LU x y
1394 AddrLeOp -> condIntCode LEU x y
1396 FloatGtOp -> condFltCode GTT x y
1397 FloatGeOp -> condFltCode GE x y
1398 FloatEqOp -> condFltCode EQQ x y
1399 FloatNeOp -> condFltCode NE x y
1400 FloatLtOp -> condFltCode LTT x y
1401 FloatLeOp -> condFltCode LE x y
1403 DoubleGtOp -> condFltCode GTT x y
1404 DoubleGeOp -> condFltCode GE x y
1405 DoubleEqOp -> condFltCode EQQ x y
1406 DoubleNeOp -> condFltCode NE x y
1407 DoubleLtOp -> condFltCode LTT x y
1408 DoubleLeOp -> condFltCode LE x y
1410 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1415 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1416 passed back up the tree.
1419 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> NatM CondCode
1421 #if alpha_TARGET_ARCH
1422 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1423 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1424 #endif {- alpha_TARGET_ARCH -}
1426 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1427 #if i386_TARGET_ARCH
1429 -- memory vs immediate
1430 condIntCode cond (StInd pk x) y
1432 = getAmode x `thenNat` \ amode ->
1434 code1 = amodeCode amode
1435 x__2 = amodeAddr amode
1436 sz = primRepToSize pk
1437 code__2 = code1 `snocOL`
1438 CMP sz (OpImm imm__2) (OpAddr x__2)
1440 returnNat (CondCode False cond code__2)
1443 imm__2 = case imm of Just x -> x
1446 condIntCode cond x (StInt 0)
1447 = getRegister x `thenNat` \ register1 ->
1448 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1450 code1 = registerCode register1 tmp1
1451 src1 = registerName register1 tmp1
1452 code__2 = code1 `snocOL`
1453 TEST L (OpReg src1) (OpReg src1)
1455 returnNat (CondCode False cond code__2)
1457 -- anything vs immediate
1458 condIntCode cond x y
1460 = getRegister x `thenNat` \ register1 ->
1461 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1463 code1 = registerCode register1 tmp1
1464 src1 = registerName register1 tmp1
1465 code__2 = code1 `snocOL`
1466 CMP L (OpImm imm__2) (OpReg src1)
1468 returnNat (CondCode False cond code__2)
1471 imm__2 = case imm of Just x -> x
1473 -- memory vs anything
1474 condIntCode cond (StInd pk x) y
1475 = getAmode x `thenNat` \ amode_x ->
1476 getRegister y `thenNat` \ reg_y ->
1477 getNewRegNCG IntRep `thenNat` \ tmp ->
1479 c_x = amodeCode amode_x
1480 am_x = amodeAddr amode_x
1481 c_y = registerCode reg_y tmp
1482 r_y = registerName reg_y tmp
1483 sz = primRepToSize pk
1485 -- optimisation: if there's no code for x, just an amode,
1486 -- use whatever reg y winds up in. Assumes that c_y doesn't
1487 -- clobber any regs in the amode am_x, which I'm not sure is
1488 -- justified. The otherwise clause makes the same assumption.
1489 code__2 | isNilOL c_x
1491 CMP sz (OpReg r_y) (OpAddr am_x)
1495 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1497 CMP sz (OpReg tmp) (OpAddr am_x)
1499 returnNat (CondCode False cond code__2)
1501 -- anything vs memory
1503 condIntCode cond y (StInd pk x)
1504 = getAmode x `thenNat` \ amode_x ->
1505 getRegister y `thenNat` \ reg_y ->
1506 getNewRegNCG IntRep `thenNat` \ tmp ->
1508 c_x = amodeCode amode_x
1509 am_x = amodeAddr amode_x
1510 c_y = registerCode reg_y tmp
1511 r_y = registerName reg_y tmp
1512 sz = primRepToSize pk
1513 -- same optimisation and nagging doubts as previous clause
1514 code__2 | isNilOL c_x
1516 CMP sz (OpAddr am_x) (OpReg r_y)
1520 MOV L (OpReg r_y) (OpReg tmp) `appOL`
1522 CMP sz (OpAddr am_x) (OpReg tmp)
1524 returnNat (CondCode False cond code__2)
1526 -- anything vs anything
1527 condIntCode cond x y
1528 = getRegister x `thenNat` \ register1 ->
1529 getRegister y `thenNat` \ register2 ->
1530 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1531 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1533 code1 = registerCode register1 tmp1
1534 src1 = registerName register1 tmp1
1535 code2 = registerCode register2 tmp2
1536 src2 = registerName register2 tmp2
1537 code__2 = code1 `snocOL`
1538 MOV L (OpReg src1) (OpReg tmp1) `appOL`
1540 CMP L (OpReg src2) (OpReg tmp1)
1542 returnNat (CondCode False cond code__2)
1545 condFltCode cond x y
1546 = getRegister x `thenNat` \ register1 ->
1547 getRegister y `thenNat` \ register2 ->
1548 getNewRegNCG (registerRep register1)
1550 getNewRegNCG (registerRep register2)
1552 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1554 pk1 = registerRep register1
1555 code1 = registerCode register1 tmp1
1556 src1 = registerName register1 tmp1
1558 pk2 = registerRep register2
1559 code2 = registerCode register2 tmp2
1560 src2 = registerName register2 tmp2
1562 code__2 | isAny register1
1563 = code1 `appOL` -- result in tmp1
1565 GCMP (primRepToSize pk1) tmp1 src2
1569 GMOV src1 tmp1 `appOL`
1571 GCMP (primRepToSize pk1) tmp1 src2
1573 {- On the 486, the flags set by FP compare are the unsigned ones!
1574 (This looks like a HACK to me. WDP 96/03)
1576 fix_FP_cond :: Cond -> Cond
1578 fix_FP_cond GE = GEU
1579 fix_FP_cond GTT = GU
1580 fix_FP_cond LTT = LU
1581 fix_FP_cond LE = LEU
1582 fix_FP_cond any = any
1584 returnNat (CondCode True (fix_FP_cond cond) code__2)
1588 #endif {- i386_TARGET_ARCH -}
1589 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1590 #if sparc_TARGET_ARCH
1592 condIntCode cond x (StInt y)
1594 = getRegister x `thenNat` \ register ->
1595 getNewRegNCG IntRep `thenNat` \ tmp ->
1597 code = registerCode register tmp
1598 src1 = registerName register tmp
1599 src2 = ImmInt (fromInteger y)
1600 code__2 = code `snocOL` SUB False True src1 (RIImm src2) g0
1602 returnNat (CondCode False cond code__2)
1604 condIntCode cond x y
1605 = getRegister x `thenNat` \ register1 ->
1606 getRegister y `thenNat` \ register2 ->
1607 getNewRegNCG IntRep `thenNat` \ tmp1 ->
1608 getNewRegNCG IntRep `thenNat` \ tmp2 ->
1610 code1 = registerCode register1 tmp1
1611 src1 = registerName register1 tmp1
1612 code2 = registerCode register2 tmp2
1613 src2 = registerName register2 tmp2
1614 code__2 = code1 `appOL` code2 `snocOL`
1615 SUB False True src1 (RIReg src2) g0
1617 returnNat (CondCode False cond code__2)
1620 condFltCode cond x y
1621 = getRegister x `thenNat` \ register1 ->
1622 getRegister y `thenNat` \ register2 ->
1623 getNewRegNCG (registerRep register1)
1625 getNewRegNCG (registerRep register2)
1627 getNewRegNCG DoubleRep `thenNat` \ tmp ->
1629 promote x = FxTOy F DF x tmp
1631 pk1 = registerRep register1
1632 code1 = registerCode register1 tmp1
1633 src1 = registerName register1 tmp1
1635 pk2 = registerRep register2
1636 code2 = registerCode register2 tmp2
1637 src2 = registerName register2 tmp2
1641 code1 `appOL` code2 `snocOL`
1642 FCMP True (primRepToSize pk1) src1 src2
1643 else if pk1 == FloatRep then
1644 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
1645 FCMP True DF tmp src2
1647 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
1648 FCMP True DF src1 tmp
1650 returnNat (CondCode True cond code__2)
1652 #endif {- sparc_TARGET_ARCH -}
1655 %************************************************************************
1657 \subsection{Generating assignments}
1659 %************************************************************************
1661 Assignments are really at the heart of the whole code generation
1662 business. Almost all top-level nodes of any real importance are
1663 assignments, which correspond to loads, stores, or register transfers.
1664 If we're really lucky, some of the register transfers will go away,
1665 because we can use the destination register to complete the code
1666 generation for the right hand side. This only fails when the right
1667 hand side is forced into a fixed register (e.g. the result of a call).
1670 assignIntCode, assignFltCode
1671 :: PrimRep -> StixTree -> StixTree -> NatM InstrBlock
1673 #if alpha_TARGET_ARCH
1675 assignIntCode pk (StInd _ dst) src
1676 = getNewRegNCG IntRep `thenNat` \ tmp ->
1677 getAmode dst `thenNat` \ amode ->
1678 getRegister src `thenNat` \ register ->
1680 code1 = amodeCode amode []
1681 dst__2 = amodeAddr amode
1682 code2 = registerCode register tmp []
1683 src__2 = registerName register tmp
1684 sz = primRepToSize pk
1685 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1689 assignIntCode pk dst src
1690 = getRegister dst `thenNat` \ register1 ->
1691 getRegister src `thenNat` \ register2 ->
1693 dst__2 = registerName register1 zeroh
1694 code = registerCode register2 dst__2
1695 src__2 = registerName register2 dst__2
1696 code__2 = if isFixed register2
1697 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1702 #endif {- alpha_TARGET_ARCH -}
1703 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1704 #if i386_TARGET_ARCH
1706 -- Destination of an assignment can only be reg or mem.
1707 -- This is the mem case.
1708 assignIntCode pk (StInd _ dst) src
1709 = getAmode dst `thenNat` \ amode ->
1710 get_op_RI src `thenNat` \ (codesrc, opsrc) ->
1711 getNewRegNCG PtrRep `thenNat` \ tmp ->
1713 -- In general, if the address computation for dst may require
1714 -- some insns preceding the addressing mode itself. So there's
1715 -- no guarantee that the code for dst and the code for src won't
1716 -- write the same register. This means either the address or
1717 -- the value needs to be copied into a temporary. We detect the
1718 -- common case where the amode has no code, and elide the copy.
1719 codea = amodeCode amode
1720 dst__a = amodeAddr amode
1722 code | isNilOL codea
1724 MOV (primRepToSize pk) opsrc (OpAddr dst__a)
1728 LEA L (OpAddr dst__a) (OpReg tmp) `appOL`
1730 MOV (primRepToSize pk) opsrc
1731 (OpAddr (AddrBaseIndex (Just tmp) Nothing (ImmInt 0)))
1737 -> NatM (InstrBlock,Operand) -- code, operator
1741 = returnNat (nilOL, OpImm imm_op)
1744 imm_op = case imm of Just x -> x
1747 = getRegister op `thenNat` \ register ->
1748 getNewRegNCG (registerRep register)
1750 let code = registerCode register tmp
1751 reg = registerName register tmp
1753 returnNat (code, OpReg reg)
1755 -- Assign; dst is a reg, rhs is mem
1756 assignIntCode pk dst (StInd pks src)
1757 = getNewRegNCG PtrRep `thenNat` \ tmp ->
1758 getAmode src `thenNat` \ amode ->
1759 getRegister dst `thenNat` \ reg_dst ->
1761 c_addr = amodeCode amode
1762 am_addr = amodeAddr amode
1764 c_dst = registerCode reg_dst tmp -- should be empty
1765 r_dst = registerName reg_dst tmp
1766 szs = primRepToSize pks
1767 opc = case szs of L -> MOV L ; B -> MOVZxL B
1769 code | isNilOL c_dst
1771 opc (OpAddr am_addr) (OpReg r_dst)
1773 = pprPanic "assignIntCode(x86): bad dst(2)" empty
1777 -- dst is a reg, but src could be anything
1778 assignIntCode pk dst src
1779 = getRegister dst `thenNat` \ registerd ->
1780 getRegister src `thenNat` \ registers ->
1781 getNewRegNCG IntRep `thenNat` \ tmp ->
1783 r_dst = registerName registerd tmp
1784 c_dst = registerCode registerd tmp -- should be empty
1785 r_src = registerName registers r_dst
1786 c_src = registerCode registers r_dst
1788 code | isNilOL c_dst
1790 MOV L (OpReg r_src) (OpReg r_dst)
1792 = pprPanic "assignIntCode(x86): bad dst(3)" empty
1796 #endif {- i386_TARGET_ARCH -}
1797 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1798 #if sparc_TARGET_ARCH
1800 assignIntCode pk (StInd _ dst) src
1801 = getNewRegNCG IntRep `thenNat` \ tmp ->
1802 getAmode dst `thenNat` \ amode ->
1803 getRegister src `thenNat` \ register ->
1805 code1 = amodeCode amode
1806 dst__2 = amodeAddr amode
1807 code2 = registerCode register tmp
1808 src__2 = registerName register tmp
1809 sz = primRepToSize pk
1810 code__2 = code1 `appOL` code2 `snocOL` ST sz src__2 dst__2
1814 assignIntCode pk dst src
1815 = getRegister dst `thenNat` \ register1 ->
1816 getRegister src `thenNat` \ register2 ->
1818 dst__2 = registerName register1 g0
1819 code = registerCode register2 dst__2
1820 src__2 = registerName register2 dst__2
1821 code__2 = if isFixed register2
1822 then code `snocOL` OR False g0 (RIReg src__2) dst__2
1827 #endif {- sparc_TARGET_ARCH -}
1830 % --------------------------------
1831 Floating-point assignments:
1832 % --------------------------------
1834 #if alpha_TARGET_ARCH
1836 assignFltCode pk (StInd _ dst) src
1837 = getNewRegNCG pk `thenNat` \ tmp ->
1838 getAmode dst `thenNat` \ amode ->
1839 getRegister src `thenNat` \ register ->
1841 code1 = amodeCode amode []
1842 dst__2 = amodeAddr amode
1843 code2 = registerCode register tmp []
1844 src__2 = registerName register tmp
1845 sz = primRepToSize pk
1846 code__2 = asmSeqThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1850 assignFltCode pk dst src
1851 = getRegister dst `thenNat` \ register1 ->
1852 getRegister src `thenNat` \ register2 ->
1854 dst__2 = registerName register1 zeroh
1855 code = registerCode register2 dst__2
1856 src__2 = registerName register2 dst__2
1857 code__2 = if isFixed register2
1858 then code . mkSeqInstr (FMOV src__2 dst__2)
1863 #endif {- alpha_TARGET_ARCH -}
1864 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1865 #if i386_TARGET_ARCH
1868 assignFltCode pk (StInd pk_dst addr) src
1870 = pprPanic "assignFltCode(x86): src/ind sz mismatch" empty
1872 = getRegister src `thenNat` \ reg_src ->
1873 getRegister addr `thenNat` \ reg_addr ->
1874 getNewRegNCG pk `thenNat` \ tmp_src ->
1875 getNewRegNCG PtrRep `thenNat` \ tmp_addr ->
1876 let r_src = registerName reg_src tmp_src
1877 c_src = registerCode reg_src tmp_src
1878 r_addr = registerName reg_addr tmp_addr
1879 c_addr = registerCode reg_addr tmp_addr
1880 sz = primRepToSize pk
1882 code = c_src `appOL`
1883 -- no need to preserve r_src across the addr computation,
1884 -- since r_src must be a float reg
1885 -- whilst r_addr is an int reg
1888 (AddrBaseIndex (Just r_addr) Nothing (ImmInt 0))
1892 -- dst must be a (FP) register
1893 assignFltCode pk dst src
1894 = getRegister dst `thenNat` \ reg_dst ->
1895 getRegister src `thenNat` \ reg_src ->
1896 getNewRegNCG pk `thenNat` \ tmp ->
1898 r_dst = registerName reg_dst tmp
1899 c_dst = registerCode reg_dst tmp -- should be empty
1901 r_src = registerName reg_src r_dst
1902 c_src = registerCode reg_src r_dst
1904 code | isNilOL c_dst
1905 = if isFixed reg_src
1906 then c_src `snocOL` GMOV r_src r_dst
1909 = pprPanic "assignFltCode(x86): lhs is not mem or reg"
1915 #endif {- i386_TARGET_ARCH -}
1916 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1917 #if sparc_TARGET_ARCH
1919 assignFltCode pk (StInd _ dst) src
1920 = getNewRegNCG pk `thenNat` \ tmp1 ->
1921 getAmode dst `thenNat` \ amode ->
1922 getRegister src `thenNat` \ register ->
1924 sz = primRepToSize pk
1925 dst__2 = amodeAddr amode
1927 code1 = amodeCode amode
1928 code2 = registerCode register tmp1
1930 src__2 = registerName register tmp1
1931 pk__2 = registerRep register
1932 sz__2 = primRepToSize pk__2
1934 code__2 = code1 `appOL` code2 `appOL`
1936 then unitOL (ST sz src__2 dst__2)
1937 else toOL [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1941 assignFltCode pk dst src
1942 = getRegister dst `thenNat` \ register1 ->
1943 getRegister src `thenNat` \ register2 ->
1945 pk__2 = registerRep register2
1946 sz__2 = primRepToSize pk__2
1948 getNewRegNCG pk__2 `thenNat` \ tmp ->
1950 sz = primRepToSize pk
1951 dst__2 = registerName register1 g0 -- must be Fixed
1954 reg__2 = if pk /= pk__2 then tmp else dst__2
1956 code = registerCode register2 reg__2
1958 src__2 = registerName register2 reg__2
1962 code `snocOL` FxTOy sz__2 sz src__2 dst__2
1963 else if isFixed register2 then
1964 code `snocOL` FMOV sz src__2 dst__2
1970 #endif {- sparc_TARGET_ARCH -}
1973 %************************************************************************
1975 \subsection{Generating an unconditional branch}
1977 %************************************************************************
1979 We accept two types of targets: an immediate CLabel or a tree that
1980 gets evaluated into a register. Any CLabels which are AsmTemporaries
1981 are assumed to be in the local block of code, close enough for a
1982 branch instruction. Other CLabels are assumed to be far away.
1984 (If applicable) Do not fill the delay slots here; you will confuse the
1988 genJump :: StixTree{-the branch target-} -> NatM InstrBlock
1990 #if alpha_TARGET_ARCH
1992 genJump (StCLbl lbl)
1993 | isAsmTemp lbl = returnInstr (BR target)
1994 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1996 target = ImmCLbl lbl
1999 = getRegister tree `thenNat` \ register ->
2000 getNewRegNCG PtrRep `thenNat` \ tmp ->
2002 dst = registerName register pv
2003 code = registerCode register pv
2004 target = registerName register pv
2006 if isFixed register then
2007 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
2009 returnNat (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
2011 #endif {- alpha_TARGET_ARCH -}
2012 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2013 #if i386_TARGET_ARCH
2015 genJump (StInd pk mem)
2016 = getAmode mem `thenNat` \ amode ->
2018 code = amodeCode amode
2019 target = amodeAddr amode
2021 returnNat (code `snocOL` JMP (OpAddr target))
2025 = returnNat (unitOL (JMP (OpImm target)))
2028 = getRegister tree `thenNat` \ register ->
2029 getNewRegNCG PtrRep `thenNat` \ tmp ->
2031 code = registerCode register tmp
2032 target = registerName register tmp
2034 returnNat (code `snocOL` JMP (OpReg target))
2037 target = case imm of Just x -> x
2039 #endif {- i386_TARGET_ARCH -}
2040 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2041 #if sparc_TARGET_ARCH
2043 genJump (StCLbl lbl)
2044 | isAsmTemp lbl = returnNat (toOL [BI ALWAYS False target, NOP])
2045 | otherwise = returnNat (toOL [CALL target 0 True, NOP])
2047 target = ImmCLbl lbl
2050 = getRegister tree `thenNat` \ register ->
2051 getNewRegNCG PtrRep `thenNat` \ tmp ->
2053 code = registerCode register tmp
2054 target = registerName register tmp
2056 returnNat (code `snocOL` JMP (AddrRegReg target g0) `snocOL` NOP)
2058 #endif {- sparc_TARGET_ARCH -}
2061 %************************************************************************
2063 \subsection{Conditional jumps}
2065 %************************************************************************
2067 Conditional jumps are always to local labels, so we can use branch
2068 instructions. We peek at the arguments to decide what kind of
2071 ALPHA: For comparisons with 0, we're laughing, because we can just do
2072 the desired conditional branch.
2074 I386: First, we have to ensure that the condition
2075 codes are set according to the supplied comparison operation.
2077 SPARC: First, we have to ensure that the condition codes are set
2078 according to the supplied comparison operation. We generate slightly
2079 different code for floating point comparisons, because a floating
2080 point operation cannot directly precede a @BF@. We assume the worst
2081 and fill that slot with a @NOP@.
2083 SPARC: Do not fill the delay slots here; you will confuse the register
2088 :: CLabel -- the branch target
2089 -> StixTree -- the condition on which to branch
2092 #if alpha_TARGET_ARCH
2094 genCondJump lbl (StPrim op [x, StInt 0])
2095 = getRegister x `thenNat` \ register ->
2096 getNewRegNCG (registerRep register)
2099 code = registerCode register tmp
2100 value = registerName register tmp
2101 pk = registerRep register
2102 target = ImmCLbl lbl
2104 returnSeq code [BI (cmpOp op) value target]
2106 cmpOp CharGtOp = GTT
2108 cmpOp CharEqOp = EQQ
2110 cmpOp CharLtOp = LTT
2119 cmpOp WordGeOp = ALWAYS
2120 cmpOp WordEqOp = EQQ
2122 cmpOp WordLtOp = NEVER
2123 cmpOp WordLeOp = EQQ
2125 cmpOp AddrGeOp = ALWAYS
2126 cmpOp AddrEqOp = EQQ
2128 cmpOp AddrLtOp = NEVER
2129 cmpOp AddrLeOp = EQQ
2131 genCondJump lbl (StPrim op [x, StDouble 0.0])
2132 = getRegister x `thenNat` \ register ->
2133 getNewRegNCG (registerRep register)
2136 code = registerCode register tmp
2137 value = registerName register tmp
2138 pk = registerRep register
2139 target = ImmCLbl lbl
2141 returnNat (code . mkSeqInstr (BF (cmpOp op) value target))
2143 cmpOp FloatGtOp = GTT
2144 cmpOp FloatGeOp = GE
2145 cmpOp FloatEqOp = EQQ
2146 cmpOp FloatNeOp = NE
2147 cmpOp FloatLtOp = LTT
2148 cmpOp FloatLeOp = LE
2149 cmpOp DoubleGtOp = GTT
2150 cmpOp DoubleGeOp = GE
2151 cmpOp DoubleEqOp = EQQ
2152 cmpOp DoubleNeOp = NE
2153 cmpOp DoubleLtOp = LTT
2154 cmpOp DoubleLeOp = LE
2156 genCondJump lbl (StPrim op [x, y])
2158 = trivialFCode pr instr x y `thenNat` \ register ->
2159 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2161 code = registerCode register tmp
2162 result = registerName register tmp
2163 target = ImmCLbl lbl
2165 returnNat (code . mkSeqInstr (BF cond result target))
2167 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2169 fltCmpOp op = case op of
2183 (instr, cond) = case op of
2184 FloatGtOp -> (FCMP TF LE, EQQ)
2185 FloatGeOp -> (FCMP TF LTT, EQQ)
2186 FloatEqOp -> (FCMP TF EQQ, NE)
2187 FloatNeOp -> (FCMP TF EQQ, EQQ)
2188 FloatLtOp -> (FCMP TF LTT, NE)
2189 FloatLeOp -> (FCMP TF LE, NE)
2190 DoubleGtOp -> (FCMP TF LE, EQQ)
2191 DoubleGeOp -> (FCMP TF LTT, EQQ)
2192 DoubleEqOp -> (FCMP TF EQQ, NE)
2193 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2194 DoubleLtOp -> (FCMP TF LTT, NE)
2195 DoubleLeOp -> (FCMP TF LE, NE)
2197 genCondJump lbl (StPrim op [x, y])
2198 = trivialCode instr x y `thenNat` \ register ->
2199 getNewRegNCG IntRep `thenNat` \ tmp ->
2201 code = registerCode register tmp
2202 result = registerName register tmp
2203 target = ImmCLbl lbl
2205 returnNat (code . mkSeqInstr (BI cond result target))
2207 (instr, cond) = case op of
2208 CharGtOp -> (CMP LE, EQQ)
2209 CharGeOp -> (CMP LTT, EQQ)
2210 CharEqOp -> (CMP EQQ, NE)
2211 CharNeOp -> (CMP EQQ, EQQ)
2212 CharLtOp -> (CMP LTT, NE)
2213 CharLeOp -> (CMP LE, NE)
2214 IntGtOp -> (CMP LE, EQQ)
2215 IntGeOp -> (CMP LTT, EQQ)
2216 IntEqOp -> (CMP EQQ, NE)
2217 IntNeOp -> (CMP EQQ, EQQ)
2218 IntLtOp -> (CMP LTT, NE)
2219 IntLeOp -> (CMP LE, NE)
2220 WordGtOp -> (CMP ULE, EQQ)
2221 WordGeOp -> (CMP ULT, EQQ)
2222 WordEqOp -> (CMP EQQ, NE)
2223 WordNeOp -> (CMP EQQ, EQQ)
2224 WordLtOp -> (CMP ULT, NE)
2225 WordLeOp -> (CMP ULE, NE)
2226 AddrGtOp -> (CMP ULE, EQQ)
2227 AddrGeOp -> (CMP ULT, EQQ)
2228 AddrEqOp -> (CMP EQQ, NE)
2229 AddrNeOp -> (CMP EQQ, EQQ)
2230 AddrLtOp -> (CMP ULT, NE)
2231 AddrLeOp -> (CMP ULE, NE)
2233 #endif {- alpha_TARGET_ARCH -}
2234 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2235 #if i386_TARGET_ARCH
2237 genCondJump lbl bool
2238 = getCondCode bool `thenNat` \ condition ->
2240 code = condCode condition
2241 cond = condName condition
2242 target = ImmCLbl lbl
2244 returnNat (code `snocOL` JXX cond lbl)
2246 #endif {- i386_TARGET_ARCH -}
2247 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2248 #if sparc_TARGET_ARCH
2250 genCondJump lbl bool
2251 = getCondCode bool `thenNat` \ condition ->
2253 code = condCode condition
2254 cond = condName condition
2255 target = ImmCLbl lbl
2260 if condFloat condition
2261 then [NOP, BF cond False target, NOP]
2262 else [BI cond False target, NOP]
2266 #endif {- sparc_TARGET_ARCH -}
2269 %************************************************************************
2271 \subsection{Generating C calls}
2273 %************************************************************************
2275 Now the biggest nightmare---calls. Most of the nastiness is buried in
2276 @get_arg@, which moves the arguments to the correct registers/stack
2277 locations. Apart from that, the code is easy.
2279 (If applicable) Do not fill the delay slots here; you will confuse the
2284 :: FAST_STRING -- function to call
2286 -> PrimRep -- type of the result
2287 -> [StixTree] -- arguments (of mixed type)
2290 #if alpha_TARGET_ARCH
2292 genCCall fn cconv kind args
2293 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2294 `thenNat` \ ((unused,_), argCode) ->
2296 nRegs = length allArgRegs - length unused
2297 code = asmSeqThen (map ($ []) argCode)
2300 LDA pv (AddrImm (ImmLab (ptext fn))),
2301 JSR ra (AddrReg pv) nRegs,
2302 LDGP gp (AddrReg ra)]
2304 ------------------------
2305 {- Try to get a value into a specific register (or registers) for
2306 a call. The first 6 arguments go into the appropriate
2307 argument register (separate registers for integer and floating
2308 point arguments, but used in lock-step), and the remaining
2309 arguments are dumped to the stack, beginning at 0(sp). Our
2310 first argument is a pair of the list of remaining argument
2311 registers to be assigned for this call and the next stack
2312 offset to use for overflowing arguments. This way,
2313 @get_Arg@ can be applied to all of a call's arguments using
2317 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2318 -> StixTree -- Current argument
2319 -> NatM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2321 -- We have to use up all of our argument registers first...
2323 get_arg ((iDst,fDst):dsts, offset) arg
2324 = getRegister arg `thenNat` \ register ->
2326 reg = if isFloatingRep pk then fDst else iDst
2327 code = registerCode register reg
2328 src = registerName register reg
2329 pk = registerRep register
2332 if isFloatingRep pk then
2333 ((dsts, offset), if isFixed register then
2334 code . mkSeqInstr (FMOV src fDst)
2337 ((dsts, offset), if isFixed register then
2338 code . mkSeqInstr (OR src (RIReg src) iDst)
2341 -- Once we have run out of argument registers, we move to the
2344 get_arg ([], offset) arg
2345 = getRegister arg `thenNat` \ register ->
2346 getNewRegNCG (registerRep register)
2349 code = registerCode register tmp
2350 src = registerName register tmp
2351 pk = registerRep register
2352 sz = primRepToSize pk
2354 returnNat (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2356 #endif {- alpha_TARGET_ARCH -}
2357 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2358 #if i386_TARGET_ARCH
2360 genCCall fn cconv kind [StInt i]
2361 | fn == SLIT ("PerformGC_wrapper")
2363 MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2364 CALL (ImmLit (ptext (if underscorePrefix
2365 then (SLIT ("_PerformGC_wrapper"))
2366 else (SLIT ("PerformGC_wrapper")))))
2372 genCCall fn cconv kind args
2373 = mapNat get_call_arg
2374 (reverse args) `thenNat` \ sizes_n_codes ->
2375 getDeltaNat `thenNat` \ delta ->
2376 let (sizes, codes) = unzip sizes_n_codes
2377 tot_arg_size = sum sizes
2378 code2 = concatOL codes
2381 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2382 DELTA (delta + tot_arg_size)
2385 setDeltaNat (delta + tot_arg_size) `thenNat` \ _ ->
2386 returnNat (code2 `appOL` call)
2389 -- function names that begin with '.' are assumed to be special
2390 -- internally generated names like '.mul,' which don't get an
2391 -- underscore prefix
2392 -- ToDo:needed (WDP 96/03) ???
2393 fn__2 = case (_HEAD_ fn) of
2394 '.' -> ImmLit (ptext fn)
2395 _ -> ImmLab False (ptext fn)
2402 get_call_arg :: StixTree{-current argument-}
2403 -> NatM (Int, InstrBlock) -- argsz, code
2406 = get_op arg `thenNat` \ (code, reg, sz) ->
2407 getDeltaNat `thenNat` \ delta ->
2408 arg_size sz `bind` \ size ->
2409 setDeltaNat (delta-size) `thenNat` \ _ ->
2410 if (case sz of DF -> True; F -> True; _ -> False)
2411 then returnNat (size,
2413 toOL [SUB L (OpImm (ImmInt size)) (OpReg esp),
2415 GST sz reg (AddrBaseIndex (Just esp)
2419 else returnNat (size,
2421 PUSH L (OpReg reg) `snocOL`
2427 -> NatM (InstrBlock, Reg, Size) -- code, reg, size
2430 = getRegister op `thenNat` \ register ->
2431 getNewRegNCG (registerRep register)
2434 code = registerCode register tmp
2435 reg = registerName register tmp
2436 pk = registerRep register
2437 sz = primRepToSize pk
2439 returnNat (code, reg, sz)
2441 #endif {- i386_TARGET_ARCH -}
2442 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2443 #if sparc_TARGET_ARCH
2444 genCCall fn cconv kind args
2445 = mapAccumLNat get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2446 `thenNat` \ ((unused,_), argCode) ->
2449 nRegs = length allArgRegs - length unused
2450 call = unitOL (CALL fn__2 nRegs False)
2451 code = concatOL argCode
2453 -- 3 because in the worst case, %o0 .. %o5 will only use up 3 args
2454 (move_sp_down, move_sp_up)
2455 = let nn = length args - 3
2458 else (unitOL (moveSp (-(2*nn))), unitOL (moveSp (2*nn)))
2460 returnNat (move_sp_down `appOL`
2466 -- function names that begin with '.' are assumed to be special
2467 -- internally generated names like '.mul,' which don't get an
2468 -- underscore prefix
2469 -- ToDo:needed (WDP 96/03) ???
2470 fn__2 = case (_HEAD_ fn) of
2471 '.' -> ImmLit (ptext fn)
2472 _ -> ImmLab False (ptext fn)
2474 ------------------------------------
2475 {- Try to get a value into a specific register (or registers) for
2476 a call. The SPARC calling convention is an absolute
2477 nightmare. The first 6x32 bits of arguments are mapped into
2478 %o0 through %o5, and the remaining arguments are dumped to the
2479 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2480 first argument is a pair of the list of remaining argument
2481 registers to be assigned for this call and the next stack
2482 offset to use for overflowing arguments. This way,
2483 @get_arg@ can be applied to all of a call's arguments using
2486 If we have to put args on the stack, move %o6==%sp down by
2487 8 x the number of args, to ensure there's enough space.
2490 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2491 -> StixTree -- Current argument
2492 -> NatM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2494 -- We have to use up all of our argument registers first...
2496 get_arg (dst:dsts, offset) arg
2497 = getRegister arg `thenNat` \ register ->
2498 getNewRegNCG (registerRep register)
2501 reg = if isFloatingRep pk then tmp else dst
2502 code = registerCode register reg
2503 src = registerName register reg
2504 pk = registerRep register
2510 [] -> ( ([], offset + 1),
2512 -- put the second part in the right stack
2513 -- and load the first part into %o5
2514 FMOV DF src f0 `snocOL`
2515 ST F f0 (spRel offset) `snocOL`
2516 LD W (spRel offset) dst `snocOL`
2517 ST F (fPair f0) (spRel offset)
2520 -> ( (dsts__2, offset),
2522 FMOV DF src f0 `snocOL`
2523 ST F f0 (spRel 16) `snocOL`
2524 LD W (spRel 16) dst `snocOL`
2525 ST F (fPair f0) (spRel 16) `snocOL`
2526 LD W (spRel 16) dst__2
2529 -> ( (dsts, offset),
2531 ST F src (spRel 16) `snocOL`
2534 _ -> ( (dsts, offset),
2536 then code `snocOL` OR False g0 (RIReg src) dst
2540 -- Once we have run out of argument registers, we move to the
2543 get_arg ([], offset) arg
2544 = getRegister arg `thenNat` \ register ->
2545 getNewRegNCG (registerRep register)
2548 code = registerCode register tmp
2549 src = registerName register tmp
2550 pk = registerRep register
2551 sz = primRepToSize pk
2552 words = if pk == DoubleRep then 2 else 1
2554 returnNat ( ([], offset + words),
2555 code `snocOL` ST sz src (spRel offset) )
2557 #endif {- sparc_TARGET_ARCH -}
2560 %************************************************************************
2562 \subsection{Support bits}
2564 %************************************************************************
2566 %************************************************************************
2568 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2570 %************************************************************************
2572 Turn those condition codes into integers now (when they appear on
2573 the right hand side of an assignment).
2575 (If applicable) Do not fill the delay slots here; you will confuse the
2579 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> NatM Register
2581 #if alpha_TARGET_ARCH
2582 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2583 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2584 #endif {- alpha_TARGET_ARCH -}
2586 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2587 #if i386_TARGET_ARCH
2590 = condIntCode cond x y `thenNat` \ condition ->
2591 getNewRegNCG IntRep `thenNat` \ tmp ->
2593 code = condCode condition
2594 cond = condName condition
2595 code__2 dst = code `appOL` toOL [
2596 SETCC cond (OpReg tmp),
2597 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2598 MOV L (OpReg tmp) (OpReg dst)]
2600 returnNat (Any IntRep code__2)
2603 = getNatLabelNCG `thenNat` \ lbl1 ->
2604 getNatLabelNCG `thenNat` \ lbl2 ->
2605 condFltCode cond x y `thenNat` \ condition ->
2607 code = condCode condition
2608 cond = condName condition
2609 code__2 dst = code `appOL` toOL [
2611 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2614 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2617 returnNat (Any IntRep code__2)
2619 #endif {- i386_TARGET_ARCH -}
2620 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2621 #if sparc_TARGET_ARCH
2623 condIntReg EQQ x (StInt 0)
2624 = getRegister x `thenNat` \ register ->
2625 getNewRegNCG IntRep `thenNat` \ tmp ->
2627 code = registerCode register tmp
2628 src = registerName register tmp
2629 code__2 dst = code `appOL` toOL [
2630 SUB False True g0 (RIReg src) g0,
2631 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2633 returnNat (Any IntRep code__2)
2636 = getRegister x `thenNat` \ register1 ->
2637 getRegister y `thenNat` \ register2 ->
2638 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2639 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2641 code1 = registerCode register1 tmp1
2642 src1 = registerName register1 tmp1
2643 code2 = registerCode register2 tmp2
2644 src2 = registerName register2 tmp2
2645 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2646 XOR False src1 (RIReg src2) dst,
2647 SUB False True g0 (RIReg dst) g0,
2648 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2650 returnNat (Any IntRep code__2)
2652 condIntReg NE x (StInt 0)
2653 = getRegister x `thenNat` \ register ->
2654 getNewRegNCG IntRep `thenNat` \ tmp ->
2656 code = registerCode register tmp
2657 src = registerName register tmp
2658 code__2 dst = code `appOL` toOL [
2659 SUB False True g0 (RIReg src) g0,
2660 ADD True False g0 (RIImm (ImmInt 0)) dst]
2662 returnNat (Any IntRep code__2)
2665 = getRegister x `thenNat` \ register1 ->
2666 getRegister y `thenNat` \ register2 ->
2667 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2668 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2670 code1 = registerCode register1 tmp1
2671 src1 = registerName register1 tmp1
2672 code2 = registerCode register2 tmp2
2673 src2 = registerName register2 tmp2
2674 code__2 dst = code1 `appOL` code2 `appOL` toOL [
2675 XOR False src1 (RIReg src2) dst,
2676 SUB False True g0 (RIReg dst) g0,
2677 ADD True False g0 (RIImm (ImmInt 0)) dst]
2679 returnNat (Any IntRep code__2)
2682 = getNatLabelNCG `thenNat` \ lbl1 ->
2683 getNatLabelNCG `thenNat` \ lbl2 ->
2684 condIntCode cond x y `thenNat` \ condition ->
2686 code = condCode condition
2687 cond = condName condition
2688 code__2 dst = code `appOL` toOL [
2689 BI cond False (ImmCLbl lbl1), NOP,
2690 OR False g0 (RIImm (ImmInt 0)) dst,
2691 BI ALWAYS False (ImmCLbl lbl2), NOP,
2693 OR False g0 (RIImm (ImmInt 1)) dst,
2696 returnNat (Any IntRep code__2)
2699 = getNatLabelNCG `thenNat` \ lbl1 ->
2700 getNatLabelNCG `thenNat` \ lbl2 ->
2701 condFltCode cond x y `thenNat` \ condition ->
2703 code = condCode condition
2704 cond = condName condition
2705 code__2 dst = code `appOL` toOL [
2707 BF cond False (ImmCLbl lbl1), NOP,
2708 OR False g0 (RIImm (ImmInt 0)) dst,
2709 BI ALWAYS False (ImmCLbl lbl2), NOP,
2711 OR False g0 (RIImm (ImmInt 1)) dst,
2714 returnNat (Any IntRep code__2)
2716 #endif {- sparc_TARGET_ARCH -}
2719 %************************************************************************
2721 \subsubsection{@trivial*Code@: deal with trivial instructions}
2723 %************************************************************************
2725 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2726 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2727 for constants on the right hand side, because that's where the generic
2728 optimizer will have put them.
2730 Similarly, for unary instructions, we don't have to worry about
2731 matching an StInt as the argument, because genericOpt will already
2732 have handled the constant-folding.
2736 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2737 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2738 -> Maybe (Operand -> Operand -> Instr)
2739 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2741 -> StixTree -> StixTree -- the two arguments
2746 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2747 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2748 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2750 -> StixTree -> StixTree -- the two arguments
2754 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2755 ,IF_ARCH_i386 ((Operand -> Instr)
2756 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2758 -> StixTree -- the one argument
2763 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2764 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2765 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2767 -> StixTree -- the one argument
2770 #if alpha_TARGET_ARCH
2772 trivialCode instr x (StInt y)
2774 = getRegister x `thenNat` \ register ->
2775 getNewRegNCG IntRep `thenNat` \ tmp ->
2777 code = registerCode register tmp
2778 src1 = registerName register tmp
2779 src2 = ImmInt (fromInteger y)
2780 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2782 returnNat (Any IntRep code__2)
2784 trivialCode instr x y
2785 = getRegister x `thenNat` \ register1 ->
2786 getRegister y `thenNat` \ register2 ->
2787 getNewRegNCG IntRep `thenNat` \ tmp1 ->
2788 getNewRegNCG IntRep `thenNat` \ tmp2 ->
2790 code1 = registerCode register1 tmp1 []
2791 src1 = registerName register1 tmp1
2792 code2 = registerCode register2 tmp2 []
2793 src2 = registerName register2 tmp2
2794 code__2 dst = asmSeqThen [code1, code2] .
2795 mkSeqInstr (instr src1 (RIReg src2) dst)
2797 returnNat (Any IntRep code__2)
2800 trivialUCode instr x
2801 = getRegister x `thenNat` \ register ->
2802 getNewRegNCG IntRep `thenNat` \ tmp ->
2804 code = registerCode register tmp
2805 src = registerName register tmp
2806 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2808 returnNat (Any IntRep code__2)
2811 trivialFCode _ instr x y
2812 = getRegister x `thenNat` \ register1 ->
2813 getRegister y `thenNat` \ register2 ->
2814 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2815 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2817 code1 = registerCode register1 tmp1
2818 src1 = registerName register1 tmp1
2820 code2 = registerCode register2 tmp2
2821 src2 = registerName register2 tmp2
2823 code__2 dst = asmSeqThen [code1 [], code2 []] .
2824 mkSeqInstr (instr src1 src2 dst)
2826 returnNat (Any DoubleRep code__2)
2828 trivialUFCode _ instr x
2829 = getRegister x `thenNat` \ register ->
2830 getNewRegNCG DoubleRep `thenNat` \ tmp ->
2832 code = registerCode register tmp
2833 src = registerName register tmp
2834 code__2 dst = code . mkSeqInstr (instr src dst)
2836 returnNat (Any DoubleRep code__2)
2838 #endif {- alpha_TARGET_ARCH -}
2839 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2840 #if i386_TARGET_ARCH
2842 The Rules of the Game are:
2844 * You cannot assume anything about the destination register dst;
2845 it may be anything, including a fixed reg.
2847 * You may compute an operand into a fixed reg, but you may not
2848 subsequently change the contents of that fixed reg. If you
2849 want to do so, first copy the value either to a temporary
2850 or into dst. You are free to modify dst even if it happens
2851 to be a fixed reg -- that's not your problem.
2853 * You cannot assume that a fixed reg will stay live over an
2854 arbitrary computation. The same applies to the dst reg.
2856 * Temporary regs obtained from getNewRegNCG are distinct from
2857 each other and from all other regs, and stay live over
2858 arbitrary computations.
2862 trivialCode instr maybe_revinstr a b
2865 = getRegister a `thenNat` \ rega ->
2868 then registerCode rega dst `bind` \ code_a ->
2870 instr (OpImm imm_b) (OpReg dst)
2871 else registerCodeF rega `bind` \ code_a ->
2872 registerNameF rega `bind` \ r_a ->
2874 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2875 instr (OpImm imm_b) (OpReg dst)
2877 returnNat (Any IntRep mkcode)
2880 = getRegister b `thenNat` \ regb ->
2881 getNewRegNCG IntRep `thenNat` \ tmp ->
2882 let revinstr_avail = maybeToBool maybe_revinstr
2883 revinstr = case maybe_revinstr of Just ri -> ri
2887 then registerCode regb dst `bind` \ code_b ->
2889 revinstr (OpImm imm_a) (OpReg dst)
2890 else registerCodeF regb `bind` \ code_b ->
2891 registerNameF regb `bind` \ r_b ->
2893 MOV L (OpReg r_b) (OpReg dst) `snocOL`
2894 revinstr (OpImm imm_a) (OpReg dst)
2898 then registerCode regb tmp `bind` \ code_b ->
2900 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2901 instr (OpReg tmp) (OpReg dst)
2902 else registerCodeF regb `bind` \ code_b ->
2903 registerNameF regb `bind` \ r_b ->
2905 MOV L (OpReg r_b) (OpReg tmp) `snocOL`
2906 MOV L (OpImm imm_a) (OpReg dst) `snocOL`
2907 instr (OpReg tmp) (OpReg dst)
2909 returnNat (Any IntRep mkcode)
2912 = getRegister a `thenNat` \ rega ->
2913 getRegister b `thenNat` \ regb ->
2914 getNewRegNCG IntRep `thenNat` \ tmp ->
2916 = case (isAny rega, isAny regb) of
2918 -> registerCode regb tmp `bind` \ code_b ->
2919 registerCode rega dst `bind` \ code_a ->
2922 instr (OpReg tmp) (OpReg dst)
2924 -> registerCode rega tmp `bind` \ code_a ->
2925 registerCodeF regb `bind` \ code_b ->
2926 registerNameF regb `bind` \ r_b ->
2929 instr (OpReg r_b) (OpReg tmp) `snocOL`
2930 MOV L (OpReg tmp) (OpReg dst)
2932 -> registerCode regb tmp `bind` \ code_b ->
2933 registerCodeF rega `bind` \ code_a ->
2934 registerNameF rega `bind` \ r_a ->
2937 MOV L (OpReg r_a) (OpReg dst) `snocOL`
2938 instr (OpReg tmp) (OpReg dst)
2940 -> registerCodeF rega `bind` \ code_a ->
2941 registerNameF rega `bind` \ r_a ->
2942 registerCodeF regb `bind` \ code_b ->
2943 registerNameF regb `bind` \ r_b ->
2945 MOV L (OpReg r_a) (OpReg tmp) `appOL`
2947 instr (OpReg r_b) (OpReg tmp) `snocOL`
2948 MOV L (OpReg tmp) (OpReg dst)
2950 returnNat (Any IntRep mkcode)
2953 maybe_imm_a = maybeImm a
2954 is_imm_a = maybeToBool maybe_imm_a
2955 imm_a = case maybe_imm_a of Just imm -> imm
2957 maybe_imm_b = maybeImm b
2958 is_imm_b = maybeToBool maybe_imm_b
2959 imm_b = case maybe_imm_b of Just imm -> imm
2963 trivialUCode instr x
2964 = getRegister x `thenNat` \ register ->
2966 code__2 dst = let code = registerCode register dst
2967 src = registerName register dst
2969 if isFixed register && dst /= src
2970 then toOL [MOV L (OpReg src) (OpReg dst),
2972 else unitOL (instr (OpReg src))
2974 returnNat (Any IntRep code__2)
2977 trivialFCode pk instr x y
2978 = getRegister x `thenNat` \ register1 ->
2979 getRegister y `thenNat` \ register2 ->
2980 getNewRegNCG DoubleRep `thenNat` \ tmp1 ->
2981 getNewRegNCG DoubleRep `thenNat` \ tmp2 ->
2983 code1 = registerCode register1 tmp1
2984 src1 = registerName register1 tmp1
2986 code2 = registerCode register2 tmp2
2987 src2 = registerName register2 tmp2
2990 -- treat the common case specially: both operands in
2992 | isAny register1 && isAny register2
2995 instr (primRepToSize pk) src1 src2 dst
2997 -- be paranoid (and inefficient)
2999 = code1 `snocOL` GMOV src1 tmp1 `appOL`
3001 instr (primRepToSize pk) tmp1 src2 dst
3003 returnNat (Any pk code__2)
3007 trivialUFCode pk instr x
3008 = getRegister x `thenNat` \ register ->
3009 getNewRegNCG pk `thenNat` \ tmp ->
3011 code = registerCode register tmp
3012 src = registerName register tmp
3013 code__2 dst = code `snocOL` instr src dst
3015 returnNat (Any pk code__2)
3017 #endif {- i386_TARGET_ARCH -}
3018 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3019 #if sparc_TARGET_ARCH
3021 trivialCode instr x (StInt y)
3023 = getRegister x `thenNat` \ register ->
3024 getNewRegNCG IntRep `thenNat` \ tmp ->
3026 code = registerCode register tmp
3027 src1 = registerName register tmp
3028 src2 = ImmInt (fromInteger y)
3029 code__2 dst = code `snocOL` instr src1 (RIImm src2) dst
3031 returnNat (Any IntRep code__2)
3033 trivialCode instr x y
3034 = getRegister x `thenNat` \ register1 ->
3035 getRegister y `thenNat` \ register2 ->
3036 getNewRegNCG IntRep `thenNat` \ tmp1 ->
3037 getNewRegNCG IntRep `thenNat` \ tmp2 ->
3039 code1 = registerCode register1 tmp1
3040 src1 = registerName register1 tmp1
3041 code2 = registerCode register2 tmp2
3042 src2 = registerName register2 tmp2
3043 code__2 dst = code1 `appOL` code2 `snocOL`
3044 instr src1 (RIReg src2) dst
3046 returnNat (Any IntRep code__2)
3049 trivialFCode pk instr x y
3050 = getRegister x `thenNat` \ register1 ->
3051 getRegister y `thenNat` \ register2 ->
3052 getNewRegNCG (registerRep register1)
3054 getNewRegNCG (registerRep register2)
3056 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3058 promote x = FxTOy F DF x tmp
3060 pk1 = registerRep register1
3061 code1 = registerCode register1 tmp1
3062 src1 = registerName register1 tmp1
3064 pk2 = registerRep register2
3065 code2 = registerCode register2 tmp2
3066 src2 = registerName register2 tmp2
3070 code1 `appOL` code2 `snocOL`
3071 instr (primRepToSize pk) src1 src2 dst
3072 else if pk1 == FloatRep then
3073 code1 `snocOL` promote src1 `appOL` code2 `snocOL`
3074 instr DF tmp src2 dst
3076 code1 `appOL` code2 `snocOL` promote src2 `snocOL`
3077 instr DF src1 tmp dst
3079 returnNat (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3082 trivialUCode instr x
3083 = getRegister x `thenNat` \ register ->
3084 getNewRegNCG IntRep `thenNat` \ tmp ->
3086 code = registerCode register tmp
3087 src = registerName register tmp
3088 code__2 dst = code `snocOL` instr (RIReg src) dst
3090 returnNat (Any IntRep code__2)
3093 trivialUFCode pk instr x
3094 = getRegister x `thenNat` \ register ->
3095 getNewRegNCG pk `thenNat` \ tmp ->
3097 code = registerCode register tmp
3098 src = registerName register tmp
3099 code__2 dst = code `snocOL` instr src dst
3101 returnNat (Any pk code__2)
3103 #endif {- sparc_TARGET_ARCH -}
3106 %************************************************************************
3108 \subsubsection{Coercing to/from integer/floating-point...}
3110 %************************************************************************
3112 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3113 to be generated. Here we just change the type on the Register passed
3114 on up. The code is machine-independent.
3116 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3117 conversions. We have to store temporaries in memory to move
3118 between the integer and the floating point register sets.
3121 coerceIntCode :: PrimRep -> StixTree -> NatM Register
3122 coerceFltCode :: StixTree -> NatM Register
3124 coerceInt2FP :: PrimRep -> StixTree -> NatM Register
3125 coerceFP2Int :: StixTree -> NatM Register
3128 = getRegister x `thenNat` \ register ->
3131 Fixed _ reg code -> Fixed pk reg code
3132 Any _ code -> Any pk code
3137 = getRegister x `thenNat` \ register ->
3140 Fixed _ reg code -> Fixed DoubleRep reg code
3141 Any _ code -> Any DoubleRep code
3146 #if alpha_TARGET_ARCH
3149 = getRegister x `thenNat` \ register ->
3150 getNewRegNCG IntRep `thenNat` \ reg ->
3152 code = registerCode register reg
3153 src = registerName register reg
3155 code__2 dst = code . mkSeqInstrs [
3157 LD TF dst (spRel 0),
3160 returnNat (Any DoubleRep code__2)
3164 = getRegister x `thenNat` \ register ->
3165 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3167 code = registerCode register tmp
3168 src = registerName register tmp
3170 code__2 dst = code . mkSeqInstrs [
3172 ST TF tmp (spRel 0),
3175 returnNat (Any IntRep code__2)
3177 #endif {- alpha_TARGET_ARCH -}
3178 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3179 #if i386_TARGET_ARCH
3182 = getRegister x `thenNat` \ register ->
3183 getNewRegNCG IntRep `thenNat` \ reg ->
3185 code = registerCode register reg
3186 src = registerName register reg
3187 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3188 code__2 dst = code `snocOL` opc src dst
3190 returnNat (Any pk code__2)
3194 = getRegister x `thenNat` \ register ->
3195 getNewRegNCG DoubleRep `thenNat` \ tmp ->
3197 code = registerCode register tmp
3198 src = registerName register tmp
3199 pk = registerRep register
3201 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3202 code__2 dst = code `snocOL` opc src dst
3204 returnNat (Any IntRep code__2)
3206 #endif {- i386_TARGET_ARCH -}
3207 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3208 #if sparc_TARGET_ARCH
3211 = getRegister x `thenNat` \ register ->
3212 getNewRegNCG IntRep `thenNat` \ reg ->
3214 code = registerCode register reg
3215 src = registerName register reg
3217 code__2 dst = code `appOL` toOL [
3218 ST W src (spRel (-2)),
3219 LD W (spRel (-2)) dst,
3220 FxTOy W (primRepToSize pk) dst dst]
3222 returnNat (Any pk code__2)
3226 = getRegister x `thenNat` \ register ->
3227 getNewRegNCG IntRep `thenNat` \ reg ->
3228 getNewRegNCG FloatRep `thenNat` \ tmp ->
3230 code = registerCode register reg
3231 src = registerName register reg
3232 pk = registerRep register
3234 code__2 dst = code `appOL` toOL [
3235 FxTOy (primRepToSize pk) W src tmp,
3236 ST W tmp (spRel (-2)),
3237 LD W (spRel (-2)) dst]
3239 returnNat (Any IntRep code__2)
3241 #endif {- sparc_TARGET_ARCH -}
3244 %************************************************************************
3246 \subsubsection{Coercing integer to @Char@...}
3248 %************************************************************************
3250 Integer to character conversion. Where applicable, we try to do this
3251 in one step if the original object is in memory.
3254 chrCode :: StixTree -> NatM Register
3256 #if alpha_TARGET_ARCH
3259 = getRegister x `thenNat` \ register ->
3260 getNewRegNCG IntRep `thenNat` \ reg ->
3262 code = registerCode register reg
3263 src = registerName register reg
3264 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3266 returnNat (Any IntRep code__2)
3268 #endif {- alpha_TARGET_ARCH -}
3269 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3270 #if i386_TARGET_ARCH
3273 = getRegister x `thenNat` \ register ->
3276 code = registerCode register dst
3277 src = registerName register dst
3279 if isFixed register && src /= dst
3280 then toOL [MOV L (OpReg src) (OpReg dst),
3281 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3282 else unitOL (AND L (OpImm (ImmInt 255)) (OpReg src))
3284 returnNat (Any IntRep code__2)
3286 #endif {- i386_TARGET_ARCH -}
3287 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3288 #if sparc_TARGET_ARCH
3290 chrCode (StInd pk mem)
3291 = getAmode mem `thenNat` \ amode ->
3293 code = amodeCode amode
3294 src = amodeAddr amode
3295 src_off = addrOffset src 3
3296 src__2 = case src_off of Just x -> x
3297 code__2 dst = if maybeToBool src_off then
3298 code `snocOL` LD BU src__2 dst
3301 LD (primRepToSize pk) src dst `snocOL`
3302 AND False dst (RIImm (ImmInt 255)) dst
3304 returnNat (Any pk code__2)
3307 = getRegister x `thenNat` \ register ->
3308 getNewRegNCG IntRep `thenNat` \ reg ->
3310 code = registerCode register reg
3311 src = registerName register reg
3312 code__2 dst = code `snocOL` AND False src (RIImm (ImmInt 255)) dst
3314 returnNat (Any IntRep code__2)
3316 #endif {- sparc_TARGET_ARCH -}