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-}
636 ISllOp -> shift_code (SHL L) x y {-False-}
637 ISraOp -> shift_code (SAR L) x y {-False-}
638 ISrlOp -> shift_code (SHR L) x y {-False-}
640 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
641 [promote x, promote y])
642 where promote x = StPrim Float2DoubleOp [x]
643 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
646 -> pprPanic "getRegister(x86,dyadic primop)"
647 (pprStixTrees [StPrim primop [x, y]])
651 shift_code :: (Imm -> Operand -> Instr)
656 {- Case1: shift length as immediate -}
657 -- Code is the same as the first eq. for trivialCode -- sigh.
658 shift_code instr x y{-amount-}
660 = getRegister x `thenUs` \ register ->
661 let op_imm = OpImm imm__2
663 let code = registerCode register dst
664 src = registerName register dst
667 if isFixed register && src /= dst
668 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
669 instr imm__2 (OpReg dst)]
670 else mkSeqInstr (instr imm__2 (OpReg src))
672 returnUs (Any IntRep code__2)
675 imm__2 = case imm of Just x -> x
677 {- Case2: shift length is complex (non-immediate) -}
678 -- Since ECX is always used as a spill temporary, we can't
679 -- use it here to do non-immediate shifts. No big deal --
680 -- they are only very rare, and we can use an equivalent
681 -- test-and-jump sequence which doesn't use ECX.
682 -- DO NOT USE REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
683 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
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 (ImmInt 16) r_dst,
713 BT L (ImmInt 3) r_tmp,
715 instr (ImmInt 8) r_dst,
718 BT L (ImmInt 2) r_tmp,
720 instr (ImmInt 4) r_dst,
723 BT L (ImmInt 1) r_tmp,
725 instr (ImmInt 2) r_dst,
728 BT L (ImmInt 0) r_tmp,
730 instr (ImmInt 1) r_dst,
733 COMMENT (_PK_ "end shift sequence")
736 returnUs (Any IntRep code__2)
739 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
741 add_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)
756 = getRegister x `thenUs` \ register1 ->
757 getRegister y `thenUs` \ register2 ->
758 getNewRegNCG IntRep `thenUs` \ tmp1 ->
759 getNewRegNCG IntRep `thenUs` \ tmp2 ->
761 code1 = registerCode register1 tmp1 asmVoid
762 src1 = registerName register1 tmp1
763 code2 = registerCode register2 tmp2 asmVoid
764 src2 = registerName register2 tmp2
766 = asmParThen [code1, code2] .
767 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1))
771 returnUs (Any IntRep code__2)
774 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
776 sub_code sz x (StInt y)
777 = getRegister x `thenUs` \ register ->
778 getNewRegNCG IntRep `thenUs` \ tmp ->
780 code = registerCode register tmp
781 src1 = registerName register tmp
782 src2 = ImmInt (-(fromInteger y))
785 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
788 returnUs (Any IntRep code__2)
790 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
795 -> StixTree -> StixTree
796 -> Bool -- True => division, False => remainder operation
799 -- x must go into eax, edx must be a sign-extension of eax, and y
800 -- should go in some other register (or memory), so that we get
801 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
802 -- put y in memory (if it is not there already)
804 quot_code sz x (StInd pk mem) is_division
805 = getRegister x `thenUs` \ register1 ->
806 getNewRegNCG IntRep `thenUs` \ tmp1 ->
807 getAmode mem `thenUs` \ amode ->
809 code1 = registerCode register1 tmp1 asmVoid
810 src1 = registerName register1 tmp1
811 code2 = amodeCode amode asmVoid
812 src2 = amodeAddr amode
813 code__2 = asmParThen [code1, code2] .
814 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
816 IDIV sz (OpAddr src2)]
818 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
820 quot_code sz x (StInt i) is_division
821 = getRegister x `thenUs` \ register1 ->
822 getNewRegNCG IntRep `thenUs` \ tmp1 ->
824 code1 = registerCode register1 tmp1 asmVoid
825 src1 = registerName register1 tmp1
826 src2 = ImmInt (fromInteger i)
827 code__2 = asmParThen [code1] .
828 mkSeqInstrs [-- we put src2 in (ebx)
830 (OpAddr (AddrBaseIndex (Just ebx) Nothing
831 (ImmInt OFFSET_R1))),
832 MOV L (OpReg src1) (OpReg eax),
834 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
838 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
840 quot_code sz x y is_division
841 = getRegister x `thenUs` \ register1 ->
842 getNewRegNCG IntRep `thenUs` \ tmp1 ->
843 getRegister y `thenUs` \ register2 ->
844 getNewRegNCG IntRep `thenUs` \ tmp2 ->
846 code1 = registerCode register1 tmp1 asmVoid
847 src1 = registerName register1 tmp1
848 code2 = registerCode register2 tmp2 asmVoid
849 src2 = registerName register2 tmp2
850 code__2 = asmParThen [code1, code2] .
851 if src2 == ecx || src2 == esi
853 MOV L (OpReg src1) (OpReg eax),
857 else mkSeqInstrs [ -- we put src2 in (ebx)
859 (OpAddr (AddrBaseIndex (Just ebx) Nothing
860 (ImmInt OFFSET_R1))),
861 MOV L (OpReg src1) (OpReg eax),
863 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
867 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
868 -----------------------
870 getRegister (StInd pk mem)
871 = getAmode mem `thenUs` \ amode ->
873 code = amodeCode amode
874 src = amodeAddr amode
875 size = primRepToSize pk
877 if pk == DoubleRep || pk == FloatRep
878 then mkSeqInstr (GLD size src dst)
879 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
881 returnUs (Any pk code__2)
883 getRegister (StInt i)
885 src = ImmInt (fromInteger i)
886 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
888 returnUs (Any IntRep code)
893 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
895 returnUs (Any PtrRep code)
897 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
900 imm__2 = case imm of Just x -> x
902 #endif {- i386_TARGET_ARCH -}
903 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
904 #if sparc_TARGET_ARCH
906 getRegister (StDouble d)
907 = getUniqLabelNCG `thenUs` \ lbl ->
908 getNewRegNCG PtrRep `thenUs` \ tmp ->
909 let code dst = mkSeqInstrs [
912 DATA DF [ImmDouble d],
914 SETHI (HI (ImmCLbl lbl)) tmp,
915 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
917 returnUs (Any DoubleRep code)
919 getRegister (StPrim primop [x]) -- unary PrimOps
921 IntNegOp -> trivialUCode (SUB False False g0) x
922 NotOp -> trivialUCode (XNOR False g0) x
924 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
926 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
928 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
929 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
931 OrdOp -> coerceIntCode IntRep x
934 Float2IntOp -> coerceFP2Int x
935 Int2FloatOp -> coerceInt2FP FloatRep x
936 Double2IntOp -> coerceFP2Int x
937 Int2DoubleOp -> coerceInt2FP DoubleRep x
941 fixed_x = if is_float_op -- promote to double
942 then StPrim Float2DoubleOp [x]
945 getRegister (StCall fn cCallConv DoubleRep [x])
949 FloatExpOp -> (True, SLIT("exp"))
950 FloatLogOp -> (True, SLIT("log"))
951 FloatSqrtOp -> (True, SLIT("sqrt"))
953 FloatSinOp -> (True, SLIT("sin"))
954 FloatCosOp -> (True, SLIT("cos"))
955 FloatTanOp -> (True, SLIT("tan"))
957 FloatAsinOp -> (True, SLIT("asin"))
958 FloatAcosOp -> (True, SLIT("acos"))
959 FloatAtanOp -> (True, SLIT("atan"))
961 FloatSinhOp -> (True, SLIT("sinh"))
962 FloatCoshOp -> (True, SLIT("cosh"))
963 FloatTanhOp -> (True, SLIT("tanh"))
965 DoubleExpOp -> (False, SLIT("exp"))
966 DoubleLogOp -> (False, SLIT("log"))
967 DoubleSqrtOp -> (True, SLIT("sqrt"))
969 DoubleSinOp -> (False, SLIT("sin"))
970 DoubleCosOp -> (False, SLIT("cos"))
971 DoubleTanOp -> (False, SLIT("tan"))
973 DoubleAsinOp -> (False, SLIT("asin"))
974 DoubleAcosOp -> (False, SLIT("acos"))
975 DoubleAtanOp -> (False, SLIT("atan"))
977 DoubleSinhOp -> (False, SLIT("sinh"))
978 DoubleCoshOp -> (False, SLIT("cosh"))
979 DoubleTanhOp -> (False, SLIT("tanh"))
980 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
982 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
984 CharGtOp -> condIntReg GTT x y
985 CharGeOp -> condIntReg GE x y
986 CharEqOp -> condIntReg EQQ x y
987 CharNeOp -> condIntReg NE x y
988 CharLtOp -> condIntReg LTT x y
989 CharLeOp -> condIntReg LE x y
991 IntGtOp -> condIntReg GTT x y
992 IntGeOp -> condIntReg GE x y
993 IntEqOp -> condIntReg EQQ x y
994 IntNeOp -> condIntReg NE x y
995 IntLtOp -> condIntReg LTT x y
996 IntLeOp -> condIntReg LE x y
998 WordGtOp -> condIntReg GU x y
999 WordGeOp -> condIntReg GEU x y
1000 WordEqOp -> condIntReg EQQ x y
1001 WordNeOp -> condIntReg NE x y
1002 WordLtOp -> condIntReg LU x y
1003 WordLeOp -> condIntReg LEU x y
1005 AddrGtOp -> condIntReg GU x y
1006 AddrGeOp -> condIntReg GEU x y
1007 AddrEqOp -> condIntReg EQQ x y
1008 AddrNeOp -> condIntReg NE x y
1009 AddrLtOp -> condIntReg LU x y
1010 AddrLeOp -> condIntReg LEU x y
1012 FloatGtOp -> condFltReg GTT x y
1013 FloatGeOp -> condFltReg GE x y
1014 FloatEqOp -> condFltReg EQQ x y
1015 FloatNeOp -> condFltReg NE x y
1016 FloatLtOp -> condFltReg LTT x y
1017 FloatLeOp -> condFltReg LE x y
1019 DoubleGtOp -> condFltReg GTT x y
1020 DoubleGeOp -> condFltReg GE x y
1021 DoubleEqOp -> condFltReg EQQ x y
1022 DoubleNeOp -> condFltReg NE x y
1023 DoubleLtOp -> condFltReg LTT x y
1024 DoubleLeOp -> condFltReg LE x y
1026 IntAddOp -> trivialCode (ADD False False) x y
1027 IntSubOp -> trivialCode (SUB False False) x y
1029 -- ToDo: teach about V8+ SPARC mul/div instructions
1030 IntMulOp -> imul_div SLIT(".umul") x y
1031 IntQuotOp -> imul_div SLIT(".div") x y
1032 IntRemOp -> imul_div SLIT(".rem") x y
1034 FloatAddOp -> trivialFCode FloatRep FADD x y
1035 FloatSubOp -> trivialFCode FloatRep FSUB x y
1036 FloatMulOp -> trivialFCode FloatRep FMUL x y
1037 FloatDivOp -> trivialFCode FloatRep FDIV x y
1039 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1040 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1041 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1042 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1044 AndOp -> trivialCode (AND False) x y
1045 OrOp -> trivialCode (OR False) x y
1046 XorOp -> trivialCode (XOR False) x y
1047 SllOp -> trivialCode SLL x y
1048 SrlOp -> trivialCode SRL x y
1050 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1051 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1052 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1054 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1055 where promote x = StPrim Float2DoubleOp [x]
1056 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1057 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1059 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1061 getRegister (StInd pk mem)
1062 = getAmode mem `thenUs` \ amode ->
1064 code = amodeCode amode
1065 src = amodeAddr amode
1066 size = primRepToSize pk
1067 code__2 dst = code . mkSeqInstr (LD size src dst)
1069 returnUs (Any pk code__2)
1071 getRegister (StInt i)
1074 src = ImmInt (fromInteger i)
1075 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1077 returnUs (Any IntRep code)
1082 code dst = mkSeqInstrs [
1083 SETHI (HI imm__2) dst,
1084 OR False dst (RIImm (LO imm__2)) dst]
1086 returnUs (Any PtrRep code)
1089 imm__2 = case imm of Just x -> x
1091 #endif {- sparc_TARGET_ARCH -}
1094 %************************************************************************
1096 \subsection{The @Amode@ type}
1098 %************************************************************************
1100 @Amode@s: Memory addressing modes passed up the tree.
1102 data Amode = Amode MachRegsAddr InstrBlock
1104 amodeAddr (Amode addr _) = addr
1105 amodeCode (Amode _ code) = code
1108 Now, given a tree (the argument to an StInd) that references memory,
1109 produce a suitable addressing mode.
1112 getAmode :: StixTree -> UniqSM Amode
1114 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1116 #if alpha_TARGET_ARCH
1118 getAmode (StPrim IntSubOp [x, StInt i])
1119 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1120 getRegister x `thenUs` \ register ->
1122 code = registerCode register tmp
1123 reg = registerName register tmp
1124 off = ImmInt (-(fromInteger i))
1126 returnUs (Amode (AddrRegImm reg off) code)
1128 getAmode (StPrim IntAddOp [x, StInt i])
1129 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1130 getRegister x `thenUs` \ register ->
1132 code = registerCode register tmp
1133 reg = registerName register tmp
1134 off = ImmInt (fromInteger i)
1136 returnUs (Amode (AddrRegImm reg off) code)
1140 = returnUs (Amode (AddrImm imm__2) id)
1143 imm__2 = case imm of Just x -> x
1146 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1147 getRegister other `thenUs` \ register ->
1149 code = registerCode register tmp
1150 reg = registerName register tmp
1152 returnUs (Amode (AddrReg reg) code)
1154 #endif {- alpha_TARGET_ARCH -}
1155 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1156 #if i386_TARGET_ARCH
1158 getAmode (StPrim IntSubOp [x, StInt i])
1159 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1160 getRegister x `thenUs` \ register ->
1162 code = registerCode register tmp
1163 reg = registerName register tmp
1164 off = ImmInt (-(fromInteger i))
1166 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1168 getAmode (StPrim IntAddOp [x, StInt i])
1171 code = mkSeqInstrs []
1173 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1176 imm__2 = case imm of Just x -> x
1178 getAmode (StPrim IntAddOp [x, StInt i])
1179 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1180 getRegister x `thenUs` \ register ->
1182 code = registerCode register tmp
1183 reg = registerName register tmp
1184 off = ImmInt (fromInteger i)
1186 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1188 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1189 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1190 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1191 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1192 getRegister x `thenUs` \ register1 ->
1193 getRegister y `thenUs` \ register2 ->
1195 code1 = registerCode register1 tmp1 asmVoid
1196 reg1 = registerName register1 tmp1
1197 code2 = registerCode register2 tmp2 asmVoid
1198 reg2 = registerName register2 tmp2
1199 code__2 = asmParThen [code1, code2]
1200 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1202 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1208 code = mkSeqInstrs []
1210 returnUs (Amode (ImmAddr imm__2 0) code)
1213 imm__2 = case imm of Just x -> x
1216 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1217 getRegister other `thenUs` \ register ->
1219 code = registerCode register tmp
1220 reg = registerName register tmp
1223 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1225 #endif {- i386_TARGET_ARCH -}
1226 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1227 #if sparc_TARGET_ARCH
1229 getAmode (StPrim IntSubOp [x, StInt i])
1231 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1232 getRegister x `thenUs` \ register ->
1234 code = registerCode register tmp
1235 reg = registerName register tmp
1236 off = ImmInt (-(fromInteger i))
1238 returnUs (Amode (AddrRegImm reg off) code)
1241 getAmode (StPrim IntAddOp [x, StInt i])
1243 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1244 getRegister x `thenUs` \ register ->
1246 code = registerCode register tmp
1247 reg = registerName register tmp
1248 off = ImmInt (fromInteger i)
1250 returnUs (Amode (AddrRegImm reg off) code)
1252 getAmode (StPrim IntAddOp [x, y])
1253 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1254 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1255 getRegister x `thenUs` \ register1 ->
1256 getRegister y `thenUs` \ register2 ->
1258 code1 = registerCode register1 tmp1 asmVoid
1259 reg1 = registerName register1 tmp1
1260 code2 = registerCode register2 tmp2 asmVoid
1261 reg2 = registerName register2 tmp2
1262 code__2 = asmParThen [code1, code2]
1264 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1268 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1270 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1272 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1275 imm__2 = case imm of Just x -> x
1278 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1279 getRegister other `thenUs` \ register ->
1281 code = registerCode register tmp
1282 reg = registerName register tmp
1285 returnUs (Amode (AddrRegImm reg off) code)
1287 #endif {- sparc_TARGET_ARCH -}
1290 %************************************************************************
1292 \subsection{The @CondCode@ type}
1294 %************************************************************************
1296 Condition codes passed up the tree.
1298 data CondCode = CondCode Bool Cond InstrBlock
1300 condName (CondCode _ cond _) = cond
1301 condFloat (CondCode is_float _ _) = is_float
1302 condCode (CondCode _ _ code) = code
1305 Set up a condition code for a conditional branch.
1308 getCondCode :: StixTree -> UniqSM CondCode
1310 #if alpha_TARGET_ARCH
1311 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1312 #endif {- alpha_TARGET_ARCH -}
1313 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1315 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1316 -- yes, they really do seem to want exactly the same!
1318 getCondCode (StPrim primop [x, y])
1320 CharGtOp -> condIntCode GTT x y
1321 CharGeOp -> condIntCode GE x y
1322 CharEqOp -> condIntCode EQQ x y
1323 CharNeOp -> condIntCode NE x y
1324 CharLtOp -> condIntCode LTT x y
1325 CharLeOp -> condIntCode LE x y
1327 IntGtOp -> condIntCode GTT x y
1328 IntGeOp -> condIntCode GE x y
1329 IntEqOp -> condIntCode EQQ x y
1330 IntNeOp -> condIntCode NE x y
1331 IntLtOp -> condIntCode LTT x y
1332 IntLeOp -> condIntCode LE x y
1334 WordGtOp -> condIntCode GU x y
1335 WordGeOp -> condIntCode GEU x y
1336 WordEqOp -> condIntCode EQQ x y
1337 WordNeOp -> condIntCode NE x y
1338 WordLtOp -> condIntCode LU x y
1339 WordLeOp -> condIntCode LEU x y
1341 AddrGtOp -> condIntCode GU x y
1342 AddrGeOp -> condIntCode GEU x y
1343 AddrEqOp -> condIntCode EQQ x y
1344 AddrNeOp -> condIntCode NE x y
1345 AddrLtOp -> condIntCode LU x y
1346 AddrLeOp -> condIntCode LEU x y
1348 FloatGtOp -> condFltCode GTT x y
1349 FloatGeOp -> condFltCode GE x y
1350 FloatEqOp -> condFltCode EQQ x y
1351 FloatNeOp -> condFltCode NE x y
1352 FloatLtOp -> condFltCode LTT x y
1353 FloatLeOp -> condFltCode LE x y
1355 DoubleGtOp -> condFltCode GTT x y
1356 DoubleGeOp -> condFltCode GE x y
1357 DoubleEqOp -> condFltCode EQQ x y
1358 DoubleNeOp -> condFltCode NE x y
1359 DoubleLtOp -> condFltCode LTT x y
1360 DoubleLeOp -> condFltCode LE x y
1362 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1367 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1368 passed back up the tree.
1371 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1373 #if alpha_TARGET_ARCH
1374 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1375 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1376 #endif {- alpha_TARGET_ARCH -}
1378 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1379 #if i386_TARGET_ARCH
1381 condIntCode cond (StInd _ x) y
1383 = getAmode x `thenUs` \ amode ->
1385 code1 = amodeCode amode asmVoid
1386 y__2 = amodeAddr amode
1387 code__2 = asmParThen [code1] .
1388 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1390 returnUs (CondCode False cond code__2)
1393 imm__2 = case imm of Just x -> x
1395 condIntCode cond x (StInt 0)
1396 = getRegister x `thenUs` \ register1 ->
1397 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1399 code1 = registerCode register1 tmp1 asmVoid
1400 src1 = registerName register1 tmp1
1401 code__2 = asmParThen [code1] .
1402 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1404 returnUs (CondCode False cond code__2)
1406 condIntCode cond x y
1408 = getRegister x `thenUs` \ register1 ->
1409 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1411 code1 = registerCode register1 tmp1 asmVoid
1412 src1 = registerName register1 tmp1
1413 code__2 = asmParThen [code1] .
1414 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1416 returnUs (CondCode False cond code__2)
1419 imm__2 = case imm of Just x -> x
1421 condIntCode cond (StInd _ x) y
1422 = getAmode x `thenUs` \ amode ->
1423 getRegister y `thenUs` \ register2 ->
1424 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1426 code1 = amodeCode amode asmVoid
1427 src1 = amodeAddr amode
1428 code2 = registerCode register2 tmp2 asmVoid
1429 src2 = registerName register2 tmp2
1430 code__2 = asmParThen [code1, code2] .
1431 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1433 returnUs (CondCode False cond code__2)
1435 condIntCode cond y (StInd _ x)
1436 = getAmode x `thenUs` \ amode ->
1437 getRegister y `thenUs` \ register2 ->
1438 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1440 code1 = amodeCode amode asmVoid
1441 src1 = amodeAddr amode
1442 code2 = registerCode register2 tmp2 asmVoid
1443 src2 = registerName register2 tmp2
1444 code__2 = asmParThen [code1, code2] .
1445 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1447 returnUs (CondCode False cond code__2)
1449 condIntCode cond x y
1450 = getRegister x `thenUs` \ register1 ->
1451 getRegister y `thenUs` \ register2 ->
1452 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1453 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1455 code1 = registerCode register1 tmp1 asmVoid
1456 src1 = registerName register1 tmp1
1457 code2 = registerCode register2 tmp2 asmVoid
1458 src2 = registerName register2 tmp2
1459 code__2 = asmParThen [code1, code2] .
1460 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1462 returnUs (CondCode False cond code__2)
1465 condFltCode cond x y
1466 = getRegister x `thenUs` \ register1 ->
1467 getRegister y `thenUs` \ register2 ->
1468 getNewRegNCG (registerRep register1)
1470 getNewRegNCG (registerRep register2)
1472 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1474 pk1 = registerRep register1
1475 code1 = registerCode register1 tmp1
1476 src1 = registerName register1 tmp1
1478 pk2 = registerRep register2
1479 code2 = registerCode register2 tmp2
1480 src2 = registerName register2 tmp2
1482 code__2 = asmParThen [code1 asmVoid, code2 asmVoid] .
1483 mkSeqInstr (GCMP (primRepToSize pk1) src1 src2)
1485 {- On the 486, the flags set by FP compare are the unsigned ones!
1486 (This looks like a HACK to me. WDP 96/03)
1488 fix_FP_cond :: Cond -> Cond
1490 fix_FP_cond GE = GEU
1491 fix_FP_cond GTT = GU
1492 fix_FP_cond LTT = LU
1493 fix_FP_cond LE = LEU
1494 fix_FP_cond any = any
1496 returnUs (CondCode True (fix_FP_cond cond) code__2)
1500 #endif {- i386_TARGET_ARCH -}
1501 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1502 #if sparc_TARGET_ARCH
1504 condIntCode cond x (StInt y)
1506 = getRegister x `thenUs` \ register ->
1507 getNewRegNCG IntRep `thenUs` \ tmp ->
1509 code = registerCode register tmp
1510 src1 = registerName register tmp
1511 src2 = ImmInt (fromInteger y)
1512 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1514 returnUs (CondCode False cond code__2)
1516 condIntCode cond x y
1517 = getRegister x `thenUs` \ register1 ->
1518 getRegister y `thenUs` \ register2 ->
1519 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1520 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1522 code1 = registerCode register1 tmp1 asmVoid
1523 src1 = registerName register1 tmp1
1524 code2 = registerCode register2 tmp2 asmVoid
1525 src2 = registerName register2 tmp2
1526 code__2 = asmParThen [code1, code2] .
1527 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1529 returnUs (CondCode False cond code__2)
1532 condFltCode cond x y
1533 = getRegister x `thenUs` \ register1 ->
1534 getRegister y `thenUs` \ register2 ->
1535 getNewRegNCG (registerRep register1)
1537 getNewRegNCG (registerRep register2)
1539 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1541 promote x = asmInstr (FxTOy F DF x tmp)
1543 pk1 = registerRep register1
1544 code1 = registerCode register1 tmp1
1545 src1 = registerName register1 tmp1
1547 pk2 = registerRep register2
1548 code2 = registerCode register2 tmp2
1549 src2 = registerName register2 tmp2
1553 asmParThen [code1 asmVoid, code2 asmVoid] .
1554 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1555 else if pk1 == FloatRep then
1556 asmParThen [code1 (promote src1), code2 asmVoid] .
1557 mkSeqInstr (FCMP True DF tmp src2)
1559 asmParThen [code1 asmVoid, code2 (promote src2)] .
1560 mkSeqInstr (FCMP True DF src1 tmp)
1562 returnUs (CondCode True cond code__2)
1564 #endif {- sparc_TARGET_ARCH -}
1567 %************************************************************************
1569 \subsection{Generating assignments}
1571 %************************************************************************
1573 Assignments are really at the heart of the whole code generation
1574 business. Almost all top-level nodes of any real importance are
1575 assignments, which correspond to loads, stores, or register transfers.
1576 If we're really lucky, some of the register transfers will go away,
1577 because we can use the destination register to complete the code
1578 generation for the right hand side. This only fails when the right
1579 hand side is forced into a fixed register (e.g. the result of a call).
1582 assignIntCode, assignFltCode
1583 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1585 #if alpha_TARGET_ARCH
1587 assignIntCode pk (StInd _ dst) src
1588 = getNewRegNCG IntRep `thenUs` \ tmp ->
1589 getAmode dst `thenUs` \ amode ->
1590 getRegister src `thenUs` \ register ->
1592 code1 = amodeCode amode asmVoid
1593 dst__2 = amodeAddr amode
1594 code2 = registerCode register tmp asmVoid
1595 src__2 = registerName register tmp
1596 sz = primRepToSize pk
1597 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1601 assignIntCode pk dst src
1602 = getRegister dst `thenUs` \ register1 ->
1603 getRegister src `thenUs` \ register2 ->
1605 dst__2 = registerName register1 zeroh
1606 code = registerCode register2 dst__2
1607 src__2 = registerName register2 dst__2
1608 code__2 = if isFixed register2
1609 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1614 #endif {- alpha_TARGET_ARCH -}
1615 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1616 #if i386_TARGET_ARCH
1618 assignIntCode pk dd@(StInd _ dst) src
1619 = getAmode dst `thenUs` \ amode ->
1620 get_op_RI src `thenUs` \ (codesrc, opsrc) ->
1622 code1 = amodeCode amode asmVoid
1623 dst__2 = amodeAddr amode
1624 code__2 = asmParThen [code1, codesrc asmVoid] .
1625 mkSeqInstr (MOV (primRepToSize pk) opsrc (OpAddr dst__2))
1631 -> UniqSM (InstrBlock,Operand) -- code, operator
1635 = returnUs (asmParThen [], OpImm imm_op)
1638 imm_op = case imm of Just x -> x
1641 = getRegister op `thenUs` \ register ->
1642 getNewRegNCG (registerRep register)
1645 code = registerCode register tmp
1646 reg = registerName register tmp
1648 returnUs (code, OpReg reg)
1650 assignIntCode pk dst (StInd pks src)
1651 = getNewRegNCG IntRep `thenUs` \ tmp ->
1652 getAmode src `thenUs` \ amode ->
1653 getRegister dst `thenUs` \ register ->
1655 code1 = amodeCode amode asmVoid
1656 src__2 = amodeAddr amode
1657 code2 = registerCode register tmp asmVoid
1658 dst__2 = registerName register tmp
1659 szs = primRepToSize pks
1660 code__2 = asmParThen [code1, code2] .
1662 L -> mkSeqInstr (MOV L (OpAddr src__2) (OpReg dst__2))
1663 B -> mkSeqInstr (MOVZxL B (OpAddr src__2) (OpReg dst__2))
1667 assignIntCode pk dst src
1668 = getRegister dst `thenUs` \ register1 ->
1669 getRegister src `thenUs` \ register2 ->
1670 getNewRegNCG IntRep `thenUs` \ tmp ->
1672 dst__2 = registerName register1 tmp
1673 code = registerCode register2 dst__2
1674 src__2 = registerName register2 dst__2
1675 code__2 = if isFixed register2 && dst__2 /= src__2
1676 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1681 #endif {- i386_TARGET_ARCH -}
1682 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1683 #if sparc_TARGET_ARCH
1685 assignIntCode pk (StInd _ dst) src
1686 = getNewRegNCG IntRep `thenUs` \ tmp ->
1687 getAmode dst `thenUs` \ amode ->
1688 getRegister src `thenUs` \ register ->
1690 code1 = amodeCode amode asmVoid
1691 dst__2 = amodeAddr amode
1692 code2 = registerCode register tmp asmVoid
1693 src__2 = registerName register tmp
1694 sz = primRepToSize pk
1695 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1699 assignIntCode pk dst src
1700 = getRegister dst `thenUs` \ register1 ->
1701 getRegister src `thenUs` \ register2 ->
1703 dst__2 = registerName register1 g0
1704 code = registerCode register2 dst__2
1705 src__2 = registerName register2 dst__2
1706 code__2 = if isFixed register2
1707 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1712 #endif {- sparc_TARGET_ARCH -}
1715 % --------------------------------
1716 Floating-point assignments:
1717 % --------------------------------
1719 #if alpha_TARGET_ARCH
1721 assignFltCode pk (StInd _ dst) src
1722 = getNewRegNCG pk `thenUs` \ tmp ->
1723 getAmode dst `thenUs` \ amode ->
1724 getRegister src `thenUs` \ register ->
1726 code1 = amodeCode amode asmVoid
1727 dst__2 = amodeAddr amode
1728 code2 = registerCode register tmp asmVoid
1729 src__2 = registerName register tmp
1730 sz = primRepToSize pk
1731 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1735 assignFltCode pk dst src
1736 = getRegister dst `thenUs` \ register1 ->
1737 getRegister src `thenUs` \ register2 ->
1739 dst__2 = registerName register1 zeroh
1740 code = registerCode register2 dst__2
1741 src__2 = registerName register2 dst__2
1742 code__2 = if isFixed register2
1743 then code . mkSeqInstr (FMOV src__2 dst__2)
1748 #endif {- alpha_TARGET_ARCH -}
1749 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1750 #if i386_TARGET_ARCH
1752 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1753 = getNewRegNCG IntRep `thenUs` \ tmp ->
1754 getAmode src `thenUs` \ amodesrc ->
1755 getAmode dst `thenUs` \ amodedst ->
1757 codesrc1 = amodeCode amodesrc asmVoid
1758 addrsrc1 = amodeAddr amodesrc
1759 codedst1 = amodeCode amodedst asmVoid
1760 addrdst1 = amodeAddr amodedst
1761 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1762 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1764 code__2 = asmParThen [codesrc1, codedst1] .
1765 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1766 MOV L (OpReg tmp) (OpAddr addrdst1)]
1769 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1770 MOV L (OpReg tmp) (OpAddr addrdst2)]
1775 assignFltCode pk (StInd _ dst) src
1776 = getNewRegNCG pk `thenUs` \ tmp ->
1777 getAmode dst `thenUs` \ amode ->
1778 getRegister src `thenUs` \ register ->
1780 sz = primRepToSize pk
1781 dst__2 = amodeAddr amode
1783 code1 = amodeCode amode asmVoid
1784 code2 = registerCode register tmp asmVoid
1786 src__2 = registerName register tmp
1788 code__2 = asmParThen [code1, code2] .
1789 mkSeqInstr (GST sz src__2 dst__2)
1793 assignFltCode pk dst src
1794 = getRegister dst `thenUs` \ register1 ->
1795 getRegister src `thenUs` \ register2 ->
1796 getNewRegNCG pk `thenUs` \ tmp ->
1798 -- the register which is dst
1799 dst__2 = registerName register1 tmp
1800 -- the register into which src is computed, preferably dst__2
1801 src__2 = registerName register2 dst__2
1802 -- code to compute src into src__2
1803 code = registerCode register2 dst__2
1805 code__2 = if isFixed register2
1806 then code . mkSeqInstr (GMOV src__2 dst__2)
1811 #endif {- i386_TARGET_ARCH -}
1812 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1813 #if sparc_TARGET_ARCH
1815 assignFltCode pk (StInd _ dst) src
1816 = getNewRegNCG pk `thenUs` \ tmp1 ->
1817 getAmode dst `thenUs` \ amode ->
1818 getRegister src `thenUs` \ register ->
1820 sz = primRepToSize pk
1821 dst__2 = amodeAddr amode
1823 code1 = amodeCode amode asmVoid
1824 code2 = registerCode register tmp1 asmVoid
1826 src__2 = registerName register tmp1
1827 pk__2 = registerRep register
1828 sz__2 = primRepToSize pk__2
1830 code__2 = asmParThen [code1, code2] .
1832 mkSeqInstr (ST sz src__2 dst__2)
1834 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1838 assignFltCode pk dst src
1839 = getRegister dst `thenUs` \ register1 ->
1840 getRegister src `thenUs` \ register2 ->
1842 pk__2 = registerRep register2
1843 sz__2 = primRepToSize pk__2
1845 getNewRegNCG pk__2 `thenUs` \ tmp ->
1847 sz = primRepToSize pk
1848 dst__2 = registerName register1 g0 -- must be Fixed
1851 reg__2 = if pk /= pk__2 then tmp else dst__2
1853 code = registerCode register2 reg__2
1855 src__2 = registerName register2 reg__2
1859 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1860 else if isFixed register2 then
1861 code . mkSeqInstr (FMOV sz src__2 dst__2)
1867 #endif {- sparc_TARGET_ARCH -}
1870 %************************************************************************
1872 \subsection{Generating an unconditional branch}
1874 %************************************************************************
1876 We accept two types of targets: an immediate CLabel or a tree that
1877 gets evaluated into a register. Any CLabels which are AsmTemporaries
1878 are assumed to be in the local block of code, close enough for a
1879 branch instruction. Other CLabels are assumed to be far away.
1881 (If applicable) Do not fill the delay slots here; you will confuse the
1885 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1887 #if alpha_TARGET_ARCH
1889 genJump (StCLbl lbl)
1890 | isAsmTemp lbl = returnInstr (BR target)
1891 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1893 target = ImmCLbl lbl
1896 = getRegister tree `thenUs` \ register ->
1897 getNewRegNCG PtrRep `thenUs` \ tmp ->
1899 dst = registerName register pv
1900 code = registerCode register pv
1901 target = registerName register pv
1903 if isFixed register then
1904 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1906 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1908 #endif {- alpha_TARGET_ARCH -}
1909 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1910 #if i386_TARGET_ARCH
1913 genJump (StCLbl lbl)
1914 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1915 | otherwise = returnInstrs [JMP (OpImm target)]
1917 target = ImmCLbl lbl
1920 genJump (StInd pk mem)
1921 = getAmode mem `thenUs` \ amode ->
1923 code = amodeCode amode
1924 target = amodeAddr amode
1926 returnSeq code [JMP (OpAddr target)]
1930 = returnInstr (JMP (OpImm target))
1933 = getRegister tree `thenUs` \ register ->
1934 getNewRegNCG PtrRep `thenUs` \ tmp ->
1936 code = registerCode register tmp
1937 target = registerName register tmp
1939 returnSeq code [JMP (OpReg target)]
1942 target = case imm of Just x -> x
1944 #endif {- i386_TARGET_ARCH -}
1945 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1946 #if sparc_TARGET_ARCH
1948 genJump (StCLbl lbl)
1949 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1950 | otherwise = returnInstrs [CALL target 0 True, NOP]
1952 target = ImmCLbl lbl
1955 = getRegister tree `thenUs` \ register ->
1956 getNewRegNCG PtrRep `thenUs` \ tmp ->
1958 code = registerCode register tmp
1959 target = registerName register tmp
1961 returnSeq code [JMP (AddrRegReg target g0), NOP]
1963 #endif {- sparc_TARGET_ARCH -}
1966 %************************************************************************
1968 \subsection{Conditional jumps}
1970 %************************************************************************
1972 Conditional jumps are always to local labels, so we can use branch
1973 instructions. We peek at the arguments to decide what kind of
1976 ALPHA: For comparisons with 0, we're laughing, because we can just do
1977 the desired conditional branch.
1979 I386: First, we have to ensure that the condition
1980 codes are set according to the supplied comparison operation.
1982 SPARC: First, we have to ensure that the condition codes are set
1983 according to the supplied comparison operation. We generate slightly
1984 different code for floating point comparisons, because a floating
1985 point operation cannot directly precede a @BF@. We assume the worst
1986 and fill that slot with a @NOP@.
1988 SPARC: Do not fill the delay slots here; you will confuse the register
1993 :: CLabel -- the branch target
1994 -> StixTree -- the condition on which to branch
1995 -> UniqSM InstrBlock
1997 #if alpha_TARGET_ARCH
1999 genCondJump lbl (StPrim op [x, StInt 0])
2000 = getRegister x `thenUs` \ register ->
2001 getNewRegNCG (registerRep register)
2004 code = registerCode register tmp
2005 value = registerName register tmp
2006 pk = registerRep register
2007 target = ImmCLbl lbl
2009 returnSeq code [BI (cmpOp op) value target]
2011 cmpOp CharGtOp = GTT
2013 cmpOp CharEqOp = EQQ
2015 cmpOp CharLtOp = LTT
2024 cmpOp WordGeOp = ALWAYS
2025 cmpOp WordEqOp = EQQ
2027 cmpOp WordLtOp = NEVER
2028 cmpOp WordLeOp = EQQ
2030 cmpOp AddrGeOp = ALWAYS
2031 cmpOp AddrEqOp = EQQ
2033 cmpOp AddrLtOp = NEVER
2034 cmpOp AddrLeOp = EQQ
2036 genCondJump lbl (StPrim op [x, StDouble 0.0])
2037 = getRegister x `thenUs` \ register ->
2038 getNewRegNCG (registerRep register)
2041 code = registerCode register tmp
2042 value = registerName register tmp
2043 pk = registerRep register
2044 target = ImmCLbl lbl
2046 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2048 cmpOp FloatGtOp = GTT
2049 cmpOp FloatGeOp = GE
2050 cmpOp FloatEqOp = EQQ
2051 cmpOp FloatNeOp = NE
2052 cmpOp FloatLtOp = LTT
2053 cmpOp FloatLeOp = LE
2054 cmpOp DoubleGtOp = GTT
2055 cmpOp DoubleGeOp = GE
2056 cmpOp DoubleEqOp = EQQ
2057 cmpOp DoubleNeOp = NE
2058 cmpOp DoubleLtOp = LTT
2059 cmpOp DoubleLeOp = LE
2061 genCondJump lbl (StPrim op [x, y])
2063 = trivialFCode pr instr x y `thenUs` \ register ->
2064 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2066 code = registerCode register tmp
2067 result = registerName register tmp
2068 target = ImmCLbl lbl
2070 returnUs (code . mkSeqInstr (BF cond result target))
2072 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2074 fltCmpOp op = case op of
2088 (instr, cond) = case op of
2089 FloatGtOp -> (FCMP TF LE, EQQ)
2090 FloatGeOp -> (FCMP TF LTT, EQQ)
2091 FloatEqOp -> (FCMP TF EQQ, NE)
2092 FloatNeOp -> (FCMP TF EQQ, EQQ)
2093 FloatLtOp -> (FCMP TF LTT, NE)
2094 FloatLeOp -> (FCMP TF LE, NE)
2095 DoubleGtOp -> (FCMP TF LE, EQQ)
2096 DoubleGeOp -> (FCMP TF LTT, EQQ)
2097 DoubleEqOp -> (FCMP TF EQQ, NE)
2098 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2099 DoubleLtOp -> (FCMP TF LTT, NE)
2100 DoubleLeOp -> (FCMP TF LE, NE)
2102 genCondJump lbl (StPrim op [x, y])
2103 = trivialCode instr x y `thenUs` \ register ->
2104 getNewRegNCG IntRep `thenUs` \ tmp ->
2106 code = registerCode register tmp
2107 result = registerName register tmp
2108 target = ImmCLbl lbl
2110 returnUs (code . mkSeqInstr (BI cond result target))
2112 (instr, cond) = case op of
2113 CharGtOp -> (CMP LE, EQQ)
2114 CharGeOp -> (CMP LTT, EQQ)
2115 CharEqOp -> (CMP EQQ, NE)
2116 CharNeOp -> (CMP EQQ, EQQ)
2117 CharLtOp -> (CMP LTT, NE)
2118 CharLeOp -> (CMP LE, NE)
2119 IntGtOp -> (CMP LE, EQQ)
2120 IntGeOp -> (CMP LTT, EQQ)
2121 IntEqOp -> (CMP EQQ, NE)
2122 IntNeOp -> (CMP EQQ, EQQ)
2123 IntLtOp -> (CMP LTT, NE)
2124 IntLeOp -> (CMP LE, NE)
2125 WordGtOp -> (CMP ULE, EQQ)
2126 WordGeOp -> (CMP ULT, EQQ)
2127 WordEqOp -> (CMP EQQ, NE)
2128 WordNeOp -> (CMP EQQ, EQQ)
2129 WordLtOp -> (CMP ULT, NE)
2130 WordLeOp -> (CMP ULE, NE)
2131 AddrGtOp -> (CMP ULE, EQQ)
2132 AddrGeOp -> (CMP ULT, EQQ)
2133 AddrEqOp -> (CMP EQQ, NE)
2134 AddrNeOp -> (CMP EQQ, EQQ)
2135 AddrLtOp -> (CMP ULT, NE)
2136 AddrLeOp -> (CMP ULE, NE)
2138 #endif {- alpha_TARGET_ARCH -}
2139 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2140 #if i386_TARGET_ARCH
2142 genCondJump lbl bool
2143 = getCondCode bool `thenUs` \ condition ->
2145 code = condCode condition
2146 cond = condName condition
2147 target = ImmCLbl lbl
2149 returnSeq code [JXX cond lbl]
2151 #endif {- i386_TARGET_ARCH -}
2152 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2153 #if sparc_TARGET_ARCH
2155 genCondJump lbl bool
2156 = getCondCode bool `thenUs` \ condition ->
2158 code = condCode condition
2159 cond = condName condition
2160 target = ImmCLbl lbl
2163 if condFloat condition then
2164 [NOP, BF cond False target, NOP]
2166 [BI cond False target, NOP]
2169 #endif {- sparc_TARGET_ARCH -}
2172 %************************************************************************
2174 \subsection{Generating C calls}
2176 %************************************************************************
2178 Now the biggest nightmare---calls. Most of the nastiness is buried in
2179 @get_arg@, which moves the arguments to the correct registers/stack
2180 locations. Apart from that, the code is easy.
2182 (If applicable) Do not fill the delay slots here; you will confuse the
2187 :: FAST_STRING -- function to call
2189 -> PrimRep -- type of the result
2190 -> [StixTree] -- arguments (of mixed type)
2191 -> UniqSM InstrBlock
2193 #if alpha_TARGET_ARCH
2195 genCCall fn cconv kind args
2196 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2197 `thenUs` \ ((unused,_), argCode) ->
2199 nRegs = length allArgRegs - length unused
2200 code = asmParThen (map ($ asmVoid) argCode)
2203 LDA pv (AddrImm (ImmLab (ptext fn))),
2204 JSR ra (AddrReg pv) nRegs,
2205 LDGP gp (AddrReg ra)]
2207 ------------------------
2208 {- Try to get a value into a specific register (or registers) for
2209 a call. The first 6 arguments go into the appropriate
2210 argument register (separate registers for integer and floating
2211 point arguments, but used in lock-step), and the remaining
2212 arguments are dumped to the stack, beginning at 0(sp). Our
2213 first argument is a pair of the list of remaining argument
2214 registers to be assigned for this call and the next stack
2215 offset to use for overflowing arguments. This way,
2216 @get_Arg@ can be applied to all of a call's arguments using
2220 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2221 -> StixTree -- Current argument
2222 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2224 -- We have to use up all of our argument registers first...
2226 get_arg ((iDst,fDst):dsts, offset) arg
2227 = getRegister arg `thenUs` \ register ->
2229 reg = if isFloatingRep pk then fDst else iDst
2230 code = registerCode register reg
2231 src = registerName register reg
2232 pk = registerRep register
2235 if isFloatingRep pk then
2236 ((dsts, offset), if isFixed register then
2237 code . mkSeqInstr (FMOV src fDst)
2240 ((dsts, offset), if isFixed register then
2241 code . mkSeqInstr (OR src (RIReg src) iDst)
2244 -- Once we have run out of argument registers, we move to the
2247 get_arg ([], offset) arg
2248 = getRegister arg `thenUs` \ register ->
2249 getNewRegNCG (registerRep register)
2252 code = registerCode register tmp
2253 src = registerName register tmp
2254 pk = registerRep register
2255 sz = primRepToSize pk
2257 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2259 #endif {- alpha_TARGET_ARCH -}
2260 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2261 #if i386_TARGET_ARCH
2263 genCCall fn cconv kind [StInt i]
2264 | fn == SLIT ("PerformGC_wrapper")
2265 = let call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2266 CALL (ImmLit (ptext (if underscorePrefix
2267 then (SLIT ("_PerformGC_wrapper"))
2268 else (SLIT ("PerformGC_wrapper")))))]
2273 genCCall fn cconv kind args
2274 = get_call_args args `thenUs` \ (tot_arg_size, argCode) ->
2276 code2 = asmParThen (map ($ asmVoid) argCode)
2277 call = [SUB L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2279 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)
2282 returnSeq code2 call
2285 -- function names that begin with '.' are assumed to be special
2286 -- internally generated names like '.mul,' which don't get an
2287 -- underscore prefix
2288 -- ToDo:needed (WDP 96/03) ???
2289 fn__2 = case (_HEAD_ fn) of
2290 '.' -> ImmLit (ptext fn)
2291 _ -> ImmLab (ptext fn)
2298 -- do get_call_arg on each arg, threading the total arg size along
2299 -- process the args right-to-left
2300 get_call_args :: [StixTree] -> UniqSM (Int, [InstrBlock])
2305 = returnUs (curr_sz, [])
2306 f curr_sz (arg:args)
2307 = f curr_sz args `thenUs` \ (new_sz, iblocks) ->
2308 get_call_arg arg new_sz `thenUs` \ (new_sz2, iblock) ->
2309 returnUs (new_sz2, iblock:iblocks)
2313 get_call_arg :: StixTree{-current argument-}
2314 -> Int{-running total of arg sizes seen so far-}
2315 -> UniqSM (Int, InstrBlock) -- updated tot argsz, code
2317 get_call_arg arg old_sz
2318 = get_op arg `thenUs` \ (code, reg, sz) ->
2319 let new_sz = old_sz + arg_size sz
2320 in if (case sz of DF -> True; F -> True; _ -> False)
2321 then returnUs (new_sz,
2323 mkSeqInstr (GST DF reg
2324 (AddrBaseIndex (Just esp)
2325 Nothing (ImmInt (- new_sz))))
2327 else returnUs (new_sz,
2329 mkSeqInstr (MOV L (OpReg reg)
2331 (AddrBaseIndex (Just esp)
2332 Nothing (ImmInt (- new_sz)))))
2337 -> UniqSM (InstrBlock, Reg, Size) -- code, reg, size
2340 = getRegister op `thenUs` \ register ->
2341 getNewRegNCG (registerRep register)
2344 code = registerCode register tmp
2345 reg = registerName register tmp
2346 pk = registerRep register
2347 sz = primRepToSize pk
2349 returnUs (code, reg, sz)
2351 #endif {- i386_TARGET_ARCH -}
2352 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2353 #if sparc_TARGET_ARCH
2355 genCCall fn cconv kind args
2356 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2357 `thenUs` \ ((unused,_), argCode) ->
2359 nRegs = length allArgRegs - length unused
2360 call = CALL fn__2 nRegs False
2361 code = asmParThen (map ($ asmVoid) argCode)
2363 returnSeq code [call, NOP]
2365 -- function names that begin with '.' are assumed to be special
2366 -- internally generated names like '.mul,' which don't get an
2367 -- underscore prefix
2368 -- ToDo:needed (WDP 96/03) ???
2369 fn__2 = case (_HEAD_ fn) of
2370 '.' -> ImmLit (ptext fn)
2371 _ -> ImmLab (ptext fn)
2373 ------------------------------------
2374 {- Try to get a value into a specific register (or registers) for
2375 a call. The SPARC calling convention is an absolute
2376 nightmare. The first 6x32 bits of arguments are mapped into
2377 %o0 through %o5, and the remaining arguments are dumped to the
2378 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2379 first argument is a pair of the list of remaining argument
2380 registers to be assigned for this call and the next stack
2381 offset to use for overflowing arguments. This way,
2382 @get_arg@ can be applied to all of a call's arguments using
2386 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2387 -> StixTree -- Current argument
2388 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2390 -- We have to use up all of our argument registers first...
2392 get_arg (dst:dsts, offset) arg
2393 = getRegister arg `thenUs` \ register ->
2394 getNewRegNCG (registerRep register)
2397 reg = if isFloatingRep pk then tmp else dst
2398 code = registerCode register reg
2399 src = registerName register reg
2400 pk = registerRep register
2402 returnUs (case pk of
2405 [] -> (([], offset + 1), code . mkSeqInstrs [
2406 -- conveniently put the second part in the right stack
2407 -- location, and load the first part into %o5
2408 ST DF src (spRel (offset - 1)),
2409 LD W (spRel (offset - 1)) dst])
2410 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2411 ST DF src (spRel (-2)),
2412 LD W (spRel (-2)) dst,
2413 LD W (spRel (-1)) dst__2])
2414 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2415 ST F src (spRel (-2)),
2416 LD W (spRel (-2)) dst])
2417 _ -> ((dsts, offset), if isFixed register then
2418 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2421 -- Once we have run out of argument registers, we move to the
2424 get_arg ([], offset) arg
2425 = getRegister arg `thenUs` \ register ->
2426 getNewRegNCG (registerRep register)
2429 code = registerCode register tmp
2430 src = registerName register tmp
2431 pk = registerRep register
2432 sz = primRepToSize pk
2433 words = if pk == DoubleRep then 2 else 1
2435 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2437 #endif {- sparc_TARGET_ARCH -}
2440 %************************************************************************
2442 \subsection{Support bits}
2444 %************************************************************************
2446 %************************************************************************
2448 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2450 %************************************************************************
2452 Turn those condition codes into integers now (when they appear on
2453 the right hand side of an assignment).
2455 (If applicable) Do not fill the delay slots here; you will confuse the
2459 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2461 #if alpha_TARGET_ARCH
2462 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2463 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2464 #endif {- alpha_TARGET_ARCH -}
2466 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2467 #if i386_TARGET_ARCH
2470 = condIntCode cond x y `thenUs` \ condition ->
2471 getNewRegNCG IntRep `thenUs` \ tmp ->
2472 --getRegister dst `thenUs` \ register ->
2474 --code2 = registerCode register tmp asmVoid
2475 --dst__2 = registerName register tmp
2476 code = condCode condition
2477 cond = condName condition
2478 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2479 code__2 dst = code . mkSeqInstrs [COMMENT (_PK_ "aaaaa"),
2480 SETCC cond (OpReg tmp),
2481 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2482 MOV L (OpReg tmp) (OpReg dst) ,COMMENT (_PK_ "bbbbb")]
2484 returnUs (Any IntRep code__2)
2487 = getUniqLabelNCG `thenUs` \ lbl1 ->
2488 getUniqLabelNCG `thenUs` \ lbl2 ->
2489 condFltCode cond x y `thenUs` \ condition ->
2491 code = condCode condition
2492 cond = condName condition
2493 code__2 dst = code . mkSeqInstrs [
2495 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2498 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2501 returnUs (Any IntRep code__2)
2503 #endif {- i386_TARGET_ARCH -}
2504 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2505 #if sparc_TARGET_ARCH
2507 condIntReg EQQ x (StInt 0)
2508 = getRegister x `thenUs` \ register ->
2509 getNewRegNCG IntRep `thenUs` \ tmp ->
2511 code = registerCode register tmp
2512 src = registerName register tmp
2513 code__2 dst = code . mkSeqInstrs [
2514 SUB False True g0 (RIReg src) g0,
2515 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2517 returnUs (Any IntRep code__2)
2520 = getRegister x `thenUs` \ register1 ->
2521 getRegister y `thenUs` \ register2 ->
2522 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2523 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2525 code1 = registerCode register1 tmp1 asmVoid
2526 src1 = registerName register1 tmp1
2527 code2 = registerCode register2 tmp2 asmVoid
2528 src2 = registerName register2 tmp2
2529 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2530 XOR False src1 (RIReg src2) dst,
2531 SUB False True g0 (RIReg dst) g0,
2532 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2534 returnUs (Any IntRep code__2)
2536 condIntReg NE x (StInt 0)
2537 = getRegister x `thenUs` \ register ->
2538 getNewRegNCG IntRep `thenUs` \ tmp ->
2540 code = registerCode register tmp
2541 src = registerName register tmp
2542 code__2 dst = code . mkSeqInstrs [
2543 SUB False True g0 (RIReg src) g0,
2544 ADD True False g0 (RIImm (ImmInt 0)) dst]
2546 returnUs (Any IntRep code__2)
2549 = getRegister x `thenUs` \ register1 ->
2550 getRegister y `thenUs` \ register2 ->
2551 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2552 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2554 code1 = registerCode register1 tmp1 asmVoid
2555 src1 = registerName register1 tmp1
2556 code2 = registerCode register2 tmp2 asmVoid
2557 src2 = registerName register2 tmp2
2558 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2559 XOR False src1 (RIReg src2) dst,
2560 SUB False True g0 (RIReg dst) g0,
2561 ADD True False g0 (RIImm (ImmInt 0)) dst]
2563 returnUs (Any IntRep code__2)
2566 = getUniqLabelNCG `thenUs` \ lbl1 ->
2567 getUniqLabelNCG `thenUs` \ lbl2 ->
2568 condIntCode cond x y `thenUs` \ condition ->
2570 code = condCode condition
2571 cond = condName condition
2572 code__2 dst = code . mkSeqInstrs [
2573 BI cond False (ImmCLbl lbl1), NOP,
2574 OR False g0 (RIImm (ImmInt 0)) dst,
2575 BI ALWAYS False (ImmCLbl lbl2), NOP,
2577 OR False g0 (RIImm (ImmInt 1)) dst,
2580 returnUs (Any IntRep code__2)
2583 = getUniqLabelNCG `thenUs` \ lbl1 ->
2584 getUniqLabelNCG `thenUs` \ lbl2 ->
2585 condFltCode cond x y `thenUs` \ condition ->
2587 code = condCode condition
2588 cond = condName condition
2589 code__2 dst = code . mkSeqInstrs [
2591 BF cond False (ImmCLbl lbl1), NOP,
2592 OR False g0 (RIImm (ImmInt 0)) dst,
2593 BI ALWAYS False (ImmCLbl lbl2), NOP,
2595 OR False g0 (RIImm (ImmInt 1)) dst,
2598 returnUs (Any IntRep code__2)
2600 #endif {- sparc_TARGET_ARCH -}
2603 %************************************************************************
2605 \subsubsection{@trivial*Code@: deal with trivial instructions}
2607 %************************************************************************
2609 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2610 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2611 for constants on the right hand side, because that's where the generic
2612 optimizer will have put them.
2614 Similarly, for unary instructions, we don't have to worry about
2615 matching an StInt as the argument, because genericOpt will already
2616 have handled the constant-folding.
2620 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2621 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2622 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2624 -> StixTree -> StixTree -- the two arguments
2629 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2630 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2631 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2633 -> StixTree -> StixTree -- the two arguments
2637 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2638 ,IF_ARCH_i386 ((Operand -> Instr)
2639 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2641 -> StixTree -- the one argument
2646 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2647 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2648 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2650 -> StixTree -- the one argument
2653 #if alpha_TARGET_ARCH
2655 trivialCode instr x (StInt y)
2657 = getRegister x `thenUs` \ register ->
2658 getNewRegNCG IntRep `thenUs` \ tmp ->
2660 code = registerCode register tmp
2661 src1 = registerName register tmp
2662 src2 = ImmInt (fromInteger y)
2663 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2665 returnUs (Any IntRep code__2)
2667 trivialCode instr x y
2668 = getRegister x `thenUs` \ register1 ->
2669 getRegister y `thenUs` \ register2 ->
2670 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2671 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2673 code1 = registerCode register1 tmp1 asmVoid
2674 src1 = registerName register1 tmp1
2675 code2 = registerCode register2 tmp2 asmVoid
2676 src2 = registerName register2 tmp2
2677 code__2 dst = asmParThen [code1, code2] .
2678 mkSeqInstr (instr src1 (RIReg src2) dst)
2680 returnUs (Any IntRep code__2)
2683 trivialUCode instr x
2684 = getRegister x `thenUs` \ register ->
2685 getNewRegNCG IntRep `thenUs` \ tmp ->
2687 code = registerCode register tmp
2688 src = registerName register tmp
2689 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2691 returnUs (Any IntRep code__2)
2694 trivialFCode _ instr x y
2695 = getRegister x `thenUs` \ register1 ->
2696 getRegister y `thenUs` \ register2 ->
2697 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2698 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2700 code1 = registerCode register1 tmp1
2701 src1 = registerName register1 tmp1
2703 code2 = registerCode register2 tmp2
2704 src2 = registerName register2 tmp2
2706 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2707 mkSeqInstr (instr src1 src2 dst)
2709 returnUs (Any DoubleRep code__2)
2711 trivialUFCode _ instr x
2712 = getRegister x `thenUs` \ register ->
2713 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2715 code = registerCode register tmp
2716 src = registerName register tmp
2717 code__2 dst = code . mkSeqInstr (instr src dst)
2719 returnUs (Any DoubleRep code__2)
2721 #endif {- alpha_TARGET_ARCH -}
2722 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2723 #if i386_TARGET_ARCH
2725 trivialCode instr x y
2727 = getRegister x `thenUs` \ register1 ->
2729 code__2 dst = let code1 = registerCode register1 dst
2730 src1 = registerName register1 dst
2732 if isFixed register1 && src1 /= dst
2733 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2734 instr (OpImm imm__2) (OpReg dst)]
2736 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2738 returnUs (Any IntRep code__2)
2741 imm__2 = case imm of Just x -> x
2743 trivialCode instr x y
2744 = getRegister x `thenUs` \ register1 ->
2745 getRegister y `thenUs` \ register2 ->
2746 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2748 code2 = registerCode register2 tmp2 asmVoid
2749 src2 = registerName register2 tmp2
2751 code1 = registerCode register1 dst asmVoid
2752 src1 = registerName register1 dst
2753 in asmParThen [code1, code2] .
2754 if isFixed register1 && src1 /= dst
2755 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2756 instr (OpReg src2) (OpReg dst)]
2758 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2760 returnUs (Any IntRep code__2)
2763 trivialUCode instr x
2764 = getRegister x `thenUs` \ register ->
2767 code = registerCode register dst
2768 src = registerName register dst
2769 in code . if isFixed register && dst /= src
2770 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2772 else mkSeqInstr (instr (OpReg src))
2774 returnUs (Any IntRep code__2)
2777 trivialFCode pk instr x y
2778 = getRegister x `thenUs` \ register1 ->
2779 getRegister y `thenUs` \ register2 ->
2780 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2781 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2783 code1 = registerCode register1 tmp1
2784 src1 = registerName register1 tmp1
2786 code2 = registerCode register2 tmp2
2787 src2 = registerName register2 tmp2
2789 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2790 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2792 returnUs (Any DoubleRep code__2)
2796 trivialUFCode pk instr x
2797 = getRegister x `thenUs` \ register ->
2798 getNewRegNCG pk `thenUs` \ tmp ->
2800 code = registerCode register tmp
2801 src = registerName register tmp
2802 code__2 dst = code . mkSeqInstr (instr src dst)
2804 returnUs (Any pk code__2)
2806 #endif {- i386_TARGET_ARCH -}
2807 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2808 #if sparc_TARGET_ARCH
2810 trivialCode instr x (StInt y)
2812 = getRegister x `thenUs` \ register ->
2813 getNewRegNCG IntRep `thenUs` \ tmp ->
2815 code = registerCode register tmp
2816 src1 = registerName register tmp
2817 src2 = ImmInt (fromInteger y)
2818 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2820 returnUs (Any IntRep code__2)
2822 trivialCode instr x y
2823 = getRegister x `thenUs` \ register1 ->
2824 getRegister y `thenUs` \ register2 ->
2825 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2826 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2828 code1 = registerCode register1 tmp1 asmVoid
2829 src1 = registerName register1 tmp1
2830 code2 = registerCode register2 tmp2 asmVoid
2831 src2 = registerName register2 tmp2
2832 code__2 dst = asmParThen [code1, code2] .
2833 mkSeqInstr (instr src1 (RIReg src2) dst)
2835 returnUs (Any IntRep code__2)
2838 trivialFCode pk instr x y
2839 = getRegister x `thenUs` \ register1 ->
2840 getRegister y `thenUs` \ register2 ->
2841 getNewRegNCG (registerRep register1)
2843 getNewRegNCG (registerRep register2)
2845 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2847 promote x = asmInstr (FxTOy F DF x tmp)
2849 pk1 = registerRep register1
2850 code1 = registerCode register1 tmp1
2851 src1 = registerName register1 tmp1
2853 pk2 = registerRep register2
2854 code2 = registerCode register2 tmp2
2855 src2 = registerName register2 tmp2
2859 asmParThen [code1 asmVoid, code2 asmVoid] .
2860 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2861 else if pk1 == FloatRep then
2862 asmParThen [code1 (promote src1), code2 asmVoid] .
2863 mkSeqInstr (instr DF tmp src2 dst)
2865 asmParThen [code1 asmVoid, code2 (promote src2)] .
2866 mkSeqInstr (instr DF src1 tmp dst)
2868 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2871 trivialUCode instr x
2872 = getRegister x `thenUs` \ register ->
2873 getNewRegNCG IntRep `thenUs` \ tmp ->
2875 code = registerCode register tmp
2876 src = registerName register tmp
2877 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2879 returnUs (Any IntRep code__2)
2882 trivialUFCode pk instr x
2883 = getRegister x `thenUs` \ register ->
2884 getNewRegNCG pk `thenUs` \ tmp ->
2886 code = registerCode register tmp
2887 src = registerName register tmp
2888 code__2 dst = code . mkSeqInstr (instr src dst)
2890 returnUs (Any pk code__2)
2892 #endif {- sparc_TARGET_ARCH -}
2895 %************************************************************************
2897 \subsubsection{Coercing to/from integer/floating-point...}
2899 %************************************************************************
2901 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
2902 to be generated. Here we just change the type on the Register passed
2903 on up. The code is machine-independent.
2905 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
2906 conversions. We have to store temporaries in memory to move
2907 between the integer and the floating point register sets.
2910 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
2911 coerceFltCode :: StixTree -> UniqSM Register
2913 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
2914 coerceFP2Int :: StixTree -> UniqSM Register
2917 = getRegister x `thenUs` \ register ->
2920 Fixed _ reg code -> Fixed pk reg code
2921 Any _ code -> Any pk code
2926 = getRegister x `thenUs` \ register ->
2929 Fixed _ reg code -> Fixed DoubleRep reg code
2930 Any _ code -> Any DoubleRep code
2935 #if alpha_TARGET_ARCH
2938 = getRegister x `thenUs` \ register ->
2939 getNewRegNCG IntRep `thenUs` \ reg ->
2941 code = registerCode register reg
2942 src = registerName register reg
2944 code__2 dst = code . mkSeqInstrs [
2946 LD TF dst (spRel 0),
2949 returnUs (Any DoubleRep code__2)
2953 = getRegister x `thenUs` \ register ->
2954 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2956 code = registerCode register tmp
2957 src = registerName register tmp
2959 code__2 dst = code . mkSeqInstrs [
2961 ST TF tmp (spRel 0),
2964 returnUs (Any IntRep code__2)
2966 #endif {- alpha_TARGET_ARCH -}
2967 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2968 #if i386_TARGET_ARCH
2971 = getRegister x `thenUs` \ register ->
2972 getNewRegNCG IntRep `thenUs` \ reg ->
2974 code = registerCode register reg
2975 src = registerName register reg
2976 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
2977 code__2 dst = code .
2978 mkSeqInstr (opc src dst)
2980 returnUs (Any pk code__2)
2984 = getRegister x `thenUs` \ register ->
2985 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2987 code = registerCode register tmp
2988 src = registerName register tmp
2989 pk = registerRep register
2991 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
2992 code__2 dst = code .
2993 mkSeqInstr (opc src dst)
2995 returnUs (Any IntRep code__2)
2997 #endif {- i386_TARGET_ARCH -}
2998 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2999 #if sparc_TARGET_ARCH
3002 = getRegister x `thenUs` \ register ->
3003 getNewRegNCG IntRep `thenUs` \ reg ->
3005 code = registerCode register reg
3006 src = registerName register reg
3008 code__2 dst = code . mkSeqInstrs [
3009 ST W src (spRel (-2)),
3010 LD W (spRel (-2)) dst,
3011 FxTOy W (primRepToSize pk) dst dst]
3013 returnUs (Any pk code__2)
3017 = getRegister x `thenUs` \ register ->
3018 getNewRegNCG IntRep `thenUs` \ reg ->
3019 getNewRegNCG FloatRep `thenUs` \ tmp ->
3021 code = registerCode register reg
3022 src = registerName register reg
3023 pk = registerRep register
3025 code__2 dst = code . mkSeqInstrs [
3026 FxTOy (primRepToSize pk) W src tmp,
3027 ST W tmp (spRel (-2)),
3028 LD W (spRel (-2)) dst]
3030 returnUs (Any IntRep code__2)
3032 #endif {- sparc_TARGET_ARCH -}
3035 %************************************************************************
3037 \subsubsection{Coercing integer to @Char@...}
3039 %************************************************************************
3041 Integer to character conversion. Where applicable, we try to do this
3042 in one step if the original object is in memory.
3045 chrCode :: StixTree -> UniqSM Register
3047 #if alpha_TARGET_ARCH
3050 = getRegister x `thenUs` \ register ->
3051 getNewRegNCG IntRep `thenUs` \ reg ->
3053 code = registerCode register reg
3054 src = registerName register reg
3055 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3057 returnUs (Any IntRep code__2)
3059 #endif {- alpha_TARGET_ARCH -}
3060 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3061 #if i386_TARGET_ARCH
3064 = getRegister x `thenUs` \ register ->
3067 code = registerCode register dst
3068 src = registerName register dst
3070 if isFixed register && src /= dst
3071 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3072 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3073 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3075 returnUs (Any IntRep code__2)
3077 #endif {- i386_TARGET_ARCH -}
3078 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3079 #if sparc_TARGET_ARCH
3081 chrCode (StInd pk mem)
3082 = getAmode mem `thenUs` \ amode ->
3084 code = amodeCode amode
3085 src = amodeAddr amode
3086 src_off = addrOffset src 3
3087 src__2 = case src_off of Just x -> x
3088 code__2 dst = if maybeToBool src_off then
3089 code . mkSeqInstr (LD BU src__2 dst)
3091 code . mkSeqInstrs [
3092 LD (primRepToSize pk) src dst,
3093 AND False dst (RIImm (ImmInt 255)) dst]
3095 returnUs (Any pk code__2)
3098 = getRegister x `thenUs` \ register ->
3099 getNewRegNCG IntRep `thenUs` \ reg ->
3101 code = registerCode register reg
3102 src = registerName register reg
3103 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3105 returnUs (Any IntRep code__2)
3107 #endif {- sparc_TARGET_ARCH -}