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(..), pprStixTrees
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 -- requires you to supply
53 -- void native_trace ( char* str )
54 StFunBegin lab -> getUniqLabelNCG `thenUs` \ str_lbl ->
55 returnUs (mkSeqInstrs [
57 COMMENT SLIT("begin trace sequence"),
60 ASCII True (showSDoc (pprCLabel_asm lab)),
63 PUSH L (OpImm (ImmCLbl str_lbl)),
64 CALL (ImmLit (text "native_trace")),
65 ADD L (OpImm (ImmInt 4)) (OpReg esp),
67 COMMENT SLIT("end trace sequence")
71 StFunEnd lab -> IF_ARCH_alpha(returnInstr (FUNEND lab),returnUs id)
72 StLabel lab -> returnInstr (LABEL lab)
74 StJump arg -> genJump arg
75 StCondJump lab arg -> genCondJump lab arg
76 StCall fn cconv VoidRep args -> genCCall fn cconv VoidRep args
79 | isFloatingRep pk -> assignFltCode pk dst src
80 | otherwise -> assignIntCode pk dst src
83 -- When falling through on the Alpha, we still have to load pv
84 -- with the address of the next routine, so that it can load gp.
85 -> IF_ARCH_alpha(returnInstr (LDA pv (AddrImm (ImmCLbl lbl)))
89 -> mapAndUnzipUs getData args `thenUs` \ (codes, imms) ->
90 returnUs (\xs -> mkSeqList (asmInstr (DATA (primRepToSize kind) imms))
91 (foldr (.) id codes xs))
93 getData :: StixTree -> UniqSM (InstrBlock, Imm)
95 getData (StInt i) = returnUs (id, ImmInteger i)
96 getData (StDouble d) = returnUs (id, ImmDouble d)
97 getData (StLitLbl s) = returnUs (id, ImmLab s)
98 getData (StCLbl l) = returnUs (id, ImmCLbl l)
99 getData (StString s) =
100 getUniqLabelNCG `thenUs` \ lbl ->
101 returnUs (mkSeqInstrs [LABEL lbl,
102 ASCII True (_UNPK_ s)],
104 -- the linker can handle simple arithmetic...
105 getData (StIndex rep (StCLbl lbl) (StInt off)) =
106 returnUs (id, ImmIndex lbl (fromInteger (off * sizeOf rep)))
109 %************************************************************************
111 \subsection{General things for putting together code sequences}
113 %************************************************************************
116 type InstrList = OrdList Instr
117 type InstrBlock = InstrList -> InstrList
120 asmVoid = mkEmptyList
122 asmInstr :: Instr -> InstrList
123 asmInstr i = mkUnitList i
125 asmSeq :: [Instr] -> InstrList
126 asmSeq is = foldr (mkSeqList . asmInstr) asmVoid is
128 asmParThen :: [InstrList] -> InstrBlock
129 asmParThen others code = mkSeqList (foldr mkParList mkEmptyList others) code
131 returnInstr :: Instr -> UniqSM InstrBlock
132 returnInstr instr = returnUs (\xs -> mkSeqList (asmInstr instr) xs)
134 returnInstrs :: [Instr] -> UniqSM InstrBlock
135 returnInstrs instrs = returnUs (\xs -> mkSeqList (asmSeq instrs) xs)
137 returnSeq :: InstrBlock -> [Instr] -> UniqSM InstrBlock
138 returnSeq code instrs = returnUs (\xs -> code (mkSeqList (asmSeq instrs) xs))
140 mkSeqInstr :: Instr -> InstrBlock
141 mkSeqInstr instr code = mkSeqList (asmInstr instr) code
143 mkSeqInstrs :: [Instr] -> InstrBlock
144 mkSeqInstrs instrs code = mkSeqList (asmSeq instrs) code
148 mangleIndexTree :: StixTree -> StixTree
150 mangleIndexTree (StIndex pk base (StInt i))
151 = StPrim IntAddOp [base, off]
153 off = StInt (i * sizeOf pk)
155 #ifndef i386_TARGET_ARCH
156 mangleIndexTree (StIndex pk base off)
157 = StPrim IntAddOp [base,
163 ASSERT(toInteger s == expectJust "MachCode" (exactLog2 (sizeOf pk)))
164 StPrim SllOp [off, StInt s]
167 shift DoubleRep = 3::Integer
168 shift _ = IF_ARCH_alpha(3,2)
170 -- Hmm..this is an attempt at fixing Adress amodes (i.e., *[disp](base,index,<n>),
171 -- that do include the size of the primitive kind we're addressing. When StIndex
172 -- is expanded to actual code, the index (in units) is by the above code approp.
173 -- shifted to get the no. of bytes. Since Address amodes do contain size info
174 -- explicitly, we disable the shifting for x86s.
175 mangleIndexTree (StIndex pk base off) = StPrim IntAddOp [base, off]
181 maybeImm :: StixTree -> Maybe Imm
183 maybeImm (StLitLbl s) = Just (ImmLab s)
184 maybeImm (StCLbl l) = Just (ImmCLbl l)
186 maybeImm (StIndex rep (StCLbl l) (StInt off)) =
187 Just (ImmIndex l (fromInteger (off * sizeOf rep)))
190 | i >= toInteger minInt && i <= toInteger maxInt
191 = Just (ImmInt (fromInteger i))
193 = Just (ImmInteger i)
198 %************************************************************************
200 \subsection{The @Register@ type}
202 %************************************************************************
204 @Register@s passed up the tree. If the stix code forces the register
205 to live in a pre-decided machine register, it comes out as @Fixed@;
206 otherwise, it comes out as @Any@, and the parent can decide which
207 register to put it in.
211 = Fixed PrimRep Reg InstrBlock
212 | Any PrimRep (Reg -> InstrBlock)
214 registerCode :: Register -> Reg -> InstrBlock
215 registerCode (Fixed _ _ code) reg = code
216 registerCode (Any _ code) reg = code reg
218 registerName :: Register -> Reg -> Reg
219 registerName (Fixed _ reg _) _ = reg
220 registerName (Any _ _) reg = reg
222 registerRep :: Register -> PrimRep
223 registerRep (Fixed pk _ _) = pk
224 registerRep (Any pk _) = pk
226 isFixed :: Register -> Bool
227 isFixed (Fixed _ _ _) = True
228 isFixed (Any _ _) = False
231 Generate code to get a subtree into a @Register@:
233 getRegister :: StixTree -> UniqSM Register
235 getRegister (StReg (StixMagicId stgreg))
236 = case (magicIdRegMaybe stgreg) of
237 Just reg -> returnUs (Fixed (magicIdPrimRep stgreg) reg id)
240 getRegister (StReg (StixTemp u pk))
241 = returnUs (Fixed pk (UnmappedReg u pk) id)
243 getRegister tree@(StIndex _ _ _) = getRegister (mangleIndexTree tree)
245 getRegister (StCall fn cconv kind args)
246 = genCCall fn cconv kind args `thenUs` \ call ->
247 returnUs (Fixed kind reg call)
249 reg = if isFloatingRep kind
250 then IF_ARCH_alpha( f0, IF_ARCH_i386( fake0, IF_ARCH_sparc( f0,)))
251 else IF_ARCH_alpha( v0, IF_ARCH_i386( eax, IF_ARCH_sparc( o0,)))
253 getRegister (StString s)
254 = getUniqLabelNCG `thenUs` \ lbl ->
256 imm_lbl = ImmCLbl lbl
258 code dst = mkSeqInstrs [
261 ASCII True (_UNPK_ s),
263 #if alpha_TARGET_ARCH
264 LDA dst (AddrImm imm_lbl)
267 MOV L (OpImm imm_lbl) (OpReg dst)
269 #if sparc_TARGET_ARCH
270 SETHI (HI imm_lbl) dst,
271 OR False dst (RIImm (LO imm_lbl)) dst
275 returnUs (Any PtrRep code)
279 -- end of machine-"independent" bit; here we go on the rest...
281 #if alpha_TARGET_ARCH
283 getRegister (StDouble d)
284 = getUniqLabelNCG `thenUs` \ lbl ->
285 getNewRegNCG PtrRep `thenUs` \ tmp ->
286 let code dst = mkSeqInstrs [
289 DATA TF [ImmLab (rational d)],
291 LDA tmp (AddrImm (ImmCLbl lbl)),
292 LD TF dst (AddrReg tmp)]
294 returnUs (Any DoubleRep code)
296 getRegister (StPrim primop [x]) -- unary PrimOps
298 IntNegOp -> trivialUCode (NEG Q False) x
300 NotOp -> trivialUCode NOT x
302 FloatNegOp -> trivialUFCode FloatRep (FNEG TF) x
303 DoubleNegOp -> trivialUFCode DoubleRep (FNEG TF) x
305 OrdOp -> coerceIntCode IntRep x
308 Float2IntOp -> coerceFP2Int x
309 Int2FloatOp -> coerceInt2FP pr x
310 Double2IntOp -> coerceFP2Int x
311 Int2DoubleOp -> coerceInt2FP pr x
313 Double2FloatOp -> coerceFltCode x
314 Float2DoubleOp -> coerceFltCode x
316 other_op -> getRegister (StCall fn cCallConv DoubleRep [x])
318 fn = case other_op of
319 FloatExpOp -> SLIT("exp")
320 FloatLogOp -> SLIT("log")
321 FloatSqrtOp -> SLIT("sqrt")
322 FloatSinOp -> SLIT("sin")
323 FloatCosOp -> SLIT("cos")
324 FloatTanOp -> SLIT("tan")
325 FloatAsinOp -> SLIT("asin")
326 FloatAcosOp -> SLIT("acos")
327 FloatAtanOp -> SLIT("atan")
328 FloatSinhOp -> SLIT("sinh")
329 FloatCoshOp -> SLIT("cosh")
330 FloatTanhOp -> SLIT("tanh")
331 DoubleExpOp -> SLIT("exp")
332 DoubleLogOp -> SLIT("log")
333 DoubleSqrtOp -> SLIT("sqrt")
334 DoubleSinOp -> SLIT("sin")
335 DoubleCosOp -> SLIT("cos")
336 DoubleTanOp -> SLIT("tan")
337 DoubleAsinOp -> SLIT("asin")
338 DoubleAcosOp -> SLIT("acos")
339 DoubleAtanOp -> SLIT("atan")
340 DoubleSinhOp -> SLIT("sinh")
341 DoubleCoshOp -> SLIT("cosh")
342 DoubleTanhOp -> SLIT("tanh")
344 pr = panic "MachCode.getRegister: no primrep needed for Alpha"
346 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
348 CharGtOp -> trivialCode (CMP LTT) y x
349 CharGeOp -> trivialCode (CMP LE) y x
350 CharEqOp -> trivialCode (CMP EQQ) x y
351 CharNeOp -> int_NE_code x y
352 CharLtOp -> trivialCode (CMP LTT) x y
353 CharLeOp -> trivialCode (CMP LE) x y
355 IntGtOp -> trivialCode (CMP LTT) y x
356 IntGeOp -> trivialCode (CMP LE) y x
357 IntEqOp -> trivialCode (CMP EQQ) x y
358 IntNeOp -> int_NE_code x y
359 IntLtOp -> trivialCode (CMP LTT) x y
360 IntLeOp -> trivialCode (CMP LE) x y
362 WordGtOp -> trivialCode (CMP ULT) y x
363 WordGeOp -> trivialCode (CMP ULE) x y
364 WordEqOp -> trivialCode (CMP EQQ) x y
365 WordNeOp -> int_NE_code x y
366 WordLtOp -> trivialCode (CMP ULT) x y
367 WordLeOp -> trivialCode (CMP ULE) x y
369 AddrGtOp -> trivialCode (CMP ULT) y x
370 AddrGeOp -> trivialCode (CMP ULE) y x
371 AddrEqOp -> trivialCode (CMP EQQ) x y
372 AddrNeOp -> int_NE_code x y
373 AddrLtOp -> trivialCode (CMP ULT) x y
374 AddrLeOp -> trivialCode (CMP ULE) x y
376 FloatGtOp -> cmpF_code (FCMP TF LE) EQQ x y
377 FloatGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
378 FloatEqOp -> cmpF_code (FCMP TF EQQ) NE x y
379 FloatNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
380 FloatLtOp -> cmpF_code (FCMP TF LTT) NE x y
381 FloatLeOp -> cmpF_code (FCMP TF LE) NE x y
383 DoubleGtOp -> cmpF_code (FCMP TF LE) EQQ x y
384 DoubleGeOp -> cmpF_code (FCMP TF LTT) EQQ x y
385 DoubleEqOp -> cmpF_code (FCMP TF EQQ) NE x y
386 DoubleNeOp -> cmpF_code (FCMP TF EQQ) EQQ x y
387 DoubleLtOp -> cmpF_code (FCMP TF LTT) NE x y
388 DoubleLeOp -> cmpF_code (FCMP TF LE) NE x y
390 IntAddOp -> trivialCode (ADD Q False) x y
391 IntSubOp -> trivialCode (SUB Q False) x y
392 IntMulOp -> trivialCode (MUL Q False) x y
393 IntQuotOp -> trivialCode (DIV Q False) x y
394 IntRemOp -> trivialCode (REM Q False) x y
396 WordQuotOp -> trivialCode (DIV Q True) x y
397 WordRemOp -> trivialCode (REM Q True) x y
399 FloatAddOp -> trivialFCode FloatRep (FADD TF) x y
400 FloatSubOp -> trivialFCode FloatRep (FSUB TF) x y
401 FloatMulOp -> trivialFCode FloatRep (FMUL TF) x y
402 FloatDivOp -> trivialFCode FloatRep (FDIV TF) x y
404 DoubleAddOp -> trivialFCode DoubleRep (FADD TF) x y
405 DoubleSubOp -> trivialFCode DoubleRep (FSUB TF) x y
406 DoubleMulOp -> trivialFCode DoubleRep (FMUL TF) x y
407 DoubleDivOp -> trivialFCode DoubleRep (FDIV TF) x y
409 AndOp -> trivialCode AND x y
410 OrOp -> trivialCode OR x y
411 XorOp -> trivialCode XOR x y
412 SllOp -> trivialCode SLL x y
413 SrlOp -> trivialCode SRL x y
415 ISllOp -> trivialCode SLL x y -- was: panic "AlphaGen:isll"
416 ISraOp -> trivialCode SRA x y -- was: panic "AlphaGen:isra"
417 ISrlOp -> trivialCode SRL x y -- was: panic "AlphaGen:isrl"
419 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
420 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x,y])
422 {- ------------------------------------------------------------
423 Some bizarre special code for getting condition codes into
424 registers. Integer non-equality is a test for equality
425 followed by an XOR with 1. (Integer comparisons always set
426 the result register to 0 or 1.) Floating point comparisons of
427 any kind leave the result in a floating point register, so we
428 need to wrangle an integer register out of things.
430 int_NE_code :: StixTree -> StixTree -> UniqSM Register
433 = trivialCode (CMP EQQ) x y `thenUs` \ register ->
434 getNewRegNCG IntRep `thenUs` \ tmp ->
436 code = registerCode register tmp
437 src = registerName register tmp
438 code__2 dst = code . mkSeqInstr (XOR src (RIImm (ImmInt 1)) dst)
440 returnUs (Any IntRep code__2)
442 {- ------------------------------------------------------------
443 Comments for int_NE_code also apply to cmpF_code
446 :: (Reg -> Reg -> Reg -> Instr)
448 -> StixTree -> StixTree
451 cmpF_code instr cond x y
452 = trivialFCode pr instr x y `thenUs` \ register ->
453 getNewRegNCG DoubleRep `thenUs` \ tmp ->
454 getUniqLabelNCG `thenUs` \ lbl ->
456 code = registerCode register tmp
457 result = registerName register tmp
459 code__2 dst = code . mkSeqInstrs [
460 OR zeroh (RIImm (ImmInt 1)) dst,
461 BF cond result (ImmCLbl lbl),
462 OR zeroh (RIReg zeroh) dst,
465 returnUs (Any IntRep code__2)
467 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
468 ------------------------------------------------------------
470 getRegister (StInd pk mem)
471 = getAmode mem `thenUs` \ amode ->
473 code = amodeCode amode
474 src = amodeAddr amode
475 size = primRepToSize pk
476 code__2 dst = code . mkSeqInstr (LD size dst src)
478 returnUs (Any pk code__2)
480 getRegister (StInt i)
483 code dst = mkSeqInstr (OR zeroh (RIImm src) dst)
485 returnUs (Any IntRep code)
488 code dst = mkSeqInstr (LDI Q dst src)
490 returnUs (Any IntRep code)
492 src = ImmInt (fromInteger i)
497 code dst = mkSeqInstr (LDA dst (AddrImm imm__2))
499 returnUs (Any PtrRep code)
502 imm__2 = case imm of Just x -> x
504 #endif {- alpha_TARGET_ARCH -}
505 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
508 getRegister (StDouble d)
509 = getUniqLabelNCG `thenUs` \ lbl ->
510 let code dst = mkSeqInstrs [
513 DATA DF [ImmDouble d],
515 GLD DF (ImmAddr (ImmCLbl lbl) 0) dst
518 returnUs (Any DoubleRep code)
521 getRegister (StPrim primop [x]) -- unary PrimOps
523 IntNegOp -> trivialUCode (NEGI L) x
524 NotOp -> trivialUCode (NOT L) x
526 FloatNegOp -> trivialUFCode FloatRep (GNEG F) x
527 DoubleNegOp -> trivialUFCode DoubleRep (GNEG DF) x
529 FloatSqrtOp -> trivialUFCode FloatRep (GSQRT F) x
530 DoubleSqrtOp -> trivialUFCode DoubleRep (GSQRT DF) x
532 Double2FloatOp -> trivialUFCode FloatRep GDTOF x
533 Float2DoubleOp -> trivialUFCode DoubleRep GFTOD x
535 OrdOp -> coerceIntCode IntRep x
538 Float2IntOp -> coerceFP2Int x
539 Int2FloatOp -> coerceInt2FP FloatRep x
540 Double2IntOp -> coerceFP2Int x
541 Int2DoubleOp -> coerceInt2FP DoubleRep x
545 fixed_x = if is_float_op -- promote to double
546 then StPrim Float2DoubleOp [x]
549 getRegister (StCall fn cCallConv DoubleRep [x])
553 FloatExpOp -> (True, SLIT("exp"))
554 FloatLogOp -> (True, SLIT("log"))
556 FloatSinOp -> (True, SLIT("sin"))
557 FloatCosOp -> (True, SLIT("cos"))
558 FloatTanOp -> (True, SLIT("tan"))
560 FloatAsinOp -> (True, SLIT("asin"))
561 FloatAcosOp -> (True, SLIT("acos"))
562 FloatAtanOp -> (True, SLIT("atan"))
564 FloatSinhOp -> (True, SLIT("sinh"))
565 FloatCoshOp -> (True, SLIT("cosh"))
566 FloatTanhOp -> (True, SLIT("tanh"))
568 DoubleExpOp -> (False, SLIT("exp"))
569 DoubleLogOp -> (False, SLIT("log"))
571 DoubleSinOp -> (False, SLIT("sin"))
572 DoubleCosOp -> (False, SLIT("cos"))
573 DoubleTanOp -> (False, SLIT("tan"))
575 DoubleAsinOp -> (False, SLIT("asin"))
576 DoubleAcosOp -> (False, SLIT("acos"))
577 DoubleAtanOp -> (False, SLIT("atan"))
579 DoubleSinhOp -> (False, SLIT("sinh"))
580 DoubleCoshOp -> (False, SLIT("cosh"))
581 DoubleTanhOp -> (False, SLIT("tanh"))
583 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
585 CharGtOp -> condIntReg GTT x y
586 CharGeOp -> condIntReg GE x y
587 CharEqOp -> condIntReg EQQ x y
588 CharNeOp -> condIntReg NE x y
589 CharLtOp -> condIntReg LTT x y
590 CharLeOp -> condIntReg LE x y
592 IntGtOp -> condIntReg GTT x y
593 IntGeOp -> condIntReg GE x y
594 IntEqOp -> condIntReg EQQ x y
595 IntNeOp -> condIntReg NE x y
596 IntLtOp -> condIntReg LTT x y
597 IntLeOp -> condIntReg LE x y
599 WordGtOp -> condIntReg GU x y
600 WordGeOp -> condIntReg GEU x y
601 WordEqOp -> condIntReg EQQ x y
602 WordNeOp -> condIntReg NE x y
603 WordLtOp -> condIntReg LU x y
604 WordLeOp -> condIntReg LEU x y
606 AddrGtOp -> condIntReg GU x y
607 AddrGeOp -> condIntReg GEU x y
608 AddrEqOp -> condIntReg EQQ x y
609 AddrNeOp -> condIntReg NE x y
610 AddrLtOp -> condIntReg LU x y
611 AddrLeOp -> condIntReg LEU x y
613 FloatGtOp -> condFltReg GTT x y
614 FloatGeOp -> condFltReg GE x y
615 FloatEqOp -> condFltReg EQQ x y
616 FloatNeOp -> condFltReg NE x y
617 FloatLtOp -> condFltReg LTT x y
618 FloatLeOp -> condFltReg LE x y
620 DoubleGtOp -> condFltReg GTT x y
621 DoubleGeOp -> condFltReg GE x y
622 DoubleEqOp -> condFltReg EQQ x y
623 DoubleNeOp -> condFltReg NE x y
624 DoubleLtOp -> condFltReg LTT x y
625 DoubleLeOp -> condFltReg LE x y
627 IntAddOp -> {- ToDo: fix this, whatever it is (WDP 96/04)...
628 -- this should be optimised by the generic Opts,
629 -- I don't know why it is not (sometimes)!
631 [x, StInt 0] -> getRegister x
636 IntSubOp -> sub_code L x y
637 IntQuotOp -> quot_code L x y True{-division-}
638 IntRemOp -> quot_code L x y False{-remainder-}
639 IntMulOp -> trivialCode (IMUL L) x y {-True-}
641 FloatAddOp -> trivialFCode FloatRep GADD x y
642 FloatSubOp -> trivialFCode FloatRep GSUB x y
643 FloatMulOp -> trivialFCode FloatRep GMUL x y
644 FloatDivOp -> trivialFCode FloatRep GDIV x y
646 DoubleAddOp -> trivialFCode DoubleRep GADD x y
647 DoubleSubOp -> trivialFCode DoubleRep GSUB x y
648 DoubleMulOp -> trivialFCode DoubleRep GMUL x y
649 DoubleDivOp -> trivialFCode DoubleRep GDIV x y
651 AndOp -> trivialCode (AND L) x y {-True-}
652 OrOp -> trivialCode (OR L) x y {-True-}
653 XorOp -> trivialCode (XOR L) x y {-True-}
655 {- Shift ops on x86s have constraints on their source, it
656 either has to be Imm, CL or 1
657 => trivialCode's is not restrictive enough (sigh.)
660 SllOp -> shift_code (SHL L) x y {-False-}
661 SrlOp -> shift_code (SHR L) x y {-False-}
663 ISllOp -> shift_code (SHL L) x y {-False-}
664 ISraOp -> shift_code (SAR L) x y {-False-}
665 ISrlOp -> shift_code (SHR L) x y {-False-}
667 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
668 [promote x, promote y])
669 where promote x = StPrim Float2DoubleOp [x]
670 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep
675 shift_code :: (Operand -> Operand -> Instr)
680 {- Case1: shift length as immediate -}
681 -- Code is the same as the first eq. for trivialCode -- sigh.
682 shift_code instr x y{-amount-}
684 = getRegister x `thenUs` \ register ->
686 op_imm = OpImm imm__2
689 code = registerCode register dst
690 src = registerName register dst
692 mkSeqInstr (COMMENT SLIT("shift_code")) .
694 if isFixed register && src /= dst
696 mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
697 instr op_imm (OpReg dst)]
699 mkSeqInstr (instr op_imm (OpReg src))
701 returnUs (Any IntRep code__2)
704 imm__2 = case imm of Just x -> x
706 {- Case2: shift length is complex (non-immediate) -}
707 shift_code instr x y{-amount-}
708 = getRegister y `thenUs` \ register1 ->
709 getRegister x `thenUs` \ register2 ->
711 -- Note: we force the shift length to be loaded
712 -- into ECX, so that we can use CL when shifting.
713 -- (only register location we are allowed
714 -- to put shift amounts.)
716 -- The shift instruction is fed ECX as src reg,
717 -- but we coerce this into CL when printing out.
718 src1 = registerName register1 ecx
719 code1 = if src1 /= ecx then -- if it is not in ecx already, force it!
720 registerCode register1 ecx .
721 mkSeqInstr (MOV L (OpReg src1) (OpReg ecx))
723 registerCode register1 ecx
726 code2 = registerCode register2 eax
727 src2 = registerName register2 eax
730 mkSeqInstr (instr (OpReg ecx) (OpReg eax))
732 returnUs (Fixed IntRep eax code__2)
735 add_code :: Size -> StixTree -> StixTree -> UniqSM Register
737 add_code sz x (StInt y)
738 = getRegister x `thenUs` \ register ->
739 getNewRegNCG IntRep `thenUs` \ tmp ->
741 code = registerCode register tmp
742 src1 = registerName register tmp
743 src2 = ImmInt (fromInteger y)
746 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
749 returnUs (Any IntRep code__2)
752 = getRegister x `thenUs` \ register1 ->
753 getRegister y `thenUs` \ register2 ->
754 getNewRegNCG IntRep `thenUs` \ tmp1 ->
755 getNewRegNCG IntRep `thenUs` \ tmp2 ->
757 code1 = registerCode register1 tmp1 asmVoid
758 src1 = registerName register1 tmp1
759 code2 = registerCode register2 tmp2 asmVoid
760 src2 = registerName register2 tmp2
762 = asmParThen [code1, code2] .
763 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) (Just (src2,1))
767 returnUs (Any IntRep code__2)
770 sub_code :: Size -> StixTree -> StixTree -> UniqSM Register
772 sub_code sz x (StInt y)
773 = getRegister x `thenUs` \ register ->
774 getNewRegNCG IntRep `thenUs` \ tmp ->
776 code = registerCode register tmp
777 src1 = registerName register tmp
778 src2 = ImmInt (-(fromInteger y))
781 mkSeqInstr (LEA sz (OpAddr (AddrBaseIndex (Just src1) Nothing src2))
784 returnUs (Any IntRep code__2)
786 sub_code sz x y = trivialCode (SUB sz) x y {-False-}
791 -> StixTree -> StixTree
792 -> Bool -- True => division, False => remainder operation
795 -- x must go into eax, edx must be a sign-extension of eax, and y
796 -- should go in some other register (or memory), so that we get
797 -- edx:eax / reg -> eax (remainder in edx) Currently we chose to
798 -- put y in memory (if it is not there already)
800 quot_code sz x (StInd pk mem) is_division
801 = getRegister x `thenUs` \ register1 ->
802 getNewRegNCG IntRep `thenUs` \ tmp1 ->
803 getAmode mem `thenUs` \ amode ->
805 code1 = registerCode register1 tmp1 asmVoid
806 src1 = registerName register1 tmp1
807 code2 = amodeCode amode asmVoid
808 src2 = amodeAddr amode
809 code__2 = asmParThen [code1, code2] .
810 mkSeqInstrs [MOV L (OpReg src1) (OpReg eax),
812 IDIV sz (OpAddr src2)]
814 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
816 quot_code sz x (StInt i) is_division
817 = getRegister x `thenUs` \ register1 ->
818 getNewRegNCG IntRep `thenUs` \ tmp1 ->
820 code1 = registerCode register1 tmp1 asmVoid
821 src1 = registerName register1 tmp1
822 src2 = ImmInt (fromInteger i)
823 code__2 = asmParThen [code1] .
824 mkSeqInstrs [-- we put src2 in (ebx)
826 (OpAddr (AddrBaseIndex (Just ebx) Nothing
827 (ImmInt OFFSET_R1))),
828 MOV L (OpReg src1) (OpReg eax),
830 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
834 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
836 quot_code sz x y is_division
837 = getRegister x `thenUs` \ register1 ->
838 getNewRegNCG IntRep `thenUs` \ tmp1 ->
839 getRegister y `thenUs` \ register2 ->
840 getNewRegNCG IntRep `thenUs` \ tmp2 ->
842 code1 = registerCode register1 tmp1 asmVoid
843 src1 = registerName register1 tmp1
844 code2 = registerCode register2 tmp2 asmVoid
845 src2 = registerName register2 tmp2
846 code__2 = asmParThen [code1, code2] .
847 if src2 == ecx || src2 == esi
849 MOV L (OpReg src1) (OpReg eax),
853 else mkSeqInstrs [ -- we put src2 in (ebx)
855 (OpAddr (AddrBaseIndex (Just ebx) Nothing
856 (ImmInt OFFSET_R1))),
857 MOV L (OpReg src1) (OpReg eax),
859 IDIV sz (OpAddr (AddrBaseIndex (Just ebx) Nothing
863 returnUs (Fixed IntRep (if is_division then eax else edx) code__2)
864 -----------------------
866 getRegister (StInd pk mem)
867 = getAmode mem `thenUs` \ amode ->
869 code = amodeCode amode
870 src = amodeAddr amode
871 size = primRepToSize pk
873 if pk == DoubleRep || pk == FloatRep
874 then mkSeqInstr (GLD size src dst)
875 else mkSeqInstr (MOV size (OpAddr src) (OpReg dst))
877 returnUs (Any pk code__2)
879 getRegister (StInt i)
881 src = ImmInt (fromInteger i)
882 code dst = mkSeqInstr (MOV L (OpImm src) (OpReg dst))
884 returnUs (Any IntRep code)
889 code dst = mkSeqInstr (MOV L (OpImm imm__2) (OpReg dst))
891 returnUs (Any PtrRep code)
893 = pprPanic "getRegister(x86)" (pprStixTrees [leaf])
897 imm__2 = case imm of Just x -> x
899 #endif {- i386_TARGET_ARCH -}
900 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
901 #if sparc_TARGET_ARCH
903 getRegister (StDouble d)
904 = getUniqLabelNCG `thenUs` \ lbl ->
905 getNewRegNCG PtrRep `thenUs` \ tmp ->
906 let code dst = mkSeqInstrs [
909 DATA DF [ImmDouble d],
911 SETHI (HI (ImmCLbl lbl)) tmp,
912 LD DF (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
914 returnUs (Any DoubleRep code)
916 getRegister (StPrim primop [x]) -- unary PrimOps
918 IntNegOp -> trivialUCode (SUB False False g0) x
919 NotOp -> trivialUCode (XNOR False g0) x
921 FloatNegOp -> trivialUFCode FloatRep (FNEG F) x
923 DoubleNegOp -> trivialUFCode DoubleRep (FNEG DF) x
925 Double2FloatOp -> trivialUFCode FloatRep (FxTOy DF F) x
926 Float2DoubleOp -> trivialUFCode DoubleRep (FxTOy F DF) x
928 OrdOp -> coerceIntCode IntRep x
931 Float2IntOp -> coerceFP2Int x
932 Int2FloatOp -> coerceInt2FP FloatRep x
933 Double2IntOp -> coerceFP2Int x
934 Int2DoubleOp -> coerceInt2FP DoubleRep x
938 fixed_x = if is_float_op -- promote to double
939 then StPrim Float2DoubleOp [x]
942 getRegister (StCall fn cCallConv DoubleRep [x])
946 FloatExpOp -> (True, SLIT("exp"))
947 FloatLogOp -> (True, SLIT("log"))
948 FloatSqrtOp -> (True, SLIT("sqrt"))
950 FloatSinOp -> (True, SLIT("sin"))
951 FloatCosOp -> (True, SLIT("cos"))
952 FloatTanOp -> (True, SLIT("tan"))
954 FloatAsinOp -> (True, SLIT("asin"))
955 FloatAcosOp -> (True, SLIT("acos"))
956 FloatAtanOp -> (True, SLIT("atan"))
958 FloatSinhOp -> (True, SLIT("sinh"))
959 FloatCoshOp -> (True, SLIT("cosh"))
960 FloatTanhOp -> (True, SLIT("tanh"))
962 DoubleExpOp -> (False, SLIT("exp"))
963 DoubleLogOp -> (False, SLIT("log"))
964 DoubleSqrtOp -> (True, SLIT("sqrt"))
966 DoubleSinOp -> (False, SLIT("sin"))
967 DoubleCosOp -> (False, SLIT("cos"))
968 DoubleTanOp -> (False, SLIT("tan"))
970 DoubleAsinOp -> (False, SLIT("asin"))
971 DoubleAcosOp -> (False, SLIT("acos"))
972 DoubleAtanOp -> (False, SLIT("atan"))
974 DoubleSinhOp -> (False, SLIT("sinh"))
975 DoubleCoshOp -> (False, SLIT("cosh"))
976 DoubleTanhOp -> (False, SLIT("tanh"))
977 _ -> panic ("Monadic PrimOp not handled: " ++ show primop)
979 getRegister (StPrim primop [x, y]) -- dyadic PrimOps
981 CharGtOp -> condIntReg GTT x y
982 CharGeOp -> condIntReg GE x y
983 CharEqOp -> condIntReg EQQ x y
984 CharNeOp -> condIntReg NE x y
985 CharLtOp -> condIntReg LTT x y
986 CharLeOp -> condIntReg LE x y
988 IntGtOp -> condIntReg GTT x y
989 IntGeOp -> condIntReg GE x y
990 IntEqOp -> condIntReg EQQ x y
991 IntNeOp -> condIntReg NE x y
992 IntLtOp -> condIntReg LTT x y
993 IntLeOp -> condIntReg LE x y
995 WordGtOp -> condIntReg GU x y
996 WordGeOp -> condIntReg GEU x y
997 WordEqOp -> condIntReg EQQ x y
998 WordNeOp -> condIntReg NE x y
999 WordLtOp -> condIntReg LU x y
1000 WordLeOp -> condIntReg LEU x y
1002 AddrGtOp -> condIntReg GU x y
1003 AddrGeOp -> condIntReg GEU x y
1004 AddrEqOp -> condIntReg EQQ x y
1005 AddrNeOp -> condIntReg NE x y
1006 AddrLtOp -> condIntReg LU x y
1007 AddrLeOp -> condIntReg LEU x y
1009 FloatGtOp -> condFltReg GTT x y
1010 FloatGeOp -> condFltReg GE x y
1011 FloatEqOp -> condFltReg EQQ x y
1012 FloatNeOp -> condFltReg NE x y
1013 FloatLtOp -> condFltReg LTT x y
1014 FloatLeOp -> condFltReg LE x y
1016 DoubleGtOp -> condFltReg GTT x y
1017 DoubleGeOp -> condFltReg GE x y
1018 DoubleEqOp -> condFltReg EQQ x y
1019 DoubleNeOp -> condFltReg NE x y
1020 DoubleLtOp -> condFltReg LTT x y
1021 DoubleLeOp -> condFltReg LE x y
1023 IntAddOp -> trivialCode (ADD False False) x y
1024 IntSubOp -> trivialCode (SUB False False) x y
1026 -- ToDo: teach about V8+ SPARC mul/div instructions
1027 IntMulOp -> imul_div SLIT(".umul") x y
1028 IntQuotOp -> imul_div SLIT(".div") x y
1029 IntRemOp -> imul_div SLIT(".rem") x y
1031 FloatAddOp -> trivialFCode FloatRep FADD x y
1032 FloatSubOp -> trivialFCode FloatRep FSUB x y
1033 FloatMulOp -> trivialFCode FloatRep FMUL x y
1034 FloatDivOp -> trivialFCode FloatRep FDIV x y
1036 DoubleAddOp -> trivialFCode DoubleRep FADD x y
1037 DoubleSubOp -> trivialFCode DoubleRep FSUB x y
1038 DoubleMulOp -> trivialFCode DoubleRep FMUL x y
1039 DoubleDivOp -> trivialFCode DoubleRep FDIV x y
1041 AndOp -> trivialCode (AND False) x y
1042 OrOp -> trivialCode (OR False) x y
1043 XorOp -> trivialCode (XOR False) x y
1044 SllOp -> trivialCode SLL x y
1045 SrlOp -> trivialCode SRL x y
1047 ISllOp -> trivialCode SLL x y --was: panic "SparcGen:isll"
1048 ISraOp -> trivialCode SRA x y --was: panic "SparcGen:isra"
1049 ISrlOp -> trivialCode SRL x y --was: panic "SparcGen:isrl"
1051 FloatPowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [promote x, promote y])
1052 where promote x = StPrim Float2DoubleOp [x]
1053 DoublePowerOp -> getRegister (StCall SLIT("pow") cCallConv DoubleRep [x, y])
1054 -- _ -> panic "Prim op " ++ (showPrimOp primop) ++ " not handled!"
1056 imul_div fn x y = getRegister (StCall fn cCallConv IntRep [x, y])
1058 getRegister (StInd pk mem)
1059 = getAmode mem `thenUs` \ amode ->
1061 code = amodeCode amode
1062 src = amodeAddr amode
1063 size = primRepToSize pk
1064 code__2 dst = code . mkSeqInstr (LD size src dst)
1066 returnUs (Any pk code__2)
1068 getRegister (StInt i)
1071 src = ImmInt (fromInteger i)
1072 code dst = mkSeqInstr (OR False g0 (RIImm src) dst)
1074 returnUs (Any IntRep code)
1079 code dst = mkSeqInstrs [
1080 SETHI (HI imm__2) dst,
1081 OR False dst (RIImm (LO imm__2)) dst]
1083 returnUs (Any PtrRep code)
1086 imm__2 = case imm of Just x -> x
1088 #endif {- sparc_TARGET_ARCH -}
1091 %************************************************************************
1093 \subsection{The @Amode@ type}
1095 %************************************************************************
1097 @Amode@s: Memory addressing modes passed up the tree.
1099 data Amode = Amode MachRegsAddr InstrBlock
1101 amodeAddr (Amode addr _) = addr
1102 amodeCode (Amode _ code) = code
1105 Now, given a tree (the argument to an StInd) that references memory,
1106 produce a suitable addressing mode.
1109 getAmode :: StixTree -> UniqSM Amode
1111 getAmode tree@(StIndex _ _ _) = getAmode (mangleIndexTree tree)
1113 #if alpha_TARGET_ARCH
1115 getAmode (StPrim IntSubOp [x, StInt i])
1116 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1117 getRegister x `thenUs` \ register ->
1119 code = registerCode register tmp
1120 reg = registerName register tmp
1121 off = ImmInt (-(fromInteger i))
1123 returnUs (Amode (AddrRegImm reg off) code)
1125 getAmode (StPrim IntAddOp [x, StInt i])
1126 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1127 getRegister x `thenUs` \ register ->
1129 code = registerCode register tmp
1130 reg = registerName register tmp
1131 off = ImmInt (fromInteger i)
1133 returnUs (Amode (AddrRegImm reg off) code)
1137 = returnUs (Amode (AddrImm imm__2) id)
1140 imm__2 = case imm of Just x -> x
1143 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1144 getRegister other `thenUs` \ register ->
1146 code = registerCode register tmp
1147 reg = registerName register tmp
1149 returnUs (Amode (AddrReg reg) code)
1151 #endif {- alpha_TARGET_ARCH -}
1152 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1153 #if i386_TARGET_ARCH
1155 getAmode (StPrim IntSubOp [x, StInt i])
1156 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1157 getRegister x `thenUs` \ register ->
1159 code = registerCode register tmp
1160 reg = registerName register tmp
1161 off = ImmInt (-(fromInteger i))
1163 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1165 getAmode (StPrim IntAddOp [x, StInt i])
1168 code = mkSeqInstrs []
1170 returnUs (Amode (ImmAddr imm__2 (fromInteger i)) code)
1173 imm__2 = case imm of Just x -> x
1175 getAmode (StPrim IntAddOp [x, StInt i])
1176 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1177 getRegister x `thenUs` \ register ->
1179 code = registerCode register tmp
1180 reg = registerName register tmp
1181 off = ImmInt (fromInteger i)
1183 returnUs (Amode (AddrBaseIndex (Just reg) Nothing off) code)
1185 getAmode (StPrim IntAddOp [x, y])
1186 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1187 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1188 getRegister x `thenUs` \ register1 ->
1189 getRegister y `thenUs` \ register2 ->
1191 code1 = registerCode register1 tmp1 asmVoid
1192 reg1 = registerName register1 tmp1
1193 code2 = registerCode register2 tmp2 asmVoid
1194 reg2 = registerName register2 tmp2
1195 code__2 = asmParThen [code1, code2]
1197 returnUs (Amode (AddrBaseIndex (Just reg1) (Just (reg2,4)) (ImmInt 0)) code__2)
1202 code = mkSeqInstrs []
1204 returnUs (Amode (ImmAddr imm__2 0) code)
1207 imm__2 = case imm of Just x -> x
1210 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1211 getRegister other `thenUs` \ register ->
1213 code = registerCode register tmp
1214 reg = registerName register tmp
1217 returnUs (Amode (AddrBaseIndex (Just reg) Nothing (ImmInt 0)) code)
1219 #endif {- i386_TARGET_ARCH -}
1220 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1221 #if sparc_TARGET_ARCH
1223 getAmode (StPrim IntSubOp [x, StInt i])
1225 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1226 getRegister x `thenUs` \ register ->
1228 code = registerCode register tmp
1229 reg = registerName register tmp
1230 off = ImmInt (-(fromInteger i))
1232 returnUs (Amode (AddrRegImm reg off) code)
1235 getAmode (StPrim IntAddOp [x, StInt i])
1237 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1238 getRegister x `thenUs` \ register ->
1240 code = registerCode register tmp
1241 reg = registerName register tmp
1242 off = ImmInt (fromInteger i)
1244 returnUs (Amode (AddrRegImm reg off) code)
1246 getAmode (StPrim IntAddOp [x, y])
1247 = getNewRegNCG PtrRep `thenUs` \ tmp1 ->
1248 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1249 getRegister x `thenUs` \ register1 ->
1250 getRegister y `thenUs` \ register2 ->
1252 code1 = registerCode register1 tmp1 asmVoid
1253 reg1 = registerName register1 tmp1
1254 code2 = registerCode register2 tmp2 asmVoid
1255 reg2 = registerName register2 tmp2
1256 code__2 = asmParThen [code1, code2]
1258 returnUs (Amode (AddrRegReg reg1 reg2) code__2)
1262 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1264 code = mkSeqInstr (SETHI (HI imm__2) tmp)
1266 returnUs (Amode (AddrRegImm tmp (LO imm__2)) code)
1269 imm__2 = case imm of Just x -> x
1272 = getNewRegNCG PtrRep `thenUs` \ tmp ->
1273 getRegister other `thenUs` \ register ->
1275 code = registerCode register tmp
1276 reg = registerName register tmp
1279 returnUs (Amode (AddrRegImm reg off) code)
1281 #endif {- sparc_TARGET_ARCH -}
1284 %************************************************************************
1286 \subsection{The @CondCode@ type}
1288 %************************************************************************
1290 Condition codes passed up the tree.
1292 data CondCode = CondCode Bool Cond InstrBlock
1294 condName (CondCode _ cond _) = cond
1295 condFloat (CondCode is_float _ _) = is_float
1296 condCode (CondCode _ _ code) = code
1299 Set up a condition code for a conditional branch.
1302 getCondCode :: StixTree -> UniqSM CondCode
1304 #if alpha_TARGET_ARCH
1305 getCondCode = panic "MachCode.getCondCode: not on Alphas"
1306 #endif {- alpha_TARGET_ARCH -}
1307 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1309 #if i386_TARGET_ARCH || sparc_TARGET_ARCH
1310 -- yes, they really do seem to want exactly the same!
1312 getCondCode (StPrim primop [x, y])
1314 CharGtOp -> condIntCode GTT x y
1315 CharGeOp -> condIntCode GE x y
1316 CharEqOp -> condIntCode EQQ x y
1317 CharNeOp -> condIntCode NE x y
1318 CharLtOp -> condIntCode LTT x y
1319 CharLeOp -> condIntCode LE x y
1321 IntGtOp -> condIntCode GTT x y
1322 IntGeOp -> condIntCode GE x y
1323 IntEqOp -> condIntCode EQQ x y
1324 IntNeOp -> condIntCode NE x y
1325 IntLtOp -> condIntCode LTT x y
1326 IntLeOp -> condIntCode LE x y
1328 WordGtOp -> condIntCode GU x y
1329 WordGeOp -> condIntCode GEU x y
1330 WordEqOp -> condIntCode EQQ x y
1331 WordNeOp -> condIntCode NE x y
1332 WordLtOp -> condIntCode LU x y
1333 WordLeOp -> condIntCode LEU x y
1335 AddrGtOp -> condIntCode GU x y
1336 AddrGeOp -> condIntCode GEU x y
1337 AddrEqOp -> condIntCode EQQ x y
1338 AddrNeOp -> condIntCode NE x y
1339 AddrLtOp -> condIntCode LU x y
1340 AddrLeOp -> condIntCode LEU x y
1342 FloatGtOp -> condFltCode GTT x y
1343 FloatGeOp -> condFltCode GE x y
1344 FloatEqOp -> condFltCode EQQ x y
1345 FloatNeOp -> condFltCode NE x y
1346 FloatLtOp -> condFltCode LTT x y
1347 FloatLeOp -> condFltCode LE x y
1349 DoubleGtOp -> condFltCode GTT x y
1350 DoubleGeOp -> condFltCode GE x y
1351 DoubleEqOp -> condFltCode EQQ x y
1352 DoubleNeOp -> condFltCode NE x y
1353 DoubleLtOp -> condFltCode LTT x y
1354 DoubleLeOp -> condFltCode LE x y
1356 #endif {- i386_TARGET_ARCH || sparc_TARGET_ARCH -}
1361 @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be
1362 passed back up the tree.
1365 condIntCode, condFltCode :: Cond -> StixTree -> StixTree -> UniqSM CondCode
1367 #if alpha_TARGET_ARCH
1368 condIntCode = panic "MachCode.condIntCode: not on Alphas"
1369 condFltCode = panic "MachCode.condFltCode: not on Alphas"
1370 #endif {- alpha_TARGET_ARCH -}
1372 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1373 #if i386_TARGET_ARCH
1375 condIntCode cond (StInd _ x) y
1377 = getAmode x `thenUs` \ amode ->
1379 code1 = amodeCode amode asmVoid
1380 y__2 = amodeAddr amode
1381 code__2 = asmParThen [code1] .
1382 mkSeqInstr (CMP L (OpImm imm__2) (OpAddr y__2))
1384 returnUs (CondCode False cond code__2)
1387 imm__2 = case imm of Just x -> x
1389 condIntCode cond x (StInt 0)
1390 = getRegister x `thenUs` \ register1 ->
1391 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1393 code1 = registerCode register1 tmp1 asmVoid
1394 src1 = registerName register1 tmp1
1395 code__2 = asmParThen [code1] .
1396 mkSeqInstr (TEST L (OpReg src1) (OpReg src1))
1398 returnUs (CondCode False cond code__2)
1400 condIntCode cond x y
1402 = getRegister x `thenUs` \ register1 ->
1403 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1405 code1 = registerCode register1 tmp1 asmVoid
1406 src1 = registerName register1 tmp1
1407 code__2 = asmParThen [code1] .
1408 mkSeqInstr (CMP L (OpImm imm__2) (OpReg src1))
1410 returnUs (CondCode False cond code__2)
1413 imm__2 = case imm of Just x -> x
1415 condIntCode cond (StInd _ x) y
1416 = getAmode x `thenUs` \ amode ->
1417 getRegister y `thenUs` \ register2 ->
1418 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1420 code1 = amodeCode amode asmVoid
1421 src1 = amodeAddr amode
1422 code2 = registerCode register2 tmp2 asmVoid
1423 src2 = registerName register2 tmp2
1424 code__2 = asmParThen [code1, code2] .
1425 mkSeqInstr (CMP L (OpReg src2) (OpAddr src1))
1427 returnUs (CondCode False cond code__2)
1429 condIntCode cond y (StInd _ x)
1430 = getAmode x `thenUs` \ amode ->
1431 getRegister y `thenUs` \ register2 ->
1432 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1434 code1 = amodeCode amode asmVoid
1435 src1 = amodeAddr amode
1436 code2 = registerCode register2 tmp2 asmVoid
1437 src2 = registerName register2 tmp2
1438 code__2 = asmParThen [code1, code2] .
1439 mkSeqInstr (CMP L (OpAddr src1) (OpReg src2))
1441 returnUs (CondCode False cond code__2)
1443 condIntCode cond x y
1444 = getRegister x `thenUs` \ register1 ->
1445 getRegister y `thenUs` \ register2 ->
1446 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1447 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1449 code1 = registerCode register1 tmp1 asmVoid
1450 src1 = registerName register1 tmp1
1451 code2 = registerCode register2 tmp2 asmVoid
1452 src2 = registerName register2 tmp2
1453 code__2 = asmParThen [code1, code2] .
1454 mkSeqInstr (CMP L (OpReg src2) (OpReg src1))
1456 returnUs (CondCode False cond code__2)
1459 condFltCode cond x y
1460 = getRegister x `thenUs` \ register1 ->
1461 getRegister y `thenUs` \ register2 ->
1462 getNewRegNCG (registerRep register1)
1464 getNewRegNCG (registerRep register2)
1466 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1468 pk1 = registerRep register1
1469 code1 = registerCode register1 tmp1
1470 src1 = registerName register1 tmp1
1472 pk2 = registerRep register2
1473 code2 = registerCode register2 tmp2
1474 src2 = registerName register2 tmp2
1476 code__2 = asmParThen [code1 asmVoid, code2 asmVoid] .
1477 mkSeqInstr (GCMP (primRepToSize pk1) src1 src2)
1479 {- On the 486, the flags set by FP compare are the unsigned ones!
1480 (This looks like a HACK to me. WDP 96/03)
1482 fix_FP_cond :: Cond -> Cond
1484 fix_FP_cond GE = GEU
1485 fix_FP_cond GTT = GU
1486 fix_FP_cond LTT = LU
1487 fix_FP_cond LE = LEU
1488 fix_FP_cond any = any
1490 returnUs (CondCode True (fix_FP_cond cond) code__2)
1494 #endif {- i386_TARGET_ARCH -}
1495 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1496 #if sparc_TARGET_ARCH
1498 condIntCode cond x (StInt y)
1500 = getRegister x `thenUs` \ register ->
1501 getNewRegNCG IntRep `thenUs` \ tmp ->
1503 code = registerCode register tmp
1504 src1 = registerName register tmp
1505 src2 = ImmInt (fromInteger y)
1506 code__2 = code . mkSeqInstr (SUB False True src1 (RIImm src2) g0)
1508 returnUs (CondCode False cond code__2)
1510 condIntCode cond x y
1511 = getRegister x `thenUs` \ register1 ->
1512 getRegister y `thenUs` \ register2 ->
1513 getNewRegNCG IntRep `thenUs` \ tmp1 ->
1514 getNewRegNCG IntRep `thenUs` \ tmp2 ->
1516 code1 = registerCode register1 tmp1 asmVoid
1517 src1 = registerName register1 tmp1
1518 code2 = registerCode register2 tmp2 asmVoid
1519 src2 = registerName register2 tmp2
1520 code__2 = asmParThen [code1, code2] .
1521 mkSeqInstr (SUB False True src1 (RIReg src2) g0)
1523 returnUs (CondCode False cond code__2)
1526 condFltCode cond x y
1527 = getRegister x `thenUs` \ register1 ->
1528 getRegister y `thenUs` \ register2 ->
1529 getNewRegNCG (registerRep register1)
1531 getNewRegNCG (registerRep register2)
1533 getNewRegNCG DoubleRep `thenUs` \ tmp ->
1535 promote x = asmInstr (FxTOy F DF x tmp)
1537 pk1 = registerRep register1
1538 code1 = registerCode register1 tmp1
1539 src1 = registerName register1 tmp1
1541 pk2 = registerRep register2
1542 code2 = registerCode register2 tmp2
1543 src2 = registerName register2 tmp2
1547 asmParThen [code1 asmVoid, code2 asmVoid] .
1548 mkSeqInstr (FCMP True (primRepToSize pk1) src1 src2)
1549 else if pk1 == FloatRep then
1550 asmParThen [code1 (promote src1), code2 asmVoid] .
1551 mkSeqInstr (FCMP True DF tmp src2)
1553 asmParThen [code1 asmVoid, code2 (promote src2)] .
1554 mkSeqInstr (FCMP True DF src1 tmp)
1556 returnUs (CondCode True cond code__2)
1558 #endif {- sparc_TARGET_ARCH -}
1561 %************************************************************************
1563 \subsection{Generating assignments}
1565 %************************************************************************
1567 Assignments are really at the heart of the whole code generation
1568 business. Almost all top-level nodes of any real importance are
1569 assignments, which correspond to loads, stores, or register transfers.
1570 If we're really lucky, some of the register transfers will go away,
1571 because we can use the destination register to complete the code
1572 generation for the right hand side. This only fails when the right
1573 hand side is forced into a fixed register (e.g. the result of a call).
1576 assignIntCode, assignFltCode
1577 :: PrimRep -> StixTree -> StixTree -> UniqSM InstrBlock
1579 #if alpha_TARGET_ARCH
1581 assignIntCode pk (StInd _ dst) src
1582 = getNewRegNCG IntRep `thenUs` \ tmp ->
1583 getAmode dst `thenUs` \ amode ->
1584 getRegister src `thenUs` \ register ->
1586 code1 = amodeCode amode asmVoid
1587 dst__2 = amodeAddr amode
1588 code2 = registerCode register tmp asmVoid
1589 src__2 = registerName register tmp
1590 sz = primRepToSize pk
1591 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1595 assignIntCode pk dst src
1596 = getRegister dst `thenUs` \ register1 ->
1597 getRegister src `thenUs` \ register2 ->
1599 dst__2 = registerName register1 zeroh
1600 code = registerCode register2 dst__2
1601 src__2 = registerName register2 dst__2
1602 code__2 = if isFixed register2
1603 then code . mkSeqInstr (OR src__2 (RIReg src__2) dst__2)
1608 #endif {- alpha_TARGET_ARCH -}
1609 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1610 #if i386_TARGET_ARCH
1612 assignIntCode pk (StInd _ dst) src
1613 = getAmode dst `thenUs` \ amode ->
1614 get_op_RI src `thenUs` \ (codesrc, opsrc, sz) ->
1616 code1 = amodeCode amode asmVoid
1617 dst__2 = amodeAddr amode
1618 code__2 = asmParThen [code1, codesrc asmVoid] .
1619 mkSeqInstr (MOV sz opsrc (OpAddr dst__2))
1625 -> UniqSM (InstrBlock,Operand, Size) -- code, operator, size
1629 = returnUs (asmParThen [], OpImm imm_op, L)
1632 imm_op = case imm of Just x -> x
1635 = getRegister op `thenUs` \ register ->
1636 getNewRegNCG (registerRep register)
1639 code = registerCode register tmp
1640 reg = registerName register tmp
1641 pk = registerRep register
1642 sz = primRepToSize pk
1644 returnUs (code, OpReg reg, sz)
1646 assignIntCode pk dst (StInd _ src)
1647 = getNewRegNCG IntRep `thenUs` \ tmp ->
1648 getAmode src `thenUs` \ amode ->
1649 getRegister dst `thenUs` \ register ->
1651 code1 = amodeCode amode asmVoid
1652 src__2 = amodeAddr amode
1653 code2 = registerCode register tmp asmVoid
1654 dst__2 = registerName register tmp
1655 sz = primRepToSize pk
1656 code__2 = asmParThen [code1, code2] .
1657 mkSeqInstr (MOV sz (OpAddr src__2) (OpReg dst__2))
1661 assignIntCode pk dst src
1662 = getRegister dst `thenUs` \ register1 ->
1663 getRegister src `thenUs` \ register2 ->
1664 getNewRegNCG IntRep `thenUs` \ tmp ->
1666 dst__2 = registerName register1 tmp
1667 code = registerCode register2 dst__2
1668 src__2 = registerName register2 dst__2
1669 code__2 = if isFixed register2 && dst__2 /= src__2
1670 then code . mkSeqInstr (MOV L (OpReg src__2) (OpReg dst__2))
1675 #endif {- i386_TARGET_ARCH -}
1676 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1677 #if sparc_TARGET_ARCH
1679 assignIntCode pk (StInd _ dst) src
1680 = getNewRegNCG IntRep `thenUs` \ tmp ->
1681 getAmode dst `thenUs` \ amode ->
1682 getRegister src `thenUs` \ register ->
1684 code1 = amodeCode amode asmVoid
1685 dst__2 = amodeAddr amode
1686 code2 = registerCode register tmp asmVoid
1687 src__2 = registerName register tmp
1688 sz = primRepToSize pk
1689 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1693 assignIntCode pk dst src
1694 = getRegister dst `thenUs` \ register1 ->
1695 getRegister src `thenUs` \ register2 ->
1697 dst__2 = registerName register1 g0
1698 code = registerCode register2 dst__2
1699 src__2 = registerName register2 dst__2
1700 code__2 = if isFixed register2
1701 then code . mkSeqInstr (OR False g0 (RIReg src__2) dst__2)
1706 #endif {- sparc_TARGET_ARCH -}
1709 % --------------------------------
1710 Floating-point assignments:
1711 % --------------------------------
1713 #if alpha_TARGET_ARCH
1715 assignFltCode pk (StInd _ dst) src
1716 = getNewRegNCG pk `thenUs` \ tmp ->
1717 getAmode dst `thenUs` \ amode ->
1718 getRegister src `thenUs` \ register ->
1720 code1 = amodeCode amode asmVoid
1721 dst__2 = amodeAddr amode
1722 code2 = registerCode register tmp asmVoid
1723 src__2 = registerName register tmp
1724 sz = primRepToSize pk
1725 code__2 = asmParThen [code1, code2] . mkSeqInstr (ST sz src__2 dst__2)
1729 assignFltCode pk dst src
1730 = getRegister dst `thenUs` \ register1 ->
1731 getRegister src `thenUs` \ register2 ->
1733 dst__2 = registerName register1 zeroh
1734 code = registerCode register2 dst__2
1735 src__2 = registerName register2 dst__2
1736 code__2 = if isFixed register2
1737 then code . mkSeqInstr (FMOV src__2 dst__2)
1742 #endif {- alpha_TARGET_ARCH -}
1743 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1744 #if i386_TARGET_ARCH
1746 assignFltCode pk (StInd pk_dst dst) (StInd pk_src src)
1747 = getNewRegNCG IntRep `thenUs` \ tmp ->
1748 getAmode src `thenUs` \ amodesrc ->
1749 getAmode dst `thenUs` \ amodedst ->
1751 codesrc1 = amodeCode amodesrc asmVoid
1752 addrsrc1 = amodeAddr amodesrc
1753 codedst1 = amodeCode amodedst asmVoid
1754 addrdst1 = amodeAddr amodedst
1755 addrsrc2 = case (addrOffset addrsrc1 4) of Just x -> x
1756 addrdst2 = case (addrOffset addrdst1 4) of Just x -> x
1758 code__2 = asmParThen [codesrc1, codedst1] .
1759 mkSeqInstrs ([MOV L (OpAddr addrsrc1) (OpReg tmp),
1760 MOV L (OpReg tmp) (OpAddr addrdst1)]
1763 then [MOV L (OpAddr addrsrc2) (OpReg tmp),
1764 MOV L (OpReg tmp) (OpAddr addrdst2)]
1769 assignFltCode pk (StInd _ dst) src
1770 = getNewRegNCG pk `thenUs` \ tmp ->
1771 getAmode dst `thenUs` \ amode ->
1772 getRegister src `thenUs` \ register ->
1774 sz = primRepToSize pk
1775 dst__2 = amodeAddr amode
1777 code1 = amodeCode amode asmVoid
1778 code2 = registerCode register tmp asmVoid
1780 src__2 = registerName register tmp
1782 code__2 = asmParThen [code1, code2] .
1783 mkSeqInstr (GST sz src__2 dst__2)
1787 assignFltCode pk dst src
1788 = getRegister dst `thenUs` \ register1 ->
1789 getRegister src `thenUs` \ register2 ->
1790 getNewRegNCG pk `thenUs` \ tmp ->
1792 -- the register which is dst
1793 dst__2 = registerName register1 tmp
1794 -- the register into which src is computed, preferably dst__2
1795 src__2 = registerName register2 dst__2
1796 -- code to compute src into src__2
1797 code = registerCode register2 dst__2
1799 code__2 = if isFixed register2
1800 then code . mkSeqInstr (GMOV src__2 dst__2)
1805 #endif {- i386_TARGET_ARCH -}
1806 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1807 #if sparc_TARGET_ARCH
1809 assignFltCode pk (StInd _ dst) src
1810 = getNewRegNCG pk `thenUs` \ tmp1 ->
1811 getAmode dst `thenUs` \ amode ->
1812 getRegister src `thenUs` \ register ->
1814 sz = primRepToSize pk
1815 dst__2 = amodeAddr amode
1817 code1 = amodeCode amode asmVoid
1818 code2 = registerCode register tmp1 asmVoid
1820 src__2 = registerName register tmp1
1821 pk__2 = registerRep register
1822 sz__2 = primRepToSize pk__2
1824 code__2 = asmParThen [code1, code2] .
1826 mkSeqInstr (ST sz src__2 dst__2)
1828 mkSeqInstrs [FxTOy sz__2 sz src__2 tmp1, ST sz tmp1 dst__2]
1832 assignFltCode pk dst src
1833 = getRegister dst `thenUs` \ register1 ->
1834 getRegister src `thenUs` \ register2 ->
1836 pk__2 = registerRep register2
1837 sz__2 = primRepToSize pk__2
1839 getNewRegNCG pk__2 `thenUs` \ tmp ->
1841 sz = primRepToSize pk
1842 dst__2 = registerName register1 g0 -- must be Fixed
1845 reg__2 = if pk /= pk__2 then tmp else dst__2
1847 code = registerCode register2 reg__2
1849 src__2 = registerName register2 reg__2
1853 code . mkSeqInstr (FxTOy sz__2 sz src__2 dst__2)
1854 else if isFixed register2 then
1855 code . mkSeqInstr (FMOV sz src__2 dst__2)
1861 #endif {- sparc_TARGET_ARCH -}
1864 %************************************************************************
1866 \subsection{Generating an unconditional branch}
1868 %************************************************************************
1870 We accept two types of targets: an immediate CLabel or a tree that
1871 gets evaluated into a register. Any CLabels which are AsmTemporaries
1872 are assumed to be in the local block of code, close enough for a
1873 branch instruction. Other CLabels are assumed to be far away.
1875 (If applicable) Do not fill the delay slots here; you will confuse the
1879 genJump :: StixTree{-the branch target-} -> UniqSM InstrBlock
1881 #if alpha_TARGET_ARCH
1883 genJump (StCLbl lbl)
1884 | isAsmTemp lbl = returnInstr (BR target)
1885 | otherwise = returnInstrs [LDA pv (AddrImm target), JMP zeroh (AddrReg pv) 0]
1887 target = ImmCLbl lbl
1890 = getRegister tree `thenUs` \ register ->
1891 getNewRegNCG PtrRep `thenUs` \ tmp ->
1893 dst = registerName register pv
1894 code = registerCode register pv
1895 target = registerName register pv
1897 if isFixed register then
1898 returnSeq code [OR dst (RIReg dst) pv, JMP zeroh (AddrReg pv) 0]
1900 returnUs (code . mkSeqInstr (JMP zeroh (AddrReg pv) 0))
1902 #endif {- alpha_TARGET_ARCH -}
1903 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1904 #if i386_TARGET_ARCH
1907 genJump (StCLbl lbl)
1908 | isAsmTemp lbl = returnInstrs [JXX ALWAYS lbl]
1909 | otherwise = returnInstrs [JMP (OpImm target)]
1911 target = ImmCLbl lbl
1914 genJump (StInd pk mem)
1915 = getAmode mem `thenUs` \ amode ->
1917 code = amodeCode amode
1918 target = amodeAddr amode
1920 returnSeq code [JMP (OpAddr target)]
1924 = returnInstr (JMP (OpImm target))
1927 = getRegister tree `thenUs` \ register ->
1928 getNewRegNCG PtrRep `thenUs` \ tmp ->
1930 code = registerCode register tmp
1931 target = registerName register tmp
1933 returnSeq code [JMP (OpReg target)]
1936 target = case imm of Just x -> x
1938 #endif {- i386_TARGET_ARCH -}
1939 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1940 #if sparc_TARGET_ARCH
1942 genJump (StCLbl lbl)
1943 | isAsmTemp lbl = returnInstrs [BI ALWAYS False target, NOP]
1944 | otherwise = returnInstrs [CALL target 0 True, NOP]
1946 target = ImmCLbl lbl
1949 = getRegister tree `thenUs` \ register ->
1950 getNewRegNCG PtrRep `thenUs` \ tmp ->
1952 code = registerCode register tmp
1953 target = registerName register tmp
1955 returnSeq code [JMP (AddrRegReg target g0), NOP]
1957 #endif {- sparc_TARGET_ARCH -}
1960 %************************************************************************
1962 \subsection{Conditional jumps}
1964 %************************************************************************
1966 Conditional jumps are always to local labels, so we can use branch
1967 instructions. We peek at the arguments to decide what kind of
1970 ALPHA: For comparisons with 0, we're laughing, because we can just do
1971 the desired conditional branch.
1973 I386: First, we have to ensure that the condition
1974 codes are set according to the supplied comparison operation.
1976 SPARC: First, we have to ensure that the condition codes are set
1977 according to the supplied comparison operation. We generate slightly
1978 different code for floating point comparisons, because a floating
1979 point operation cannot directly precede a @BF@. We assume the worst
1980 and fill that slot with a @NOP@.
1982 SPARC: Do not fill the delay slots here; you will confuse the register
1987 :: CLabel -- the branch target
1988 -> StixTree -- the condition on which to branch
1989 -> UniqSM InstrBlock
1991 #if alpha_TARGET_ARCH
1993 genCondJump lbl (StPrim op [x, StInt 0])
1994 = getRegister x `thenUs` \ register ->
1995 getNewRegNCG (registerRep register)
1998 code = registerCode register tmp
1999 value = registerName register tmp
2000 pk = registerRep register
2001 target = ImmCLbl lbl
2003 returnSeq code [BI (cmpOp op) value target]
2005 cmpOp CharGtOp = GTT
2007 cmpOp CharEqOp = EQQ
2009 cmpOp CharLtOp = LTT
2018 cmpOp WordGeOp = ALWAYS
2019 cmpOp WordEqOp = EQQ
2021 cmpOp WordLtOp = NEVER
2022 cmpOp WordLeOp = EQQ
2024 cmpOp AddrGeOp = ALWAYS
2025 cmpOp AddrEqOp = EQQ
2027 cmpOp AddrLtOp = NEVER
2028 cmpOp AddrLeOp = EQQ
2030 genCondJump lbl (StPrim op [x, StDouble 0.0])
2031 = getRegister x `thenUs` \ register ->
2032 getNewRegNCG (registerRep register)
2035 code = registerCode register tmp
2036 value = registerName register tmp
2037 pk = registerRep register
2038 target = ImmCLbl lbl
2040 returnUs (code . mkSeqInstr (BF (cmpOp op) value target))
2042 cmpOp FloatGtOp = GTT
2043 cmpOp FloatGeOp = GE
2044 cmpOp FloatEqOp = EQQ
2045 cmpOp FloatNeOp = NE
2046 cmpOp FloatLtOp = LTT
2047 cmpOp FloatLeOp = LE
2048 cmpOp DoubleGtOp = GTT
2049 cmpOp DoubleGeOp = GE
2050 cmpOp DoubleEqOp = EQQ
2051 cmpOp DoubleNeOp = NE
2052 cmpOp DoubleLtOp = LTT
2053 cmpOp DoubleLeOp = LE
2055 genCondJump lbl (StPrim op [x, y])
2057 = trivialFCode pr instr x y `thenUs` \ register ->
2058 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2060 code = registerCode register tmp
2061 result = registerName register tmp
2062 target = ImmCLbl lbl
2064 returnUs (code . mkSeqInstr (BF cond result target))
2066 pr = panic "trivialU?FCode: does not use PrimRep on Alpha"
2068 fltCmpOp op = case op of
2082 (instr, cond) = case op of
2083 FloatGtOp -> (FCMP TF LE, EQQ)
2084 FloatGeOp -> (FCMP TF LTT, EQQ)
2085 FloatEqOp -> (FCMP TF EQQ, NE)
2086 FloatNeOp -> (FCMP TF EQQ, EQQ)
2087 FloatLtOp -> (FCMP TF LTT, NE)
2088 FloatLeOp -> (FCMP TF LE, NE)
2089 DoubleGtOp -> (FCMP TF LE, EQQ)
2090 DoubleGeOp -> (FCMP TF LTT, EQQ)
2091 DoubleEqOp -> (FCMP TF EQQ, NE)
2092 DoubleNeOp -> (FCMP TF EQQ, EQQ)
2093 DoubleLtOp -> (FCMP TF LTT, NE)
2094 DoubleLeOp -> (FCMP TF LE, NE)
2096 genCondJump lbl (StPrim op [x, y])
2097 = trivialCode instr x y `thenUs` \ register ->
2098 getNewRegNCG IntRep `thenUs` \ tmp ->
2100 code = registerCode register tmp
2101 result = registerName register tmp
2102 target = ImmCLbl lbl
2104 returnUs (code . mkSeqInstr (BI cond result target))
2106 (instr, cond) = case op of
2107 CharGtOp -> (CMP LE, EQQ)
2108 CharGeOp -> (CMP LTT, EQQ)
2109 CharEqOp -> (CMP EQQ, NE)
2110 CharNeOp -> (CMP EQQ, EQQ)
2111 CharLtOp -> (CMP LTT, NE)
2112 CharLeOp -> (CMP LE, NE)
2113 IntGtOp -> (CMP LE, EQQ)
2114 IntGeOp -> (CMP LTT, EQQ)
2115 IntEqOp -> (CMP EQQ, NE)
2116 IntNeOp -> (CMP EQQ, EQQ)
2117 IntLtOp -> (CMP LTT, NE)
2118 IntLeOp -> (CMP LE, NE)
2119 WordGtOp -> (CMP ULE, EQQ)
2120 WordGeOp -> (CMP ULT, EQQ)
2121 WordEqOp -> (CMP EQQ, NE)
2122 WordNeOp -> (CMP EQQ, EQQ)
2123 WordLtOp -> (CMP ULT, NE)
2124 WordLeOp -> (CMP ULE, NE)
2125 AddrGtOp -> (CMP ULE, EQQ)
2126 AddrGeOp -> (CMP ULT, EQQ)
2127 AddrEqOp -> (CMP EQQ, NE)
2128 AddrNeOp -> (CMP EQQ, EQQ)
2129 AddrLtOp -> (CMP ULT, NE)
2130 AddrLeOp -> (CMP ULE, NE)
2132 #endif {- alpha_TARGET_ARCH -}
2133 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2134 #if i386_TARGET_ARCH
2136 genCondJump lbl bool
2137 = getCondCode bool `thenUs` \ condition ->
2139 code = condCode condition
2140 cond = condName condition
2141 target = ImmCLbl lbl
2143 returnSeq code [JXX cond lbl]
2145 #endif {- i386_TARGET_ARCH -}
2146 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2147 #if sparc_TARGET_ARCH
2149 genCondJump lbl bool
2150 = getCondCode bool `thenUs` \ condition ->
2152 code = condCode condition
2153 cond = condName condition
2154 target = ImmCLbl lbl
2157 if condFloat condition then
2158 [NOP, BF cond False target, NOP]
2160 [BI cond False target, NOP]
2163 #endif {- sparc_TARGET_ARCH -}
2166 %************************************************************************
2168 \subsection{Generating C calls}
2170 %************************************************************************
2172 Now the biggest nightmare---calls. Most of the nastiness is buried in
2173 @get_arg@, which moves the arguments to the correct registers/stack
2174 locations. Apart from that, the code is easy.
2176 (If applicable) Do not fill the delay slots here; you will confuse the
2181 :: FAST_STRING -- function to call
2183 -> PrimRep -- type of the result
2184 -> [StixTree] -- arguments (of mixed type)
2185 -> UniqSM InstrBlock
2187 #if alpha_TARGET_ARCH
2189 genCCall fn cconv kind args
2190 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2191 `thenUs` \ ((unused,_), argCode) ->
2193 nRegs = length allArgRegs - length unused
2194 code = asmParThen (map ($ asmVoid) argCode)
2197 LDA pv (AddrImm (ImmLab (ptext fn))),
2198 JSR ra (AddrReg pv) nRegs,
2199 LDGP gp (AddrReg ra)]
2201 ------------------------
2202 {- Try to get a value into a specific register (or registers) for
2203 a call. The first 6 arguments go into the appropriate
2204 argument register (separate registers for integer and floating
2205 point arguments, but used in lock-step), and the remaining
2206 arguments are dumped to the stack, beginning at 0(sp). Our
2207 first argument is a pair of the list of remaining argument
2208 registers to be assigned for this call and the next stack
2209 offset to use for overflowing arguments. This way,
2210 @get_Arg@ can be applied to all of a call's arguments using
2214 :: ([(Reg,Reg)], Int) -- Argument registers and stack offset (accumulator)
2215 -> StixTree -- Current argument
2216 -> UniqSM (([(Reg,Reg)],Int), InstrBlock) -- Updated accumulator and code
2218 -- We have to use up all of our argument registers first...
2220 get_arg ((iDst,fDst):dsts, offset) arg
2221 = getRegister arg `thenUs` \ register ->
2223 reg = if isFloatingRep pk then fDst else iDst
2224 code = registerCode register reg
2225 src = registerName register reg
2226 pk = registerRep register
2229 if isFloatingRep pk then
2230 ((dsts, offset), if isFixed register then
2231 code . mkSeqInstr (FMOV src fDst)
2234 ((dsts, offset), if isFixed register then
2235 code . mkSeqInstr (OR src (RIReg src) iDst)
2238 -- Once we have run out of argument registers, we move to the
2241 get_arg ([], offset) arg
2242 = getRegister arg `thenUs` \ register ->
2243 getNewRegNCG (registerRep register)
2246 code = registerCode register tmp
2247 src = registerName register tmp
2248 pk = registerRep register
2249 sz = primRepToSize pk
2251 returnUs (([], offset + 1), code . mkSeqInstr (ST sz src (spRel offset)))
2253 #endif {- alpha_TARGET_ARCH -}
2254 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2255 #if i386_TARGET_ARCH
2257 genCCall fn cconv kind [StInt i]
2258 | fn == SLIT ("PerformGC_wrapper")
2259 = let call = [MOV L (OpImm (ImmInt (fromInteger i))) (OpReg eax),
2260 CALL (ImmLit (ptext (if underscorePrefix
2261 then (SLIT ("_PerformGC_wrapper"))
2262 else (SLIT ("PerformGC_wrapper")))))]
2267 genCCall fn cconv kind args
2268 = get_call_args args `thenUs` \ (tot_arg_size, argCode) ->
2270 code2 = asmParThen (map ($ asmVoid) argCode)
2271 call = [SUB L (OpImm (ImmInt tot_arg_size)) (OpReg esp),
2273 ADD L (OpImm (ImmInt tot_arg_size)) (OpReg esp)
2276 returnSeq code2 call
2279 -- function names that begin with '.' are assumed to be special
2280 -- internally generated names like '.mul,' which don't get an
2281 -- underscore prefix
2282 -- ToDo:needed (WDP 96/03) ???
2283 fn__2 = case (_HEAD_ fn) of
2284 '.' -> ImmLit (ptext fn)
2285 _ -> ImmLab (ptext fn)
2291 -- do get_call_arg on each arg, threading the total arg size along
2292 -- process the args right-to-left
2293 get_call_args :: [StixTree] -> UniqSM (Int, [InstrBlock])
2298 = returnUs (curr_sz, [])
2299 f curr_sz (arg:args)
2300 = f curr_sz args `thenUs` \ (new_sz, iblocks) ->
2301 get_call_arg arg new_sz `thenUs` \ (new_sz2, iblock) ->
2302 returnUs (new_sz2, iblock:iblocks)
2306 get_call_arg :: StixTree{-current argument-}
2307 -> Int{-running total of arg sizes seen so far-}
2308 -> UniqSM (Int, InstrBlock) -- updated tot argsz, code
2310 get_call_arg arg old_sz
2311 = get_op arg `thenUs` \ (code, reg, sz) ->
2312 let new_sz = old_sz + arg_size sz
2313 in if (case sz of DF -> True; F -> True; _ -> False)
2314 then returnUs (new_sz,
2316 mkSeqInstr (GST sz reg
2317 (AddrBaseIndex (Just esp)
2318 Nothing (ImmInt (- new_sz))))
2320 else returnUs (new_sz,
2322 mkSeqInstr (MOV sz (OpReg reg)
2324 (AddrBaseIndex (Just esp)
2325 Nothing (ImmInt (- new_sz)))))
2330 -> UniqSM (InstrBlock, Reg, Size) -- code, reg, size
2333 = getRegister op `thenUs` \ register ->
2334 getNewRegNCG (registerRep register)
2337 code = registerCode register tmp
2338 reg = registerName register tmp
2339 pk = registerRep register
2340 sz = primRepToSize pk
2342 returnUs (code, reg, sz)
2344 #endif {- i386_TARGET_ARCH -}
2345 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2346 #if sparc_TARGET_ARCH
2348 genCCall fn cconv kind args
2349 = mapAccumLUs get_arg (allArgRegs, eXTRA_STK_ARGS_HERE) args
2350 `thenUs` \ ((unused,_), argCode) ->
2352 nRegs = length allArgRegs - length unused
2353 call = CALL fn__2 nRegs False
2354 code = asmParThen (map ($ asmVoid) argCode)
2356 returnSeq code [call, NOP]
2358 -- function names that begin with '.' are assumed to be special
2359 -- internally generated names like '.mul,' which don't get an
2360 -- underscore prefix
2361 -- ToDo:needed (WDP 96/03) ???
2362 fn__2 = case (_HEAD_ fn) of
2363 '.' -> ImmLit (ptext fn)
2364 _ -> ImmLab (ptext fn)
2366 ------------------------------------
2367 {- Try to get a value into a specific register (or registers) for
2368 a call. The SPARC calling convention is an absolute
2369 nightmare. The first 6x32 bits of arguments are mapped into
2370 %o0 through %o5, and the remaining arguments are dumped to the
2371 stack, beginning at [%sp+92]. (Note that %o6 == %sp.) Our
2372 first argument is a pair of the list of remaining argument
2373 registers to be assigned for this call and the next stack
2374 offset to use for overflowing arguments. This way,
2375 @get_arg@ can be applied to all of a call's arguments using
2379 :: ([Reg],Int) -- Argument registers and stack offset (accumulator)
2380 -> StixTree -- Current argument
2381 -> UniqSM (([Reg],Int), InstrBlock) -- Updated accumulator and code
2383 -- We have to use up all of our argument registers first...
2385 get_arg (dst:dsts, offset) arg
2386 = getRegister arg `thenUs` \ register ->
2387 getNewRegNCG (registerRep register)
2390 reg = if isFloatingRep pk then tmp else dst
2391 code = registerCode register reg
2392 src = registerName register reg
2393 pk = registerRep register
2395 returnUs (case pk of
2398 [] -> (([], offset + 1), code . mkSeqInstrs [
2399 -- conveniently put the second part in the right stack
2400 -- location, and load the first part into %o5
2401 ST DF src (spRel (offset - 1)),
2402 LD W (spRel (offset - 1)) dst])
2403 (dst__2:dsts__2) -> ((dsts__2, offset), code . mkSeqInstrs [
2404 ST DF src (spRel (-2)),
2405 LD W (spRel (-2)) dst,
2406 LD W (spRel (-1)) dst__2])
2407 FloatRep -> ((dsts, offset), code . mkSeqInstrs [
2408 ST F src (spRel (-2)),
2409 LD W (spRel (-2)) dst])
2410 _ -> ((dsts, offset), if isFixed register then
2411 code . mkSeqInstr (OR False g0 (RIReg src) dst)
2414 -- Once we have run out of argument registers, we move to the
2417 get_arg ([], offset) arg
2418 = getRegister arg `thenUs` \ register ->
2419 getNewRegNCG (registerRep register)
2422 code = registerCode register tmp
2423 src = registerName register tmp
2424 pk = registerRep register
2425 sz = primRepToSize pk
2426 words = if pk == DoubleRep then 2 else 1
2428 returnUs (([], offset + words), code . mkSeqInstr (ST sz src (spRel offset)))
2430 #endif {- sparc_TARGET_ARCH -}
2433 %************************************************************************
2435 \subsection{Support bits}
2437 %************************************************************************
2439 %************************************************************************
2441 \subsubsection{@condIntReg@ and @condFltReg@: condition codes into registers}
2443 %************************************************************************
2445 Turn those condition codes into integers now (when they appear on
2446 the right hand side of an assignment).
2448 (If applicable) Do not fill the delay slots here; you will confuse the
2452 condIntReg, condFltReg :: Cond -> StixTree -> StixTree -> UniqSM Register
2454 #if alpha_TARGET_ARCH
2455 condIntReg = panic "MachCode.condIntReg (not on Alpha)"
2456 condFltReg = panic "MachCode.condFltReg (not on Alpha)"
2457 #endif {- alpha_TARGET_ARCH -}
2459 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2460 #if i386_TARGET_ARCH
2463 = condIntCode cond x y `thenUs` \ condition ->
2464 getNewRegNCG IntRep `thenUs` \ tmp ->
2465 --getRegister dst `thenUs` \ register ->
2467 --code2 = registerCode register tmp asmVoid
2468 --dst__2 = registerName register tmp
2469 code = condCode condition
2470 cond = condName condition
2471 -- ToDo: if dst is eax, ebx, ecx, or edx we would not need the move.
2472 code__2 dst = code . mkSeqInstrs [
2473 SETCC cond (OpReg tmp),
2474 AND L (OpImm (ImmInt 1)) (OpReg tmp),
2475 MOV L (OpReg tmp) (OpReg dst)]
2477 returnUs (Any IntRep code__2)
2480 = getUniqLabelNCG `thenUs` \ lbl1 ->
2481 getUniqLabelNCG `thenUs` \ lbl2 ->
2482 condFltCode cond x y `thenUs` \ condition ->
2484 code = condCode condition
2485 cond = condName condition
2486 code__2 dst = code . mkSeqInstrs [
2488 MOV L (OpImm (ImmInt 0)) (OpReg dst),
2491 MOV L (OpImm (ImmInt 1)) (OpReg dst),
2494 returnUs (Any IntRep code__2)
2496 #endif {- i386_TARGET_ARCH -}
2497 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2498 #if sparc_TARGET_ARCH
2500 condIntReg EQQ x (StInt 0)
2501 = getRegister x `thenUs` \ register ->
2502 getNewRegNCG IntRep `thenUs` \ tmp ->
2504 code = registerCode register tmp
2505 src = registerName register tmp
2506 code__2 dst = code . mkSeqInstrs [
2507 SUB False True g0 (RIReg src) g0,
2508 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2510 returnUs (Any IntRep code__2)
2513 = getRegister x `thenUs` \ register1 ->
2514 getRegister y `thenUs` \ register2 ->
2515 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2516 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2518 code1 = registerCode register1 tmp1 asmVoid
2519 src1 = registerName register1 tmp1
2520 code2 = registerCode register2 tmp2 asmVoid
2521 src2 = registerName register2 tmp2
2522 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2523 XOR False src1 (RIReg src2) dst,
2524 SUB False True g0 (RIReg dst) g0,
2525 SUB True False g0 (RIImm (ImmInt (-1))) dst]
2527 returnUs (Any IntRep code__2)
2529 condIntReg NE x (StInt 0)
2530 = getRegister x `thenUs` \ register ->
2531 getNewRegNCG IntRep `thenUs` \ tmp ->
2533 code = registerCode register tmp
2534 src = registerName register tmp
2535 code__2 dst = code . mkSeqInstrs [
2536 SUB False True g0 (RIReg src) g0,
2537 ADD True False g0 (RIImm (ImmInt 0)) dst]
2539 returnUs (Any IntRep code__2)
2542 = getRegister x `thenUs` \ register1 ->
2543 getRegister y `thenUs` \ register2 ->
2544 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2545 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2547 code1 = registerCode register1 tmp1 asmVoid
2548 src1 = registerName register1 tmp1
2549 code2 = registerCode register2 tmp2 asmVoid
2550 src2 = registerName register2 tmp2
2551 code__2 dst = asmParThen [code1, code2] . mkSeqInstrs [
2552 XOR False src1 (RIReg src2) dst,
2553 SUB False True g0 (RIReg dst) g0,
2554 ADD True False g0 (RIImm (ImmInt 0)) dst]
2556 returnUs (Any IntRep code__2)
2559 = getUniqLabelNCG `thenUs` \ lbl1 ->
2560 getUniqLabelNCG `thenUs` \ lbl2 ->
2561 condIntCode cond x y `thenUs` \ condition ->
2563 code = condCode condition
2564 cond = condName condition
2565 code__2 dst = code . mkSeqInstrs [
2566 BI cond False (ImmCLbl lbl1), NOP,
2567 OR False g0 (RIImm (ImmInt 0)) dst,
2568 BI ALWAYS False (ImmCLbl lbl2), NOP,
2570 OR False g0 (RIImm (ImmInt 1)) dst,
2573 returnUs (Any IntRep code__2)
2576 = getUniqLabelNCG `thenUs` \ lbl1 ->
2577 getUniqLabelNCG `thenUs` \ lbl2 ->
2578 condFltCode cond x y `thenUs` \ condition ->
2580 code = condCode condition
2581 cond = condName condition
2582 code__2 dst = code . mkSeqInstrs [
2584 BF cond False (ImmCLbl lbl1), NOP,
2585 OR False g0 (RIImm (ImmInt 0)) dst,
2586 BI ALWAYS False (ImmCLbl lbl2), NOP,
2588 OR False g0 (RIImm (ImmInt 1)) dst,
2591 returnUs (Any IntRep code__2)
2593 #endif {- sparc_TARGET_ARCH -}
2596 %************************************************************************
2598 \subsubsection{@trivial*Code@: deal with trivial instructions}
2600 %************************************************************************
2602 Trivial (dyadic: @trivialCode@, floating-point: @trivialFCode@, unary:
2603 @trivialUCode@, unary fl-pt:@trivialUFCode@) instructions. Only look
2604 for constants on the right hand side, because that's where the generic
2605 optimizer will have put them.
2607 Similarly, for unary instructions, we don't have to worry about
2608 matching an StInt as the argument, because genericOpt will already
2609 have handled the constant-folding.
2613 :: IF_ARCH_alpha((Reg -> RI -> Reg -> Instr)
2614 ,IF_ARCH_i386 ((Operand -> Operand -> Instr)
2615 ,IF_ARCH_sparc((Reg -> RI -> Reg -> Instr)
2617 -> StixTree -> StixTree -- the two arguments
2622 -> IF_ARCH_alpha((Reg -> Reg -> Reg -> Instr)
2623 ,IF_ARCH_sparc((Size -> Reg -> Reg -> Reg -> Instr)
2624 ,IF_ARCH_i386 ((Size -> Reg -> Reg -> Reg -> Instr)
2626 -> StixTree -> StixTree -- the two arguments
2630 :: IF_ARCH_alpha((RI -> Reg -> Instr)
2631 ,IF_ARCH_i386 ((Operand -> Instr)
2632 ,IF_ARCH_sparc((RI -> Reg -> Instr)
2634 -> StixTree -- the one argument
2639 -> IF_ARCH_alpha((Reg -> Reg -> Instr)
2640 ,IF_ARCH_i386 ((Reg -> Reg -> Instr)
2641 ,IF_ARCH_sparc((Reg -> Reg -> Instr)
2643 -> StixTree -- the one argument
2646 #if alpha_TARGET_ARCH
2648 trivialCode instr x (StInt y)
2650 = getRegister x `thenUs` \ register ->
2651 getNewRegNCG IntRep `thenUs` \ tmp ->
2653 code = registerCode register tmp
2654 src1 = registerName register tmp
2655 src2 = ImmInt (fromInteger y)
2656 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2658 returnUs (Any IntRep code__2)
2660 trivialCode instr x y
2661 = getRegister x `thenUs` \ register1 ->
2662 getRegister y `thenUs` \ register2 ->
2663 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2664 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2666 code1 = registerCode register1 tmp1 asmVoid
2667 src1 = registerName register1 tmp1
2668 code2 = registerCode register2 tmp2 asmVoid
2669 src2 = registerName register2 tmp2
2670 code__2 dst = asmParThen [code1, code2] .
2671 mkSeqInstr (instr src1 (RIReg src2) dst)
2673 returnUs (Any IntRep code__2)
2676 trivialUCode instr x
2677 = getRegister x `thenUs` \ register ->
2678 getNewRegNCG IntRep `thenUs` \ tmp ->
2680 code = registerCode register tmp
2681 src = registerName register tmp
2682 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2684 returnUs (Any IntRep code__2)
2687 trivialFCode _ instr x y
2688 = getRegister x `thenUs` \ register1 ->
2689 getRegister y `thenUs` \ register2 ->
2690 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2691 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2693 code1 = registerCode register1 tmp1
2694 src1 = registerName register1 tmp1
2696 code2 = registerCode register2 tmp2
2697 src2 = registerName register2 tmp2
2699 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2700 mkSeqInstr (instr src1 src2 dst)
2702 returnUs (Any DoubleRep code__2)
2704 trivialUFCode _ instr x
2705 = getRegister x `thenUs` \ register ->
2706 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2708 code = registerCode register tmp
2709 src = registerName register tmp
2710 code__2 dst = code . mkSeqInstr (instr src dst)
2712 returnUs (Any DoubleRep code__2)
2714 #endif {- alpha_TARGET_ARCH -}
2715 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2716 #if i386_TARGET_ARCH
2718 trivialCode instr x y
2720 = getRegister x `thenUs` \ register1 ->
2722 code__2 dst = let code1 = registerCode register1 dst
2723 src1 = registerName register1 dst
2725 if isFixed register1 && src1 /= dst
2726 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2727 instr (OpImm imm__2) (OpReg dst)]
2729 mkSeqInstrs [instr (OpImm imm__2) (OpReg src1)]
2731 returnUs (Any IntRep code__2)
2734 imm__2 = case imm of Just x -> x
2736 -- This seems pretty dubious to me. JRS, 000125.
2737 trivialCode instr x y
2739 = getRegister y `thenUs` \ register1 ->
2741 code__2 dst = let code1 = registerCode register1 dst
2742 src1 = registerName register1 dst
2744 if isFixed register1 && src1 /= dst
2745 then mkSeqInstrs [MOV L (OpImm imm__2) (OpReg dst),
2746 instr (OpReg src1) (OpReg dst)]
2748 -- can't possibly be right, if instr is
2750 mkSeqInstr (instr (OpImm imm__2) (OpReg src1))
2752 returnUs (Any IntRep code__2)
2755 imm__2 = case imm of Just x -> x
2758 trivialCode instr x y
2759 = getRegister x `thenUs` \ register1 ->
2760 getRegister y `thenUs` \ register2 ->
2761 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2763 code2 = registerCode register2 tmp2 asmVoid
2764 src2 = registerName register2 tmp2
2766 code1 = registerCode register1 dst asmVoid
2767 src1 = registerName register1 dst
2768 in asmParThen [code1, code2] .
2769 if isFixed register1 && src1 /= dst
2770 then mkSeqInstrs [MOV L (OpReg src1) (OpReg dst),
2771 instr (OpReg src2) (OpReg dst)]
2773 mkSeqInstr (instr (OpReg src2) (OpReg src1))
2775 returnUs (Any IntRep code__2)
2778 trivialUCode instr x
2779 = getRegister x `thenUs` \ register ->
2782 code = registerCode register dst
2783 src = registerName register dst
2784 in code . if isFixed register && dst /= src
2785 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
2787 else mkSeqInstr (instr (OpReg src))
2789 returnUs (Any IntRep code__2)
2792 trivialFCode pk instr x y
2793 = getRegister x `thenUs` \ register1 ->
2794 getRegister y `thenUs` \ register2 ->
2795 getNewRegNCG DoubleRep `thenUs` \ tmp1 ->
2796 getNewRegNCG DoubleRep `thenUs` \ tmp2 ->
2798 code1 = registerCode register1 tmp1
2799 src1 = registerName register1 tmp1
2801 code2 = registerCode register2 tmp2
2802 src2 = registerName register2 tmp2
2804 code__2 dst = asmParThen [code1 asmVoid, code2 asmVoid] .
2805 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2807 returnUs (Any DoubleRep code__2)
2811 trivialUFCode pk instr x
2812 = getRegister x `thenUs` \ register ->
2813 getNewRegNCG pk `thenUs` \ tmp ->
2815 code = registerCode register tmp
2816 src = registerName register tmp
2817 code__2 dst = code . mkSeqInstr (instr src dst)
2819 returnUs (Any pk code__2)
2821 #endif {- i386_TARGET_ARCH -}
2822 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2823 #if sparc_TARGET_ARCH
2825 trivialCode instr x (StInt y)
2827 = getRegister x `thenUs` \ register ->
2828 getNewRegNCG IntRep `thenUs` \ tmp ->
2830 code = registerCode register tmp
2831 src1 = registerName register tmp
2832 src2 = ImmInt (fromInteger y)
2833 code__2 dst = code . mkSeqInstr (instr src1 (RIImm src2) dst)
2835 returnUs (Any IntRep code__2)
2837 trivialCode instr x y
2838 = getRegister x `thenUs` \ register1 ->
2839 getRegister y `thenUs` \ register2 ->
2840 getNewRegNCG IntRep `thenUs` \ tmp1 ->
2841 getNewRegNCG IntRep `thenUs` \ tmp2 ->
2843 code1 = registerCode register1 tmp1 asmVoid
2844 src1 = registerName register1 tmp1
2845 code2 = registerCode register2 tmp2 asmVoid
2846 src2 = registerName register2 tmp2
2847 code__2 dst = asmParThen [code1, code2] .
2848 mkSeqInstr (instr src1 (RIReg src2) dst)
2850 returnUs (Any IntRep code__2)
2853 trivialFCode pk instr x y
2854 = getRegister x `thenUs` \ register1 ->
2855 getRegister y `thenUs` \ register2 ->
2856 getNewRegNCG (registerRep register1)
2858 getNewRegNCG (registerRep register2)
2860 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2862 promote x = asmInstr (FxTOy F DF x tmp)
2864 pk1 = registerRep register1
2865 code1 = registerCode register1 tmp1
2866 src1 = registerName register1 tmp1
2868 pk2 = registerRep register2
2869 code2 = registerCode register2 tmp2
2870 src2 = registerName register2 tmp2
2874 asmParThen [code1 asmVoid, code2 asmVoid] .
2875 mkSeqInstr (instr (primRepToSize pk) src1 src2 dst)
2876 else if pk1 == FloatRep then
2877 asmParThen [code1 (promote src1), code2 asmVoid] .
2878 mkSeqInstr (instr DF tmp src2 dst)
2880 asmParThen [code1 asmVoid, code2 (promote src2)] .
2881 mkSeqInstr (instr DF src1 tmp dst)
2883 returnUs (Any (if pk1 == pk2 then pk1 else DoubleRep) code__2)
2886 trivialUCode instr x
2887 = getRegister x `thenUs` \ register ->
2888 getNewRegNCG IntRep `thenUs` \ tmp ->
2890 code = registerCode register tmp
2891 src = registerName register tmp
2892 code__2 dst = code . mkSeqInstr (instr (RIReg src) dst)
2894 returnUs (Any IntRep code__2)
2897 trivialUFCode pk instr x
2898 = getRegister x `thenUs` \ register ->
2899 getNewRegNCG pk `thenUs` \ tmp ->
2901 code = registerCode register tmp
2902 src = registerName register tmp
2903 code__2 dst = code . mkSeqInstr (instr src dst)
2905 returnUs (Any pk code__2)
2907 #endif {- sparc_TARGET_ARCH -}
2910 %************************************************************************
2912 \subsubsection{Coercing to/from integer/floating-point...}
2914 %************************************************************************
2916 @coerce(Int|Flt)Code@ are simple coercions that don't require any code
2917 to be generated. Here we just change the type on the Register passed
2918 on up. The code is machine-independent.
2920 @coerce(Int2FP|FP2Int)@ are more complicated integer/float
2921 conversions. We have to store temporaries in memory to move
2922 between the integer and the floating point register sets.
2925 coerceIntCode :: PrimRep -> StixTree -> UniqSM Register
2926 coerceFltCode :: StixTree -> UniqSM Register
2928 coerceInt2FP :: PrimRep -> StixTree -> UniqSM Register
2929 coerceFP2Int :: StixTree -> UniqSM Register
2932 = getRegister x `thenUs` \ register ->
2935 Fixed _ reg code -> Fixed pk reg code
2936 Any _ code -> Any pk code
2941 = getRegister x `thenUs` \ register ->
2944 Fixed _ reg code -> Fixed DoubleRep reg code
2945 Any _ code -> Any DoubleRep code
2950 #if alpha_TARGET_ARCH
2953 = getRegister x `thenUs` \ register ->
2954 getNewRegNCG IntRep `thenUs` \ reg ->
2956 code = registerCode register reg
2957 src = registerName register reg
2959 code__2 dst = code . mkSeqInstrs [
2961 LD TF dst (spRel 0),
2964 returnUs (Any DoubleRep code__2)
2968 = getRegister x `thenUs` \ register ->
2969 getNewRegNCG DoubleRep `thenUs` \ tmp ->
2971 code = registerCode register tmp
2972 src = registerName register tmp
2974 code__2 dst = code . mkSeqInstrs [
2976 ST TF tmp (spRel 0),
2979 returnUs (Any IntRep code__2)
2981 #endif {- alpha_TARGET_ARCH -}
2982 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2983 #if i386_TARGET_ARCH
2986 = getRegister x `thenUs` \ register ->
2987 getNewRegNCG IntRep `thenUs` \ reg ->
2989 code = registerCode register reg
2990 src = registerName register reg
2991 opc = case pk of FloatRep -> GITOF ; DoubleRep -> GITOD
2992 code__2 dst = code .
2993 mkSeqInstr (opc src dst)
2995 returnUs (Any pk code__2)
2999 = getRegister x `thenUs` \ register ->
3000 getNewRegNCG DoubleRep `thenUs` \ tmp ->
3002 code = registerCode register tmp
3003 src = registerName register tmp
3004 pk = registerRep register
3006 opc = case pk of FloatRep -> GFTOI ; DoubleRep -> GDTOI
3007 code__2 dst = code .
3008 mkSeqInstr (opc src dst)
3010 returnUs (Any IntRep code__2)
3012 #endif {- i386_TARGET_ARCH -}
3013 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3014 #if sparc_TARGET_ARCH
3017 = getRegister x `thenUs` \ register ->
3018 getNewRegNCG IntRep `thenUs` \ reg ->
3020 code = registerCode register reg
3021 src = registerName register reg
3023 code__2 dst = code . mkSeqInstrs [
3024 ST W src (spRel (-2)),
3025 LD W (spRel (-2)) dst,
3026 FxTOy W (primRepToSize pk) dst dst]
3028 returnUs (Any pk code__2)
3032 = getRegister x `thenUs` \ register ->
3033 getNewRegNCG IntRep `thenUs` \ reg ->
3034 getNewRegNCG FloatRep `thenUs` \ tmp ->
3036 code = registerCode register reg
3037 src = registerName register reg
3038 pk = registerRep register
3040 code__2 dst = code . mkSeqInstrs [
3041 FxTOy (primRepToSize pk) W src tmp,
3042 ST W tmp (spRel (-2)),
3043 LD W (spRel (-2)) dst]
3045 returnUs (Any IntRep code__2)
3047 #endif {- sparc_TARGET_ARCH -}
3050 %************************************************************************
3052 \subsubsection{Coercing integer to @Char@...}
3054 %************************************************************************
3056 Integer to character conversion. Where applicable, we try to do this
3057 in one step if the original object is in memory.
3060 chrCode :: StixTree -> UniqSM Register
3062 #if alpha_TARGET_ARCH
3065 = getRegister x `thenUs` \ register ->
3066 getNewRegNCG IntRep `thenUs` \ reg ->
3068 code = registerCode register reg
3069 src = registerName register reg
3070 code__2 dst = code . mkSeqInstr (ZAPNOT src (RIImm (ImmInt 1)) dst)
3072 returnUs (Any IntRep code__2)
3074 #endif {- alpha_TARGET_ARCH -}
3075 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3076 #if i386_TARGET_ARCH
3079 = getRegister x `thenUs` \ register ->
3080 --getNewRegNCG IntRep `thenUs` \ reg ->
3083 code = registerCode register dst
3084 src = registerName register dst
3086 if isFixed register && src /= dst
3087 then mkSeqInstrs [MOV L (OpReg src) (OpReg dst),
3088 AND L (OpImm (ImmInt 255)) (OpReg dst)]
3089 else mkSeqInstr (AND L (OpImm (ImmInt 255)) (OpReg src))
3091 returnUs (Any IntRep code__2)
3093 #endif {- i386_TARGET_ARCH -}
3094 -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3095 #if sparc_TARGET_ARCH
3097 chrCode (StInd pk mem)
3098 = getAmode mem `thenUs` \ amode ->
3100 code = amodeCode amode
3101 src = amodeAddr amode
3102 src_off = addrOffset src 3
3103 src__2 = case src_off of Just x -> x
3104 code__2 dst = if maybeToBool src_off then
3105 code . mkSeqInstr (LD BU src__2 dst)
3107 code . mkSeqInstrs [
3108 LD (primRepToSize pk) src dst,
3109 AND False dst (RIImm (ImmInt 255)) dst]
3111 returnUs (Any pk code__2)
3114 = getRegister x `thenUs` \ register ->
3115 getNewRegNCG IntRep `thenUs` \ reg ->
3117 code = registerCode register reg
3118 src = registerName register reg
3119 code__2 dst = code . mkSeqInstr (AND False src (RIImm (ImmInt 255)) dst)
3121 returnUs (Any IntRep code__2)
3123 #endif {- sparc_TARGET_ARCH -}