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,
39 Code extractor for an entire stix tree---stix statement level.
42 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
44 stmt2Instrs stmt = case stmt of
45 StComment s -> returnInstr (COMMENT s)
46 StSegment seg -> returnInstr (SEGMENT seg)
48 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
49 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
50 StLabel lab -> returnInstr (LABEL lab)
52 StJump arg -> genJump arg
53 StCondJump lab arg -> genCondJump lab arg
54 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
57 | isFloatingRep pk -> assignFltCode pk dst src
58 | otherwise -> assignIntCode pk dst src
61 -- When falling through on the Alpha, we still have to load pv
62 -- with the address of the next routine, so that it can load gp.
63 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
67 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
68 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
69 (foldr (.) id codes xs))
71 getData :: StixTree -> UniqSM (InstrBlock, Imm)
73 getData (StInt i) = returnUs (id, ImmInteger i)
74 getData (StDouble d) = returnUs (id, ImmDouble d)
75 getData (StLitLbl s) = returnUs (id, ImmLab s)
76 getData (StCLbl l) = returnUs (id, ImmCLbl l)
77 getData (StString s) =
78 getUniqLabelNCG `thenUs` \ lbl ->
79 returnUs (mkSeqInstrs [LABEL lbl,
80 ASCII True (_UNPK_ s)],
82 -- the linker can handle simple arithmetic...
83 getData (StIndex rep (StCLbl lbl) (StInt off)) =
84 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
87 %************************************************************************
89 \subsection{General things for putting together code sequences}
91 %************************************************************************
94 type InstrList = OrdList Instr
95 type InstrBlock = InstrList -> InstrList
100 asmInstr :: Instr -> InstrList
101 asmInstr i = mkUnitList i
103 asmSeq :: [Instr] -> InstrList
104 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
106 asmParThen :: [InstrList] -> InstrBlock
107 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
109 returnInstr :: Instr -> UniqSM InstrBlock
110 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
112 returnInstrs :: [Instr] -> UniqSM InstrBlock
113 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
115 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
116 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
118 mkSeqInstr :: Instr -> InstrBlock
119 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
121 mkSeqInstrs :: [Instr] -> InstrBlock
122 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
126 mangleIndexTree :: StixTree -> StixTree
128 mangleIndexTree (StIndex pk base (StInt i))
129 = StPrim IntAddOp [base, off]
131 off = StInt (i * sizeOf pk)
133 mangleIndexTree (StIndex pk base off)
137 in ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
138 if s == 0 then off else StPrim SllOp [off, StInt s]
141 shift DoubleRep = 3::Integer
142 shift CharRep = 0::Integer
143 shift _ = IF_ARCH_alpha(3,2)
147 maybeImm :: StixTree -> Maybe Imm
149 maybeImm (StLitLbl s) = Just (ImmLab s)
150 maybeImm (StCLbl l) = Just (ImmCLbl l)
152 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
153 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
156 | i >= toInteger minInt && i <= toInteger maxInt
157 = Just (ImmInt (fromInteger i))
159 = Just (ImmInteger i)
164 %************************************************************************
166 \subsection{The @Register@ type}
168 %************************************************************************
170 @Register@s passed up the tree. If the stix code forces the register
171 to live in a pre-decided machine register, it comes out as @Fixed@;
172 otherwise, it comes out as @Any@, and the parent can decide which
173 register to put it in.
177 = Fixed PrimRep Reg InstrBlock
178 | Any PrimRep (Reg -> InstrBlock)
180 registerCode :: Register -> Reg -> InstrBlock
181 registerCode (Fixed _ _ code) reg = code
182 registerCode (Any _ code) reg = code reg
184 registerName :: Register -> Reg -> Reg
185 registerName (Fixed _ reg _) _ = reg
186 registerName (Any _ _) reg = reg
188 registerRep :: Register -> PrimRep
189 registerRep (Fixed pk _ _) = pk
190 registerRep (Any pk _) = pk
192 isFixed :: Register -> Bool
193 isFixed (Fixed _ _ _) = True
194 isFixed (Any _ _) = False
197 Generate code to get a subtree into a @Register@:
199 getRegister :: StixTree -> UniqSM Register
201 getRegister (StReg (StixMagicId stgreg))
202 = case (magicIdRegMaybe stgreg) of
203 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
206 getRegister (StReg (StixTemp u pk))
207 = returnUs (Fixed pk (UnmappedReg u pk) id)
209 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
211 getRegister (StCall fn cconv kind args)
212 = genCCall fn cconv kind args `thenUs` \ call ->
213 returnUs (Fixed kind reg call)
215 reg = if isFloatingRep kind
216 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
217 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
219 getRegister (StString s)
220 = getUniqLabelNCG `thenUs` \ lbl ->
222 imm_lbl = ImmCLbl lbl
224 code dst = mkSeqInstrs [
227 ASCII True (_UNPK_ s),
229 #if alpha_TARGET_ARCH
230 LDA dst (AddrImm imm_lbl)
233 MOV L (OpImm imm_lbl) (OpReg dst)
235 #if sparc_TARGET_ARCH
236 SETHI (HI imm_lbl) dst,
237 OR False dst (RIImm (LO imm_lbl)) dst
241 returnUs (Any PtrRep code)
245 -- end of machine-"independent" bit; here we go on the rest...
247 #if alpha_TARGET_ARCH
249 getRegister (StDouble d)
250 = getUniqLabelNCG `thenUs` \ lbl ->
251 getNewRegNCG PtrRep `thenUs` \ tmp ->
252 let code dst = mkSeqInstrs [
255 DATA TF [ImmLab (rational d)],
257 LDA tmp (AddrImm (ImmCLbl lbl)),
258 LD TF dst (AddrReg tmp)]
260 returnUs (Any DoubleRep code)
262 getRegister (StPrim primop [x]) -- unary PrimOps
264 IntNegOp -> trivialUCode (NEG Q False) x
266 NotOp -> trivialUCode NOT x
268 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
269 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
271 OrdOp -> coerceIntCode IntRep x
274 Float2IntOp -> coerceFP2Int x
275 Int2FloatOp -> coerceInt2FP pr x
276 Double2IntOp -> coerceFP2Int x
277 Int2DoubleOp -> coerceInt2FP pr x
279 Double2FloatOp -> coerceFltCode x
280 Float2DoubleOp -> coerceFltCode x
282 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
284 fn = case other_op of
285 FloatExpOp -> SLIT("exp")
286 FloatLogOp -> SLIT("log")
287 FloatSqrtOp -> SLIT("sqrt")
288 FloatSinOp -> SLIT("sin")
289 FloatCosOp -> SLIT("cos")
290 FloatTanOp -> SLIT("tan")
291 FloatAsinOp -> SLIT("asin")
292 FloatAcosOp -> SLIT("acos")
293 FloatAtanOp -> SLIT("atan")
294 FloatSinhOp -> SLIT("sinh")
295 FloatCoshOp -> SLIT("cosh")
296 FloatTanhOp -> SLIT("tanh")
297 DoubleExpOp -> SLIT("exp")
298 DoubleLogOp -> SLIT("log")
299 DoubleSqrtOp -> SLIT("sqrt")
300 DoubleSinOp -> SLIT("sin")
301 DoubleCosOp -> SLIT("cos")
302 DoubleTanOp -> SLIT("tan")
303 DoubleAsinOp -> SLIT("asin")
304 DoubleAcosOp -> SLIT("acos")
305 DoubleAtanOp -> SLIT("atan")
306 DoubleSinhOp -> SLIT("sinh")
307 DoubleCoshOp -> SLIT("cosh")
308 DoubleTanhOp -> SLIT("tanh")
310 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
312 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
314 CharGtOp -> trivialCode (CMP LTT) y x
315 CharGeOp -> trivialCode (CMP LE) y x
316 CharEqOp -> trivialCode (CMP EQQ) x y
317 CharNeOp -> int_NE_code x y
318 CharLtOp -> trivialCode (CMP LTT) x y
319 CharLeOp -> trivialCode (CMP LE) x y
321 IntGtOp -> trivialCode (CMP LTT) y x
322 IntGeOp -> trivialCode (CMP LE) y x
323 IntEqOp -> trivialCode (CMP EQQ) x y
324 IntNeOp -> int_NE_code x y
325 IntLtOp -> trivialCode (CMP LTT) x y
326 IntLeOp -> trivialCode (CMP LE) x y
328 WordGtOp -> trivialCode (CMP ULT) y x
329 WordGeOp -> trivialCode (CMP ULE) x y
330 WordEqOp -> trivialCode (CMP EQQ) x y
331 WordNeOp -> int_NE_code x y
332 WordLtOp -> trivialCode (CMP ULT) x y
333 WordLeOp -> trivialCode (CMP ULE) x y
335 AddrGtOp -> trivialCode (CMP ULT) y x
336 AddrGeOp -> trivialCode (CMP ULE) y x
337 AddrEqOp -> trivialCode (CMP EQQ) x y
338 AddrNeOp -> int_NE_code x y
339 AddrLtOp -> trivialCode (CMP ULT) x y
340 AddrLeOp -> trivialCode (CMP ULE) x y
342 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
343 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
344 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
345 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
346 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
347 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
349 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
350 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
351 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
352 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
353 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
354 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
356 IntAddOp -> trivialCode (ADD Q False) x y
357 IntSubOp -> trivialCode (SUB Q False) x y
358 IntMulOp -> trivialCode (MUL Q False) x y
359 IntQuotOp -> trivialCode (DIV Q False) x y
360 IntRemOp -> trivialCode (REM Q False) x y
362 WordQuotOp -> trivialCode (DIV Q True) x y
363 WordRemOp -> trivialCode (REM Q True) x y
365 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
366 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
367 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
368 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
370 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
371 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
372 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
373 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
375 AndOp -> trivialCode AND x y
376 OrOp -> trivialCode OR x y
377 XorOp -> trivialCode XOR x y
378 SllOp -> trivialCode SLL x y
379 SrlOp -> trivialCode SRL x y
381 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
382 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
383 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
385 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
386 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
388 {- ------------------------------------------------------------
389 Some bizarre special code for getting condition codes into
390 registers. Integer non-equality is a test for equality
391 followed by an XOR with 1. (Integer comparisons always set
392 the result register to 0 or 1.) Floating point comparisons of
393 any kind leave the result in a floating point register, so we
394 need to wrangle an integer register out of things.
396 int_NE_code :: StixTree -> StixTree -> UniqSM Register
399 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
400 getNewRegNCG IntRep `thenUs` \ tmp ->
402 code = registerCode register tmp
403 src = registerName register tmp
404 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
406 returnUs (Any IntRep code__2)
408 {- ------------------------------------------------------------
409 Comments for int_NE_code also apply to cmpF_code
412 :: (Reg -> Reg -> Reg -> Instr)
414 -> StixTree -> StixTree
417 cmpF_code instr cond x y
418 = trivialFCode pr instr x y `thenUs` \ register ->
419 getNewRegNCG DoubleRep `thenUs` \ tmp ->
420 getUniqLabelNCG `thenUs` \ lbl ->
422 code = registerCode register tmp
423 result = registerName register tmp
425 code__2 dst = code . mkSeqInstrs [
426 OR zeroh (RIImm (ImmInt 1)) dst,
427 BF cond result (ImmCLbl lbl),
428 OR zeroh (RIReg zeroh) dst,
431 returnUs (Any IntRep code__2)
433 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
434 ------------------------------------------------------------
436 getRegister (StInd pk mem)
437 = getAmode mem `thenUs` \ amode ->
439 code = amodeCode amode
440 src = amodeAddr amode
441 size = primRepToSize pk
442 code__2 dst = code . mkSeqInstr (LD size dst src)
444 returnUs (Any pk code__2)
446 getRegister (StInt i)
449 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
451 returnUs (Any IntRep code)
454 code dst = mkSeqInstr (LDI Q dst src)
456 returnUs (Any IntRep code)
458 src = ImmInt (fromInteger i)
463 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
465 returnUs (Any PtrRep code)
468 imm__2 = case imm of Just x -> x
470 #endif {- alpha_TARGET_ARCH -}
471 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
474 getRegister (StDouble d)
475 = getUniqLabelNCG `thenUs` \ lbl ->
476 let code dst = mkSeqInstrs [
479 DATA DF [ImmDouble d],
481 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
484 returnUs (Any DoubleRep code)
486 getRegister (StScratchWord i)
487 = let code dst = mkSeqInstr (LEA L (OpAddr (spRel (-1000+i))) (OpReg dst))
488 in returnUs (Any PtrRep code)
490 getRegister (StPrim primop [x]) -- unary PrimOps
492 IntNegOp -> trivialUCode (NEGI L) x
493 NotOp -> trivialUCode (NOT L) x
495 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
496 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
498 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
499 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
501 FloatSinOp -> trivialUFCode FloatRep (GSIN F) x
502 DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
504 FloatCosOp -> trivialUFCode FloatRep (GCOS F) x
505 DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
507 FloatTanOp -> trivialUFCode FloatRep (GTAN F) x
508 DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
510 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
511 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
513 OrdOp -> coerceIntCode IntRep x
516 Float2IntOp -> coerceFP2Int x
517 Int2FloatOp -> coerceInt2FP FloatRep x
518 Double2IntOp -> coerceFP2Int x
519 Int2DoubleOp -> coerceInt2FP DoubleRep x
523 fixed_x = if is_float_op -- promote to double
524 then StPrim Float2DoubleOp [x]
527 getRegister (StCall fn cCallConv DoubleRep [x])
531 FloatExpOp -> (True, SLIT("exp"))
532 FloatLogOp -> (True, SLIT("log"))
534 --FloatSinOp -> (True, SLIT("sin"))
535 --FloatCosOp -> (True, SLIT("cos"))
536 --FloatTanOp -> (True, SLIT("tan"))
538 FloatAsinOp -> (True, SLIT("asin"))
539 FloatAcosOp -> (True, SLIT("acos"))
540 FloatAtanOp -> (True, SLIT("atan"))
542 FloatSinhOp -> (True, SLIT("sinh"))
543 FloatCoshOp -> (True, SLIT("cosh"))
544 FloatTanhOp -> (True, SLIT("tanh"))
546 DoubleExpOp -> (False, SLIT("exp"))
547 DoubleLogOp -> (False, SLIT("log"))
549 --DoubleSinOp -> (False, SLIT("sin"))
550 --DoubleCosOp -> (False, SLIT("cos"))
551 --DoubleTanOp -> (False, SLIT("tan"))
553 DoubleAsinOp -> (False, SLIT("asin"))
554 DoubleAcosOp -> (False, SLIT("acos"))
555 DoubleAtanOp -> (False, SLIT("atan"))
557 DoubleSinhOp -> (False, SLIT("sinh"))
558 DoubleCoshOp -> (False, SLIT("cosh"))
559 DoubleTanhOp -> (False, SLIT("tanh"))
562 -> pprPanic "getRegister(x86,unary primop)"
563 (pprStixTrees [StPrim primop [x]])
565 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
567 CharGtOp -> condIntReg GTT x y
568 CharGeOp -> condIntReg GE x y
569 CharEqOp -> condIntReg EQQ x y
570 CharNeOp -> condIntReg NE x y
571 CharLtOp -> condIntReg LTT x y
572 CharLeOp -> condIntReg LE x y
574 IntGtOp -> condIntReg GTT x y
575 IntGeOp -> condIntReg GE x y
576 IntEqOp -> condIntReg EQQ x y
577 IntNeOp -> condIntReg NE x y
578 IntLtOp -> condIntReg LTT x y
579 IntLeOp -> condIntReg LE x y
581 WordGtOp -> condIntReg GU x y
582 WordGeOp -> condIntReg GEU x y
583 WordEqOp -> condIntReg EQQ x y
584 WordNeOp -> condIntReg NE x y
585 WordLtOp -> condIntReg LU x y
586 WordLeOp -> condIntReg LEU x y
588 AddrGtOp -> condIntReg GU x y
589 AddrGeOp -> condIntReg GEU x y
590 AddrEqOp -> condIntReg EQQ x y
591 AddrNeOp -> condIntReg NE x y
592 AddrLtOp -> condIntReg LU x y
593 AddrLeOp -> condIntReg LEU x y
595 FloatGtOp -> condFltReg GTT x y
596 FloatGeOp -> condFltReg GE x y
597 FloatEqOp -> condFltReg EQQ x y
598 FloatNeOp -> condFltReg NE x y
599 FloatLtOp -> condFltReg LTT x y
600 FloatLeOp -> condFltReg LE x y
602 DoubleGtOp -> condFltReg GTT x y
603 DoubleGeOp -> condFltReg GE x y
604 DoubleEqOp -> condFltReg EQQ x y
605 DoubleNeOp -> condFltReg NE x y
606 DoubleLtOp -> condFltReg LTT x y
607 DoubleLeOp -> condFltReg LE x y
609 IntAddOp -> add_code L x y
610 IntSubOp -> sub_code L x y
611 IntQuotOp -> quot_code L x y True{-division-}
612 IntRemOp -> quot_code L x y False{-remainder-}
613 IntMulOp -> trivialCode (IMUL L) x y {-True-}
615 FloatAddOp -> trivialFCode FloatRep GADD x y
616 FloatSubOp -> trivialFCode FloatRep GSUB x y
617 FloatMulOp -> trivialFCode FloatRep GMUL x y
618 FloatDivOp -> trivialFCode FloatRep GDIV x y
620 DoubleAddOp -> trivialFCode DoubleRep GADD x y
621 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
622 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
623 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
625 AndOp -> trivialCode (AND L) x y {-True-}
626 OrOp -> trivialCode (OR L) x y {-True-}
627 XorOp -> trivialCode (XOR L) x y {-True-}
629 {- Shift ops on x86s have constraints on their source, it
630 either has to be Imm, CL or 1
631 => trivialCode's is not restrictive enough (sigh.)
634 SllOp -> shift_code (SHL L) x y {-False-}
635 SrlOp -> shift_code (SHR L) x y {-False-}
637 ISllOp -> shift_code (SHL L) x y {-False-}
638 ISraOp -> shift_code (SAR L) x y {-False-}
639 ISrlOp -> shift_code (SHR L) x y {-False-}
641 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
642 [promote x, promote y])
643 where promote x = StPrim Float2DoubleOp [x]
644 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
647 -> pprPanic "getRegister(x86,dyadic primop)"
648 (pprStixTrees [StPrim primop [x, y]])
652 shift_code :: (Operand -> Operand -> Instr)
657 {- Case1: shift length as immediate -}
658 -- Code is the same as the first eq. for trivialCode -- sigh.
659 shift_code instr x y{-amount-}
661 = getRegister x `thenUs` \ register ->
663 op_imm = OpImm imm__2
666 code = registerCode register dst
667 src = registerName register dst
669 mkSeqInstr (COMMENT SLIT("shift_code")) .
671 if isFixed register && src /= dst
673 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
674 instr op_imm (OpReg dst)]
676 mkSeqInstr (instr op_imm (OpReg src))
678 returnUs (Any IntRep code__2)
681 imm__2 = case imm of Just x -> x
683 {- Case2: shift length is complex (non-immediate) -}
684 shift_code instr x y{-amount-}
685 = getRegister x `thenUs` \ register1 ->
686 getRegister y `thenUs` \ register2 ->
687 getUniqLabelNCG `thenUs` \ lbl_test3 ->
688 getUniqLabelNCG `thenUs` \ lbl_test2 ->
689 getUniqLabelNCG `thenUs` \ lbl_test1 ->
690 getUniqLabelNCG `thenUs` \ lbl_test0 ->
691 getUniqLabelNCG `thenUs` \ lbl_after ->
692 getNewRegNCG IntRep `thenUs` \ tmp ->
694 = let src_val = registerName register1 dst
695 code_val = registerCode register1 dst
696 src_amt = registerName register2 tmp
697 code_amt = registerCode register2 tmp
704 COMMENT (_PK_ "begin shift sequence"),
705 MOV L (OpReg src_val) r_dst,
706 MOV L (OpReg src_amt) r_tmp,
708 BT L (ImmInt 4) r_tmp,
710 instr (OpImm (ImmInt 16)) r_dst,
713 BT L (ImmInt 3) r_tmp,
715 instr (OpImm (ImmInt 8)) r_dst,
718 BT L (ImmInt 2) r_tmp,
720 instr (OpImm (ImmInt 4)) r_dst,
723 BT L (ImmInt 1) r_tmp,
725 instr (OpImm (ImmInt 2)) r_dst,
728 BT L (ImmInt 0) r_tmp,
730 instr (OpImm (ImmInt 1)) r_dst,
733 COMMENT (_PK_ "end shift sequence")
736 returnUs (Any IntRep code__2)
739 -- since ECX is always used as a spill temporary, we can't
740 -- use it here to do non-immediate shifts. No big deal --
741 -- they are only very rare, and we can give an equivalent
742 -- insn sequence which doesn't use ECX.
743 -- DO NOT USE THIS CODE, SINCE IT IS INCOMPATIBLE WITH THE SPILLER
744 = getRegister y `thenUs` \ register1 ->
745 getRegister x `thenUs` \ register2 ->
747 -- Note: we force the shift length to be loaded
748 -- into ECX, so that we can use CL when shifting.
749 -- (only register location we are allowed
750 -- to put shift amounts.)
752 -- The shift instruction is fed ECX as src reg,
753 -- but we coerce this into CL when printing out.
754 src1 = registerName register1 ecx
755 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
756 registerCode register1 ecx .
757 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
759 registerCode register1 ecx
762 code2 = registerCode register2 eax
763 src2 = registerName register2 eax
766 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
768 returnUs (Fixed IntRep eax code__2)
772 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
774 add_code sz x (StInt y)
775 = getRegister x `thenUs` \ register ->
776 getNewRegNCG IntRep `thenUs` \ tmp ->
778 code = registerCode register tmp
779 src1 = registerName register tmp
780 src2 = ImmInt (fromInteger y)
783 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
786 returnUs (Any IntRep code__2)
789 = getRegister x `thenUs` \ register1 ->
790 getRegister y `thenUs` \ register2 ->
791 getNewRegNCG IntRep `thenUs` \ tmp1 ->
792 getNewRegNCG IntRep `thenUs` \ tmp2 ->
794 code1 = registerCode register1 tmp1 asmVoid
795 src1 = registerName register1 tmp1
796 code2 = registerCode register2 tmp2 asmVoid
797 src2 = registerName register2 tmp2
799 = asmParThen [code1, code2] .
800 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1))
804 returnUs (Any IntRep code__2)
807 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
809 sub_code sz x (StInt y)
810 = getRegister x `thenUs` \ register ->
811 getNewRegNCG IntRep `thenUs` \ tmp ->
813 code = registerCode register tmp
814 src1 = registerName register tmp
815 src2 = ImmInt (-(fromInteger y))
818 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
821 returnUs (Any IntRep code__2)
823 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
828 -> StixTree -> StixTree
829 -> Bool -- True => division, False => remainder operation
832 -- x must go into eax, edx must be a sign-extension of eax, and y
833 -- should go in some other register (or memory), so that we get
834 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
835 -- put y in memory (if it is not there already)
837 quot_code sz x (StInd pk mem) is_division
838 = getRegister x `thenUs` \ register1 ->
839 getNewRegNCG IntRep `thenUs` \ tmp1 ->
840 getAmode mem `thenUs` \ amode ->
842 code1 = registerCode register1 tmp1 asmVoid
843 src1 = registerName register1 tmp1
844 code2 = amodeCode amode asmVoid
845 src2 = amodeAddr amode
846 code__2 = asmParThen [code1, code2] .
847 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
849 IDIV sz (OpAddr src2)]
851 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
853 quot_code sz x (StInt i) is_division
854 = getRegister x `thenUs` \ register1 ->
855 getNewRegNCG IntRep `thenUs` \ tmp1 ->
857 code1 = registerCode register1 tmp1 asmVoid
858 src1 = registerName register1 tmp1
859 src2 = ImmInt (fromInteger i)
860 code__2 = asmParThen [code1] .
861 mkSeqInstrs [-- we put src2 in (ebx)
863 (OpAddr (AddrBaseIndex (Just ebx) Nothing
864 (ImmInt OFFSET_R1))),
865 MOV L (OpReg src1) (OpReg eax),
867 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
871 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
873 quot_code sz x y is_division
874 = getRegister x `thenUs` \ register1 ->
875 getNewRegNCG IntRep `thenUs` \ tmp1 ->
876 getRegister y `thenUs` \ register2 ->
877 getNewRegNCG IntRep `thenUs` \ tmp2 ->
879 code1 = registerCode register1 tmp1 asmVoid
880 src1 = registerName register1 tmp1
881 code2 = registerCode register2 tmp2 asmVoid
882 src2 = registerName register2 tmp2
883 code__2 = asmParThen [code1, code2] .
884 if src2 == ecx || src2 == esi
886 MOV L (OpReg src1) (OpReg eax),
890 else mkSeqInstrs [ -- we put src2 in (ebx)
892 (OpAddr (AddrBaseIndex (Just ebx) Nothing
893 (ImmInt OFFSET_R1))),
894 MOV L (OpReg src1) (OpReg eax),
896 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
900 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
901 -----------------------
903 getRegister (StInd pk mem)
904 = getAmode mem `thenUs` \ amode ->
906 code = amodeCode amode
907 src = amodeAddr amode
908 size = primRepToSize pk
910 if pk == DoubleRep || pk == FloatRep
911 then mkSeqInstr (GLD size src dst)
912 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
914 returnUs (Any pk code__2)
916 getRegister (StInt i)
918 src = ImmInt (fromInteger i)
919 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
921 returnUs (Any IntRep code)
926 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
928 returnUs (Any PtrRep code)
930 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
933 imm__2 = case imm of Just x -> x
935 #endif {- i386_TARGET_ARCH -}
936 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
937 #if sparc_TARGET_ARCH
939 getRegister (StDouble d)
940 = getUniqLabelNCG `thenUs` \ lbl ->
941 getNewRegNCG PtrRep `thenUs` \ tmp ->
942 let code dst = mkSeqInstrs [
945 DATA DF [ImmDouble d],
947 SETHI (HI (ImmCLbl lbl)) tmp,
948 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
950 returnUs (Any DoubleRep code)
952 getRegister (StPrim primop [x]) -- unary PrimOps
954 IntNegOp -> trivialUCode (SUB False False g0) x
955 NotOp -> trivialUCode (XNOR False g0) x
957 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
959 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
961 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
962 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
964 OrdOp -> coerceIntCode IntRep x
967 Float2IntOp -> coerceFP2Int x
968 Int2FloatOp -> coerceInt2FP FloatRep x
969 Double2IntOp -> coerceFP2Int x
970 Int2DoubleOp -> coerceInt2FP DoubleRep x
974 fixed_x = if is_float_op -- promote to double
975 then StPrim Float2DoubleOp [x]
978 getRegister (StCall fn cCallConv DoubleRep [x])
982 FloatExpOp -> (True, SLIT("exp"))
983 FloatLogOp -> (True, SLIT("log"))
984 FloatSqrtOp -> (True, SLIT("sqrt"))
986 FloatSinOp -> (True, SLIT("sin"))
987 FloatCosOp -> (True, SLIT("cos"))
988 FloatTanOp -> (True, SLIT("tan"))
990 FloatAsinOp -> (True, SLIT("asin"))
991 FloatAcosOp -> (True, SLIT("acos"))
992 FloatAtanOp -> (True, SLIT("atan"))
994 FloatSinhOp -> (True, SLIT("sinh"))
995 FloatCoshOp -> (True, SLIT("cosh"))
996 FloatTanhOp -> (True, SLIT("tanh"))
998 DoubleExpOp -> (False, SLIT("exp"))
999 DoubleLogOp -> (False, SLIT("log"))
1000 DoubleSqrtOp -> (True, SLIT("sqrt"))
1002 DoubleSinOp -> (False, SLIT("sin"))
1003 DoubleCosOp -> (False, SLIT("cos"))
1004 DoubleTanOp -> (False, SLIT("tan"))
1006 DoubleAsinOp -> (False, SLIT("asin"))
1007 DoubleAcosOp -> (False, SLIT("acos"))
1008 DoubleAtanOp -> (False, SLIT("atan"))
1010 DoubleSinhOp -> (False, SLIT("sinh"))
1011 DoubleCoshOp -> (False, SLIT("cosh"))
1012 DoubleTanhOp -> (False, SLIT("tanh"))
1013 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
1015 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1017 CharGtOp -> condIntReg GTT x y
1018 CharGeOp -> condIntReg GE x y
1019 CharEqOp -> condIntReg EQQ x y
1020 CharNeOp -> condIntReg NE x y
1021 CharLtOp -> condIntReg LTT x y
1022 CharLeOp -> condIntReg LE x y
1024 IntGtOp -> condIntReg GTT x y
1025 IntGeOp -> condIntReg GE x y
1026 IntEqOp -> condIntReg EQQ x y
1027 IntNeOp -> condIntReg NE x y
1028 IntLtOp -> condIntReg LTT x y
1029 IntLeOp -> condIntReg LE x y
1031 WordGtOp -> condIntReg GU x y
1032 WordGeOp -> condIntReg GEU x y
1033 WordEqOp -> condIntReg EQQ x y
1034 WordNeOp -> condIntReg NE x y
1035 WordLtOp -> condIntReg LU x y
1036 WordLeOp -> condIntReg LEU x y
1038 AddrGtOp -> condIntReg GU x y
1039 AddrGeOp -> condIntReg GEU x y
1040 AddrEqOp -> condIntReg EQQ x y
1041 AddrNeOp -> condIntReg NE x y
1042 AddrLtOp -> condIntReg LU x y
1043 AddrLeOp -> condIntReg LEU x y
1045 FloatGtOp -> condFltReg GTT x y
1046 FloatGeOp -> condFltReg GE x y
1047 FloatEqOp -> condFltReg EQQ x y
1048 FloatNeOp -> condFltReg NE x y
1049 FloatLtOp -> condFltReg LTT x y
1050 FloatLeOp -> condFltReg LE x y
1052 DoubleGtOp -> condFltReg GTT x y
1053 DoubleGeOp -> condFltReg GE x y
1054 DoubleEqOp -> condFltReg EQQ x y
1055 DoubleNeOp -> condFltReg NE x y
1056 DoubleLtOp -> condFltReg LTT x y
1057 DoubleLeOp -> condFltReg LE x y
1059 IntAddOp -> trivialCode (ADD False False) x y
1060 IntSubOp -> trivialCode (SUB False False) x y
1062 -- ToDo: teach about V8+ SPARC mul/div instructions
1063 IntMulOp -> imul_div SLIT(".umul") x y
1064 IntQuotOp -> imul_div SLIT(".div") x y
1065 IntRemOp -> imul_div SLIT(".rem") x y
1067 FloatAddOp -> trivialFCode FloatRep FADD x y
1068 FloatSubOp -> trivialFCode FloatRep FSUB x y
1069 FloatMulOp -> trivialFCode FloatRep FMUL x y
1070 FloatDivOp -> trivialFCode FloatRep FDIV x y
1072 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1073 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1074 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1075 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1077 AndOp -> trivialCode (AND False) x y
1078 OrOp -> trivialCode (OR False) x y
1079 XorOp -> trivialCode (XOR False) x y
1080 SllOp -> trivialCode SLL x y
1081 SrlOp -> trivialCode SRL x y
1083 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1084 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1085 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1087 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1088 where promote x = StPrim Float2DoubleOp [x]
1089 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1090 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1092 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1094 getRegister (StInd pk mem)
1095 = getAmode mem `thenUs` \ amode ->
1097 code = amodeCode amode
1098 src = amodeAddr amode
1099 size = primRepToSize pk
1100 code__2 dst = code . mkSeqInstr (LD size src dst)
1102 returnUs (Any pk code__2)
1104 getRegister (StInt i)
1107 src = ImmInt (fromInteger i)
1108 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1110 returnUs (Any IntRep code)
1115 code dst = mkSeqInstrs [
1116 SETHI (HI imm__2) dst,
1117 OR False dst (RIImm (LO imm__2)) dst]
1119 returnUs (Any PtrRep code)
1122 imm__2 = case imm of Just x -> x
1124 #endif {- sparc_TARGET_ARCH -}
1127 %************************************************************************
1129 \subsection{The @Amode@ type}
1131 %************************************************************************
1133 @Amode@s: Memory addressing modes passed up the tree.
1135 data Amode = Amode MachRegsAddr InstrBlock
1137 amodeAddr (Amode addr _) = addr
1138 amodeCode (Amode _ code) = code
1141 Now, given a tree (the argument to an StInd) that references memory,
1142 produce a suitable addressing mode.
1145 getAmode :: StixTree -> UniqSM Amode
1147 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1149 #if alpha_TARGET_ARCH
1151 getAmode (StPrim IntSubOp [x, StInt i])
1152 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1153 getRegister x `thenUs` \ register ->
1155 code = registerCode register tmp
1156 reg = registerName register tmp
1157 off = ImmInt (-(fromInteger i))
1159 returnUs (Amode (AddrRegImm reg off) code)
1161 getAmode (StPrim IntAddOp [x, StInt i])
1162 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1163 getRegister x `thenUs` \ register ->
1165 code = registerCode register tmp
1166 reg = registerName register tmp
1167 off = ImmInt (fromInteger i)
1169 returnUs (Amode (AddrRegImm reg off) code)
1173 = returnUs (Amode (AddrImm imm__2) id)
1176 imm__2 = case imm of Just x -> x
1179 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1180 getRegister other `thenUs` \ register ->
1182 code = registerCode register tmp
1183 reg = registerName register tmp
1185 returnUs (Amode (AddrReg reg) code)
1187 #endif {- alpha_TARGET_ARCH -}
1188 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1189 #if i386_TARGET_ARCH
1191 getAmode (StPrim IntSubOp [x, StInt i])
1192 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1193 getRegister x `thenUs` \ register ->
1195 code = registerCode register tmp
1196 reg = registerName register tmp
1197 off = ImmInt (-(fromInteger i))
1199 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1201 getAmode (StPrim IntAddOp [x, StInt i])
1204 code = mkSeqInstrs []
1206 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1209 imm__2 = case imm of Just x -> x
1211 getAmode (StPrim IntAddOp [x, StInt i])
1212 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1213 getRegister x `thenUs` \ register ->
1215 code = registerCode register tmp
1216 reg = registerName register tmp
1217 off = ImmInt (fromInteger i)
1219 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1221 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1222 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1223 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1224 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1225 getRegister x `thenUs` \ register1 ->
1226 getRegister y `thenUs` \ register2 ->
1228 code1 = registerCode register1 tmp1 asmVoid
1229 reg1 = registerName register1 tmp1
1230 code2 = registerCode register2 tmp2 asmVoid
1231 reg2 = registerName register2 tmp2
1232 code__2 = asmParThen [code1, code2]
1233 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1235 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1241 code = mkSeqInstrs []
1243 returnUs (Amode (ImmAddr imm__2 0) code)
1246 imm__2 = case imm of Just x -> x
1249 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1250 getRegister other `thenUs` \ register ->
1252 code = registerCode register tmp
1253 reg = registerName register tmp
1256 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1258 #endif {- i386_TARGET_ARCH -}
1259 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1260 #if sparc_TARGET_ARCH
1262 getAmode (StPrim IntSubOp [x, StInt i])
1264 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1265 getRegister x `thenUs` \ register ->
1267 code = registerCode register tmp
1268 reg = registerName register tmp
1269 off = ImmInt (-(fromInteger i))
1271 returnUs (Amode (AddrRegImm reg off) code)
1274 getAmode (StPrim IntAddOp [x, StInt i])
1276 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1277 getRegister x `thenUs` \ register ->
1279 code = registerCode register tmp
1280 reg = registerName register tmp
1281 off = ImmInt (fromInteger i)
1283 returnUs (Amode (AddrRegImm reg off) code)
1285 getAmode (StPrim IntAddOp [x, y])
1286 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1287 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1288 getRegister x `thenUs` \ register1 ->
1289 getRegister y `thenUs` \ register2 ->
1291 code1 = registerCode register1 tmp1 asmVoid
1292 reg1 = registerName register1 tmp1
1293 code2 = registerCode register2 tmp2 asmVoid
1294 reg2 = registerName register2 tmp2
1295 code__2 = asmParThen [code1, code2]
1297 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1301 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1303 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1305 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1308 imm__2 = case imm of Just x -> x
1311 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1312 getRegister other `thenUs` \ register ->
1314 code = registerCode register tmp
1315 reg = registerName register tmp
1318 returnUs (Amode (AddrRegImm reg off) code)
1320 #endif {- sparc_TARGET_ARCH -}
1323 %************************************************************************
1325 \subsection{The @CondCode@ type}
1327 %************************************************************************
1329 Condition codes passed up the tree.
1331 data CondCode = CondCode Bool Cond InstrBlock
1333 condName (CondCode _ cond _) = cond
1334 condFloat (CondCode is_float _ _) = is_float
1335 condCode (CondCode _ _ code) = code
1338 Set up a condition code for a conditional branch.
1341 getCondCode :: StixTree -> UniqSM CondCode
1343 #if alpha_TARGET_ARCH
1344 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1345 #endif {- alpha_TARGET_ARCH -}
1346 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1348 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1349 -- yes, they really do seem to want exactly the same!
1351 getCondCode (StPrim primop [x, y])
1353 CharGtOp -> condIntCode GTT x y
1354 CharGeOp -> condIntCode GE x y
1355 CharEqOp -> condIntCode EQQ x y
1356 CharNeOp -> condIntCode NE x y
1357 CharLtOp -> condIntCode LTT x y
1358 CharLeOp -> condIntCode LE x y
1360 IntGtOp -> condIntCode GTT x y
1361 IntGeOp -> condIntCode GE x y
1362 IntEqOp -> condIntCode EQQ x y
1363 IntNeOp -> condIntCode NE x y
1364 IntLtOp -> condIntCode LTT x y
1365 IntLeOp -> condIntCode LE x y
1367 WordGtOp -> condIntCode GU x y
1368 WordGeOp -> condIntCode GEU x y
1369 WordEqOp -> condIntCode EQQ x y
1370 WordNeOp -> condIntCode NE x y
1371 WordLtOp -> condIntCode LU x y
1372 WordLeOp -> condIntCode LEU x y
1374 AddrGtOp -> condIntCode GU x y
1375 AddrGeOp -> condIntCode GEU x y
1376 AddrEqOp -> condIntCode EQQ x y
1377 AddrNeOp -> condIntCode NE x y
1378 AddrLtOp -> condIntCode LU x y
1379 AddrLeOp -> condIntCode LEU x y
1381 FloatGtOp -> condFltCode GTT x y
1382 FloatGeOp -> condFltCode GE x y
1383 FloatEqOp -> condFltCode EQQ x y
1384 FloatNeOp -> condFltCode NE x y
1385 FloatLtOp -> condFltCode LTT x y
1386 FloatLeOp -> condFltCode LE x y
1388 DoubleGtOp -> condFltCode GTT x y
1389 DoubleGeOp -> condFltCode GE x y
1390 DoubleEqOp -> condFltCode EQQ x y
1391 DoubleNeOp -> condFltCode NE x y
1392 DoubleLtOp -> condFltCode LTT x y
1393 DoubleLeOp -> condFltCode LE x y
1395 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1400 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1401 passed back up the tree.
1404 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1406 #if alpha_TARGET_ARCH
1407 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1408 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1409 #endif {- alpha_TARGET_ARCH -}
1411 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1412 #if i386_TARGET_ARCH
1414 condIntCode cond (StInd _ x) y
1416 = getAmode x `thenUs` \ amode ->
1418 code1 = amodeCode amode asmVoid
1419 y__2 = amodeAddr amode
1420 code__2 = asmParThen [code1] .
1421 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1423 returnUs (CondCode False cond code__2)
1426 imm__2 = case imm of Just x -> x
1428 condIntCode cond x (StInt 0)
1429 = getRegister x `thenUs` \ register1 ->
1430 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1432 code1 = registerCode register1 tmp1 asmVoid
1433 src1 = registerName register1 tmp1
1434 code__2 = asmParThen [code1] .
1435 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1437 returnUs (CondCode False cond code__2)
1439 condIntCode cond x y
1441 = getRegister x `thenUs` \ register1 ->
1442 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1444 code1 = registerCode register1 tmp1 asmVoid
1445 src1 = registerName register1 tmp1
1446 code__2 = asmParThen [code1] .
1447 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1449 returnUs (CondCode False cond code__2)
1452 imm__2 = case imm of Just x -> x
1454 condIntCode cond (StInd _ x) y
1455 = getAmode x `thenUs` \ amode ->
1456 getRegister y `thenUs` \ register2 ->
1457 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1459 code1 = amodeCode amode asmVoid
1460 src1 = amodeAddr amode
1461 code2 = registerCode register2 tmp2 asmVoid
1462 src2 = registerName register2 tmp2
1463 code__2 = asmParThen [code1, code2] .
1464 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1466 returnUs (CondCode False cond code__2)
1468 condIntCode cond y (StInd _ x)
1469 = getAmode x `thenUs` \ amode ->
1470 getRegister y `thenUs` \ register2 ->
1471 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1473 code1 = amodeCode amode asmVoid
1474 src1 = amodeAddr amode
1475 code2 = registerCode register2 tmp2 asmVoid
1476 src2 = registerName register2 tmp2
1477 code__2 = asmParThen [code1, code2] .
1478 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1480 returnUs (CondCode False cond code__2)
1482 condIntCode cond x y
1483 = getRegister x `thenUs` \ register1 ->
1484 getRegister y `thenUs` \ register2 ->
1485 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1486 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1488 code1 = registerCode register1 tmp1 asmVoid
1489 src1 = registerName register1 tmp1
1490 code2 = registerCode register2 tmp2 asmVoid
1491 src2 = registerName register2 tmp2
1492 code__2 = asmParThen [code1, code2] .
1493 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1495 returnUs (CondCode False cond code__2)
1498 condFltCode cond x y
1499 = getRegister x `thenUs` \ register1 ->
1500 getRegister y `thenUs` \ register2 ->
1501 getNewRegNCG (registerRep register1)
1503 getNewRegNCG (registerRep register2)
1505 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1507 pk1 = registerRep register1
1508 code1 = registerCode register1 tmp1
1509 src1 = registerName register1 tmp1
1511 pk2 = registerRep register2
1512 code2 = registerCode register2 tmp2
1513 src2 = registerName register2 tmp2
1515 code__2 = asmParThen [code1 asmVoid, code2 asmVoid] .
1516 mkSeqInstr (GCMP (primRepToSize pk1) src1 src2)
1518 {- On the 486, the flags set by FP compare are the unsigned ones!
1519 (This looks like a HACK to me. WDP 96/03)
1521 fix_FP_cond :: Cond -> Cond
1523 fix_FP_cond GE = GEU
1524 fix_FP_cond GTT = GU
1525 fix_FP_cond LTT = LU
1526 fix_FP_cond LE = LEU
1527 fix_FP_cond any = any
1529 returnUs (CondCode True (fix_FP_cond cond) code__2)
1533 #endif {- i386_TARGET_ARCH -}
1534 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1535 #if sparc_TARGET_ARCH
1537 condIntCode cond x (StInt y)
1539 = getRegister x `thenUs` \ register ->
1540 getNewRegNCG IntRep `thenUs` \ tmp ->
1542 code = registerCode register tmp
1543 src1 = registerName register tmp
1544 src2 = ImmInt (fromInteger y)
1545 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1547 returnUs (CondCode False cond code__2)
1549 condIntCode cond x y
1550 = getRegister x `thenUs` \ register1 ->
1551 getRegister y `thenUs` \ register2 ->
1552 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1553 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1555 code1 = registerCode register1 tmp1 asmVoid
1556 src1 = registerName register1 tmp1
1557 code2 = registerCode register2 tmp2 asmVoid
1558 src2 = registerName register2 tmp2
1559 code__2 = asmParThen [code1, code2] .
1560 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1562 returnUs (CondCode False cond code__2)
1565 condFltCode cond x y
1566 = getRegister x `thenUs` \ register1 ->
1567 getRegister y `thenUs` \ register2 ->
1568 getNewRegNCG (registerRep register1)
1570 getNewRegNCG (registerRep register2)
1572 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1574 promote x = asmInstr (FxTOy F DF x tmp)
1576 pk1 = registerRep register1
1577 code1 = registerCode register1 tmp1
1578 src1 = registerName register1 tmp1
1580 pk2 = registerRep register2
1581 code2 = registerCode register2 tmp2
1582 src2 = registerName register2 tmp2
1586 asmParThen [code1 asmVoid, code2 asmVoid] .
1587 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1588 else if pk1 == FloatRep then
1589 asmParThen [code1 (promote src1), code2 asmVoid] .
1590 mkSeqInstr (FCMP True DF tmp src2)
1592 asmParThen [code1 asmVoid, code2 (promote src2)] .
1593 mkSeqInstr (FCMP True DF src1 tmp)
1595 returnUs (CondCode True cond code__2)
1597 #endif {- sparc_TARGET_ARCH -}
1600 %************************************************************************
1602 \subsection{Generating assignments}
1604 %************************************************************************
1606 Assignments are really at the heart of the whole code generation
1607 business. Almost all top-level nodes of any real importance are
1608 assignments, which correspond to loads, stores, or register transfers.
1609 If we're really lucky, some of the register transfers will go away,
1610 because we can use the destination register to complete the code
1611 generation for the right hand side. This only fails when the right
1612 hand side is forced into a fixed register (e.g. the result of a call).
1615 assignIntCode, assignFltCode
1616 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1618 #if alpha_TARGET_ARCH
1620 assignIntCode pk (StInd _ dst) src
1621 = getNewRegNCG IntRep `thenUs` \ tmp ->
1622 getAmode dst `thenUs` \ amode ->
1623 getRegister src `thenUs` \ register ->
1625 code1 = amodeCode amode asmVoid
1626 dst__2 = amodeAddr amode
1627 code2 = registerCode register tmp asmVoid
1628 src__2 = registerName register tmp
1629 sz = primRepToSize pk
1630 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1634 assignIntCode pk dst src
1635 = getRegister dst `thenUs` \ register1 ->
1636 getRegister src `thenUs` \ register2 ->
1638 dst__2 = registerName register1 zeroh
1639 code = registerCode register2 dst__2
1640 src__2 = registerName register2 dst__2
1641 code__2 = if isFixed register2
1642 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1647 #endif {- alpha_TARGET_ARCH -}
1648 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1649 #if i386_TARGET_ARCH
1651 assignIntCode pk dd@(StInd _ dst) src
1652 = getAmode dst `thenUs` \ amode ->
1653 get_op_RI src `thenUs` \ (codesrc, opsrc) ->
1655 code1 = amodeCode amode asmVoid
1656 dst__2 = amodeAddr amode
1657 code__2 = asmParThen [code1, codesrc asmVoid] .
1658 mkSeqInstr (MOV (primRepToSize pk) opsrc (OpAddr dst__2))
1664 -> UniqSM (InstrBlock,Operand) -- code, operator
1668 = returnUs (asmParThen [], OpImm imm_op)
1671 imm_op = case imm of Just x -> x
1674 = getRegister op `thenUs` \ register ->
1675 getNewRegNCG (registerRep register)
1678 code = registerCode register tmp
1679 reg = registerName register tmp
1681 returnUs (code, OpReg reg)
1683 assignIntCode pk dst (StInd pks src)
1684 = getNewRegNCG IntRep `thenUs` \ tmp ->
1685 getAmode src `thenUs` \ amode ->
1686 getRegister dst `thenUs` \ register ->
1688 code1 = amodeCode amode asmVoid
1689 src__2 = amodeAddr amode
1690 code2 = registerCode register tmp asmVoid
1691 dst__2 = registerName register tmp
1692 szs = primRepToSize pks
1693 code__2 = asmParThen [code1, code2] .
1695 L -> mkSeqInstr (MOV L (OpAddr src__2) (OpReg dst__2))
1696 B -> mkSeqInstr (MOVZxL B (OpAddr src__2) (OpReg dst__2))
1700 assignIntCode pk dst src
1701 = getRegister dst `thenUs` \ register1 ->
1702 getRegister src `thenUs` \ register2 ->
1703 getNewRegNCG IntRep `thenUs` \ tmp ->
1705 dst__2 = registerName register1 tmp
1706 code = registerCode register2 dst__2
1707 src__2 = registerName register2 dst__2
1708 code__2 = if isFixed register2 && dst__2 /= src__2
1709 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1714 #endif {- i386_TARGET_ARCH -}
1715 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1716 #if sparc_TARGET_ARCH
1718 assignIntCode pk (StInd _ dst) src
1719 = getNewRegNCG IntRep `thenUs` \ tmp ->
1720 getAmode dst `thenUs` \ amode ->
1721 getRegister src `thenUs` \ register ->
1723 code1 = amodeCode amode asmVoid
1724 dst__2 = amodeAddr amode
1725 code2 = registerCode register tmp asmVoid
1726 src__2 = registerName register tmp
1727 sz = primRepToSize pk
1728 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1732 assignIntCode pk dst src
1733 = getRegister dst `thenUs` \ register1 ->
1734 getRegister src `thenUs` \ register2 ->
1736 dst__2 = registerName register1 g0
1737 code = registerCode register2 dst__2
1738 src__2 = registerName register2 dst__2
1739 code__2 = if isFixed register2
1740 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1745 #endif {- sparc_TARGET_ARCH -}
1748 % --------------------------------
1749 Floating-point assignments:
1750 % --------------------------------
1752 #if alpha_TARGET_ARCH
1754 assignFltCode pk (StInd _ dst) src
1755 = getNewRegNCG pk `thenUs` \ tmp ->
1756 getAmode dst `thenUs` \ amode ->
1757 getRegister src `thenUs` \ register ->
1759 code1 = amodeCode amode asmVoid
1760 dst__2 = amodeAddr amode
1761 code2 = registerCode register tmp asmVoid
1762 src__2 = registerName register tmp
1763 sz = primRepToSize pk
1764 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1768 assignFltCode pk dst src
1769 = getRegister dst `thenUs` \ register1 ->
1770 getRegister src `thenUs` \ register2 ->
1772 dst__2 = registerName register1 zeroh
1773 code = registerCode register2 dst__2
1774 src__2 = registerName register2 dst__2
1775 code__2 = if isFixed register2
1776 then code . mkSeqInstr (FMOV src__2 dst__2)
1781 #endif {- alpha_TARGET_ARCH -}
1782 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1783 #if i386_TARGET_ARCH
1785 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1786 = getNewRegNCG IntRep `thenUs` \ tmp ->
1787 getAmode src `thenUs` \ amodesrc ->
1788 getAmode dst `thenUs` \ amodedst ->
1790 codesrc1 = amodeCode amodesrc asmVoid
1791 addrsrc1 = amodeAddr amodesrc
1792 codedst1 = amodeCode amodedst asmVoid
1793 addrdst1 = amodeAddr amodedst
1794 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1795 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1797 code__2 = asmParThen [codesrc1, codedst1] .
1798 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1799 MOV L (OpReg tmp) (OpAddr addrdst1)]
1802 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1803 MOV L (OpReg tmp) (OpAddr addrdst2)]
1808 assignFltCode pk (StInd _ dst) src
1809 = getNewRegNCG pk `thenUs` \ tmp ->
1810 getAmode dst `thenUs` \ amode ->
1811 getRegister src `thenUs` \ register ->
1813 sz = primRepToSize pk
1814 dst__2 = amodeAddr amode
1816 code1 = amodeCode amode asmVoid
1817 code2 = registerCode register tmp asmVoid
1819 src__2 = registerName register tmp
1821 code__2 = asmParThen [code1, code2] .
1822 mkSeqInstr (GST sz src__2 dst__2)
1826 assignFltCode pk dst src
1827 = getRegister dst `thenUs` \ register1 ->
1828 getRegister src `thenUs` \ register2 ->
1829 getNewRegNCG pk `thenUs` \ tmp ->
1831 -- the register which is dst
1832 dst__2 = registerName register1 tmp
1833 -- the register into which src is computed, preferably dst__2
1834 src__2 = registerName register2 dst__2
1835 -- code to compute src into src__2
1836 code = registerCode register2 dst__2
1838 code__2 = if isFixed register2
1839 then code . mkSeqInstr (GMOV src__2 dst__2)
1844 #endif {- i386_TARGET_ARCH -}
1845 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1846 #if sparc_TARGET_ARCH
1848 assignFltCode pk (StInd _ dst) src
1849 = getNewRegNCG pk `thenUs` \ tmp1 ->
1850 getAmode dst `thenUs` \ amode ->
1851 getRegister src `thenUs` \ register ->
1853 sz = primRepToSize pk
1854 dst__2 = amodeAddr amode
1856 code1 = amodeCode amode asmVoid
1857 code2 = registerCode register tmp1 asmVoid
1859 src__2 = registerName register tmp1
1860 pk__2 = registerRep register
1861 sz__2 = primRepToSize pk__2
1863 code__2 = asmParThen [code1, code2] .
1865 mkSeqInstr (ST sz src__2 dst__2)
1867 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1871 assignFltCode pk dst src
1872 = getRegister dst `thenUs` \ register1 ->
1873 getRegister src `thenUs` \ register2 ->
1875 pk__2 = registerRep register2
1876 sz__2 = primRepToSize pk__2
1878 getNewRegNCG pk__2 `thenUs` \ tmp ->
1880 sz = primRepToSize pk
1881 dst__2 = registerName register1 g0 -- must be Fixed
1884 reg__2 = if pk /= pk__2 then tmp else dst__2
1886 code = registerCode register2 reg__2
1888 src__2 = registerName register2 reg__2
1892 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1893 else if isFixed register2 then
1894 code . mkSeqInstr (FMOV sz src__2 dst__2)
1900 #endif {- sparc_TARGET_ARCH -}
1903 %************************************************************************
1905 \subsection{Generating an unconditional branch}
1907 %************************************************************************
1909 We accept two types of targets: an immediate CLabel or a tree that
1910 gets evaluated into a register. Any CLabels which are AsmTemporaries
1911 are assumed to be in the local block of code, close enough for a
1912 branch instruction. Other CLabels are assumed to be far away.
1914 (If applicable) Do not fill the delay slots here; you will confuse the
1918 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1920 #if alpha_TARGET_ARCH
1922 genJump (StCLbl lbl)
1923 | isAsmTemp lbl = returnInstr (BR target)
1924 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1926 target = ImmCLbl lbl
1929 = getRegister tree `thenUs` \ register ->
1930 getNewRegNCG PtrRep `thenUs` \ tmp ->
1932 dst = registerName register pv
1933 code = registerCode register pv
1934 target = registerName register pv
1936 if isFixed register then
1937 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1939 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1941 #endif {- alpha_TARGET_ARCH -}
1942 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1943 #if i386_TARGET_ARCH
1946 genJump (StCLbl lbl)
1947 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1948 | otherwise = returnInstrs [JMP (OpImm target)]
1950 target = ImmCLbl lbl
1953 genJump (StInd pk mem)
1954 = getAmode mem `thenUs` \ amode ->
1956 code = amodeCode amode
1957 target = amodeAddr amode
1959 returnSeq code [JMP (OpAddr target)]
1963 = returnInstr (JMP (OpImm target))
1966 = getRegister tree `thenUs` \ register ->
1967 getNewRegNCG PtrRep `thenUs` \ tmp ->
1969 code = registerCode register tmp
1970 target = registerName register tmp
1972 returnSeq code [JMP (OpReg target)]
1975 target = case imm of Just x -> x
1977 #endif {- i386_TARGET_ARCH -}
1978 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1979 #if sparc_TARGET_ARCH
1981 genJump (StCLbl lbl)
1982 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1983 | otherwise = returnInstrs [CALL target 0 True, NOP]
1985 target = ImmCLbl lbl
1988 = getRegister tree `thenUs` \ register ->
1989 getNewRegNCG PtrRep `thenUs` \ tmp ->
1991 code = registerCode register tmp
1992 target = registerName register tmp
1994 returnSeq code [JMP (AddrRegReg target g0), NOP]
1996 #endif {- sparc_TARGET_ARCH -}
1999 %************************************************************************
2001 \subsection{Conditional jumps}
2003 %************************************************************************
2005 Conditional jumps are always to local labels, so we can use branch
2006 instructions. We peek at the arguments to decide what kind of
2009 ALPHA: For comparisons with 0, we're laughing, because we can just do
2010 the desired conditional branch.
2012 I386: First, we have to ensure that the condition
2013 codes are set according to the supplied comparison operation.
2015 SPARC: First, we have to ensure that the condition codes are set
2016 according to the supplied comparison operation. We generate slightly
2017 different code for floating point comparisons, because a floating
2018 point operation cannot directly precede a @BF@. We assume the worst
2019 and fill that slot with a @NOP@.
2021 SPARC: Do not fill the delay slots here; you will confuse the register
2026 :: CLabel -- the branch target
2027 -> StixTree -- the condition on which to branch
2028 -> UniqSM InstrBlock
2030 #if alpha_TARGET_ARCH
2032 genCondJump lbl (StPrim op [x, StInt 0])
2033 = getRegister x `thenUs` \ register ->
2034 getNewRegNCG (registerRep register)
2037 code = registerCode register tmp
2038 value = registerName register tmp
2039 pk = registerRep register
2040 target = ImmCLbl lbl
2042 returnSeq code [BI (cmpOp op) value target]
2044 cmpOp CharGtOp = GTT
2046 cmpOp CharEqOp = EQQ
2048 cmpOp CharLtOp = LTT
2057 cmpOp WordGeOp = ALWAYS
2058 cmpOp WordEqOp = EQQ
2060 cmpOp WordLtOp = NEVER
2061 cmpOp WordLeOp = EQQ
2063 cmpOp AddrGeOp = ALWAYS
2064 cmpOp AddrEqOp = EQQ
2066 cmpOp AddrLtOp = NEVER
2067 cmpOp AddrLeOp = EQQ
2069 genCondJump lbl (StPrim op [x, StDouble 0.0])
2070 = getRegister x `thenUs` \ register ->
2071 getNewRegNCG (registerRep register)
2074 code = registerCode register tmp
2075 value = registerName register tmp
2076 pk = registerRep register
2077 target = ImmCLbl lbl
2079 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2081 cmpOp FloatGtOp = GTT
2082 cmpOp FloatGeOp = GE
2083 cmpOp FloatEqOp = EQQ
2084 cmpOp FloatNeOp = NE
2085 cmpOp FloatLtOp = LTT
2086 cmpOp FloatLeOp = LE
2087 cmpOp DoubleGtOp = GTT
2088 cmpOp DoubleGeOp = GE
2089 cmpOp DoubleEqOp = EQQ
2090 cmpOp DoubleNeOp = NE
2091 cmpOp DoubleLtOp = LTT
2092 cmpOp DoubleLeOp = LE
2094 genCondJump lbl (StPrim op [x, y])
2096 = trivialFCode pr instr x y `thenUs` \ register ->
2097 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2099 code = registerCode register tmp
2100 result = registerName register tmp
2101 target = ImmCLbl lbl
2103 returnUs (code . mkSeqInstr (BF cond result target))
2105 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2107 fltCmpOp op = case op of
2121 (instr, cond) = case op of
2122 FloatGtOp -> (FCMP TF LE, EQQ)
2123 FloatGeOp -> (FCMP TF LTT, EQQ)
2124 FloatEqOp -> (FCMP TF EQQ, NE)
2125 FloatNeOp -> (FCMP TF EQQ, EQQ)
2126 FloatLtOp -> (FCMP TF LTT, NE)
2127 FloatLeOp -> (FCMP TF LE, NE)
2128 DoubleGtOp -> (FCMP TF LE, EQQ)
2129 DoubleGeOp -> (FCMP TF LTT, EQQ)
2130 DoubleEqOp -> (FCMP TF EQQ, NE)
2131 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2132 DoubleLtOp -> (FCMP TF LTT, NE)
2133 DoubleLeOp -> (FCMP TF LE, NE)
2135 genCondJump lbl (StPrim op [x, y])
2136 = trivialCode instr x y `thenUs` \ register ->
2137 getNewRegNCG IntRep `thenUs` \ tmp ->
2139 code = registerCode register tmp
2140 result = registerName register tmp
2141 target = ImmCLbl lbl
2143 returnUs (code . mkSeqInstr (BI cond result target))
2145 (instr, cond) = case op of
2146 CharGtOp -> (CMP LE, EQQ)
2147 CharGeOp -> (CMP LTT, EQQ)
2148 CharEqOp -> (CMP EQQ, NE)
2149 CharNeOp -> (CMP EQQ, EQQ)
2150 CharLtOp -> (CMP LTT, NE)
2151 CharLeOp -> (CMP LE, NE)
2152 IntGtOp -> (CMP LE, EQQ)
2153 IntGeOp -> (CMP LTT, EQQ)
2154 IntEqOp -> (CMP EQQ, NE)
2155 IntNeOp -> (CMP EQQ, EQQ)
2156 IntLtOp -> (CMP LTT, NE)
2157 IntLeOp -> (CMP LE, NE)
2158 WordGtOp -> (CMP ULE, EQQ)
2159 WordGeOp -> (CMP ULT, EQQ)
2160 WordEqOp -> (CMP EQQ, NE)
2161 WordNeOp -> (CMP EQQ, EQQ)
2162 WordLtOp -> (CMP ULT, NE)
2163 WordLeOp -> (CMP ULE, NE)
2164 AddrGtOp -> (CMP ULE, EQQ)
2165 AddrGeOp -> (CMP ULT, EQQ)
2166 AddrEqOp -> (CMP EQQ, NE)
2167 AddrNeOp -> (CMP EQQ, EQQ)
2168 AddrLtOp -> (CMP ULT, NE)
2169 AddrLeOp -> (CMP ULE, NE)
2171 #endif {- alpha_TARGET_ARCH -}
2172 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2173 #if i386_TARGET_ARCH
2175 genCondJump lbl bool
2176 = getCondCode bool `thenUs` \ condition ->
2178 code = condCode condition
2179 cond = condName condition
2180 target = ImmCLbl lbl
2182 returnSeq code [JXX cond lbl]
2184 #endif {- i386_TARGET_ARCH -}
2185 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2186 #if sparc_TARGET_ARCH
2188 genCondJump lbl bool
2189 = getCondCode bool `thenUs` \ condition ->
2191 code = condCode condition
2192 cond = condName condition
2193 target = ImmCLbl lbl
2196 if condFloat condition then
2197 [NOP, BF cond False target, NOP]
2199 [BI cond False target, NOP]
2202 #endif {- sparc_TARGET_ARCH -}
2205 %************************************************************************
2207 \subsection{Generating C calls}
2209 %************************************************************************
2211 Now the biggest nightmare---calls. Most of the nastiness is buried in
2212 @get_arg@, which moves the arguments to the correct registers/stack
2213 locations. Apart from that, the code is easy.
2215 (If applicable) Do not fill the delay slots here; you will confuse the
2220 :: FAST_STRING -- function to call
2222 -> PrimRep -- type of the result
2223 -> [StixTree] -- arguments (of mixed type)
2224 -> UniqSM InstrBlock
2226 #if alpha_TARGET_ARCH
2228 genCCall fn cconv kind args
2229 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2230 `thenUs` \ ((unused,_), argCode) ->
2232 nRegs = length allArgRegs - length unused
2233 code = asmParThen (map ($ asmVoid) argCode)
2236 LDA pv (AddrImm (ImmLab (ptext fn))),
2237 JSR ra (AddrReg pv) nRegs,
2238 LDGP gp (AddrReg ra)]
2240 ------------------------
2241 {- Try to get a value into a specific register (or registers) for
2242 a call. The first 6 arguments go into the appropriate
2243 argument register (separate registers for integer and floating
2244 point arguments, but used in lock-step), and the remaining
2245 arguments are dumped to the stack, beginning at 0(sp). Our
2246 first argument is a pair of the list of remaining argument
2247 registers to be assigned for this call and the next stack
2248 offset to use for overflowing arguments. This way,
2249 @get_Arg@ can be applied to all of a call's arguments using
2253 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2254 -> StixTree -- Current argument
2255 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2257 -- We have to use up all of our argument registers first...
2259 get_arg ((iDst,fDst):dsts, offset) arg
2260 = getRegister arg `thenUs` \ register ->
2262 reg = if isFloatingRep pk then fDst else iDst
2263 code = registerCode register reg
2264 src = registerName register reg
2265 pk = registerRep register
2268 if isFloatingRep pk then
2269 ((dsts, offset), if isFixed register then
2270 code . mkSeqInstr (FMOV src fDst)
2273 ((dsts, offset), if isFixed register then
2274 code . mkSeqInstr (OR src (RIReg src) iDst)
2277 -- Once we have run out of argument registers, we move to the
2280 get_arg ([], offset) arg
2281 = getRegister arg `thenUs` \ register ->
2282 getNewRegNCG (registerRep register)
2285 code = registerCode register tmp
2286 src = registerName register tmp
2287 pk = registerRep register
2288 sz = primRepToSize pk
2290 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2292 #endif {- alpha_TARGET_ARCH -}
2293 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2294 #if i386_TARGET_ARCH
2296 genCCall fn cconv kind [StInt i]
2297 | fn == SLIT ("PerformGC_wrapper")
2298 = let call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2299 CALL (ImmLit (ptext (if underscorePrefix
2300 then (SLIT ("_PerformGC_wrapper"))
2301 else (SLIT ("PerformGC_wrapper")))))]
2306 genCCall fn cconv kind args
2307 = get_call_args args `thenUs` \ (tot_arg_size, argCode) ->
2309 code2 = asmParThen (map ($ asmVoid) argCode)
2310 call = [SUB L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2312 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)
2315 returnSeq code2 call
2318 -- function names that begin with '.' are assumed to be special
2319 -- internally generated names like '.mul,' which don't get an
2320 -- underscore prefix
2321 -- ToDo:needed (WDP 96/03) ???
2322 fn__2 = case (_HEAD_ fn) of
2323 '.' -> ImmLit (ptext fn)
2324 _ -> ImmLab (ptext fn)
2331 -- do get_call_arg on each arg, threading the total arg size along
2332 -- process the args right-to-left
2333 get_call_args :: [StixTree] -> UniqSM (Int, [InstrBlock])
2338 = returnUs (curr_sz, [])
2339 f curr_sz (arg:args)
2340 = f curr_sz args `thenUs` \ (new_sz, iblocks) ->
2341 get_call_arg arg new_sz `thenUs` \ (new_sz2, iblock) ->
2342 returnUs (new_sz2, iblock:iblocks)
2346 get_call_arg :: StixTree{-current argument-}
2347 -> Int{-running total of arg sizes seen so far-}
2348 -> UniqSM (Int, InstrBlock) -- updated tot argsz, code
2350 get_call_arg arg old_sz
2351 = get_op arg `thenUs` \ (code, reg, sz) ->
2352 let new_sz = old_sz + arg_size sz
2353 in if (case sz of DF -> True; F -> True; _ -> False)
2354 then returnUs (new_sz,
2356 mkSeqInstr (GST DF reg
2357 (AddrBaseIndex (Just esp)
2358 Nothing (ImmInt (- new_sz))))
2360 else returnUs (new_sz,
2362 mkSeqInstr (MOV L (OpReg reg)
2364 (AddrBaseIndex (Just esp)
2365 Nothing (ImmInt (- new_sz)))))
2370 -> UniqSM (InstrBlock, Reg, Size) -- code, reg, size
2373 = getRegister op `thenUs` \ register ->
2374 getNewRegNCG (registerRep register)
2377 code = registerCode register tmp
2378 reg = registerName register tmp
2379 pk = registerRep register
2380 sz = primRepToSize pk
2382 returnUs (code, reg, sz)
2384 #endif {- i386_TARGET_ARCH -}
2385 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2386 #if sparc_TARGET_ARCH
2388 genCCall fn cconv kind args
2389 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2390 `thenUs` \ ((unused,_), argCode) ->
2392 nRegs = length allArgRegs - length unused
2393 call = CALL fn__2 nRegs False
2394 code = asmParThen (map ($ asmVoid) argCode)
2396 returnSeq code [call, NOP]
2398 -- function names that begin with '.' are assumed to be special
2399 -- internally generated names like '.mul,' which don't get an
2400 -- underscore prefix
2401 -- ToDo:needed (WDP 96/03) ???
2402 fn__2 = case (_HEAD_ fn) of
2403 '.' -> ImmLit (ptext fn)
2404 _ -> ImmLab (ptext fn)
2406 ------------------------------------
2407 {- Try to get a value into a specific register (or registers) for
2408 a call. The SPARC calling convention is an absolute
2409 nightmare. The first 6x32 bits of arguments are mapped into
2410 %o0 through %o5, and the remaining arguments are dumped to the
2411 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2412 first argument is a pair of the list of remaining argument
2413 registers to be assigned for this call and the next stack
2414 offset to use for overflowing arguments. This way,
2415 @get_arg@ can be applied to all of a call's arguments using
2419 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2420 -> StixTree -- Current argument
2421 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2423 -- We have to use up all of our argument registers first...
2425 get_arg (dst:dsts, offset) arg
2426 = getRegister arg `thenUs` \ register ->
2427 getNewRegNCG (registerRep register)
2430 reg = if isFloatingRep pk then tmp else dst
2431 code = registerCode register reg
2432 src = registerName register reg
2433 pk = registerRep register
2435 returnUs (case pk of
2438 [] -> (([], offset + 1), code . mkSeqInstrs [
2439 -- conveniently put the second part in the right stack
2440 -- location, and load the first part into %o5
2441 ST DF src (spRel (offset - 1)),
2442 LD W (spRel (offset - 1)) dst])
2443 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2444 ST DF src (spRel (-2)),
2445 LD W (spRel (-2)) dst,
2446 LD W (spRel (-1)) dst__2])
2447 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2448 ST F src (spRel (-2)),
2449 LD W (spRel (-2)) dst])
2450 _ -> ((dsts, offset), if isFixed register then
2451 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2454 -- Once we have run out of argument registers, we move to the
2457 get_arg ([], offset) arg
2458 = getRegister arg `thenUs` \ register ->
2459 getNewRegNCG (registerRep register)
2462 code = registerCode register tmp
2463 src = registerName register tmp
2464 pk = registerRep register
2465 sz = primRepToSize pk
2466 words = if pk == DoubleRep then 2 else 1
2468 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2470 #endif {- sparc_TARGET_ARCH -}
2473 %************************************************************************
2475 \subsection{Support bits}
2477 %************************************************************************
2479 %************************************************************************
2481 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2483 %************************************************************************
2485 Turn those condition codes into integers now (when they appear on
2486 the right hand side of an assignment).
2488 (If applicable) Do not fill the delay slots here; you will confuse the
2492 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2494 #if alpha_TARGET_ARCH
2495 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2496 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2497 #endif {- alpha_TARGET_ARCH -}
2499 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2500 #if i386_TARGET_ARCH
2503 = condIntCode cond x y `thenUs` \ condition ->
2504 getNewRegNCG IntRep `thenUs` \ tmp ->
2505 --getRegister dst `thenUs` \ register ->
2507 --code2 = registerCode register tmp asmVoid
2508 --dst__2 = registerName register tmp
2509 code = condCode condition
2510 cond = condName condition
2511 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2512 code__2 dst = code . mkSeqInstrs [COMMENT (_PK_ "aaaaa"),
2513 SETCC cond (OpReg tmp),
2514 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2515 MOV L (OpReg tmp) (OpReg dst) ,COMMENT (_PK_ "bbbbb")]
2517 returnUs (Any IntRep code__2)
2520 = getUniqLabelNCG `thenUs` \ lbl1 ->
2521 getUniqLabelNCG `thenUs` \ lbl2 ->
2522 condFltCode cond x y `thenUs` \ condition ->
2524 code = condCode condition
2525 cond = condName condition
2526 code__2 dst = code . mkSeqInstrs [
2528 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2531 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2534 returnUs (Any IntRep code__2)
2536 #endif {- i386_TARGET_ARCH -}
2537 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2538 #if sparc_TARGET_ARCH
2540 condIntReg EQQ x (StInt 0)
2541 = getRegister x `thenUs` \ register ->
2542 getNewRegNCG IntRep `thenUs` \ tmp ->
2544 code = registerCode register tmp
2545 src = registerName register tmp
2546 code__2 dst = code . mkSeqInstrs [
2547 SUB False True g0 (RIReg src) g0,
2548 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2550 returnUs (Any IntRep code__2)
2553 = getRegister x `thenUs` \ register1 ->
2554 getRegister y `thenUs` \ register2 ->
2555 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2556 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2558 code1 = registerCode register1 tmp1 asmVoid
2559 src1 = registerName register1 tmp1
2560 code2 = registerCode register2 tmp2 asmVoid
2561 src2 = registerName register2 tmp2
2562 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2563 XOR False src1 (RIReg src2) dst,
2564 SUB False True g0 (RIReg dst) g0,
2565 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2567 returnUs (Any IntRep code__2)
2569 condIntReg NE x (StInt 0)
2570 = getRegister x `thenUs` \ register ->
2571 getNewRegNCG IntRep `thenUs` \ tmp ->
2573 code = registerCode register tmp
2574 src = registerName register tmp
2575 code__2 dst = code . mkSeqInstrs [
2576 SUB False True g0 (RIReg src) g0,
2577 ADD True False g0 (RIImm (ImmInt 0)) dst]
2579 returnUs (Any IntRep code__2)
2582 = getRegister x `thenUs` \ register1 ->
2583 getRegister y `thenUs` \ register2 ->
2584 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2585 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2587 code1 = registerCode register1 tmp1 asmVoid
2588 src1 = registerName register1 tmp1
2589 code2 = registerCode register2 tmp2 asmVoid
2590 src2 = registerName register2 tmp2
2591 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2592 XOR False src1 (RIReg src2) dst,
2593 SUB False True g0 (RIReg dst) g0,
2594 ADD True False g0 (RIImm (ImmInt 0)) dst]
2596 returnUs (Any IntRep code__2)
2599 = getUniqLabelNCG `thenUs` \ lbl1 ->
2600 getUniqLabelNCG `thenUs` \ lbl2 ->
2601 condIntCode cond x y `thenUs` \ condition ->
2603 code = condCode condition
2604 cond = condName condition
2605 code__2 dst = code . mkSeqInstrs [
2606 BI cond False (ImmCLbl lbl1), NOP,
2607 OR False g0 (RIImm (ImmInt 0)) dst,
2608 BI ALWAYS False (ImmCLbl lbl2), NOP,
2610 OR False g0 (RIImm (ImmInt 1)) dst,
2613 returnUs (Any IntRep code__2)
2616 = getUniqLabelNCG `thenUs` \ lbl1 ->
2617 getUniqLabelNCG `thenUs` \ lbl2 ->
2618 condFltCode cond x y `thenUs` \ condition ->
2620 code = condCode condition
2621 cond = condName condition
2622 code__2 dst = code . mkSeqInstrs [
2624 BF cond False (ImmCLbl lbl1), NOP,
2625 OR False g0 (RIImm (ImmInt 0)) dst,
2626 BI ALWAYS False (ImmCLbl lbl2), NOP,
2628 OR False g0 (RIImm (ImmInt 1)) dst,
2631 returnUs (Any IntRep code__2)
2633 #endif {- sparc_TARGET_ARCH -}
2636 %************************************************************************
2638 \subsubsection{@trivial*Code@: deal with trivial instructions}
2640 %************************************************************************
2642 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2643 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2644 for constants on the right hand side, because that's where the generic
2645 optimizer will have put them.
2647 Similarly, for unary instructions, we don't have to worry about
2648 matching an StInt as the argument, because genericOpt will already
2649 have handled the constant-folding.
2653 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2654 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2655 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2657 -> StixTree -> StixTree -- the two arguments
2662 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2663 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2664 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2666 -> StixTree -> StixTree -- the two arguments
2670 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2671 ,IF_ARCH_i386 ((Operand -> Instr)
2672 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2674 -> StixTree -- the one argument
2679 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2680 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2681 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2683 -> StixTree -- the one argument
2686 #if alpha_TARGET_ARCH
2688 trivialCode instr x (StInt y)
2690 = getRegister x `thenUs` \ register ->
2691 getNewRegNCG IntRep `thenUs` \ tmp ->
2693 code = registerCode register tmp
2694 src1 = registerName register tmp
2695 src2 = ImmInt (fromInteger y)
2696 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2698 returnUs (Any IntRep code__2)
2700 trivialCode instr x y
2701 = getRegister x `thenUs` \ register1 ->
2702 getRegister y `thenUs` \ register2 ->
2703 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2704 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2706 code1 = registerCode register1 tmp1 asmVoid
2707 src1 = registerName register1 tmp1
2708 code2 = registerCode register2 tmp2 asmVoid
2709 src2 = registerName register2 tmp2
2710 code__2 dst = asmParThen [code1, code2] .
2711 mkSeqInstr (instr src1 (RIReg src2) dst)
2713 returnUs (Any IntRep code__2)
2716 trivialUCode instr x
2717 = getRegister x `thenUs` \ register ->
2718 getNewRegNCG IntRep `thenUs` \ tmp ->
2720 code = registerCode register tmp
2721 src = registerName register tmp
2722 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2724 returnUs (Any IntRep code__2)
2727 trivialFCode _ instr x y
2728 = getRegister x `thenUs` \ register1 ->
2729 getRegister y `thenUs` \ register2 ->
2730 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2731 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2733 code1 = registerCode register1 tmp1
2734 src1 = registerName register1 tmp1
2736 code2 = registerCode register2 tmp2
2737 src2 = registerName register2 tmp2
2739 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2740 mkSeqInstr (instr src1 src2 dst)
2742 returnUs (Any DoubleRep code__2)
2744 trivialUFCode _ instr x
2745 = getRegister x `thenUs` \ register ->
2746 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2748 code = registerCode register tmp
2749 src = registerName register tmp
2750 code__2 dst = code . mkSeqInstr (instr src dst)
2752 returnUs (Any DoubleRep code__2)
2754 #endif {- alpha_TARGET_ARCH -}
2755 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2756 #if i386_TARGET_ARCH
2758 trivialCode instr x y
2760 = getRegister x `thenUs` \ register1 ->
2762 code__2 dst = let code1 = registerCode register1 dst
2763 src1 = registerName register1 dst
2765 if isFixed register1 && src1 /= dst
2766 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2767 instr (OpImm imm__2) (OpReg dst)]
2769 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2771 returnUs (Any IntRep code__2)
2774 imm__2 = case imm of Just x -> x
2776 trivialCode instr x y
2777 = getRegister x `thenUs` \ register1 ->
2778 getRegister y `thenUs` \ register2 ->
2779 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2781 code2 = registerCode register2 tmp2 asmVoid
2782 src2 = registerName register2 tmp2
2784 code1 = registerCode register1 dst asmVoid
2785 src1 = registerName register1 dst
2786 in asmParThen [code1, code2] .
2787 if isFixed register1 && src1 /= dst
2788 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2789 instr (OpReg src2) (OpReg dst)]
2791 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2793 returnUs (Any IntRep code__2)
2796 trivialUCode instr x
2797 = getRegister x `thenUs` \ register ->
2800 code = registerCode register dst
2801 src = registerName register dst
2802 in code . if isFixed register && dst /= src
2803 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2805 else mkSeqInstr (instr (OpReg src))
2807 returnUs (Any IntRep code__2)
2810 trivialFCode pk instr x y
2811 = getRegister x `thenUs` \ register1 ->
2812 getRegister y `thenUs` \ register2 ->
2813 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2814 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2816 code1 = registerCode register1 tmp1
2817 src1 = registerName register1 tmp1
2819 code2 = registerCode register2 tmp2
2820 src2 = registerName register2 tmp2
2822 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2823 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2825 returnUs (Any DoubleRep code__2)
2829 trivialUFCode pk instr x
2830 = getRegister x `thenUs` \ register ->
2831 getNewRegNCG pk `thenUs` \ tmp ->
2833 code = registerCode register tmp
2834 src = registerName register tmp
2835 code__2 dst = code . mkSeqInstr (instr src dst)
2837 returnUs (Any pk code__2)
2839 #endif {- i386_TARGET_ARCH -}
2840 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2841 #if sparc_TARGET_ARCH
2843 trivialCode instr x (StInt y)
2845 = getRegister x `thenUs` \ register ->
2846 getNewRegNCG IntRep `thenUs` \ tmp ->
2848 code = registerCode register tmp
2849 src1 = registerName register tmp
2850 src2 = ImmInt (fromInteger y)
2851 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2853 returnUs (Any IntRep code__2)
2855 trivialCode instr x y
2856 = getRegister x `thenUs` \ register1 ->
2857 getRegister y `thenUs` \ register2 ->
2858 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2859 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2861 code1 = registerCode register1 tmp1 asmVoid
2862 src1 = registerName register1 tmp1
2863 code2 = registerCode register2 tmp2 asmVoid
2864 src2 = registerName register2 tmp2
2865 code__2 dst = asmParThen [code1, code2] .
2866 mkSeqInstr (instr src1 (RIReg src2) dst)
2868 returnUs (Any IntRep code__2)
2871 trivialFCode pk instr x y
2872 = getRegister x `thenUs` \ register1 ->
2873 getRegister y `thenUs` \ register2 ->
2874 getNewRegNCG (registerRep register1)
2876 getNewRegNCG (registerRep register2)
2878 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2880 promote x = asmInstr (FxTOy F DF x tmp)
2882 pk1 = registerRep register1
2883 code1 = registerCode register1 tmp1
2884 src1 = registerName register1 tmp1
2886 pk2 = registerRep register2
2887 code2 = registerCode register2 tmp2
2888 src2 = registerName register2 tmp2
2892 asmParThen [code1 asmVoid, code2 asmVoid] .
2893 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2894 else if pk1 == FloatRep then
2895 asmParThen [code1 (promote src1), code2 asmVoid] .
2896 mkSeqInstr (instr DF tmp src2 dst)
2898 asmParThen [code1 asmVoid, code2 (promote src2)] .
2899 mkSeqInstr (instr DF src1 tmp dst)
2901 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2904 trivialUCode instr x
2905 = getRegister x `thenUs` \ register ->
2906 getNewRegNCG IntRep `thenUs` \ tmp ->
2908 code = registerCode register tmp
2909 src = registerName register tmp
2910 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2912 returnUs (Any IntRep code__2)
2915 trivialUFCode pk instr x
2916 = getRegister x `thenUs` \ register ->
2917 getNewRegNCG pk `thenUs` \ tmp ->
2919 code = registerCode register tmp
2920 src = registerName register tmp
2921 code__2 dst = code . mkSeqInstr (instr src dst)
2923 returnUs (Any pk code__2)
2925 #endif {- sparc_TARGET_ARCH -}
2928 %************************************************************************
2930 \subsubsection{Coercing to/from integer/floating-point...}
2932 %************************************************************************
2934 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
2935 to be generated. Here we just change the type on the Register passed
2936 on up. The code is machine-independent.
2938 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
2939 conversions. We have to store temporaries in memory to move
2940 between the integer and the floating point register sets.
2943 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
2944 coerceFltCode :: StixTree -> UniqSM Register
2946 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
2947 coerceFP2Int :: StixTree -> UniqSM Register
2950 = getRegister x `thenUs` \ register ->
2953 Fixed _ reg code -> Fixed pk reg code
2954 Any _ code -> Any pk code
2959 = getRegister x `thenUs` \ register ->
2962 Fixed _ reg code -> Fixed DoubleRep reg code
2963 Any _ code -> Any DoubleRep code
2968 #if alpha_TARGET_ARCH
2971 = getRegister x `thenUs` \ register ->
2972 getNewRegNCG IntRep `thenUs` \ reg ->
2974 code = registerCode register reg
2975 src = registerName register reg
2977 code__2 dst = code . mkSeqInstrs [
2979 LD TF dst (spRel 0),
2982 returnUs (Any DoubleRep code__2)
2986 = getRegister x `thenUs` \ register ->
2987 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2989 code = registerCode register tmp
2990 src = registerName register tmp
2992 code__2 dst = code . mkSeqInstrs [
2994 ST TF tmp (spRel 0),
2997 returnUs (Any IntRep code__2)
2999 #endif {- alpha_TARGET_ARCH -}
3000 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3001 #if i386_TARGET_ARCH
3004 = getRegister x `thenUs` \ register ->
3005 getNewRegNCG IntRep `thenUs` \ reg ->
3007 code = registerCode register reg
3008 src = registerName register reg
3009 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
3010 code__2 dst = code .
3011 mkSeqInstr (opc src dst)
3013 returnUs (Any pk code__2)
3017 = getRegister x `thenUs` \ register ->
3018 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3020 code = registerCode register tmp
3021 src = registerName register tmp
3022 pk = registerRep register
3024 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3025 code__2 dst = code .
3026 mkSeqInstr (opc src dst)
3028 returnUs (Any IntRep code__2)
3030 #endif {- i386_TARGET_ARCH -}
3031 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3032 #if sparc_TARGET_ARCH
3035 = getRegister x `thenUs` \ register ->
3036 getNewRegNCG IntRep `thenUs` \ reg ->
3038 code = registerCode register reg
3039 src = registerName register reg
3041 code__2 dst = code . mkSeqInstrs [
3042 ST W src (spRel (-2)),
3043 LD W (spRel (-2)) dst,
3044 FxTOy W (primRepToSize pk) dst dst]
3046 returnUs (Any pk code__2)
3050 = getRegister x `thenUs` \ register ->
3051 getNewRegNCG IntRep `thenUs` \ reg ->
3052 getNewRegNCG FloatRep `thenUs` \ tmp ->
3054 code = registerCode register reg
3055 src = registerName register reg
3056 pk = registerRep register
3058 code__2 dst = code . mkSeqInstrs [
3059 FxTOy (primRepToSize pk) W src tmp,
3060 ST W tmp (spRel (-2)),
3061 LD W (spRel (-2)) dst]
3063 returnUs (Any IntRep code__2)
3065 #endif {- sparc_TARGET_ARCH -}
3068 %************************************************************************
3070 \subsubsection{Coercing integer to @Char@...}
3072 %************************************************************************
3074 Integer to character conversion. Where applicable, we try to do this
3075 in one step if the original object is in memory.
3078 chrCode :: StixTree -> UniqSM Register
3080 #if alpha_TARGET_ARCH
3083 = getRegister x `thenUs` \ register ->
3084 getNewRegNCG IntRep `thenUs` \ reg ->
3086 code = registerCode register reg
3087 src = registerName register reg
3088 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3090 returnUs (Any IntRep code__2)
3092 #endif {- alpha_TARGET_ARCH -}
3093 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3094 #if i386_TARGET_ARCH
3097 = getRegister x `thenUs` \ register ->
3100 code = registerCode register dst
3101 src = registerName register dst
3103 if isFixed register && src /= dst
3104 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3105 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3106 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3108 returnUs (Any IntRep code__2)
3110 #endif {- i386_TARGET_ARCH -}
3111 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3112 #if sparc_TARGET_ARCH
3114 chrCode (StInd pk mem)
3115 = getAmode mem `thenUs` \ amode ->
3117 code = amodeCode amode
3118 src = amodeAddr amode
3119 src_off = addrOffset src 3
3120 src__2 = case src_off of Just x -> x
3121 code__2 dst = if maybeToBool src_off then
3122 code . mkSeqInstr (LD BU src__2 dst)
3124 code . mkSeqInstrs [
3125 LD (primRepToSize pk) src dst,
3126 AND False dst (RIImm (ImmInt 255)) dst]
3128 returnUs (Any pk code__2)
3131 = getRegister x `thenUs` \ register ->
3132 getNewRegNCG IntRep `thenUs` \ reg ->
3134 code = registerCode register reg
3135 src = registerName register reg
3136 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3138 returnUs (Any IntRep code__2)
3140 #endif {- sparc_TARGET_ARCH -}