IntAddOp -> add_code L x y
IntSubOp -> sub_code L x y
- IntQuotOp -> quot_code L x y True{-division-}
- IntRemOp -> quot_code L x y False{-remainder-}
+ IntQuotOp -> trivialCode (IQUOT L) Nothing x y
+ IntRemOp -> trivialCode (IREM L) Nothing x y
IntMulOp -> let op = IMUL L in trivialCode op (Just op) x y
FloatAddOp -> trivialFCode FloatRep GADD x y
sub_code sz x y = trivialCode (SUB sz) Nothing x y
- --------------------
- quot_code
- :: Size
- -> StixTree -> StixTree
- -> Bool -- True => division, False => remainder operation
- -> NatM Register
-
- -- x must go into eax, edx must be a sign-extension of eax, and y
- -- should go in some other register (or memory), so that we get
- -- edx:eax / reg -> eax (remainder in edx). Currently we choose
- -- to put y on the C stack, since that avoids tying up yet another
- -- precious register.
-
- quot_code sz x y is_division
- = getRegister x `thenNat` \ register1 ->
- getRegister y `thenNat` \ register2 ->
- getNewRegNCG IntRep `thenNat` \ tmp ->
- getDeltaNat `thenNat` \ delta ->
- let
- code1 = registerCode register1 tmp
- src1 = registerName register1 tmp
- code2 = registerCode register2 tmp
- src2 = registerName register2 tmp
- code__2 = code2 `snocOL` -- src2 := y
- PUSH L (OpReg src2) `snocOL` -- -4(%esp) := y
- DELTA (delta-4) `appOL`
- code1 `snocOL` -- src1 := x
- MOV L (OpReg src1) (OpReg eax) `snocOL` -- eax := x
- CLTD `snocOL`
- IDIV sz (OpAddr (spRel 0)) `snocOL`
- ADD L (OpImm (ImmInt 4)) (OpReg esp) `snocOL`
- DELTA delta
- in
- returnNat (Fixed IntRep (if is_division then eax else edx) code__2)
- -----------------------
getRegister (StInd pk mem)
= getAmode mem `thenNat` \ amode ->
chosen to bless us with (let's not be churlish, after all).
Hence GLDZ and GLD1. Bwahahahahahahaha!
+LATER (10 Nov 2000): idiv gives problems with the register spiller,
+because the spiller is simpleminded and because idiv has fixed uses of
+%eax and %edx. Rather than make the spiller cleverer, we do away with
+idiv, and instead have iquot and irem fake (integer) insns, which have
+no operand register constraints -- ie, they behave like add, sub, mul.
+The printer-outer transforms them to a sequence of real insns which does
+the Right Thing (tm). As with the FP stuff, this gives ropey code,
+but we don't care, since it doesn't get used much. We hope.
+
\begin{code}
#if i386_TARGET_ARCH
| ADD Size Operand Operand
| SUB Size Operand Operand
+ | IMUL Size Operand Operand
--- Multiplication (signed and unsigned), Division (signed and unsigned),
--- result in %eax, %edx.
+-- Quotient and remainder. SEE comment above -- these are not
+-- real x86 insns; instead they are expanded when printed
+-- into a sequence of real insns.
- | IMUL Size Operand Operand
- | IDIV Size Operand
+ | IQUOT Size Operand Operand
+ | IREM Size Operand Operand
-- Simple bit-twiddling.
= pprSizeOpOp SLIT("add") size src dst
pprInstr (SUB size src dst) = pprSizeOpOp SLIT("sub") size src dst
pprInstr (IMUL size op1 op2) = pprSizeOpOp SLIT("imul") size op1 op2
-pprInstr (IDIV size op) = pprSizeOp SLIT("idiv") size op
pprInstr (AND size src dst) = pprSizeOpOp SLIT("and") size src dst
pprInstr (OR size src dst) = pprSizeOpOp SLIT("or") size src dst
pprInstr (JMP dsts op) = (<>) (ptext SLIT("\tjmp *")) (pprOperand L op)
pprInstr (CALL imm) = (<>) (ptext SLIT("\tcall ")) (pprImm imm)
+pprInstr (IQUOT sz src dst) = pprInstr_quotRem True sz src dst
+pprInstr (IREM sz src dst) = pprInstr_quotRem False sz src dst
-- Simulating a flat register set on the x86 FP stack is tricky.
-- you have to free %st(7) before pushing anything on the FP reg stack
ptext SLIT("\tffree %st(4) ;ffree %st(5) ;ffree %st(6) ;ffree %st(7)")
]
+
+pprInstr_quotRem isQuot sz src dst
+ | case sz of L -> False; _ -> True
+ = panic "pprInstr_quotRem: dunno how to do non-32bit operands"
+ | otherwise
+ = vcat [
+ (text "\t# BEGIN " <> fakeInsn),
+ (text "\tpushl $0; pushl %eax; pushl %edx; pushl " <> pprOperand sz src),
+ (text "\tmovl " <> pprOperand sz dst <> text ",%eax; xorl %edx,%edx; cltd"),
+ (text "\tdivl 0(%esp); movl " <> text resReg <> text ",12(%esp)"),
+ (text "\tpopl %edx; popl %edx; popl %eax; popl " <> pprOperand sz dst),
+ (text "\t# END " <> fakeInsn)
+ ]
+ where
+ resReg = if isQuot then "%eax" else "%edx"
+ opStr = if isQuot then "IQUOT" else "IREM"
+ fakeInsn = text opStr <+> pprOperand sz src <> char ',' <+> pprOperand sz dst
+
--------------------------
-- coerce %st(0) to the specified size
ADD sz src dst -> usageRM src dst
SUB sz src dst -> usageRM src dst
IMUL sz src dst -> usageRM src dst
- IDIV sz src -> mkRU (eax:edx:use_R src) [eax,edx]
+ IQUOT sz src dst -> usageRM src dst
+ IREM sz src dst -> usageRM src dst
AND sz src dst -> usageRM src dst
OR sz src dst -> usageRM src dst
XOR sz src dst -> usageRM src dst
mkRU src dst = RU (regSetFromList (filter interesting src))
(regSetFromList (filter interesting dst))
--- Allow the spiller to de\cide whether or not it can use
--- %edx as a spill temporary.
-hasFixedEDX instr
- = case instr of
- IDIV _ _ -> True
- CLTD -> True
- other -> False
-
#endif {- i386_TARGET_ARCH -}
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#if sparc_TARGET_ARCH
#endif
#if i386_TARGET_ARCH
-- We can use %fake4 and %fake5 safely for float temps.
- -- Int regs are more troublesome. Only %ecx is definitely
- -- available. If there are no division insns, we can use %edx
- -- too. At a pinch, we also could bag %eax if there are no
- -- divisions and no ccalls, but so far we've never encountered
+ -- Int regs are more troublesome. Only %ecx and %edx are
+ -- definitely. At a pinch, we also could bag %eax if there
+ -- are no ccalls, but so far we've never encountered
-- a situation where three integer temporaries are necessary.
--
-- Because registers are in short supply on x86, we give the
= let f1 = fake5
f2 = fake4
intregs_avail
- = ecx : if any hasFixedEDX instrs then [] else [edx]
+ = [ecx, edx]
possibilities
= case intregs_avail of
[i1] -> [ [], [i1], [f1], [i1,f1], [f1,f2],
ADD sz src dst -> patch2 (ADD sz) src dst
SUB sz src dst -> patch2 (SUB sz) src dst
IMUL sz src dst -> patch2 (IMUL sz) src dst
- IDIV sz src -> patch1 (IDIV sz) src
+ IQUOT sz src dst -> patch2 (IQUOT sz) src dst
+ IREM sz src dst -> patch2 (IREM sz) src dst
AND sz src dst -> patch2 (AND sz) src dst
OR sz src dst -> patch2 (OR sz) src dst
XOR sz src dst -> patch2 (XOR sz) src dst