--- /dev/null
+
+-- | Expand out synthetic instructions into single machine instrs.
+module SPARC.CodeGen.Expand (
+ expandTop
+)
+
+where
+
+import SPARC.Instr
+import SPARC.Imm
+import SPARC.AddrMode
+import SPARC.Regs
+import SPARC.Ppr ()
+import Instruction
+import Reg
+import Size
+import Cmm
+
+
+import Outputable
+import OrdList
+
+-- | Expand out synthetic instructions in this top level thing
+expandTop :: NatCmmTop Instr -> NatCmmTop Instr
+expandTop top@(CmmData{})
+ = top
+
+expandTop (CmmProc info lbl params (ListGraph blocks))
+ = CmmProc info lbl params (ListGraph $ map expandBlock blocks)
+
+
+-- | Expand out synthetic instructions in this block
+expandBlock :: NatBasicBlock Instr -> NatBasicBlock Instr
+
+expandBlock (BasicBlock label instrs)
+ = let instrs_ol = expandBlockInstrs instrs
+ instrs' = fromOL instrs_ol
+ in BasicBlock label instrs'
+
+
+-- | Expand out some instructions
+expandBlockInstrs :: [Instr] -> OrdList Instr
+expandBlockInstrs [] = nilOL
+
+expandBlockInstrs (ii:is)
+ = let ii_doubleRegs = remapRegPair ii
+ is_misaligned = expandMisalignedDoubles ii_doubleRegs
+
+ in is_misaligned `appOL` expandBlockInstrs is
+
+
+
+-- | In the SPARC instruction set the FP register pairs that are used
+-- to hold 64 bit floats are refered to by just the first reg
+-- of the pair. Remap our internal reg pairs to the appropriate reg.
+--
+-- For example:
+-- ldd [%l1], (%f0 | %f1)
+--
+-- gets mapped to
+-- ldd [$l1], %f0
+--
+remapRegPair :: Instr -> Instr
+remapRegPair instr
+ = let patchF reg
+ = case reg of
+ RegReal (RealRegSingle _)
+ -> reg
+
+ RegReal (RealRegPair r1 r2)
+
+ -- sanity checking
+ | r1 >= 32
+ , r1 <= 63
+ , r1 `mod` 2 == 0
+ , r2 == r1 + 1
+ -> RegReal (RealRegSingle r1)
+
+ | otherwise
+ -> pprPanic "SPARC.CodeGen.Expand: not remapping dodgy looking reg pair " (ppr reg)
+
+ RegVirtual _
+ -> pprPanic "SPARC.CodeGen.Expand: not remapping virtual reg " (ppr reg)
+
+ in patchRegsOfInstr instr patchF
+
+
+
+
+-- Expand out 64 bit load/stores into individual instructions to handle
+-- possible double alignment problems.
+--
+-- TODO: It'd be better to use a scratch reg instead of the add/sub thing.
+-- We might be able to do this faster if we use the UA2007 instr set
+-- instead of restricting ourselves to SPARC V9.
+--
+expandMisalignedDoubles :: Instr -> OrdList Instr
+expandMisalignedDoubles instr
+
+ -- Translate to:
+ -- add g1,g2,g1
+ -- ld [g1],%fn
+ -- ld [g1+4],%f(n+1)
+ -- sub g1,g2,g1 -- to restore g1
+ | LD FF64 (AddrRegReg r1 r2) fReg <- instr
+ = toOL [ ADD False False r1 (RIReg r2) r1
+ , LD FF32 (AddrRegReg r1 g0) fReg
+ , LD FF32 (AddrRegImm r1 (ImmInt 4)) (fRegHi fReg)
+ , SUB False False r1 (RIReg r2) r1 ]
+
+ -- Translate to
+ -- ld [addr],%fn
+ -- ld [addr+4],%f(n+1)
+ | LD FF64 addr fReg <- instr
+ = let Just addr' = addrOffset addr 4
+ in toOL [ LD FF32 addr fReg
+ , LD FF32 addr' (fRegHi fReg) ]
+
+ -- Translate to:
+ -- add g1,g2,g1
+ -- st %fn,[g1]
+ -- st %f(n+1),[g1+4]
+ -- sub g1,g2,g1 -- to restore g1
+ | ST FF64 fReg (AddrRegReg r1 r2) <- instr
+ = toOL [ ADD False False r1 (RIReg r2) r1
+ , ST FF32 fReg (AddrRegReg r1 g0)
+ , ST FF32 (fRegHi fReg) (AddrRegImm r1 (ImmInt 4))
+ , SUB False False r1 (RIReg r2) r1 ]
+
+ -- Translate to
+ -- ld [addr],%fn
+ -- ld [addr+4],%f(n+1)
+ | ST FF64 fReg addr <- instr
+ = let Just addr' = addrOffset addr 4
+ in toOL [ ST FF32 fReg addr
+ , ST FF32 (fRegHi fReg) addr' ]
+
+ -- some other instr
+ | otherwise
+ = unitOL instr
+
+
+
+-- | The the high partner for this float reg.
+fRegHi :: Reg -> Reg
+fRegHi (RegReal (RealRegSingle r1))
+ | r1 >= 32
+ , r1 <= 63
+ , r1 `mod` 2 == 0
+ = (RegReal $ RealRegSingle (r1 + 1))
+
+-- Can't take high partner for non-low reg.
+fRegHi reg
+ = pprPanic "SPARC.CodeGen.Expand: can't take fRegHi from " (ppr reg)
+
+
+
+
+
+
+