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(..)
32 import UniqSupply ( returnUs, thenUs, mapUs, mapAndUnzipUs,
38 Code extractor for an entire stix tree---stix statement level.
41 stmt2Instrs :: StixTree {- a stix statement -} -> UniqSM InstrBlock
43 stmt2Instrs stmt = case stmt of
44 StComment s -> returnInstr (COMMENT s)
45 StSegment seg -> returnInstr (SEGMENT seg)
48 -- StFunBegin, normal non-debugging code for all architectures
49 StFunBegin lab -> returnInstr (IF_ARCH_alpha(FUNBEGIN lab,LABEL lab))
51 -- StFunBegin, special tracing code for x86-Linux only
52 StFunBegin lab -> getUniqLabelNCG `thenUs` \ str_lbl ->
53 returnUs (mkSeqInstrs [
55 COMMENT SLIT("begin trace sequence"),
58 ASCII True (showSDoc (pprCLabel_asm lab)),
61 PUSH L (OpImm (ImmCLbl str_lbl)),
62 CALL (ImmLit (text "native_trace")),
63 ADD L (OpImm (ImmInt 4)) (OpReg esp),
65 COMMENT SLIT("end trace sequence")
69 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
70 StLabel lab -> returnInstr (LABEL lab)
72 StJump arg -> genJump arg
73 StCondJump lab arg -> genCondJump lab arg
74 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
77 | isFloatingRep pk -> assignFltCode pk dst src
78 | otherwise -> assignIntCode pk dst src
81 -- When falling through on the Alpha, we still have to load pv
82 -- with the address of the next routine, so that it can load gp.
83 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
87 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
88 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
89 (foldr (.) id codes xs))
91 getData :: StixTree -> UniqSM (InstrBlock, Imm)
93 getData (StInt i) = returnUs (id, ImmInteger i)
94 getData (StDouble d) = returnUs (id, ImmDouble d)
95 getData (StLitLbl s) = returnUs (id, ImmLab s)
96 getData (StCLbl l) = returnUs (id, ImmCLbl l)
97 getData (StString s) =
98 getUniqLabelNCG `thenUs` \ lbl ->
99 returnUs (mkSeqInstrs [LABEL lbl,
100 ASCII True (_UNPK_ s)],
102 -- the linker can handle simple arithmetic...
103 getData (StIndex rep (StCLbl lbl) (StInt off)) =
104 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
107 %************************************************************************
109 \subsection{General things for putting together code sequences}
111 %************************************************************************
114 type InstrList = OrdList Instr
115 type InstrBlock = InstrList -> InstrList
118 asmVoid = mkEmptyList
120 asmInstr :: Instr -> InstrList
121 asmInstr i = mkUnitList i
123 asmSeq :: [Instr] -> InstrList
124 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
126 asmParThen :: [InstrList] -> InstrBlock
127 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
129 returnInstr :: Instr -> UniqSM InstrBlock
130 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
132 returnInstrs :: [Instr] -> UniqSM InstrBlock
133 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
135 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
136 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
138 mkSeqInstr :: Instr -> InstrBlock
139 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
141 mkSeqInstrs :: [Instr] -> InstrBlock
142 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
146 mangleIndexTree :: StixTree -> StixTree
148 mangleIndexTree (StIndex pk base (StInt i))
149 = StPrim IntAddOp [base, off]
151 off = StInt (i * sizeOf pk)
153 #ifndef i386_TARGET_ARCH
154 mangleIndexTree (StIndex pk base off)
155 = StPrim IntAddOp [base,
161 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
162 StPrim SllOp [off, StInt s]
165 shift DoubleRep = 3::Integer
166 shift _ = IF_ARCH_alpha(3,2)
168 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
169 -- that do include the size of the primitive kind we're addressing. When StIndex
170 -- is expanded to actual code, the index (in units) is by the above code approp.
171 -- shifted to get the no. of bytes. Since Address amodes do contain size info
172 -- explicitly, we disable the shifting for x86s.
173 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
179 maybeImm :: StixTree -> Maybe Imm
181 maybeImm (StLitLbl s) = Just (ImmLab s)
182 maybeImm (StCLbl l) = Just (ImmCLbl l)
184 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
185 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
188 | i >= toInteger minInt && i <= toInteger maxInt
189 = Just (ImmInt (fromInteger i))
191 = Just (ImmInteger i)
196 %************************************************************************
198 \subsection{The @Register@ type}
200 %************************************************************************
202 @Register@s passed up the tree. If the stix code forces the register
203 to live in a pre-decided machine register, it comes out as @Fixed@;
204 otherwise, it comes out as @Any@, and the parent can decide which
205 register to put it in.
209 = Fixed PrimRep Reg InstrBlock
210 | Any PrimRep (Reg -> InstrBlock)
212 registerCode :: Register -> Reg -> InstrBlock
213 registerCode (Fixed _ _ code) reg = code
214 registerCode (Any _ code) reg = code reg
216 registerName :: Register -> Reg -> Reg
217 registerName (Fixed _ reg _) _ = reg
218 registerName (Any _ _) reg = reg
220 registerRep :: Register -> PrimRep
221 registerRep (Fixed pk _ _) = pk
222 registerRep (Any pk _) = pk
224 isFixed :: Register -> Bool
225 isFixed (Fixed _ _ _) = True
226 isFixed (Any _ _) = False
229 Generate code to get a subtree into a @Register@:
231 getRegister :: StixTree -> UniqSM Register
233 getRegister (StReg (StixMagicId stgreg))
234 = case (magicIdRegMaybe stgreg) of
235 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
238 getRegister (StReg (StixTemp u pk))
239 = returnUs (Fixed pk (UnmappedReg u pk) id)
241 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
243 getRegister (StCall fn cconv kind args)
244 = genCCall fn cconv kind args `thenUs` \ call ->
245 returnUs (Fixed kind reg call)
247 reg = if isFloatingRep kind
248 then IF_ARCH_alpha( f0, IF_ARCH_i386( st0, IF_ARCH_sparc( f0,)))
249 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
251 getRegister (StString s)
252 = getUniqLabelNCG `thenUs` \ lbl ->
254 imm_lbl = ImmCLbl lbl
256 code dst = mkSeqInstrs [
259 ASCII True (_UNPK_ s),
261 #if alpha_TARGET_ARCH
262 LDA dst (AddrImm imm_lbl)
265 MOV L (OpImm imm_lbl) (OpReg dst)
267 #if sparc_TARGET_ARCH
268 SETHI (HI imm_lbl) dst,
269 OR False dst (RIImm (LO imm_lbl)) dst
273 returnUs (Any PtrRep code)
277 -- end of machine-"independent" bit; here we go on the rest...
279 #if alpha_TARGET_ARCH
281 getRegister (StDouble d)
282 = getUniqLabelNCG `thenUs` \ lbl ->
283 getNewRegNCG PtrRep `thenUs` \ tmp ->
284 let code dst = mkSeqInstrs [
287 DATA TF [ImmLab (rational d)],
289 LDA tmp (AddrImm (ImmCLbl lbl)),
290 LD TF dst (AddrReg tmp)]
292 returnUs (Any DoubleRep code)
294 getRegister (StPrim primop [x]) -- unary PrimOps
296 IntNegOp -> trivialUCode (NEG Q False) x
298 NotOp -> trivialUCode NOT x
300 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
301 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
303 OrdOp -> coerceIntCode IntRep x
306 Float2IntOp -> coerceFP2Int x
307 Int2FloatOp -> coerceInt2FP pr x
308 Double2IntOp -> coerceFP2Int x
309 Int2DoubleOp -> coerceInt2FP pr x
311 Double2FloatOp -> coerceFltCode x
312 Float2DoubleOp -> coerceFltCode x
314 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
316 fn = case other_op of
317 FloatExpOp -> SLIT("exp")
318 FloatLogOp -> SLIT("log")
319 FloatSqrtOp -> SLIT("sqrt")
320 FloatSinOp -> SLIT("sin")
321 FloatCosOp -> SLIT("cos")
322 FloatTanOp -> SLIT("tan")
323 FloatAsinOp -> SLIT("asin")
324 FloatAcosOp -> SLIT("acos")
325 FloatAtanOp -> SLIT("atan")
326 FloatSinhOp -> SLIT("sinh")
327 FloatCoshOp -> SLIT("cosh")
328 FloatTanhOp -> SLIT("tanh")
329 DoubleExpOp -> SLIT("exp")
330 DoubleLogOp -> SLIT("log")
331 DoubleSqrtOp -> SLIT("sqrt")
332 DoubleSinOp -> SLIT("sin")
333 DoubleCosOp -> SLIT("cos")
334 DoubleTanOp -> SLIT("tan")
335 DoubleAsinOp -> SLIT("asin")
336 DoubleAcosOp -> SLIT("acos")
337 DoubleAtanOp -> SLIT("atan")
338 DoubleSinhOp -> SLIT("sinh")
339 DoubleCoshOp -> SLIT("cosh")
340 DoubleTanhOp -> SLIT("tanh")
342 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
344 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
346 CharGtOp -> trivialCode (CMP LTT) y x
347 CharGeOp -> trivialCode (CMP LE) y x
348 CharEqOp -> trivialCode (CMP EQQ) x y
349 CharNeOp -> int_NE_code x y
350 CharLtOp -> trivialCode (CMP LTT) x y
351 CharLeOp -> trivialCode (CMP LE) x y
353 IntGtOp -> trivialCode (CMP LTT) y x
354 IntGeOp -> trivialCode (CMP LE) y x
355 IntEqOp -> trivialCode (CMP EQQ) x y
356 IntNeOp -> int_NE_code x y
357 IntLtOp -> trivialCode (CMP LTT) x y
358 IntLeOp -> trivialCode (CMP LE) x y
360 WordGtOp -> trivialCode (CMP ULT) y x
361 WordGeOp -> trivialCode (CMP ULE) x y
362 WordEqOp -> trivialCode (CMP EQQ) x y
363 WordNeOp -> int_NE_code x y
364 WordLtOp -> trivialCode (CMP ULT) x y
365 WordLeOp -> trivialCode (CMP ULE) x y
367 AddrGtOp -> trivialCode (CMP ULT) y x
368 AddrGeOp -> trivialCode (CMP ULE) y x
369 AddrEqOp -> trivialCode (CMP EQQ) x y
370 AddrNeOp -> int_NE_code x y
371 AddrLtOp -> trivialCode (CMP ULT) x y
372 AddrLeOp -> trivialCode (CMP ULE) x y
374 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
375 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
376 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
377 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
378 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
379 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
381 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
382 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
383 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
384 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
385 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
386 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
388 IntAddOp -> trivialCode (ADD Q False) x y
389 IntSubOp -> trivialCode (SUB Q False) x y
390 IntMulOp -> trivialCode (MUL Q False) x y
391 IntQuotOp -> trivialCode (DIV Q False) x y
392 IntRemOp -> trivialCode (REM Q False) x y
394 WordQuotOp -> trivialCode (DIV Q True) x y
395 WordRemOp -> trivialCode (REM Q True) x y
397 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
398 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
399 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
400 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
402 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
403 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
404 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
405 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
407 AndOp -> trivialCode AND x y
408 OrOp -> trivialCode OR x y
409 XorOp -> trivialCode XOR x y
410 SllOp -> trivialCode SLL x y
411 SrlOp -> trivialCode SRL x y
413 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
414 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
415 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
417 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
418 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
420 {- ------------------------------------------------------------
421 Some bizarre special code for getting condition codes into
422 registers. Integer non-equality is a test for equality
423 followed by an XOR with 1. (Integer comparisons always set
424 the result register to 0 or 1.) Floating point comparisons of
425 any kind leave the result in a floating point register, so we
426 need to wrangle an integer register out of things.
428 int_NE_code :: StixTree -> StixTree -> UniqSM Register
431 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
432 getNewRegNCG IntRep `thenUs` \ tmp ->
434 code = registerCode register tmp
435 src = registerName register tmp
436 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
438 returnUs (Any IntRep code__2)
440 {- ------------------------------------------------------------
441 Comments for int_NE_code also apply to cmpF_code
444 :: (Reg -> Reg -> Reg -> Instr)
446 -> StixTree -> StixTree
449 cmpF_code instr cond x y
450 = trivialFCode pr instr x y `thenUs` \ register ->
451 getNewRegNCG DoubleRep `thenUs` \ tmp ->
452 getUniqLabelNCG `thenUs` \ lbl ->
454 code = registerCode register tmp
455 result = registerName register tmp
457 code__2 dst = code . mkSeqInstrs [
458 OR zeroh (RIImm (ImmInt 1)) dst,
459 BF cond result (ImmCLbl lbl),
460 OR zeroh (RIReg zeroh) dst,
463 returnUs (Any IntRep code__2)
465 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
466 ------------------------------------------------------------
468 getRegister (StInd pk mem)
469 = getAmode mem `thenUs` \ amode ->
471 code = amodeCode amode
472 src = amodeAddr amode
473 size = primRepToSize pk
474 code__2 dst = code . mkSeqInstr (LD size dst src)
476 returnUs (Any pk code__2)
478 getRegister (StInt i)
481 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
483 returnUs (Any IntRep code)
486 code dst = mkSeqInstr (LDI Q dst src)
488 returnUs (Any IntRep code)
490 src = ImmInt (fromInteger i)
495 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
497 returnUs (Any PtrRep code)
500 imm__2 = case imm of Just x -> x
502 #endif {- alpha_TARGET_ARCH -}
503 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
506 getRegister (StDouble 0.0)
508 code dst = mkSeqInstrs [FLDZ]
510 returnUs (Any DoubleRep code)
512 getRegister (StDouble 1.0)
514 code dst = mkSeqInstrs [FLD1]
516 returnUs (Any DoubleRep code)
518 getRegister (StDouble d)
519 = getUniqLabelNCG `thenUs` \ lbl ->
520 --getNewRegNCG PtrRep `thenUs` \ tmp ->
521 let code dst = mkSeqInstrs [
524 DATA DF [ImmDouble d],
526 FLD DF (OpImm (ImmCLbl lbl))
529 returnUs (Any DoubleRep code)
531 getRegister (StPrim primop [x]) -- unary PrimOps
533 IntNegOp -> trivialUCode (NEGI L) x
535 NotOp -> trivialUCode (NOT L) x
537 FloatNegOp -> trivialUFCode FloatRep FCHS x
538 FloatSqrtOp -> trivialUFCode FloatRep FSQRT x
539 DoubleNegOp -> trivialUFCode DoubleRep FCHS x
541 DoubleSqrtOp -> trivialUFCode DoubleRep FSQRT x
543 OrdOp -> coerceIntCode IntRep x
546 Float2IntOp -> coerceFP2Int x
547 Int2FloatOp -> coerceInt2FP FloatRep x
548 Double2IntOp -> coerceFP2Int x
549 Int2DoubleOp -> coerceInt2FP DoubleRep x
551 Double2FloatOp -> coerceFltCode x
552 Float2DoubleOp -> coerceFltCode x
556 fixed_x = if is_float_op -- promote to double
557 then StPrim Float2DoubleOp [x]
560 getRegister (StCall fn cCallConv DoubleRep [x])
564 FloatExpOp -> (True, SLIT("exp"))
565 FloatLogOp -> (True, SLIT("log"))
567 FloatSinOp -> (True, SLIT("sin"))
568 FloatCosOp -> (True, SLIT("cos"))
569 FloatTanOp -> (True, SLIT("tan"))
571 FloatAsinOp -> (True, SLIT("asin"))
572 FloatAcosOp -> (True, SLIT("acos"))
573 FloatAtanOp -> (True, SLIT("atan"))
575 FloatSinhOp -> (True, SLIT("sinh"))
576 FloatCoshOp -> (True, SLIT("cosh"))
577 FloatTanhOp -> (True, SLIT("tanh"))
579 DoubleExpOp -> (False, SLIT("exp"))
580 DoubleLogOp -> (False, SLIT("log"))
582 DoubleSinOp -> (False, SLIT("sin"))
583 DoubleCosOp -> (False, SLIT("cos"))
584 DoubleTanOp -> (False, SLIT("tan"))
586 DoubleAsinOp -> (False, SLIT("asin"))
587 DoubleAcosOp -> (False, SLIT("acos"))
588 DoubleAtanOp -> (False, SLIT("atan"))
590 DoubleSinhOp -> (False, SLIT("sinh"))
591 DoubleCoshOp -> (False, SLIT("cosh"))
592 DoubleTanhOp -> (False, SLIT("tanh"))
594 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
596 CharGtOp -> condIntReg GTT x y
597 CharGeOp -> condIntReg GE x y
598 CharEqOp -> condIntReg EQQ x y
599 CharNeOp -> condIntReg NE x y
600 CharLtOp -> condIntReg LTT x y
601 CharLeOp -> condIntReg LE x y
603 IntGtOp -> condIntReg GTT x y
604 IntGeOp -> condIntReg GE x y
605 IntEqOp -> condIntReg EQQ x y
606 IntNeOp -> condIntReg NE x y
607 IntLtOp -> condIntReg LTT x y
608 IntLeOp -> condIntReg LE x y
610 WordGtOp -> condIntReg GU x y
611 WordGeOp -> condIntReg GEU x y
612 WordEqOp -> condIntReg EQQ x y
613 WordNeOp -> condIntReg NE x y
614 WordLtOp -> condIntReg LU x y
615 WordLeOp -> condIntReg LEU x y
617 AddrGtOp -> condIntReg GU x y
618 AddrGeOp -> condIntReg GEU x y
619 AddrEqOp -> condIntReg EQQ x y
620 AddrNeOp -> condIntReg NE x y
621 AddrLtOp -> condIntReg LU x y
622 AddrLeOp -> condIntReg LEU x y
624 FloatGtOp -> condFltReg GTT x y
625 FloatGeOp -> condFltReg GE x y
626 FloatEqOp -> condFltReg EQQ x y
627 FloatNeOp -> condFltReg NE x y
628 FloatLtOp -> condFltReg LTT x y
629 FloatLeOp -> condFltReg LE x y
631 DoubleGtOp -> condFltReg GTT x y
632 DoubleGeOp -> condFltReg GE x y
633 DoubleEqOp -> condFltReg EQQ x y
634 DoubleNeOp -> condFltReg NE x y
635 DoubleLtOp -> condFltReg LTT x y
636 DoubleLeOp -> condFltReg LE x y
638 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
639 -- this should be optimised by the generic Opts,
640 -- I don't know why it is not (sometimes)!
642 [x, StInt 0] -> getRegister x
647 IntSubOp -> sub_code L x y
648 IntQuotOp -> quot_code L x y True{-division-}
649 IntRemOp -> quot_code L x y False{-remainder-}
650 IntMulOp -> trivialCode (IMUL L) x y {-True-}
652 FloatAddOp -> trivialFCode FloatRep FADD FADD FADDP FADDP x y
653 FloatSubOp -> trivialFCode FloatRep FSUB FSUBR FSUBP FSUBRP x y
654 FloatMulOp -> trivialFCode FloatRep FMUL FMUL FMULP FMULP x y
655 FloatDivOp -> trivialFCode FloatRep FDIV FDIVR FDIVP FDIVRP x y
657 DoubleAddOp -> trivialFCode DoubleRep FADD FADD FADDP FADDP x y
658 DoubleSubOp -> trivialFCode DoubleRep FSUB FSUBR FSUBP FSUBRP x y
659 DoubleMulOp -> trivialFCode DoubleRep FMUL FMUL FMULP FMULP x y
660 DoubleDivOp -> trivialFCode DoubleRep FDIV FDIVR FDIVP FDIVRP x y
662 AndOp -> trivialCode (AND L) x y {-True-}
663 OrOp -> trivialCode (OR L) x y {-True-}
664 XorOp -> trivialCode (XOR L) x y {-True-}
666 {- Shift ops on x86s have constraints on their source, it
667 either has to be Imm, CL or 1
668 => trivialCode's is not restrictive enough (sigh.)
671 SllOp -> shift_code (SHL L) x y {-False-}
672 SrlOp -> shift_code (SHR L) x y {-False-}
674 ISllOp -> shift_code (SHL L) x y {-False-} --was:panic "I386Gen:isll"
675 ISraOp -> shift_code (SAR L) x y {-False-} --was:panic "I386Gen:isra"
676 ISrlOp -> shift_code (SHR L) x y {-False-} --was:panic "I386Gen:isrl"
678 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
679 where promote x = StPrim Float2DoubleOp [x]
680 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
682 shift_code :: (Operand -> Operand -> Instr)
686 {- Case1: shift length as immediate -}
687 -- Code is the same as the first eq. for trivialCode -- sigh.
688 shift_code instr x y{-amount-}
690 = getRegister x `thenUs` \ register ->
692 op_imm = OpImm imm__2
695 code = registerCode register dst
696 src = registerName register dst
698 mkSeqInstr (COMMENT SLIT("shift_code")) .
700 if isFixed register && src /= dst
702 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
703 instr op_imm (OpReg dst)]
705 mkSeqInstr (instr op_imm (OpReg src))
707 returnUs (Any IntRep code__2)
710 imm__2 = case imm of Just x -> x
712 {- Case2: shift length is complex (non-immediate) -}
713 shift_code instr x y{-amount-}
714 = getRegister y `thenUs` \ register1 ->
715 getRegister x `thenUs` \ register2 ->
716 -- getNewRegNCG IntRep `thenUs` \ dst ->
718 -- Note: we force the shift length to be loaded
719 -- into ECX, so that we can use CL when shifting.
720 -- (only register location we are allowed
721 -- to put shift amounts.)
723 -- The shift instruction is fed ECX as src reg,
724 -- but we coerce this into CL when printing out.
725 src1 = registerName register1 ecx
726 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
727 registerCode register1 ecx .
728 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
730 registerCode register1 ecx
733 code2 = registerCode register2 eax
734 src2 = registerName register2 eax
737 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
739 returnUs (Fixed IntRep eax 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)
751 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
753 returnUs (Any IntRep code__2)
755 add_code sz x (StInd _ mem)
756 = getRegister x `thenUs` \ register1 ->
757 --getNewRegNCG (registerRep register1)
758 -- `thenUs` \ tmp1 ->
759 getAmode mem `thenUs` \ amode ->
761 code2 = amodeCode amode
762 src2 = amodeAddr amode
764 code__2 dst = let code1 = registerCode register1 dst
765 src1 = registerName register1 dst
766 in asmParThen [code2 asmVoid,code1 asmVoid] .
767 if isFixed register1 && src1 /= dst
768 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
769 ADD sz (OpAddr src2) (OpReg dst)]
771 mkSeqInstrs [ADD sz (OpAddr src2) (OpReg src1)]
773 returnUs (Any IntRep code__2)
775 add_code sz (StInd _ mem) y
776 = getRegister y `thenUs` \ register2 ->
777 --getNewRegNCG (registerRep register2)
778 -- `thenUs` \ tmp2 ->
779 getAmode mem `thenUs` \ amode ->
781 code1 = amodeCode amode
782 src1 = amodeAddr amode
784 code__2 dst = let code2 = registerCode register2 dst
785 src2 = registerName register2 dst
786 in asmParThen [code1 asmVoid,code2 asmVoid] .
787 if isFixed register2 && src2 /= dst
788 then mkSeqInstrs [MOV L (OpReg src2) (OpReg dst),
789 ADD sz (OpAddr src1) (OpReg dst)]
791 mkSeqInstrs [ADD sz (OpAddr src1) (OpReg src2)]
793 returnUs (Any IntRep code__2)
796 = getRegister x `thenUs` \ register1 ->
797 getRegister y `thenUs` \ register2 ->
798 getNewRegNCG IntRep `thenUs` \ tmp1 ->
799 getNewRegNCG IntRep `thenUs` \ tmp2 ->
801 code1 = registerCode register1 tmp1 asmVoid
802 src1 = registerName register1 tmp1
803 code2 = registerCode register2 tmp2 asmVoid
804 src2 = registerName register2 tmp2
805 code__2 dst = asmParThen [code1, code2] .
806 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1)) (ImmInt 0))) (OpReg dst))
808 returnUs (Any IntRep code__2)
811 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
813 sub_code sz x (StInt y)
814 = getRegister x `thenUs` \ register ->
815 getNewRegNCG IntRep `thenUs` \ tmp ->
817 code = registerCode register tmp
818 src1 = registerName register tmp
819 src2 = ImmInt (-(fromInteger y))
821 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2)) (OpReg dst))
823 returnUs (Any IntRep code__2)
825 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
830 -> StixTree -> StixTree
831 -> Bool -- True => division, False => remainder operation
834 -- x must go into eax, edx must be a sign-extension of eax, and y
835 -- should go in some other register (or memory), so that we get
836 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
837 -- put y in memory (if it is not there already)
839 quot_code sz x (StInd pk mem) is_division
840 = getRegister x `thenUs` \ register1 ->
841 getNewRegNCG IntRep `thenUs` \ tmp1 ->
842 getAmode mem `thenUs` \ amode ->
844 code1 = registerCode register1 tmp1 asmVoid
845 src1 = registerName register1 tmp1
846 code2 = amodeCode amode asmVoid
847 src2 = amodeAddr amode
848 code__2 = asmParThen [code1, code2] .
849 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
851 IDIV sz (OpAddr src2)]
853 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
855 quot_code sz x (StInt i) is_division
856 = getRegister x `thenUs` \ register1 ->
857 getNewRegNCG IntRep `thenUs` \ tmp1 ->
859 code1 = registerCode register1 tmp1 asmVoid
860 src1 = registerName register1 tmp1
861 src2 = ImmInt (fromInteger i)
862 code__2 = asmParThen [code1] .
863 mkSeqInstrs [-- we put src2 in (ebx)
864 MOV L (OpImm src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
865 MOV L (OpReg src1) (OpReg eax),
867 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
869 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
871 quot_code sz x y is_division
872 = getRegister x `thenUs` \ register1 ->
873 getNewRegNCG IntRep `thenUs` \ tmp1 ->
874 getRegister y `thenUs` \ register2 ->
875 getNewRegNCG IntRep `thenUs` \ tmp2 ->
877 code1 = registerCode register1 tmp1 asmVoid
878 src1 = registerName register1 tmp1
879 code2 = registerCode register2 tmp2 asmVoid
880 src2 = registerName register2 tmp2
881 code__2 = asmParThen [code1, code2] .
882 if src2 == ecx || src2 == esi
883 then mkSeqInstrs [ MOV L (OpReg src1) (OpReg eax),
885 IDIV sz (OpReg src2)]
886 else mkSeqInstrs [ -- we put src2 in (ebx)
887 MOV L (OpReg src2) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
888 MOV L (OpReg src1) (OpReg eax),
890 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)))]
892 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
893 -----------------------
895 getRegister (StInd pk mem)
896 = getAmode mem `thenUs` \ amode ->
898 code = amodeCode amode
899 src = amodeAddr amode
900 size = primRepToSize pk
902 if pk == DoubleRep || pk == FloatRep
903 then mkSeqInstr (FLD {-DF-} size (OpAddr src))
904 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
906 returnUs (Any pk code__2)
909 getRegister (StInt i)
911 src = ImmInt (fromInteger i)
912 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
914 returnUs (Any IntRep code)
919 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
921 returnUs (Any PtrRep code)
924 imm__2 = case imm of Just x -> x
926 #endif {- i386_TARGET_ARCH -}
927 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
928 #if sparc_TARGET_ARCH
930 getRegister (StDouble d)
931 = getUniqLabelNCG `thenUs` \ lbl ->
932 getNewRegNCG PtrRep `thenUs` \ tmp ->
933 let code dst = mkSeqInstrs [
936 DATA DF [ImmDouble d],
938 SETHI (HI (ImmCLbl lbl)) tmp,
939 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
941 returnUs (Any DoubleRep code)
943 getRegister (StPrim primop [x]) -- unary PrimOps
945 IntNegOp -> trivialUCode (SUB False False g0) x
946 NotOp -> trivialUCode (XNOR False g0) x
948 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
950 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
952 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
953 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
955 OrdOp -> coerceIntCode IntRep x
958 Float2IntOp -> coerceFP2Int x
959 Int2FloatOp -> coerceInt2FP FloatRep x
960 Double2IntOp -> coerceFP2Int x
961 Int2DoubleOp -> coerceInt2FP DoubleRep x
965 fixed_x = if is_float_op -- promote to double
966 then StPrim Float2DoubleOp [x]
969 getRegister (StCall fn cCallConv DoubleRep [x])
973 FloatExpOp -> (True, SLIT("exp"))
974 FloatLogOp -> (True, SLIT("log"))
975 FloatSqrtOp -> (True, SLIT("sqrt"))
977 FloatSinOp -> (True, SLIT("sin"))
978 FloatCosOp -> (True, SLIT("cos"))
979 FloatTanOp -> (True, SLIT("tan"))
981 FloatAsinOp -> (True, SLIT("asin"))
982 FloatAcosOp -> (True, SLIT("acos"))
983 FloatAtanOp -> (True, SLIT("atan"))
985 FloatSinhOp -> (True, SLIT("sinh"))
986 FloatCoshOp -> (True, SLIT("cosh"))
987 FloatTanhOp -> (True, SLIT("tanh"))
989 DoubleExpOp -> (False, SLIT("exp"))
990 DoubleLogOp -> (False, SLIT("log"))
991 DoubleSqrtOp -> (True, SLIT("sqrt"))
993 DoubleSinOp -> (False, SLIT("sin"))
994 DoubleCosOp -> (False, SLIT("cos"))
995 DoubleTanOp -> (False, SLIT("tan"))
997 DoubleAsinOp -> (False, SLIT("asin"))
998 DoubleAcosOp -> (False, SLIT("acos"))
999 DoubleAtanOp -> (False, SLIT("atan"))
1001 DoubleSinhOp -> (False, SLIT("sinh"))
1002 DoubleCoshOp -> (False, SLIT("cosh"))
1003 DoubleTanhOp -> (False, SLIT("tanh"))
1004 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
1006 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
1008 CharGtOp -> condIntReg GTT x y
1009 CharGeOp -> condIntReg GE x y
1010 CharEqOp -> condIntReg EQQ x y
1011 CharNeOp -> condIntReg NE x y
1012 CharLtOp -> condIntReg LTT x y
1013 CharLeOp -> condIntReg LE x y
1015 IntGtOp -> condIntReg GTT x y
1016 IntGeOp -> condIntReg GE x y
1017 IntEqOp -> condIntReg EQQ x y
1018 IntNeOp -> condIntReg NE x y
1019 IntLtOp -> condIntReg LTT x y
1020 IntLeOp -> condIntReg LE x y
1022 WordGtOp -> condIntReg GU x y
1023 WordGeOp -> condIntReg GEU x y
1024 WordEqOp -> condIntReg EQQ x y
1025 WordNeOp -> condIntReg NE x y
1026 WordLtOp -> condIntReg LU x y
1027 WordLeOp -> condIntReg LEU x y
1029 AddrGtOp -> condIntReg GU x y
1030 AddrGeOp -> condIntReg GEU x y
1031 AddrEqOp -> condIntReg EQQ x y
1032 AddrNeOp -> condIntReg NE x y
1033 AddrLtOp -> condIntReg LU x y
1034 AddrLeOp -> condIntReg LEU x y
1036 FloatGtOp -> condFltReg GTT x y
1037 FloatGeOp -> condFltReg GE x y
1038 FloatEqOp -> condFltReg EQQ x y
1039 FloatNeOp -> condFltReg NE x y
1040 FloatLtOp -> condFltReg LTT x y
1041 FloatLeOp -> condFltReg LE x y
1043 DoubleGtOp -> condFltReg GTT x y
1044 DoubleGeOp -> condFltReg GE x y
1045 DoubleEqOp -> condFltReg EQQ x y
1046 DoubleNeOp -> condFltReg NE x y
1047 DoubleLtOp -> condFltReg LTT x y
1048 DoubleLeOp -> condFltReg LE x y
1050 IntAddOp -> trivialCode (ADD False False) x y
1051 IntSubOp -> trivialCode (SUB False False) x y
1053 -- ToDo: teach about V8+ SPARC mul/div instructions
1054 IntMulOp -> imul_div SLIT(".umul") x y
1055 IntQuotOp -> imul_div SLIT(".div") x y
1056 IntRemOp -> imul_div SLIT(".rem") x y
1058 FloatAddOp -> trivialFCode FloatRep FADD x y
1059 FloatSubOp -> trivialFCode FloatRep FSUB x y
1060 FloatMulOp -> trivialFCode FloatRep FMUL x y
1061 FloatDivOp -> trivialFCode FloatRep FDIV x y
1063 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1064 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1065 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1066 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1068 AndOp -> trivialCode (AND False) x y
1069 OrOp -> trivialCode (OR False) x y
1070 XorOp -> trivialCode (XOR False) x y
1071 SllOp -> trivialCode SLL x y
1072 SrlOp -> trivialCode SRL x y
1074 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1075 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1076 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1078 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1079 where promote x = StPrim Float2DoubleOp [x]
1080 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1081 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1083 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1085 getRegister (StInd pk mem)
1086 = getAmode mem `thenUs` \ amode ->
1088 code = amodeCode amode
1089 src = amodeAddr amode
1090 size = primRepToSize pk
1091 code__2 dst = code . mkSeqInstr (LD size src dst)
1093 returnUs (Any pk code__2)
1095 getRegister (StInt i)
1098 src = ImmInt (fromInteger i)
1099 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1101 returnUs (Any IntRep code)
1106 code dst = mkSeqInstrs [
1107 SETHI (HI imm__2) dst,
1108 OR False dst (RIImm (LO imm__2)) dst]
1110 returnUs (Any PtrRep code)
1113 imm__2 = case imm of Just x -> x
1115 #endif {- sparc_TARGET_ARCH -}
1118 %************************************************************************
1120 \subsection{The @Amode@ type}
1122 %************************************************************************
1124 @Amode@s: Memory addressing modes passed up the tree.
1126 data Amode = Amode MachRegsAddr InstrBlock
1128 amodeAddr (Amode addr _) = addr
1129 amodeCode (Amode _ code) = code
1132 Now, given a tree (the argument to an StInd) that references memory,
1133 produce a suitable addressing mode.
1136 getAmode :: StixTree -> UniqSM Amode
1138 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1140 #if alpha_TARGET_ARCH
1142 getAmode (StPrim IntSubOp [x, StInt i])
1143 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1144 getRegister x `thenUs` \ register ->
1146 code = registerCode register tmp
1147 reg = registerName register tmp
1148 off = ImmInt (-(fromInteger i))
1150 returnUs (Amode (AddrRegImm reg off) code)
1152 getAmode (StPrim IntAddOp [x, StInt i])
1153 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1154 getRegister x `thenUs` \ register ->
1156 code = registerCode register tmp
1157 reg = registerName register tmp
1158 off = ImmInt (fromInteger i)
1160 returnUs (Amode (AddrRegImm reg off) code)
1164 = returnUs (Amode (AddrImm imm__2) id)
1167 imm__2 = case imm of Just x -> x
1170 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1171 getRegister other `thenUs` \ register ->
1173 code = registerCode register tmp
1174 reg = registerName register tmp
1176 returnUs (Amode (AddrReg reg) code)
1178 #endif {- alpha_TARGET_ARCH -}
1179 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1180 #if i386_TARGET_ARCH
1182 getAmode (StPrim IntSubOp [x, StInt i])
1183 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1184 getRegister x `thenUs` \ register ->
1186 code = registerCode register tmp
1187 reg = registerName register tmp
1188 off = ImmInt (-(fromInteger i))
1190 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1192 getAmode (StPrim IntAddOp [x, StInt i])
1195 code = mkSeqInstrs []
1197 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1200 imm__2 = case imm of Just x -> x
1202 getAmode (StPrim IntAddOp [x, StInt i])
1203 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1204 getRegister x `thenUs` \ register ->
1206 code = registerCode register tmp
1207 reg = registerName register tmp
1208 off = ImmInt (fromInteger i)
1210 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1212 getAmode (StPrim IntAddOp [x, y])
1213 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1214 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1215 getRegister x `thenUs` \ register1 ->
1216 getRegister y `thenUs` \ register2 ->
1218 code1 = registerCode register1 tmp1 asmVoid
1219 reg1 = registerName register1 tmp1
1220 code2 = registerCode register2 tmp2 asmVoid
1221 reg2 = registerName register2 tmp2
1222 code__2 = asmParThen [code1, code2]
1224 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1229 code = mkSeqInstrs []
1231 returnUs (Amode (ImmAddr imm__2 0) code)
1234 imm__2 = case imm of Just x -> x
1237 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1238 getRegister other `thenUs` \ register ->
1240 code = registerCode register tmp
1241 reg = registerName register tmp
1244 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1246 #endif {- i386_TARGET_ARCH -}
1247 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1248 #if sparc_TARGET_ARCH
1250 getAmode (StPrim IntSubOp [x, StInt i])
1252 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1253 getRegister x `thenUs` \ register ->
1255 code = registerCode register tmp
1256 reg = registerName register tmp
1257 off = ImmInt (-(fromInteger i))
1259 returnUs (Amode (AddrRegImm reg off) code)
1262 getAmode (StPrim IntAddOp [x, StInt i])
1264 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1265 getRegister x `thenUs` \ register ->
1267 code = registerCode register tmp
1268 reg = registerName register tmp
1269 off = ImmInt (fromInteger i)
1271 returnUs (Amode (AddrRegImm reg off) code)
1273 getAmode (StPrim IntAddOp [x, y])
1274 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1275 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1276 getRegister x `thenUs` \ register1 ->
1277 getRegister y `thenUs` \ register2 ->
1279 code1 = registerCode register1 tmp1 asmVoid
1280 reg1 = registerName register1 tmp1
1281 code2 = registerCode register2 tmp2 asmVoid
1282 reg2 = registerName register2 tmp2
1283 code__2 = asmParThen [code1, code2]
1285 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1289 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1291 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1293 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1296 imm__2 = case imm of Just x -> x
1299 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1300 getRegister other `thenUs` \ register ->
1302 code = registerCode register tmp
1303 reg = registerName register tmp
1306 returnUs (Amode (AddrRegImm reg off) code)
1308 #endif {- sparc_TARGET_ARCH -}
1311 %************************************************************************
1313 \subsection{The @CondCode@ type}
1315 %************************************************************************
1317 Condition codes passed up the tree.
1319 data CondCode = CondCode Bool Cond InstrBlock
1321 condName (CondCode _ cond _) = cond
1322 condFloat (CondCode is_float _ _) = is_float
1323 condCode (CondCode _ _ code) = code
1326 Set up a condition code for a conditional branch.
1329 getCondCode :: StixTree -> UniqSM CondCode
1331 #if alpha_TARGET_ARCH
1332 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1333 #endif {- alpha_TARGET_ARCH -}
1334 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1336 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1337 -- yes, they really do seem to want exactly the same!
1339 getCondCode (StPrim primop [x, y])
1341 CharGtOp -> condIntCode GTT x y
1342 CharGeOp -> condIntCode GE x y
1343 CharEqOp -> condIntCode EQQ x y
1344 CharNeOp -> condIntCode NE x y
1345 CharLtOp -> condIntCode LTT x y
1346 CharLeOp -> condIntCode LE x y
1348 IntGtOp -> condIntCode GTT x y
1349 IntGeOp -> condIntCode GE x y
1350 IntEqOp -> condIntCode EQQ x y
1351 IntNeOp -> condIntCode NE x y
1352 IntLtOp -> condIntCode LTT x y
1353 IntLeOp -> condIntCode LE x y
1355 WordGtOp -> condIntCode GU x y
1356 WordGeOp -> condIntCode GEU x y
1357 WordEqOp -> condIntCode EQQ x y
1358 WordNeOp -> condIntCode NE x y
1359 WordLtOp -> condIntCode LU x y
1360 WordLeOp -> condIntCode LEU x y
1362 AddrGtOp -> condIntCode GU x y
1363 AddrGeOp -> condIntCode GEU x y
1364 AddrEqOp -> condIntCode EQQ x y
1365 AddrNeOp -> condIntCode NE x y
1366 AddrLtOp -> condIntCode LU x y
1367 AddrLeOp -> condIntCode LEU x y
1369 FloatGtOp -> condFltCode GTT x y
1370 FloatGeOp -> condFltCode GE x y
1371 FloatEqOp -> condFltCode EQQ x y
1372 FloatNeOp -> condFltCode NE x y
1373 FloatLtOp -> condFltCode LTT x y
1374 FloatLeOp -> condFltCode LE x y
1376 DoubleGtOp -> condFltCode GTT x y
1377 DoubleGeOp -> condFltCode GE x y
1378 DoubleEqOp -> condFltCode EQQ x y
1379 DoubleNeOp -> condFltCode NE x y
1380 DoubleLtOp -> condFltCode LTT x y
1381 DoubleLeOp -> condFltCode LE x y
1383 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1388 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1389 passed back up the tree.
1392 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1394 #if alpha_TARGET_ARCH
1395 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1396 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1397 #endif {- alpha_TARGET_ARCH -}
1399 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1400 #if i386_TARGET_ARCH
1402 condIntCode cond (StInd _ x) y
1404 = getAmode x `thenUs` \ amode ->
1406 code1 = amodeCode amode asmVoid
1407 y__2 = amodeAddr amode
1408 code__2 = asmParThen [code1] .
1409 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1411 returnUs (CondCode False cond code__2)
1414 imm__2 = case imm of Just x -> x
1416 condIntCode cond x (StInt 0)
1417 = getRegister x `thenUs` \ register1 ->
1418 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1420 code1 = registerCode register1 tmp1 asmVoid
1421 src1 = registerName register1 tmp1
1422 code__2 = asmParThen [code1] .
1423 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1425 returnUs (CondCode False cond code__2)
1427 condIntCode cond x y
1429 = getRegister x `thenUs` \ register1 ->
1430 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1432 code1 = registerCode register1 tmp1 asmVoid
1433 src1 = registerName register1 tmp1
1434 code__2 = asmParThen [code1] .
1435 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1437 returnUs (CondCode False cond code__2)
1440 imm__2 = case imm of Just x -> x
1442 condIntCode cond (StInd _ x) y
1443 = getAmode x `thenUs` \ amode ->
1444 getRegister y `thenUs` \ register2 ->
1445 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1447 code1 = amodeCode amode asmVoid
1448 src1 = amodeAddr amode
1449 code2 = registerCode register2 tmp2 asmVoid
1450 src2 = registerName register2 tmp2
1451 code__2 = asmParThen [code1, code2] .
1452 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1454 returnUs (CondCode False cond code__2)
1456 condIntCode cond y (StInd _ x)
1457 = getAmode x `thenUs` \ amode ->
1458 getRegister y `thenUs` \ register2 ->
1459 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1461 code1 = amodeCode amode asmVoid
1462 src1 = amodeAddr amode
1463 code2 = registerCode register2 tmp2 asmVoid
1464 src2 = registerName register2 tmp2
1465 code__2 = asmParThen [code1, code2] .
1466 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1468 returnUs (CondCode False cond code__2)
1470 condIntCode cond x y
1471 = getRegister x `thenUs` \ register1 ->
1472 getRegister y `thenUs` \ register2 ->
1473 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1474 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1476 code1 = registerCode register1 tmp1 asmVoid
1477 src1 = registerName register1 tmp1
1478 code2 = registerCode register2 tmp2 asmVoid
1479 src2 = registerName register2 tmp2
1480 code__2 = asmParThen [code1, code2] .
1481 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1483 returnUs (CondCode False cond code__2)
1487 condFltCode cond x (StDouble 0.0)
1488 = getRegister x `thenUs` \ register1 ->
1489 getNewRegNCG (registerRep register1)
1492 pk1 = registerRep register1
1493 code1 = registerCode register1 tmp1
1494 src1 = registerName register1 tmp1
1496 code__2 = asmParThen [code1 asmVoid] .
1497 mkSeqInstrs [FTST, FSTP DF (OpReg st0), -- or FLDZ, FUCOMPP ?
1499 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1500 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1504 returnUs (CondCode True (fix_FP_cond cond) code__2)
1506 condFltCode cond x y
1507 = getRegister x `thenUs` \ register1 ->
1508 getRegister y `thenUs` \ register2 ->
1509 getNewRegNCG (registerRep register1)
1511 getNewRegNCG (registerRep register2)
1514 pk1 = registerRep register1
1515 code1 = registerCode register1 tmp1
1516 src1 = registerName register1 tmp1
1518 code2 = registerCode register2 tmp2
1519 src2 = registerName register2 tmp2
1521 code__2 = asmParThen [code2 asmVoid, code1 asmVoid] .
1522 mkSeqInstrs [FUCOMPP,
1524 --AND HB (OpImm (ImmInt 68)) (OpReg eax),
1525 --XOR HB (OpImm (ImmInt 64)) (OpReg eax)
1529 returnUs (CondCode True (fix_FP_cond cond) code__2)
1531 {- On the 486, the flags set by FP compare are the unsigned ones!
1532 (This looks like a HACK to me. WDP 96/03)
1535 fix_FP_cond :: Cond -> Cond
1537 fix_FP_cond GE = GEU
1538 fix_FP_cond GTT = GU
1539 fix_FP_cond LTT = LU
1540 fix_FP_cond LE = LEU
1541 fix_FP_cond any = any
1543 #endif {- i386_TARGET_ARCH -}
1544 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1545 #if sparc_TARGET_ARCH
1547 condIntCode cond x (StInt y)
1549 = getRegister x `thenUs` \ register ->
1550 getNewRegNCG IntRep `thenUs` \ tmp ->
1552 code = registerCode register tmp
1553 src1 = registerName register tmp
1554 src2 = ImmInt (fromInteger y)
1555 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1557 returnUs (CondCode False cond code__2)
1559 condIntCode cond x y
1560 = getRegister x `thenUs` \ register1 ->
1561 getRegister y `thenUs` \ register2 ->
1562 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1563 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1565 code1 = registerCode register1 tmp1 asmVoid
1566 src1 = registerName register1 tmp1
1567 code2 = registerCode register2 tmp2 asmVoid
1568 src2 = registerName register2 tmp2
1569 code__2 = asmParThen [code1, code2] .
1570 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1572 returnUs (CondCode False cond code__2)
1575 condFltCode cond x y
1576 = getRegister x `thenUs` \ register1 ->
1577 getRegister y `thenUs` \ register2 ->
1578 getNewRegNCG (registerRep register1)
1580 getNewRegNCG (registerRep register2)
1582 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1584 promote x = asmInstr (FxTOy F DF x tmp)
1586 pk1 = registerRep register1
1587 code1 = registerCode register1 tmp1
1588 src1 = registerName register1 tmp1
1590 pk2 = registerRep register2
1591 code2 = registerCode register2 tmp2
1592 src2 = registerName register2 tmp2
1596 asmParThen [code1 asmVoid, code2 asmVoid] .
1597 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1598 else if pk1 == FloatRep then
1599 asmParThen [code1 (promote src1), code2 asmVoid] .
1600 mkSeqInstr (FCMP True DF tmp src2)
1602 asmParThen [code1 asmVoid, code2 (promote src2)] .
1603 mkSeqInstr (FCMP True DF src1 tmp)
1605 returnUs (CondCode True cond code__2)
1607 #endif {- sparc_TARGET_ARCH -}
1610 %************************************************************************
1612 \subsection{Generating assignments}
1614 %************************************************************************
1616 Assignments are really at the heart of the whole code generation
1617 business. Almost all top-level nodes of any real importance are
1618 assignments, which correspond to loads, stores, or register transfers.
1619 If we're really lucky, some of the register transfers will go away,
1620 because we can use the destination register to complete the code
1621 generation for the right hand side. This only fails when the right
1622 hand side is forced into a fixed register (e.g. the result of a call).
1625 assignIntCode, assignFltCode
1626 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1628 #if alpha_TARGET_ARCH
1630 assignIntCode pk (StInd _ dst) src
1631 = getNewRegNCG IntRep `thenUs` \ tmp ->
1632 getAmode dst `thenUs` \ amode ->
1633 getRegister src `thenUs` \ register ->
1635 code1 = amodeCode amode asmVoid
1636 dst__2 = amodeAddr amode
1637 code2 = registerCode register tmp asmVoid
1638 src__2 = registerName register tmp
1639 sz = primRepToSize pk
1640 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1644 assignIntCode pk dst src
1645 = getRegister dst `thenUs` \ register1 ->
1646 getRegister src `thenUs` \ register2 ->
1648 dst__2 = registerName register1 zeroh
1649 code = registerCode register2 dst__2
1650 src__2 = registerName register2 dst__2
1651 code__2 = if isFixed register2
1652 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1657 #endif {- alpha_TARGET_ARCH -}
1658 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1659 #if i386_TARGET_ARCH
1661 assignIntCode pk (StInd _ dst) src
1662 = getAmode dst `thenUs` \ amode ->
1663 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1665 code1 = amodeCode amode asmVoid
1666 dst__2 = amodeAddr amode
1667 code__2 = asmParThen [code1, codesrc asmVoid] .
1668 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1674 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1678 = returnUs (asmParThen [], OpImm imm_op, L)
1681 imm_op = case imm of Just x -> x
1684 = getRegister op `thenUs` \ register ->
1685 getNewRegNCG (registerRep register)
1688 code = registerCode register tmp
1689 reg = registerName register tmp
1690 pk = registerRep register
1691 sz = primRepToSize pk
1693 returnUs (code, OpReg reg, sz)
1695 assignIntCode pk dst (StInd _ src)
1696 = getNewRegNCG IntRep `thenUs` \ tmp ->
1697 getAmode src `thenUs` \ amode ->
1698 getRegister dst `thenUs` \ register ->
1700 code1 = amodeCode amode asmVoid
1701 src__2 = amodeAddr amode
1702 code2 = registerCode register tmp asmVoid
1703 dst__2 = registerName register tmp
1704 sz = primRepToSize pk
1705 code__2 = asmParThen [code1, code2] .
1706 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1710 assignIntCode pk dst src
1711 = getRegister dst `thenUs` \ register1 ->
1712 getRegister src `thenUs` \ register2 ->
1713 getNewRegNCG IntRep `thenUs` \ tmp ->
1715 dst__2 = registerName register1 tmp
1716 code = registerCode register2 dst__2
1717 src__2 = registerName register2 dst__2
1718 code__2 = if isFixed register2 && dst__2 /= src__2
1719 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1724 #endif {- i386_TARGET_ARCH -}
1725 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1726 #if sparc_TARGET_ARCH
1728 assignIntCode pk (StInd _ dst) src
1729 = getNewRegNCG IntRep `thenUs` \ tmp ->
1730 getAmode dst `thenUs` \ amode ->
1731 getRegister src `thenUs` \ register ->
1733 code1 = amodeCode amode asmVoid
1734 dst__2 = amodeAddr amode
1735 code2 = registerCode register tmp asmVoid
1736 src__2 = registerName register tmp
1737 sz = primRepToSize pk
1738 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1742 assignIntCode pk dst src
1743 = getRegister dst `thenUs` \ register1 ->
1744 getRegister src `thenUs` \ register2 ->
1746 dst__2 = registerName register1 g0
1747 code = registerCode register2 dst__2
1748 src__2 = registerName register2 dst__2
1749 code__2 = if isFixed register2
1750 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1755 #endif {- sparc_TARGET_ARCH -}
1758 % --------------------------------
1759 Floating-point assignments:
1760 % --------------------------------
1762 #if alpha_TARGET_ARCH
1764 assignFltCode pk (StInd _ dst) src
1765 = getNewRegNCG pk `thenUs` \ tmp ->
1766 getAmode dst `thenUs` \ amode ->
1767 getRegister src `thenUs` \ register ->
1769 code1 = amodeCode amode asmVoid
1770 dst__2 = amodeAddr amode
1771 code2 = registerCode register tmp asmVoid
1772 src__2 = registerName register tmp
1773 sz = primRepToSize pk
1774 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1778 assignFltCode pk dst src
1779 = getRegister dst `thenUs` \ register1 ->
1780 getRegister src `thenUs` \ register2 ->
1782 dst__2 = registerName register1 zeroh
1783 code = registerCode register2 dst__2
1784 src__2 = registerName register2 dst__2
1785 code__2 = if isFixed register2
1786 then code . mkSeqInstr (FMOV src__2 dst__2)
1791 #endif {- alpha_TARGET_ARCH -}
1792 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1793 #if i386_TARGET_ARCH
1795 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1796 = getNewRegNCG IntRep `thenUs` \ tmp ->
1797 getAmode src `thenUs` \ amodesrc ->
1798 getAmode dst `thenUs` \ amodedst ->
1799 --getRegister src `thenUs` \ register ->
1801 codesrc1 = amodeCode amodesrc asmVoid
1802 addrsrc1 = amodeAddr amodesrc
1803 codedst1 = amodeCode amodedst asmVoid
1804 addrdst1 = amodeAddr amodedst
1805 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1806 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1808 code__2 = asmParThen [codesrc1, codedst1] .
1809 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1810 MOV L (OpReg tmp) (OpAddr addrdst1)]
1813 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1814 MOV L (OpReg tmp) (OpAddr addrdst2)]
1819 assignFltCode pk (StInd _ dst) src
1820 = --getNewRegNCG pk `thenUs` \ tmp ->
1821 getAmode dst `thenUs` \ amode ->
1822 getRegister src `thenUs` \ register ->
1824 sz = primRepToSize pk
1825 dst__2 = amodeAddr amode
1827 code1 = amodeCode amode asmVoid
1828 code2 = registerCode register {-tmp-}st0 asmVoid
1830 --src__2= registerName register tmp
1831 pk__2 = registerRep register
1832 sz__2 = primRepToSize pk__2
1834 code__2 = asmParThen [code1, code2] .
1835 mkSeqInstr (FSTP sz (OpAddr dst__2))
1839 assignFltCode pk dst src
1840 = getRegister dst `thenUs` \ register1 ->
1841 getRegister src `thenUs` \ register2 ->
1842 --getNewRegNCG (registerRep register2)
1843 -- `thenUs` \ tmp ->
1845 sz = primRepToSize pk
1846 dst__2 = registerName register1 st0 --tmp
1848 code = registerCode register2 dst__2
1849 src__2 = registerName register2 dst__2
1855 #endif {- i386_TARGET_ARCH -}
1856 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1857 #if sparc_TARGET_ARCH
1859 assignFltCode pk (StInd _ dst) src
1860 = getNewRegNCG pk `thenUs` \ tmp1 ->
1861 getAmode dst `thenUs` \ amode ->
1862 getRegister src `thenUs` \ register ->
1864 sz = primRepToSize pk
1865 dst__2 = amodeAddr amode
1867 code1 = amodeCode amode asmVoid
1868 code2 = registerCode register tmp1 asmVoid
1870 src__2 = registerName register tmp1
1871 pk__2 = registerRep register
1872 sz__2 = primRepToSize pk__2
1874 code__2 = asmParThen [code1, code2] .
1876 mkSeqInstr (ST sz src__2 dst__2)
1878 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1882 assignFltCode pk dst src
1883 = getRegister dst `thenUs` \ register1 ->
1884 getRegister src `thenUs` \ register2 ->
1886 pk__2 = registerRep register2
1887 sz__2 = primRepToSize pk__2
1889 getNewRegNCG pk__2 `thenUs` \ tmp ->
1891 sz = primRepToSize pk
1892 dst__2 = registerName register1 g0 -- must be Fixed
1895 reg__2 = if pk /= pk__2 then tmp else dst__2
1897 code = registerCode register2 reg__2
1899 src__2 = registerName register2 reg__2
1903 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1904 else if isFixed register2 then
1905 code . mkSeqInstr (FMOV sz src__2 dst__2)
1911 #endif {- sparc_TARGET_ARCH -}
1914 %************************************************************************
1916 \subsection{Generating an unconditional branch}
1918 %************************************************************************
1920 We accept two types of targets: an immediate CLabel or a tree that
1921 gets evaluated into a register. Any CLabels which are AsmTemporaries
1922 are assumed to be in the local block of code, close enough for a
1923 branch instruction. Other CLabels are assumed to be far away.
1925 (If applicable) Do not fill the delay slots here; you will confuse the
1929 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1931 #if alpha_TARGET_ARCH
1933 genJump (StCLbl lbl)
1934 | isAsmTemp lbl = returnInstr (BR target)
1935 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1937 target = ImmCLbl lbl
1940 = getRegister tree `thenUs` \ register ->
1941 getNewRegNCG PtrRep `thenUs` \ tmp ->
1943 dst = registerName register pv
1944 code = registerCode register pv
1945 target = registerName register pv
1947 if isFixed register then
1948 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1950 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1952 #endif {- alpha_TARGET_ARCH -}
1953 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1954 #if i386_TARGET_ARCH
1957 genJump (StCLbl lbl)
1958 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1959 | otherwise = returnInstrs [JMP (OpImm target)]
1961 target = ImmCLbl lbl
1964 genJump (StInd pk mem)
1965 = getAmode mem `thenUs` \ amode ->
1967 code = amodeCode amode
1968 target = amodeAddr amode
1970 returnSeq code [JMP (OpAddr target)]
1974 = returnInstr (JMP (OpImm target))
1977 = getRegister tree `thenUs` \ register ->
1978 getNewRegNCG PtrRep `thenUs` \ tmp ->
1980 code = registerCode register tmp
1981 target = registerName register tmp
1983 returnSeq code [JMP (OpReg target)]
1986 target = case imm of Just x -> x
1988 #endif {- i386_TARGET_ARCH -}
1989 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1990 #if sparc_TARGET_ARCH
1992 genJump (StCLbl lbl)
1993 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1994 | otherwise = returnInstrs [CALL target 0 True, NOP]
1996 target = ImmCLbl lbl
1999 = getRegister tree `thenUs` \ register ->
2000 getNewRegNCG PtrRep `thenUs` \ tmp ->
2002 code = registerCode register tmp
2003 target = registerName register tmp
2005 returnSeq code [JMP (AddrRegReg target g0), NOP]
2007 #endif {- sparc_TARGET_ARCH -}
2010 %************************************************************************
2012 \subsection{Conditional jumps}
2014 %************************************************************************
2016 Conditional jumps are always to local labels, so we can use branch
2017 instructions. We peek at the arguments to decide what kind of
2020 ALPHA: For comparisons with 0, we're laughing, because we can just do
2021 the desired conditional branch.
2023 I386: First, we have to ensure that the condition
2024 codes are set according to the supplied comparison operation.
2026 SPARC: First, we have to ensure that the condition codes are set
2027 according to the supplied comparison operation. We generate slightly
2028 different code for floating point comparisons, because a floating
2029 point operation cannot directly precede a @BF@. We assume the worst
2030 and fill that slot with a @NOP@.
2032 SPARC: Do not fill the delay slots here; you will confuse the register
2037 :: CLabel -- the branch target
2038 -> StixTree -- the condition on which to branch
2039 -> UniqSM InstrBlock
2041 #if alpha_TARGET_ARCH
2043 genCondJump lbl (StPrim op [x, StInt 0])
2044 = getRegister x `thenUs` \ register ->
2045 getNewRegNCG (registerRep register)
2048 code = registerCode register tmp
2049 value = registerName register tmp
2050 pk = registerRep register
2051 target = ImmCLbl lbl
2053 returnSeq code [BI (cmpOp op) value target]
2055 cmpOp CharGtOp = GTT
2057 cmpOp CharEqOp = EQQ
2059 cmpOp CharLtOp = LTT
2068 cmpOp WordGeOp = ALWAYS
2069 cmpOp WordEqOp = EQQ
2071 cmpOp WordLtOp = NEVER
2072 cmpOp WordLeOp = EQQ
2074 cmpOp AddrGeOp = ALWAYS
2075 cmpOp AddrEqOp = EQQ
2077 cmpOp AddrLtOp = NEVER
2078 cmpOp AddrLeOp = EQQ
2080 genCondJump lbl (StPrim op [x, StDouble 0.0])
2081 = getRegister x `thenUs` \ register ->
2082 getNewRegNCG (registerRep register)
2085 code = registerCode register tmp
2086 value = registerName register tmp
2087 pk = registerRep register
2088 target = ImmCLbl lbl
2090 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2092 cmpOp FloatGtOp = GTT
2093 cmpOp FloatGeOp = GE
2094 cmpOp FloatEqOp = EQQ
2095 cmpOp FloatNeOp = NE
2096 cmpOp FloatLtOp = LTT
2097 cmpOp FloatLeOp = LE
2098 cmpOp DoubleGtOp = GTT
2099 cmpOp DoubleGeOp = GE
2100 cmpOp DoubleEqOp = EQQ
2101 cmpOp DoubleNeOp = NE
2102 cmpOp DoubleLtOp = LTT
2103 cmpOp DoubleLeOp = LE
2105 genCondJump lbl (StPrim op [x, y])
2107 = trivialFCode pr instr x y `thenUs` \ register ->
2108 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2110 code = registerCode register tmp
2111 result = registerName register tmp
2112 target = ImmCLbl lbl
2114 returnUs (code . mkSeqInstr (BF cond result target))
2116 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2118 fltCmpOp op = case op of
2132 (instr, cond) = case op of
2133 FloatGtOp -> (FCMP TF LE, EQQ)
2134 FloatGeOp -> (FCMP TF LTT, EQQ)
2135 FloatEqOp -> (FCMP TF EQQ, NE)
2136 FloatNeOp -> (FCMP TF EQQ, EQQ)
2137 FloatLtOp -> (FCMP TF LTT, NE)
2138 FloatLeOp -> (FCMP TF LE, NE)
2139 DoubleGtOp -> (FCMP TF LE, EQQ)
2140 DoubleGeOp -> (FCMP TF LTT, EQQ)
2141 DoubleEqOp -> (FCMP TF EQQ, NE)
2142 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2143 DoubleLtOp -> (FCMP TF LTT, NE)
2144 DoubleLeOp -> (FCMP TF LE, NE)
2146 genCondJump lbl (StPrim op [x, y])
2147 = trivialCode instr x y `thenUs` \ register ->
2148 getNewRegNCG IntRep `thenUs` \ tmp ->
2150 code = registerCode register tmp
2151 result = registerName register tmp
2152 target = ImmCLbl lbl
2154 returnUs (code . mkSeqInstr (BI cond result target))
2156 (instr, cond) = case op of
2157 CharGtOp -> (CMP LE, EQQ)
2158 CharGeOp -> (CMP LTT, EQQ)
2159 CharEqOp -> (CMP EQQ, NE)
2160 CharNeOp -> (CMP EQQ, EQQ)
2161 CharLtOp -> (CMP LTT, NE)
2162 CharLeOp -> (CMP LE, NE)
2163 IntGtOp -> (CMP LE, EQQ)
2164 IntGeOp -> (CMP LTT, EQQ)
2165 IntEqOp -> (CMP EQQ, NE)
2166 IntNeOp -> (CMP EQQ, EQQ)
2167 IntLtOp -> (CMP LTT, NE)
2168 IntLeOp -> (CMP LE, NE)
2169 WordGtOp -> (CMP ULE, EQQ)
2170 WordGeOp -> (CMP ULT, EQQ)
2171 WordEqOp -> (CMP EQQ, NE)
2172 WordNeOp -> (CMP EQQ, EQQ)
2173 WordLtOp -> (CMP ULT, NE)
2174 WordLeOp -> (CMP ULE, NE)
2175 AddrGtOp -> (CMP ULE, EQQ)
2176 AddrGeOp -> (CMP ULT, EQQ)
2177 AddrEqOp -> (CMP EQQ, NE)
2178 AddrNeOp -> (CMP EQQ, EQQ)
2179 AddrLtOp -> (CMP ULT, NE)
2180 AddrLeOp -> (CMP ULE, NE)
2182 #endif {- alpha_TARGET_ARCH -}
2183 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2184 #if i386_TARGET_ARCH
2186 genCondJump lbl bool
2187 = getCondCode bool `thenUs` \ condition ->
2189 code = condCode condition
2190 cond = condName condition
2191 target = ImmCLbl lbl
2193 returnSeq code [JXX cond lbl]
2195 #endif {- i386_TARGET_ARCH -}
2196 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2197 #if sparc_TARGET_ARCH
2199 genCondJump lbl bool
2200 = getCondCode bool `thenUs` \ condition ->
2202 code = condCode condition
2203 cond = condName condition
2204 target = ImmCLbl lbl
2207 if condFloat condition then
2208 [NOP, BF cond False target, NOP]
2210 [BI cond False target, NOP]
2213 #endif {- sparc_TARGET_ARCH -}
2216 %************************************************************************
2218 \subsection{Generating C calls}
2220 %************************************************************************
2222 Now the biggest nightmare---calls. Most of the nastiness is buried in
2223 @get_arg@, which moves the arguments to the correct registers/stack
2224 locations. Apart from that, the code is easy.
2226 (If applicable) Do not fill the delay slots here; you will confuse the
2231 :: FAST_STRING -- function to call
2233 -> PrimRep -- type of the result
2234 -> [StixTree] -- arguments (of mixed type)
2235 -> UniqSM InstrBlock
2237 #if alpha_TARGET_ARCH
2239 genCCall fn cconv kind args
2240 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2241 `thenUs` \ ((unused,_), argCode) ->
2243 nRegs = length allArgRegs - length unused
2244 code = asmParThen (map ($ asmVoid) argCode)
2247 LDA pv (AddrImm (ImmLab (ptext fn))),
2248 JSR ra (AddrReg pv) nRegs,
2249 LDGP gp (AddrReg ra)]
2251 ------------------------
2252 {- Try to get a value into a specific register (or registers) for
2253 a call. The first 6 arguments go into the appropriate
2254 argument register (separate registers for integer and floating
2255 point arguments, but used in lock-step), and the remaining
2256 arguments are dumped to the stack, beginning at 0(sp). Our
2257 first argument is a pair of the list of remaining argument
2258 registers to be assigned for this call and the next stack
2259 offset to use for overflowing arguments. This way,
2260 @get_Arg@ can be applied to all of a call's arguments using
2264 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2265 -> StixTree -- Current argument
2266 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2268 -- We have to use up all of our argument registers first...
2270 get_arg ((iDst,fDst):dsts, offset) arg
2271 = getRegister arg `thenUs` \ register ->
2273 reg = if isFloatingRep pk then fDst else iDst
2274 code = registerCode register reg
2275 src = registerName register reg
2276 pk = registerRep register
2279 if isFloatingRep pk then
2280 ((dsts, offset), if isFixed register then
2281 code . mkSeqInstr (FMOV src fDst)
2284 ((dsts, offset), if isFixed register then
2285 code . mkSeqInstr (OR src (RIReg src) iDst)
2288 -- Once we have run out of argument registers, we move to the
2291 get_arg ([], offset) arg
2292 = getRegister arg `thenUs` \ register ->
2293 getNewRegNCG (registerRep register)
2296 code = registerCode register tmp
2297 src = registerName register tmp
2298 pk = registerRep register
2299 sz = primRepToSize pk
2301 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2303 #endif {- alpha_TARGET_ARCH -}
2304 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2305 #if i386_TARGET_ARCH
2307 genCCall fn cconv kind [StInt i]
2308 | fn == SLIT ("PerformGC_wrapper")
2309 = let call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2310 CALL (ImmLit (ptext (if underscorePrefix
2311 then (SLIT ("_PerformGC_wrapper"))
2312 else (SLIT ("PerformGC_wrapper")))))]
2317 genCCall fn cconv kind args
2318 = mapUs get_call_arg args `thenUs` \ sizes_and_argCodes ->
2320 (sizes, argCode) = unzip sizes_and_argCodes
2321 tot_arg_size = sum (map (\sz -> case sz of DF -> 8; _ -> 4) sizes)
2323 code2 = asmParThen (map ($ asmVoid) (reverse argCode))
2324 call = [CALL fn__2 ,
2325 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)
2328 returnSeq (code2) call
2331 -- function names that begin with '.' are assumed to be special
2332 -- internally generated names like '.mul,' which don't get an
2333 -- underscore prefix
2334 -- ToDo:needed (WDP 96/03) ???
2335 fn__2 = case (_HEAD_ fn) of
2336 '.' -> ImmLit (ptext fn)
2337 _ -> ImmLab (ptext fn)
2340 get_call_arg :: StixTree{-current argument-}
2341 -> UniqSM (Size, InstrBlock) -- arg size, code
2344 = get_op arg `thenUs` \ (code, op, sz) ->
2348 mkSeqInstr (FLD L op) .
2349 mkSeqInstr (SUB L (OpImm (ImmInt 8)) (OpReg esp)) .
2350 mkSeqInstr (FSTP DF (OpAddr (AddrBaseIndex
2352 Nothing (ImmInt 0))))
2355 code . mkSeqInstr (PUSH sz op))
2360 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
2363 = returnUs (asmParThen [], OpImm (ImmInt (fromInteger i)), L)
2365 get_op (StInd pk mem)
2366 = getAmode mem `thenUs` \ amode ->
2368 code = amodeCode amode --asmVoid
2369 addr = amodeAddr amode
2370 sz = primRepToSize pk
2372 returnUs (code, OpAddr addr, sz)
2375 = getRegister op `thenUs` \ register ->
2376 getNewRegNCG (registerRep register)
2379 code = registerCode register tmp
2380 reg = registerName register tmp
2381 pk = registerRep register
2382 sz = primRepToSize pk
2384 returnUs (code, OpReg reg, sz)
2386 #endif {- i386_TARGET_ARCH -}
2387 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2388 #if sparc_TARGET_ARCH
2390 genCCall fn cconv kind args
2391 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2392 `thenUs` \ ((unused,_), argCode) ->
2394 nRegs = length allArgRegs - length unused
2395 call = CALL fn__2 nRegs False
2396 code = asmParThen (map ($ asmVoid) argCode)
2398 returnSeq code [call, NOP]
2400 -- function names that begin with '.' are assumed to be special
2401 -- internally generated names like '.mul,' which don't get an
2402 -- underscore prefix
2403 -- ToDo:needed (WDP 96/03) ???
2404 fn__2 = case (_HEAD_ fn) of
2405 '.' -> ImmLit (ptext fn)
2406 _ -> ImmLab (ptext fn)
2408 ------------------------------------
2409 {- Try to get a value into a specific register (or registers) for
2410 a call. The SPARC calling convention is an absolute
2411 nightmare. The first 6x32 bits of arguments are mapped into
2412 %o0 through %o5, and the remaining arguments are dumped to the
2413 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2414 first argument is a pair of the list of remaining argument
2415 registers to be assigned for this call and the next stack
2416 offset to use for overflowing arguments. This way,
2417 @get_arg@ can be applied to all of a call's arguments using
2421 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2422 -> StixTree -- Current argument
2423 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2425 -- We have to use up all of our argument registers first...
2427 get_arg (dst:dsts, offset) arg
2428 = getRegister arg `thenUs` \ register ->
2429 getNewRegNCG (registerRep register)
2432 reg = if isFloatingRep pk then tmp else dst
2433 code = registerCode register reg
2434 src = registerName register reg
2435 pk = registerRep register
2437 returnUs (case pk of
2440 [] -> (([], offset + 1), code . mkSeqInstrs [
2441 -- conveniently put the second part in the right stack
2442 -- location, and load the first part into %o5
2443 ST DF src (spRel (offset - 1)),
2444 LD W (spRel (offset - 1)) dst])
2445 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2446 ST DF src (spRel (-2)),
2447 LD W (spRel (-2)) dst,
2448 LD W (spRel (-1)) dst__2])
2449 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2450 ST F src (spRel (-2)),
2451 LD W (spRel (-2)) dst])
2452 _ -> ((dsts, offset), if isFixed register then
2453 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2456 -- Once we have run out of argument registers, we move to the
2459 get_arg ([], offset) arg
2460 = getRegister arg `thenUs` \ register ->
2461 getNewRegNCG (registerRep register)
2464 code = registerCode register tmp
2465 src = registerName register tmp
2466 pk = registerRep register
2467 sz = primRepToSize pk
2468 words = if pk == DoubleRep then 2 else 1
2470 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2472 #endif {- sparc_TARGET_ARCH -}
2475 %************************************************************************
2477 \subsection{Support bits}
2479 %************************************************************************
2481 %************************************************************************
2483 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2485 %************************************************************************
2487 Turn those condition codes into integers now (when they appear on
2488 the right hand side of an assignment).
2490 (If applicable) Do not fill the delay slots here; you will confuse the
2494 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2496 #if alpha_TARGET_ARCH
2497 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2498 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2499 #endif {- alpha_TARGET_ARCH -}
2501 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2502 #if i386_TARGET_ARCH
2505 = condIntCode cond x y `thenUs` \ condition ->
2506 getNewRegNCG IntRep `thenUs` \ tmp ->
2507 --getRegister dst `thenUs` \ register ->
2509 --code2 = registerCode register tmp asmVoid
2510 --dst__2 = registerName register tmp
2511 code = condCode condition
2512 cond = condName condition
2513 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2514 code__2 dst = code . mkSeqInstrs [
2515 SETCC cond (OpReg tmp),
2516 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2517 MOV L (OpReg tmp) (OpReg dst)]
2519 returnUs (Any IntRep code__2)
2522 = getUniqLabelNCG `thenUs` \ lbl1 ->
2523 getUniqLabelNCG `thenUs` \ lbl2 ->
2524 condFltCode cond x y `thenUs` \ condition ->
2526 code = condCode condition
2527 cond = condName condition
2528 code__2 dst = code . mkSeqInstrs [
2530 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2533 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2536 returnUs (Any IntRep code__2)
2538 #endif {- i386_TARGET_ARCH -}
2539 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2540 #if sparc_TARGET_ARCH
2542 condIntReg EQQ x (StInt 0)
2543 = getRegister x `thenUs` \ register ->
2544 getNewRegNCG IntRep `thenUs` \ tmp ->
2546 code = registerCode register tmp
2547 src = registerName register tmp
2548 code__2 dst = code . mkSeqInstrs [
2549 SUB False True g0 (RIReg src) g0,
2550 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2552 returnUs (Any IntRep code__2)
2555 = getRegister x `thenUs` \ register1 ->
2556 getRegister y `thenUs` \ register2 ->
2557 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2558 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2560 code1 = registerCode register1 tmp1 asmVoid
2561 src1 = registerName register1 tmp1
2562 code2 = registerCode register2 tmp2 asmVoid
2563 src2 = registerName register2 tmp2
2564 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2565 XOR False src1 (RIReg src2) dst,
2566 SUB False True g0 (RIReg dst) g0,
2567 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2569 returnUs (Any IntRep code__2)
2571 condIntReg NE x (StInt 0)
2572 = getRegister x `thenUs` \ register ->
2573 getNewRegNCG IntRep `thenUs` \ tmp ->
2575 code = registerCode register tmp
2576 src = registerName register tmp
2577 code__2 dst = code . mkSeqInstrs [
2578 SUB False True g0 (RIReg src) g0,
2579 ADD True False g0 (RIImm (ImmInt 0)) dst]
2581 returnUs (Any IntRep code__2)
2584 = getRegister x `thenUs` \ register1 ->
2585 getRegister y `thenUs` \ register2 ->
2586 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2587 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2589 code1 = registerCode register1 tmp1 asmVoid
2590 src1 = registerName register1 tmp1
2591 code2 = registerCode register2 tmp2 asmVoid
2592 src2 = registerName register2 tmp2
2593 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2594 XOR False src1 (RIReg src2) dst,
2595 SUB False True g0 (RIReg dst) g0,
2596 ADD True False g0 (RIImm (ImmInt 0)) dst]
2598 returnUs (Any IntRep code__2)
2601 = getUniqLabelNCG `thenUs` \ lbl1 ->
2602 getUniqLabelNCG `thenUs` \ lbl2 ->
2603 condIntCode cond x y `thenUs` \ condition ->
2605 code = condCode condition
2606 cond = condName condition
2607 code__2 dst = code . mkSeqInstrs [
2608 BI cond False (ImmCLbl lbl1), NOP,
2609 OR False g0 (RIImm (ImmInt 0)) dst,
2610 BI ALWAYS False (ImmCLbl lbl2), NOP,
2612 OR False g0 (RIImm (ImmInt 1)) dst,
2615 returnUs (Any IntRep code__2)
2618 = getUniqLabelNCG `thenUs` \ lbl1 ->
2619 getUniqLabelNCG `thenUs` \ lbl2 ->
2620 condFltCode cond x y `thenUs` \ condition ->
2622 code = condCode condition
2623 cond = condName condition
2624 code__2 dst = code . mkSeqInstrs [
2626 BF cond False (ImmCLbl lbl1), NOP,
2627 OR False g0 (RIImm (ImmInt 0)) dst,
2628 BI ALWAYS False (ImmCLbl lbl2), NOP,
2630 OR False g0 (RIImm (ImmInt 1)) dst,
2633 returnUs (Any IntRep code__2)
2635 #endif {- sparc_TARGET_ARCH -}
2638 %************************************************************************
2640 \subsubsection{@trivial*Code@: deal with trivial instructions}
2642 %************************************************************************
2644 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2645 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2646 for constants on the right hand side, because that's where the generic
2647 optimizer will have put them.
2649 Similarly, for unary instructions, we don't have to worry about
2650 matching an StInt as the argument, because genericOpt will already
2651 have handled the constant-folding.
2655 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2656 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2657 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2659 -> StixTree -> StixTree -- the two arguments
2664 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2665 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2667 {-this bizarre type for i386 seems a little too weird (WDP 96/03)-}
2668 (Size -> Operand -> Instr)
2669 -> (Size -> Operand -> Instr) {-reversed instr-}
2671 -> Instr {-reversed instr: pop-}
2673 -> StixTree -> StixTree -- the two arguments
2677 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2678 ,IF_ARCH_i386 ((Operand -> Instr)
2679 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2681 -> StixTree -- the one argument
2686 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2687 ,IF_ARCH_i386 (Instr
2688 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2690 -> StixTree -- the one argument
2693 #if alpha_TARGET_ARCH
2695 trivialCode instr x (StInt y)
2697 = getRegister x `thenUs` \ register ->
2698 getNewRegNCG IntRep `thenUs` \ tmp ->
2700 code = registerCode register tmp
2701 src1 = registerName register tmp
2702 src2 = ImmInt (fromInteger y)
2703 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2705 returnUs (Any IntRep code__2)
2707 trivialCode instr x y
2708 = getRegister x `thenUs` \ register1 ->
2709 getRegister y `thenUs` \ register2 ->
2710 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2711 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2713 code1 = registerCode register1 tmp1 asmVoid
2714 src1 = registerName register1 tmp1
2715 code2 = registerCode register2 tmp2 asmVoid
2716 src2 = registerName register2 tmp2
2717 code__2 dst = asmParThen [code1, code2] .
2718 mkSeqInstr (instr src1 (RIReg src2) dst)
2720 returnUs (Any IntRep code__2)
2723 trivialUCode instr x
2724 = getRegister x `thenUs` \ register ->
2725 getNewRegNCG IntRep `thenUs` \ tmp ->
2727 code = registerCode register tmp
2728 src = registerName register tmp
2729 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2731 returnUs (Any IntRep code__2)
2734 trivialFCode _ instr x y
2735 = getRegister x `thenUs` \ register1 ->
2736 getRegister y `thenUs` \ register2 ->
2737 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2738 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2740 code1 = registerCode register1 tmp1
2741 src1 = registerName register1 tmp1
2743 code2 = registerCode register2 tmp2
2744 src2 = registerName register2 tmp2
2746 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2747 mkSeqInstr (instr src1 src2 dst)
2749 returnUs (Any DoubleRep code__2)
2751 trivialUFCode _ instr x
2752 = getRegister x `thenUs` \ register ->
2753 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2755 code = registerCode register tmp
2756 src = registerName register tmp
2757 code__2 dst = code . mkSeqInstr (instr src dst)
2759 returnUs (Any DoubleRep code__2)
2761 #endif {- alpha_TARGET_ARCH -}
2762 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2763 #if i386_TARGET_ARCH
2765 trivialCode instr x y
2767 = getRegister x `thenUs` \ register1 ->
2768 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2770 code__2 dst = let code1 = registerCode register1 dst
2771 src1 = registerName register1 dst
2773 if isFixed register1 && src1 /= dst
2774 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2775 instr (OpImm imm__2) (OpReg dst)]
2777 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2779 returnUs (Any IntRep code__2)
2782 imm__2 = case imm of Just x -> x
2784 trivialCode instr x y
2786 = getRegister y `thenUs` \ register1 ->
2787 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2789 code__2 dst = let code1 = registerCode register1 dst
2790 src1 = registerName register1 dst
2792 if isFixed register1 && src1 /= dst
2793 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2794 instr (OpImm imm__2) (OpReg dst)]
2796 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2798 returnUs (Any IntRep code__2)
2801 imm__2 = case imm of Just x -> x
2803 trivialCode instr x (StInd pk mem)
2804 = getRegister x `thenUs` \ register ->
2805 --getNewRegNCG IntRep `thenUs` \ tmp ->
2806 getAmode mem `thenUs` \ amode ->
2808 code2 = amodeCode amode asmVoid
2809 src2 = amodeAddr amode
2810 code__2 dst = let code1 = registerCode register dst asmVoid
2811 src1 = registerName register dst
2812 in asmParThen [code1, code2] .
2813 if isFixed register && src1 /= dst
2814 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2815 instr (OpAddr src2) (OpReg dst)]
2817 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2819 returnUs (Any pk code__2)
2821 trivialCode instr (StInd pk mem) y
2822 = getRegister y `thenUs` \ register ->
2823 --getNewRegNCG IntRep `thenUs` \ tmp ->
2824 getAmode mem `thenUs` \ amode ->
2826 code2 = amodeCode amode asmVoid
2827 src2 = amodeAddr amode
2829 code1 = registerCode register dst asmVoid
2830 src1 = registerName register dst
2831 in asmParThen [code1, code2] .
2832 if isFixed register && src1 /= dst
2833 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2834 instr (OpAddr src2) (OpReg dst)]
2836 mkSeqInstr (instr (OpAddr src2) (OpReg src1))
2838 returnUs (Any pk code__2)
2840 trivialCode instr x y
2841 = getRegister x `thenUs` \ register1 ->
2842 getRegister y `thenUs` \ register2 ->
2843 --getNewRegNCG IntRep `thenUs` \ tmp1 ->
2844 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2846 code2 = registerCode register2 tmp2 asmVoid
2847 src2 = registerName register2 tmp2
2849 code1 = registerCode register1 dst asmVoid
2850 src1 = registerName register1 dst
2851 in asmParThen [code1, code2] .
2852 if isFixed register1 && src1 /= dst
2853 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2854 instr (OpReg src2) (OpReg dst)]
2856 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2858 returnUs (Any IntRep code__2)
2861 trivialUCode instr x
2862 = getRegister x `thenUs` \ register ->
2863 -- getNewRegNCG IntRep `thenUs` \ tmp ->
2866 code = registerCode register dst
2867 src = registerName register dst
2868 in code . if isFixed register && dst /= src
2869 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2871 else mkSeqInstr (instr (OpReg src))
2873 returnUs (Any IntRep code__2)
2876 trivialFCode pk _ instrr _ _ (StInd pk' mem) y
2877 = getRegister y `thenUs` \ register2 ->
2878 --getNewRegNCG (registerRep register2)
2879 -- `thenUs` \ tmp2 ->
2880 getAmode mem `thenUs` \ amode ->
2882 code1 = amodeCode amode
2883 src1 = amodeAddr amode
2886 code2 = registerCode register2 dst
2887 src2 = registerName register2 dst
2888 in asmParThen [code1 asmVoid,code2 asmVoid] .
2889 mkSeqInstrs [instrr (primRepToSize pk) (OpAddr src1)]
2891 returnUs (Any pk code__2)
2893 trivialFCode pk instr _ _ _ x (StInd pk' mem)
2894 = getRegister x `thenUs` \ register1 ->
2895 --getNewRegNCG (registerRep register1)
2896 -- `thenUs` \ tmp1 ->
2897 getAmode mem `thenUs` \ amode ->
2899 code2 = amodeCode amode
2900 src2 = amodeAddr amode
2903 code1 = registerCode register1 dst
2904 src1 = registerName register1 dst
2905 in asmParThen [code2 asmVoid,code1 asmVoid] .
2906 mkSeqInstrs [instr (primRepToSize pk) (OpAddr src2)]
2908 returnUs (Any pk code__2)
2910 trivialFCode pk _ _ _ instrpr x y
2911 = getRegister x `thenUs` \ register1 ->
2912 getRegister y `thenUs` \ register2 ->
2913 --getNewRegNCG (registerRep register1)
2914 -- `thenUs` \ tmp1 ->
2915 --getNewRegNCG (registerRep register2)
2916 -- `thenUs` \ tmp2 ->
2917 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2919 pk1 = registerRep register1
2920 code1 = registerCode register1 st0 --tmp1
2921 src1 = registerName register1 st0 --tmp1
2923 pk2 = registerRep register2
2926 code2 = registerCode register2 dst
2927 src2 = registerName register2 dst
2928 in asmParThen [code1 asmVoid, code2 asmVoid] .
2931 returnUs (Any pk1 code__2)
2934 trivialUFCode pk instr (StInd pk' mem)
2935 = getAmode mem `thenUs` \ amode ->
2937 code = amodeCode amode
2938 src = amodeAddr amode
2939 code__2 dst = code . mkSeqInstrs [FLD (primRepToSize pk) (OpAddr src),
2942 returnUs (Any pk code__2)
2944 trivialUFCode pk instr x
2945 = getRegister x `thenUs` \ register ->
2946 --getNewRegNCG pk `thenUs` \ tmp ->
2949 code = registerCode register dst
2950 src = registerName register dst
2951 in code . mkSeqInstrs [instr]
2953 returnUs (Any pk code__2)
2955 #endif {- i386_TARGET_ARCH -}
2956 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2957 #if sparc_TARGET_ARCH
2959 trivialCode instr x (StInt y)
2961 = getRegister x `thenUs` \ register ->
2962 getNewRegNCG IntRep `thenUs` \ tmp ->
2964 code = registerCode register tmp
2965 src1 = registerName register tmp
2966 src2 = ImmInt (fromInteger y)
2967 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2969 returnUs (Any IntRep code__2)
2971 trivialCode instr x y
2972 = getRegister x `thenUs` \ register1 ->
2973 getRegister y `thenUs` \ register2 ->
2974 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2975 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2977 code1 = registerCode register1 tmp1 asmVoid
2978 src1 = registerName register1 tmp1
2979 code2 = registerCode register2 tmp2 asmVoid
2980 src2 = registerName register2 tmp2
2981 code__2 dst = asmParThen [code1, code2] .
2982 mkSeqInstr (instr src1 (RIReg src2) dst)
2984 returnUs (Any IntRep code__2)
2987 trivialFCode pk instr x y
2988 = getRegister x `thenUs` \ register1 ->
2989 getRegister y `thenUs` \ register2 ->
2990 getNewRegNCG (registerRep register1)
2992 getNewRegNCG (registerRep register2)
2994 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2996 promote x = asmInstr (FxTOy F DF x tmp)
2998 pk1 = registerRep register1
2999 code1 = registerCode register1 tmp1
3000 src1 = registerName register1 tmp1
3002 pk2 = registerRep register2
3003 code2 = registerCode register2 tmp2
3004 src2 = registerName register2 tmp2
3008 asmParThen [code1 asmVoid, code2 asmVoid] .
3009 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
3010 else if pk1 == FloatRep then
3011 asmParThen [code1 (promote src1), code2 asmVoid] .
3012 mkSeqInstr (instr DF tmp src2 dst)
3014 asmParThen [code1 asmVoid, code2 (promote src2)] .
3015 mkSeqInstr (instr DF src1 tmp dst)
3017 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
3020 trivialUCode instr x
3021 = getRegister x `thenUs` \ register ->
3022 getNewRegNCG IntRep `thenUs` \ tmp ->
3024 code = registerCode register tmp
3025 src = registerName register tmp
3026 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
3028 returnUs (Any IntRep code__2)
3031 trivialUFCode pk instr x
3032 = getRegister x `thenUs` \ register ->
3033 getNewRegNCG pk `thenUs` \ tmp ->
3035 code = registerCode register tmp
3036 src = registerName register tmp
3037 code__2 dst = code . mkSeqInstr (instr src dst)
3039 returnUs (Any pk code__2)
3041 #endif {- sparc_TARGET_ARCH -}
3044 %************************************************************************
3046 \subsubsection{Coercing to/from integer/floating-point...}
3048 %************************************************************************
3050 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
3051 to be generated. Here we just change the type on the Register passed
3052 on up. The code is machine-independent.
3054 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
3055 conversions. We have to store temporaries in memory to move
3056 between the integer and the floating point register sets.
3059 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
3060 coerceFltCode :: StixTree -> UniqSM Register
3062 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
3063 coerceFP2Int :: StixTree -> UniqSM Register
3066 = getRegister x `thenUs` \ register ->
3069 Fixed _ reg code -> Fixed pk reg code
3070 Any _ code -> Any pk code
3075 = getRegister x `thenUs` \ register ->
3078 Fixed _ reg code -> Fixed DoubleRep reg code
3079 Any _ code -> Any DoubleRep code
3084 #if alpha_TARGET_ARCH
3087 = getRegister x `thenUs` \ register ->
3088 getNewRegNCG IntRep `thenUs` \ reg ->
3090 code = registerCode register reg
3091 src = registerName register reg
3093 code__2 dst = code . mkSeqInstrs [
3095 LD TF dst (spRel 0),
3098 returnUs (Any DoubleRep code__2)
3102 = getRegister x `thenUs` \ register ->
3103 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3105 code = registerCode register tmp
3106 src = registerName register tmp
3108 code__2 dst = code . mkSeqInstrs [
3110 ST TF tmp (spRel 0),
3113 returnUs (Any IntRep code__2)
3115 #endif {- alpha_TARGET_ARCH -}
3116 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3117 #if i386_TARGET_ARCH
3120 = getRegister x `thenUs` \ register ->
3121 getNewRegNCG IntRep `thenUs` \ reg ->
3123 code = registerCode register reg
3124 src = registerName register reg
3126 code__2 dst = code . mkSeqInstrs [
3127 -- to fix: should spill instead of using R1
3128 MOV L (OpReg src) (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))),
3129 FILD (primRepToSize pk) (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)) dst]
3131 returnUs (Any pk code__2)
3135 = getRegister x `thenUs` \ register ->
3136 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3138 code = registerCode register tmp
3139 src = registerName register tmp
3140 pk = registerRep register
3142 code__2 dst = code . mkSeqInstrs [
3144 FIST L (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1)),
3145 MOV L (OpAddr (AddrBaseIndex (Just ebx) Nothing (ImmInt OFFSET_R1))) (OpReg dst)]
3147 returnUs (Any IntRep code__2)
3149 #endif {- i386_TARGET_ARCH -}
3150 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3151 #if sparc_TARGET_ARCH
3154 = getRegister x `thenUs` \ register ->
3155 getNewRegNCG IntRep `thenUs` \ reg ->
3157 code = registerCode register reg
3158 src = registerName register reg
3160 code__2 dst = code . mkSeqInstrs [
3161 ST W src (spRel (-2)),
3162 LD W (spRel (-2)) dst,
3163 FxTOy W (primRepToSize pk) dst dst]
3165 returnUs (Any pk code__2)
3169 = getRegister x `thenUs` \ register ->
3170 getNewRegNCG IntRep `thenUs` \ reg ->
3171 getNewRegNCG FloatRep `thenUs` \ tmp ->
3173 code = registerCode register reg
3174 src = registerName register reg
3175 pk = registerRep register
3177 code__2 dst = code . mkSeqInstrs [
3178 FxTOy (primRepToSize pk) W src tmp,
3179 ST W tmp (spRel (-2)),
3180 LD W (spRel (-2)) dst]
3182 returnUs (Any IntRep code__2)
3184 #endif {- sparc_TARGET_ARCH -}
3187 %************************************************************************
3189 \subsubsection{Coercing integer to @Char@...}
3191 %************************************************************************
3193 Integer to character conversion. Where applicable, we try to do this
3194 in one step if the original object is in memory.
3197 chrCode :: StixTree -> UniqSM Register
3199 #if alpha_TARGET_ARCH
3202 = getRegister x `thenUs` \ register ->
3203 getNewRegNCG IntRep `thenUs` \ reg ->
3205 code = registerCode register reg
3206 src = registerName register reg
3207 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3209 returnUs (Any IntRep code__2)
3211 #endif {- alpha_TARGET_ARCH -}
3212 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3213 #if i386_TARGET_ARCH
3216 = getRegister x `thenUs` \ register ->
3217 --getNewRegNCG IntRep `thenUs` \ reg ->
3220 code = registerCode register dst
3221 src = registerName register dst
3223 if isFixed register && src /= dst
3224 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3225 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3226 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3228 returnUs (Any IntRep code__2)
3230 #endif {- i386_TARGET_ARCH -}
3231 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3232 #if sparc_TARGET_ARCH
3234 chrCode (StInd pk mem)
3235 = getAmode mem `thenUs` \ amode ->
3237 code = amodeCode amode
3238 src = amodeAddr amode
3239 src_off = addrOffset src 3
3240 src__2 = case src_off of Just x -> x
3241 code__2 dst = if maybeToBool src_off then
3242 code . mkSeqInstr (LD BU src__2 dst)
3244 code . mkSeqInstrs [
3245 LD (primRepToSize pk) src dst,
3246 AND False dst (RIImm (ImmInt 255)) dst]
3248 returnUs (Any pk code__2)
3251 = getRegister x `thenUs` \ register ->
3252 getNewRegNCG IntRep `thenUs` \ reg ->
3254 code = registerCode register reg
3255 src = registerName register reg
3256 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3258 returnUs (Any IntRep code__2)
3260 #endif {- sparc_TARGET_ARCH -}