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
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)
expandBlock :: NatBasicBlock Instr -> NatBasicBlock Instr
expandBlock (BasicBlock label instrs)
 = let  instrs_ol       = expandBlockInstrs instrs
        instrs'         = fromOL instrs_ol
   in   BasicBlock label instrs'
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
remapRegPair :: Instr -> Instr
remapRegPair instr
 = let  patchF reg
         = case reg of
                RegReal (RealRegSingle _)
                        -> reg
                RegReal (RealRegPair r1 r2)
                        
                        | 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
expandMisalignedDoubles :: Instr -> OrdList Instr
expandMisalignedDoubles instr
        
        
        
        
        
        | 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 ]
        
        
        
        | LD FF64 addr fReg                     <- instr
        = let   Just addr'      = addrOffset addr 4
          in    toOL    [ LD  FF32  addr        fReg
                        , LD  FF32  addr'       (fRegHi fReg) ]
        
        
        
        
        
        | 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 ]
        
        
        
        | ST FF64 fReg addr                     <- instr
        = let   Just addr'      = addrOffset addr 4
          in    toOL    [ ST  FF32  fReg           addr
                        , ST  FF32  (fRegHi fReg)  addr'         ]
        
        | otherwise
        = unitOL instr
fRegHi :: Reg -> Reg
fRegHi (RegReal (RealRegSingle r1))
        | r1            >= 32
        , r1            <= 63
        , r1 `mod` 2 == 0
        = (RegReal $ RealRegSingle (r1 + 1))
fRegHi reg
        = pprPanic "SPARC.CodeGen.Expand: can't take fRegHi from " (ppr reg)