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 module MachCode ( stmt2Instrs, asmVoid, InstrList ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
20 import AbsCSyn ( MagicId )
21 import AbsCUtils ( magicIdPrimRep )
22 import CLabel ( isAsmTemp, CLabel )
23 import Maybes ( maybeToBool, expectJust )
24 import OrdList -- quite a bit of it
25 import PrimRep ( isFloatingRep, PrimRep(..) )
26 import PrimOp ( PrimOp(..), showPrimOp )
27 import Stix ( getUniqLabelNCG, StixTree(..),
28 StixReg(..), CodeSegment(..)
30 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
36 Code extractor for an entire stix tree---stix statement level.
39 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
41 stmt2Instrs stmt = case stmt of
42 StComment s -> returnInstr (COMMENT s)
43 StSegment seg -> returnInstr (SEGMENT seg)
44 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
45 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
46 StLabel lab -> returnInstr (LABEL lab)
48 StJump arg -> genJump arg
49 StCondJump lab arg -> genCondJump lab arg
50 StCall fn VoidRep args -> genCCall fn VoidRep args
53 | isFloatingRep pk -> assignFltCode pk dst src
54 | otherwise -> assignIntCode pk dst src
57 -- When falling through on the Alpha, we still have to load pv
58 -- with the address of the next routine, so that it can load gp.
59 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
63 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
64 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
65 (foldr1 (.) codes xs))
67 getData :: StixTree -> UniqSM (InstrBlock, Imm)
69 getData (StInt i) = returnUs (id, ImmInteger i)
70 getData (StDouble d) = returnUs (id, dblImmLit d)
71 getData (StLitLbl s) = returnUs (id, ImmLab s)
72 getData (StLitLit s) = returnUs (id, strImmLit (cvtLitLit (_UNPK_ s)))
73 getData (StCLbl l) = returnUs (id, ImmCLbl l)
74 getData (StString s) =
75 getUniqLabelNCG `thenUs` \ lbl ->
76 returnUs (mkSeqInstrs [LABEL lbl,
77 ASCII True (_UNPK_ s)],
81 %************************************************************************
83 \subsection{General things for putting together code sequences}
85 %************************************************************************
88 type InstrList = OrdList Instr
89 type InstrBlock = InstrList -> InstrList
94 asmInstr :: Instr -> InstrList
95 asmInstr i = mkUnitList i
97 asmSeq :: [Instr] -> InstrList
98 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
100 asmParThen :: [InstrList] -> InstrBlock
101 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
103 returnInstr :: Instr -> UniqSM InstrBlock
104 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
106 returnInstrs :: [Instr] -> UniqSM InstrBlock
107 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
109 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
110 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
112 mkSeqInstr :: Instr -> InstrBlock
113 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
115 mkSeqInstrs :: [Instr] -> InstrBlock
116 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
120 mangleIndexTree :: StixTree -> StixTree
122 mangleIndexTree (StIndex pk base (StInt i))
123 = StPrim IntAddOp [base, off]
125 off = StInt (i * sizeOf pk)
127 #ifndef i386_TARGET_ARCH
128 mangleIndexTree (StIndex pk base off)
129 = StPrim IntAddOp [base,
135 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
136 StPrim SllOp [off, StInt s]
139 shift DoubleRep = 3::Integer
140 shift _ = IF_ARCH_alpha(3,2)
142 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
143 -- that do include the size of the primitive kind we're addressing. When StIndex
144 -- is expanded to actual code, the index (in units) is by the above code approp.
145 -- shifted to get the no. of bytes. Since Address amodes do contain size info
146 -- explicitly, we disable the shifting for x86s.
147 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
153 maybeImm :: StixTree -> Maybe Imm
155 maybeImm (StLitLbl s) = Just (ImmLab s)
156 maybeImm (StLitLit s) = Just (strImmLit (cvtLitLit (_UNPK_ s)))
157 maybeImm (StCLbl l) = Just (ImmCLbl l)
160 | i >= toInteger minInt && i <= toInteger maxInt
161 = Just (ImmInt (fromInteger i))
163 = Just (ImmInteger i)
168 %************************************************************************
170 \subsection{The @Register@ type}
172 %************************************************************************
174 @Register@s passed up the tree. If the stix code forces the register
175 to live in a pre-decided machine register, it comes out as @Fixed@;
176 otherwise, it comes out as @Any@, and the parent can decide which
177 register to put it in.
181 = Fixed PrimRep Reg InstrBlock
182 | Any PrimRep (Reg -> InstrBlock)
184 registerCode :: Register -> Reg -> InstrBlock
185 registerCode (Fixed _ _ code) reg = code
186 registerCode (Any _ code) reg = code reg
188 registerName :: Register -> Reg -> Reg
189 registerName (Fixed _ reg _) _ = reg
190 registerName (Any _ _) reg = reg
192 registerRep :: Register -> PrimRep
193 registerRep (Fixed pk _ _) = pk
194 registerRep (Any pk _) = pk
196 isFixed :: Register -> Bool
197 isFixed (Fixed _ _ _) = True
198 isFixed (Any _ _) = False
201 Generate code to get a subtree into a @Register@:
203 getRegister :: StixTree -> UniqSM Register
205 getRegister (StReg (StixMagicId stgreg))
206 = case (magicIdRegMaybe stgreg) of
207 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
210 getRegister (StReg (StixTemp u pk))
211 = returnUs (Fixed pk (UnmappedReg u pk) id)
213 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
215 getRegister (StCall fn kind args)
216 = genCCall fn kind args `thenUs` \ call ->
217 returnUs (Fixed kind reg call)
219 reg = if isFloatingRep kind
220 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
221 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
223 getRegister (StString s)
224 = getUniqLabelNCG `thenUs` \ lbl ->
226 imm_lbl = ImmCLbl lbl
228 code dst = mkSeqInstrs [
231 ASCII True (_UNPK_ s),
233 #if alpha_TARGET_ARCH
234 LDA dst (AddrImm imm_lbl)
237 MOV L (OpImm imm_lbl) (OpReg dst)
239 #if sparc_TARGET_ARCH
240 SETHI (HI imm_lbl) dst,
241 OR False dst (RIImm (LO imm_lbl)) dst
245 returnUs (Any PtrRep code)
247 getRegister (StLitLit s) | _HEAD_ s == '"' && last xs == '"'
248 = getUniqLabelNCG `thenUs` \ lbl ->
250 imm_lbl = ImmCLbl lbl
252 code dst = mkSeqInstrs [
255 ASCII False (init xs),
257 #if alpha_TARGET_ARCH
258 LDA dst (AddrImm imm_lbl)
261 MOV L (OpImm imm_lbl) (OpReg dst)
263 #if sparc_TARGET_ARCH
264 SETHI (HI imm_lbl) dst,
265 OR False dst (RIImm (LO imm_lbl)) dst
269 returnUs (Any PtrRep code)
271 xs = _UNPK_ (_TAIL_ s)
273 -- end of machine-"independent" bit; here we go on the rest...
275 #if alpha_TARGET_ARCH
277 getRegister (StDouble d)
278 = getUniqLabelNCG `thenUs` \ lbl ->
279 getNewRegNCG PtrRep `thenUs` \ tmp ->
280 let code dst = mkSeqInstrs [
283 DATA TF [ImmLab (rational d)],
285 LDA tmp (AddrImm (ImmCLbl lbl)),
286 LD TF dst (AddrReg tmp)]
288 returnUs (Any DoubleRep code)
290 getRegister (StPrim primop [x]) -- unary PrimOps
292 IntNegOp -> trivialUCode (NEG Q False) x
293 IntAbsOp -> trivialUCode (ABS Q) x
295 NotOp -> trivialUCode NOT x
297 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
298 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
300 OrdOp -> coerceIntCode IntRep x
303 Float2IntOp -> coerceFP2Int x
304 Int2FloatOp -> coerceInt2FP pr x
305 Double2IntOp -> coerceFP2Int x
306 Int2DoubleOp -> coerceInt2FP pr x
308 Double2FloatOp -> coerceFltCode x
309 Float2DoubleOp -> coerceFltCode x
311 other_op -> getRegister (StCall fn DoubleRep [x])
313 fn = case other_op of
314 FloatExpOp -> SLIT("exp")
315 FloatLogOp -> SLIT("log")
316 FloatSqrtOp -> SLIT("sqrt")
317 FloatSinOp -> SLIT("sin")
318 FloatCosOp -> SLIT("cos")
319 FloatTanOp -> SLIT("tan")
320 FloatAsinOp -> SLIT("asin")
321 FloatAcosOp -> SLIT("acos")
322 FloatAtanOp -> SLIT("atan")
323 FloatSinhOp -> SLIT("sinh")
324 FloatCoshOp -> SLIT("cosh")
325 FloatTanhOp -> SLIT("tanh")
326 DoubleExpOp -> SLIT("exp")
327 DoubleLogOp -> SLIT("log")
328 DoubleSqrtOp -> SLIT("sqrt")
329 DoubleSinOp -> SLIT("sin")
330 DoubleCosOp -> SLIT("cos")
331 DoubleTanOp -> SLIT("tan")
332 DoubleAsinOp -> SLIT("asin")
333 DoubleAcosOp -> SLIT("acos")
334 DoubleAtanOp -> SLIT("atan")
335 DoubleSinhOp -> SLIT("sinh")
336 DoubleCoshOp -> SLIT("cosh")
337 DoubleTanhOp -> SLIT("tanh")
339 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
341 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
343 CharGtOp -> trivialCode (CMP LTT) y x
344 CharGeOp -> trivialCode (CMP LE) y x
345 CharEqOp -> trivialCode (CMP EQQ) x y
346 CharNeOp -> int_NE_code x y
347 CharLtOp -> trivialCode (CMP LTT) x y
348 CharLeOp -> trivialCode (CMP LE) x y
350 IntGtOp -> trivialCode (CMP LTT) y x
351 IntGeOp -> trivialCode (CMP LE) y x
352 IntEqOp -> trivialCode (CMP EQQ) x y
353 IntNeOp -> int_NE_code x y
354 IntLtOp -> trivialCode (CMP LTT) x y
355 IntLeOp -> trivialCode (CMP LE) x y
357 WordGtOp -> trivialCode (CMP ULT) y x
358 WordGeOp -> trivialCode (CMP ULE) x y
359 WordEqOp -> trivialCode (CMP EQQ) x y
360 WordNeOp -> int_NE_code x y
361 WordLtOp -> trivialCode (CMP ULT) x y
362 WordLeOp -> trivialCode (CMP ULE) x y
364 AddrGtOp -> trivialCode (CMP ULT) y x
365 AddrGeOp -> trivialCode (CMP ULE) y x
366 AddrEqOp -> trivialCode (CMP EQQ) x y
367 AddrNeOp -> int_NE_code x y
368 AddrLtOp -> trivialCode (CMP ULT) x y
369 AddrLeOp -> trivialCode (CMP ULE) x y
371 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
372 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
373 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
374 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
375 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
376 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
378 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
379 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
380 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
381 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
382 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
383 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
385 IntAddOp -> trivialCode (ADD Q False) x y
386 IntSubOp -> trivialCode (SUB Q False) x y
387 IntMulOp -> trivialCode (MUL Q False) x y
388 IntQuotOp -> trivialCode (DIV Q False) x y
389 IntRemOp -> trivialCode (REM Q False) x y
391 WordQuotOp -> trivialCode (DIV Q True) x y
392 WordRemOp -> trivialCode (REM Q True) x y
394 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
395 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
396 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
397 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
399 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
400 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
401 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
402 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
404 AndOp -> trivialCode AND x y
405 OrOp -> trivialCode OR x y
406 XorOp -> trivialCode XOR 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-}
665 XorOp -> trivialCode (XOR L) x y {-True-}
667 {- Shift ops on x86s have constraints on their source, it
668 either has to be Imm, CL or 1
669 => trivialCode's is not restrictive enough (sigh.)
672 SllOp -> shift_code (SHL L) x y {-False-}
673 SraOp -> shift_code (SAR L) x y {-False-}
674 SrlOp -> shift_code (SHR L) x y {-False-}
677 ISllOp -> panic "I386Gen:isll"
678 ISraOp -> panic "I386Gen:isra"
679 ISrlOp -> panic "I386Gen:isrl"
681 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
682 where promote x = StPrim Float2DoubleOp [x]
683 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
685 shift_code :: (Operand -> Operand -> Instr)
689 {- Case1: shift length as immediate -}
690 -- Code is the same as the first eq. for trivialCode -- sigh.
691 shift_code instr x y{-amount-}
693 = getRegister x `thenUs` \ register ->
695 op_imm = OpImm imm__2
698 code = registerCode register dst
699 src = registerName register dst
701 mkSeqInstr (COMMENT SLIT("shift_code")) .
703 if isFixed register && src /= dst
705 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
706 instr op_imm (OpReg dst)]
708 mkSeqInstr (instr op_imm (OpReg src))
710 returnUs (Any IntRep code__2)
713 imm__2 = case imm of Just x -> x
715 {- Case2: shift length is complex (non-immediate) -}
716 shift_code instr x y{-amount-}
717 = getRegister y `thenUs` \ register1 ->
718 getRegister x `thenUs` \ register2 ->
719 -- getNewRegNCG IntRep `thenUs` \ dst ->
721 -- Note: we force the shift length to be loaded
722 -- into ECX, so that we can use CL when shifting.
723 -- (only register location we are allowed
724 -- to put shift amounts.)
726 -- The shift instruction is fed ECX as src reg,
727 -- but we coerce this into CL when printing out.
728 src1 = registerName register1 ecx
729 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
730 registerCode register1 ecx .
731 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
733 registerCode register1 ecx
736 code2 = registerCode register2 eax
737 src2 = registerName register2 eax
740 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
742 returnUs (Fixed IntRep eax code__2)
744 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
746 add_code sz x (StInt y)
747 = getRegister x `thenUs` \ register ->
748 getNewRegNCG IntRep `thenUs` \ tmp ->
750 code = registerCode register tmp
751 src1 = registerName register tmp
752 src2 = ImmInt (fromInteger y)
754 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
756 returnUs (Any IntRep code__2)
758 add_code sz x (StInd _ mem)
759 = getRegister x `thenUs` \ register1 ->
760 --getNewRegNCG (registerRep register1)
761 -- `thenUs` \ tmp1 ->
762 getAmode mem `thenUs` \ amode ->
764 code2 = amodeCode amode
765 src2 = amodeAddr amode
767 -- fixedname = registerName register1 eax
768 code__2 dst = let code1 = registerCode register1 dst
769 src1 = registerName register1 dst
770 in asmParThen [code2 asmVoid,code1 asmVoid] .
771 if isFixed register1 && src1 /= dst
772 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
773 ADD sz (OpAddr src2) (OpReg dst)]
775 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
777 returnUs (Any IntRep code__2)
779 add_code sz (StInd _ mem) y
780 = getRegister y `thenUs` \ register2 ->
781 --getNewRegNCG (registerRep register2)
782 -- `thenUs` \ tmp2 ->
783 getAmode mem `thenUs` \ amode ->
785 code1 = amodeCode amode
786 src1 = amodeAddr amode
788 -- fixedname = registerName register2 eax
789 code__2 dst = let code2 = registerCode register2 dst
790 src2 = registerName register2 dst
791 in asmParThen [code1 asmVoid,code2 asmVoid] .
792 if isFixed register2 && src2 /= dst
793 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
794 ADD sz (OpAddr src1) (OpReg dst)]
796 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
798 returnUs (Any IntRep code__2)
801 = getRegister x `thenUs` \ register1 ->
802 getRegister y `thenUs` \ register2 ->
803 getNewRegNCG IntRep `thenUs` \ tmp1 ->
804 getNewRegNCG IntRep `thenUs` \ tmp2 ->
806 code1 = registerCode register1 tmp1 asmVoid
807 src1 = registerName register1 tmp1
808 code2 = registerCode register2 tmp2 asmVoid
809 src2 = registerName register2 tmp2
810 code__2 dst = asmParThen [code1, code2] .
811 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
813 returnUs (Any IntRep code__2)
816 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
818 sub_code sz x (StInt y)
819 = getRegister x `thenUs` \ register ->
820 getNewRegNCG IntRep `thenUs` \ tmp ->
822 code = registerCode register tmp
823 src1 = registerName register tmp
824 src2 = ImmInt (-(fromInteger y))
826 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
828 returnUs (Any IntRep code__2)
830 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
835 -> StixTree -> StixTree
836 -> Bool -- True => division, False => remainder operation
839 -- x must go into eax, edx must be a sign-extension of eax, and y
840 -- should go in some other register (or memory), so that we get
841 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
842 -- put y in memory (if it is not there already)
844 quot_code sz x (StInd pk mem) is_division
845 = getRegister x `thenUs` \ register1 ->
846 getNewRegNCG IntRep `thenUs` \ tmp1 ->
847 getAmode mem `thenUs` \ amode ->
849 code1 = registerCode register1 tmp1 asmVoid
850 src1 = registerName register1 tmp1
851 code2 = amodeCode amode asmVoid
852 src2 = amodeAddr amode
853 code__2 = asmParThen [code1, code2] .
854 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
856 IDIV sz (OpAddr src2)]
858 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
860 quot_code sz x (StInt i) is_division
861 = getRegister x `thenUs` \ register1 ->
862 getNewRegNCG IntRep `thenUs` \ tmp1 ->
864 code1 = registerCode register1 tmp1 asmVoid
865 src1 = registerName register1 tmp1
866 src2 = ImmInt (fromInteger i)
867 code__2 = asmParThen [code1] .
868 mkSeqInstrs [-- we put src2 in (ebx)
869 MOV L (OpImm src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
870 MOV L (OpReg src1) (OpReg eax),
872 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
874 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
876 quot_code sz x y is_division
877 = getRegister x `thenUs` \ register1 ->
878 getNewRegNCG IntRep `thenUs` \ tmp1 ->
879 getRegister y `thenUs` \ register2 ->
880 getNewRegNCG IntRep `thenUs` \ tmp2 ->
882 code1 = registerCode register1 tmp1 asmVoid
883 src1 = registerName register1 tmp1
884 code2 = registerCode register2 tmp2 asmVoid
885 src2 = registerName register2 tmp2
886 code__2 = asmParThen [code1, code2] .
887 if src2 == ecx || src2 == esi
888 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
890 IDIV sz (OpReg src2)]
891 else mkSeqInstrs [ -- we put src2 in (ebx)
892 MOV L (OpReg src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
893 MOV L (OpReg src1) (OpReg eax),
895 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
897 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
898 -----------------------
900 getRegister (StInd pk mem)
901 = getAmode mem `thenUs` \ amode ->
903 code = amodeCode amode
904 src = amodeAddr amode
905 size = primRepToSize pk
907 if pk == DoubleRep || pk == FloatRep
908 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
909 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
911 returnUs (Any pk code__2)
914 getRegister (StInt i)
916 src = ImmInt (fromInteger i)
917 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
919 returnUs (Any IntRep code)
924 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
926 returnUs (Any PtrRep code)
929 imm__2 = case imm of Just x -> x
931 #endif {- i386_TARGET_ARCH -}
932 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
933 #if sparc_TARGET_ARCH
935 getRegister (StDouble d)
936 = getUniqLabelNCG `thenUs` \ lbl ->
937 getNewRegNCG PtrRep `thenUs` \ tmp ->
938 let code dst = mkSeqInstrs [
941 DATA DF [dblImmLit d],
943 SETHI (HI (ImmCLbl lbl)) tmp,
944 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
946 returnUs (Any DoubleRep code)
948 getRegister (StPrim primop [x]) -- unary PrimOps
950 IntNegOp -> trivialUCode (SUB False False g0) x
951 IntAbsOp -> absIntCode x
952 NotOp -> trivialUCode (XNOR False g0) x
954 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
956 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
958 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
959 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
961 OrdOp -> coerceIntCode IntRep x
964 Float2IntOp -> coerceFP2Int x
965 Int2FloatOp -> coerceInt2FP FloatRep x
966 Double2IntOp -> coerceFP2Int x
967 Int2DoubleOp -> coerceInt2FP DoubleRep x
971 fixed_x = if is_float_op -- promote to double
972 then StPrim Float2DoubleOp [x]
975 getRegister (StCall fn DoubleRep [x])
979 FloatExpOp -> (True, SLIT("exp"))
980 FloatLogOp -> (True, SLIT("log"))
981 FloatSqrtOp -> (True, SLIT("sqrt"))
983 FloatSinOp -> (True, SLIT("sin"))
984 FloatCosOp -> (True, SLIT("cos"))
985 FloatTanOp -> (True, SLIT("tan"))
987 FloatAsinOp -> (True, SLIT("asin"))
988 FloatAcosOp -> (True, SLIT("acos"))
989 FloatAtanOp -> (True, SLIT("atan"))
991 FloatSinhOp -> (True, SLIT("sinh"))
992 FloatCoshOp -> (True, SLIT("cosh"))
993 FloatTanhOp -> (True, SLIT("tanh"))
995 DoubleExpOp -> (False, SLIT("exp"))
996 DoubleLogOp -> (False, SLIT("log"))
997 DoubleSqrtOp -> (True, SLIT("sqrt"))
999 DoubleSinOp -> (False, SLIT("sin"))
1000 DoubleCosOp -> (False, SLIT("cos"))
1001 DoubleTanOp -> (False, SLIT("tan"))
1003 DoubleAsinOp -> (False, SLIT("asin"))
1004 DoubleAcosOp -> (False, SLIT("acos"))
1005 DoubleAtanOp -> (False, SLIT("atan"))
1007 DoubleSinhOp -> (False, SLIT("sinh"))
1008 DoubleCoshOp -> (False, SLIT("cosh"))
1009 DoubleTanhOp -> (False, SLIT("tanh"))
1010 _ -> panic ("Monadic PrimOp not handled: " ++ showPrimOp primop)
1012 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1014 CharGtOp -> condIntReg GTT x y
1015 CharGeOp -> condIntReg GE x y
1016 CharEqOp -> condIntReg EQQ x y
1017 CharNeOp -> condIntReg NE x y
1018 CharLtOp -> condIntReg LTT x y
1019 CharLeOp -> condIntReg LE x y
1021 IntGtOp -> condIntReg GTT x y
1022 IntGeOp -> condIntReg GE x y
1023 IntEqOp -> condIntReg EQQ x y
1024 IntNeOp -> condIntReg NE x y
1025 IntLtOp -> condIntReg LTT x y
1026 IntLeOp -> condIntReg LE x y
1028 WordGtOp -> condIntReg GU x y
1029 WordGeOp -> condIntReg GEU x y
1030 WordEqOp -> condIntReg EQQ x y
1031 WordNeOp -> condIntReg NE x y
1032 WordLtOp -> condIntReg LU x y
1033 WordLeOp -> condIntReg LEU x y
1035 AddrGtOp -> condIntReg GU x y
1036 AddrGeOp -> condIntReg GEU x y
1037 AddrEqOp -> condIntReg EQQ x y
1038 AddrNeOp -> condIntReg NE x y
1039 AddrLtOp -> condIntReg LU x y
1040 AddrLeOp -> condIntReg LEU x y
1042 FloatGtOp -> condFltReg GTT x y
1043 FloatGeOp -> condFltReg GE x y
1044 FloatEqOp -> condFltReg EQQ x y
1045 FloatNeOp -> condFltReg NE x y
1046 FloatLtOp -> condFltReg LTT x y
1047 FloatLeOp -> condFltReg LE x y
1049 DoubleGtOp -> condFltReg GTT x y
1050 DoubleGeOp -> condFltReg GE x y
1051 DoubleEqOp -> condFltReg EQQ x y
1052 DoubleNeOp -> condFltReg NE x y
1053 DoubleLtOp -> condFltReg LTT x y
1054 DoubleLeOp -> condFltReg LE x y
1056 IntAddOp -> trivialCode (ADD False False) x y
1057 IntSubOp -> trivialCode (SUB False False) x y
1059 -- ToDo: teach about V8+ SPARC mul/div instructions
1060 IntMulOp -> imul_div SLIT(".umul") x y
1061 IntQuotOp -> imul_div SLIT(".div") x y
1062 IntRemOp -> imul_div SLIT(".rem") x y
1064 FloatAddOp -> trivialFCode FloatRep FADD x y
1065 FloatSubOp -> trivialFCode FloatRep FSUB x y
1066 FloatMulOp -> trivialFCode FloatRep FMUL x y
1067 FloatDivOp -> trivialFCode FloatRep FDIV x y
1069 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1070 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1071 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1072 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1074 AndOp -> trivialCode (AND False) x y
1075 OrOp -> trivialCode (OR False) x y
1076 XorOp -> trivialCode (XOR False) x y
1077 SllOp -> trivialCode SLL x y
1078 SraOp -> trivialCode SRA x y
1079 SrlOp -> trivialCode SRL x y
1081 ISllOp -> panic "SparcGen:isll"
1082 ISraOp -> panic "SparcGen:isra"
1083 ISrlOp -> panic "SparcGen:isrl"
1085 FloatPowerOp -> getRegister (StCall SLIT("pow") DoubleRep [promote x, promote y])
1086 where promote x = StPrim Float2DoubleOp [x]
1087 DoublePowerOp -> getRegister (StCall SLIT("pow") DoubleRep [x, y])
1089 imul_div fn x y = getRegister (StCall fn IntRep [x, y])
1091 getRegister (StInd pk mem)
1092 = getAmode mem `thenUs` \ amode ->
1094 code = amodeCode amode
1095 src = amodeAddr amode
1096 size = primRepToSize pk
1097 code__2 dst = code . mkSeqInstr (LD size src dst)
1099 returnUs (Any pk code__2)
1101 getRegister (StInt i)
1104 src = ImmInt (fromInteger i)
1105 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1107 returnUs (Any IntRep code)
1112 code dst = mkSeqInstrs [
1113 SETHI (HI imm__2) dst,
1114 OR False dst (RIImm (LO imm__2)) dst]
1116 returnUs (Any PtrRep code)
1119 imm__2 = case imm of Just x -> x
1121 #endif {- sparc_TARGET_ARCH -}
1124 %************************************************************************
1126 \subsection{The @Amode@ type}
1128 %************************************************************************
1130 @Amode@s: Memory addressing modes passed up the tree.
1132 data Amode = Amode MachRegsAddr InstrBlock
1134 amodeAddr (Amode addr _) = addr
1135 amodeCode (Amode _ code) = code
1138 Now, given a tree (the argument to an StInd) that references memory,
1139 produce a suitable addressing mode.
1142 getAmode :: StixTree -> UniqSM Amode
1144 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1146 #if alpha_TARGET_ARCH
1148 getAmode (StPrim IntSubOp [x, StInt i])
1149 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1150 getRegister x `thenUs` \ register ->
1152 code = registerCode register tmp
1153 reg = registerName register tmp
1154 off = ImmInt (-(fromInteger i))
1156 returnUs (Amode (AddrRegImm reg off) code)
1158 getAmode (StPrim IntAddOp [x, StInt i])
1159 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1160 getRegister x `thenUs` \ register ->
1162 code = registerCode register tmp
1163 reg = registerName register tmp
1164 off = ImmInt (fromInteger i)
1166 returnUs (Amode (AddrRegImm reg off) code)
1170 = returnUs (Amode (AddrImm imm__2) id)
1173 imm__2 = case imm of Just x -> x
1176 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1177 getRegister other `thenUs` \ register ->
1179 code = registerCode register tmp
1180 reg = registerName register tmp
1182 returnUs (Amode (AddrReg reg) code)
1184 #endif {- alpha_TARGET_ARCH -}
1185 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1186 #if i386_TARGET_ARCH
1188 getAmode (StPrim IntSubOp [x, StInt i])
1189 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1190 getRegister x `thenUs` \ register ->
1192 code = registerCode register tmp
1193 reg = registerName register tmp
1194 off = ImmInt (-(fromInteger i))
1196 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1198 getAmode (StPrim IntAddOp [x, StInt i])
1201 code = mkSeqInstrs []
1203 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1206 imm__2 = case imm of Just x -> x
1208 getAmode (StPrim IntAddOp [x, StInt i])
1209 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1210 getRegister x `thenUs` \ register ->
1212 code = registerCode register tmp
1213 reg = registerName register tmp
1214 off = ImmInt (fromInteger i)
1216 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1218 getAmode (StPrim IntAddOp [x, y])
1219 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1220 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1221 getRegister x `thenUs` \ register1 ->
1222 getRegister y `thenUs` \ register2 ->
1224 code1 = registerCode register1 tmp1 asmVoid
1225 reg1 = registerName register1 tmp1
1226 code2 = registerCode register2 tmp2 asmVoid
1227 reg2 = registerName register2 tmp2
1228 code__2 = asmParThen [code1, code2]
1230 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1235 code = mkSeqInstrs []
1237 returnUs (Amode (ImmAddr imm__2 0) code)
1240 imm__2 = case imm of Just x -> x
1243 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1244 getRegister other `thenUs` \ register ->
1246 code = registerCode register tmp
1247 reg = registerName register tmp
1250 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1252 #endif {- i386_TARGET_ARCH -}
1253 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1254 #if sparc_TARGET_ARCH
1256 getAmode (StPrim IntSubOp [x, StInt i])
1258 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1259 getRegister x `thenUs` \ register ->
1261 code = registerCode register tmp
1262 reg = registerName register tmp
1263 off = ImmInt (-(fromInteger i))
1265 returnUs (Amode (AddrRegImm reg off) code)
1268 getAmode (StPrim IntAddOp [x, StInt i])
1270 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1271 getRegister x `thenUs` \ register ->
1273 code = registerCode register tmp
1274 reg = registerName register tmp
1275 off = ImmInt (fromInteger i)
1277 returnUs (Amode (AddrRegImm reg off) code)
1279 getAmode (StPrim IntAddOp [x, y])
1280 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1281 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1282 getRegister x `thenUs` \ register1 ->
1283 getRegister y `thenUs` \ register2 ->
1285 code1 = registerCode register1 tmp1 asmVoid
1286 reg1 = registerName register1 tmp1
1287 code2 = registerCode register2 tmp2 asmVoid
1288 reg2 = registerName register2 tmp2
1289 code__2 = asmParThen [code1, code2]
1291 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1295 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1297 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1299 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1302 imm__2 = case imm of Just x -> x
1305 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1306 getRegister other `thenUs` \ register ->
1308 code = registerCode register tmp
1309 reg = registerName register tmp
1312 returnUs (Amode (AddrRegImm reg off) code)
1314 #endif {- sparc_TARGET_ARCH -}
1317 %************************************************************************
1319 \subsection{The @CondCode@ type}
1321 %************************************************************************
1323 Condition codes passed up the tree.
1325 data CondCode = CondCode Bool Cond InstrBlock
1327 condName (CondCode _ cond _) = cond
1328 condFloat (CondCode is_float _ _) = is_float
1329 condCode (CondCode _ _ code) = code
1332 Set up a condition code for a conditional branch.
1335 getCondCode :: StixTree -> UniqSM CondCode
1337 #if alpha_TARGET_ARCH
1338 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1339 #endif {- alpha_TARGET_ARCH -}
1340 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1342 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1343 -- yes, they really do seem to want exactly the same!
1345 getCondCode (StPrim primop [x, y])
1347 CharGtOp -> condIntCode GTT x y
1348 CharGeOp -> condIntCode GE x y
1349 CharEqOp -> condIntCode EQQ x y
1350 CharNeOp -> condIntCode NE x y
1351 CharLtOp -> condIntCode LTT x y
1352 CharLeOp -> condIntCode LE x y
1354 IntGtOp -> condIntCode GTT x y
1355 IntGeOp -> condIntCode GE x y
1356 IntEqOp -> condIntCode EQQ x y
1357 IntNeOp -> condIntCode NE x y
1358 IntLtOp -> condIntCode LTT x y
1359 IntLeOp -> condIntCode LE x y
1361 WordGtOp -> condIntCode GU x y
1362 WordGeOp -> condIntCode GEU x y
1363 WordEqOp -> condIntCode EQQ x y
1364 WordNeOp -> condIntCode NE x y
1365 WordLtOp -> condIntCode LU x y
1366 WordLeOp -> condIntCode LEU x y
1368 AddrGtOp -> condIntCode GU x y
1369 AddrGeOp -> condIntCode GEU x y
1370 AddrEqOp -> condIntCode EQQ x y
1371 AddrNeOp -> condIntCode NE x y
1372 AddrLtOp -> condIntCode LU x y
1373 AddrLeOp -> condIntCode LEU x y
1375 FloatGtOp -> condFltCode GTT x y
1376 FloatGeOp -> condFltCode GE x y
1377 FloatEqOp -> condFltCode EQQ x y
1378 FloatNeOp -> condFltCode NE x y
1379 FloatLtOp -> condFltCode LTT x y
1380 FloatLeOp -> condFltCode LE x y
1382 DoubleGtOp -> condFltCode GTT x y
1383 DoubleGeOp -> condFltCode GE x y
1384 DoubleEqOp -> condFltCode EQQ x y
1385 DoubleNeOp -> condFltCode NE x y
1386 DoubleLtOp -> condFltCode LTT x y
1387 DoubleLeOp -> condFltCode LE x y
1389 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1394 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1395 passed back up the tree.
1398 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1400 #if alpha_TARGET_ARCH
1401 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1402 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1403 #endif {- alpha_TARGET_ARCH -}
1405 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1406 #if i386_TARGET_ARCH
1408 condIntCode cond (StInd _ x) y
1410 = getAmode x `thenUs` \ amode ->
1412 code1 = amodeCode amode asmVoid
1413 y__2 = amodeAddr amode
1414 code__2 = asmParThen [code1] .
1415 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1417 returnUs (CondCode False cond code__2)
1420 imm__2 = case imm of Just x -> x
1422 condIntCode cond x (StInt 0)
1423 = getRegister x `thenUs` \ register1 ->
1424 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1426 code1 = registerCode register1 tmp1 asmVoid
1427 src1 = registerName register1 tmp1
1428 code__2 = asmParThen [code1] .
1429 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1431 returnUs (CondCode False cond code__2)
1433 condIntCode cond x y
1435 = getRegister x `thenUs` \ register1 ->
1436 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1438 code1 = registerCode register1 tmp1 asmVoid
1439 src1 = registerName register1 tmp1
1440 code__2 = asmParThen [code1] .
1441 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1443 returnUs (CondCode False cond code__2)
1446 imm__2 = case imm of Just x -> x
1448 condIntCode cond (StInd _ x) y
1449 = getAmode x `thenUs` \ amode ->
1450 getRegister y `thenUs` \ register2 ->
1451 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1453 code1 = amodeCode amode asmVoid
1454 src1 = amodeAddr amode
1455 code2 = registerCode register2 tmp2 asmVoid
1456 src2 = registerName register2 tmp2
1457 code__2 = asmParThen [code1, code2] .
1458 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1460 returnUs (CondCode False cond code__2)
1462 condIntCode cond y (StInd _ x)
1463 = getAmode x `thenUs` \ amode ->
1464 getRegister y `thenUs` \ register2 ->
1465 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1467 code1 = amodeCode amode asmVoid
1468 src1 = amodeAddr amode
1469 code2 = registerCode register2 tmp2 asmVoid
1470 src2 = registerName register2 tmp2
1471 code__2 = asmParThen [code1, code2] .
1472 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1474 returnUs (CondCode False cond code__2)
1476 condIntCode cond x y
1477 = getRegister x `thenUs` \ register1 ->
1478 getRegister y `thenUs` \ register2 ->
1479 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1480 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1482 code1 = registerCode register1 tmp1 asmVoid
1483 src1 = registerName register1 tmp1
1484 code2 = registerCode register2 tmp2 asmVoid
1485 src2 = registerName register2 tmp2
1486 code__2 = asmParThen [code1, code2] .
1487 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1489 returnUs (CondCode False cond code__2)
1493 condFltCode cond x (StDouble 0.0)
1494 = getRegister x `thenUs` \ register1 ->
1495 getNewRegNCG (registerRep register1)
1498 pk1 = registerRep register1
1499 code1 = registerCode register1 tmp1
1500 src1 = registerName register1 tmp1
1502 code__2 = asmParThen [code1 asmVoid] .
1503 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1505 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1506 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1510 returnUs (CondCode True (fix_FP_cond cond) code__2)
1512 condFltCode cond x y
1513 = getRegister x `thenUs` \ register1 ->
1514 getRegister y `thenUs` \ register2 ->
1515 getNewRegNCG (registerRep register1)
1517 getNewRegNCG (registerRep register2)
1520 pk1 = registerRep register1
1521 code1 = registerCode register1 tmp1
1522 src1 = registerName register1 tmp1
1524 code2 = registerCode register2 tmp2
1525 src2 = registerName register2 tmp2
1527 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1528 mkSeqInstrs [FUCOMPP,
1530 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1531 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1535 returnUs (CondCode True (fix_FP_cond cond) code__2)
1537 {- On the 486, the flags set by FP compare are the unsigned ones!
1538 (This looks like a HACK to me. WDP 96/03)
1541 fix_FP_cond :: Cond -> Cond
1543 fix_FP_cond GE = GEU
1544 fix_FP_cond GTT = GU
1545 fix_FP_cond LTT = LU
1546 fix_FP_cond LE = LEU
1547 fix_FP_cond any = any
1549 #endif {- i386_TARGET_ARCH -}
1550 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1551 #if sparc_TARGET_ARCH
1553 condIntCode cond x (StInt y)
1555 = getRegister x `thenUs` \ register ->
1556 getNewRegNCG IntRep `thenUs` \ tmp ->
1558 code = registerCode register tmp
1559 src1 = registerName register tmp
1560 src2 = ImmInt (fromInteger y)
1561 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1563 returnUs (CondCode False cond code__2)
1565 condIntCode cond x y
1566 = getRegister x `thenUs` \ register1 ->
1567 getRegister y `thenUs` \ register2 ->
1568 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1569 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1571 code1 = registerCode register1 tmp1 asmVoid
1572 src1 = registerName register1 tmp1
1573 code2 = registerCode register2 tmp2 asmVoid
1574 src2 = registerName register2 tmp2
1575 code__2 = asmParThen [code1, code2] .
1576 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1578 returnUs (CondCode False cond code__2)
1581 condFltCode cond x y
1582 = getRegister x `thenUs` \ register1 ->
1583 getRegister y `thenUs` \ register2 ->
1584 getNewRegNCG (registerRep register1)
1586 getNewRegNCG (registerRep register2)
1588 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1590 promote x = asmInstr (FxTOy F DF x tmp)
1592 pk1 = registerRep register1
1593 code1 = registerCode register1 tmp1
1594 src1 = registerName register1 tmp1
1596 pk2 = registerRep register2
1597 code2 = registerCode register2 tmp2
1598 src2 = registerName register2 tmp2
1602 asmParThen [code1 asmVoid, code2 asmVoid] .
1603 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1604 else if pk1 == FloatRep then
1605 asmParThen [code1 (promote src1), code2 asmVoid] .
1606 mkSeqInstr (FCMP True DF tmp src2)
1608 asmParThen [code1 asmVoid, code2 (promote src2)] .
1609 mkSeqInstr (FCMP True DF src1 tmp)
1611 returnUs (CondCode True cond code__2)
1613 #endif {- sparc_TARGET_ARCH -}
1616 %************************************************************************
1618 \subsection{Generating assignments}
1620 %************************************************************************
1622 Assignments are really at the heart of the whole code generation
1623 business. Almost all top-level nodes of any real importance are
1624 assignments, which correspond to loads, stores, or register transfers.
1625 If we're really lucky, some of the register transfers will go away,
1626 because we can use the destination register to complete the code
1627 generation for the right hand side. This only fails when the right
1628 hand side is forced into a fixed register (e.g. the result of a call).
1631 assignIntCode, assignFltCode
1632 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1634 #if alpha_TARGET_ARCH
1636 assignIntCode pk (StInd _ dst) src
1637 = getNewRegNCG IntRep `thenUs` \ tmp ->
1638 getAmode dst `thenUs` \ amode ->
1639 getRegister src `thenUs` \ register ->
1641 code1 = amodeCode amode asmVoid
1642 dst__2 = amodeAddr amode
1643 code2 = registerCode register tmp asmVoid
1644 src__2 = registerName register tmp
1645 sz = primRepToSize pk
1646 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1650 assignIntCode pk dst src
1651 = getRegister dst `thenUs` \ register1 ->
1652 getRegister src `thenUs` \ register2 ->
1654 dst__2 = registerName register1 zeroh
1655 code = registerCode register2 dst__2
1656 src__2 = registerName register2 dst__2
1657 code__2 = if isFixed register2
1658 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1663 #endif {- alpha_TARGET_ARCH -}
1664 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1665 #if i386_TARGET_ARCH
1667 assignIntCode pk (StInd _ dst) src
1668 = getAmode dst `thenUs` \ amode ->
1669 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1671 code1 = amodeCode amode asmVoid
1672 dst__2 = amodeAddr amode
1673 code__2 = asmParThen [code1, codesrc asmVoid] .
1674 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1680 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1684 = returnUs (asmParThen [], OpImm imm_op, L)
1687 imm_op = case imm of Just x -> x
1690 = getRegister op `thenUs` \ register ->
1691 getNewRegNCG (registerRep register)
1694 code = registerCode register tmp
1695 reg = registerName register tmp
1696 pk = registerRep register
1697 sz = primRepToSize pk
1699 returnUs (code, OpReg reg, sz)
1701 assignIntCode pk dst (StInd _ src)
1702 = getNewRegNCG IntRep `thenUs` \ tmp ->
1703 getAmode src `thenUs` \ amode ->
1704 getRegister dst `thenUs` \ register ->
1706 code1 = amodeCode amode asmVoid
1707 src__2 = amodeAddr amode
1708 code2 = registerCode register tmp asmVoid
1709 dst__2 = registerName register tmp
1710 sz = primRepToSize pk
1711 code__2 = asmParThen [code1, code2] .
1712 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1716 assignIntCode pk dst src
1717 = getRegister dst `thenUs` \ register1 ->
1718 getRegister src `thenUs` \ register2 ->
1719 getNewRegNCG IntRep `thenUs` \ tmp ->
1721 dst__2 = registerName register1 tmp
1722 code = registerCode register2 dst__2
1723 src__2 = registerName register2 dst__2
1724 code__2 = if isFixed register2 && dst__2 /= src__2
1725 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1730 #endif {- i386_TARGET_ARCH -}
1731 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1732 #if sparc_TARGET_ARCH
1734 assignIntCode pk (StInd _ dst) src
1735 = getNewRegNCG IntRep `thenUs` \ tmp ->
1736 getAmode dst `thenUs` \ amode ->
1737 getRegister src `thenUs` \ register ->
1739 code1 = amodeCode amode asmVoid
1740 dst__2 = amodeAddr amode
1741 code2 = registerCode register tmp asmVoid
1742 src__2 = registerName register tmp
1743 sz = primRepToSize pk
1744 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1748 assignIntCode pk dst src
1749 = getRegister dst `thenUs` \ register1 ->
1750 getRegister src `thenUs` \ register2 ->
1752 dst__2 = registerName register1 g0
1753 code = registerCode register2 dst__2
1754 src__2 = registerName register2 dst__2
1755 code__2 = if isFixed register2
1756 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1761 #endif {- sparc_TARGET_ARCH -}
1764 % --------------------------------
1765 Floating-point assignments:
1766 % --------------------------------
1768 #if alpha_TARGET_ARCH
1770 assignFltCode pk (StInd _ dst) src
1771 = getNewRegNCG pk `thenUs` \ tmp ->
1772 getAmode dst `thenUs` \ amode ->
1773 getRegister src `thenUs` \ register ->
1775 code1 = amodeCode amode asmVoid
1776 dst__2 = amodeAddr amode
1777 code2 = registerCode register tmp asmVoid
1778 src__2 = registerName register tmp
1779 sz = primRepToSize pk
1780 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1784 assignFltCode pk dst src
1785 = getRegister dst `thenUs` \ register1 ->
1786 getRegister src `thenUs` \ register2 ->
1788 dst__2 = registerName register1 zeroh
1789 code = registerCode register2 dst__2
1790 src__2 = registerName register2 dst__2
1791 code__2 = if isFixed register2
1792 then code . mkSeqInstr (FMOV src__2 dst__2)
1797 #endif {- alpha_TARGET_ARCH -}
1798 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1799 #if i386_TARGET_ARCH
1801 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1802 = getNewRegNCG IntRep `thenUs` \ tmp ->
1803 getAmode src `thenUs` \ amodesrc ->
1804 getAmode dst `thenUs` \ amodedst ->
1805 --getRegister src `thenUs` \ register ->
1807 codesrc1 = amodeCode amodesrc asmVoid
1808 addrsrc1 = amodeAddr amodesrc
1809 codedst1 = amodeCode amodedst asmVoid
1810 addrdst1 = amodeAddr amodedst
1811 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1812 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1814 code__2 = asmParThen [codesrc1, codedst1] .
1815 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1816 MOV L (OpReg tmp) (OpAddr addrdst1)]
1819 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1820 MOV L (OpReg tmp) (OpAddr addrdst2)]
1825 assignFltCode pk (StInd _ dst) src
1826 = --getNewRegNCG pk `thenUs` \ tmp ->
1827 getAmode dst `thenUs` \ amode ->
1828 getRegister src `thenUs` \ register ->
1830 sz = primRepToSize pk
1831 dst__2 = amodeAddr amode
1833 code1 = amodeCode amode asmVoid
1834 code2 = registerCode register {-tmp-}st0 asmVoid
1836 --src__2= registerName register tmp
1837 pk__2 = registerRep register
1838 sz__2 = primRepToSize pk__2
1840 code__2 = asmParThen [code1, code2] .
1841 mkSeqInstr (FSTP sz (OpAddr dst__2))
1845 assignFltCode pk dst src
1846 = getRegister dst `thenUs` \ register1 ->
1847 getRegister src `thenUs` \ register2 ->
1848 --getNewRegNCG (registerRep register2)
1849 -- `thenUs` \ tmp ->
1851 sz = primRepToSize pk
1852 dst__2 = registerName register1 st0 --tmp
1854 code = registerCode register2 dst__2
1855 src__2 = registerName register2 dst__2
1861 #endif {- i386_TARGET_ARCH -}
1862 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1863 #if sparc_TARGET_ARCH
1865 assignFltCode pk (StInd _ dst) src
1866 = getNewRegNCG pk `thenUs` \ tmp1 ->
1867 getAmode dst `thenUs` \ amode ->
1868 getRegister src `thenUs` \ register ->
1870 sz = primRepToSize pk
1871 dst__2 = amodeAddr amode
1873 code1 = amodeCode amode asmVoid
1874 code2 = registerCode register tmp1 asmVoid
1876 src__2 = registerName register tmp1
1877 pk__2 = registerRep register
1878 sz__2 = primRepToSize pk__2
1880 code__2 = asmParThen [code1, code2] .
1882 mkSeqInstr (ST sz src__2 dst__2)
1884 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1888 assignFltCode pk dst src
1889 = getRegister dst `thenUs` \ register1 ->
1890 getRegister src `thenUs` \ register2 ->
1892 pk__2 = registerRep register2
1893 sz__2 = primRepToSize pk__2
1895 getNewRegNCG pk__2 `thenUs` \ tmp ->
1897 sz = primRepToSize pk
1898 dst__2 = registerName register1 g0 -- must be Fixed
1901 reg__2 = if pk /= pk__2 then tmp else dst__2
1903 code = registerCode register2 reg__2
1905 src__2 = registerName register2 reg__2
1909 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1910 else if isFixed register2 then
1911 code . mkSeqInstr (FMOV sz src__2 dst__2)
1917 #endif {- sparc_TARGET_ARCH -}
1920 %************************************************************************
1922 \subsection{Generating an unconditional branch}
1924 %************************************************************************
1926 We accept two types of targets: an immediate CLabel or a tree that
1927 gets evaluated into a register. Any CLabels which are AsmTemporaries
1928 are assumed to be in the local block of code, close enough for a
1929 branch instruction. Other CLabels are assumed to be far away.
1931 (If applicable) Do not fill the delay slots here; you will confuse the
1935 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1937 #if alpha_TARGET_ARCH
1939 genJump (StCLbl lbl)
1940 | isAsmTemp lbl = returnInstr (BR target)
1941 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1943 target = ImmCLbl lbl
1946 = getRegister tree `thenUs` \ register ->
1947 getNewRegNCG PtrRep `thenUs` \ tmp ->
1949 dst = registerName register pv
1950 code = registerCode register pv
1951 target = registerName register pv
1953 if isFixed register then
1954 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1956 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1958 #endif {- alpha_TARGET_ARCH -}
1959 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1960 #if i386_TARGET_ARCH
1963 genJump (StCLbl lbl)
1964 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1965 | otherwise = returnInstrs [JMP (OpImm target)]
1967 target = ImmCLbl lbl
1970 genJump (StInd pk mem)
1971 = getAmode mem `thenUs` \ amode ->
1973 code = amodeCode amode
1974 target = amodeAddr amode
1976 returnSeq code [JMP (OpAddr target)]
1980 = returnInstr (JMP (OpImm target))
1983 = getRegister tree `thenUs` \ register ->
1984 getNewRegNCG PtrRep `thenUs` \ tmp ->
1986 code = registerCode register tmp
1987 target = registerName register tmp
1989 returnSeq code [JMP (OpReg target)]
1992 target = case imm of Just x -> x
1994 #endif {- i386_TARGET_ARCH -}
1995 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1996 #if sparc_TARGET_ARCH
1998 genJump (StCLbl lbl)
1999 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
2000 | otherwise = returnInstrs [CALL target 0 True, NOP]
2002 target = ImmCLbl lbl
2005 = getRegister tree `thenUs` \ register ->
2006 getNewRegNCG PtrRep `thenUs` \ tmp ->
2008 code = registerCode register tmp
2009 target = registerName register tmp
2011 returnSeq code [JMP (AddrRegReg target g0), NOP]
2013 #endif {- sparc_TARGET_ARCH -}
2016 %************************************************************************
2018 \subsection{Conditional jumps}
2020 %************************************************************************
2022 Conditional jumps are always to local labels, so we can use branch
2023 instructions. We peek at the arguments to decide what kind of
2026 ALPHA: For comparisons with 0, we're laughing, because we can just do
2027 the desired conditional branch.
2029 I386: First, we have to ensure that the condition
2030 codes are set according to the supplied comparison operation.
2032 SPARC: First, we have to ensure that the condition codes are set
2033 according to the supplied comparison operation. We generate slightly
2034 different code for floating point comparisons, because a floating
2035 point operation cannot directly precede a @BF@. We assume the worst
2036 and fill that slot with a @NOP@.
2038 SPARC: Do not fill the delay slots here; you will confuse the register
2043 :: CLabel -- the branch target
2044 -> StixTree -- the condition on which to branch
2045 -> UniqSM InstrBlock
2047 #if alpha_TARGET_ARCH
2049 genCondJump lbl (StPrim op [x, StInt 0])
2050 = getRegister x `thenUs` \ register ->
2051 getNewRegNCG (registerRep register)
2054 code = registerCode register tmp
2055 value = registerName register tmp
2056 pk = registerRep register
2057 target = ImmCLbl lbl
2059 returnSeq code [BI (cmpOp op) value target]
2061 cmpOp CharGtOp = GTT
2063 cmpOp CharEqOp = EQQ
2065 cmpOp CharLtOp = LTT
2074 cmpOp WordGeOp = ALWAYS
2075 cmpOp WordEqOp = EQQ
2077 cmpOp WordLtOp = NEVER
2078 cmpOp WordLeOp = EQQ
2080 cmpOp AddrGeOp = ALWAYS
2081 cmpOp AddrEqOp = EQQ
2083 cmpOp AddrLtOp = NEVER
2084 cmpOp AddrLeOp = EQQ
2086 genCondJump lbl (StPrim op [x, StDouble 0.0])
2087 = getRegister x `thenUs` \ register ->
2088 getNewRegNCG (registerRep register)
2091 code = registerCode register tmp
2092 value = registerName register tmp
2093 pk = registerRep register
2094 target = ImmCLbl lbl
2096 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2098 cmpOp FloatGtOp = GTT
2099 cmpOp FloatGeOp = GE
2100 cmpOp FloatEqOp = EQQ
2101 cmpOp FloatNeOp = NE
2102 cmpOp FloatLtOp = LTT
2103 cmpOp FloatLeOp = LE
2104 cmpOp DoubleGtOp = GTT
2105 cmpOp DoubleGeOp = GE
2106 cmpOp DoubleEqOp = EQQ
2107 cmpOp DoubleNeOp = NE
2108 cmpOp DoubleLtOp = LTT
2109 cmpOp DoubleLeOp = LE
2111 genCondJump lbl (StPrim op [x, y])
2113 = trivialFCode pr instr x y `thenUs` \ register ->
2114 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2116 code = registerCode register tmp
2117 result = registerName register tmp
2118 target = ImmCLbl lbl
2120 returnUs (code . mkSeqInstr (BF cond result target))
2122 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2124 fltCmpOp op = case op of
2138 (instr, cond) = case op of
2139 FloatGtOp -> (FCMP TF LE, EQQ)
2140 FloatGeOp -> (FCMP TF LTT, EQQ)
2141 FloatEqOp -> (FCMP TF EQQ, NE)
2142 FloatNeOp -> (FCMP TF EQQ, EQQ)
2143 FloatLtOp -> (FCMP TF LTT, NE)
2144 FloatLeOp -> (FCMP TF LE, NE)
2145 DoubleGtOp -> (FCMP TF LE, EQQ)
2146 DoubleGeOp -> (FCMP TF LTT, EQQ)
2147 DoubleEqOp -> (FCMP TF EQQ, NE)
2148 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2149 DoubleLtOp -> (FCMP TF LTT, NE)
2150 DoubleLeOp -> (FCMP TF LE, NE)
2152 genCondJump lbl (StPrim op [x, y])
2153 = trivialCode instr x y `thenUs` \ register ->
2154 getNewRegNCG IntRep `thenUs` \ tmp ->
2156 code = registerCode register tmp
2157 result = registerName register tmp
2158 target = ImmCLbl lbl
2160 returnUs (code . mkSeqInstr (BI cond result target))
2162 (instr, cond) = case op of
2163 CharGtOp -> (CMP LE, EQQ)
2164 CharGeOp -> (CMP LTT, EQQ)
2165 CharEqOp -> (CMP EQQ, NE)
2166 CharNeOp -> (CMP EQQ, EQQ)
2167 CharLtOp -> (CMP LTT, NE)
2168 CharLeOp -> (CMP LE, NE)
2169 IntGtOp -> (CMP LE, EQQ)
2170 IntGeOp -> (CMP LTT, EQQ)
2171 IntEqOp -> (CMP EQQ, NE)
2172 IntNeOp -> (CMP EQQ, EQQ)
2173 IntLtOp -> (CMP LTT, NE)
2174 IntLeOp -> (CMP LE, NE)
2175 WordGtOp -> (CMP ULE, EQQ)
2176 WordGeOp -> (CMP ULT, EQQ)
2177 WordEqOp -> (CMP EQQ, NE)
2178 WordNeOp -> (CMP EQQ, EQQ)
2179 WordLtOp -> (CMP ULT, NE)
2180 WordLeOp -> (CMP ULE, NE)
2181 AddrGtOp -> (CMP ULE, EQQ)
2182 AddrGeOp -> (CMP ULT, EQQ)
2183 AddrEqOp -> (CMP EQQ, NE)
2184 AddrNeOp -> (CMP EQQ, EQQ)
2185 AddrLtOp -> (CMP ULT, NE)
2186 AddrLeOp -> (CMP ULE, NE)
2188 #endif {- alpha_TARGET_ARCH -}
2189 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2190 #if i386_TARGET_ARCH
2192 genCondJump lbl bool
2193 = getCondCode bool `thenUs` \ condition ->
2195 code = condCode condition
2196 cond = condName condition
2197 target = ImmCLbl lbl
2199 returnSeq code [JXX cond lbl]
2201 #endif {- i386_TARGET_ARCH -}
2202 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2203 #if sparc_TARGET_ARCH
2205 genCondJump lbl bool
2206 = getCondCode bool `thenUs` \ condition ->
2208 code = condCode condition
2209 cond = condName condition
2210 target = ImmCLbl lbl
2213 if condFloat condition then
2214 [NOP, BF cond False target, NOP]
2216 [BI cond False target, NOP]
2219 #endif {- sparc_TARGET_ARCH -}
2222 %************************************************************************
2224 \subsection{Generating C calls}
2226 %************************************************************************
2228 Now the biggest nightmare---calls. Most of the nastiness is buried in
2229 @get_arg@, which moves the arguments to the correct registers/stack
2230 locations. Apart from that, the code is easy.
2232 (If applicable) Do not fill the delay slots here; you will confuse the
2237 :: FAST_STRING -- function to call
2238 -> PrimRep -- type of the result
2239 -> [StixTree] -- arguments (of mixed type)
2240 -> UniqSM InstrBlock
2242 #if alpha_TARGET_ARCH
2244 genCCall fn kind args
2245 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2246 `thenUs` \ ((unused,_), argCode) ->
2248 nRegs = length allArgRegs - length unused
2249 code = asmParThen (map ($ asmVoid) argCode)
2252 LDA pv (AddrImm (ImmLab (ptext fn))),
2253 JSR ra (AddrReg pv) nRegs,
2254 LDGP gp (AddrReg ra)]
2256 ------------------------
2257 {- Try to get a value into a specific register (or registers) for
2258 a call. The first 6 arguments go into the appropriate
2259 argument register (separate registers for integer and floating
2260 point arguments, but used in lock-step), and the remaining
2261 arguments are dumped to the stack, beginning at 0(sp). Our
2262 first argument is a pair of the list of remaining argument
2263 registers to be assigned for this call and the next stack
2264 offset to use for overflowing arguments. This way,
2265 @get_Arg@ can be applied to all of a call's arguments using
2269 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2270 -> StixTree -- Current argument
2271 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2273 -- We have to use up all of our argument registers first...
2275 get_arg ((iDst,fDst):dsts, offset) arg
2276 = getRegister arg `thenUs` \ register ->
2278 reg = if isFloatingRep pk then fDst else iDst
2279 code = registerCode register reg
2280 src = registerName register reg
2281 pk = registerRep register
2284 if isFloatingRep pk then
2285 ((dsts, offset), if isFixed register then
2286 code . mkSeqInstr (FMOV src fDst)
2289 ((dsts, offset), if isFixed register then
2290 code . mkSeqInstr (OR src (RIReg src) iDst)
2293 -- Once we have run out of argument registers, we move to the
2296 get_arg ([], offset) arg
2297 = getRegister arg `thenUs` \ register ->
2298 getNewRegNCG (registerRep register)
2301 code = registerCode register tmp
2302 src = registerName register tmp
2303 pk = registerRep register
2304 sz = primRepToSize pk
2306 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2308 #endif {- alpha_TARGET_ARCH -}
2309 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2310 #if i386_TARGET_ARCH
2312 genCCall fn kind [StInt i]
2313 | fn == SLIT ("PerformGC_wrapper")
2315 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2316 CALL (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))]
2321 = getUniqLabelNCG `thenUs` \ lbl ->
2323 call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2324 MOV L (OpImm (ImmCLbl lbl))
2325 -- this is hardwired
2326 (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 104))),
2327 JMP (OpImm (ImmLit (ptext (if underscorePrefix then (SLIT ("_PerformGC_wrapper")) else (SLIT ("PerformGC_wrapper")))))),
2333 genCCall fn kind args
2334 = mapUs get_call_arg args `thenUs` \ argCode ->
2338 {- OLD: Since there's no attempt at stealing %esp at the moment,
2339 restoring %esp from MainRegTable.rCstkptr is not done. -- SOF 97/09
2340 (ditto for saving away old-esp in MainRegTable.Hp (!!) )
2341 code1 = asmParThen [asmSeq [ -- MOV L (OpReg esp) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))),
2342 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 100))) (OpReg esp)
2346 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2347 call = [CALL fn__2 ,
2348 -- pop args; all args word sized?
2349 ADD L (OpImm (ImmInt (nargs * 4))) (OpReg esp) --,
2351 -- Don't restore %esp (see above)
2352 -- MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt 80))) (OpReg esp)
2355 returnSeq (code2) call
2357 -- function names that begin with '.' are assumed to be special
2358 -- internally generated names like '.mul,' which don't get an
2359 -- underscore prefix
2360 -- ToDo:needed (WDP 96/03) ???
2361 fn__2 = case (_HEAD_ fn) of
2362 '.' -> ImmLit (ptext fn)
2363 _ -> ImmLab (ptext fn)
2366 get_call_arg :: StixTree{-current argument-} -> UniqSM InstrBlock -- code
2369 = get_op arg `thenUs` \ (code, op, sz) ->
2370 returnUs (code . mkSeqInstr (PUSH sz op))
2375 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2378 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2380 get_op (StInd pk mem)
2381 = getAmode mem `thenUs` \ amode ->
2383 code = amodeCode amode --asmVoid
2384 addr = amodeAddr amode
2385 sz = primRepToSize pk
2387 returnUs (code, OpAddr addr, sz)
2390 = getRegister op `thenUs` \ register ->
2391 getNewRegNCG (registerRep register)
2394 code = registerCode register tmp
2395 reg = registerName register tmp
2396 pk = registerRep register
2397 sz = primRepToSize pk
2399 returnUs (code, OpReg reg, sz)
2401 #endif {- i386_TARGET_ARCH -}
2402 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2403 #if sparc_TARGET_ARCH
2405 genCCall fn kind args
2406 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2407 `thenUs` \ ((unused,_), argCode) ->
2409 nRegs = length allArgRegs - length unused
2410 call = CALL fn__2 nRegs False
2411 code = asmParThen (map ($ asmVoid) argCode)
2413 returnSeq code [call, NOP]
2415 -- function names that begin with '.' are assumed to be special
2416 -- internally generated names like '.mul,' which don't get an
2417 -- underscore prefix
2418 -- ToDo:needed (WDP 96/03) ???
2419 fn__2 = case (_HEAD_ fn) of
2420 '.' -> ImmLit (ptext fn)
2421 _ -> ImmLab (ptext fn)
2423 ------------------------------------
2424 {- Try to get a value into a specific register (or registers) for
2425 a call. The SPARC calling convention is an absolute
2426 nightmare. The first 6x32 bits of arguments are mapped into
2427 %o0 through %o5, and the remaining arguments are dumped to the
2428 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2429 first argument is a pair of the list of remaining argument
2430 registers to be assigned for this call and the next stack
2431 offset to use for overflowing arguments. This way,
2432 @get_arg@ can be applied to all of a call's arguments using
2436 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2437 -> StixTree -- Current argument
2438 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2440 -- We have to use up all of our argument registers first...
2442 get_arg (dst:dsts, offset) arg
2443 = getRegister arg `thenUs` \ register ->
2444 getNewRegNCG (registerRep register)
2447 reg = if isFloatingRep pk then tmp else dst
2448 code = registerCode register reg
2449 src = registerName register reg
2450 pk = registerRep register
2452 returnUs (case pk of
2455 [] -> (([], offset + 1), code . mkSeqInstrs [
2456 -- conveniently put the second part in the right stack
2457 -- location, and load the first part into %o5
2458 ST DF src (spRel (offset - 1)),
2459 LD W (spRel (offset - 1)) dst])
2460 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2461 ST DF src (spRel (-2)),
2462 LD W (spRel (-2)) dst,
2463 LD W (spRel (-1)) dst__2])
2464 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2465 ST F src (spRel (-2)),
2466 LD W (spRel (-2)) dst])
2467 _ -> ((dsts, offset), if isFixed register then
2468 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2471 -- Once we have run out of argument registers, we move to the
2474 get_arg ([], offset) arg
2475 = getRegister arg `thenUs` \ register ->
2476 getNewRegNCG (registerRep register)
2479 code = registerCode register tmp
2480 src = registerName register tmp
2481 pk = registerRep register
2482 sz = primRepToSize pk
2483 words = if pk == DoubleRep then 2 else 1
2485 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2487 #endif {- sparc_TARGET_ARCH -}
2490 %************************************************************************
2492 \subsection{Support bits}
2494 %************************************************************************
2496 %************************************************************************
2498 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2500 %************************************************************************
2502 Turn those condition codes into integers now (when they appear on
2503 the right hand side of an assignment).
2505 (If applicable) Do not fill the delay slots here; you will confuse the
2509 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2511 #if alpha_TARGET_ARCH
2512 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2513 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2514 #endif {- alpha_TARGET_ARCH -}
2516 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2517 #if i386_TARGET_ARCH
2520 = condIntCode cond x y `thenUs` \ condition ->
2521 getNewRegNCG IntRep `thenUs` \ tmp ->
2522 --getRegister dst `thenUs` \ register ->
2524 --code2 = registerCode register tmp asmVoid
2525 --dst__2 = registerName register tmp
2526 code = condCode condition
2527 cond = condName condition
2528 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2529 code__2 dst = code . mkSeqInstrs [
2530 SETCC cond (OpReg tmp),
2531 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2532 MOV L (OpReg tmp) (OpReg dst)]
2534 returnUs (Any IntRep code__2)
2537 = getUniqLabelNCG `thenUs` \ lbl1 ->
2538 getUniqLabelNCG `thenUs` \ lbl2 ->
2539 condFltCode cond x y `thenUs` \ condition ->
2541 code = condCode condition
2542 cond = condName condition
2543 code__2 dst = code . mkSeqInstrs [
2545 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2548 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2551 returnUs (Any IntRep code__2)
2553 #endif {- i386_TARGET_ARCH -}
2554 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2555 #if sparc_TARGET_ARCH
2557 condIntReg EQQ x (StInt 0)
2558 = getRegister x `thenUs` \ register ->
2559 getNewRegNCG IntRep `thenUs` \ tmp ->
2561 code = registerCode register tmp
2562 src = registerName register tmp
2563 code__2 dst = code . mkSeqInstrs [
2564 SUB False True g0 (RIReg src) g0,
2565 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2567 returnUs (Any IntRep code__2)
2570 = getRegister x `thenUs` \ register1 ->
2571 getRegister y `thenUs` \ register2 ->
2572 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2573 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2575 code1 = registerCode register1 tmp1 asmVoid
2576 src1 = registerName register1 tmp1
2577 code2 = registerCode register2 tmp2 asmVoid
2578 src2 = registerName register2 tmp2
2579 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2580 XOR False src1 (RIReg src2) dst,
2581 SUB False True g0 (RIReg dst) g0,
2582 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2584 returnUs (Any IntRep code__2)
2586 condIntReg NE x (StInt 0)
2587 = getRegister x `thenUs` \ register ->
2588 getNewRegNCG IntRep `thenUs` \ tmp ->
2590 code = registerCode register tmp
2591 src = registerName register tmp
2592 code__2 dst = code . mkSeqInstrs [
2593 SUB False True g0 (RIReg src) g0,
2594 ADD True False g0 (RIImm (ImmInt 0)) dst]
2596 returnUs (Any IntRep code__2)
2599 = getRegister x `thenUs` \ register1 ->
2600 getRegister y `thenUs` \ register2 ->
2601 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2602 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2604 code1 = registerCode register1 tmp1 asmVoid
2605 src1 = registerName register1 tmp1
2606 code2 = registerCode register2 tmp2 asmVoid
2607 src2 = registerName register2 tmp2
2608 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2609 XOR False src1 (RIReg src2) dst,
2610 SUB False True g0 (RIReg dst) g0,
2611 ADD True False g0 (RIImm (ImmInt 0)) dst]
2613 returnUs (Any IntRep code__2)
2616 = getUniqLabelNCG `thenUs` \ lbl1 ->
2617 getUniqLabelNCG `thenUs` \ lbl2 ->
2618 condIntCode cond x y `thenUs` \ condition ->
2620 code = condCode condition
2621 cond = condName condition
2622 code__2 dst = code . mkSeqInstrs [
2623 BI cond False (ImmCLbl lbl1), NOP,
2624 OR False g0 (RIImm (ImmInt 0)) dst,
2625 BI ALWAYS False (ImmCLbl lbl2), NOP,
2627 OR False g0 (RIImm (ImmInt 1)) dst,
2630 returnUs (Any IntRep code__2)
2633 = getUniqLabelNCG `thenUs` \ lbl1 ->
2634 getUniqLabelNCG `thenUs` \ lbl2 ->
2635 condFltCode cond x y `thenUs` \ condition ->
2637 code = condCode condition
2638 cond = condName condition
2639 code__2 dst = code . mkSeqInstrs [
2641 BF cond False (ImmCLbl lbl1), NOP,
2642 OR False g0 (RIImm (ImmInt 0)) dst,
2643 BI ALWAYS False (ImmCLbl lbl2), NOP,
2645 OR False g0 (RIImm (ImmInt 1)) dst,
2648 returnUs (Any IntRep code__2)
2650 #endif {- sparc_TARGET_ARCH -}
2653 %************************************************************************
2655 \subsubsection{@trivial*Code@: deal with trivial instructions}
2657 %************************************************************************
2659 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2660 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2661 for constants on the right hand side, because that's where the generic
2662 optimizer will have put them.
2664 Similarly, for unary instructions, we don't have to worry about
2665 matching an StInt as the argument, because genericOpt will already
2666 have handled the constant-folding.
2670 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2671 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2672 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2674 -> StixTree -> StixTree -- the two arguments
2679 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2680 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2682 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2683 (Size -> Operand -> Instr)
2684 -> (Size -> Operand -> Instr) {-reversed instr-}
2686 -> Instr {-reversed instr: pop-}
2688 -> StixTree -> StixTree -- the two arguments
2692 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2693 ,IF_ARCH_i386 ((Operand -> Instr)
2694 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2696 -> StixTree -- the one argument
2701 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2702 ,IF_ARCH_i386 (Instr
2703 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2705 -> StixTree -- the one argument
2708 #if alpha_TARGET_ARCH
2710 trivialCode instr x (StInt y)
2712 = getRegister x `thenUs` \ register ->
2713 getNewRegNCG IntRep `thenUs` \ tmp ->
2715 code = registerCode register tmp
2716 src1 = registerName register tmp
2717 src2 = ImmInt (fromInteger y)
2718 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2720 returnUs (Any IntRep code__2)
2722 trivialCode instr x y
2723 = getRegister x `thenUs` \ register1 ->
2724 getRegister y `thenUs` \ register2 ->
2725 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2726 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2728 code1 = registerCode register1 tmp1 asmVoid
2729 src1 = registerName register1 tmp1
2730 code2 = registerCode register2 tmp2 asmVoid
2731 src2 = registerName register2 tmp2
2732 code__2 dst = asmParThen [code1, code2] .
2733 mkSeqInstr (instr src1 (RIReg src2) dst)
2735 returnUs (Any IntRep code__2)
2738 trivialUCode instr x
2739 = getRegister x `thenUs` \ register ->
2740 getNewRegNCG IntRep `thenUs` \ tmp ->
2742 code = registerCode register tmp
2743 src = registerName register tmp
2744 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2746 returnUs (Any IntRep code__2)
2749 trivialFCode _ instr x y
2750 = getRegister x `thenUs` \ register1 ->
2751 getRegister y `thenUs` \ register2 ->
2752 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2753 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2755 code1 = registerCode register1 tmp1
2756 src1 = registerName register1 tmp1
2758 code2 = registerCode register2 tmp2
2759 src2 = registerName register2 tmp2
2761 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2762 mkSeqInstr (instr src1 src2 dst)
2764 returnUs (Any DoubleRep code__2)
2766 trivialUFCode _ instr x
2767 = getRegister x `thenUs` \ register ->
2768 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2770 code = registerCode register tmp
2771 src = registerName register tmp
2772 code__2 dst = code . mkSeqInstr (instr src dst)
2774 returnUs (Any DoubleRep code__2)
2776 #endif {- alpha_TARGET_ARCH -}
2777 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2778 #if i386_TARGET_ARCH
2780 trivialCode instr x y
2782 = getRegister x `thenUs` \ register1 ->
2783 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2785 -- fixedname = registerName register1 eax
2786 code__2 dst = let code1 = registerCode register1 dst
2787 src1 = registerName register1 dst
2789 if isFixed register1 && src1 /= dst
2790 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2791 instr (OpImm imm__2) (OpReg dst)]
2793 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2795 returnUs (Any IntRep code__2)
2798 imm__2 = case imm of Just x -> x
2800 trivialCode instr x y
2802 = getRegister y `thenUs` \ register1 ->
2803 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2805 -- fixedname = registerName register1 eax
2806 code__2 dst = let code1 = registerCode register1 dst
2807 src1 = registerName register1 dst
2809 if isFixed register1 && src1 /= dst
2810 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2811 instr (OpImm imm__2) (OpReg dst)]
2813 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2815 returnUs (Any IntRep code__2)
2818 imm__2 = case imm of Just x -> x
2820 trivialCode instr x (StInd pk mem)
2821 = getRegister x `thenUs` \ register ->
2822 --getNewRegNCG IntRep `thenUs` \ tmp ->
2823 getAmode mem `thenUs` \ amode ->
2825 -- fixedname = registerName register eax
2826 code2 = amodeCode amode asmVoid
2827 src2 = amodeAddr amode
2828 code__2 dst = let code1 = registerCode register dst asmVoid
2829 src1 = registerName register dst
2830 in asmParThen [code1, code2] .
2831 if isFixed register && src1 /= dst
2832 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2833 instr (OpAddr src2) (OpReg dst)]
2835 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2837 returnUs (Any pk code__2)
2839 trivialCode instr (StInd pk mem) y
2840 = getRegister y `thenUs` \ register ->
2841 --getNewRegNCG IntRep `thenUs` \ tmp ->
2842 getAmode mem `thenUs` \ amode ->
2844 -- fixedname = registerName register eax
2845 code2 = amodeCode amode asmVoid
2846 src2 = amodeAddr amode
2848 code1 = registerCode register dst asmVoid
2849 src1 = registerName register dst
2850 in asmParThen [code1, code2] .
2851 if isFixed register && src1 /= dst
2852 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2853 instr (OpAddr src2) (OpReg dst)]
2855 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2857 returnUs (Any pk code__2)
2859 trivialCode instr x y
2860 = getRegister x `thenUs` \ register1 ->
2861 getRegister y `thenUs` \ register2 ->
2862 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2863 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2865 -- fixedname = registerName register1 eax
2866 code2 = registerCode register2 tmp2 asmVoid
2867 src2 = registerName register2 tmp2
2869 code1 = registerCode register1 dst asmVoid
2870 src1 = registerName register1 dst
2871 in asmParThen [code1, code2] .
2872 if isFixed register1 && src1 /= dst
2873 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2874 instr (OpReg src2) (OpReg dst)]
2876 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2878 returnUs (Any IntRep code__2)
2881 trivialUCode instr x
2882 = getRegister x `thenUs` \ register ->
2883 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2885 -- fixedname = registerName register eax
2887 code = registerCode register dst
2888 src = registerName register dst
2889 in code . if isFixed register && dst /= src
2890 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2892 else mkSeqInstr (instr (OpReg src))
2894 returnUs (Any IntRep code__2)
2897 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2898 = getRegister y `thenUs` \ register2 ->
2899 --getNewRegNCG (registerRep register2)
2900 -- `thenUs` \ tmp2 ->
2901 getAmode mem `thenUs` \ amode ->
2903 code1 = amodeCode amode
2904 src1 = amodeAddr amode
2907 code2 = registerCode register2 dst
2908 src2 = registerName register2 dst
2909 in asmParThen [code1 asmVoid,code2 asmVoid] .
2910 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2912 returnUs (Any pk code__2)
2914 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2915 = getRegister x `thenUs` \ register1 ->
2916 --getNewRegNCG (registerRep register1)
2917 -- `thenUs` \ tmp1 ->
2918 getAmode mem `thenUs` \ amode ->
2920 code2 = amodeCode amode
2921 src2 = amodeAddr amode
2924 code1 = registerCode register1 dst
2925 src1 = registerName register1 dst
2926 in asmParThen [code2 asmVoid,code1 asmVoid] .
2927 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2929 returnUs (Any pk code__2)
2931 trivialFCode pk _ _ _ instrpr x y
2932 = getRegister x `thenUs` \ register1 ->
2933 getRegister y `thenUs` \ register2 ->
2934 --getNewRegNCG (registerRep register1)
2935 -- `thenUs` \ tmp1 ->
2936 --getNewRegNCG (registerRep register2)
2937 -- `thenUs` \ tmp2 ->
2938 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2940 pk1 = registerRep register1
2941 code1 = registerCode register1 st0 --tmp1
2942 src1 = registerName register1 st0 --tmp1
2944 pk2 = registerRep register2
2947 code2 = registerCode register2 dst
2948 src2 = registerName register2 dst
2949 in asmParThen [code1 asmVoid, code2 asmVoid] .
2952 returnUs (Any pk1 code__2)
2955 trivialUFCode pk instr (StInd pk' mem)
2956 = getAmode mem `thenUs` \ amode ->
2958 code = amodeCode amode
2959 src = amodeAddr amode
2960 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2963 returnUs (Any pk code__2)
2965 trivialUFCode pk instr x
2966 = getRegister x `thenUs` \ register ->
2967 --getNewRegNCG pk `thenUs` \ tmp ->
2970 code = registerCode register dst
2971 src = registerName register dst
2972 in code . mkSeqInstrs [instr]
2974 returnUs (Any pk code__2)
2976 #endif {- i386_TARGET_ARCH -}
2977 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2978 #if sparc_TARGET_ARCH
2980 trivialCode instr x (StInt y)
2982 = getRegister x `thenUs` \ register ->
2983 getNewRegNCG IntRep `thenUs` \ tmp ->
2985 code = registerCode register tmp
2986 src1 = registerName register tmp
2987 src2 = ImmInt (fromInteger y)
2988 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2990 returnUs (Any IntRep code__2)
2992 trivialCode instr x y
2993 = getRegister x `thenUs` \ register1 ->
2994 getRegister y `thenUs` \ register2 ->
2995 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2996 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2998 code1 = registerCode register1 tmp1 asmVoid
2999 src1 = registerName register1 tmp1
3000 code2 = registerCode register2 tmp2 asmVoid
3001 src2 = registerName register2 tmp2
3002 code__2 dst = asmParThen [code1, code2] .
3003 mkSeqInstr (instr src1 (RIReg src2) dst)
3005 returnUs (Any IntRep code__2)
3008 trivialFCode pk instr x y
3009 = getRegister x `thenUs` \ register1 ->
3010 getRegister y `thenUs` \ register2 ->
3011 getNewRegNCG (registerRep register1)
3013 getNewRegNCG (registerRep register2)
3015 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3017 promote x = asmInstr (FxTOy F DF x tmp)
3019 pk1 = registerRep register1
3020 code1 = registerCode register1 tmp1
3021 src1 = registerName register1 tmp1
3023 pk2 = registerRep register2
3024 code2 = registerCode register2 tmp2
3025 src2 = registerName register2 tmp2
3029 asmParThen [code1 asmVoid, code2 asmVoid] .
3030 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3031 else if pk1 == FloatRep then
3032 asmParThen [code1 (promote src1), code2 asmVoid] .
3033 mkSeqInstr (instr DF tmp src2 dst)
3035 asmParThen [code1 asmVoid, code2 (promote src2)] .
3036 mkSeqInstr (instr DF src1 tmp dst)
3038 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3041 trivialUCode instr x
3042 = getRegister x `thenUs` \ register ->
3043 getNewRegNCG IntRep `thenUs` \ tmp ->
3045 code = registerCode register tmp
3046 src = registerName register tmp
3047 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3049 returnUs (Any IntRep code__2)
3052 trivialUFCode pk instr x
3053 = getRegister x `thenUs` \ register ->
3054 getNewRegNCG pk `thenUs` \ tmp ->
3056 code = registerCode register tmp
3057 src = registerName register tmp
3058 code__2 dst = code . mkSeqInstr (instr src dst)
3060 returnUs (Any pk code__2)
3062 #endif {- sparc_TARGET_ARCH -}
3065 %************************************************************************
3067 \subsubsection{Coercing to/from integer/floating-point...}
3069 %************************************************************************
3071 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3072 to be generated. Here we just change the type on the Register passed
3073 on up. The code is machine-independent.
3075 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3076 conversions. We have to store temporaries in memory to move
3077 between the integer and the floating point register sets.
3080 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3081 coerceFltCode :: StixTree -> UniqSM Register
3083 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3084 coerceFP2Int :: StixTree -> UniqSM Register
3087 = getRegister x `thenUs` \ register ->
3090 Fixed _ reg code -> Fixed pk reg code
3091 Any _ code -> Any pk code
3096 = getRegister x `thenUs` \ register ->
3099 Fixed _ reg code -> Fixed DoubleRep reg code
3100 Any _ code -> Any DoubleRep code
3105 #if alpha_TARGET_ARCH
3108 = getRegister x `thenUs` \ register ->
3109 getNewRegNCG IntRep `thenUs` \ reg ->
3111 code = registerCode register reg
3112 src = registerName register reg
3114 code__2 dst = code . mkSeqInstrs [
3116 LD TF dst (spRel 0),
3119 returnUs (Any DoubleRep code__2)
3123 = getRegister x `thenUs` \ register ->
3124 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3126 code = registerCode register tmp
3127 src = registerName register tmp
3129 code__2 dst = code . mkSeqInstrs [
3131 ST TF tmp (spRel 0),
3134 returnUs (Any IntRep code__2)
3136 #endif {- alpha_TARGET_ARCH -}
3137 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3138 #if i386_TARGET_ARCH
3141 = getRegister x `thenUs` \ register ->
3142 getNewRegNCG IntRep `thenUs` \ reg ->
3144 code = registerCode register reg
3145 src = registerName register reg
3147 code__2 dst = code . mkSeqInstrs [
3148 -- to fix: should spill instead of using R1
3149 MOV L (OpReg src) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
3150 FILD (primRepToSize pk) (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3152 returnUs (Any pk code__2)
3156 = getRegister x `thenUs` \ register ->
3157 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3159 code = registerCode register tmp
3160 src = registerName register tmp
3161 pk = registerRep register
3164 in code . mkSeqInstrs [
3166 FIST L (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)),
3167 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3169 returnUs (Any IntRep code__2)
3171 #endif {- i386_TARGET_ARCH -}
3172 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3173 #if sparc_TARGET_ARCH
3176 = getRegister x `thenUs` \ register ->
3177 getNewRegNCG IntRep `thenUs` \ reg ->
3179 code = registerCode register reg
3180 src = registerName register reg
3182 code__2 dst = code . mkSeqInstrs [
3183 ST W src (spRel (-2)),
3184 LD W (spRel (-2)) dst,
3185 FxTOy W (primRepToSize pk) dst dst]
3187 returnUs (Any pk code__2)
3191 = getRegister x `thenUs` \ register ->
3192 getNewRegNCG IntRep `thenUs` \ reg ->
3193 getNewRegNCG FloatRep `thenUs` \ tmp ->
3195 code = registerCode register reg
3196 src = registerName register reg
3197 pk = registerRep register
3199 code__2 dst = code . mkSeqInstrs [
3200 FxTOy (primRepToSize pk) W src tmp,
3201 ST W tmp (spRel (-2)),
3202 LD W (spRel (-2)) dst]
3204 returnUs (Any IntRep code__2)
3206 #endif {- sparc_TARGET_ARCH -}
3209 %************************************************************************
3211 \subsubsection{Coercing integer to @Char@...}
3213 %************************************************************************
3215 Integer to character conversion. Where applicable, we try to do this
3216 in one step if the original object is in memory.
3219 chrCode :: StixTree -> UniqSM Register
3221 #if alpha_TARGET_ARCH
3224 = getRegister x `thenUs` \ register ->
3225 getNewRegNCG IntRep `thenUs` \ reg ->
3227 code = registerCode register reg
3228 src = registerName register reg
3229 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3231 returnUs (Any IntRep code__2)
3233 #endif {- alpha_TARGET_ARCH -}
3234 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3235 #if i386_TARGET_ARCH
3238 = getRegister x `thenUs` \ register ->
3239 --getNewRegNCG IntRep `thenUs` \ reg ->
3241 -- fixedname = registerName register eax
3243 code = registerCode register dst
3244 src = registerName register dst
3246 if isFixed register && src /= dst
3247 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3248 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3249 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3251 returnUs (Any IntRep code__2)
3253 #endif {- i386_TARGET_ARCH -}
3254 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3255 #if sparc_TARGET_ARCH
3257 chrCode (StInd pk mem)
3258 = getAmode mem `thenUs` \ amode ->
3260 code = amodeCode amode
3261 src = amodeAddr amode
3262 src_off = addrOffset src 3
3263 src__2 = case src_off of Just x -> x
3264 code__2 dst = if maybeToBool src_off then
3265 code . mkSeqInstr (LD BU src__2 dst)
3267 code . mkSeqInstrs [
3268 LD (primRepToSize pk) src dst,
3269 AND False dst (RIImm (ImmInt 255)) dst]
3271 returnUs (Any pk code__2)
3274 = getRegister x `thenUs` \ register ->
3275 getNewRegNCG IntRep `thenUs` \ reg ->
3277 code = registerCode register reg
3278 src = registerName register reg
3279 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3281 returnUs (Any IntRep code__2)
3283 #endif {- sparc_TARGET_ARCH -}
3286 %************************************************************************
3288 \subsubsection{Absolute value on integers}
3290 %************************************************************************
3292 Absolute value on integers, mostly for gmp size check macros. Again,
3293 the argument cannot be an StInt, because genericOpt already folded
3296 If applicable, do not fill the delay slots here; you will confuse the
3300 absIntCode :: StixTree -> UniqSM Register
3302 #if alpha_TARGET_ARCH
3303 absIntCode = panic "MachCode.absIntCode: not on Alphas"
3304 #endif {- alpha_TARGET_ARCH -}
3306 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3307 #if i386_TARGET_ARCH
3310 = getRegister x `thenUs` \ register ->
3311 --getNewRegNCG IntRep `thenUs` \ reg ->
3312 getUniqLabelNCG `thenUs` \ lbl ->
3314 code__2 dst = let code = registerCode register dst
3315 src = registerName register dst
3316 in code . if isFixed register && dst /= src
3317 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3318 TEST L (OpReg dst) (OpReg dst),
3322 else mkSeqInstrs [TEST L (OpReg src) (OpReg src),
3327 returnUs (Any IntRep code__2)
3329 #endif {- i386_TARGET_ARCH -}
3330 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3331 #if sparc_TARGET_ARCH
3334 = getRegister x `thenUs` \ register ->
3335 getNewRegNCG IntRep `thenUs` \ reg ->
3336 getUniqLabelNCG `thenUs` \ lbl ->
3338 code = registerCode register reg
3339 src = registerName register reg
3340 code__2 dst = code . mkSeqInstrs [
3341 SUB False True g0 (RIReg src) dst,
3342 BI GE False (ImmCLbl lbl), NOP,
3343 OR False g0 (RIReg src) dst,
3346 returnUs (Any IntRep code__2)
3348 #endif {- sparc_TARGET_ARCH -}