2 % (c) The AQUA Project, Glasgow University, 1996
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 #include "HsVersions.h"
13 #include "nativeGen/NCG.h"
15 module MachCode ( stmt2Instrs, asmVoid, SYN_IE(InstrList) ) where
19 import MachMisc -- may differ per-platform
22 import AbsCSyn ( MagicId )
23 import AbsCUtils ( magicIdPrimRep )
24 import CLabel ( isAsmTemp, CLabel )
25 import Maybes ( maybeToBool, expectJust )
26 import OrdList -- quite a bit of it
27 import Outputable ( PprStyle(..) )
28 import Pretty ( ptext, rational )
29 import PrimRep ( isFloatingRep, PrimRep(..) )
30 import PrimOp ( PrimOp(..), showPrimOp )
31 import Stix ( getUniqLabelNCG, StixTree(..),
32 StixReg(..), CodeSegment(..)
34 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
35 mapAccumLUs, SYN_IE(UniqSM)
37 import Util ( panic, assertPanic )
40 Code extractor for an entire stix tree---stix statement level.
43 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
45 stmt2Instrs stmt = case stmt of
46 StComment s -> returnInstr (COMMENT s)
47 StSegment seg -> returnInstr (SEGMENT seg)
48 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
49 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
50 StLabel lab -> returnInstr (LABEL lab)
52 StJump arg -> genJump arg
53 StCondJump lab arg -> genCondJump lab arg
54 StCall fn VoidRep args -> genCCall fn VoidRep args
57 | isFloatingRep pk -> assignFltCode pk dst src
58 | otherwise -> assignIntCode pk dst src
61 -- When falling through on the Alpha, we still have to load pv
62 -- with the address of the next routine, so that it can load gp.
63 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
67 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
68 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
69 (foldr1 (.) codes xs))
71 getData :: StixTree -> UniqSM (InstrBlock, Imm)
73 getData (StInt i) = returnUs (id, ImmInteger i)
74 getData (StDouble d) = returnUs (id, dblImmLit d)
75 getData (StLitLbl s) = returnUs (id, ImmLab s)
76 getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
77 getData (StCLbl l) = returnUs (id, ImmCLbl l)
78 getData (StString s) =
79 getUniqLabelNCG `thenUs` \ lbl ->
80 returnUs (mkSeqInstrs [LABEL lbl,
81 ASCII True (_UNPK_ s)],
85 %************************************************************************
87 \subsection{General things for putting together code sequences}
89 %************************************************************************
92 type InstrList = OrdList Instr
93 type InstrBlock = InstrList -> InstrList
98 asmInstr :: Instr -> InstrList
99 asmInstr i = mkUnitList i
101 asmSeq :: [Instr] -> InstrList
102 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
104 asmParThen :: [InstrList] -> InstrBlock
105 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
107 returnInstr :: Instr -> UniqSM InstrBlock
108 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
110 returnInstrs :: [Instr] -> UniqSM InstrBlock
111 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
113 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
114 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
116 mkSeqInstr :: Instr -> InstrBlock
117 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
119 mkSeqInstrs :: [Instr] -> InstrBlock
120 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
124 mangleIndexTree :: StixTree -> StixTree
126 mangleIndexTree (StIndex pk base (StInt i))
127 = StPrim IntAddOp [base, off]
129 off = StInt (i * sizeOf pk)
131 #ifndef i386_TARGET_ARCH
132 mangleIndexTree (StIndex pk base off)
133 = StPrim IntAddOp [base,
139 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
140 StPrim SllOp [off, StInt s]
143 shift DoubleRep = 3::Integer
144 shift _ = IF_ARCH_alpha(3,2)
146 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
147 -- that do include the size of the primitive kind we're addressing. When StIndex
148 -- is expanded to actual code, the index (in units) is by the above code approp.
149 -- shifted to get the no. of bytes. Since Address amodes do contain size info
150 -- explicitly, we disable the shifting for x86s.
151 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
157 maybeImm :: StixTree -> Maybe Imm
159 maybeImm (StLitLbl s) = Just (ImmLab s)
160 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
161 maybeImm (StCLbl l) = Just (ImmCLbl l)
164 | i >= toInteger minInt && i <= toInteger maxInt
165 = Just (ImmInt (fromInteger i))
167 = Just (ImmInteger i)
172 %************************************************************************
174 \subsection{The @Register@ type}
176 %************************************************************************
178 @Register@s passed up the tree. If the stix code forces the register
179 to live in a pre-decided machine register, it comes out as @Fixed@;
180 otherwise, it comes out as @Any@, and the parent can decide which
181 register to put it in.
185 = Fixed PrimRep Reg InstrBlock
186 | Any PrimRep (Reg -> InstrBlock)
188 registerCode :: Register -> Reg -> InstrBlock
189 registerCode (Fixed _ _ code) reg = code
190 registerCode (Any _ code) reg = code reg
192 registerName :: Register -> Reg -> Reg
193 registerName (Fixed _ reg _) _ = reg
194 registerName (Any _ _) reg = reg
196 registerRep :: Register -> PrimRep
197 registerRep (Fixed pk _ _) = pk
198 registerRep (Any pk _) = pk
200 isFixed :: Register -> Bool
201 isFixed (Fixed _ _ _) = True
202 isFixed (Any _ _) = False
205 Generate code to get a subtree into a @Register@:
207 getRegister :: StixTree -> UniqSM Register
209 getRegister (StReg (StixMagicId stgreg))
210 = case (magicIdRegMaybe stgreg) of
211 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
214 getRegister (StReg (StixTemp u pk))
215 = returnUs (Fixed pk (UnmappedReg u pk) id)
217 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
219 getRegister (StCall fn kind args)
220 = genCCall fn kind args `thenUs` \ call ->
221 returnUs (Fixed kind reg call)
223 reg = if isFloatingRep kind
224 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
225 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
227 getRegister (StString s)
228 = getUniqLabelNCG `thenUs` \ lbl ->
230 imm_lbl = ImmCLbl lbl
232 code dst = mkSeqInstrs [
235 ASCII True (_UNPK_ s),
237 #if alpha_TARGET_ARCH
238 LDA dst (AddrImm imm_lbl)
241 MOV L (OpImm imm_lbl) (OpReg dst)
243 #if sparc_TARGET_ARCH
244 SETHI (HI imm_lbl) dst,
245 OR False dst (RIImm (LO imm_lbl)) dst
249 returnUs (Any PtrRep code)
251 getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
252 = getUniqLabelNCG `thenUs` \ lbl ->
254 imm_lbl = ImmCLbl lbl
256 code dst = mkSeqInstrs [
259 ASCII False (init xs),
261 #if alpha_TARGET_ARCH
262 LDA dst (AddrImm imm_lbl)
265 MOV L (OpImm imm_lbl) (OpReg dst)
267 #if sparc_TARGET_ARCH
268 SETHI (HI imm_lbl) dst,
269 OR False dst (RIImm (LO imm_lbl)) dst
273 returnUs (Any PtrRep code)
275 xs = _UNPK_ (_TAIL_ s)
277 -- end of machine-"independent" bit; here we go on the rest...
279 #if alpha_TARGET_ARCH
281 getRegister (StDouble d)
282 = getUniqLabelNCG `thenUs` \ lbl ->
283 getNewRegNCG PtrRep `thenUs` \ tmp ->
284 let code dst = mkSeqInstrs [
287 DATA TF [ImmLab (rational d)],
289 LDA tmp (AddrImm (ImmCLbl lbl)),
290 LD TF dst (AddrReg tmp)]
292 returnUs (Any DoubleRep code)
294 getRegister (StPrim primop [x]) -- unary PrimOps
296 IntNegOp -> trivialUCode (NEG Q False) x
297 IntAbsOp -> trivialUCode (ABS Q) x
299 NotOp -> trivialUCode NOT x
301 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
302 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
304 OrdOp -> coerceIntCode IntRep x
307 Float2IntOp -> coerceFP2Int x
308 Int2FloatOp -> coerceInt2FP pr x
309 Double2IntOp -> coerceFP2Int x
310 Int2DoubleOp -> coerceInt2FP pr x
312 Double2FloatOp -> coerceFltCode x
313 Float2DoubleOp -> coerceFltCode x
315 other_op -> getRegister (StCall fn DoubleRep [x])
317 fn = case other_op of
318 FloatExpOp -> SLIT("exp")
319 FloatLogOp -> SLIT("log")
320 FloatSqrtOp -> SLIT("sqrt")
321 FloatSinOp -> SLIT("sin")
322 FloatCosOp -> SLIT("cos")
323 FloatTanOp -> SLIT("tan")
324 FloatAsinOp -> SLIT("asin")
325 FloatAcosOp -> SLIT("acos")
326 FloatAtanOp -> SLIT("atan")
327 FloatSinhOp -> SLIT("sinh")
328 FloatCoshOp -> SLIT("cosh")
329 FloatTanhOp -> SLIT("tanh")
330 DoubleExpOp -> SLIT("exp")
331 DoubleLogOp -> SLIT("log")
332 DoubleSqrtOp -> SLIT("sqrt")
333 DoubleSinOp -> SLIT("sin")
334 DoubleCosOp -> SLIT("cos")
335 DoubleTanOp -> SLIT("tan")
336 DoubleAsinOp -> SLIT("asin")
337 DoubleAcosOp -> SLIT("acos")
338 DoubleAtanOp -> SLIT("atan")
339 DoubleSinhOp -> SLIT("sinh")
340 DoubleCoshOp -> SLIT("cosh")
341 DoubleTanhOp -> SLIT("tanh")
343 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
345 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
347 CharGtOp -> trivialCode (CMP LTT) y x
348 CharGeOp -> trivialCode (CMP LE) y x
349 CharEqOp -> trivialCode (CMP EQQ) x y
350 CharNeOp -> int_NE_code x y
351 CharLtOp -> trivialCode (CMP LTT) x y
352 CharLeOp -> trivialCode (CMP LE) x y
354 IntGtOp -> trivialCode (CMP LTT) y x
355 IntGeOp -> trivialCode (CMP LE) y x
356 IntEqOp -> trivialCode (CMP EQQ) x y
357 IntNeOp -> int_NE_code x y
358 IntLtOp -> trivialCode (CMP LTT) x y
359 IntLeOp -> trivialCode (CMP LE) x y
361 WordGtOp -> trivialCode (CMP ULT) y x
362 WordGeOp -> trivialCode (CMP ULE) x y
363 WordEqOp -> trivialCode (CMP EQQ) x y
364 WordNeOp -> int_NE_code x y
365 WordLtOp -> trivialCode (CMP ULT) x y
366 WordLeOp -> trivialCode (CMP ULE) x y
368 AddrGtOp -> trivialCode (CMP ULT) y x
369 AddrGeOp -> trivialCode (CMP ULE) y x
370 AddrEqOp -> trivialCode (CMP EQQ) x y
371 AddrNeOp -> int_NE_code x y
372 AddrLtOp -> trivialCode (CMP ULT) x y
373 AddrLeOp -> trivialCode (CMP ULE) x y
375 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
376 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
377 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
378 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
379 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
380 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
382 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
383 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
384 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
385 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
386 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
387 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
389 IntAddOp -> trivialCode (ADD Q False) x y
390 IntSubOp -> trivialCode (SUB Q False) x y
391 IntMulOp -> trivialCode (MUL Q False) x y
392 IntQuotOp -> trivialCode (DIV Q False) x y
393 IntRemOp -> trivialCode (REM Q False) x y
395 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
396 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
397 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
398 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
400 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
401 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
402 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
403 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
405 AndOp -> trivialCode AND x y
406 OrOp -> trivialCode OR x y
407 SllOp -> trivialCode SLL x y
408 SraOp -> trivialCode SRA x y
409 SrlOp -> trivialCode SRL x y
411 ISllOp -> panic "AlphaGen:isll"
412 ISraOp -> panic "AlphaGen:isra"
413 ISrlOp -> panic "AlphaGen:isrl"
415 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x,y])
416 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x,y])
418 {- ------------------------------------------------------------
419 Some bizarre special code for getting condition codes into
420 registers. Integer non-equality is a test for equality
421 followed by an XOR with 1. (Integer comparisons always set
422 the result register to 0 or 1.) Floating point comparisons of
423 any kind leave the result in a floating point register, so we
424 need to wrangle an integer register out of things.
426 int_NE_code :: StixTree -> StixTree -> UniqSM Register
429 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
430 getNewRegNCG IntRep `thenUs` \ tmp ->
432 code = registerCode register tmp
433 src = registerName register tmp
434 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
436 returnUs (Any IntRep code__2)
438 {- ------------------------------------------------------------
439 Comments for int_NE_code also apply to cmpF_code
442 :: (Reg -> Reg -> Reg -> Instr)
444 -> StixTree -> StixTree
447 cmpF_code instr cond x y
448 = trivialFCode pr instr x y `thenUs` \ register ->
449 getNewRegNCG DoubleRep `thenUs` \ tmp ->
450 getUniqLabelNCG `thenUs` \ lbl ->
452 code = registerCode register tmp
453 result = registerName register tmp
455 code__2 dst = code . mkSeqInstrs [
456 OR zeroh (RIImm (ImmInt 1)) dst,
457 BF cond result (ImmCLbl lbl),
458 OR zeroh (RIReg zeroh) dst,
461 returnUs (Any IntRep code__2)
463 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
464 ------------------------------------------------------------
466 getRegister (StInd pk mem)
467 = getAmode mem `thenUs` \ amode ->
469 code = amodeCode amode
470 src = amodeAddr amode
471 size = primRepToSize pk
472 code__2 dst = code . mkSeqInstr (LD size dst src)
474 returnUs (Any pk code__2)
476 getRegister (StInt i)
479 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
481 returnUs (Any IntRep code)
484 code dst = mkSeqInstr (LDI Q dst src)
486 returnUs (Any IntRep code)
488 src = ImmInt (fromInteger i)
493 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
495 returnUs (Any PtrRep code)
498 imm__2 = case imm of Just x -> x
500 #endif {- alpha_TARGET_ARCH -}
501 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
504 getRegister (StReg (StixTemp u pk)) = returnUs (Fixed pk (UnmappedReg u pk) id)
506 getRegister (StDouble 0.0)
508 code dst = mkSeqInstrs [FLDZ]
510 returnUs (Any DoubleRep code)
512 getRegister (StDouble 1.0)
514 code dst = mkSeqInstrs [FLD1]
516 returnUs (Any DoubleRep code)
518 getRegister (StDouble d)
519 = getUniqLabelNCG `thenUs` \ lbl ->
520 --getNewRegNCG PtrRep `thenUs` \ tmp ->
521 let code dst = mkSeqInstrs [
524 DATA DF [dblImmLit d],
526 FLD DF (OpImm (ImmCLbl lbl))
529 returnUs (Any DoubleRep code)
531 getRegister (StPrim primop [x]) -- unary PrimOps
533 IntNegOp -> trivialUCode (NEGI L) x
534 IntAbsOp -> absIntCode x
536 NotOp -> trivialUCode (NOT L) x
538 FloatNegOp -> trivialUFCode FloatRep FCHS x
539 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
540 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
542 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
544 OrdOp -> coerceIntCode IntRep x
547 Float2IntOp -> coerceFP2Int x
548 Int2FloatOp -> coerceInt2FP FloatRep x
549 Double2IntOp -> coerceFP2Int x
550 Int2DoubleOp -> coerceInt2FP DoubleRep x
552 Double2FloatOp -> coerceFltCode x
553 Float2DoubleOp -> coerceFltCode x
557 fixed_x = if is_float_op -- promote to double
558 then StPrim Float2DoubleOp [x]
561 getRegister (StCall fn DoubleRep [x])
565 FloatExpOp -> (True, SLIT("exp"))
566 FloatLogOp -> (True, SLIT("log"))
568 FloatSinOp -> (True, SLIT("sin"))
569 FloatCosOp -> (True, SLIT("cos"))
570 FloatTanOp -> (True, SLIT("tan"))
572 FloatAsinOp -> (True, SLIT("asin"))
573 FloatAcosOp -> (True, SLIT("acos"))
574 FloatAtanOp -> (True, SLIT("atan"))
576 FloatSinhOp -> (True, SLIT("sinh"))
577 FloatCoshOp -> (True, SLIT("cosh"))
578 FloatTanhOp -> (True, SLIT("tanh"))
580 DoubleExpOp -> (False, SLIT("exp"))
581 DoubleLogOp -> (False, SLIT("log"))
583 DoubleSinOp -> (False, SLIT("sin"))
584 DoubleCosOp -> (False, SLIT("cos"))
585 DoubleTanOp -> (False, SLIT("tan"))
587 DoubleAsinOp -> (False, SLIT("asin"))
588 DoubleAcosOp -> (False, SLIT("acos"))
589 DoubleAtanOp -> (False, SLIT("atan"))
591 DoubleSinhOp -> (False, SLIT("sinh"))
592 DoubleCoshOp -> (False, SLIT("cosh"))
593 DoubleTanhOp -> (False, SLIT("tanh"))
595 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
597 CharGtOp -> condIntReg GTT x y
598 CharGeOp -> condIntReg GE x y
599 CharEqOp -> condIntReg EQQ x y
600 CharNeOp -> condIntReg NE x y
601 CharLtOp -> condIntReg LTT x y
602 CharLeOp -> condIntReg LE x y
604 IntGtOp -> condIntReg GTT x y
605 IntGeOp -> condIntReg GE x y
606 IntEqOp -> condIntReg EQQ x y
607 IntNeOp -> condIntReg NE x y
608 IntLtOp -> condIntReg LTT x y
609 IntLeOp -> condIntReg LE x y
611 WordGtOp -> condIntReg GU x y
612 WordGeOp -> condIntReg GEU x y
613 WordEqOp -> condIntReg EQQ x y
614 WordNeOp -> condIntReg NE x y
615 WordLtOp -> condIntReg LU x y
616 WordLeOp -> condIntReg LEU x y
618 AddrGtOp -> condIntReg GU x y
619 AddrGeOp -> condIntReg GEU x y
620 AddrEqOp -> condIntReg EQQ x y
621 AddrNeOp -> condIntReg NE x y
622 AddrLtOp -> condIntReg LU x y
623 AddrLeOp -> condIntReg LEU x y
625 FloatGtOp -> condFltReg GTT x y
626 FloatGeOp -> condFltReg GE x y
627 FloatEqOp -> condFltReg EQQ x y
628 FloatNeOp -> condFltReg NE x y
629 FloatLtOp -> condFltReg LTT x y
630 FloatLeOp -> condFltReg LE x y
632 DoubleGtOp -> condFltReg GTT x y
633 DoubleGeOp -> condFltReg GE x y
634 DoubleEqOp -> condFltReg EQQ x y
635 DoubleNeOp -> condFltReg NE x y
636 DoubleLtOp -> condFltReg LTT x y
637 DoubleLeOp -> condFltReg LE x y
639 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
640 -- this should be optimised by the generic Opts,
641 -- I don't know why it is not (sometimes)!
643 [x, StInt 0] -> getRegister x
648 IntSubOp -> sub_code L x y
649 IntQuotOp -> quot_code L x y True{-division-}
650 IntRemOp -> quot_code L x y False{-remainder-}
651 IntMulOp -> trivialCode (IMUL L) x y {-True-}
653 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
654 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
655 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
656 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
658 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
659 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
660 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
661 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
663 AndOp -> trivialCode (AND L) x y {-True-}
664 OrOp -> trivialCode (OR L) x y {-True-}
666 {- Shift ops on x86s have constraints on their source, it
667 either has to be Imm, CL or 1
668 => trivialCode's is not restrictive enough (sigh.)
671 SllOp -> shift_code (SHL L) x y {-False-}
672 SraOp -> shift_code (SAR L) x y {-False-}
673 SrlOp -> shift_code (SHR L) x y {-False-}
676 ISllOp -> panic "I386Gen:isll"
677 ISraOp -> panic "I386Gen:isra"
678 ISrlOp -> panic "I386Gen:isrl"
680 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
681 where promote x = StPrim Float2DoubleOp [x]
682 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
684 shift_code :: (Operand -> Operand -> Instr)
688 {- Case1: shift length as immediate -}
689 -- Code is the same as the first eq. for trivialCode -- sigh.
690 shift_code instr x y{-amount-}
692 = getRegister x `thenUs` \ register ->
694 op_imm = OpImm imm__2
697 code = registerCode register dst
698 src = registerName register dst
700 mkSeqInstr (COMMENT SLIT("shift_code")) .
702 if isFixed register && src /= dst
704 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
705 instr op_imm (OpReg dst)]
707 mkSeqInstr (instr op_imm (OpReg src))
709 returnUs (Any IntRep code__2)
712 imm__2 = case imm of Just x -> x
714 {- Case2: shift length is complex (non-immediate) -}
715 shift_code instr x y{-amount-}
716 = getRegister y `thenUs` \ register1 ->
717 getRegister x `thenUs` \ register2 ->
718 -- getNewRegNCG IntRep `thenUs` \ dst ->
720 -- Note: we force the shift length to be loaded
721 -- into ECX, so that we can use CL when shifting.
722 -- (only register location we are allowed
723 -- to put shift amounts.)
725 -- The shift instruction is fed ECX as src reg,
726 -- but we coerce this into CL when printing out.
727 src1 = registerName register1 ecx
728 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
729 registerCode register1 ecx .
730 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
732 registerCode register1 ecx
735 code2 = registerCode register2 eax
736 src2 = registerName register2 eax
739 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
741 returnUs (Fixed IntRep eax code__2)
743 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
745 add_code sz x (StInt y)
746 = getRegister x `thenUs` \ register ->
747 getNewRegNCG IntRep `thenUs` \ tmp ->
749 code = registerCode register tmp
750 src1 = registerName register tmp
751 src2 = ImmInt (fromInteger y)
753 mkSeqInstr (LEA sz (OpAddr (Address (Just src1) Nothing src2)) (OpReg dst))
755 returnUs (Any IntRep code__2)
757 add_code sz x (StInd _ mem)
758 = getRegister x `thenUs` \ register1 ->
759 --getNewRegNCG (registerRep register1)
760 -- `thenUs` \ tmp1 ->
761 getAmode mem `thenUs` \ amode ->
763 code2 = amodeCode amode
764 src2 = amodeAddr amode
766 -- fixedname = registerName register1 eax
767 code__2 dst = let code1 = registerCode register1 dst
768 src1 = registerName register1 dst
769 in asmParThen [code2 asmVoid,code1 asmVoid] .
770 if isFixed register1 && src1 /= dst
771 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
772 ADD sz (OpAddr src2) (OpReg dst)]
774 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
776 returnUs (Any IntRep code__2)
778 add_code sz (StInd _ mem) y
779 = getRegister y `thenUs` \ register2 ->
780 --getNewRegNCG (registerRep register2)
781 -- `thenUs` \ tmp2 ->
782 getAmode mem `thenUs` \ amode ->
784 code1 = amodeCode amode
785 src1 = amodeAddr amode
787 -- fixedname = registerName register2 eax
788 code__2 dst = let code2 = registerCode register2 dst
789 src2 = registerName register2 dst
790 in asmParThen [code1 asmVoid,code2 asmVoid] .
791 if isFixed register2 && src2 /= dst
792 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
793 ADD sz (OpAddr src1) (OpReg dst)]
795 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
797 returnUs (Any IntRep code__2)
800 = getRegister x `thenUs` \ register1 ->
801 getRegister y `thenUs` \ register2 ->
802 getNewRegNCG IntRep `thenUs` \ tmp1 ->
803 getNewRegNCG IntRep `thenUs` \ tmp2 ->
805 code1 = registerCode register1 tmp1 asmVoid
806 src1 = registerName register1 tmp1
807 code2 = registerCode register2 tmp2 asmVoid
808 src2 = registerName register2 tmp2
809 code__2 dst = asmParThen [code1, code2] .
810 mkSeqInstr (LEA sz (OpAddr (Address (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
812 returnUs (Any IntRep code__2)
815 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
817 sub_code sz x (StInt y)
818 = getRegister x `thenUs` \ register ->
819 getNewRegNCG IntRep `thenUs` \ tmp ->
821 code = registerCode register tmp
822 src1 = registerName register tmp
823 src2 = ImmInt (-(fromInteger y))
825 mkSeqInstr (LEA sz (OpAddr (Address (Just src1) Nothing src2)) (OpReg dst))
827 returnUs (Any IntRep code__2)
829 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
834 -> StixTree -> StixTree
835 -> Bool -- True => division, False => remainder operation
838 -- x must go into eax, edx must be a sign-extension of eax, and y
839 -- should go in some other register (or memory), so that we get
840 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
841 -- put y in memory (if it is not there already)
843 quot_code sz x (StInd pk mem) is_division
844 = getRegister x `thenUs` \ register1 ->
845 getNewRegNCG IntRep `thenUs` \ tmp1 ->
846 getAmode mem `thenUs` \ amode ->
848 code1 = registerCode register1 tmp1 asmVoid
849 src1 = registerName register1 tmp1
850 code2 = amodeCode amode asmVoid
851 src2 = amodeAddr amode
852 code__2 = asmParThen [code1, code2] .
853 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
855 IDIV sz (OpAddr src2)]
857 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
859 quot_code sz x (StInt i) is_division
860 = getRegister x `thenUs` \ register1 ->
861 getNewRegNCG IntRep `thenUs` \ tmp1 ->
863 code1 = registerCode register1 tmp1 asmVoid
864 src1 = registerName register1 tmp1
865 src2 = ImmInt (fromInteger i)
866 code__2 = asmParThen [code1] .
867 mkSeqInstrs [-- we put src2 in (ebx)
868 MOV L (OpImm src2) (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))),
869 MOV L (OpReg src1) (OpReg eax),
871 IDIV sz (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1)))]
873 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
875 quot_code sz x y is_division
876 = getRegister x `thenUs` \ register1 ->
877 getNewRegNCG IntRep `thenUs` \ tmp1 ->
878 getRegister y `thenUs` \ register2 ->
879 getNewRegNCG IntRep `thenUs` \ tmp2 ->
881 code1 = registerCode register1 tmp1 asmVoid
882 src1 = registerName register1 tmp1
883 code2 = registerCode register2 tmp2 asmVoid
884 src2 = registerName register2 tmp2
885 code__2 = asmParThen [code1, code2] .
886 if src2 == ecx || src2 == esi
887 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
889 IDIV sz (OpReg src2)]
890 else mkSeqInstrs [ -- we put src2 in (ebx)
891 MOV L (OpReg src2) (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))),
892 MOV L (OpReg src1) (OpReg eax),
894 IDIV sz (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1)))]
896 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
897 -----------------------
899 getRegister (StInd pk mem)
900 = getAmode mem `thenUs` \ amode ->
902 code = amodeCode amode
903 src = amodeAddr amode
904 size = primRepToSize pk
906 if pk == DoubleRep || pk == FloatRep
907 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
908 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
910 returnUs (Any pk code__2)
913 getRegister (StInt i)
915 src = ImmInt (fromInteger i)
916 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
918 returnUs (Any IntRep code)
923 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
925 returnUs (Any PtrRep code)
928 imm__2 = case imm of Just x -> x
930 #endif {- i386_TARGET_ARCH -}
931 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
932 #if sparc_TARGET_ARCH
934 getRegister (StDouble d)
935 = getUniqLabelNCG `thenUs` \ lbl ->
936 getNewRegNCG PtrRep `thenUs` \ tmp ->
937 let code dst = mkSeqInstrs [
940 DATA DF [dblImmLit d],
942 SETHI (HI (ImmCLbl lbl)) tmp,
943 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
945 returnUs (Any DoubleRep code)
947 getRegister (StPrim primop [x]) -- unary PrimOps
949 IntNegOp -> trivialUCode (SUB False False g0) x
950 IntAbsOp -> absIntCode x
951 NotOp -> trivialUCode (XNOR False g0) x
953 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
955 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
957 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
958 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
960 OrdOp -> coerceIntCode IntRep x
963 Float2IntOp -> coerceFP2Int x
964 Int2FloatOp -> coerceInt2FP FloatRep x
965 Double2IntOp -> coerceFP2Int x
966 Int2DoubleOp -> coerceInt2FP DoubleRep x
970 fixed_x = if is_float_op -- promote to double
971 then StPrim Float2DoubleOp [x]
974 getRegister (StCall fn DoubleRep [x])
978 FloatExpOp -> (True, SLIT("exp"))
979 FloatLogOp -> (True, SLIT("log"))
980 FloatSqrtOp -> (True, SLIT("sqrt"))
982 FloatSinOp -> (True, SLIT("sin"))
983 FloatCosOp -> (True, SLIT("cos"))
984 FloatTanOp -> (True, SLIT("tan"))
986 FloatAsinOp -> (True, SLIT("asin"))
987 FloatAcosOp -> (True, SLIT("acos"))
988 FloatAtanOp -> (True, SLIT("atan"))
990 FloatSinhOp -> (True, SLIT("sinh"))
991 FloatCoshOp -> (True, SLIT("cosh"))
992 FloatTanhOp -> (True, SLIT("tanh"))
994 DoubleExpOp -> (False, SLIT("exp"))
995 DoubleLogOp -> (False, SLIT("log"))
996 DoubleSqrtOp -> (True, SLIT("sqrt"))
998 DoubleSinOp -> (False, SLIT("sin"))
999 DoubleCosOp -> (False, SLIT("cos"))
1000 DoubleTanOp -> (False, SLIT("tan"))
1002 DoubleAsinOp -> (False, SLIT("asin"))
1003 DoubleAcosOp -> (False, SLIT("acos"))
1004 DoubleAtanOp -> (False, SLIT("atan"))
1006 DoubleSinhOp -> (False, SLIT("sinh"))
1007 DoubleCoshOp -> (False, SLIT("cosh"))
1008 DoubleTanhOp -> (False, SLIT("tanh"))
1009 _ -> panic ("Monadic PrimOp not handled: " ++ showPrimOp PprDebug primop)
1011 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1013 CharGtOp -> condIntReg GTT x y
1014 CharGeOp -> condIntReg GE x y
1015 CharEqOp -> condIntReg EQQ x y
1016 CharNeOp -> condIntReg NE x y
1017 CharLtOp -> condIntReg LTT x y
1018 CharLeOp -> condIntReg LE x y
1020 IntGtOp -> condIntReg GTT x y
1021 IntGeOp -> condIntReg GE x y
1022 IntEqOp -> condIntReg EQQ x y
1023 IntNeOp -> condIntReg NE x y
1024 IntLtOp -> condIntReg LTT x y
1025 IntLeOp -> condIntReg LE x y
1027 WordGtOp -> condIntReg GU x y
1028 WordGeOp -> condIntReg GEU x y
1029 WordEqOp -> condIntReg EQQ x y
1030 WordNeOp -> condIntReg NE x y
1031 WordLtOp -> condIntReg LU x y
1032 WordLeOp -> condIntReg LEU x y
1034 AddrGtOp -> condIntReg GU x y
1035 AddrGeOp -> condIntReg GEU x y
1036 AddrEqOp -> condIntReg EQQ x y
1037 AddrNeOp -> condIntReg NE x y
1038 AddrLtOp -> condIntReg LU x y
1039 AddrLeOp -> condIntReg LEU x y
1041 FloatGtOp -> condFltReg GTT x y
1042 FloatGeOp -> condFltReg GE x y
1043 FloatEqOp -> condFltReg EQQ x y
1044 FloatNeOp -> condFltReg NE x y
1045 FloatLtOp -> condFltReg LTT x y
1046 FloatLeOp -> condFltReg LE x y
1048 DoubleGtOp -> condFltReg GTT x y
1049 DoubleGeOp -> condFltReg GE x y
1050 DoubleEqOp -> condFltReg EQQ x y
1051 DoubleNeOp -> condFltReg NE x y
1052 DoubleLtOp -> condFltReg LTT x y
1053 DoubleLeOp -> condFltReg LE x y
1055 IntAddOp -> trivialCode (ADD False False) x y
1056 IntSubOp -> trivialCode (SUB False False) x y
1058 -- ToDo: teach about V8+ SPARC mul/div instructions
1059 IntMulOp -> imul_div SLIT(".umul") x y
1060 IntQuotOp -> imul_div SLIT(".div") x y
1061 IntRemOp -> imul_div SLIT(".rem") x y
1063 FloatAddOp -> trivialFCode FloatRep FADD x y
1064 FloatSubOp -> trivialFCode FloatRep FSUB x y
1065 FloatMulOp -> trivialFCode FloatRep FMUL x y
1066 FloatDivOp -> trivialFCode FloatRep FDIV x y
1068 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1069 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1070 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1071 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1073 AndOp -> trivialCode (AND False) x y
1074 OrOp -> trivialCode (OR False) x y
1075 SllOp -> trivialCode SLL x y
1076 SraOp -> trivialCode SRA x y
1077 SrlOp -> trivialCode SRL x y
1079 ISllOp -> panic "SparcGen:isll"
1080 ISraOp -> panic "SparcGen:isra"
1081 ISrlOp -> panic "SparcGen:isrl"
1083 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
1084 where promote x = StPrim Float2DoubleOp [x]
1085 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
1087 imul_div fn x y = getRegister (StCall fn IntRep [x, y])
1089 getRegister (StInd pk mem)
1090 = getAmode mem `thenUs` \ amode ->
1092 code = amodeCode amode
1093 src = amodeAddr amode
1094 size = primRepToSize pk
1095 code__2 dst = code . mkSeqInstr (LD size src dst)
1097 returnUs (Any pk code__2)
1099 getRegister (StInt i)
1102 src = ImmInt (fromInteger i)
1103 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1105 returnUs (Any IntRep code)
1110 code dst = mkSeqInstrs [
1111 SETHI (HI imm__2) dst,
1112 OR False dst (RIImm (LO imm__2)) dst]
1114 returnUs (Any PtrRep code)
1117 imm__2 = case imm of Just x -> x
1119 #endif {- sparc_TARGET_ARCH -}
1122 %************************************************************************
1124 \subsection{The @Amode@ type}
1126 %************************************************************************
1128 @Amode@s: Memory addressing modes passed up the tree.
1130 data Amode = Amode Address InstrBlock
1132 amodeAddr (Amode addr _) = addr
1133 amodeCode (Amode _ code) = code
1136 Now, given a tree (the argument to an StInd) that references memory,
1137 produce a suitable addressing mode.
1140 getAmode :: StixTree -> UniqSM Amode
1142 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1144 #if alpha_TARGET_ARCH
1146 getAmode (StPrim IntSubOp [x, StInt i])
1147 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1148 getRegister x `thenUs` \ register ->
1150 code = registerCode register tmp
1151 reg = registerName register tmp
1152 off = ImmInt (-(fromInteger i))
1154 returnUs (Amode (AddrRegImm reg off) code)
1156 getAmode (StPrim IntAddOp [x, StInt i])
1157 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1158 getRegister x `thenUs` \ register ->
1160 code = registerCode register tmp
1161 reg = registerName register tmp
1162 off = ImmInt (fromInteger i)
1164 returnUs (Amode (AddrRegImm reg off) code)
1168 = returnUs (Amode (AddrImm imm__2) id)
1171 imm__2 = case imm of Just x -> x
1174 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1175 getRegister other `thenUs` \ register ->
1177 code = registerCode register tmp
1178 reg = registerName register tmp
1180 returnUs (Amode (AddrReg reg) code)
1182 #endif {- alpha_TARGET_ARCH -}
1183 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1184 #if i386_TARGET_ARCH
1186 getAmode (StPrim IntSubOp [x, StInt i])
1187 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1188 getRegister x `thenUs` \ register ->
1190 code = registerCode register tmp
1191 reg = registerName register tmp
1192 off = ImmInt (-(fromInteger i))
1194 returnUs (Amode (Address (Just reg) Nothing off) code)
1196 getAmode (StPrim IntAddOp [x, StInt i])
1199 code = mkSeqInstrs []
1201 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1204 imm__2 = case imm of Just x -> x
1206 getAmode (StPrim IntAddOp [x, StInt i])
1207 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1208 getRegister x `thenUs` \ register ->
1210 code = registerCode register tmp
1211 reg = registerName register tmp
1212 off = ImmInt (fromInteger i)
1214 returnUs (Amode (Address (Just reg) Nothing off) code)
1216 getAmode (StPrim IntAddOp [x, y])
1217 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1218 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1219 getRegister x `thenUs` \ register1 ->
1220 getRegister y `thenUs` \ register2 ->
1222 code1 = registerCode register1 tmp1 asmVoid
1223 reg1 = registerName register1 tmp1
1224 code2 = registerCode register2 tmp2 asmVoid
1225 reg2 = registerName register2 tmp2
1226 code__2 = asmParThen [code1, code2]
1228 returnUs (Amode (Address (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1233 code = mkSeqInstrs []
1235 returnUs (Amode (ImmAddr imm__2 0) code)
1238 imm__2 = case imm of Just x -> x
1241 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1242 getRegister other `thenUs` \ register ->
1244 code = registerCode register tmp
1245 reg = registerName register tmp
1248 returnUs (Amode (Address (Just reg) Nothing (ImmInt 0)) code)
1250 #endif {- i386_TARGET_ARCH -}
1251 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1252 #if sparc_TARGET_ARCH
1254 getAmode (StPrim IntSubOp [x, StInt i])
1256 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1257 getRegister x `thenUs` \ register ->
1259 code = registerCode register tmp
1260 reg = registerName register tmp
1261 off = ImmInt (-(fromInteger i))
1263 returnUs (Amode (AddrRegImm reg off) code)
1266 getAmode (StPrim IntAddOp [x, StInt i])
1268 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1269 getRegister x `thenUs` \ register ->
1271 code = registerCode register tmp
1272 reg = registerName register tmp
1273 off = ImmInt (fromInteger i)
1275 returnUs (Amode (AddrRegImm reg off) code)
1277 getAmode (StPrim IntAddOp [x, y])
1278 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1279 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1280 getRegister x `thenUs` \ register1 ->
1281 getRegister y `thenUs` \ register2 ->
1283 code1 = registerCode register1 tmp1 asmVoid
1284 reg1 = registerName register1 tmp1
1285 code2 = registerCode register2 tmp2 asmVoid
1286 reg2 = registerName register2 tmp2
1287 code__2 = asmParThen [code1, code2]
1289 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1293 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1295 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1297 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1300 imm__2 = case imm of Just x -> x
1303 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1304 getRegister other `thenUs` \ register ->
1306 code = registerCode register tmp
1307 reg = registerName register tmp
1310 returnUs (Amode (AddrRegImm reg off) code)
1312 #endif {- sparc_TARGET_ARCH -}
1315 %************************************************************************
1317 \subsection{The @CondCode@ type}
1319 %************************************************************************
1321 Condition codes passed up the tree.
1323 data CondCode = CondCode Bool Cond InstrBlock
1325 condName (CondCode _ cond _) = cond
1326 condFloat (CondCode is_float _ _) = is_float
1327 condCode (CondCode _ _ code) = code
1330 Set up a condition code for a conditional branch.
1333 getCondCode :: StixTree -> UniqSM CondCode
1335 #if alpha_TARGET_ARCH
1336 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1337 #endif {- alpha_TARGET_ARCH -}
1338 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1340 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1341 -- yes, they really do seem to want exactly the same!
1343 getCondCode (StPrim primop [x, y])
1345 CharGtOp -> condIntCode GTT x y
1346 CharGeOp -> condIntCode GE x y
1347 CharEqOp -> condIntCode EQQ x y
1348 CharNeOp -> condIntCode NE x y
1349 CharLtOp -> condIntCode LTT x y
1350 CharLeOp -> condIntCode LE x y
1352 IntGtOp -> condIntCode GTT x y
1353 IntGeOp -> condIntCode GE x y
1354 IntEqOp -> condIntCode EQQ x y
1355 IntNeOp -> condIntCode NE x y
1356 IntLtOp -> condIntCode LTT x y
1357 IntLeOp -> condIntCode LE x y
1359 WordGtOp -> condIntCode GU x y
1360 WordGeOp -> condIntCode GEU x y
1361 WordEqOp -> condIntCode EQQ x y
1362 WordNeOp -> condIntCode NE x y
1363 WordLtOp -> condIntCode LU x y
1364 WordLeOp -> condIntCode LEU x y
1366 AddrGtOp -> condIntCode GU x y
1367 AddrGeOp -> condIntCode GEU x y
1368 AddrEqOp -> condIntCode EQQ x y
1369 AddrNeOp -> condIntCode NE x y
1370 AddrLtOp -> condIntCode LU x y
1371 AddrLeOp -> condIntCode LEU x y
1373 FloatGtOp -> condFltCode GTT x y
1374 FloatGeOp -> condFltCode GE x y
1375 FloatEqOp -> condFltCode EQQ x y
1376 FloatNeOp -> condFltCode NE x y
1377 FloatLtOp -> condFltCode LTT x y
1378 FloatLeOp -> condFltCode LE x y
1380 DoubleGtOp -> condFltCode GTT x y
1381 DoubleGeOp -> condFltCode GE x y
1382 DoubleEqOp -> condFltCode EQQ x y
1383 DoubleNeOp -> condFltCode NE x y
1384 DoubleLtOp -> condFltCode LTT x y
1385 DoubleLeOp -> condFltCode LE x y
1387 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1392 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1393 passed back up the tree.
1396 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1398 #if alpha_TARGET_ARCH
1399 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1400 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1401 #endif {- alpha_TARGET_ARCH -}
1403 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1404 #if i386_TARGET_ARCH
1406 condIntCode cond (StInd _ x) y
1408 = getAmode x `thenUs` \ amode ->
1410 code1 = amodeCode amode asmVoid
1411 y__2 = amodeAddr amode
1412 code__2 = asmParThen [code1] .
1413 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1415 returnUs (CondCode False cond code__2)
1418 imm__2 = case imm of Just x -> x
1420 condIntCode cond x (StInt 0)
1421 = getRegister x `thenUs` \ register1 ->
1422 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1424 code1 = registerCode register1 tmp1 asmVoid
1425 src1 = registerName register1 tmp1
1426 code__2 = asmParThen [code1] .
1427 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1429 returnUs (CondCode False cond code__2)
1431 condIntCode cond x y
1433 = getRegister x `thenUs` \ register1 ->
1434 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1436 code1 = registerCode register1 tmp1 asmVoid
1437 src1 = registerName register1 tmp1
1438 code__2 = asmParThen [code1] .
1439 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1441 returnUs (CondCode False cond code__2)
1444 imm__2 = case imm of Just x -> x
1446 condIntCode cond (StInd _ x) y
1447 = getAmode x `thenUs` \ amode ->
1448 getRegister y `thenUs` \ register2 ->
1449 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1451 code1 = amodeCode amode asmVoid
1452 src1 = amodeAddr amode
1453 code2 = registerCode register2 tmp2 asmVoid
1454 src2 = registerName register2 tmp2
1455 code__2 = asmParThen [code1, code2] .
1456 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1458 returnUs (CondCode False cond code__2)
1460 condIntCode cond y (StInd _ x)
1461 = getAmode x `thenUs` \ amode ->
1462 getRegister y `thenUs` \ register2 ->
1463 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1465 code1 = amodeCode amode asmVoid
1466 src1 = amodeAddr amode
1467 code2 = registerCode register2 tmp2 asmVoid
1468 src2 = registerName register2 tmp2
1469 code__2 = asmParThen [code1, code2] .
1470 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1472 returnUs (CondCode False cond code__2)
1474 condIntCode cond x y
1475 = getRegister x `thenUs` \ register1 ->
1476 getRegister y `thenUs` \ register2 ->
1477 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1478 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1480 code1 = registerCode register1 tmp1 asmVoid
1481 src1 = registerName register1 tmp1
1482 code2 = registerCode register2 tmp2 asmVoid
1483 src2 = registerName register2 tmp2
1484 code__2 = asmParThen [code1, code2] .
1485 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1487 returnUs (CondCode False cond code__2)
1491 condFltCode cond x (StDouble 0.0)
1492 = getRegister x `thenUs` \ register1 ->
1493 getNewRegNCG (registerRep register1)
1496 pk1 = registerRep register1
1497 code1 = registerCode register1 tmp1
1498 src1 = registerName register1 tmp1
1500 code__2 = asmParThen [code1 asmVoid] .
1501 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1503 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1504 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1508 returnUs (CondCode True (fix_FP_cond cond) code__2)
1510 condFltCode cond x y
1511 = getRegister x `thenUs` \ register1 ->
1512 getRegister y `thenUs` \ register2 ->
1513 getNewRegNCG (registerRep register1)
1515 getNewRegNCG (registerRep register2)
1518 pk1 = registerRep register1
1519 code1 = registerCode register1 tmp1
1520 src1 = registerName register1 tmp1
1522 code2 = registerCode register2 tmp2
1523 src2 = registerName register2 tmp2
1525 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1526 mkSeqInstrs [FUCOMPP,
1528 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1529 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1533 returnUs (CondCode True (fix_FP_cond cond) code__2)
1535 {- On the 486, the flags set by FP compare are the unsigned ones!
1536 (This looks like a HACK to me. WDP 96/03)
1539 fix_FP_cond :: Cond -> Cond
1541 fix_FP_cond GE = GEU
1542 fix_FP_cond GTT = GU
1543 fix_FP_cond LTT = LU
1544 fix_FP_cond LE = LEU
1545 fix_FP_cond any = any
1547 #endif {- i386_TARGET_ARCH -}
1548 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1549 #if sparc_TARGET_ARCH
1551 condIntCode cond x (StInt y)
1553 = getRegister x `thenUs` \ register ->
1554 getNewRegNCG IntRep `thenUs` \ tmp ->
1556 code = registerCode register tmp
1557 src1 = registerName register tmp
1558 src2 = ImmInt (fromInteger y)
1559 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1561 returnUs (CondCode False cond code__2)
1563 condIntCode cond x y
1564 = getRegister x `thenUs` \ register1 ->
1565 getRegister y `thenUs` \ register2 ->
1566 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1567 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1569 code1 = registerCode register1 tmp1 asmVoid
1570 src1 = registerName register1 tmp1
1571 code2 = registerCode register2 tmp2 asmVoid
1572 src2 = registerName register2 tmp2
1573 code__2 = asmParThen [code1, code2] .
1574 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1576 returnUs (CondCode False cond code__2)
1579 condFltCode cond x y
1580 = getRegister x `thenUs` \ register1 ->
1581 getRegister y `thenUs` \ register2 ->
1582 getNewRegNCG (registerRep register1)
1584 getNewRegNCG (registerRep register2)
1586 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1588 promote x = asmInstr (FxTOy F DF x tmp)
1590 pk1 = registerRep register1
1591 code1 = registerCode register1 tmp1
1592 src1 = registerName register1 tmp1
1594 pk2 = registerRep register2
1595 code2 = registerCode register2 tmp2
1596 src2 = registerName register2 tmp2
1600 asmParThen [code1 asmVoid, code2 asmVoid] .
1601 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1602 else if pk1 == FloatRep then
1603 asmParThen [code1 (promote src1), code2 asmVoid] .
1604 mkSeqInstr (FCMP True DF tmp src2)
1606 asmParThen [code1 asmVoid, code2 (promote src2)] .
1607 mkSeqInstr (FCMP True DF src1 tmp)
1609 returnUs (CondCode True cond code__2)
1611 #endif {- sparc_TARGET_ARCH -}
1614 %************************************************************************
1616 \subsection{Generating assignments}
1618 %************************************************************************
1620 Assignments are really at the heart of the whole code generation
1621 business. Almost all top-level nodes of any real importance are
1622 assignments, which correspond to loads, stores, or register transfers.
1623 If we're really lucky, some of the register transfers will go away,
1624 because we can use the destination register to complete the code
1625 generation for the right hand side. This only fails when the right
1626 hand side is forced into a fixed register (e.g. the result of a call).
1629 assignIntCode, assignFltCode
1630 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1632 #if alpha_TARGET_ARCH
1634 assignIntCode pk (StInd _ dst) src
1635 = getNewRegNCG IntRep `thenUs` \ tmp ->
1636 getAmode dst `thenUs` \ amode ->
1637 getRegister src `thenUs` \ register ->
1639 code1 = amodeCode amode asmVoid
1640 dst__2 = amodeAddr amode
1641 code2 = registerCode register tmp asmVoid
1642 src__2 = registerName register tmp
1643 sz = primRepToSize pk
1644 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1648 assignIntCode pk dst src
1649 = getRegister dst `thenUs` \ register1 ->
1650 getRegister src `thenUs` \ register2 ->
1652 dst__2 = registerName register1 zeroh
1653 code = registerCode register2 dst__2
1654 src__2 = registerName register2 dst__2
1655 code__2 = if isFixed register2
1656 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1661 #endif {- alpha_TARGET_ARCH -}
1662 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1663 #if i386_TARGET_ARCH
1665 assignIntCode pk (StInd _ dst) src
1666 = getAmode dst `thenUs` \ amode ->
1667 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1669 code1 = amodeCode amode asmVoid
1670 dst__2 = amodeAddr amode
1671 code__2 = asmParThen [code1, codesrc asmVoid] .
1672 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1678 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1682 = returnUs (asmParThen [], OpImm imm_op, L)
1685 imm_op = case imm of Just x -> x
1688 = getRegister op `thenUs` \ register ->
1689 getNewRegNCG (registerRep register)
1692 code = registerCode register tmp
1693 reg = registerName register tmp
1694 pk = registerRep register
1695 sz = primRepToSize pk
1697 returnUs (code, OpReg reg, sz)
1699 assignIntCode pk dst (StInd _ src)
1700 = getNewRegNCG IntRep `thenUs` \ tmp ->
1701 getAmode src `thenUs` \ amode ->
1702 getRegister dst `thenUs` \ register ->
1704 code1 = amodeCode amode asmVoid
1705 src__2 = amodeAddr amode
1706 code2 = registerCode register tmp asmVoid
1707 dst__2 = registerName register tmp
1708 sz = primRepToSize pk
1709 code__2 = asmParThen [code1, code2] .
1710 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1714 assignIntCode pk dst src
1715 = getRegister dst `thenUs` \ register1 ->
1716 getRegister src `thenUs` \ register2 ->
1717 getNewRegNCG IntRep `thenUs` \ tmp ->
1719 dst__2 = registerName register1 tmp
1720 code = registerCode register2 dst__2
1721 src__2 = registerName register2 dst__2
1722 code__2 = if isFixed register2 && dst__2 /= src__2
1723 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1728 #endif {- i386_TARGET_ARCH -}
1729 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1730 #if sparc_TARGET_ARCH
1732 assignIntCode pk (StInd _ dst) src
1733 = getNewRegNCG IntRep `thenUs` \ tmp ->
1734 getAmode dst `thenUs` \ amode ->
1735 getRegister src `thenUs` \ register ->
1737 code1 = amodeCode amode asmVoid
1738 dst__2 = amodeAddr amode
1739 code2 = registerCode register tmp asmVoid
1740 src__2 = registerName register tmp
1741 sz = primRepToSize pk
1742 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1746 assignIntCode pk dst src
1747 = getRegister dst `thenUs` \ register1 ->
1748 getRegister src `thenUs` \ register2 ->
1750 dst__2 = registerName register1 g0
1751 code = registerCode register2 dst__2
1752 src__2 = registerName register2 dst__2
1753 code__2 = if isFixed register2
1754 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1759 #endif {- sparc_TARGET_ARCH -}
1762 % --------------------------------
1763 Floating-point assignments:
1764 % --------------------------------
1766 #if alpha_TARGET_ARCH
1768 assignFltCode pk (StInd _ dst) src
1769 = getNewRegNCG pk `thenUs` \ tmp ->
1770 getAmode dst `thenUs` \ amode ->
1771 getRegister src `thenUs` \ register ->
1773 code1 = amodeCode amode asmVoid
1774 dst__2 = amodeAddr amode
1775 code2 = registerCode register tmp asmVoid
1776 src__2 = registerName register tmp
1777 sz = primRepToSize pk
1778 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1782 assignFltCode pk dst src
1783 = getRegister dst `thenUs` \ register1 ->
1784 getRegister src `thenUs` \ register2 ->
1786 dst__2 = registerName register1 zeroh
1787 code = registerCode register2 dst__2
1788 src__2 = registerName register2 dst__2
1789 code__2 = if isFixed register2
1790 then code . mkSeqInstr (FMOV src__2 dst__2)
1795 #endif {- alpha_TARGET_ARCH -}
1796 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1797 #if i386_TARGET_ARCH
1799 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1800 = getNewRegNCG IntRep `thenUs` \ tmp ->
1801 getAmode src `thenUs` \ amodesrc ->
1802 getAmode dst `thenUs` \ amodedst ->
1803 --getRegister src `thenUs` \ register ->
1805 codesrc1 = amodeCode amodesrc asmVoid
1806 addrsrc1 = amodeAddr amodesrc
1807 codedst1 = amodeCode amodedst asmVoid
1808 addrdst1 = amodeAddr amodedst
1809 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1810 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1812 code__2 = asmParThen [codesrc1, codedst1] .
1813 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1814 MOV L (OpReg tmp) (OpAddr addrdst1)]
1817 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1818 MOV L (OpReg tmp) (OpAddr addrdst2)]
1823 assignFltCode pk (StInd _ dst) src
1824 = --getNewRegNCG pk `thenUs` \ tmp ->
1825 getAmode dst `thenUs` \ amode ->
1826 getRegister src `thenUs` \ register ->
1828 sz = primRepToSize pk
1829 dst__2 = amodeAddr amode
1831 code1 = amodeCode amode asmVoid
1832 code2 = registerCode register {-tmp-}st0 asmVoid
1834 --src__2= registerName register tmp
1835 pk__2 = registerRep register
1836 sz__2 = primRepToSize pk__2
1838 code__2 = asmParThen [code1, code2] .
1839 mkSeqInstr (FSTP sz (OpAddr dst__2))
1843 assignFltCode pk dst src
1844 = getRegister dst `thenUs` \ register1 ->
1845 getRegister src `thenUs` \ register2 ->
1846 --getNewRegNCG (registerRep register2)
1847 -- `thenUs` \ tmp ->
1849 sz = primRepToSize pk
1850 dst__2 = registerName register1 st0 --tmp
1852 code = registerCode register2 dst__2
1853 src__2 = registerName register2 dst__2
1859 #endif {- i386_TARGET_ARCH -}
1860 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1861 #if sparc_TARGET_ARCH
1863 assignFltCode pk (StInd _ dst) src
1864 = getNewRegNCG pk `thenUs` \ tmp1 ->
1865 getAmode dst `thenUs` \ amode ->
1866 getRegister src `thenUs` \ register ->
1868 sz = primRepToSize pk
1869 dst__2 = amodeAddr amode
1871 code1 = amodeCode amode asmVoid
1872 code2 = registerCode register tmp1 asmVoid
1874 src__2 = registerName register tmp1
1875 pk__2 = registerRep register
1876 sz__2 = primRepToSize pk__2
1878 code__2 = asmParThen [code1, code2] .
1880 mkSeqInstr (ST sz src__2 dst__2)
1882 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1886 assignFltCode pk dst src
1887 = getRegister dst `thenUs` \ register1 ->
1888 getRegister src `thenUs` \ register2 ->
1890 pk__2 = registerRep register2
1891 sz__2 = primRepToSize pk__2
1893 getNewRegNCG pk__2 `thenUs` \ tmp ->
1895 sz = primRepToSize pk
1896 dst__2 = registerName register1 g0 -- must be Fixed
1899 reg__2 = if pk /= pk__2 then tmp else dst__2
1901 code = registerCode register2 reg__2
1903 src__2 = registerName register2 reg__2
1907 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1908 else if isFixed register2 then
1909 code . mkSeqInstr (FMOV sz src__2 dst__2)
1915 #endif {- sparc_TARGET_ARCH -}
1918 %************************************************************************
1920 \subsection{Generating an unconditional branch}
1922 %************************************************************************
1924 We accept two types of targets: an immediate CLabel or a tree that
1925 gets evaluated into a register. Any CLabels which are AsmTemporaries
1926 are assumed to be in the local block of code, close enough for a
1927 branch instruction. Other CLabels are assumed to be far away.
1929 (If applicable) Do not fill the delay slots here; you will confuse the
1933 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1935 #if alpha_TARGET_ARCH
1937 genJump (StCLbl lbl)
1938 | isAsmTemp lbl = returnInstr (BR target)
1939 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1941 target = ImmCLbl lbl
1944 = getRegister tree `thenUs` \ register ->
1945 getNewRegNCG PtrRep `thenUs` \ tmp ->
1947 dst = registerName register pv
1948 code = registerCode register pv
1949 target = registerName register pv
1951 if isFixed register then
1952 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1954 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1956 #endif {- alpha_TARGET_ARCH -}
1957 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1958 #if i386_TARGET_ARCH
1961 genJump (StCLbl lbl)
1962 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1963 | otherwise = returnInstrs [JMP (OpImm target)]
1965 target = ImmCLbl lbl
1968 genJump (StInd pk mem)
1969 = getAmode mem `thenUs` \ amode ->
1971 code = amodeCode amode
1972 target = amodeAddr amode
1974 returnSeq code [JMP (OpAddr target)]
1978 = returnInstr (JMP (OpImm target))
1981 = getRegister tree `thenUs` \ register ->
1982 getNewRegNCG PtrRep `thenUs` \ tmp ->
1984 code = registerCode register tmp
1985 target = registerName register tmp
1987 returnSeq code [JMP (OpReg target)]
1990 target = case imm of Just x -> x
1992 #endif {- i386_TARGET_ARCH -}
1993 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1994 #if sparc_TARGET_ARCH
1996 genJump (StCLbl lbl)
1997 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1998 | otherwise = returnInstrs [CALL target 0 True, NOP]
2000 target = ImmCLbl lbl
2003 = getRegister tree `thenUs` \ register ->
2004 getNewRegNCG PtrRep `thenUs` \ tmp ->
2006 code = registerCode register tmp
2007 target = registerName register tmp
2009 returnSeq code [JMP (AddrRegReg target g0), NOP]
2011 #endif {- sparc_TARGET_ARCH -}
2014 %************************************************************************
2016 \subsection{Conditional jumps}
2018 %************************************************************************
2020 Conditional jumps are always to local labels, so we can use branch
2021 instructions. We peek at the arguments to decide what kind of
2024 ALPHA: For comparisons with 0, we're laughing, because we can just do
2025 the desired conditional branch.
2027 I386: First, we have to ensure that the condition
2028 codes are set according to the supplied comparison operation.
2030 SPARC: First, we have to ensure that the condition codes are set
2031 according to the supplied comparison operation. We generate slightly
2032 different code for floating point comparisons, because a floating
2033 point operation cannot directly precede a @BF@. We assume the worst
2034 and fill that slot with a @NOP@.
2036 SPARC: Do not fill the delay slots here; you will confuse the register
2041 :: CLabel -- the branch target
2042 -> StixTree -- the condition on which to branch
2043 -> UniqSM InstrBlock
2045 #if alpha_TARGET_ARCH
2047 genCondJump lbl (StPrim op [x, StInt 0])
2048 = getRegister x `thenUs` \ register ->
2049 getNewRegNCG (registerRep register)
2052 code = registerCode register tmp
2053 value = registerName register tmp
2054 pk = registerRep register
2055 target = ImmCLbl lbl
2057 returnSeq code [BI (cmpOp op) value target]
2059 cmpOp CharGtOp = GTT
2061 cmpOp CharEqOp = EQQ
2063 cmpOp CharLtOp = LTT
2072 cmpOp WordGeOp = ALWAYS
2073 cmpOp WordEqOp = EQQ
2075 cmpOp WordLtOp = NEVER
2076 cmpOp WordLeOp = EQQ
2078 cmpOp AddrGeOp = ALWAYS
2079 cmpOp AddrEqOp = EQQ
2081 cmpOp AddrLtOp = NEVER
2082 cmpOp AddrLeOp = EQQ
2084 genCondJump lbl (StPrim op [x, StDouble 0.0])
2085 = getRegister x `thenUs` \ register ->
2086 getNewRegNCG (registerRep register)
2089 code = registerCode register tmp
2090 value = registerName register tmp
2091 pk = registerRep register
2092 target = ImmCLbl lbl
2094 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2096 cmpOp FloatGtOp = GTT
2097 cmpOp FloatGeOp = GE
2098 cmpOp FloatEqOp = EQQ
2099 cmpOp FloatNeOp = NE
2100 cmpOp FloatLtOp = LTT
2101 cmpOp FloatLeOp = LE
2102 cmpOp DoubleGtOp = GTT
2103 cmpOp DoubleGeOp = GE
2104 cmpOp DoubleEqOp = EQQ
2105 cmpOp DoubleNeOp = NE
2106 cmpOp DoubleLtOp = LTT
2107 cmpOp DoubleLeOp = LE
2109 genCondJump lbl (StPrim op [x, y])
2111 = trivialFCode pr instr x y `thenUs` \ register ->
2112 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2114 code = registerCode register tmp
2115 result = registerName register tmp
2116 target = ImmCLbl lbl
2118 returnUs (code . mkSeqInstr (BF cond result target))
2120 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2122 fltCmpOp op = case op of
2136 (instr, cond) = case op of
2137 FloatGtOp -> (FCMP TF LE, EQQ)
2138 FloatGeOp -> (FCMP TF LTT, EQQ)
2139 FloatEqOp -> (FCMP TF EQQ, NE)
2140 FloatNeOp -> (FCMP TF EQQ, EQQ)
2141 FloatLtOp -> (FCMP TF LTT, NE)
2142 FloatLeOp -> (FCMP TF LE, NE)
2143 DoubleGtOp -> (FCMP TF LE, EQQ)
2144 DoubleGeOp -> (FCMP TF LTT, EQQ)
2145 DoubleEqOp -> (FCMP TF EQQ, NE)
2146 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2147 DoubleLtOp -> (FCMP TF LTT, NE)
2148 DoubleLeOp -> (FCMP TF LE, NE)
2150 genCondJump lbl (StPrim op [x, y])
2151 = trivialCode instr x y `thenUs` \ register ->
2152 getNewRegNCG IntRep `thenUs` \ tmp ->
2154 code = registerCode register tmp
2155 result = registerName register tmp
2156 target = ImmCLbl lbl
2158 returnUs (code . mkSeqInstr (BI cond result target))
2160 (instr, cond) = case op of
2161 CharGtOp -> (CMP LE, EQQ)
2162 CharGeOp -> (CMP LTT, EQQ)
2163 CharEqOp -> (CMP EQQ, NE)
2164 CharNeOp -> (CMP EQQ, EQQ)
2165 CharLtOp -> (CMP LTT, NE)
2166 CharLeOp -> (CMP LE, NE)
2167 IntGtOp -> (CMP LE, EQQ)
2168 IntGeOp -> (CMP LTT, EQQ)
2169 IntEqOp -> (CMP EQQ, NE)
2170 IntNeOp -> (CMP EQQ, EQQ)
2171 IntLtOp -> (CMP LTT, NE)
2172 IntLeOp -> (CMP LE, NE)
2173 WordGtOp -> (CMP ULE, EQQ)
2174 WordGeOp -> (CMP ULT, EQQ)
2175 WordEqOp -> (CMP EQQ, NE)
2176 WordNeOp -> (CMP EQQ, EQQ)
2177 WordLtOp -> (CMP ULT, NE)
2178 WordLeOp -> (CMP ULE, NE)
2179 AddrGtOp -> (CMP ULE, EQQ)
2180 AddrGeOp -> (CMP ULT, EQQ)
2181 AddrEqOp -> (CMP EQQ, NE)
2182 AddrNeOp -> (CMP EQQ, EQQ)
2183 AddrLtOp -> (CMP ULT, NE)
2184 AddrLeOp -> (CMP ULE, NE)
2186 #endif {- alpha_TARGET_ARCH -}
2187 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2188 #if i386_TARGET_ARCH
2190 genCondJump lbl bool
2191 = getCondCode bool `thenUs` \ condition ->
2193 code = condCode condition
2194 cond = condName condition
2195 target = ImmCLbl lbl
2197 returnSeq code [JXX cond lbl]
2199 #endif {- i386_TARGET_ARCH -}
2200 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2201 #if sparc_TARGET_ARCH
2203 genCondJump lbl bool
2204 = getCondCode bool `thenUs` \ condition ->
2206 code = condCode condition
2207 cond = condName condition
2208 target = ImmCLbl lbl
2211 if condFloat condition then
2212 [NOP, BF cond False target, NOP]
2214 [BI cond False target, NOP]
2217 #endif {- sparc_TARGET_ARCH -}
2220 %************************************************************************
2222 \subsection{Generating C calls}
2224 %************************************************************************
2226 Now the biggest nightmare---calls. Most of the nastiness is buried in
2227 @get_arg@, which moves the arguments to the correct registers/stack
2228 locations. Apart from that, the code is easy.
2230 (If applicable) Do not fill the delay slots here; you will confuse the
2235 :: FAST_STRING -- function to call
2236 -> PrimRep -- type of the result
2237 -> [StixTree] -- arguments (of mixed type)
2238 -> UniqSM InstrBlock
2240 #if alpha_TARGET_ARCH
2242 genCCall fn kind args
2243 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2244 `thenUs` \ ((unused,_), argCode) ->
2246 nRegs = length allArgRegs - length unused
2247 code = asmParThen (map ($ asmVoid) argCode)
2250 LDA pv (AddrImm (ImmLab (ptext fn))),
2251 JSR ra (AddrReg pv) nRegs,
2252 LDGP gp (AddrReg ra)]
2254 ------------------------
2255 {- Try to get a value into a specific register (or registers) for
2256 a call. The first 6 arguments go into the appropriate
2257 argument register (separate registers for integer and floating
2258 point arguments, but used in lock-step), and the remaining
2259 arguments are dumped to the stack, beginning at 0(sp). Our
2260 first argument is a pair of the list of remaining argument
2261 registers to be assigned for this call and the next stack
2262 offset to use for overflowing arguments. This way,
2263 @get_Arg@ can be applied to all of a call's arguments using
2267 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2268 -> StixTree -- Current argument
2269 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2271 -- We have to use up all of our argument registers first...
2273 get_arg ((iDst,fDst):dsts, offset) arg
2274 = getRegister arg `thenUs` \ register ->
2276 reg = if isFloatingRep pk then fDst else iDst
2277 code = registerCode register reg
2278 src = registerName register reg
2279 pk = registerRep register
2282 if isFloatingRep pk then
2283 ((dsts, offset), if isFixed register then
2284 code . mkSeqInstr (FMOV src fDst)
2287 ((dsts, offset), if isFixed register then
2288 code . mkSeqInstr (OR src (RIReg src) iDst)
2291 -- Once we have run out of argument registers, we move to the
2294 get_arg ([], offset) arg
2295 = getRegister arg `thenUs` \ register ->
2296 getNewRegNCG (registerRep register)
2299 code = registerCode register tmp
2300 src = registerName register tmp
2301 pk = registerRep register
2302 sz = primRepToSize pk
2304 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2306 #endif {- alpha_TARGET_ARCH -}
2307 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2308 #if i386_TARGET_ARCH
2310 genCCall fn kind [StInt i]
2311 | fn == SLIT ("PerformGC_wrapper")
2313 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2314 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2319 = getUniqLabelNCG `thenUs` \ lbl ->
2321 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2322 MOV L (OpImm (ImmCLbl lbl))
2323 -- this is hardwired
2324 (OpAddr (Address (Just ebx) Nothing (ImmInt 104))),
2325 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2331 genCCall fn kind args
2332 = mapUs get_call_arg args `thenUs` \ argCode ->
2335 {- OLD: Since there's no attempt at stealing %esp at the moment,
2336 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2337 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2338 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (Address (Just ebx) Nothing (ImmInt 80))),
2339 MOV L (OpAddr (Address (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2343 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2344 call = [CALL fn__2 ,
2345 -- pop args; all args word sized?
2346 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2348 -- Don't restore %esp (see above)
2349 -- MOV L (OpAddr (Address (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2352 returnSeq (code2) call
2354 -- function names that begin with '.' are assumed to be special
2355 -- internally generated names like '.mul,' which don't get an
2356 -- underscore prefix
2357 -- ToDo:needed (WDP 96/03) ???
2358 fn__2 = case (_HEAD_ fn) of
2359 '.' -> ImmLit (ptext fn)
2360 _ -> ImmLab (ptext fn)
2363 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2366 = get_op arg `thenUs` \ (code, op, sz) ->
2367 returnUs (code . mkSeqInstr (PUSH sz op))
2372 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2375 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2377 get_op (StInd pk mem)
2378 = getAmode mem `thenUs` \ amode ->
2380 code = amodeCode amode --asmVoid
2381 addr = amodeAddr amode
2382 sz = primRepToSize pk
2384 returnUs (code, OpAddr addr, sz)
2387 = getRegister op `thenUs` \ register ->
2388 getNewRegNCG (registerRep register)
2391 code = registerCode register tmp
2392 reg = registerName register tmp
2393 pk = registerRep register
2394 sz = primRepToSize pk
2396 returnUs (code, OpReg reg, sz)
2398 #endif {- i386_TARGET_ARCH -}
2399 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2400 #if sparc_TARGET_ARCH
2402 genCCall fn kind args
2403 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2404 `thenUs` \ ((unused,_), argCode) ->
2406 nRegs = length allArgRegs - length unused
2407 call = CALL fn__2 nRegs False
2408 code = asmParThen (map ($ asmVoid) argCode)
2410 returnSeq code [call, NOP]
2412 -- function names that begin with '.' are assumed to be special
2413 -- internally generated names like '.mul,' which don't get an
2414 -- underscore prefix
2415 -- ToDo:needed (WDP 96/03) ???
2416 fn__2 = case (_HEAD_ fn) of
2417 '.' -> ImmLit (ptext fn)
2418 _ -> ImmLab (ptext fn)
2420 ------------------------------------
2421 {- Try to get a value into a specific register (or registers) for
2422 a call. The SPARC calling convention is an absolute
2423 nightmare. The first 6x32 bits of arguments are mapped into
2424 %o0 through %o5, and the remaining arguments are dumped to the
2425 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2426 first argument is a pair of the list of remaining argument
2427 registers to be assigned for this call and the next stack
2428 offset to use for overflowing arguments. This way,
2429 @get_arg@ can be applied to all of a call's arguments using
2433 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2434 -> StixTree -- Current argument
2435 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2437 -- We have to use up all of our argument registers first...
2439 get_arg (dst:dsts, offset) arg
2440 = getRegister arg `thenUs` \ register ->
2441 getNewRegNCG (registerRep register)
2444 reg = if isFloatingRep pk then tmp else dst
2445 code = registerCode register reg
2446 src = registerName register reg
2447 pk = registerRep register
2449 returnUs (case pk of
2452 [] -> (([], offset + 1), code . mkSeqInstrs [
2453 -- conveniently put the second part in the right stack
2454 -- location, and load the first part into %o5
2455 ST DF src (spRel (offset - 1)),
2456 LD W (spRel (offset - 1)) dst])
2457 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2458 ST DF src (spRel (-2)),
2459 LD W (spRel (-2)) dst,
2460 LD W (spRel (-1)) dst__2])
2461 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2462 ST F src (spRel (-2)),
2463 LD W (spRel (-2)) dst])
2464 _ -> ((dsts, offset), if isFixed register then
2465 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2468 -- Once we have run out of argument registers, we move to the
2471 get_arg ([], offset) arg
2472 = getRegister arg `thenUs` \ register ->
2473 getNewRegNCG (registerRep register)
2476 code = registerCode register tmp
2477 src = registerName register tmp
2478 pk = registerRep register
2479 sz = primRepToSize pk
2480 words = if pk == DoubleRep then 2 else 1
2482 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2484 #endif {- sparc_TARGET_ARCH -}
2487 %************************************************************************
2489 \subsection{Support bits}
2491 %************************************************************************
2493 %************************************************************************
2495 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2497 %************************************************************************
2499 Turn those condition codes into integers now (when they appear on
2500 the right hand side of an assignment).
2502 (If applicable) Do not fill the delay slots here; you will confuse the
2506 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2508 #if alpha_TARGET_ARCH
2509 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2510 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2511 #endif {- alpha_TARGET_ARCH -}
2513 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2514 #if i386_TARGET_ARCH
2517 = condIntCode cond x y `thenUs` \ condition ->
2518 getNewRegNCG IntRep `thenUs` \ tmp ->
2519 --getRegister dst `thenUs` \ register ->
2521 --code2 = registerCode register tmp asmVoid
2522 --dst__2 = registerName register tmp
2523 code = condCode condition
2524 cond = condName condition
2525 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2526 code__2 dst = code . mkSeqInstrs [
2527 SETCC cond (OpReg tmp),
2528 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2529 MOV L (OpReg tmp) (OpReg dst)]
2531 returnUs (Any IntRep code__2)
2534 = getUniqLabelNCG `thenUs` \ lbl1 ->
2535 getUniqLabelNCG `thenUs` \ lbl2 ->
2536 condFltCode cond x y `thenUs` \ condition ->
2538 code = condCode condition
2539 cond = condName condition
2540 code__2 dst = code . mkSeqInstrs [
2542 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2545 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2548 returnUs (Any IntRep code__2)
2550 #endif {- i386_TARGET_ARCH -}
2551 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2552 #if sparc_TARGET_ARCH
2554 condIntReg EQQ x (StInt 0)
2555 = getRegister x `thenUs` \ register ->
2556 getNewRegNCG IntRep `thenUs` \ tmp ->
2558 code = registerCode register tmp
2559 src = registerName register tmp
2560 code__2 dst = code . mkSeqInstrs [
2561 SUB False True g0 (RIReg src) g0,
2562 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2564 returnUs (Any IntRep code__2)
2567 = getRegister x `thenUs` \ register1 ->
2568 getRegister y `thenUs` \ register2 ->
2569 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2570 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2572 code1 = registerCode register1 tmp1 asmVoid
2573 src1 = registerName register1 tmp1
2574 code2 = registerCode register2 tmp2 asmVoid
2575 src2 = registerName register2 tmp2
2576 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2577 XOR False src1 (RIReg src2) dst,
2578 SUB False True g0 (RIReg dst) g0,
2579 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2581 returnUs (Any IntRep code__2)
2583 condIntReg NE x (StInt 0)
2584 = getRegister x `thenUs` \ register ->
2585 getNewRegNCG IntRep `thenUs` \ tmp ->
2587 code = registerCode register tmp
2588 src = registerName register tmp
2589 code__2 dst = code . mkSeqInstrs [
2590 SUB False True g0 (RIReg src) g0,
2591 ADD True False g0 (RIImm (ImmInt 0)) dst]
2593 returnUs (Any IntRep code__2)
2596 = getRegister x `thenUs` \ register1 ->
2597 getRegister y `thenUs` \ register2 ->
2598 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2599 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2601 code1 = registerCode register1 tmp1 asmVoid
2602 src1 = registerName register1 tmp1
2603 code2 = registerCode register2 tmp2 asmVoid
2604 src2 = registerName register2 tmp2
2605 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2606 XOR False src1 (RIReg src2) dst,
2607 SUB False True g0 (RIReg dst) g0,
2608 ADD True False g0 (RIImm (ImmInt 0)) dst]
2610 returnUs (Any IntRep code__2)
2613 = getUniqLabelNCG `thenUs` \ lbl1 ->
2614 getUniqLabelNCG `thenUs` \ lbl2 ->
2615 condIntCode cond x y `thenUs` \ condition ->
2617 code = condCode condition
2618 cond = condName condition
2619 code__2 dst = code . mkSeqInstrs [
2620 BI cond False (ImmCLbl lbl1), NOP,
2621 OR False g0 (RIImm (ImmInt 0)) dst,
2622 BI ALWAYS False (ImmCLbl lbl2), NOP,
2624 OR False g0 (RIImm (ImmInt 1)) dst,
2627 returnUs (Any IntRep code__2)
2630 = getUniqLabelNCG `thenUs` \ lbl1 ->
2631 getUniqLabelNCG `thenUs` \ lbl2 ->
2632 condFltCode cond x y `thenUs` \ condition ->
2634 code = condCode condition
2635 cond = condName condition
2636 code__2 dst = code . mkSeqInstrs [
2638 BF cond False (ImmCLbl lbl1), NOP,
2639 OR False g0 (RIImm (ImmInt 0)) dst,
2640 BI ALWAYS False (ImmCLbl lbl2), NOP,
2642 OR False g0 (RIImm (ImmInt 1)) dst,
2645 returnUs (Any IntRep code__2)
2647 #endif {- sparc_TARGET_ARCH -}
2650 %************************************************************************
2652 \subsubsection{@trivial*Code@: deal with trivial instructions}
2654 %************************************************************************
2656 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2657 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2658 for constants on the right hand side, because that's where the generic
2659 optimizer will have put them.
2661 Similarly, for unary instructions, we don't have to worry about
2662 matching an StInt as the argument, because genericOpt will already
2663 have handled the constant-folding.
2667 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2668 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2669 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2671 -> StixTree -> StixTree -- the two arguments
2676 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2677 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2679 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2680 (Size -> Operand -> Instr)
2681 -> (Size -> Operand -> Instr) {-reversed instr-}
2683 -> Instr {-reversed instr: pop-}
2685 -> StixTree -> StixTree -- the two arguments
2689 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2690 ,IF_ARCH_i386 ((Operand -> Instr)
2691 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2693 -> StixTree -- the one argument
2698 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2699 ,IF_ARCH_i386 (Instr
2700 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2702 -> StixTree -- the one argument
2705 #if alpha_TARGET_ARCH
2707 trivialCode instr x (StInt y)
2709 = getRegister x `thenUs` \ register ->
2710 getNewRegNCG IntRep `thenUs` \ tmp ->
2712 code = registerCode register tmp
2713 src1 = registerName register tmp
2714 src2 = ImmInt (fromInteger y)
2715 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2717 returnUs (Any IntRep code__2)
2719 trivialCode instr x y
2720 = getRegister x `thenUs` \ register1 ->
2721 getRegister y `thenUs` \ register2 ->
2722 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2723 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2725 code1 = registerCode register1 tmp1 asmVoid
2726 src1 = registerName register1 tmp1
2727 code2 = registerCode register2 tmp2 asmVoid
2728 src2 = registerName register2 tmp2
2729 code__2 dst = asmParThen [code1, code2] .
2730 mkSeqInstr (instr src1 (RIReg src2) dst)
2732 returnUs (Any IntRep code__2)
2735 trivialUCode instr x
2736 = getRegister x `thenUs` \ register ->
2737 getNewRegNCG IntRep `thenUs` \ tmp ->
2739 code = registerCode register tmp
2740 src = registerName register tmp
2741 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2743 returnUs (Any IntRep code__2)
2746 trivialFCode _ instr x y
2747 = getRegister x `thenUs` \ register1 ->
2748 getRegister y `thenUs` \ register2 ->
2749 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2750 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2752 code1 = registerCode register1 tmp1
2753 src1 = registerName register1 tmp1
2755 code2 = registerCode register2 tmp2
2756 src2 = registerName register2 tmp2
2758 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2759 mkSeqInstr (instr src1 src2 dst)
2761 returnUs (Any DoubleRep code__2)
2763 trivialUFCode _ instr x
2764 = getRegister x `thenUs` \ register ->
2765 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2767 code = registerCode register tmp
2768 src = registerName register tmp
2769 code__2 dst = code . mkSeqInstr (instr src dst)
2771 returnUs (Any DoubleRep code__2)
2773 #endif {- alpha_TARGET_ARCH -}
2774 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2775 #if i386_TARGET_ARCH
2777 trivialCode instr x y
2779 = getRegister x `thenUs` \ register1 ->
2780 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2782 -- fixedname = registerName register1 eax
2783 code__2 dst = let code1 = registerCode register1 dst
2784 src1 = registerName register1 dst
2786 if isFixed register1 && src1 /= dst
2787 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2788 instr (OpImm imm__2) (OpReg dst)]
2790 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2792 returnUs (Any IntRep code__2)
2795 imm__2 = case imm of Just x -> x
2797 trivialCode instr x y
2799 = getRegister y `thenUs` \ register1 ->
2800 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2802 -- fixedname = registerName register1 eax
2803 code__2 dst = let code1 = registerCode register1 dst
2804 src1 = registerName register1 dst
2806 if isFixed register1 && src1 /= dst
2807 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2808 instr (OpImm imm__2) (OpReg dst)]
2810 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2812 returnUs (Any IntRep code__2)
2815 imm__2 = case imm of Just x -> x
2817 trivialCode instr x (StInd pk mem)
2818 = getRegister x `thenUs` \ register ->
2819 --getNewRegNCG IntRep `thenUs` \ tmp ->
2820 getAmode mem `thenUs` \ amode ->
2822 -- fixedname = registerName register eax
2823 code2 = amodeCode amode asmVoid
2824 src2 = amodeAddr amode
2825 code__2 dst = let code1 = registerCode register dst asmVoid
2826 src1 = registerName register dst
2827 in asmParThen [code1, code2] .
2828 if isFixed register && src1 /= dst
2829 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2830 instr (OpAddr src2) (OpReg dst)]
2832 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2834 returnUs (Any pk code__2)
2836 trivialCode instr (StInd pk mem) y
2837 = getRegister y `thenUs` \ register ->
2838 --getNewRegNCG IntRep `thenUs` \ tmp ->
2839 getAmode mem `thenUs` \ amode ->
2841 -- fixedname = registerName register eax
2842 code2 = amodeCode amode asmVoid
2843 src2 = amodeAddr amode
2845 code1 = registerCode register dst asmVoid
2846 src1 = registerName register dst
2847 in asmParThen [code1, code2] .
2848 if isFixed register && src1 /= dst
2849 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2850 instr (OpAddr src2) (OpReg dst)]
2852 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2854 returnUs (Any pk code__2)
2856 trivialCode instr x y
2857 = getRegister x `thenUs` \ register1 ->
2858 getRegister y `thenUs` \ register2 ->
2859 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2860 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2862 -- fixedname = registerName register1 eax
2863 code2 = registerCode register2 tmp2 asmVoid
2864 src2 = registerName register2 tmp2
2866 code1 = registerCode register1 dst asmVoid
2867 src1 = registerName register1 dst
2868 in asmParThen [code1, code2] .
2869 if isFixed register1 && src1 /= dst
2870 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2871 instr (OpReg src2) (OpReg dst)]
2873 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2875 returnUs (Any IntRep code__2)
2878 trivialUCode instr x
2879 = getRegister x `thenUs` \ register ->
2880 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2882 -- fixedname = registerName register eax
2884 code = registerCode register dst
2885 src = registerName register dst
2886 in code . if isFixed register && dst /= src
2887 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2889 else mkSeqInstr (instr (OpReg src))
2891 returnUs (Any IntRep code__2)
2894 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2895 = getRegister y `thenUs` \ register2 ->
2896 --getNewRegNCG (registerRep register2)
2897 -- `thenUs` \ tmp2 ->
2898 getAmode mem `thenUs` \ amode ->
2900 code1 = amodeCode amode
2901 src1 = amodeAddr amode
2904 code2 = registerCode register2 dst
2905 src2 = registerName register2 dst
2906 in asmParThen [code1 asmVoid,code2 asmVoid] .
2907 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2909 returnUs (Any pk code__2)
2911 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2912 = getRegister x `thenUs` \ register1 ->
2913 --getNewRegNCG (registerRep register1)
2914 -- `thenUs` \ tmp1 ->
2915 getAmode mem `thenUs` \ amode ->
2917 code2 = amodeCode amode
2918 src2 = amodeAddr amode
2921 code1 = registerCode register1 dst
2922 src1 = registerName register1 dst
2923 in asmParThen [code2 asmVoid,code1 asmVoid] .
2924 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2926 returnUs (Any pk code__2)
2928 trivialFCode pk _ _ _ instrpr x y
2929 = getRegister x `thenUs` \ register1 ->
2930 getRegister y `thenUs` \ register2 ->
2931 --getNewRegNCG (registerRep register1)
2932 -- `thenUs` \ tmp1 ->
2933 --getNewRegNCG (registerRep register2)
2934 -- `thenUs` \ tmp2 ->
2935 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2937 pk1 = registerRep register1
2938 code1 = registerCode register1 st0 --tmp1
2939 src1 = registerName register1 st0 --tmp1
2941 pk2 = registerRep register2
2944 code2 = registerCode register2 dst
2945 src2 = registerName register2 dst
2946 in asmParThen [code1 asmVoid, code2 asmVoid] .
2949 returnUs (Any pk1 code__2)
2952 trivialUFCode pk instr (StInd pk' mem)
2953 = getAmode mem `thenUs` \ amode ->
2955 code = amodeCode amode
2956 src = amodeAddr amode
2957 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2960 returnUs (Any pk code__2)
2962 trivialUFCode pk instr x
2963 = getRegister x `thenUs` \ register ->
2964 --getNewRegNCG pk `thenUs` \ tmp ->
2967 code = registerCode register dst
2968 src = registerName register dst
2969 in code . mkSeqInstrs [instr]
2971 returnUs (Any pk code__2)
2973 #endif {- i386_TARGET_ARCH -}
2974 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2975 #if sparc_TARGET_ARCH
2977 trivialCode instr x (StInt y)
2979 = getRegister x `thenUs` \ register ->
2980 getNewRegNCG IntRep `thenUs` \ tmp ->
2982 code = registerCode register tmp
2983 src1 = registerName register tmp
2984 src2 = ImmInt (fromInteger y)
2985 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2987 returnUs (Any IntRep code__2)
2989 trivialCode instr x y
2990 = getRegister x `thenUs` \ register1 ->
2991 getRegister y `thenUs` \ register2 ->
2992 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2993 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2995 code1 = registerCode register1 tmp1 asmVoid
2996 src1 = registerName register1 tmp1
2997 code2 = registerCode register2 tmp2 asmVoid
2998 src2 = registerName register2 tmp2
2999 code__2 dst = asmParThen [code1, code2] .
3000 mkSeqInstr (instr src1 (RIReg src2) dst)
3002 returnUs (Any IntRep code__2)
3005 trivialFCode pk instr x y
3006 = getRegister x `thenUs` \ register1 ->
3007 getRegister y `thenUs` \ register2 ->
3008 getNewRegNCG (registerRep register1)
3010 getNewRegNCG (registerRep register2)
3012 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3014 promote x = asmInstr (FxTOy F DF x tmp)
3016 pk1 = registerRep register1
3017 code1 = registerCode register1 tmp1
3018 src1 = registerName register1 tmp1
3020 pk2 = registerRep register2
3021 code2 = registerCode register2 tmp2
3022 src2 = registerName register2 tmp2
3026 asmParThen [code1 asmVoid, code2 asmVoid] .
3027 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3028 else if pk1 == FloatRep then
3029 asmParThen [code1 (promote src1), code2 asmVoid] .
3030 mkSeqInstr (instr DF tmp src2 dst)
3032 asmParThen [code1 asmVoid, code2 (promote src2)] .
3033 mkSeqInstr (instr DF src1 tmp dst)
3035 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3038 trivialUCode instr x
3039 = getRegister x `thenUs` \ register ->
3040 getNewRegNCG IntRep `thenUs` \ tmp ->
3042 code = registerCode register tmp
3043 src = registerName register tmp
3044 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3046 returnUs (Any IntRep code__2)
3049 trivialUFCode pk instr x
3050 = getRegister x `thenUs` \ register ->
3051 getNewRegNCG pk `thenUs` \ tmp ->
3053 code = registerCode register tmp
3054 src = registerName register tmp
3055 code__2 dst = code . mkSeqInstr (instr src dst)
3057 returnUs (Any pk code__2)
3059 #endif {- sparc_TARGET_ARCH -}
3062 %************************************************************************
3064 \subsubsection{Coercing to/from integer/floating-point...}
3066 %************************************************************************
3068 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3069 to be generated. Here we just change the type on the Register passed
3070 on up. The code is machine-independent.
3072 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3073 conversions. We have to store temporaries in memory to move
3074 between the integer and the floating point register sets.
3077 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3078 coerceFltCode :: StixTree -> UniqSM Register
3080 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3081 coerceFP2Int :: StixTree -> UniqSM Register
3084 = getRegister x `thenUs` \ register ->
3087 Fixed _ reg code -> Fixed pk reg code
3088 Any _ code -> Any pk code
3093 = getRegister x `thenUs` \ register ->
3096 Fixed _ reg code -> Fixed DoubleRep reg code
3097 Any _ code -> Any DoubleRep code
3102 #if alpha_TARGET_ARCH
3105 = getRegister x `thenUs` \ register ->
3106 getNewRegNCG IntRep `thenUs` \ reg ->
3108 code = registerCode register reg
3109 src = registerName register reg
3111 code__2 dst = code . mkSeqInstrs [
3113 LD TF dst (spRel 0),
3116 returnUs (Any DoubleRep code__2)
3120 = getRegister x `thenUs` \ register ->
3121 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3123 code = registerCode register tmp
3124 src = registerName register tmp
3126 code__2 dst = code . mkSeqInstrs [
3128 ST TF tmp (spRel 0),
3131 returnUs (Any IntRep code__2)
3133 #endif {- alpha_TARGET_ARCH -}
3134 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3135 #if i386_TARGET_ARCH
3138 = getRegister x `thenUs` \ register ->
3139 getNewRegNCG IntRep `thenUs` \ reg ->
3141 code = registerCode register reg
3142 src = registerName register reg
3144 code__2 dst = code . mkSeqInstrs [
3145 -- to fix: should spill instead of using R1
3146 MOV L (OpReg src) (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))),
3147 FILD (primRepToSize pk) (Address (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3149 returnUs (Any pk code__2)
3153 = getRegister x `thenUs` \ register ->
3154 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3156 code = registerCode register tmp
3157 src = registerName register tmp
3158 pk = registerRep register
3161 in code . mkSeqInstrs [
3163 FIST L (Address (Just ebx) Nothing (ImmInt OFFSET_R1)),
3164 MOV L (OpAddr (Address (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3166 returnUs (Any IntRep code__2)
3168 #endif {- i386_TARGET_ARCH -}
3169 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3170 #if sparc_TARGET_ARCH
3173 = getRegister x `thenUs` \ register ->
3174 getNewRegNCG IntRep `thenUs` \ reg ->
3176 code = registerCode register reg
3177 src = registerName register reg
3179 code__2 dst = code . mkSeqInstrs [
3180 ST W src (spRel (-2)),
3181 LD W (spRel (-2)) dst,
3182 FxTOy W (primRepToSize pk) dst dst]
3184 returnUs (Any pk code__2)
3188 = getRegister x `thenUs` \ register ->
3189 getNewRegNCG IntRep `thenUs` \ reg ->
3190 getNewRegNCG FloatRep `thenUs` \ tmp ->
3192 code = registerCode register reg
3193 src = registerName register reg
3194 pk = registerRep register
3196 code__2 dst = code . mkSeqInstrs [
3197 FxTOy (primRepToSize pk) W src tmp,
3198 ST W tmp (spRel (-2)),
3199 LD W (spRel (-2)) dst]
3201 returnUs (Any IntRep code__2)
3203 #endif {- sparc_TARGET_ARCH -}
3206 %************************************************************************
3208 \subsubsection{Coercing integer to @Char@...}
3210 %************************************************************************
3212 Integer to character conversion. Where applicable, we try to do this
3213 in one step if the original object is in memory.
3216 chrCode :: StixTree -> UniqSM Register
3218 #if alpha_TARGET_ARCH
3221 = getRegister x `thenUs` \ register ->
3222 getNewRegNCG IntRep `thenUs` \ reg ->
3224 code = registerCode register reg
3225 src = registerName register reg
3226 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3228 returnUs (Any IntRep code__2)
3230 #endif {- alpha_TARGET_ARCH -}
3231 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3232 #if i386_TARGET_ARCH
3235 = getRegister x `thenUs` \ register ->
3236 --getNewRegNCG IntRep `thenUs` \ reg ->
3238 -- fixedname = registerName register eax
3240 code = registerCode register dst
3241 src = registerName register dst
3243 if isFixed register && src /= dst
3244 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3245 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3246 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3248 returnUs (Any IntRep code__2)
3250 #endif {- i386_TARGET_ARCH -}
3251 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3252 #if sparc_TARGET_ARCH
3254 chrCode (StInd pk mem)
3255 = getAmode mem `thenUs` \ amode ->
3257 code = amodeCode amode
3258 src = amodeAddr amode
3259 src_off = addrOffset src 3
3260 src__2 = case src_off of Just x -> x
3261 code__2 dst = if maybeToBool src_off then
3262 code . mkSeqInstr (LD BU src__2 dst)
3264 code . mkSeqInstrs [
3265 LD (primRepToSize pk) src dst,
3266 AND False dst (RIImm (ImmInt 255)) dst]
3268 returnUs (Any pk code__2)
3271 = getRegister x `thenUs` \ register ->
3272 getNewRegNCG IntRep `thenUs` \ reg ->
3274 code = registerCode register reg
3275 src = registerName register reg
3276 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3278 returnUs (Any IntRep code__2)
3280 #endif {- sparc_TARGET_ARCH -}
3283 %************************************************************************
3285 \subsubsection{Absolute value on integers}
3287 %************************************************************************
3289 Absolute value on integers, mostly for gmp size check macros. Again,
3290 the argument cannot be an StInt, because genericOpt already folded
3293 If applicable, do not fill the delay slots here; you will confuse the
3297 absIntCode :: StixTree -> UniqSM Register
3299 #if alpha_TARGET_ARCH
3300 absIntCode = panic "MachCode.absIntCode: not on Alphas"
3301 #endif {- alpha_TARGET_ARCH -}
3303 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3304 #if i386_TARGET_ARCH
3307 = getRegister x `thenUs` \ register ->
3308 --getNewRegNCG IntRep `thenUs` \ reg ->
3309 getUniqLabelNCG `thenUs` \ lbl ->
3311 code__2 dst = let code = registerCode register dst
3312 src = registerName register dst
3313 in code . if isFixed register && dst /= src
3314 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3315 TEST L (OpReg dst) (OpReg dst),
3319 else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
3324 returnUs (Any IntRep code__2)
3326 #endif {- i386_TARGET_ARCH -}
3327 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3328 #if sparc_TARGET_ARCH
3331 = getRegister x `thenUs` \ register ->
3332 getNewRegNCG IntRep `thenUs` \ reg ->
3333 getUniqLabelNCG `thenUs` \ lbl ->
3335 code = registerCode register reg
3336 src = registerName register reg
3337 code__2 dst = code . mkSeqInstrs [
3338 SUB False True g0 (RIReg src) dst,
3339 BI GE False (ImmCLbl lbl), NOP,
3340 OR False g0 (RIReg src) dst,
3343 returnUs (Any IntRep code__2)
3345 #endif {- sparc_TARGET_ARCH -}