2 % (c) The AQUA Project, Glasgow University, 1996-1998
4 \section[MachCode]{Generating machine code}
6 This is a big module, but, if you pay attention to
7 (a) the sectioning, (b) the type signatures, and
8 (c) the \tr{#if blah_TARGET_ARCH} things, the
9 structure should not be too overwhelming.
12 module MachCode ( stmt2Instrs, asmVoid, InstrList ) where
14 #include "HsVersions.h"
15 #include "nativeGen/NCG.h"
17 import MachMisc -- may differ per-platform
20 import AbsCSyn ( MagicId )
21 import AbsCUtils ( magicIdPrimRep )
22 import CallConv ( CallConv )
23 import CLabel ( isAsmTemp, CLabel, pprCLabel_asm )
24 import Maybes ( maybeToBool, expectJust )
25 import OrdList -- quite a bit of it
26 import PrimRep ( isFloatingRep, PrimRep(..) )
27 import PrimOp ( PrimOp(..) )
28 import CallConv ( cCallConv )
29 import Stix ( getUniqLabelNCG, StixTree(..),
30 StixReg(..), CodeSegment(..),
31 pprStixTrees, ppStixReg
33 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
37 import PprMach ( pprSize )
40 Code extractor for an entire stix tree---stix statement level.
43 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
45 stmt2Instrs stmt = case stmt of
46 StComment s -> returnInstr (COMMENT s)
47 StSegment seg -> returnInstr (SEGMENT seg)
49 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
50 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
51 StLabel lab -> returnInstr (LABEL lab)
53 StJump arg -> genJump arg
54 StCondJump lab arg -> genCondJump lab arg
55 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
58 | isFloatingRep pk -> assignFltCode pk dst src
59 | otherwise -> assignIntCode pk dst src
62 -- When falling through on the Alpha, we still have to load pv
63 -- with the address of the next routine, so that it can load gp.
64 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
68 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
69 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
70 (foldr (.) id codes xs))
72 getData :: StixTree -> UniqSM (InstrBlock, Imm)
74 getData (StInt i) = returnUs (id, ImmInteger i)
75 getData (StDouble d) = returnUs (id, ImmDouble d)
76 getData (StLitLbl s) = returnUs (id, ImmLab s)
77 getData (StCLbl l) = returnUs (id, ImmCLbl l)
78 getData (StString s) =
79 getUniqLabelNCG `thenUs` \ lbl ->
80 returnUs (mkSeqInstrs [LABEL lbl,
81 ASCII True (_UNPK_ s)],
83 -- the linker can handle simple arithmetic...
84 getData (StIndex rep (StCLbl lbl) (StInt off)) =
85 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
88 %************************************************************************
90 \subsection{General things for putting together code sequences}
92 %************************************************************************
95 type InstrList = OrdList Instr
96 type InstrBlock = InstrList -> InstrList
101 asmInstr :: Instr -> InstrList
102 asmInstr i = mkUnitList i
104 asmSeq :: [Instr] -> InstrList
105 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
107 asmParThen :: [InstrList] -> InstrBlock
108 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
110 returnInstr :: Instr -> UniqSM InstrBlock
111 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
113 returnInstrs :: [Instr] -> UniqSM InstrBlock
114 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
116 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
117 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
119 mkSeqInstr :: Instr -> InstrBlock
120 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
122 mkSeqInstrs :: [Instr] -> InstrBlock
123 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
127 mangleIndexTree :: StixTree -> StixTree
129 mangleIndexTree (StIndex pk base (StInt i))
130 = StPrim IntAddOp [base, off]
132 off = StInt (i * sizeOf pk)
134 mangleIndexTree (StIndex pk base off)
138 in ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
139 if s == 0 then off else StPrim SllOp [off, StInt s]
142 shift DoubleRep = 3::Integer
143 shift CharRep = 0::Integer
144 shift _ = IF_ARCH_alpha(3,2)
148 maybeImm :: StixTree -> Maybe Imm
150 maybeImm (StLitLbl s) = Just (ImmLab s)
151 maybeImm (StCLbl l) = Just (ImmCLbl l)
153 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
154 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
157 | i >= toInteger minInt && i <= toInteger maxInt
158 = Just (ImmInt (fromInteger i))
160 = Just (ImmInteger i)
165 %************************************************************************
167 \subsection{The @Register@ type}
169 %************************************************************************
171 @Register@s passed up the tree. If the stix code forces the register
172 to live in a pre-decided machine register, it comes out as @Fixed@;
173 otherwise, it comes out as @Any@, and the parent can decide which
174 register to put it in.
178 = Fixed PrimRep Reg InstrBlock
179 | Any PrimRep (Reg -> InstrBlock)
181 registerCode :: Register -> Reg -> InstrBlock
182 registerCode (Fixed _ _ code) reg = code
183 registerCode (Any _ code) reg = code reg
185 registerName :: Register -> Reg -> Reg
186 registerName (Fixed _ reg _) _ = reg
187 registerName (Any _ _) reg = reg
189 registerRep :: Register -> PrimRep
190 registerRep (Fixed pk _ _) = pk
191 registerRep (Any pk _) = pk
193 isFixed :: Register -> Bool
194 isFixed (Fixed _ _ _) = True
195 isFixed (Any _ _) = False
198 Generate code to get a subtree into a @Register@:
200 getRegister :: StixTree -> UniqSM Register
202 getRegister (StReg (StixMagicId stgreg))
203 = case (magicIdRegMaybe stgreg) of
204 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
207 getRegister (StReg (StixTemp u pk))
208 = returnUs (Fixed pk (UnmappedReg u pk) id)
210 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
212 getRegister (StCall fn cconv kind args)
213 = genCCall fn cconv kind args `thenUs` \ call ->
214 returnUs (Fixed kind reg call)
216 reg = if isFloatingRep kind
217 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
218 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
220 getRegister (StString s)
221 = getUniqLabelNCG `thenUs` \ lbl ->
223 imm_lbl = ImmCLbl lbl
225 code dst = mkSeqInstrs [
228 ASCII True (_UNPK_ s),
230 #if alpha_TARGET_ARCH
231 LDA dst (AddrImm imm_lbl)
234 MOV L (OpImm imm_lbl) (OpReg dst)
236 #if sparc_TARGET_ARCH
237 SETHI (HI imm_lbl) dst,
238 OR False dst (RIImm (LO imm_lbl)) dst
242 returnUs (Any PtrRep code)
246 -- end of machine-"independent" bit; here we go on the rest...
248 #if alpha_TARGET_ARCH
250 getRegister (StDouble d)
251 = getUniqLabelNCG `thenUs` \ lbl ->
252 getNewRegNCG PtrRep `thenUs` \ tmp ->
253 let code dst = mkSeqInstrs [
256 DATA TF [ImmLab (rational d)],
258 LDA tmp (AddrImm (ImmCLbl lbl)),
259 LD TF dst (AddrReg tmp)]
261 returnUs (Any DoubleRep code)
263 getRegister (StPrim primop [x]) -- unary PrimOps
265 IntNegOp -> trivialUCode (NEG Q False) x
267 NotOp -> trivialUCode NOT x
269 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
270 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
272 OrdOp -> coerceIntCode IntRep x
275 Float2IntOp -> coerceFP2Int x
276 Int2FloatOp -> coerceInt2FP pr x
277 Double2IntOp -> coerceFP2Int x
278 Int2DoubleOp -> coerceInt2FP pr x
280 Double2FloatOp -> coerceFltCode x
281 Float2DoubleOp -> coerceFltCode x
283 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
285 fn = case other_op of
286 FloatExpOp -> SLIT("exp")
287 FloatLogOp -> SLIT("log")
288 FloatSqrtOp -> SLIT("sqrt")
289 FloatSinOp -> SLIT("sin")
290 FloatCosOp -> SLIT("cos")
291 FloatTanOp -> SLIT("tan")
292 FloatAsinOp -> SLIT("asin")
293 FloatAcosOp -> SLIT("acos")
294 FloatAtanOp -> SLIT("atan")
295 FloatSinhOp -> SLIT("sinh")
296 FloatCoshOp -> SLIT("cosh")
297 FloatTanhOp -> SLIT("tanh")
298 DoubleExpOp -> SLIT("exp")
299 DoubleLogOp -> SLIT("log")
300 DoubleSqrtOp -> SLIT("sqrt")
301 DoubleSinOp -> SLIT("sin")
302 DoubleCosOp -> SLIT("cos")
303 DoubleTanOp -> SLIT("tan")
304 DoubleAsinOp -> SLIT("asin")
305 DoubleAcosOp -> SLIT("acos")
306 DoubleAtanOp -> SLIT("atan")
307 DoubleSinhOp -> SLIT("sinh")
308 DoubleCoshOp -> SLIT("cosh")
309 DoubleTanhOp -> SLIT("tanh")
311 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
313 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
315 CharGtOp -> trivialCode (CMP LTT) y x
316 CharGeOp -> trivialCode (CMP LE) y x
317 CharEqOp -> trivialCode (CMP EQQ) x y
318 CharNeOp -> int_NE_code x y
319 CharLtOp -> trivialCode (CMP LTT) x y
320 CharLeOp -> trivialCode (CMP LE) x y
322 IntGtOp -> trivialCode (CMP LTT) y x
323 IntGeOp -> trivialCode (CMP LE) y x
324 IntEqOp -> trivialCode (CMP EQQ) x y
325 IntNeOp -> int_NE_code x y
326 IntLtOp -> trivialCode (CMP LTT) x y
327 IntLeOp -> trivialCode (CMP LE) x y
329 WordGtOp -> trivialCode (CMP ULT) y x
330 WordGeOp -> trivialCode (CMP ULE) x y
331 WordEqOp -> trivialCode (CMP EQQ) x y
332 WordNeOp -> int_NE_code x y
333 WordLtOp -> trivialCode (CMP ULT) x y
334 WordLeOp -> trivialCode (CMP ULE) x y
336 AddrGtOp -> trivialCode (CMP ULT) y x
337 AddrGeOp -> trivialCode (CMP ULE) y x
338 AddrEqOp -> trivialCode (CMP EQQ) x y
339 AddrNeOp -> int_NE_code x y
340 AddrLtOp -> trivialCode (CMP ULT) x y
341 AddrLeOp -> trivialCode (CMP ULE) x y
343 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
344 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
345 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
346 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
347 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
348 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
350 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
351 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
352 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
353 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
354 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
355 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
357 IntAddOp -> trivialCode (ADD Q False) x y
358 IntSubOp -> trivialCode (SUB Q False) x y
359 IntMulOp -> trivialCode (MUL Q False) x y
360 IntQuotOp -> trivialCode (DIV Q False) x y
361 IntRemOp -> trivialCode (REM Q False) x y
363 WordQuotOp -> trivialCode (DIV Q True) x y
364 WordRemOp -> trivialCode (REM Q True) x y
366 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
367 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
368 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
369 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
371 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
372 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
373 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
374 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
376 AndOp -> trivialCode AND x y
377 OrOp -> trivialCode OR x y
378 XorOp -> trivialCode XOR x y
379 SllOp -> trivialCode SLL x y
380 SrlOp -> trivialCode SRL x y
382 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
383 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
384 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
386 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
387 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
389 {- ------------------------------------------------------------
390 Some bizarre special code for getting condition codes into
391 registers. Integer non-equality is a test for equality
392 followed by an XOR with 1. (Integer comparisons always set
393 the result register to 0 or 1.) Floating point comparisons of
394 any kind leave the result in a floating point register, so we
395 need to wrangle an integer register out of things.
397 int_NE_code :: StixTree -> StixTree -> UniqSM Register
400 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
401 getNewRegNCG IntRep `thenUs` \ tmp ->
403 code = registerCode register tmp
404 src = registerName register tmp
405 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
407 returnUs (Any IntRep code__2)
409 {- ------------------------------------------------------------
410 Comments for int_NE_code also apply to cmpF_code
413 :: (Reg -> Reg -> Reg -> Instr)
415 -> StixTree -> StixTree
418 cmpF_code instr cond x y
419 = trivialFCode pr instr x y `thenUs` \ register ->
420 getNewRegNCG DoubleRep `thenUs` \ tmp ->
421 getUniqLabelNCG `thenUs` \ lbl ->
423 code = registerCode register tmp
424 result = registerName register tmp
426 code__2 dst = code . mkSeqInstrs [
427 OR zeroh (RIImm (ImmInt 1)) dst,
428 BF cond result (ImmCLbl lbl),
429 OR zeroh (RIReg zeroh) dst,
432 returnUs (Any IntRep code__2)
434 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
435 ------------------------------------------------------------
437 getRegister (StInd pk mem)
438 = getAmode mem `thenUs` \ amode ->
440 code = amodeCode amode
441 src = amodeAddr amode
442 size = primRepToSize pk
443 code__2 dst = code . mkSeqInstr (LD size dst src)
445 returnUs (Any pk code__2)
447 getRegister (StInt i)
450 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
452 returnUs (Any IntRep code)
455 code dst = mkSeqInstr (LDI Q dst src)
457 returnUs (Any IntRep code)
459 src = ImmInt (fromInteger i)
464 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
466 returnUs (Any PtrRep code)
469 imm__2 = case imm of Just x -> x
471 #endif {- alpha_TARGET_ARCH -}
472 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
475 getRegister (StDouble d)
476 = getUniqLabelNCG `thenUs` \ lbl ->
477 let code dst = mkSeqInstrs [
480 DATA DF [ImmDouble d],
482 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
485 returnUs (Any DoubleRep code)
487 getRegister (StScratchWord i)
488 = let code dst = mkSeqInstr (LEA L (OpAddr (spRel (-1000+i))) (OpReg dst))
489 in returnUs (Any PtrRep code)
491 getRegister (StPrim primop [x]) -- unary PrimOps
493 IntNegOp -> trivialUCode (NEGI L) x
494 NotOp -> trivialUCode (NOT L) x
496 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
497 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
499 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
500 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
502 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
503 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
505 OrdOp -> coerceIntCode IntRep x
508 Float2IntOp -> coerceFP2Int x
509 Int2FloatOp -> coerceInt2FP FloatRep x
510 Double2IntOp -> coerceFP2Int x
511 Int2DoubleOp -> coerceInt2FP DoubleRep x
515 fixed_x = if is_float_op -- promote to double
516 then StPrim Float2DoubleOp [x]
519 getRegister (StCall fn cCallConv DoubleRep [x])
523 FloatExpOp -> (True, SLIT("exp"))
524 FloatLogOp -> (True, SLIT("log"))
526 FloatSinOp -> (True, SLIT("sin"))
527 FloatCosOp -> (True, SLIT("cos"))
528 FloatTanOp -> (True, SLIT("tan"))
530 FloatAsinOp -> (True, SLIT("asin"))
531 FloatAcosOp -> (True, SLIT("acos"))
532 FloatAtanOp -> (True, SLIT("atan"))
534 FloatSinhOp -> (True, SLIT("sinh"))
535 FloatCoshOp -> (True, SLIT("cosh"))
536 FloatTanhOp -> (True, SLIT("tanh"))
538 DoubleExpOp -> (False, SLIT("exp"))
539 DoubleLogOp -> (False, SLIT("log"))
541 DoubleSinOp -> (False, SLIT("sin"))
542 DoubleCosOp -> (False, SLIT("cos"))
543 DoubleTanOp -> (False, SLIT("tan"))
545 DoubleAsinOp -> (False, SLIT("asin"))
546 DoubleAcosOp -> (False, SLIT("acos"))
547 DoubleAtanOp -> (False, SLIT("atan"))
549 DoubleSinhOp -> (False, SLIT("sinh"))
550 DoubleCoshOp -> (False, SLIT("cosh"))
551 DoubleTanhOp -> (False, SLIT("tanh"))
554 -> pprPanic "getRegister(x86,unary primop)"
555 (pprStixTrees [StPrim primop [x]])
557 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
559 CharGtOp -> condIntReg GTT x y
560 CharGeOp -> condIntReg GE x y
561 CharEqOp -> condIntReg EQQ x y
562 CharNeOp -> condIntReg NE x y
563 CharLtOp -> condIntReg LTT x y
564 CharLeOp -> condIntReg LE x y
566 IntGtOp -> condIntReg GTT x y
567 IntGeOp -> condIntReg GE x y
568 IntEqOp -> condIntReg EQQ x y
569 IntNeOp -> condIntReg NE x y
570 IntLtOp -> condIntReg LTT x y
571 IntLeOp -> condIntReg LE x y
573 WordGtOp -> condIntReg GU x y
574 WordGeOp -> condIntReg GEU x y
575 WordEqOp -> condIntReg EQQ x y
576 WordNeOp -> condIntReg NE x y
577 WordLtOp -> condIntReg LU x y
578 WordLeOp -> condIntReg LEU x y
580 AddrGtOp -> condIntReg GU x y
581 AddrGeOp -> condIntReg GEU x y
582 AddrEqOp -> condIntReg EQQ x y
583 AddrNeOp -> condIntReg NE x y
584 AddrLtOp -> condIntReg LU x y
585 AddrLeOp -> condIntReg LEU x y
587 FloatGtOp -> condFltReg GTT x y
588 FloatGeOp -> condFltReg GE x y
589 FloatEqOp -> condFltReg EQQ x y
590 FloatNeOp -> condFltReg NE x y
591 FloatLtOp -> condFltReg LTT x y
592 FloatLeOp -> condFltReg LE x y
594 DoubleGtOp -> condFltReg GTT x y
595 DoubleGeOp -> condFltReg GE x y
596 DoubleEqOp -> condFltReg EQQ x y
597 DoubleNeOp -> condFltReg NE x y
598 DoubleLtOp -> condFltReg LTT x y
599 DoubleLeOp -> condFltReg LE x y
601 IntAddOp -> add_code L x y
602 IntSubOp -> sub_code L x y
603 IntQuotOp -> quot_code L x y True{-division-}
604 IntRemOp -> quot_code L x y False{-remainder-}
605 IntMulOp -> trivialCode (IMUL L) x y {-True-}
607 FloatAddOp -> trivialFCode FloatRep GADD x y
608 FloatSubOp -> trivialFCode FloatRep GSUB x y
609 FloatMulOp -> trivialFCode FloatRep GMUL x y
610 FloatDivOp -> trivialFCode FloatRep GDIV x y
612 DoubleAddOp -> trivialFCode DoubleRep GADD x y
613 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
614 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
615 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
617 AndOp -> trivialCode (AND L) x y {-True-}
618 OrOp -> trivialCode (OR L) x y {-True-}
619 XorOp -> trivialCode (XOR L) x y {-True-}
621 {- Shift ops on x86s have constraints on their source, it
622 either has to be Imm, CL or 1
623 => trivialCode's is not restrictive enough (sigh.)
626 SllOp -> shift_code (SHL L) x y {-False-}
627 SrlOp -> shift_code (SHR L) x y {-False-}
629 ISllOp -> shift_code (SHL L) x y {-False-}
630 ISraOp -> shift_code (SAR L) x y {-False-}
631 ISrlOp -> shift_code (SHR L) x y {-False-}
633 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
634 [promote x, promote y])
635 where promote x = StPrim Float2DoubleOp [x]
636 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
639 -> pprPanic "getRegister(x86,dyadic primop)"
640 (pprStixTrees [StPrim primop [x, y]])
644 shift_code :: (Operand -> Operand -> Instr)
649 {- Case1: shift length as immediate -}
650 -- Code is the same as the first eq. for trivialCode -- sigh.
651 shift_code instr x y{-amount-}
653 = getRegister x `thenUs` \ register ->
655 op_imm = OpImm imm__2
658 code = registerCode register dst
659 src = registerName register dst
661 mkSeqInstr (COMMENT SLIT("shift_code")) .
663 if isFixed register && src /= dst
665 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
666 instr op_imm (OpReg dst)]
668 mkSeqInstr (instr op_imm (OpReg src))
670 returnUs (Any IntRep code__2)
673 imm__2 = case imm of Just x -> x
675 {- Case2: shift length is complex (non-immediate) -}
676 shift_code instr x y{-amount-}
677 = getRegister y `thenUs` \ register1 ->
678 getRegister x `thenUs` \ register2 ->
680 -- Note: we force the shift length to be loaded
681 -- into ECX, so that we can use CL when shifting.
682 -- (only register location we are allowed
683 -- to put shift amounts.)
685 -- The shift instruction is fed ECX as src reg,
686 -- but we coerce this into CL when printing out.
687 src1 = registerName register1 ecx
688 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
689 registerCode register1 ecx .
690 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
692 registerCode register1 ecx
695 code2 = registerCode register2 eax
696 src2 = registerName register2 eax
699 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
701 returnUs (Fixed IntRep eax code__2)
704 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
706 add_code sz x (StInt y)
707 = getRegister x `thenUs` \ register ->
708 getNewRegNCG IntRep `thenUs` \ tmp ->
710 code = registerCode register tmp
711 src1 = registerName register tmp
712 src2 = ImmInt (fromInteger y)
715 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
718 returnUs (Any IntRep code__2)
721 = getRegister x `thenUs` \ register1 ->
722 getRegister y `thenUs` \ register2 ->
723 getNewRegNCG IntRep `thenUs` \ tmp1 ->
724 getNewRegNCG IntRep `thenUs` \ tmp2 ->
726 code1 = registerCode register1 tmp1 asmVoid
727 src1 = registerName register1 tmp1
728 code2 = registerCode register2 tmp2 asmVoid
729 src2 = registerName register2 tmp2
731 = asmParThen [code1, code2] .
732 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1))
736 returnUs (Any IntRep code__2)
739 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
741 sub_code sz x (StInt y)
742 = getRegister x `thenUs` \ register ->
743 getNewRegNCG IntRep `thenUs` \ tmp ->
745 code = registerCode register tmp
746 src1 = registerName register tmp
747 src2 = ImmInt (-(fromInteger y))
750 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
753 returnUs (Any IntRep code__2)
755 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
760 -> StixTree -> StixTree
761 -> Bool -- True => division, False => remainder operation
764 -- x must go into eax, edx must be a sign-extension of eax, and y
765 -- should go in some other register (or memory), so that we get
766 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
767 -- put y in memory (if it is not there already)
769 quot_code sz x (StInd pk mem) is_division
770 = getRegister x `thenUs` \ register1 ->
771 getNewRegNCG IntRep `thenUs` \ tmp1 ->
772 getAmode mem `thenUs` \ amode ->
774 code1 = registerCode register1 tmp1 asmVoid
775 src1 = registerName register1 tmp1
776 code2 = amodeCode amode asmVoid
777 src2 = amodeAddr amode
778 code__2 = asmParThen [code1, code2] .
779 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
781 IDIV sz (OpAddr src2)]
783 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
785 quot_code sz x (StInt i) is_division
786 = getRegister x `thenUs` \ register1 ->
787 getNewRegNCG IntRep `thenUs` \ tmp1 ->
789 code1 = registerCode register1 tmp1 asmVoid
790 src1 = registerName register1 tmp1
791 src2 = ImmInt (fromInteger i)
792 code__2 = asmParThen [code1] .
793 mkSeqInstrs [-- we put src2 in (ebx)
795 (OpAddr (AddrBaseIndex (Just ebx) Nothing
796 (ImmInt OFFSET_R1))),
797 MOV L (OpReg src1) (OpReg eax),
799 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
803 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
805 quot_code sz x y is_division
806 = getRegister x `thenUs` \ register1 ->
807 getNewRegNCG IntRep `thenUs` \ tmp1 ->
808 getRegister y `thenUs` \ register2 ->
809 getNewRegNCG IntRep `thenUs` \ tmp2 ->
811 code1 = registerCode register1 tmp1 asmVoid
812 src1 = registerName register1 tmp1
813 code2 = registerCode register2 tmp2 asmVoid
814 src2 = registerName register2 tmp2
815 code__2 = asmParThen [code1, code2] .
816 if src2 == ecx || src2 == esi
818 MOV L (OpReg src1) (OpReg eax),
822 else mkSeqInstrs [ -- we put src2 in (ebx)
824 (OpAddr (AddrBaseIndex (Just ebx) Nothing
825 (ImmInt OFFSET_R1))),
826 MOV L (OpReg src1) (OpReg eax),
828 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
832 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
833 -----------------------
835 getRegister (StInd pk mem)
836 = getAmode mem `thenUs` \ amode ->
838 code = amodeCode amode
839 src = amodeAddr amode
840 size = primRepToSize pk
842 if pk == DoubleRep || pk == FloatRep
843 then mkSeqInstr (GLD size src dst)
844 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
846 returnUs (Any pk code__2)
848 getRegister (StInt i)
850 src = ImmInt (fromInteger i)
851 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
853 returnUs (Any IntRep code)
858 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
860 returnUs (Any PtrRep code)
862 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
865 imm__2 = case imm of Just x -> x
867 #endif {- i386_TARGET_ARCH -}
868 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
869 #if sparc_TARGET_ARCH
871 getRegister (StDouble d)
872 = getUniqLabelNCG `thenUs` \ lbl ->
873 getNewRegNCG PtrRep `thenUs` \ tmp ->
874 let code dst = mkSeqInstrs [
877 DATA DF [ImmDouble d],
879 SETHI (HI (ImmCLbl lbl)) tmp,
880 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
882 returnUs (Any DoubleRep code)
884 getRegister (StPrim primop [x]) -- unary PrimOps
886 IntNegOp -> trivialUCode (SUB False False g0) x
887 NotOp -> trivialUCode (XNOR False g0) x
889 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
891 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
893 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
894 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
896 OrdOp -> coerceIntCode IntRep x
899 Float2IntOp -> coerceFP2Int x
900 Int2FloatOp -> coerceInt2FP FloatRep x
901 Double2IntOp -> coerceFP2Int x
902 Int2DoubleOp -> coerceInt2FP DoubleRep x
906 fixed_x = if is_float_op -- promote to double
907 then StPrim Float2DoubleOp [x]
910 getRegister (StCall fn cCallConv DoubleRep [x])
914 FloatExpOp -> (True, SLIT("exp"))
915 FloatLogOp -> (True, SLIT("log"))
916 FloatSqrtOp -> (True, SLIT("sqrt"))
918 FloatSinOp -> (True, SLIT("sin"))
919 FloatCosOp -> (True, SLIT("cos"))
920 FloatTanOp -> (True, SLIT("tan"))
922 FloatAsinOp -> (True, SLIT("asin"))
923 FloatAcosOp -> (True, SLIT("acos"))
924 FloatAtanOp -> (True, SLIT("atan"))
926 FloatSinhOp -> (True, SLIT("sinh"))
927 FloatCoshOp -> (True, SLIT("cosh"))
928 FloatTanhOp -> (True, SLIT("tanh"))
930 DoubleExpOp -> (False, SLIT("exp"))
931 DoubleLogOp -> (False, SLIT("log"))
932 DoubleSqrtOp -> (True, SLIT("sqrt"))
934 DoubleSinOp -> (False, SLIT("sin"))
935 DoubleCosOp -> (False, SLIT("cos"))
936 DoubleTanOp -> (False, SLIT("tan"))
938 DoubleAsinOp -> (False, SLIT("asin"))
939 DoubleAcosOp -> (False, SLIT("acos"))
940 DoubleAtanOp -> (False, SLIT("atan"))
942 DoubleSinhOp -> (False, SLIT("sinh"))
943 DoubleCoshOp -> (False, SLIT("cosh"))
944 DoubleTanhOp -> (False, SLIT("tanh"))
945 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
947 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
949 CharGtOp -> condIntReg GTT x y
950 CharGeOp -> condIntReg GE x y
951 CharEqOp -> condIntReg EQQ x y
952 CharNeOp -> condIntReg NE x y
953 CharLtOp -> condIntReg LTT x y
954 CharLeOp -> condIntReg LE x y
956 IntGtOp -> condIntReg GTT x y
957 IntGeOp -> condIntReg GE x y
958 IntEqOp -> condIntReg EQQ x y
959 IntNeOp -> condIntReg NE x y
960 IntLtOp -> condIntReg LTT x y
961 IntLeOp -> condIntReg LE x y
963 WordGtOp -> condIntReg GU x y
964 WordGeOp -> condIntReg GEU x y
965 WordEqOp -> condIntReg EQQ x y
966 WordNeOp -> condIntReg NE x y
967 WordLtOp -> condIntReg LU x y
968 WordLeOp -> condIntReg LEU x y
970 AddrGtOp -> condIntReg GU x y
971 AddrGeOp -> condIntReg GEU x y
972 AddrEqOp -> condIntReg EQQ x y
973 AddrNeOp -> condIntReg NE x y
974 AddrLtOp -> condIntReg LU x y
975 AddrLeOp -> condIntReg LEU x y
977 FloatGtOp -> condFltReg GTT x y
978 FloatGeOp -> condFltReg GE x y
979 FloatEqOp -> condFltReg EQQ x y
980 FloatNeOp -> condFltReg NE x y
981 FloatLtOp -> condFltReg LTT x y
982 FloatLeOp -> condFltReg LE x y
984 DoubleGtOp -> condFltReg GTT x y
985 DoubleGeOp -> condFltReg GE x y
986 DoubleEqOp -> condFltReg EQQ x y
987 DoubleNeOp -> condFltReg NE x y
988 DoubleLtOp -> condFltReg LTT x y
989 DoubleLeOp -> condFltReg LE x y
991 IntAddOp -> trivialCode (ADD False False) x y
992 IntSubOp -> trivialCode (SUB False False) x y
994 -- ToDo: teach about V8+ SPARC mul/div instructions
995 IntMulOp -> imul_div SLIT(".umul") x y
996 IntQuotOp -> imul_div SLIT(".div") x y
997 IntRemOp -> imul_div SLIT(".rem") x y
999 FloatAddOp -> trivialFCode FloatRep FADD x y
1000 FloatSubOp -> trivialFCode FloatRep FSUB x y
1001 FloatMulOp -> trivialFCode FloatRep FMUL x y
1002 FloatDivOp -> trivialFCode FloatRep FDIV x y
1004 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1005 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1006 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1007 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1009 AndOp -> trivialCode (AND False) x y
1010 OrOp -> trivialCode (OR False) x y
1011 XorOp -> trivialCode (XOR False) x y
1012 SllOp -> trivialCode SLL x y
1013 SrlOp -> trivialCode SRL x y
1015 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1016 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1017 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1019 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1020 where promote x = StPrim Float2DoubleOp [x]
1021 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1022 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1024 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1026 getRegister (StInd pk mem)
1027 = getAmode mem `thenUs` \ amode ->
1029 code = amodeCode amode
1030 src = amodeAddr amode
1031 size = primRepToSize pk
1032 code__2 dst = code . mkSeqInstr (LD size src dst)
1034 returnUs (Any pk code__2)
1036 getRegister (StInt i)
1039 src = ImmInt (fromInteger i)
1040 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1042 returnUs (Any IntRep code)
1047 code dst = mkSeqInstrs [
1048 SETHI (HI imm__2) dst,
1049 OR False dst (RIImm (LO imm__2)) dst]
1051 returnUs (Any PtrRep code)
1054 imm__2 = case imm of Just x -> x
1056 #endif {- sparc_TARGET_ARCH -}
1059 %************************************************************************
1061 \subsection{The @Amode@ type}
1063 %************************************************************************
1065 @Amode@s: Memory addressing modes passed up the tree.
1067 data Amode = Amode MachRegsAddr InstrBlock
1069 amodeAddr (Amode addr _) = addr
1070 amodeCode (Amode _ code) = code
1073 Now, given a tree (the argument to an StInd) that references memory,
1074 produce a suitable addressing mode.
1077 getAmode :: StixTree -> UniqSM Amode
1079 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1081 #if alpha_TARGET_ARCH
1083 getAmode (StPrim IntSubOp [x, StInt i])
1084 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1085 getRegister x `thenUs` \ register ->
1087 code = registerCode register tmp
1088 reg = registerName register tmp
1089 off = ImmInt (-(fromInteger i))
1091 returnUs (Amode (AddrRegImm reg off) code)
1093 getAmode (StPrim IntAddOp [x, StInt i])
1094 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1095 getRegister x `thenUs` \ register ->
1097 code = registerCode register tmp
1098 reg = registerName register tmp
1099 off = ImmInt (fromInteger i)
1101 returnUs (Amode (AddrRegImm reg off) code)
1105 = returnUs (Amode (AddrImm imm__2) id)
1108 imm__2 = case imm of Just x -> x
1111 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1112 getRegister other `thenUs` \ register ->
1114 code = registerCode register tmp
1115 reg = registerName register tmp
1117 returnUs (Amode (AddrReg reg) code)
1119 #endif {- alpha_TARGET_ARCH -}
1120 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1121 #if i386_TARGET_ARCH
1123 getAmode (StPrim IntSubOp [x, StInt i])
1124 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1125 getRegister x `thenUs` \ register ->
1127 code = registerCode register tmp
1128 reg = registerName register tmp
1129 off = ImmInt (-(fromInteger i))
1131 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1133 getAmode (StPrim IntAddOp [x, StInt i])
1136 code = mkSeqInstrs []
1138 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1141 imm__2 = case imm of Just x -> x
1143 getAmode (StPrim IntAddOp [x, StInt i])
1144 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1145 getRegister x `thenUs` \ register ->
1147 code = registerCode register tmp
1148 reg = registerName register tmp
1149 off = ImmInt (fromInteger i)
1151 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1153 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1154 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1155 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1156 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1157 getRegister x `thenUs` \ register1 ->
1158 getRegister y `thenUs` \ register2 ->
1160 code1 = registerCode register1 tmp1 asmVoid
1161 reg1 = registerName register1 tmp1
1162 code2 = registerCode register2 tmp2 asmVoid
1163 reg2 = registerName register2 tmp2
1164 code__2 = asmParThen [code1, code2]
1165 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1167 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1173 code = mkSeqInstrs []
1175 returnUs (Amode (ImmAddr imm__2 0) code)
1178 imm__2 = case imm of Just x -> x
1181 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1182 getRegister other `thenUs` \ register ->
1184 code = registerCode register tmp
1185 reg = registerName register tmp
1188 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1190 #endif {- i386_TARGET_ARCH -}
1191 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1192 #if sparc_TARGET_ARCH
1194 getAmode (StPrim IntSubOp [x, StInt i])
1196 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1197 getRegister x `thenUs` \ register ->
1199 code = registerCode register tmp
1200 reg = registerName register tmp
1201 off = ImmInt (-(fromInteger i))
1203 returnUs (Amode (AddrRegImm reg off) code)
1206 getAmode (StPrim IntAddOp [x, StInt i])
1208 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1209 getRegister x `thenUs` \ register ->
1211 code = registerCode register tmp
1212 reg = registerName register tmp
1213 off = ImmInt (fromInteger i)
1215 returnUs (Amode (AddrRegImm reg off) code)
1217 getAmode (StPrim IntAddOp [x, y])
1218 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1219 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1220 getRegister x `thenUs` \ register1 ->
1221 getRegister y `thenUs` \ register2 ->
1223 code1 = registerCode register1 tmp1 asmVoid
1224 reg1 = registerName register1 tmp1
1225 code2 = registerCode register2 tmp2 asmVoid
1226 reg2 = registerName register2 tmp2
1227 code__2 = asmParThen [code1, code2]
1229 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1233 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1235 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1237 returnUs (Amode (AddrRegImm tmp (LO imm__2)) 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 (AddrRegImm reg off) code)
1252 #endif {- sparc_TARGET_ARCH -}
1255 %************************************************************************
1257 \subsection{The @CondCode@ type}
1259 %************************************************************************
1261 Condition codes passed up the tree.
1263 data CondCode = CondCode Bool Cond InstrBlock
1265 condName (CondCode _ cond _) = cond
1266 condFloat (CondCode is_float _ _) = is_float
1267 condCode (CondCode _ _ code) = code
1270 Set up a condition code for a conditional branch.
1273 getCondCode :: StixTree -> UniqSM CondCode
1275 #if alpha_TARGET_ARCH
1276 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1277 #endif {- alpha_TARGET_ARCH -}
1278 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1280 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1281 -- yes, they really do seem to want exactly the same!
1283 getCondCode (StPrim primop [x, y])
1285 CharGtOp -> condIntCode GTT x y
1286 CharGeOp -> condIntCode GE x y
1287 CharEqOp -> condIntCode EQQ x y
1288 CharNeOp -> condIntCode NE x y
1289 CharLtOp -> condIntCode LTT x y
1290 CharLeOp -> condIntCode LE x y
1292 IntGtOp -> condIntCode GTT x y
1293 IntGeOp -> condIntCode GE x y
1294 IntEqOp -> condIntCode EQQ x y
1295 IntNeOp -> condIntCode NE x y
1296 IntLtOp -> condIntCode LTT x y
1297 IntLeOp -> condIntCode LE x y
1299 WordGtOp -> condIntCode GU x y
1300 WordGeOp -> condIntCode GEU x y
1301 WordEqOp -> condIntCode EQQ x y
1302 WordNeOp -> condIntCode NE x y
1303 WordLtOp -> condIntCode LU x y
1304 WordLeOp -> condIntCode LEU x y
1306 AddrGtOp -> condIntCode GU x y
1307 AddrGeOp -> condIntCode GEU x y
1308 AddrEqOp -> condIntCode EQQ x y
1309 AddrNeOp -> condIntCode NE x y
1310 AddrLtOp -> condIntCode LU x y
1311 AddrLeOp -> condIntCode LEU x y
1313 FloatGtOp -> condFltCode GTT x y
1314 FloatGeOp -> condFltCode GE x y
1315 FloatEqOp -> condFltCode EQQ x y
1316 FloatNeOp -> condFltCode NE x y
1317 FloatLtOp -> condFltCode LTT x y
1318 FloatLeOp -> condFltCode LE x y
1320 DoubleGtOp -> condFltCode GTT x y
1321 DoubleGeOp -> condFltCode GE x y
1322 DoubleEqOp -> condFltCode EQQ x y
1323 DoubleNeOp -> condFltCode NE x y
1324 DoubleLtOp -> condFltCode LTT x y
1325 DoubleLeOp -> condFltCode LE x y
1327 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1332 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1333 passed back up the tree.
1336 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1338 #if alpha_TARGET_ARCH
1339 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1340 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1341 #endif {- alpha_TARGET_ARCH -}
1343 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1344 #if i386_TARGET_ARCH
1346 condIntCode cond (StInd _ x) y
1348 = getAmode x `thenUs` \ amode ->
1350 code1 = amodeCode amode asmVoid
1351 y__2 = amodeAddr amode
1352 code__2 = asmParThen [code1] .
1353 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1355 returnUs (CondCode False cond code__2)
1358 imm__2 = case imm of Just x -> x
1360 condIntCode cond x (StInt 0)
1361 = getRegister x `thenUs` \ register1 ->
1362 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1364 code1 = registerCode register1 tmp1 asmVoid
1365 src1 = registerName register1 tmp1
1366 code__2 = asmParThen [code1] .
1367 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1369 returnUs (CondCode False cond code__2)
1371 condIntCode cond x y
1373 = getRegister x `thenUs` \ register1 ->
1374 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1376 code1 = registerCode register1 tmp1 asmVoid
1377 src1 = registerName register1 tmp1
1378 code__2 = asmParThen [code1] .
1379 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1381 returnUs (CondCode False cond code__2)
1384 imm__2 = case imm of Just x -> x
1386 condIntCode cond (StInd _ x) y
1387 = getAmode x `thenUs` \ amode ->
1388 getRegister y `thenUs` \ register2 ->
1389 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1391 code1 = amodeCode amode asmVoid
1392 src1 = amodeAddr amode
1393 code2 = registerCode register2 tmp2 asmVoid
1394 src2 = registerName register2 tmp2
1395 code__2 = asmParThen [code1, code2] .
1396 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1398 returnUs (CondCode False cond code__2)
1400 condIntCode cond y (StInd _ x)
1401 = getAmode x `thenUs` \ amode ->
1402 getRegister y `thenUs` \ register2 ->
1403 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1405 code1 = amodeCode amode asmVoid
1406 src1 = amodeAddr amode
1407 code2 = registerCode register2 tmp2 asmVoid
1408 src2 = registerName register2 tmp2
1409 code__2 = asmParThen [code1, code2] .
1410 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1412 returnUs (CondCode False cond code__2)
1414 condIntCode cond x y
1415 = getRegister x `thenUs` \ register1 ->
1416 getRegister y `thenUs` \ register2 ->
1417 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1418 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1420 code1 = registerCode register1 tmp1 asmVoid
1421 src1 = registerName register1 tmp1
1422 code2 = registerCode register2 tmp2 asmVoid
1423 src2 = registerName register2 tmp2
1424 code__2 = asmParThen [code1, code2] .
1425 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1427 returnUs (CondCode False cond code__2)
1430 condFltCode cond x y
1431 = getRegister x `thenUs` \ register1 ->
1432 getRegister y `thenUs` \ register2 ->
1433 getNewRegNCG (registerRep register1)
1435 getNewRegNCG (registerRep register2)
1437 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1439 pk1 = registerRep register1
1440 code1 = registerCode register1 tmp1
1441 src1 = registerName register1 tmp1
1443 pk2 = registerRep register2
1444 code2 = registerCode register2 tmp2
1445 src2 = registerName register2 tmp2
1447 code__2 = asmParThen [code1 asmVoid, code2 asmVoid] .
1448 mkSeqInstr (GCMP (primRepToSize pk1) src1 src2)
1450 {- On the 486, the flags set by FP compare are the unsigned ones!
1451 (This looks like a HACK to me. WDP 96/03)
1453 fix_FP_cond :: Cond -> Cond
1455 fix_FP_cond GE = GEU
1456 fix_FP_cond GTT = GU
1457 fix_FP_cond LTT = LU
1458 fix_FP_cond LE = LEU
1459 fix_FP_cond any = any
1461 returnUs (CondCode True (fix_FP_cond cond) code__2)
1465 #endif {- i386_TARGET_ARCH -}
1466 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1467 #if sparc_TARGET_ARCH
1469 condIntCode cond x (StInt y)
1471 = getRegister x `thenUs` \ register ->
1472 getNewRegNCG IntRep `thenUs` \ tmp ->
1474 code = registerCode register tmp
1475 src1 = registerName register tmp
1476 src2 = ImmInt (fromInteger y)
1477 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1479 returnUs (CondCode False cond code__2)
1481 condIntCode cond x y
1482 = getRegister x `thenUs` \ register1 ->
1483 getRegister y `thenUs` \ register2 ->
1484 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1485 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1487 code1 = registerCode register1 tmp1 asmVoid
1488 src1 = registerName register1 tmp1
1489 code2 = registerCode register2 tmp2 asmVoid
1490 src2 = registerName register2 tmp2
1491 code__2 = asmParThen [code1, code2] .
1492 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1494 returnUs (CondCode False cond code__2)
1497 condFltCode cond x y
1498 = getRegister x `thenUs` \ register1 ->
1499 getRegister y `thenUs` \ register2 ->
1500 getNewRegNCG (registerRep register1)
1502 getNewRegNCG (registerRep register2)
1504 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1506 promote x = asmInstr (FxTOy F DF x tmp)
1508 pk1 = registerRep register1
1509 code1 = registerCode register1 tmp1
1510 src1 = registerName register1 tmp1
1512 pk2 = registerRep register2
1513 code2 = registerCode register2 tmp2
1514 src2 = registerName register2 tmp2
1518 asmParThen [code1 asmVoid, code2 asmVoid] .
1519 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1520 else if pk1 == FloatRep then
1521 asmParThen [code1 (promote src1), code2 asmVoid] .
1522 mkSeqInstr (FCMP True DF tmp src2)
1524 asmParThen [code1 asmVoid, code2 (promote src2)] .
1525 mkSeqInstr (FCMP True DF src1 tmp)
1527 returnUs (CondCode True cond code__2)
1529 #endif {- sparc_TARGET_ARCH -}
1532 %************************************************************************
1534 \subsection{Generating assignments}
1536 %************************************************************************
1538 Assignments are really at the heart of the whole code generation
1539 business. Almost all top-level nodes of any real importance are
1540 assignments, which correspond to loads, stores, or register transfers.
1541 If we're really lucky, some of the register transfers will go away,
1542 because we can use the destination register to complete the code
1543 generation for the right hand side. This only fails when the right
1544 hand side is forced into a fixed register (e.g. the result of a call).
1547 assignIntCode, assignFltCode
1548 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1550 #if alpha_TARGET_ARCH
1552 assignIntCode pk (StInd _ dst) src
1553 = getNewRegNCG IntRep `thenUs` \ tmp ->
1554 getAmode dst `thenUs` \ amode ->
1555 getRegister src `thenUs` \ register ->
1557 code1 = amodeCode amode asmVoid
1558 dst__2 = amodeAddr amode
1559 code2 = registerCode register tmp asmVoid
1560 src__2 = registerName register tmp
1561 sz = primRepToSize pk
1562 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1566 assignIntCode pk dst src
1567 = getRegister dst `thenUs` \ register1 ->
1568 getRegister src `thenUs` \ register2 ->
1570 dst__2 = registerName register1 zeroh
1571 code = registerCode register2 dst__2
1572 src__2 = registerName register2 dst__2
1573 code__2 = if isFixed register2
1574 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1579 #endif {- alpha_TARGET_ARCH -}
1580 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1581 #if i386_TARGET_ARCH
1583 assignIntCode pk dd@(StInd _ dst) src
1584 = getAmode dst `thenUs` \ amode ->
1585 get_op_RI src `thenUs` \ (codesrc, opsrc) ->
1587 code1 = amodeCode amode asmVoid
1588 dst__2 = amodeAddr amode
1589 code__2 = asmParThen [code1, codesrc asmVoid] .
1590 mkSeqInstr (MOV (primRepToSize pk) opsrc (OpAddr dst__2))
1596 -> UniqSM (InstrBlock,Operand) -- code, operator
1600 = returnUs (asmParThen [], OpImm imm_op)
1603 imm_op = case imm of Just x -> x
1606 = getRegister op `thenUs` \ register ->
1607 getNewRegNCG (registerRep register)
1610 code = registerCode register tmp
1611 reg = registerName register tmp
1613 returnUs (code, OpReg reg)
1615 assignIntCode pk dst (StInd pks src)
1616 = getNewRegNCG IntRep `thenUs` \ tmp ->
1617 getAmode src `thenUs` \ amode ->
1618 getRegister dst `thenUs` \ register ->
1620 code1 = amodeCode amode asmVoid
1621 src__2 = amodeAddr amode
1622 code2 = registerCode register tmp asmVoid
1623 dst__2 = registerName register tmp
1624 szs = primRepToSize pks
1625 code__2 = asmParThen [code1, code2] .
1627 L -> mkSeqInstr (MOV L (OpAddr src__2) (OpReg dst__2))
1628 B -> mkSeqInstr (MOVZxL B (OpAddr src__2) (OpReg dst__2))
1632 assignIntCode pk dst src
1633 = getRegister dst `thenUs` \ register1 ->
1634 getRegister src `thenUs` \ register2 ->
1635 getNewRegNCG IntRep `thenUs` \ tmp ->
1637 dst__2 = registerName register1 tmp
1638 code = registerCode register2 dst__2
1639 src__2 = registerName register2 dst__2
1640 code__2 = if isFixed register2 && dst__2 /= src__2
1641 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1646 #endif {- i386_TARGET_ARCH -}
1647 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1648 #if sparc_TARGET_ARCH
1650 assignIntCode pk (StInd _ dst) src
1651 = getNewRegNCG IntRep `thenUs` \ tmp ->
1652 getAmode dst `thenUs` \ amode ->
1653 getRegister src `thenUs` \ register ->
1655 code1 = amodeCode amode asmVoid
1656 dst__2 = amodeAddr amode
1657 code2 = registerCode register tmp asmVoid
1658 src__2 = registerName register tmp
1659 sz = primRepToSize pk
1660 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1664 assignIntCode pk dst src
1665 = getRegister dst `thenUs` \ register1 ->
1666 getRegister src `thenUs` \ register2 ->
1668 dst__2 = registerName register1 g0
1669 code = registerCode register2 dst__2
1670 src__2 = registerName register2 dst__2
1671 code__2 = if isFixed register2
1672 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1677 #endif {- sparc_TARGET_ARCH -}
1680 % --------------------------------
1681 Floating-point assignments:
1682 % --------------------------------
1684 #if alpha_TARGET_ARCH
1686 assignFltCode pk (StInd _ dst) src
1687 = getNewRegNCG pk `thenUs` \ tmp ->
1688 getAmode dst `thenUs` \ amode ->
1689 getRegister src `thenUs` \ register ->
1691 code1 = amodeCode amode asmVoid
1692 dst__2 = amodeAddr amode
1693 code2 = registerCode register tmp asmVoid
1694 src__2 = registerName register tmp
1695 sz = primRepToSize pk
1696 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1700 assignFltCode pk dst src
1701 = getRegister dst `thenUs` \ register1 ->
1702 getRegister src `thenUs` \ register2 ->
1704 dst__2 = registerName register1 zeroh
1705 code = registerCode register2 dst__2
1706 src__2 = registerName register2 dst__2
1707 code__2 = if isFixed register2
1708 then code . mkSeqInstr (FMOV src__2 dst__2)
1713 #endif {- alpha_TARGET_ARCH -}
1714 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1715 #if i386_TARGET_ARCH
1717 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1718 = getNewRegNCG IntRep `thenUs` \ tmp ->
1719 getAmode src `thenUs` \ amodesrc ->
1720 getAmode dst `thenUs` \ amodedst ->
1722 codesrc1 = amodeCode amodesrc asmVoid
1723 addrsrc1 = amodeAddr amodesrc
1724 codedst1 = amodeCode amodedst asmVoid
1725 addrdst1 = amodeAddr amodedst
1726 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1727 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1729 code__2 = asmParThen [codesrc1, codedst1] .
1730 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1731 MOV L (OpReg tmp) (OpAddr addrdst1)]
1734 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1735 MOV L (OpReg tmp) (OpAddr addrdst2)]
1740 assignFltCode pk (StInd _ dst) src
1741 = getNewRegNCG pk `thenUs` \ tmp ->
1742 getAmode dst `thenUs` \ amode ->
1743 getRegister src `thenUs` \ register ->
1745 sz = primRepToSize pk
1746 dst__2 = amodeAddr amode
1748 code1 = amodeCode amode asmVoid
1749 code2 = registerCode register tmp asmVoid
1751 src__2 = registerName register tmp
1753 code__2 = asmParThen [code1, code2] .
1754 mkSeqInstr (GST sz src__2 dst__2)
1758 assignFltCode pk dst src
1759 = getRegister dst `thenUs` \ register1 ->
1760 getRegister src `thenUs` \ register2 ->
1761 getNewRegNCG pk `thenUs` \ tmp ->
1763 -- the register which is dst
1764 dst__2 = registerName register1 tmp
1765 -- the register into which src is computed, preferably dst__2
1766 src__2 = registerName register2 dst__2
1767 -- code to compute src into src__2
1768 code = registerCode register2 dst__2
1770 code__2 = if isFixed register2
1771 then code . mkSeqInstr (GMOV src__2 dst__2)
1776 #endif {- i386_TARGET_ARCH -}
1777 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1778 #if sparc_TARGET_ARCH
1780 assignFltCode pk (StInd _ dst) src
1781 = getNewRegNCG pk `thenUs` \ tmp1 ->
1782 getAmode dst `thenUs` \ amode ->
1783 getRegister src `thenUs` \ register ->
1785 sz = primRepToSize pk
1786 dst__2 = amodeAddr amode
1788 code1 = amodeCode amode asmVoid
1789 code2 = registerCode register tmp1 asmVoid
1791 src__2 = registerName register tmp1
1792 pk__2 = registerRep register
1793 sz__2 = primRepToSize pk__2
1795 code__2 = asmParThen [code1, code2] .
1797 mkSeqInstr (ST sz src__2 dst__2)
1799 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1803 assignFltCode pk dst src
1804 = getRegister dst `thenUs` \ register1 ->
1805 getRegister src `thenUs` \ register2 ->
1807 pk__2 = registerRep register2
1808 sz__2 = primRepToSize pk__2
1810 getNewRegNCG pk__2 `thenUs` \ tmp ->
1812 sz = primRepToSize pk
1813 dst__2 = registerName register1 g0 -- must be Fixed
1816 reg__2 = if pk /= pk__2 then tmp else dst__2
1818 code = registerCode register2 reg__2
1820 src__2 = registerName register2 reg__2
1824 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1825 else if isFixed register2 then
1826 code . mkSeqInstr (FMOV sz src__2 dst__2)
1832 #endif {- sparc_TARGET_ARCH -}
1835 %************************************************************************
1837 \subsection{Generating an unconditional branch}
1839 %************************************************************************
1841 We accept two types of targets: an immediate CLabel or a tree that
1842 gets evaluated into a register. Any CLabels which are AsmTemporaries
1843 are assumed to be in the local block of code, close enough for a
1844 branch instruction. Other CLabels are assumed to be far away.
1846 (If applicable) Do not fill the delay slots here; you will confuse the
1850 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1852 #if alpha_TARGET_ARCH
1854 genJump (StCLbl lbl)
1855 | isAsmTemp lbl = returnInstr (BR target)
1856 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1858 target = ImmCLbl lbl
1861 = getRegister tree `thenUs` \ register ->
1862 getNewRegNCG PtrRep `thenUs` \ tmp ->
1864 dst = registerName register pv
1865 code = registerCode register pv
1866 target = registerName register pv
1868 if isFixed register then
1869 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1871 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1873 #endif {- alpha_TARGET_ARCH -}
1874 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1875 #if i386_TARGET_ARCH
1878 genJump (StCLbl lbl)
1879 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1880 | otherwise = returnInstrs [JMP (OpImm target)]
1882 target = ImmCLbl lbl
1885 genJump (StInd pk mem)
1886 = getAmode mem `thenUs` \ amode ->
1888 code = amodeCode amode
1889 target = amodeAddr amode
1891 returnSeq code [JMP (OpAddr target)]
1895 = returnInstr (JMP (OpImm target))
1898 = getRegister tree `thenUs` \ register ->
1899 getNewRegNCG PtrRep `thenUs` \ tmp ->
1901 code = registerCode register tmp
1902 target = registerName register tmp
1904 returnSeq code [JMP (OpReg target)]
1907 target = case imm of Just x -> x
1909 #endif {- i386_TARGET_ARCH -}
1910 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1911 #if sparc_TARGET_ARCH
1913 genJump (StCLbl lbl)
1914 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1915 | otherwise = returnInstrs [CALL target 0 True, NOP]
1917 target = ImmCLbl lbl
1920 = getRegister tree `thenUs` \ register ->
1921 getNewRegNCG PtrRep `thenUs` \ tmp ->
1923 code = registerCode register tmp
1924 target = registerName register tmp
1926 returnSeq code [JMP (AddrRegReg target g0), NOP]
1928 #endif {- sparc_TARGET_ARCH -}
1931 %************************************************************************
1933 \subsection{Conditional jumps}
1935 %************************************************************************
1937 Conditional jumps are always to local labels, so we can use branch
1938 instructions. We peek at the arguments to decide what kind of
1941 ALPHA: For comparisons with 0, we're laughing, because we can just do
1942 the desired conditional branch.
1944 I386: First, we have to ensure that the condition
1945 codes are set according to the supplied comparison operation.
1947 SPARC: First, we have to ensure that the condition codes are set
1948 according to the supplied comparison operation. We generate slightly
1949 different code for floating point comparisons, because a floating
1950 point operation cannot directly precede a @BF@. We assume the worst
1951 and fill that slot with a @NOP@.
1953 SPARC: Do not fill the delay slots here; you will confuse the register
1958 :: CLabel -- the branch target
1959 -> StixTree -- the condition on which to branch
1960 -> UniqSM InstrBlock
1962 #if alpha_TARGET_ARCH
1964 genCondJump lbl (StPrim op [x, StInt 0])
1965 = getRegister x `thenUs` \ register ->
1966 getNewRegNCG (registerRep register)
1969 code = registerCode register tmp
1970 value = registerName register tmp
1971 pk = registerRep register
1972 target = ImmCLbl lbl
1974 returnSeq code [BI (cmpOp op) value target]
1976 cmpOp CharGtOp = GTT
1978 cmpOp CharEqOp = EQQ
1980 cmpOp CharLtOp = LTT
1989 cmpOp WordGeOp = ALWAYS
1990 cmpOp WordEqOp = EQQ
1992 cmpOp WordLtOp = NEVER
1993 cmpOp WordLeOp = EQQ
1995 cmpOp AddrGeOp = ALWAYS
1996 cmpOp AddrEqOp = EQQ
1998 cmpOp AddrLtOp = NEVER
1999 cmpOp AddrLeOp = EQQ
2001 genCondJump lbl (StPrim op [x, StDouble 0.0])
2002 = getRegister x `thenUs` \ register ->
2003 getNewRegNCG (registerRep register)
2006 code = registerCode register tmp
2007 value = registerName register tmp
2008 pk = registerRep register
2009 target = ImmCLbl lbl
2011 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2013 cmpOp FloatGtOp = GTT
2014 cmpOp FloatGeOp = GE
2015 cmpOp FloatEqOp = EQQ
2016 cmpOp FloatNeOp = NE
2017 cmpOp FloatLtOp = LTT
2018 cmpOp FloatLeOp = LE
2019 cmpOp DoubleGtOp = GTT
2020 cmpOp DoubleGeOp = GE
2021 cmpOp DoubleEqOp = EQQ
2022 cmpOp DoubleNeOp = NE
2023 cmpOp DoubleLtOp = LTT
2024 cmpOp DoubleLeOp = LE
2026 genCondJump lbl (StPrim op [x, y])
2028 = trivialFCode pr instr x y `thenUs` \ register ->
2029 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2031 code = registerCode register tmp
2032 result = registerName register tmp
2033 target = ImmCLbl lbl
2035 returnUs (code . mkSeqInstr (BF cond result target))
2037 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2039 fltCmpOp op = case op of
2053 (instr, cond) = case op of
2054 FloatGtOp -> (FCMP TF LE, EQQ)
2055 FloatGeOp -> (FCMP TF LTT, EQQ)
2056 FloatEqOp -> (FCMP TF EQQ, NE)
2057 FloatNeOp -> (FCMP TF EQQ, EQQ)
2058 FloatLtOp -> (FCMP TF LTT, NE)
2059 FloatLeOp -> (FCMP TF LE, NE)
2060 DoubleGtOp -> (FCMP TF LE, EQQ)
2061 DoubleGeOp -> (FCMP TF LTT, EQQ)
2062 DoubleEqOp -> (FCMP TF EQQ, NE)
2063 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2064 DoubleLtOp -> (FCMP TF LTT, NE)
2065 DoubleLeOp -> (FCMP TF LE, NE)
2067 genCondJump lbl (StPrim op [x, y])
2068 = trivialCode instr x y `thenUs` \ register ->
2069 getNewRegNCG IntRep `thenUs` \ tmp ->
2071 code = registerCode register tmp
2072 result = registerName register tmp
2073 target = ImmCLbl lbl
2075 returnUs (code . mkSeqInstr (BI cond result target))
2077 (instr, cond) = case op of
2078 CharGtOp -> (CMP LE, EQQ)
2079 CharGeOp -> (CMP LTT, EQQ)
2080 CharEqOp -> (CMP EQQ, NE)
2081 CharNeOp -> (CMP EQQ, EQQ)
2082 CharLtOp -> (CMP LTT, NE)
2083 CharLeOp -> (CMP LE, NE)
2084 IntGtOp -> (CMP LE, EQQ)
2085 IntGeOp -> (CMP LTT, EQQ)
2086 IntEqOp -> (CMP EQQ, NE)
2087 IntNeOp -> (CMP EQQ, EQQ)
2088 IntLtOp -> (CMP LTT, NE)
2089 IntLeOp -> (CMP LE, NE)
2090 WordGtOp -> (CMP ULE, EQQ)
2091 WordGeOp -> (CMP ULT, EQQ)
2092 WordEqOp -> (CMP EQQ, NE)
2093 WordNeOp -> (CMP EQQ, EQQ)
2094 WordLtOp -> (CMP ULT, NE)
2095 WordLeOp -> (CMP ULE, NE)
2096 AddrGtOp -> (CMP ULE, EQQ)
2097 AddrGeOp -> (CMP ULT, EQQ)
2098 AddrEqOp -> (CMP EQQ, NE)
2099 AddrNeOp -> (CMP EQQ, EQQ)
2100 AddrLtOp -> (CMP ULT, NE)
2101 AddrLeOp -> (CMP ULE, NE)
2103 #endif {- alpha_TARGET_ARCH -}
2104 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2105 #if i386_TARGET_ARCH
2107 genCondJump lbl bool
2108 = getCondCode bool `thenUs` \ condition ->
2110 code = condCode condition
2111 cond = condName condition
2112 target = ImmCLbl lbl
2114 returnSeq code [JXX cond lbl]
2116 #endif {- i386_TARGET_ARCH -}
2117 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2118 #if sparc_TARGET_ARCH
2120 genCondJump lbl bool
2121 = getCondCode bool `thenUs` \ condition ->
2123 code = condCode condition
2124 cond = condName condition
2125 target = ImmCLbl lbl
2128 if condFloat condition then
2129 [NOP, BF cond False target, NOP]
2131 [BI cond False target, NOP]
2134 #endif {- sparc_TARGET_ARCH -}
2137 %************************************************************************
2139 \subsection{Generating C calls}
2141 %************************************************************************
2143 Now the biggest nightmare---calls. Most of the nastiness is buried in
2144 @get_arg@, which moves the arguments to the correct registers/stack
2145 locations. Apart from that, the code is easy.
2147 (If applicable) Do not fill the delay slots here; you will confuse the
2152 :: FAST_STRING -- function to call
2154 -> PrimRep -- type of the result
2155 -> [StixTree] -- arguments (of mixed type)
2156 -> UniqSM InstrBlock
2158 #if alpha_TARGET_ARCH
2160 genCCall fn cconv kind args
2161 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2162 `thenUs` \ ((unused,_), argCode) ->
2164 nRegs = length allArgRegs - length unused
2165 code = asmParThen (map ($ asmVoid) argCode)
2168 LDA pv (AddrImm (ImmLab (ptext fn))),
2169 JSR ra (AddrReg pv) nRegs,
2170 LDGP gp (AddrReg ra)]
2172 ------------------------
2173 {- Try to get a value into a specific register (or registers) for
2174 a call. The first 6 arguments go into the appropriate
2175 argument register (separate registers for integer and floating
2176 point arguments, but used in lock-step), and the remaining
2177 arguments are dumped to the stack, beginning at 0(sp). Our
2178 first argument is a pair of the list of remaining argument
2179 registers to be assigned for this call and the next stack
2180 offset to use for overflowing arguments. This way,
2181 @get_Arg@ can be applied to all of a call's arguments using
2185 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2186 -> StixTree -- Current argument
2187 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2189 -- We have to use up all of our argument registers first...
2191 get_arg ((iDst,fDst):dsts, offset) arg
2192 = getRegister arg `thenUs` \ register ->
2194 reg = if isFloatingRep pk then fDst else iDst
2195 code = registerCode register reg
2196 src = registerName register reg
2197 pk = registerRep register
2200 if isFloatingRep pk then
2201 ((dsts, offset), if isFixed register then
2202 code . mkSeqInstr (FMOV src fDst)
2205 ((dsts, offset), if isFixed register then
2206 code . mkSeqInstr (OR src (RIReg src) iDst)
2209 -- Once we have run out of argument registers, we move to the
2212 get_arg ([], offset) arg
2213 = getRegister arg `thenUs` \ register ->
2214 getNewRegNCG (registerRep register)
2217 code = registerCode register tmp
2218 src = registerName register tmp
2219 pk = registerRep register
2220 sz = primRepToSize pk
2222 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2224 #endif {- alpha_TARGET_ARCH -}
2225 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2226 #if i386_TARGET_ARCH
2228 genCCall fn cconv kind [StInt i]
2229 | fn == SLIT ("PerformGC_wrapper")
2230 = let call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2231 CALL (ImmLit (ptext (if underscorePrefix
2232 then (SLIT ("_PerformGC_wrapper"))
2233 else (SLIT ("PerformGC_wrapper")))))]
2238 genCCall fn cconv kind args
2239 = get_call_args args `thenUs` \ (tot_arg_size, argCode) ->
2241 code2 = asmParThen (map ($ asmVoid) argCode)
2242 call = [SUB L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2244 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)
2247 returnSeq code2 call
2250 -- function names that begin with '.' are assumed to be special
2251 -- internally generated names like '.mul,' which don't get an
2252 -- underscore prefix
2253 -- ToDo:needed (WDP 96/03) ???
2254 fn__2 = case (_HEAD_ fn) of
2255 '.' -> ImmLit (ptext fn)
2256 _ -> ImmLab (ptext fn)
2263 -- do get_call_arg on each arg, threading the total arg size along
2264 -- process the args right-to-left
2265 get_call_args :: [StixTree] -> UniqSM (Int, [InstrBlock])
2270 = returnUs (curr_sz, [])
2271 f curr_sz (arg:args)
2272 = f curr_sz args `thenUs` \ (new_sz, iblocks) ->
2273 get_call_arg arg new_sz `thenUs` \ (new_sz2, iblock) ->
2274 returnUs (new_sz2, iblock:iblocks)
2278 get_call_arg :: StixTree{-current argument-}
2279 -> Int{-running total of arg sizes seen so far-}
2280 -> UniqSM (Int, InstrBlock) -- updated tot argsz, code
2282 get_call_arg arg old_sz
2283 = get_op arg `thenUs` \ (code, reg, sz) ->
2284 let new_sz = old_sz + arg_size sz
2285 in if (case sz of DF -> True; F -> True; _ -> False)
2286 then returnUs (new_sz,
2288 mkSeqInstr (GST DF reg
2289 (AddrBaseIndex (Just esp)
2290 Nothing (ImmInt (- new_sz))))
2292 else returnUs (new_sz,
2294 mkSeqInstr (MOV L (OpReg reg)
2296 (AddrBaseIndex (Just esp)
2297 Nothing (ImmInt (- new_sz)))))
2302 -> UniqSM (InstrBlock, Reg, Size) -- code, reg, size
2305 = getRegister op `thenUs` \ register ->
2306 getNewRegNCG (registerRep register)
2309 code = registerCode register tmp
2310 reg = registerName register tmp
2311 pk = registerRep register
2312 sz = primRepToSize pk
2314 returnUs (code, reg, sz)
2316 #endif {- i386_TARGET_ARCH -}
2317 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2318 #if sparc_TARGET_ARCH
2320 genCCall fn cconv kind args
2321 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2322 `thenUs` \ ((unused,_), argCode) ->
2324 nRegs = length allArgRegs - length unused
2325 call = CALL fn__2 nRegs False
2326 code = asmParThen (map ($ asmVoid) argCode)
2328 returnSeq code [call, NOP]
2330 -- function names that begin with '.' are assumed to be special
2331 -- internally generated names like '.mul,' which don't get an
2332 -- underscore prefix
2333 -- ToDo:needed (WDP 96/03) ???
2334 fn__2 = case (_HEAD_ fn) of
2335 '.' -> ImmLit (ptext fn)
2336 _ -> ImmLab (ptext fn)
2338 ------------------------------------
2339 {- Try to get a value into a specific register (or registers) for
2340 a call. The SPARC calling convention is an absolute
2341 nightmare. The first 6x32 bits of arguments are mapped into
2342 %o0 through %o5, and the remaining arguments are dumped to the
2343 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2344 first argument is a pair of the list of remaining argument
2345 registers to be assigned for this call and the next stack
2346 offset to use for overflowing arguments. This way,
2347 @get_arg@ can be applied to all of a call's arguments using
2351 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2352 -> StixTree -- Current argument
2353 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2355 -- We have to use up all of our argument registers first...
2357 get_arg (dst:dsts, offset) arg
2358 = getRegister arg `thenUs` \ register ->
2359 getNewRegNCG (registerRep register)
2362 reg = if isFloatingRep pk then tmp else dst
2363 code = registerCode register reg
2364 src = registerName register reg
2365 pk = registerRep register
2367 returnUs (case pk of
2370 [] -> (([], offset + 1), code . mkSeqInstrs [
2371 -- conveniently put the second part in the right stack
2372 -- location, and load the first part into %o5
2373 ST DF src (spRel (offset - 1)),
2374 LD W (spRel (offset - 1)) dst])
2375 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2376 ST DF src (spRel (-2)),
2377 LD W (spRel (-2)) dst,
2378 LD W (spRel (-1)) dst__2])
2379 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2380 ST F src (spRel (-2)),
2381 LD W (spRel (-2)) dst])
2382 _ -> ((dsts, offset), if isFixed register then
2383 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2386 -- Once we have run out of argument registers, we move to the
2389 get_arg ([], offset) arg
2390 = getRegister arg `thenUs` \ register ->
2391 getNewRegNCG (registerRep register)
2394 code = registerCode register tmp
2395 src = registerName register tmp
2396 pk = registerRep register
2397 sz = primRepToSize pk
2398 words = if pk == DoubleRep then 2 else 1
2400 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2402 #endif {- sparc_TARGET_ARCH -}
2405 %************************************************************************
2407 \subsection{Support bits}
2409 %************************************************************************
2411 %************************************************************************
2413 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2415 %************************************************************************
2417 Turn those condition codes into integers now (when they appear on
2418 the right hand side of an assignment).
2420 (If applicable) Do not fill the delay slots here; you will confuse the
2424 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2426 #if alpha_TARGET_ARCH
2427 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2428 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2429 #endif {- alpha_TARGET_ARCH -}
2431 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2432 #if i386_TARGET_ARCH
2435 = condIntCode cond x y `thenUs` \ condition ->
2436 getNewRegNCG IntRep `thenUs` \ tmp ->
2437 --getRegister dst `thenUs` \ register ->
2439 --code2 = registerCode register tmp asmVoid
2440 --dst__2 = registerName register tmp
2441 code = condCode condition
2442 cond = condName condition
2443 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2444 code__2 dst = code . mkSeqInstrs [
2445 SETCC cond (OpReg tmp),
2446 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2447 MOV L (OpReg tmp) (OpReg dst)]
2449 returnUs (Any IntRep code__2)
2452 = getUniqLabelNCG `thenUs` \ lbl1 ->
2453 getUniqLabelNCG `thenUs` \ lbl2 ->
2454 condFltCode cond x y `thenUs` \ condition ->
2456 code = condCode condition
2457 cond = condName condition
2458 code__2 dst = code . mkSeqInstrs [
2460 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2463 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2466 returnUs (Any IntRep code__2)
2468 #endif {- i386_TARGET_ARCH -}
2469 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2470 #if sparc_TARGET_ARCH
2472 condIntReg EQQ x (StInt 0)
2473 = getRegister x `thenUs` \ register ->
2474 getNewRegNCG IntRep `thenUs` \ tmp ->
2476 code = registerCode register tmp
2477 src = registerName register tmp
2478 code__2 dst = code . mkSeqInstrs [
2479 SUB False True g0 (RIReg src) g0,
2480 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2482 returnUs (Any IntRep code__2)
2485 = getRegister x `thenUs` \ register1 ->
2486 getRegister y `thenUs` \ register2 ->
2487 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2488 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2490 code1 = registerCode register1 tmp1 asmVoid
2491 src1 = registerName register1 tmp1
2492 code2 = registerCode register2 tmp2 asmVoid
2493 src2 = registerName register2 tmp2
2494 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2495 XOR False src1 (RIReg src2) dst,
2496 SUB False True g0 (RIReg dst) g0,
2497 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2499 returnUs (Any IntRep code__2)
2501 condIntReg NE x (StInt 0)
2502 = getRegister x `thenUs` \ register ->
2503 getNewRegNCG IntRep `thenUs` \ tmp ->
2505 code = registerCode register tmp
2506 src = registerName register tmp
2507 code__2 dst = code . mkSeqInstrs [
2508 SUB False True g0 (RIReg src) g0,
2509 ADD True False g0 (RIImm (ImmInt 0)) dst]
2511 returnUs (Any IntRep code__2)
2514 = getRegister x `thenUs` \ register1 ->
2515 getRegister y `thenUs` \ register2 ->
2516 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2517 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2519 code1 = registerCode register1 tmp1 asmVoid
2520 src1 = registerName register1 tmp1
2521 code2 = registerCode register2 tmp2 asmVoid
2522 src2 = registerName register2 tmp2
2523 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2524 XOR False src1 (RIReg src2) dst,
2525 SUB False True g0 (RIReg dst) g0,
2526 ADD True False g0 (RIImm (ImmInt 0)) dst]
2528 returnUs (Any IntRep code__2)
2531 = getUniqLabelNCG `thenUs` \ lbl1 ->
2532 getUniqLabelNCG `thenUs` \ lbl2 ->
2533 condIntCode cond x y `thenUs` \ condition ->
2535 code = condCode condition
2536 cond = condName condition
2537 code__2 dst = code . mkSeqInstrs [
2538 BI cond False (ImmCLbl lbl1), NOP,
2539 OR False g0 (RIImm (ImmInt 0)) dst,
2540 BI ALWAYS False (ImmCLbl lbl2), NOP,
2542 OR False g0 (RIImm (ImmInt 1)) dst,
2545 returnUs (Any IntRep code__2)
2548 = getUniqLabelNCG `thenUs` \ lbl1 ->
2549 getUniqLabelNCG `thenUs` \ lbl2 ->
2550 condFltCode cond x y `thenUs` \ condition ->
2552 code = condCode condition
2553 cond = condName condition
2554 code__2 dst = code . mkSeqInstrs [
2556 BF cond False (ImmCLbl lbl1), NOP,
2557 OR False g0 (RIImm (ImmInt 0)) dst,
2558 BI ALWAYS False (ImmCLbl lbl2), NOP,
2560 OR False g0 (RIImm (ImmInt 1)) dst,
2563 returnUs (Any IntRep code__2)
2565 #endif {- sparc_TARGET_ARCH -}
2568 %************************************************************************
2570 \subsubsection{@trivial*Code@: deal with trivial instructions}
2572 %************************************************************************
2574 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2575 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2576 for constants on the right hand side, because that's where the generic
2577 optimizer will have put them.
2579 Similarly, for unary instructions, we don't have to worry about
2580 matching an StInt as the argument, because genericOpt will already
2581 have handled the constant-folding.
2585 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2586 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2587 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2589 -> StixTree -> StixTree -- the two arguments
2594 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2595 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2596 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2598 -> StixTree -> StixTree -- the two arguments
2602 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2603 ,IF_ARCH_i386 ((Operand -> Instr)
2604 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2606 -> StixTree -- the one argument
2611 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2612 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2613 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2615 -> StixTree -- the one argument
2618 #if alpha_TARGET_ARCH
2620 trivialCode instr x (StInt y)
2622 = getRegister x `thenUs` \ register ->
2623 getNewRegNCG IntRep `thenUs` \ tmp ->
2625 code = registerCode register tmp
2626 src1 = registerName register tmp
2627 src2 = ImmInt (fromInteger y)
2628 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2630 returnUs (Any IntRep code__2)
2632 trivialCode instr x y
2633 = getRegister x `thenUs` \ register1 ->
2634 getRegister y `thenUs` \ register2 ->
2635 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2636 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2638 code1 = registerCode register1 tmp1 asmVoid
2639 src1 = registerName register1 tmp1
2640 code2 = registerCode register2 tmp2 asmVoid
2641 src2 = registerName register2 tmp2
2642 code__2 dst = asmParThen [code1, code2] .
2643 mkSeqInstr (instr src1 (RIReg src2) dst)
2645 returnUs (Any IntRep code__2)
2648 trivialUCode instr x
2649 = getRegister x `thenUs` \ register ->
2650 getNewRegNCG IntRep `thenUs` \ tmp ->
2652 code = registerCode register tmp
2653 src = registerName register tmp
2654 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2656 returnUs (Any IntRep code__2)
2659 trivialFCode _ instr x y
2660 = getRegister x `thenUs` \ register1 ->
2661 getRegister y `thenUs` \ register2 ->
2662 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2663 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2665 code1 = registerCode register1 tmp1
2666 src1 = registerName register1 tmp1
2668 code2 = registerCode register2 tmp2
2669 src2 = registerName register2 tmp2
2671 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2672 mkSeqInstr (instr src1 src2 dst)
2674 returnUs (Any DoubleRep code__2)
2676 trivialUFCode _ instr x
2677 = getRegister x `thenUs` \ register ->
2678 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2680 code = registerCode register tmp
2681 src = registerName register tmp
2682 code__2 dst = code . mkSeqInstr (instr src dst)
2684 returnUs (Any DoubleRep code__2)
2686 #endif {- alpha_TARGET_ARCH -}
2687 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2688 #if i386_TARGET_ARCH
2690 trivialCode instr x y
2692 = getRegister x `thenUs` \ register1 ->
2694 code__2 dst = let code1 = registerCode register1 dst
2695 src1 = registerName register1 dst
2697 if isFixed register1 && src1 /= dst
2698 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2699 instr (OpImm imm__2) (OpReg dst)]
2701 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2703 returnUs (Any IntRep code__2)
2706 imm__2 = case imm of Just x -> x
2708 trivialCode instr x y
2709 = getRegister x `thenUs` \ register1 ->
2710 getRegister y `thenUs` \ register2 ->
2711 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2713 code2 = registerCode register2 tmp2 asmVoid
2714 src2 = registerName register2 tmp2
2716 code1 = registerCode register1 dst asmVoid
2717 src1 = registerName register1 dst
2718 in asmParThen [code1, code2] .
2719 if isFixed register1 && src1 /= dst
2720 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2721 instr (OpReg src2) (OpReg dst)]
2723 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2725 returnUs (Any IntRep code__2)
2728 trivialUCode instr x
2729 = getRegister x `thenUs` \ register ->
2732 code = registerCode register dst
2733 src = registerName register dst
2734 in code . if isFixed register && dst /= src
2735 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2737 else mkSeqInstr (instr (OpReg src))
2739 returnUs (Any IntRep code__2)
2742 trivialFCode pk instr x y
2743 = getRegister x `thenUs` \ register1 ->
2744 getRegister y `thenUs` \ register2 ->
2745 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2746 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2748 code1 = registerCode register1 tmp1
2749 src1 = registerName register1 tmp1
2751 code2 = registerCode register2 tmp2
2752 src2 = registerName register2 tmp2
2754 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2755 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2757 returnUs (Any DoubleRep code__2)
2761 trivialUFCode pk instr x
2762 = getRegister x `thenUs` \ register ->
2763 getNewRegNCG pk `thenUs` \ tmp ->
2765 code = registerCode register tmp
2766 src = registerName register tmp
2767 code__2 dst = code . mkSeqInstr (instr src dst)
2769 returnUs (Any pk code__2)
2771 #endif {- i386_TARGET_ARCH -}
2772 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2773 #if sparc_TARGET_ARCH
2775 trivialCode instr x (StInt y)
2777 = getRegister x `thenUs` \ register ->
2778 getNewRegNCG IntRep `thenUs` \ tmp ->
2780 code = registerCode register tmp
2781 src1 = registerName register tmp
2782 src2 = ImmInt (fromInteger y)
2783 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2785 returnUs (Any IntRep code__2)
2787 trivialCode instr x y
2788 = getRegister x `thenUs` \ register1 ->
2789 getRegister y `thenUs` \ register2 ->
2790 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2791 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2793 code1 = registerCode register1 tmp1 asmVoid
2794 src1 = registerName register1 tmp1
2795 code2 = registerCode register2 tmp2 asmVoid
2796 src2 = registerName register2 tmp2
2797 code__2 dst = asmParThen [code1, code2] .
2798 mkSeqInstr (instr src1 (RIReg src2) dst)
2800 returnUs (Any IntRep code__2)
2803 trivialFCode pk instr x y
2804 = getRegister x `thenUs` \ register1 ->
2805 getRegister y `thenUs` \ register2 ->
2806 getNewRegNCG (registerRep register1)
2808 getNewRegNCG (registerRep register2)
2810 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2812 promote x = asmInstr (FxTOy F DF x tmp)
2814 pk1 = registerRep register1
2815 code1 = registerCode register1 tmp1
2816 src1 = registerName register1 tmp1
2818 pk2 = registerRep register2
2819 code2 = registerCode register2 tmp2
2820 src2 = registerName register2 tmp2
2824 asmParThen [code1 asmVoid, code2 asmVoid] .
2825 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2826 else if pk1 == FloatRep then
2827 asmParThen [code1 (promote src1), code2 asmVoid] .
2828 mkSeqInstr (instr DF tmp src2 dst)
2830 asmParThen [code1 asmVoid, code2 (promote src2)] .
2831 mkSeqInstr (instr DF src1 tmp dst)
2833 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2836 trivialUCode instr x
2837 = getRegister x `thenUs` \ register ->
2838 getNewRegNCG IntRep `thenUs` \ tmp ->
2840 code = registerCode register tmp
2841 src = registerName register tmp
2842 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2844 returnUs (Any IntRep code__2)
2847 trivialUFCode pk instr x
2848 = getRegister x `thenUs` \ register ->
2849 getNewRegNCG pk `thenUs` \ tmp ->
2851 code = registerCode register tmp
2852 src = registerName register tmp
2853 code__2 dst = code . mkSeqInstr (instr src dst)
2855 returnUs (Any pk code__2)
2857 #endif {- sparc_TARGET_ARCH -}
2860 %************************************************************************
2862 \subsubsection{Coercing to/from integer/floating-point...}
2864 %************************************************************************
2866 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
2867 to be generated. Here we just change the type on the Register passed
2868 on up. The code is machine-independent.
2870 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
2871 conversions. We have to store temporaries in memory to move
2872 between the integer and the floating point register sets.
2875 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
2876 coerceFltCode :: StixTree -> UniqSM Register
2878 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
2879 coerceFP2Int :: StixTree -> UniqSM Register
2882 = getRegister x `thenUs` \ register ->
2885 Fixed _ reg code -> Fixed pk reg code
2886 Any _ code -> Any pk code
2891 = getRegister x `thenUs` \ register ->
2894 Fixed _ reg code -> Fixed DoubleRep reg code
2895 Any _ code -> Any DoubleRep code
2900 #if alpha_TARGET_ARCH
2903 = getRegister x `thenUs` \ register ->
2904 getNewRegNCG IntRep `thenUs` \ reg ->
2906 code = registerCode register reg
2907 src = registerName register reg
2909 code__2 dst = code . mkSeqInstrs [
2911 LD TF dst (spRel 0),
2914 returnUs (Any DoubleRep code__2)
2918 = getRegister x `thenUs` \ register ->
2919 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2921 code = registerCode register tmp
2922 src = registerName register tmp
2924 code__2 dst = code . mkSeqInstrs [
2926 ST TF tmp (spRel 0),
2929 returnUs (Any IntRep code__2)
2931 #endif {- alpha_TARGET_ARCH -}
2932 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2933 #if i386_TARGET_ARCH
2936 = getRegister x `thenUs` \ register ->
2937 getNewRegNCG IntRep `thenUs` \ reg ->
2939 code = registerCode register reg
2940 src = registerName register reg
2941 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
2942 code__2 dst = code .
2943 mkSeqInstr (opc src dst)
2945 returnUs (Any pk code__2)
2949 = getRegister x `thenUs` \ register ->
2950 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2952 code = registerCode register tmp
2953 src = registerName register tmp
2954 pk = registerRep register
2956 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
2957 code__2 dst = code .
2958 mkSeqInstr (opc src dst)
2960 returnUs (Any IntRep code__2)
2962 #endif {- i386_TARGET_ARCH -}
2963 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2964 #if sparc_TARGET_ARCH
2967 = getRegister x `thenUs` \ register ->
2968 getNewRegNCG IntRep `thenUs` \ reg ->
2970 code = registerCode register reg
2971 src = registerName register reg
2973 code__2 dst = code . mkSeqInstrs [
2974 ST W src (spRel (-2)),
2975 LD W (spRel (-2)) dst,
2976 FxTOy W (primRepToSize pk) dst dst]
2978 returnUs (Any pk code__2)
2982 = getRegister x `thenUs` \ register ->
2983 getNewRegNCG IntRep `thenUs` \ reg ->
2984 getNewRegNCG FloatRep `thenUs` \ tmp ->
2986 code = registerCode register reg
2987 src = registerName register reg
2988 pk = registerRep register
2990 code__2 dst = code . mkSeqInstrs [
2991 FxTOy (primRepToSize pk) W src tmp,
2992 ST W tmp (spRel (-2)),
2993 LD W (spRel (-2)) dst]
2995 returnUs (Any IntRep code__2)
2997 #endif {- sparc_TARGET_ARCH -}
3000 %************************************************************************
3002 \subsubsection{Coercing integer to @Char@...}
3004 %************************************************************************
3006 Integer to character conversion. Where applicable, we try to do this
3007 in one step if the original object is in memory.
3010 chrCode :: StixTree -> UniqSM Register
3012 #if alpha_TARGET_ARCH
3015 = getRegister x `thenUs` \ register ->
3016 getNewRegNCG IntRep `thenUs` \ reg ->
3018 code = registerCode register reg
3019 src = registerName register reg
3020 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3022 returnUs (Any IntRep code__2)
3024 #endif {- alpha_TARGET_ARCH -}
3025 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3026 #if i386_TARGET_ARCH
3029 = getRegister x `thenUs` \ register ->
3032 code = registerCode register dst
3033 src = registerName register dst
3035 if isFixed register && src /= dst
3036 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3037 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3038 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3040 returnUs (Any IntRep code__2)
3042 #endif {- i386_TARGET_ARCH -}
3043 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3044 #if sparc_TARGET_ARCH
3046 chrCode (StInd pk mem)
3047 = getAmode mem `thenUs` \ amode ->
3049 code = amodeCode amode
3050 src = amodeAddr amode
3051 src_off = addrOffset src 3
3052 src__2 = case src_off of Just x -> x
3053 code__2 dst = if maybeToBool src_off then
3054 code . mkSeqInstr (LD BU src__2 dst)
3056 code . mkSeqInstrs [
3057 LD (primRepToSize pk) src dst,
3058 AND False dst (RIImm (ImmInt 255)) dst]
3060 returnUs (Any pk code__2)
3063 = getRegister x `thenUs` \ register ->
3064 getNewRegNCG IntRep `thenUs` \ reg ->
3066 code = registerCode register reg
3067 src = registerName register reg
3068 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3070 returnUs (Any IntRep code__2)
3072 #endif {- sparc_TARGET_ARCH -}