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 -- incorrectly assumes that %esp doesn't move (as does spilling); ToDo: fix
487 getRegister (StScratchWord i)
489 = let code dst = mkSeqInstr (LEA L (OpAddr (spRel (i+1))) (OpReg dst))
490 in returnUs (Any PtrRep code)
492 getRegister (StPrim primop [x]) -- unary PrimOps
494 IntNegOp -> trivialUCode (NEGI L) x
495 NotOp -> trivialUCode (NOT L) x
497 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
498 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
500 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
501 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
503 FloatSinOp -> trivialUFCode FloatRep (GSIN F) x
504 DoubleSinOp -> trivialUFCode DoubleRep (GSIN DF) x
506 FloatCosOp -> trivialUFCode FloatRep (GCOS F) x
507 DoubleCosOp -> trivialUFCode DoubleRep (GCOS DF) x
509 FloatTanOp -> trivialUFCode FloatRep (GTAN F) x
510 DoubleTanOp -> trivialUFCode DoubleRep (GTAN DF) x
512 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
513 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
515 OrdOp -> coerceIntCode IntRep x
518 Float2IntOp -> coerceFP2Int x
519 Int2FloatOp -> coerceInt2FP FloatRep x
520 Double2IntOp -> coerceFP2Int x
521 Int2DoubleOp -> coerceInt2FP DoubleRep x
525 fixed_x = if is_float_op -- promote to double
526 then StPrim Float2DoubleOp [x]
529 getRegister (StCall fn cCallConv DoubleRep [x])
533 FloatExpOp -> (True, SLIT("exp"))
534 FloatLogOp -> (True, SLIT("log"))
536 --FloatSinOp -> (True, SLIT("sin"))
537 --FloatCosOp -> (True, SLIT("cos"))
538 --FloatTanOp -> (True, SLIT("tan"))
540 FloatAsinOp -> (True, SLIT("asin"))
541 FloatAcosOp -> (True, SLIT("acos"))
542 FloatAtanOp -> (True, SLIT("atan"))
544 FloatSinhOp -> (True, SLIT("sinh"))
545 FloatCoshOp -> (True, SLIT("cosh"))
546 FloatTanhOp -> (True, SLIT("tanh"))
548 DoubleExpOp -> (False, SLIT("exp"))
549 DoubleLogOp -> (False, SLIT("log"))
551 --DoubleSinOp -> (False, SLIT("sin"))
552 --DoubleCosOp -> (False, SLIT("cos"))
553 --DoubleTanOp -> (False, SLIT("tan"))
555 DoubleAsinOp -> (False, SLIT("asin"))
556 DoubleAcosOp -> (False, SLIT("acos"))
557 DoubleAtanOp -> (False, SLIT("atan"))
559 DoubleSinhOp -> (False, SLIT("sinh"))
560 DoubleCoshOp -> (False, SLIT("cosh"))
561 DoubleTanhOp -> (False, SLIT("tanh"))
564 -> pprPanic "getRegister(x86,unary primop)"
565 (pprStixTrees [StPrim primop [x]])
567 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
569 CharGtOp -> condIntReg GTT x y
570 CharGeOp -> condIntReg GE x y
571 CharEqOp -> condIntReg EQQ x y
572 CharNeOp -> condIntReg NE x y
573 CharLtOp -> condIntReg LTT x y
574 CharLeOp -> condIntReg LE x y
576 IntGtOp -> condIntReg GTT x y
577 IntGeOp -> condIntReg GE x y
578 IntEqOp -> condIntReg EQQ x y
579 IntNeOp -> condIntReg NE x y
580 IntLtOp -> condIntReg LTT x y
581 IntLeOp -> condIntReg LE x y
583 WordGtOp -> condIntReg GU x y
584 WordGeOp -> condIntReg GEU x y
585 WordEqOp -> condIntReg EQQ x y
586 WordNeOp -> condIntReg NE x y
587 WordLtOp -> condIntReg LU x y
588 WordLeOp -> condIntReg LEU x y
590 AddrGtOp -> condIntReg GU x y
591 AddrGeOp -> condIntReg GEU x y
592 AddrEqOp -> condIntReg EQQ x y
593 AddrNeOp -> condIntReg NE x y
594 AddrLtOp -> condIntReg LU x y
595 AddrLeOp -> condIntReg LEU x y
597 FloatGtOp -> condFltReg GTT x y
598 FloatGeOp -> condFltReg GE x y
599 FloatEqOp -> condFltReg EQQ x y
600 FloatNeOp -> condFltReg NE x y
601 FloatLtOp -> condFltReg LTT x y
602 FloatLeOp -> condFltReg LE x y
604 DoubleGtOp -> condFltReg GTT x y
605 DoubleGeOp -> condFltReg GE x y
606 DoubleEqOp -> condFltReg EQQ x y
607 DoubleNeOp -> condFltReg NE x y
608 DoubleLtOp -> condFltReg LTT x y
609 DoubleLeOp -> condFltReg LE x y
611 IntAddOp -> add_code L x y
612 IntSubOp -> sub_code L x y
613 IntQuotOp -> quot_code L x y True{-division-}
614 IntRemOp -> quot_code L x y False{-remainder-}
615 IntMulOp -> trivialCode (IMUL L) x y {-True-}
617 FloatAddOp -> trivialFCode FloatRep GADD x y
618 FloatSubOp -> trivialFCode FloatRep GSUB x y
619 FloatMulOp -> trivialFCode FloatRep GMUL x y
620 FloatDivOp -> trivialFCode FloatRep GDIV x y
622 DoubleAddOp -> trivialFCode DoubleRep GADD x y
623 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
624 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
625 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
627 AndOp -> trivialCode (AND L) x y {-True-}
628 OrOp -> trivialCode (OR L) x y {-True-}
629 XorOp -> trivialCode (XOR L) x y {-True-}
631 {- Shift ops on x86s have constraints on their source, it
632 either has to be Imm, CL or 1
633 => trivialCode's is not restrictive enough (sigh.)
636 SllOp -> shift_code (SHL L) x y {-False-}
637 SrlOp -> shift_code (SHR L) x y {-False-}
638 ISllOp -> shift_code (SHL L) x y {-False-}
639 ISraOp -> shift_code (SAR L) x y {-False-}
640 ISrlOp -> shift_code (SHR L) x y {-False-}
642 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
643 [promote x, promote y])
644 where promote x = StPrim Float2DoubleOp [x]
645 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
648 -> pprPanic "getRegister(x86,dyadic primop)"
649 (pprStixTrees [StPrim primop [x, y]])
653 shift_code :: (Imm -> Operand -> Instr)
658 {- Case1: shift length as immediate -}
659 -- Code is the same as the first eq. for trivialCode -- sigh.
660 shift_code instr x y{-amount-}
662 = getRegister x `thenUs` \ register ->
663 let op_imm = OpImm imm__2
665 let code = registerCode register dst
666 src = registerName register dst
669 if isFixed register && src /= dst
670 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
671 instr imm__2 (OpReg dst)]
672 else mkSeqInstr (instr imm__2 (OpReg src))
674 returnUs (Any IntRep code__2)
677 imm__2 = case imm of Just x -> x
679 {- Case2: shift length is complex (non-immediate) -}
680 -- Since ECX is always used as a spill temporary, we can't
681 -- use it here to do non-immediate shifts. No big deal --
682 -- they are only very rare, and we can use an equivalent
683 -- test-and-jump sequence which doesn't use ECX.
684 -- DO NOT USE REPLACE THIS CODE WITH THE "OBVIOUS" shl/shr/sar CODE,
685 -- SINCE IT WILL CAUSE SERIOUS PROBLEMS WITH THE SPILLER
686 shift_code instr x y{-amount-}
687 = getRegister x `thenUs` \ register1 ->
688 getRegister y `thenUs` \ register2 ->
689 getUniqLabelNCG `thenUs` \ lbl_test3 ->
690 getUniqLabelNCG `thenUs` \ lbl_test2 ->
691 getUniqLabelNCG `thenUs` \ lbl_test1 ->
692 getUniqLabelNCG `thenUs` \ lbl_test0 ->
693 getUniqLabelNCG `thenUs` \ lbl_after ->
694 getNewRegNCG IntRep `thenUs` \ tmp ->
696 = let src_val = registerName register1 dst
697 code_val = registerCode register1 dst
698 src_amt = registerName register2 tmp
699 code_amt = registerCode register2 tmp
706 COMMENT (_PK_ "begin shift sequence"),
707 MOV L (OpReg src_val) r_dst,
708 MOV L (OpReg src_amt) r_tmp,
710 BT L (ImmInt 4) r_tmp,
712 instr (ImmInt 16) r_dst,
715 BT L (ImmInt 3) r_tmp,
717 instr (ImmInt 8) r_dst,
720 BT L (ImmInt 2) r_tmp,
722 instr (ImmInt 4) r_dst,
725 BT L (ImmInt 1) r_tmp,
727 instr (ImmInt 2) r_dst,
730 BT L (ImmInt 0) r_tmp,
732 instr (ImmInt 1) r_dst,
735 COMMENT (_PK_ "end shift sequence")
738 returnUs (Any IntRep code__2)
741 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
743 add_code sz x (StInt y)
744 = getRegister x `thenUs` \ register ->
745 getNewRegNCG IntRep `thenUs` \ tmp ->
747 code = registerCode register tmp
748 src1 = registerName register tmp
749 src2 = ImmInt (fromInteger y)
752 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
755 returnUs (Any IntRep code__2)
758 = getRegister x `thenUs` \ register1 ->
759 getRegister y `thenUs` \ register2 ->
760 getNewRegNCG IntRep `thenUs` \ tmp1 ->
761 getNewRegNCG IntRep `thenUs` \ tmp2 ->
763 code1 = registerCode register1 tmp1 asmVoid
764 src1 = registerName register1 tmp1
765 code2 = registerCode register2 tmp2 asmVoid
766 src2 = registerName register2 tmp2
768 = asmParThen [code1, code2] .
769 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1))
773 returnUs (Any IntRep code__2)
776 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
778 sub_code sz x (StInt y)
779 = getRegister x `thenUs` \ register ->
780 getNewRegNCG IntRep `thenUs` \ tmp ->
782 code = registerCode register tmp
783 src1 = registerName register tmp
784 src2 = ImmInt (-(fromInteger y))
787 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
790 returnUs (Any IntRep code__2)
792 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
797 -> StixTree -> StixTree
798 -> Bool -- True => division, False => remainder operation
801 -- x must go into eax, edx must be a sign-extension of eax, and y
802 -- should go in some other register (or memory), so that we get
803 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
804 -- put y in memory (if it is not there already)
806 quot_code sz x (StInd pk mem) is_division
807 = getRegister x `thenUs` \ register1 ->
808 getNewRegNCG IntRep `thenUs` \ tmp1 ->
809 getAmode mem `thenUs` \ amode ->
811 code1 = registerCode register1 tmp1 asmVoid
812 src1 = registerName register1 tmp1
813 code2 = amodeCode amode asmVoid
814 src2 = amodeAddr amode
815 code__2 = asmParThen [code1, code2] .
816 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
818 IDIV sz (OpAddr src2)]
820 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
822 quot_code sz x (StInt i) is_division
823 = getRegister x `thenUs` \ register1 ->
824 getNewRegNCG IntRep `thenUs` \ tmp1 ->
826 code1 = registerCode register1 tmp1 asmVoid
827 src1 = registerName register1 tmp1
828 src2 = ImmInt (fromInteger i)
829 code__2 = asmParThen [code1] .
830 mkSeqInstrs [-- we put src2 in (ebx)
832 (OpAddr (AddrBaseIndex (Just ebx) Nothing
833 (ImmInt OFFSET_R1))),
834 MOV L (OpReg src1) (OpReg eax),
836 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
840 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
842 quot_code sz x y is_division
843 = getRegister x `thenUs` \ register1 ->
844 getNewRegNCG IntRep `thenUs` \ tmp1 ->
845 getRegister y `thenUs` \ register2 ->
846 getNewRegNCG IntRep `thenUs` \ tmp2 ->
848 code1 = registerCode register1 tmp1 asmVoid
849 src1 = registerName register1 tmp1
850 code2 = registerCode register2 tmp2 asmVoid
851 src2 = registerName register2 tmp2
852 code__2 = asmParThen [code1, code2] .
853 if src2 == ecx || src2 == esi
855 MOV L (OpReg src1) (OpReg eax),
859 else mkSeqInstrs [ -- we put src2 in (ebx)
861 (OpAddr (AddrBaseIndex (Just ebx) Nothing
862 (ImmInt OFFSET_R1))),
863 MOV L (OpReg src1) (OpReg eax),
865 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
869 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
870 -----------------------
872 getRegister (StInd pk mem)
873 = getAmode mem `thenUs` \ amode ->
875 code = amodeCode amode
876 src = amodeAddr amode
877 size = primRepToSize pk
879 if pk == DoubleRep || pk == FloatRep
880 then mkSeqInstr (GLD size src dst)
881 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
883 returnUs (Any pk code__2)
885 getRegister (StInt i)
887 src = ImmInt (fromInteger i)
888 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
890 returnUs (Any IntRep code)
895 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
897 returnUs (Any PtrRep code)
899 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
902 imm__2 = case imm of Just x -> x
904 #endif {- i386_TARGET_ARCH -}
905 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
906 #if sparc_TARGET_ARCH
908 getRegister (StDouble d)
909 = getUniqLabelNCG `thenUs` \ lbl ->
910 getNewRegNCG PtrRep `thenUs` \ tmp ->
911 let code dst = mkSeqInstrs [
914 DATA DF [ImmDouble d],
916 SETHI (HI (ImmCLbl lbl)) tmp,
917 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
919 returnUs (Any DoubleRep code)
921 getRegister (StPrim primop [x]) -- unary PrimOps
923 IntNegOp -> trivialUCode (SUB False False g0) x
924 NotOp -> trivialUCode (XNOR False g0) x
926 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
928 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
930 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
931 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
933 OrdOp -> coerceIntCode IntRep x
936 Float2IntOp -> coerceFP2Int x
937 Int2FloatOp -> coerceInt2FP FloatRep x
938 Double2IntOp -> coerceFP2Int x
939 Int2DoubleOp -> coerceInt2FP DoubleRep x
943 fixed_x = if is_float_op -- promote to double
944 then StPrim Float2DoubleOp [x]
947 getRegister (StCall fn cCallConv DoubleRep [x])
951 FloatExpOp -> (True, SLIT("exp"))
952 FloatLogOp -> (True, SLIT("log"))
953 FloatSqrtOp -> (True, SLIT("sqrt"))
955 FloatSinOp -> (True, SLIT("sin"))
956 FloatCosOp -> (True, SLIT("cos"))
957 FloatTanOp -> (True, SLIT("tan"))
959 FloatAsinOp -> (True, SLIT("asin"))
960 FloatAcosOp -> (True, SLIT("acos"))
961 FloatAtanOp -> (True, SLIT("atan"))
963 FloatSinhOp -> (True, SLIT("sinh"))
964 FloatCoshOp -> (True, SLIT("cosh"))
965 FloatTanhOp -> (True, SLIT("tanh"))
967 DoubleExpOp -> (False, SLIT("exp"))
968 DoubleLogOp -> (False, SLIT("log"))
969 DoubleSqrtOp -> (True, SLIT("sqrt"))
971 DoubleSinOp -> (False, SLIT("sin"))
972 DoubleCosOp -> (False, SLIT("cos"))
973 DoubleTanOp -> (False, SLIT("tan"))
975 DoubleAsinOp -> (False, SLIT("asin"))
976 DoubleAcosOp -> (False, SLIT("acos"))
977 DoubleAtanOp -> (False, SLIT("atan"))
979 DoubleSinhOp -> (False, SLIT("sinh"))
980 DoubleCoshOp -> (False, SLIT("cosh"))
981 DoubleTanhOp -> (False, SLIT("tanh"))
982 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
984 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
986 CharGtOp -> condIntReg GTT x y
987 CharGeOp -> condIntReg GE x y
988 CharEqOp -> condIntReg EQQ x y
989 CharNeOp -> condIntReg NE x y
990 CharLtOp -> condIntReg LTT x y
991 CharLeOp -> condIntReg LE x y
993 IntGtOp -> condIntReg GTT x y
994 IntGeOp -> condIntReg GE x y
995 IntEqOp -> condIntReg EQQ x y
996 IntNeOp -> condIntReg NE x y
997 IntLtOp -> condIntReg LTT x y
998 IntLeOp -> condIntReg LE x y
1000 WordGtOp -> condIntReg GU x y
1001 WordGeOp -> condIntReg GEU x y
1002 WordEqOp -> condIntReg EQQ x y
1003 WordNeOp -> condIntReg NE x y
1004 WordLtOp -> condIntReg LU x y
1005 WordLeOp -> condIntReg LEU x y
1007 AddrGtOp -> condIntReg GU x y
1008 AddrGeOp -> condIntReg GEU x y
1009 AddrEqOp -> condIntReg EQQ x y
1010 AddrNeOp -> condIntReg NE x y
1011 AddrLtOp -> condIntReg LU x y
1012 AddrLeOp -> condIntReg LEU x y
1014 FloatGtOp -> condFltReg GTT x y
1015 FloatGeOp -> condFltReg GE x y
1016 FloatEqOp -> condFltReg EQQ x y
1017 FloatNeOp -> condFltReg NE x y
1018 FloatLtOp -> condFltReg LTT x y
1019 FloatLeOp -> condFltReg LE x y
1021 DoubleGtOp -> condFltReg GTT x y
1022 DoubleGeOp -> condFltReg GE x y
1023 DoubleEqOp -> condFltReg EQQ x y
1024 DoubleNeOp -> condFltReg NE x y
1025 DoubleLtOp -> condFltReg LTT x y
1026 DoubleLeOp -> condFltReg LE x y
1028 IntAddOp -> trivialCode (ADD False False) x y
1029 IntSubOp -> trivialCode (SUB False False) x y
1031 -- ToDo: teach about V8+ SPARC mul/div instructions
1032 IntMulOp -> imul_div SLIT(".umul") x y
1033 IntQuotOp -> imul_div SLIT(".div") x y
1034 IntRemOp -> imul_div SLIT(".rem") x y
1036 FloatAddOp -> trivialFCode FloatRep FADD x y
1037 FloatSubOp -> trivialFCode FloatRep FSUB x y
1038 FloatMulOp -> trivialFCode FloatRep FMUL x y
1039 FloatDivOp -> trivialFCode FloatRep FDIV x y
1041 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1042 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1043 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1044 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1046 AndOp -> trivialCode (AND False) x y
1047 OrOp -> trivialCode (OR False) x y
1048 XorOp -> trivialCode (XOR False) x y
1049 SllOp -> trivialCode SLL x y
1050 SrlOp -> trivialCode SRL x y
1052 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1053 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1054 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1056 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1057 where promote x = StPrim Float2DoubleOp [x]
1058 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1059 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1061 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1063 getRegister (StInd pk mem)
1064 = getAmode mem `thenUs` \ amode ->
1066 code = amodeCode amode
1067 src = amodeAddr amode
1068 size = primRepToSize pk
1069 code__2 dst = code . mkSeqInstr (LD size src dst)
1071 returnUs (Any pk code__2)
1073 getRegister (StInt i)
1076 src = ImmInt (fromInteger i)
1077 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1079 returnUs (Any IntRep code)
1084 code dst = mkSeqInstrs [
1085 SETHI (HI imm__2) dst,
1086 OR False dst (RIImm (LO imm__2)) dst]
1088 returnUs (Any PtrRep code)
1091 imm__2 = case imm of Just x -> x
1093 #endif {- sparc_TARGET_ARCH -}
1096 %************************************************************************
1098 \subsection{The @Amode@ type}
1100 %************************************************************************
1102 @Amode@s: Memory addressing modes passed up the tree.
1104 data Amode = Amode MachRegsAddr InstrBlock
1106 amodeAddr (Amode addr _) = addr
1107 amodeCode (Amode _ code) = code
1110 Now, given a tree (the argument to an StInd) that references memory,
1111 produce a suitable addressing mode.
1114 getAmode :: StixTree -> UniqSM Amode
1116 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1118 #if alpha_TARGET_ARCH
1120 getAmode (StPrim IntSubOp [x, StInt i])
1121 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1122 getRegister x `thenUs` \ register ->
1124 code = registerCode register tmp
1125 reg = registerName register tmp
1126 off = ImmInt (-(fromInteger i))
1128 returnUs (Amode (AddrRegImm reg off) code)
1130 getAmode (StPrim IntAddOp [x, StInt i])
1131 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1132 getRegister x `thenUs` \ register ->
1134 code = registerCode register tmp
1135 reg = registerName register tmp
1136 off = ImmInt (fromInteger i)
1138 returnUs (Amode (AddrRegImm reg off) code)
1142 = returnUs (Amode (AddrImm imm__2) id)
1145 imm__2 = case imm of Just x -> x
1148 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1149 getRegister other `thenUs` \ register ->
1151 code = registerCode register tmp
1152 reg = registerName register tmp
1154 returnUs (Amode (AddrReg reg) code)
1156 #endif {- alpha_TARGET_ARCH -}
1157 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1158 #if i386_TARGET_ARCH
1160 getAmode (StPrim IntSubOp [x, StInt i])
1161 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1162 getRegister x `thenUs` \ register ->
1164 code = registerCode register tmp
1165 reg = registerName register tmp
1166 off = ImmInt (-(fromInteger i))
1168 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1170 getAmode (StPrim IntAddOp [x, StInt i])
1173 code = mkSeqInstrs []
1175 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1178 imm__2 = case imm of Just x -> x
1180 getAmode (StPrim IntAddOp [x, StInt i])
1181 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1182 getRegister x `thenUs` \ register ->
1184 code = registerCode register tmp
1185 reg = registerName register tmp
1186 off = ImmInt (fromInteger i)
1188 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1190 getAmode (StPrim IntAddOp [x, StPrim SllOp [y, StInt shift]])
1191 | shift == 0 || shift == 1 || shift == 2 || shift == 3
1192 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1193 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1194 getRegister x `thenUs` \ register1 ->
1195 getRegister y `thenUs` \ register2 ->
1197 code1 = registerCode register1 tmp1 asmVoid
1198 reg1 = registerName register1 tmp1
1199 code2 = registerCode register2 tmp2 asmVoid
1200 reg2 = registerName register2 tmp2
1201 code__2 = asmParThen [code1, code2]
1202 base = case shift of 0 -> 1 ; 1 -> 2; 2 -> 4; 3 -> 8
1204 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,base)) (ImmInt 0))
1210 code = mkSeqInstrs []
1212 returnUs (Amode (ImmAddr imm__2 0) code)
1215 imm__2 = case imm of Just x -> x
1218 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1219 getRegister other `thenUs` \ register ->
1221 code = registerCode register tmp
1222 reg = registerName register tmp
1225 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1227 #endif {- i386_TARGET_ARCH -}
1228 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1229 #if sparc_TARGET_ARCH
1231 getAmode (StPrim IntSubOp [x, StInt i])
1233 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1234 getRegister x `thenUs` \ register ->
1236 code = registerCode register tmp
1237 reg = registerName register tmp
1238 off = ImmInt (-(fromInteger i))
1240 returnUs (Amode (AddrRegImm reg off) code)
1243 getAmode (StPrim IntAddOp [x, StInt i])
1245 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1246 getRegister x `thenUs` \ register ->
1248 code = registerCode register tmp
1249 reg = registerName register tmp
1250 off = ImmInt (fromInteger i)
1252 returnUs (Amode (AddrRegImm reg off) code)
1254 getAmode (StPrim IntAddOp [x, y])
1255 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1256 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1257 getRegister x `thenUs` \ register1 ->
1258 getRegister y `thenUs` \ register2 ->
1260 code1 = registerCode register1 tmp1 asmVoid
1261 reg1 = registerName register1 tmp1
1262 code2 = registerCode register2 tmp2 asmVoid
1263 reg2 = registerName register2 tmp2
1264 code__2 = asmParThen [code1, code2]
1266 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1270 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1272 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1274 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1277 imm__2 = case imm of Just x -> x
1280 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1281 getRegister other `thenUs` \ register ->
1283 code = registerCode register tmp
1284 reg = registerName register tmp
1287 returnUs (Amode (AddrRegImm reg off) code)
1289 #endif {- sparc_TARGET_ARCH -}
1292 %************************************************************************
1294 \subsection{The @CondCode@ type}
1296 %************************************************************************
1298 Condition codes passed up the tree.
1300 data CondCode = CondCode Bool Cond InstrBlock
1302 condName (CondCode _ cond _) = cond
1303 condFloat (CondCode is_float _ _) = is_float
1304 condCode (CondCode _ _ code) = code
1307 Set up a condition code for a conditional branch.
1310 getCondCode :: StixTree -> UniqSM CondCode
1312 #if alpha_TARGET_ARCH
1313 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1314 #endif {- alpha_TARGET_ARCH -}
1315 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1317 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1318 -- yes, they really do seem to want exactly the same!
1320 getCondCode (StPrim primop [x, y])
1322 CharGtOp -> condIntCode GTT x y
1323 CharGeOp -> condIntCode GE x y
1324 CharEqOp -> condIntCode EQQ x y
1325 CharNeOp -> condIntCode NE x y
1326 CharLtOp -> condIntCode LTT x y
1327 CharLeOp -> condIntCode LE x y
1329 IntGtOp -> condIntCode GTT x y
1330 IntGeOp -> condIntCode GE x y
1331 IntEqOp -> condIntCode EQQ x y
1332 IntNeOp -> condIntCode NE x y
1333 IntLtOp -> condIntCode LTT x y
1334 IntLeOp -> condIntCode LE x y
1336 WordGtOp -> condIntCode GU x y
1337 WordGeOp -> condIntCode GEU x y
1338 WordEqOp -> condIntCode EQQ x y
1339 WordNeOp -> condIntCode NE x y
1340 WordLtOp -> condIntCode LU x y
1341 WordLeOp -> condIntCode LEU x y
1343 AddrGtOp -> condIntCode GU x y
1344 AddrGeOp -> condIntCode GEU x y
1345 AddrEqOp -> condIntCode EQQ x y
1346 AddrNeOp -> condIntCode NE x y
1347 AddrLtOp -> condIntCode LU x y
1348 AddrLeOp -> condIntCode LEU x y
1350 FloatGtOp -> condFltCode GTT x y
1351 FloatGeOp -> condFltCode GE x y
1352 FloatEqOp -> condFltCode EQQ x y
1353 FloatNeOp -> condFltCode NE x y
1354 FloatLtOp -> condFltCode LTT x y
1355 FloatLeOp -> condFltCode LE x y
1357 DoubleGtOp -> condFltCode GTT x y
1358 DoubleGeOp -> condFltCode GE x y
1359 DoubleEqOp -> condFltCode EQQ x y
1360 DoubleNeOp -> condFltCode NE x y
1361 DoubleLtOp -> condFltCode LTT x y
1362 DoubleLeOp -> condFltCode LE x y
1364 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1369 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1370 passed back up the tree.
1373 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1375 #if alpha_TARGET_ARCH
1376 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1377 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1378 #endif {- alpha_TARGET_ARCH -}
1380 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1381 #if i386_TARGET_ARCH
1383 condIntCode cond (StInd _ x) y
1385 = getAmode x `thenUs` \ amode ->
1387 code1 = amodeCode amode asmVoid
1388 y__2 = amodeAddr amode
1389 code__2 = asmParThen [code1] .
1390 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1392 returnUs (CondCode False cond code__2)
1395 imm__2 = case imm of Just x -> x
1397 condIntCode cond x (StInt 0)
1398 = getRegister x `thenUs` \ register1 ->
1399 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1401 code1 = registerCode register1 tmp1 asmVoid
1402 src1 = registerName register1 tmp1
1403 code__2 = asmParThen [code1] .
1404 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1406 returnUs (CondCode False cond code__2)
1408 condIntCode cond x y
1410 = getRegister x `thenUs` \ register1 ->
1411 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1413 code1 = registerCode register1 tmp1 asmVoid
1414 src1 = registerName register1 tmp1
1415 code__2 = asmParThen [code1] .
1416 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1418 returnUs (CondCode False cond code__2)
1421 imm__2 = case imm of Just x -> x
1423 condIntCode cond (StInd _ x) y
1424 = getAmode x `thenUs` \ amode ->
1425 getRegister y `thenUs` \ register2 ->
1426 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1428 code1 = amodeCode amode asmVoid
1429 src1 = amodeAddr amode
1430 code2 = registerCode register2 tmp2 asmVoid
1431 src2 = registerName register2 tmp2
1432 code__2 = asmParThen [code1, code2] .
1433 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1435 returnUs (CondCode False cond code__2)
1437 condIntCode cond y (StInd _ x)
1438 = getAmode x `thenUs` \ amode ->
1439 getRegister y `thenUs` \ register2 ->
1440 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1442 code1 = amodeCode amode asmVoid
1443 src1 = amodeAddr amode
1444 code2 = registerCode register2 tmp2 asmVoid
1445 src2 = registerName register2 tmp2
1446 code__2 = asmParThen [code1, code2] .
1447 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1449 returnUs (CondCode False cond code__2)
1451 condIntCode cond x y
1452 = getRegister x `thenUs` \ register1 ->
1453 getRegister y `thenUs` \ register2 ->
1454 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1455 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1457 code1 = registerCode register1 tmp1 asmVoid
1458 src1 = registerName register1 tmp1
1459 code2 = registerCode register2 tmp2 asmVoid
1460 src2 = registerName register2 tmp2
1461 code__2 = asmParThen [code1, code2] .
1462 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1464 returnUs (CondCode False cond code__2)
1467 condFltCode cond x y
1468 = getRegister x `thenUs` \ register1 ->
1469 getRegister y `thenUs` \ register2 ->
1470 getNewRegNCG (registerRep register1)
1472 getNewRegNCG (registerRep register2)
1474 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1476 pk1 = registerRep register1
1477 code1 = registerCode register1 tmp1
1478 src1 = registerName register1 tmp1
1480 pk2 = registerRep register2
1481 code2 = registerCode register2 tmp2
1482 src2 = registerName register2 tmp2
1484 code__2 = asmParThen [code1 asmVoid, code2 asmVoid] .
1485 mkSeqInstr (GCMP (primRepToSize pk1) src1 src2)
1487 {- On the 486, the flags set by FP compare are the unsigned ones!
1488 (This looks like a HACK to me. WDP 96/03)
1490 fix_FP_cond :: Cond -> Cond
1492 fix_FP_cond GE = GEU
1493 fix_FP_cond GTT = GU
1494 fix_FP_cond LTT = LU
1495 fix_FP_cond LE = LEU
1496 fix_FP_cond any = any
1498 returnUs (CondCode True (fix_FP_cond cond) code__2)
1502 #endif {- i386_TARGET_ARCH -}
1503 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1504 #if sparc_TARGET_ARCH
1506 condIntCode cond x (StInt y)
1508 = getRegister x `thenUs` \ register ->
1509 getNewRegNCG IntRep `thenUs` \ tmp ->
1511 code = registerCode register tmp
1512 src1 = registerName register tmp
1513 src2 = ImmInt (fromInteger y)
1514 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1516 returnUs (CondCode False cond code__2)
1518 condIntCode cond x y
1519 = getRegister x `thenUs` \ register1 ->
1520 getRegister y `thenUs` \ register2 ->
1521 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1522 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1524 code1 = registerCode register1 tmp1 asmVoid
1525 src1 = registerName register1 tmp1
1526 code2 = registerCode register2 tmp2 asmVoid
1527 src2 = registerName register2 tmp2
1528 code__2 = asmParThen [code1, code2] .
1529 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1531 returnUs (CondCode False cond code__2)
1534 condFltCode cond x y
1535 = getRegister x `thenUs` \ register1 ->
1536 getRegister y `thenUs` \ register2 ->
1537 getNewRegNCG (registerRep register1)
1539 getNewRegNCG (registerRep register2)
1541 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1543 promote x = asmInstr (FxTOy F DF x tmp)
1545 pk1 = registerRep register1
1546 code1 = registerCode register1 tmp1
1547 src1 = registerName register1 tmp1
1549 pk2 = registerRep register2
1550 code2 = registerCode register2 tmp2
1551 src2 = registerName register2 tmp2
1555 asmParThen [code1 asmVoid, code2 asmVoid] .
1556 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1557 else if pk1 == FloatRep then
1558 asmParThen [code1 (promote src1), code2 asmVoid] .
1559 mkSeqInstr (FCMP True DF tmp src2)
1561 asmParThen [code1 asmVoid, code2 (promote src2)] .
1562 mkSeqInstr (FCMP True DF src1 tmp)
1564 returnUs (CondCode True cond code__2)
1566 #endif {- sparc_TARGET_ARCH -}
1569 %************************************************************************
1571 \subsection{Generating assignments}
1573 %************************************************************************
1575 Assignments are really at the heart of the whole code generation
1576 business. Almost all top-level nodes of any real importance are
1577 assignments, which correspond to loads, stores, or register transfers.
1578 If we're really lucky, some of the register transfers will go away,
1579 because we can use the destination register to complete the code
1580 generation for the right hand side. This only fails when the right
1581 hand side is forced into a fixed register (e.g. the result of a call).
1584 assignIntCode, assignFltCode
1585 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1587 #if alpha_TARGET_ARCH
1589 assignIntCode pk (StInd _ dst) src
1590 = getNewRegNCG IntRep `thenUs` \ tmp ->
1591 getAmode dst `thenUs` \ amode ->
1592 getRegister src `thenUs` \ register ->
1594 code1 = amodeCode amode asmVoid
1595 dst__2 = amodeAddr amode
1596 code2 = registerCode register tmp asmVoid
1597 src__2 = registerName register tmp
1598 sz = primRepToSize pk
1599 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1603 assignIntCode pk dst src
1604 = getRegister dst `thenUs` \ register1 ->
1605 getRegister src `thenUs` \ register2 ->
1607 dst__2 = registerName register1 zeroh
1608 code = registerCode register2 dst__2
1609 src__2 = registerName register2 dst__2
1610 code__2 = if isFixed register2
1611 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1616 #endif {- alpha_TARGET_ARCH -}
1617 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1618 #if i386_TARGET_ARCH
1620 assignIntCode pk dd@(StInd _ dst) src
1621 = getAmode dst `thenUs` \ amode ->
1622 get_op_RI src `thenUs` \ (codesrc, opsrc) ->
1624 code1 = amodeCode amode asmVoid
1625 dst__2 = amodeAddr amode
1626 code__2 = asmParThen [code1, codesrc asmVoid] .
1627 mkSeqInstr (MOV (primRepToSize pk) opsrc (OpAddr dst__2))
1633 -> UniqSM (InstrBlock,Operand) -- code, operator
1637 = returnUs (asmParThen [], OpImm imm_op)
1640 imm_op = case imm of Just x -> x
1643 = getRegister op `thenUs` \ register ->
1644 getNewRegNCG (registerRep register)
1647 code = registerCode register tmp
1648 reg = registerName register tmp
1650 returnUs (code, OpReg reg)
1652 assignIntCode pk dst (StInd pks src)
1653 = getNewRegNCG IntRep `thenUs` \ tmp ->
1654 getAmode src `thenUs` \ amode ->
1655 getRegister dst `thenUs` \ register ->
1657 code1 = amodeCode amode asmVoid
1658 src__2 = amodeAddr amode
1659 code2 = registerCode register tmp asmVoid
1660 dst__2 = registerName register tmp
1661 szs = primRepToSize pks
1662 code__2 = asmParThen [code1, code2] .
1664 L -> mkSeqInstr (MOV L (OpAddr src__2) (OpReg dst__2))
1665 B -> mkSeqInstr (MOVZxL B (OpAddr src__2) (OpReg dst__2))
1669 assignIntCode pk dst src
1670 = getRegister dst `thenUs` \ register1 ->
1671 getRegister src `thenUs` \ register2 ->
1672 getNewRegNCG IntRep `thenUs` \ tmp ->
1674 dst__2 = registerName register1 tmp
1675 code = registerCode register2 dst__2
1676 src__2 = registerName register2 dst__2
1677 code__2 = if isFixed register2 && dst__2 /= src__2
1678 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1683 #endif {- i386_TARGET_ARCH -}
1684 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1685 #if sparc_TARGET_ARCH
1687 assignIntCode pk (StInd _ dst) src
1688 = getNewRegNCG IntRep `thenUs` \ tmp ->
1689 getAmode dst `thenUs` \ amode ->
1690 getRegister src `thenUs` \ register ->
1692 code1 = amodeCode amode asmVoid
1693 dst__2 = amodeAddr amode
1694 code2 = registerCode register tmp asmVoid
1695 src__2 = registerName register tmp
1696 sz = primRepToSize pk
1697 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1701 assignIntCode pk dst src
1702 = getRegister dst `thenUs` \ register1 ->
1703 getRegister src `thenUs` \ register2 ->
1705 dst__2 = registerName register1 g0
1706 code = registerCode register2 dst__2
1707 src__2 = registerName register2 dst__2
1708 code__2 = if isFixed register2
1709 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1714 #endif {- sparc_TARGET_ARCH -}
1717 % --------------------------------
1718 Floating-point assignments:
1719 % --------------------------------
1721 #if alpha_TARGET_ARCH
1723 assignFltCode pk (StInd _ dst) src
1724 = getNewRegNCG pk `thenUs` \ tmp ->
1725 getAmode dst `thenUs` \ amode ->
1726 getRegister src `thenUs` \ register ->
1728 code1 = amodeCode amode asmVoid
1729 dst__2 = amodeAddr amode
1730 code2 = registerCode register tmp asmVoid
1731 src__2 = registerName register tmp
1732 sz = primRepToSize pk
1733 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1737 assignFltCode pk dst src
1738 = getRegister dst `thenUs` \ register1 ->
1739 getRegister src `thenUs` \ register2 ->
1741 dst__2 = registerName register1 zeroh
1742 code = registerCode register2 dst__2
1743 src__2 = registerName register2 dst__2
1744 code__2 = if isFixed register2
1745 then code . mkSeqInstr (FMOV src__2 dst__2)
1750 #endif {- alpha_TARGET_ARCH -}
1751 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1752 #if i386_TARGET_ARCH
1754 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1755 = getNewRegNCG IntRep `thenUs` \ tmp ->
1756 getAmode src `thenUs` \ amodesrc ->
1757 getAmode dst `thenUs` \ amodedst ->
1759 codesrc1 = amodeCode amodesrc asmVoid
1760 addrsrc1 = amodeAddr amodesrc
1761 codedst1 = amodeCode amodedst asmVoid
1762 addrdst1 = amodeAddr amodedst
1763 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1764 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1766 code__2 = asmParThen [codesrc1, codedst1] .
1767 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1768 MOV L (OpReg tmp) (OpAddr addrdst1)]
1771 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1772 MOV L (OpReg tmp) (OpAddr addrdst2)]
1777 assignFltCode pk (StInd _ dst) src
1778 = getNewRegNCG pk `thenUs` \ tmp ->
1779 getAmode dst `thenUs` \ amode ->
1780 getRegister src `thenUs` \ register ->
1782 sz = primRepToSize pk
1783 dst__2 = amodeAddr amode
1785 code1 = amodeCode amode asmVoid
1786 code2 = registerCode register tmp asmVoid
1788 src__2 = registerName register tmp
1790 code__2 = asmParThen [code1, code2] .
1791 mkSeqInstr (GST sz src__2 dst__2)
1795 assignFltCode pk dst src
1796 = getRegister dst `thenUs` \ register1 ->
1797 getRegister src `thenUs` \ register2 ->
1798 getNewRegNCG pk `thenUs` \ tmp ->
1800 -- the register which is dst
1801 dst__2 = registerName register1 tmp
1802 -- the register into which src is computed, preferably dst__2
1803 src__2 = registerName register2 dst__2
1804 -- code to compute src into src__2
1805 code = registerCode register2 dst__2
1807 code__2 = if isFixed register2
1808 then code . mkSeqInstr (GMOV src__2 dst__2)
1813 #endif {- i386_TARGET_ARCH -}
1814 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1815 #if sparc_TARGET_ARCH
1817 assignFltCode pk (StInd _ dst) src
1818 = getNewRegNCG pk `thenUs` \ tmp1 ->
1819 getAmode dst `thenUs` \ amode ->
1820 getRegister src `thenUs` \ register ->
1822 sz = primRepToSize pk
1823 dst__2 = amodeAddr amode
1825 code1 = amodeCode amode asmVoid
1826 code2 = registerCode register tmp1 asmVoid
1828 src__2 = registerName register tmp1
1829 pk__2 = registerRep register
1830 sz__2 = primRepToSize pk__2
1832 code__2 = asmParThen [code1, code2] .
1834 mkSeqInstr (ST sz src__2 dst__2)
1836 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1840 assignFltCode pk dst src
1841 = getRegister dst `thenUs` \ register1 ->
1842 getRegister src `thenUs` \ register2 ->
1844 pk__2 = registerRep register2
1845 sz__2 = primRepToSize pk__2
1847 getNewRegNCG pk__2 `thenUs` \ tmp ->
1849 sz = primRepToSize pk
1850 dst__2 = registerName register1 g0 -- must be Fixed
1853 reg__2 = if pk /= pk__2 then tmp else dst__2
1855 code = registerCode register2 reg__2
1857 src__2 = registerName register2 reg__2
1861 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1862 else if isFixed register2 then
1863 code . mkSeqInstr (FMOV sz src__2 dst__2)
1869 #endif {- sparc_TARGET_ARCH -}
1872 %************************************************************************
1874 \subsection{Generating an unconditional branch}
1876 %************************************************************************
1878 We accept two types of targets: an immediate CLabel or a tree that
1879 gets evaluated into a register. Any CLabels which are AsmTemporaries
1880 are assumed to be in the local block of code, close enough for a
1881 branch instruction. Other CLabels are assumed to be far away.
1883 (If applicable) Do not fill the delay slots here; you will confuse the
1887 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1889 #if alpha_TARGET_ARCH
1891 genJump (StCLbl lbl)
1892 | isAsmTemp lbl = returnInstr (BR target)
1893 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1895 target = ImmCLbl lbl
1898 = getRegister tree `thenUs` \ register ->
1899 getNewRegNCG PtrRep `thenUs` \ tmp ->
1901 dst = registerName register pv
1902 code = registerCode register pv
1903 target = registerName register pv
1905 if isFixed register then
1906 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1908 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1910 #endif {- alpha_TARGET_ARCH -}
1911 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1912 #if i386_TARGET_ARCH
1915 genJump (StCLbl lbl)
1916 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1917 | otherwise = returnInstrs [JMP (OpImm target)]
1919 target = ImmCLbl lbl
1922 genJump (StInd pk mem)
1923 = getAmode mem `thenUs` \ amode ->
1925 code = amodeCode amode
1926 target = amodeAddr amode
1928 returnSeq code [JMP (OpAddr target)]
1932 = returnInstr (JMP (OpImm target))
1935 = getRegister tree `thenUs` \ register ->
1936 getNewRegNCG PtrRep `thenUs` \ tmp ->
1938 code = registerCode register tmp
1939 target = registerName register tmp
1941 returnSeq code [JMP (OpReg target)]
1944 target = case imm of Just x -> x
1946 #endif {- i386_TARGET_ARCH -}
1947 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1948 #if sparc_TARGET_ARCH
1950 genJump (StCLbl lbl)
1951 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1952 | otherwise = returnInstrs [CALL target 0 True, NOP]
1954 target = ImmCLbl lbl
1957 = getRegister tree `thenUs` \ register ->
1958 getNewRegNCG PtrRep `thenUs` \ tmp ->
1960 code = registerCode register tmp
1961 target = registerName register tmp
1963 returnSeq code [JMP (AddrRegReg target g0), NOP]
1965 #endif {- sparc_TARGET_ARCH -}
1968 %************************************************************************
1970 \subsection{Conditional jumps}
1972 %************************************************************************
1974 Conditional jumps are always to local labels, so we can use branch
1975 instructions. We peek at the arguments to decide what kind of
1978 ALPHA: For comparisons with 0, we're laughing, because we can just do
1979 the desired conditional branch.
1981 I386: First, we have to ensure that the condition
1982 codes are set according to the supplied comparison operation.
1984 SPARC: First, we have to ensure that the condition codes are set
1985 according to the supplied comparison operation. We generate slightly
1986 different code for floating point comparisons, because a floating
1987 point operation cannot directly precede a @BF@. We assume the worst
1988 and fill that slot with a @NOP@.
1990 SPARC: Do not fill the delay slots here; you will confuse the register
1995 :: CLabel -- the branch target
1996 -> StixTree -- the condition on which to branch
1997 -> UniqSM InstrBlock
1999 #if alpha_TARGET_ARCH
2001 genCondJump lbl (StPrim op [x, StInt 0])
2002 = getRegister x `thenUs` \ register ->
2003 getNewRegNCG (registerRep register)
2006 code = registerCode register tmp
2007 value = registerName register tmp
2008 pk = registerRep register
2009 target = ImmCLbl lbl
2011 returnSeq code [BI (cmpOp op) value target]
2013 cmpOp CharGtOp = GTT
2015 cmpOp CharEqOp = EQQ
2017 cmpOp CharLtOp = LTT
2026 cmpOp WordGeOp = ALWAYS
2027 cmpOp WordEqOp = EQQ
2029 cmpOp WordLtOp = NEVER
2030 cmpOp WordLeOp = EQQ
2032 cmpOp AddrGeOp = ALWAYS
2033 cmpOp AddrEqOp = EQQ
2035 cmpOp AddrLtOp = NEVER
2036 cmpOp AddrLeOp = EQQ
2038 genCondJump lbl (StPrim op [x, StDouble 0.0])
2039 = getRegister x `thenUs` \ register ->
2040 getNewRegNCG (registerRep register)
2043 code = registerCode register tmp
2044 value = registerName register tmp
2045 pk = registerRep register
2046 target = ImmCLbl lbl
2048 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2050 cmpOp FloatGtOp = GTT
2051 cmpOp FloatGeOp = GE
2052 cmpOp FloatEqOp = EQQ
2053 cmpOp FloatNeOp = NE
2054 cmpOp FloatLtOp = LTT
2055 cmpOp FloatLeOp = LE
2056 cmpOp DoubleGtOp = GTT
2057 cmpOp DoubleGeOp = GE
2058 cmpOp DoubleEqOp = EQQ
2059 cmpOp DoubleNeOp = NE
2060 cmpOp DoubleLtOp = LTT
2061 cmpOp DoubleLeOp = LE
2063 genCondJump lbl (StPrim op [x, y])
2065 = trivialFCode pr instr x y `thenUs` \ register ->
2066 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2068 code = registerCode register tmp
2069 result = registerName register tmp
2070 target = ImmCLbl lbl
2072 returnUs (code . mkSeqInstr (BF cond result target))
2074 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2076 fltCmpOp op = case op of
2090 (instr, cond) = case op of
2091 FloatGtOp -> (FCMP TF LE, EQQ)
2092 FloatGeOp -> (FCMP TF LTT, EQQ)
2093 FloatEqOp -> (FCMP TF EQQ, NE)
2094 FloatNeOp -> (FCMP TF EQQ, EQQ)
2095 FloatLtOp -> (FCMP TF LTT, NE)
2096 FloatLeOp -> (FCMP TF LE, NE)
2097 DoubleGtOp -> (FCMP TF LE, EQQ)
2098 DoubleGeOp -> (FCMP TF LTT, EQQ)
2099 DoubleEqOp -> (FCMP TF EQQ, NE)
2100 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2101 DoubleLtOp -> (FCMP TF LTT, NE)
2102 DoubleLeOp -> (FCMP TF LE, NE)
2104 genCondJump lbl (StPrim op [x, y])
2105 = trivialCode instr x y `thenUs` \ register ->
2106 getNewRegNCG IntRep `thenUs` \ tmp ->
2108 code = registerCode register tmp
2109 result = registerName register tmp
2110 target = ImmCLbl lbl
2112 returnUs (code . mkSeqInstr (BI cond result target))
2114 (instr, cond) = case op of
2115 CharGtOp -> (CMP LE, EQQ)
2116 CharGeOp -> (CMP LTT, EQQ)
2117 CharEqOp -> (CMP EQQ, NE)
2118 CharNeOp -> (CMP EQQ, EQQ)
2119 CharLtOp -> (CMP LTT, NE)
2120 CharLeOp -> (CMP LE, NE)
2121 IntGtOp -> (CMP LE, EQQ)
2122 IntGeOp -> (CMP LTT, EQQ)
2123 IntEqOp -> (CMP EQQ, NE)
2124 IntNeOp -> (CMP EQQ, EQQ)
2125 IntLtOp -> (CMP LTT, NE)
2126 IntLeOp -> (CMP LE, NE)
2127 WordGtOp -> (CMP ULE, EQQ)
2128 WordGeOp -> (CMP ULT, EQQ)
2129 WordEqOp -> (CMP EQQ, NE)
2130 WordNeOp -> (CMP EQQ, EQQ)
2131 WordLtOp -> (CMP ULT, NE)
2132 WordLeOp -> (CMP ULE, NE)
2133 AddrGtOp -> (CMP ULE, EQQ)
2134 AddrGeOp -> (CMP ULT, EQQ)
2135 AddrEqOp -> (CMP EQQ, NE)
2136 AddrNeOp -> (CMP EQQ, EQQ)
2137 AddrLtOp -> (CMP ULT, NE)
2138 AddrLeOp -> (CMP ULE, NE)
2140 #endif {- alpha_TARGET_ARCH -}
2141 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2142 #if i386_TARGET_ARCH
2144 genCondJump lbl bool
2145 = getCondCode bool `thenUs` \ condition ->
2147 code = condCode condition
2148 cond = condName condition
2149 target = ImmCLbl lbl
2151 returnSeq code [JXX cond lbl]
2153 #endif {- i386_TARGET_ARCH -}
2154 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2155 #if sparc_TARGET_ARCH
2157 genCondJump lbl bool
2158 = getCondCode bool `thenUs` \ condition ->
2160 code = condCode condition
2161 cond = condName condition
2162 target = ImmCLbl lbl
2165 if condFloat condition then
2166 [NOP, BF cond False target, NOP]
2168 [BI cond False target, NOP]
2171 #endif {- sparc_TARGET_ARCH -}
2174 %************************************************************************
2176 \subsection{Generating C calls}
2178 %************************************************************************
2180 Now the biggest nightmare---calls. Most of the nastiness is buried in
2181 @get_arg@, which moves the arguments to the correct registers/stack
2182 locations. Apart from that, the code is easy.
2184 (If applicable) Do not fill the delay slots here; you will confuse the
2189 :: FAST_STRING -- function to call
2191 -> PrimRep -- type of the result
2192 -> [StixTree] -- arguments (of mixed type)
2193 -> UniqSM InstrBlock
2195 #if alpha_TARGET_ARCH
2197 genCCall fn cconv kind args
2198 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2199 `thenUs` \ ((unused,_), argCode) ->
2201 nRegs = length allArgRegs - length unused
2202 code = asmParThen (map ($ asmVoid) argCode)
2205 LDA pv (AddrImm (ImmLab (ptext fn))),
2206 JSR ra (AddrReg pv) nRegs,
2207 LDGP gp (AddrReg ra)]
2209 ------------------------
2210 {- Try to get a value into a specific register (or registers) for
2211 a call. The first 6 arguments go into the appropriate
2212 argument register (separate registers for integer and floating
2213 point arguments, but used in lock-step), and the remaining
2214 arguments are dumped to the stack, beginning at 0(sp). Our
2215 first argument is a pair of the list of remaining argument
2216 registers to be assigned for this call and the next stack
2217 offset to use for overflowing arguments. This way,
2218 @get_Arg@ can be applied to all of a call's arguments using
2222 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2223 -> StixTree -- Current argument
2224 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2226 -- We have to use up all of our argument registers first...
2228 get_arg ((iDst,fDst):dsts, offset) arg
2229 = getRegister arg `thenUs` \ register ->
2231 reg = if isFloatingRep pk then fDst else iDst
2232 code = registerCode register reg
2233 src = registerName register reg
2234 pk = registerRep register
2237 if isFloatingRep pk then
2238 ((dsts, offset), if isFixed register then
2239 code . mkSeqInstr (FMOV src fDst)
2242 ((dsts, offset), if isFixed register then
2243 code . mkSeqInstr (OR src (RIReg src) iDst)
2246 -- Once we have run out of argument registers, we move to the
2249 get_arg ([], offset) arg
2250 = getRegister arg `thenUs` \ register ->
2251 getNewRegNCG (registerRep register)
2254 code = registerCode register tmp
2255 src = registerName register tmp
2256 pk = registerRep register
2257 sz = primRepToSize pk
2259 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2261 #endif {- alpha_TARGET_ARCH -}
2262 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2263 #if i386_TARGET_ARCH
2265 genCCall fn cconv kind [StInt i]
2266 | fn == SLIT ("PerformGC_wrapper")
2267 = let call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2268 CALL (ImmLit (ptext (if underscorePrefix
2269 then (SLIT ("_PerformGC_wrapper"))
2270 else (SLIT ("PerformGC_wrapper")))))]
2275 genCCall fn cconv kind args
2276 = get_call_args args `thenUs` \ (tot_arg_size, argCode) ->
2278 code2 = asmParThen (map ($ asmVoid) argCode)
2279 call = [SUB L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2281 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)
2284 returnSeq code2 call
2287 -- function names that begin with '.' are assumed to be special
2288 -- internally generated names like '.mul,' which don't get an
2289 -- underscore prefix
2290 -- ToDo:needed (WDP 96/03) ???
2291 fn__2 = case (_HEAD_ fn) of
2292 '.' -> ImmLit (ptext fn)
2293 _ -> ImmLab (ptext fn)
2300 -- do get_call_arg on each arg, threading the total arg size along
2301 -- process the args right-to-left
2302 get_call_args :: [StixTree] -> UniqSM (Int, [InstrBlock])
2307 = returnUs (curr_sz, [])
2308 f curr_sz (arg:args)
2309 = f curr_sz args `thenUs` \ (new_sz, iblocks) ->
2310 get_call_arg arg new_sz `thenUs` \ (new_sz2, iblock) ->
2311 returnUs (new_sz2, iblock:iblocks)
2315 get_call_arg :: StixTree{-current argument-}
2316 -> Int{-running total of arg sizes seen so far-}
2317 -> UniqSM (Int, InstrBlock) -- updated tot argsz, code
2319 get_call_arg arg old_sz
2320 = get_op arg `thenUs` \ (code, reg, sz) ->
2321 let new_sz = old_sz + arg_size sz
2322 in if (case sz of DF -> True; F -> True; _ -> False)
2323 then returnUs (new_sz,
2325 mkSeqInstr (GST DF reg
2326 (AddrBaseIndex (Just esp)
2327 Nothing (ImmInt (- new_sz))))
2329 else returnUs (new_sz,
2331 mkSeqInstr (MOV L (OpReg reg)
2333 (AddrBaseIndex (Just esp)
2334 Nothing (ImmInt (- new_sz)))))
2339 -> UniqSM (InstrBlock, Reg, Size) -- code, reg, size
2342 = getRegister op `thenUs` \ register ->
2343 getNewRegNCG (registerRep register)
2346 code = registerCode register tmp
2347 reg = registerName register tmp
2348 pk = registerRep register
2349 sz = primRepToSize pk
2351 returnUs (code, reg, sz)
2353 #endif {- i386_TARGET_ARCH -}
2354 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2355 #if sparc_TARGET_ARCH
2357 genCCall fn cconv kind args
2358 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2359 `thenUs` \ ((unused,_), argCode) ->
2361 nRegs = length allArgRegs - length unused
2362 call = CALL fn__2 nRegs False
2363 code = asmParThen (map ($ asmVoid) argCode)
2365 returnSeq code [call, NOP]
2367 -- function names that begin with '.' are assumed to be special
2368 -- internally generated names like '.mul,' which don't get an
2369 -- underscore prefix
2370 -- ToDo:needed (WDP 96/03) ???
2371 fn__2 = case (_HEAD_ fn) of
2372 '.' -> ImmLit (ptext fn)
2373 _ -> ImmLab (ptext fn)
2375 ------------------------------------
2376 {- Try to get a value into a specific register (or registers) for
2377 a call. The SPARC calling convention is an absolute
2378 nightmare. The first 6x32 bits of arguments are mapped into
2379 %o0 through %o5, and the remaining arguments are dumped to the
2380 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2381 first argument is a pair of the list of remaining argument
2382 registers to be assigned for this call and the next stack
2383 offset to use for overflowing arguments. This way,
2384 @get_arg@ can be applied to all of a call's arguments using
2388 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2389 -> StixTree -- Current argument
2390 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2392 -- We have to use up all of our argument registers first...
2394 get_arg (dst:dsts, offset) arg
2395 = getRegister arg `thenUs` \ register ->
2396 getNewRegNCG (registerRep register)
2399 reg = if isFloatingRep pk then tmp else dst
2400 code = registerCode register reg
2401 src = registerName register reg
2402 pk = registerRep register
2404 returnUs (case pk of
2407 [] -> (([], offset + 1), code . mkSeqInstrs [
2408 -- conveniently put the second part in the right stack
2409 -- location, and load the first part into %o5
2410 ST DF src (spRel (offset - 1)),
2411 LD W (spRel (offset - 1)) dst])
2412 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2413 ST DF src (spRel (-2)),
2414 LD W (spRel (-2)) dst,
2415 LD W (spRel (-1)) dst__2])
2416 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2417 ST F src (spRel (-2)),
2418 LD W (spRel (-2)) dst])
2419 _ -> ((dsts, offset), if isFixed register then
2420 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2423 -- Once we have run out of argument registers, we move to the
2426 get_arg ([], offset) arg
2427 = getRegister arg `thenUs` \ register ->
2428 getNewRegNCG (registerRep register)
2431 code = registerCode register tmp
2432 src = registerName register tmp
2433 pk = registerRep register
2434 sz = primRepToSize pk
2435 words = if pk == DoubleRep then 2 else 1
2437 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2439 #endif {- sparc_TARGET_ARCH -}
2442 %************************************************************************
2444 \subsection{Support bits}
2446 %************************************************************************
2448 %************************************************************************
2450 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2452 %************************************************************************
2454 Turn those condition codes into integers now (when they appear on
2455 the right hand side of an assignment).
2457 (If applicable) Do not fill the delay slots here; you will confuse the
2461 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2463 #if alpha_TARGET_ARCH
2464 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2465 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2466 #endif {- alpha_TARGET_ARCH -}
2468 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2469 #if i386_TARGET_ARCH
2472 = condIntCode cond x y `thenUs` \ condition ->
2473 getNewRegNCG IntRep `thenUs` \ tmp ->
2474 --getRegister dst `thenUs` \ register ->
2476 --code2 = registerCode register tmp asmVoid
2477 --dst__2 = registerName register tmp
2478 code = condCode condition
2479 cond = condName condition
2480 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2481 code__2 dst = code . mkSeqInstrs [
2482 SETCC cond (OpReg tmp),
2483 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2484 MOV L (OpReg tmp) (OpReg dst)]
2486 returnUs (Any IntRep code__2)
2489 = getUniqLabelNCG `thenUs` \ lbl1 ->
2490 getUniqLabelNCG `thenUs` \ lbl2 ->
2491 condFltCode cond x y `thenUs` \ condition ->
2493 code = condCode condition
2494 cond = condName condition
2495 code__2 dst = code . mkSeqInstrs [
2497 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2500 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2503 returnUs (Any IntRep code__2)
2505 #endif {- i386_TARGET_ARCH -}
2506 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2507 #if sparc_TARGET_ARCH
2509 condIntReg EQQ x (StInt 0)
2510 = getRegister x `thenUs` \ register ->
2511 getNewRegNCG IntRep `thenUs` \ tmp ->
2513 code = registerCode register tmp
2514 src = registerName register tmp
2515 code__2 dst = code . mkSeqInstrs [
2516 SUB False True g0 (RIReg src) g0,
2517 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2519 returnUs (Any IntRep code__2)
2522 = getRegister x `thenUs` \ register1 ->
2523 getRegister y `thenUs` \ register2 ->
2524 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2525 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2527 code1 = registerCode register1 tmp1 asmVoid
2528 src1 = registerName register1 tmp1
2529 code2 = registerCode register2 tmp2 asmVoid
2530 src2 = registerName register2 tmp2
2531 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2532 XOR False src1 (RIReg src2) dst,
2533 SUB False True g0 (RIReg dst) g0,
2534 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2536 returnUs (Any IntRep code__2)
2538 condIntReg NE x (StInt 0)
2539 = getRegister x `thenUs` \ register ->
2540 getNewRegNCG IntRep `thenUs` \ tmp ->
2542 code = registerCode register tmp
2543 src = registerName register tmp
2544 code__2 dst = code . mkSeqInstrs [
2545 SUB False True g0 (RIReg src) g0,
2546 ADD True False g0 (RIImm (ImmInt 0)) dst]
2548 returnUs (Any IntRep code__2)
2551 = getRegister x `thenUs` \ register1 ->
2552 getRegister y `thenUs` \ register2 ->
2553 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2554 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2556 code1 = registerCode register1 tmp1 asmVoid
2557 src1 = registerName register1 tmp1
2558 code2 = registerCode register2 tmp2 asmVoid
2559 src2 = registerName register2 tmp2
2560 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2561 XOR False src1 (RIReg src2) dst,
2562 SUB False True g0 (RIReg dst) g0,
2563 ADD True False g0 (RIImm (ImmInt 0)) dst]
2565 returnUs (Any IntRep code__2)
2568 = getUniqLabelNCG `thenUs` \ lbl1 ->
2569 getUniqLabelNCG `thenUs` \ lbl2 ->
2570 condIntCode cond x y `thenUs` \ condition ->
2572 code = condCode condition
2573 cond = condName condition
2574 code__2 dst = code . mkSeqInstrs [
2575 BI cond False (ImmCLbl lbl1), NOP,
2576 OR False g0 (RIImm (ImmInt 0)) dst,
2577 BI ALWAYS False (ImmCLbl lbl2), NOP,
2579 OR False g0 (RIImm (ImmInt 1)) dst,
2582 returnUs (Any IntRep code__2)
2585 = getUniqLabelNCG `thenUs` \ lbl1 ->
2586 getUniqLabelNCG `thenUs` \ lbl2 ->
2587 condFltCode cond x y `thenUs` \ condition ->
2589 code = condCode condition
2590 cond = condName condition
2591 code__2 dst = code . mkSeqInstrs [
2593 BF cond False (ImmCLbl lbl1), NOP,
2594 OR False g0 (RIImm (ImmInt 0)) dst,
2595 BI ALWAYS False (ImmCLbl lbl2), NOP,
2597 OR False g0 (RIImm (ImmInt 1)) dst,
2600 returnUs (Any IntRep code__2)
2602 #endif {- sparc_TARGET_ARCH -}
2605 %************************************************************************
2607 \subsubsection{@trivial*Code@: deal with trivial instructions}
2609 %************************************************************************
2611 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2612 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2613 for constants on the right hand side, because that's where the generic
2614 optimizer will have put them.
2616 Similarly, for unary instructions, we don't have to worry about
2617 matching an StInt as the argument, because genericOpt will already
2618 have handled the constant-folding.
2622 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2623 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2624 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2626 -> StixTree -> StixTree -- the two arguments
2631 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2632 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2633 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2635 -> StixTree -> StixTree -- the two arguments
2639 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2640 ,IF_ARCH_i386 ((Operand -> Instr)
2641 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2643 -> StixTree -- the one argument
2648 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2649 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2650 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2652 -> StixTree -- the one argument
2655 #if alpha_TARGET_ARCH
2657 trivialCode instr x (StInt y)
2659 = getRegister x `thenUs` \ register ->
2660 getNewRegNCG IntRep `thenUs` \ tmp ->
2662 code = registerCode register tmp
2663 src1 = registerName register tmp
2664 src2 = ImmInt (fromInteger y)
2665 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2667 returnUs (Any IntRep code__2)
2669 trivialCode instr x y
2670 = getRegister x `thenUs` \ register1 ->
2671 getRegister y `thenUs` \ register2 ->
2672 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2673 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2675 code1 = registerCode register1 tmp1 asmVoid
2676 src1 = registerName register1 tmp1
2677 code2 = registerCode register2 tmp2 asmVoid
2678 src2 = registerName register2 tmp2
2679 code__2 dst = asmParThen [code1, code2] .
2680 mkSeqInstr (instr src1 (RIReg src2) dst)
2682 returnUs (Any IntRep code__2)
2685 trivialUCode instr x
2686 = getRegister x `thenUs` \ register ->
2687 getNewRegNCG IntRep `thenUs` \ tmp ->
2689 code = registerCode register tmp
2690 src = registerName register tmp
2691 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2693 returnUs (Any IntRep code__2)
2696 trivialFCode _ instr x y
2697 = getRegister x `thenUs` \ register1 ->
2698 getRegister y `thenUs` \ register2 ->
2699 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2700 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2702 code1 = registerCode register1 tmp1
2703 src1 = registerName register1 tmp1
2705 code2 = registerCode register2 tmp2
2706 src2 = registerName register2 tmp2
2708 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2709 mkSeqInstr (instr src1 src2 dst)
2711 returnUs (Any DoubleRep code__2)
2713 trivialUFCode _ instr x
2714 = getRegister x `thenUs` \ register ->
2715 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2717 code = registerCode register tmp
2718 src = registerName register tmp
2719 code__2 dst = code . mkSeqInstr (instr src dst)
2721 returnUs (Any DoubleRep code__2)
2723 #endif {- alpha_TARGET_ARCH -}
2724 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2725 #if i386_TARGET_ARCH
2727 trivialCode instr x y
2729 = getRegister x `thenUs` \ register1 ->
2731 code__2 dst = let code1 = registerCode register1 dst
2732 src1 = registerName register1 dst
2734 if isFixed register1 && src1 /= dst
2735 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2736 instr (OpImm imm__2) (OpReg dst)]
2737 else mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2739 returnUs (Any IntRep code__2)
2742 imm__2 = case imm of Just x -> x
2744 trivialCode instr x y
2745 = getRegister x `thenUs` \ register1 ->
2746 getRegister y `thenUs` \ register2 ->
2747 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2749 code2 = registerCode register2 tmp2 --asmVoid
2750 src2 = registerName register2 tmp2
2751 code__2 dst = let code1 = registerCode register1 dst --asmVoid
2752 src1 = registerName register1 dst
2753 in code2 . code1 . --asmParThen [code1, code2] .
2754 if isFixed register1 && src1 /= dst
2755 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2756 instr (OpReg src2) (OpReg dst)]
2757 else mkSeqInstr (instr (OpReg src2) (OpReg src1))
2759 returnUs (Any IntRep code__2)
2762 trivialUCode instr x
2763 = getRegister x `thenUs` \ register ->
2765 code__2 dst = let code = registerCode register dst
2766 src = registerName register dst
2768 if isFixed register && dst /= src
2769 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2771 else mkSeqInstr (instr (OpReg src))
2773 returnUs (Any IntRep code__2)
2776 trivialFCode pk instr x y
2777 = getRegister x `thenUs` \ register1 ->
2778 getRegister y `thenUs` \ register2 ->
2779 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2780 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2782 code1 = registerCode register1 tmp1
2783 src1 = registerName register1 tmp1
2785 code2 = registerCode register2 tmp2
2786 src2 = registerName register2 tmp2
2788 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2789 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2791 returnUs (Any DoubleRep code__2)
2795 trivialUFCode pk instr x
2796 = getRegister x `thenUs` \ register ->
2797 getNewRegNCG pk `thenUs` \ tmp ->
2799 code = registerCode register tmp
2800 src = registerName register tmp
2801 code__2 dst = code . mkSeqInstr (instr src dst)
2803 returnUs (Any pk code__2)
2805 #endif {- i386_TARGET_ARCH -}
2806 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2807 #if sparc_TARGET_ARCH
2809 trivialCode instr x (StInt y)
2811 = getRegister x `thenUs` \ register ->
2812 getNewRegNCG IntRep `thenUs` \ tmp ->
2814 code = registerCode register tmp
2815 src1 = registerName register tmp
2816 src2 = ImmInt (fromInteger y)
2817 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2819 returnUs (Any IntRep code__2)
2821 trivialCode instr x y
2822 = getRegister x `thenUs` \ register1 ->
2823 getRegister y `thenUs` \ register2 ->
2824 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2825 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2827 code1 = registerCode register1 tmp1 asmVoid
2828 src1 = registerName register1 tmp1
2829 code2 = registerCode register2 tmp2 asmVoid
2830 src2 = registerName register2 tmp2
2831 code__2 dst = asmParThen [code1, code2] .
2832 mkSeqInstr (instr src1 (RIReg src2) dst)
2834 returnUs (Any IntRep code__2)
2837 trivialFCode pk instr x y
2838 = getRegister x `thenUs` \ register1 ->
2839 getRegister y `thenUs` \ register2 ->
2840 getNewRegNCG (registerRep register1)
2842 getNewRegNCG (registerRep register2)
2844 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2846 promote x = asmInstr (FxTOy F DF x tmp)
2848 pk1 = registerRep register1
2849 code1 = registerCode register1 tmp1
2850 src1 = registerName register1 tmp1
2852 pk2 = registerRep register2
2853 code2 = registerCode register2 tmp2
2854 src2 = registerName register2 tmp2
2858 asmParThen [code1 asmVoid, code2 asmVoid] .
2859 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2860 else if pk1 == FloatRep then
2861 asmParThen [code1 (promote src1), code2 asmVoid] .
2862 mkSeqInstr (instr DF tmp src2 dst)
2864 asmParThen [code1 asmVoid, code2 (promote src2)] .
2865 mkSeqInstr (instr DF src1 tmp dst)
2867 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2870 trivialUCode instr x
2871 = getRegister x `thenUs` \ register ->
2872 getNewRegNCG IntRep `thenUs` \ tmp ->
2874 code = registerCode register tmp
2875 src = registerName register tmp
2876 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2878 returnUs (Any IntRep code__2)
2881 trivialUFCode pk instr x
2882 = getRegister x `thenUs` \ register ->
2883 getNewRegNCG pk `thenUs` \ tmp ->
2885 code = registerCode register tmp
2886 src = registerName register tmp
2887 code__2 dst = code . mkSeqInstr (instr src dst)
2889 returnUs (Any pk code__2)
2891 #endif {- sparc_TARGET_ARCH -}
2894 %************************************************************************
2896 \subsubsection{Coercing to/from integer/floating-point...}
2898 %************************************************************************
2900 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
2901 to be generated. Here we just change the type on the Register passed
2902 on up. The code is machine-independent.
2904 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
2905 conversions. We have to store temporaries in memory to move
2906 between the integer and the floating point register sets.
2909 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
2910 coerceFltCode :: StixTree -> UniqSM Register
2912 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
2913 coerceFP2Int :: StixTree -> UniqSM Register
2916 = getRegister x `thenUs` \ register ->
2919 Fixed _ reg code -> Fixed pk reg code
2920 Any _ code -> Any pk code
2925 = getRegister x `thenUs` \ register ->
2928 Fixed _ reg code -> Fixed DoubleRep reg code
2929 Any _ code -> Any DoubleRep code
2934 #if alpha_TARGET_ARCH
2937 = getRegister x `thenUs` \ register ->
2938 getNewRegNCG IntRep `thenUs` \ reg ->
2940 code = registerCode register reg
2941 src = registerName register reg
2943 code__2 dst = code . mkSeqInstrs [
2945 LD TF dst (spRel 0),
2948 returnUs (Any DoubleRep code__2)
2952 = getRegister x `thenUs` \ register ->
2953 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2955 code = registerCode register tmp
2956 src = registerName register tmp
2958 code__2 dst = code . mkSeqInstrs [
2960 ST TF tmp (spRel 0),
2963 returnUs (Any IntRep code__2)
2965 #endif {- alpha_TARGET_ARCH -}
2966 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2967 #if i386_TARGET_ARCH
2970 = getRegister x `thenUs` \ register ->
2971 getNewRegNCG IntRep `thenUs` \ reg ->
2973 code = registerCode register reg
2974 src = registerName register reg
2975 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
2976 code__2 dst = code .
2977 mkSeqInstr (opc src dst)
2979 returnUs (Any pk code__2)
2983 = getRegister x `thenUs` \ register ->
2984 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2986 code = registerCode register tmp
2987 src = registerName register tmp
2988 pk = registerRep register
2990 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
2991 code__2 dst = code .
2992 mkSeqInstr (opc src dst)
2994 returnUs (Any IntRep code__2)
2996 #endif {- i386_TARGET_ARCH -}
2997 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2998 #if sparc_TARGET_ARCH
3001 = getRegister x `thenUs` \ register ->
3002 getNewRegNCG IntRep `thenUs` \ reg ->
3004 code = registerCode register reg
3005 src = registerName register reg
3007 code__2 dst = code . mkSeqInstrs [
3008 ST W src (spRel (-2)),
3009 LD W (spRel (-2)) dst,
3010 FxTOy W (primRepToSize pk) dst dst]
3012 returnUs (Any pk code__2)
3016 = getRegister x `thenUs` \ register ->
3017 getNewRegNCG IntRep `thenUs` \ reg ->
3018 getNewRegNCG FloatRep `thenUs` \ tmp ->
3020 code = registerCode register reg
3021 src = registerName register reg
3022 pk = registerRep register
3024 code__2 dst = code . mkSeqInstrs [
3025 FxTOy (primRepToSize pk) W src tmp,
3026 ST W tmp (spRel (-2)),
3027 LD W (spRel (-2)) dst]
3029 returnUs (Any IntRep code__2)
3031 #endif {- sparc_TARGET_ARCH -}
3034 %************************************************************************
3036 \subsubsection{Coercing integer to @Char@...}
3038 %************************************************************************
3040 Integer to character conversion. Where applicable, we try to do this
3041 in one step if the original object is in memory.
3044 chrCode :: StixTree -> UniqSM Register
3046 #if alpha_TARGET_ARCH
3049 = getRegister x `thenUs` \ register ->
3050 getNewRegNCG IntRep `thenUs` \ reg ->
3052 code = registerCode register reg
3053 src = registerName register reg
3054 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3056 returnUs (Any IntRep code__2)
3058 #endif {- alpha_TARGET_ARCH -}
3059 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3060 #if i386_TARGET_ARCH
3063 = getRegister x `thenUs` \ register ->
3066 code = registerCode register dst
3067 src = registerName register dst
3069 if isFixed register && src /= dst
3070 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3071 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3072 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3074 returnUs (Any IntRep code__2)
3076 #endif {- i386_TARGET_ARCH -}
3077 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3078 #if sparc_TARGET_ARCH
3080 chrCode (StInd pk mem)
3081 = getAmode mem `thenUs` \ amode ->
3083 code = amodeCode amode
3084 src = amodeAddr amode
3085 src_off = addrOffset src 3
3086 src__2 = case src_off of Just x -> x
3087 code__2 dst = if maybeToBool src_off then
3088 code . mkSeqInstr (LD BU src__2 dst)
3090 code . mkSeqInstrs [
3091 LD (primRepToSize pk) src dst,
3092 AND False dst (RIImm (ImmInt 255)) dst]
3094 returnUs (Any pk code__2)
3097 = getRegister x `thenUs` \ register ->
3098 getNewRegNCG IntRep `thenUs` \ reg ->
3100 code = registerCode register reg
3101 src = registerName register reg
3102 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3104 returnUs (Any IntRep code__2)
3106 #endif {- sparc_TARGET_ARCH -}