-- | Expand out synthetic instructions into single machine instrs. module SPARC.CodeGen.Expand ( expandTop ) where import GhcPrelude import SPARC.Instr import SPARC.Imm import SPARC.AddrMode import SPARC.Regs import SPARC.Ppr () import Instruction import Reg import Format import Cmm import Outputable import OrdList -- | Expand out synthetic instructions in this top level thing expandTop :: NatCmmDecl CmmStatics Instr -> NatCmmDecl CmmStatics Instr expandTop top@(CmmData{}) = top expandTop (CmmProc info lbl live (ListGraph blocks)) = CmmProc info lbl live (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 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)