X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FnativeGen%2FMachMisc.lhs;h=6f5337339de89f7fd7915febdc8f87924174251e;hb=298e7a785bd89b51e0e8c34980cd4ceac7d3dce0;hp=3c593e0567c51d6522c88fb668a2ef84ab1e61e5;hpb=25a35596e753b471ccc4811f9e91eec82fb55900;p=ghc-hetmet.git diff --git a/ghc/compiler/nativeGen/MachMisc.lhs b/ghc/compiler/nativeGen/MachMisc.lhs index 3c593e0..6f53373 100644 --- a/ghc/compiler/nativeGen/MachMisc.lhs +++ b/ghc/compiler/nativeGen/MachMisc.lhs @@ -24,8 +24,9 @@ module MachMisc ( Instr(..), IF_ARCH_i386(Operand(..) COMMA,) Cond(..), - Size(..) - + Size(..), + IF_ARCH_i386(i386_insert_ffrees COMMA,) + #if alpha_TARGET_ARCH , RI(..) #endif @@ -41,7 +42,7 @@ module MachMisc ( import AbsCSyn ( MagicId(..) ) import AbsCUtils ( magicIdPrimRep ) -import CLabel ( CLabel ) +import CLabel ( CLabel, isAsmTemp ) import Const ( mkMachInt, Literal(..) ) import MachRegs ( stgReg, callerSaves, RegLoc(..), Imm(..), Reg(..), @@ -76,7 +77,7 @@ fmtAsmLbl s -} '$' : s ,{-otherwise-} - s + '.':'L':s ) --------------------------- @@ -319,7 +320,7 @@ primRepToSize CodePtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( primRepToSize DataPtrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,))) primRepToSize RetRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,))) primRepToSize CostCentreRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,))) -primRepToSize CharRep = IF_ARCH_alpha( BU, IF_ARCH_i386( L, IF_ARCH_sparc( BU,))) +primRepToSize CharRep = IF_ARCH_alpha( BU, IF_ARCH_i386( B, IF_ARCH_sparc( BU,))) primRepToSize IntRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,))) primRepToSize WordRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,))) primRepToSize AddrRep = IF_ARCH_alpha( Q, IF_ARCH_i386( L, IF_ARCH_sparc( W ,))) @@ -435,6 +436,40 @@ data RI #endif {- alpha_TARGET_ARCH -} \end{code} +Intel, in their infinite wisdom, selected a stack model for floating +point registers on x86. That might have made sense back in 1979 -- +nowadays we can see it for the nonsense it really is. A stack model +fits poorly with the existing nativeGen infrastructure, which assumes +flat integer and FP register sets. Prior to this commit, nativeGen +could not generate correct x86 FP code -- to do so would have meant +somehow working the register-stack paradigm into the register +allocator and spiller, which sounds very difficult. + +We have decided to cheat, and go for a simple fix which requires no +infrastructure modifications, at the expense of generating ropey but +correct FP code. All notions of the x86 FP stack and its insns have +been removed. Instead, we pretend (to the instruction selector and +register allocator) that x86 has six floating point registers, %fake0 +.. %fake5, which can be used in the usual flat manner. We further +claim that x86 has floating point instructions very similar to SPARC +and Alpha, that is, a simple 3-operand register-register arrangement. +Code generation and register allocation proceed on this basis. + +When we come to print out the final assembly, our convenient fiction +is converted to dismal reality. Each fake instruction is +independently converted to a series of real x86 instructions. +%fake0 .. %fake5 are mapped to %st(0) .. %st(5). To do reg-reg +arithmetic operations, the two operands are pushed onto the top of the +FP stack, the operation done, and the result copied back into the +relevant register. There are only six %fake registers because 2 are +needed for the translation, and x86 has 8 in total. + +The translation is inefficient but is simple and it works. A cleverer +translation would handle a sequence of insns, simulating the FP stack +contents, would not impose a fixed mapping from %fake to %st regs, and +hopefully could avoid most of the redundant reg-reg moves of the +current translation. + \begin{code} #if i386_TARGET_ARCH @@ -443,8 +478,8 @@ data RI -- Moves. | MOV Size Operand Operand - | MOVZX Size Operand Operand -- size is the size of operand 2 - | MOVSX Size Operand Operand -- size is the size of operand 2 + | MOVZxL Size Operand Operand -- size is the size of operand 1 + | MOVSxL Size Operand Operand -- size is the size of operand 1 -- Load effective address (also a very useful three-operand add instruction :-) @@ -468,57 +503,48 @@ data RI | XOR Size Operand Operand | NOT Size Operand | NEGI Size Operand -- NEG instruction (name clash with Cond) - | SHL Size Operand Operand -- 1st operand must be an Imm or CL - | SAR Size Operand Operand -- 1st operand must be an Imm or CL - | SHR Size Operand Operand -- 1st operand must be an Imm or CL + | SHL Size Imm Operand -- Only immediate shifts allowed + | SAR Size Imm Operand -- Only immediate shifts allowed + | SHR Size Imm Operand -- Only immediate shifts allowed + | BT Size Imm Operand | NOP -- Float Arithmetic. -- ToDo for 386 --- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single instructions +-- Note that we cheat by treating G{ABS,MOV,NEG} of doubles as single instructions -- right up until we spit them out. - | SAHF -- stores ah into flags - | FABS - | FADD Size Operand -- src - | FADDP - | FIADD Size MachRegsAddr -- src - | FCHS - | FCOM Size Operand -- src - | FCOS - | FDIV Size Operand -- src - | FDIVP - | FIDIV Size MachRegsAddr -- src - | FDIVR Size Operand -- src - | FDIVRP - | FIDIVR Size MachRegsAddr -- src - | FICOM Size MachRegsAddr -- src - | FILD Size MachRegsAddr Reg -- src, dst - | FIST Size MachRegsAddr -- dst - | FLD Size Operand -- src - | FLD1 - | FLDZ - | FMUL Size Operand -- src - | FMULP - | FIMUL Size MachRegsAddr -- src - | FRNDINT - | FSIN - | FSQRT - | FST Size Operand -- dst - | FSTP Size Operand -- dst - | FSUB Size Operand -- src - | FSUBP - | FISUB Size MachRegsAddr -- src - | FSUBR Size Operand -- src - | FSUBRP - | FISUBR Size MachRegsAddr -- src - | FTST - | FCOMP Size Operand -- src - | FUCOMPP - | FXCH - | FNSTSW - | FNOP + -- all the 3-operand fake fp insns are src1 src2 dst + -- and furthermore are constrained to be fp regs only. + -- IMPORTANT: keep is_G_insn up to date with any changes here + | GMOV Reg Reg -- src(fpreg), dst(fpreg) + | GLD Size MachRegsAddr Reg -- src, dst(fpreg) + | GST Size Reg MachRegsAddr -- src(fpreg), dst + + | GFTOD Reg Reg -- src(fpreg), dst(fpreg) + | GFTOI Reg Reg -- src(fpreg), dst(intreg) + + | GDTOF Reg Reg -- src(fpreg), dst(fpreg) + | GDTOI Reg Reg -- src(fpreg), dst(intreg) + + | GITOF Reg Reg -- src(intreg), dst(fpreg) + | GITOD Reg Reg -- src(intreg), dst(fpreg) + | GADD Size Reg Reg Reg -- src1, src2, dst + | GDIV Size Reg Reg Reg -- src1, src2, dst + | GSUB Size Reg Reg Reg -- src1, src2, dst + | GMUL Size Reg Reg Reg -- src1, src2, dst + + | GCMP Size Reg Reg -- src1, src2 + + | GABS Size Reg Reg -- src, dst + | GNEG Size Reg Reg -- src, dst + | GSQRT Size Reg Reg -- src, dst + | GSIN Size Reg Reg -- src, dst + | GCOS Size Reg Reg -- src, dst + | GTAN Size Reg Reg -- src, dst + + | GFREE -- do ffree on all x86 regs; an ugly hack -- Comparison | TEST Size Operand Operand @@ -547,6 +573,39 @@ data Operand | OpImm Imm -- immediate value | OpAddr MachRegsAddr -- memory reference + +i386_insert_ffrees :: [Instr] -> [Instr] +i386_insert_ffrees insns + | any is_G_instr insns + = concatMap ffree_before_nonlocal_transfers insns + | otherwise + = insns + +ffree_before_nonlocal_transfers insn + = case insn of + CALL _ -> [GFREE, insn] + JMP (OpImm (ImmCLbl clbl)) | isAsmTemp clbl -> [insn] + JMP _ -> [GFREE, insn] + other -> [insn] + + +-- if you ever add a new FP insn to the fake x86 FP insn set, +-- you must update this too +is_G_instr :: Instr -> Bool +is_G_instr instr + = case instr of + GMOV _ _ -> True; GLD _ _ _ -> True; GST _ _ _ -> True; + GFTOD _ _ -> True; GFTOI _ _ -> True; + GDTOF _ _ -> True; GDTOI _ _ -> True; + GITOF _ _ -> True; GITOD _ _ -> True; + GADD _ _ _ _ -> True; GDIV _ _ _ _ -> True + GSUB _ _ _ _ -> True; GMUL _ _ _ _ -> True + GCMP _ _ _ -> True; GABS _ _ _ -> True + GNEG _ _ _ -> True; GSQRT _ _ _ -> True + GSIN _ _ _ -> True; GCOS _ _ _ -> True; GTAN _ _ _ -> True; + GFREE -> panic "is_G_instr: GFREE (!)" + other -> False + #endif {- i386_TARGET_ARCH -} \end{code}