ghc-8.10.1: nativeGen/SPARC/CodeGen/Expand.hs
-- | 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 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)