module GHC.CmmToAsm.PPC.Ppr
( pprNatCmmDecl
, pprInstr
)
where
import GHC.Prelude
import GHC.CmmToAsm.PPC.Regs
import GHC.CmmToAsm.PPC.Instr
import GHC.CmmToAsm.PPC.Cond
import GHC.CmmToAsm.Ppr
import GHC.CmmToAsm.Format
import GHC.Platform.Reg
import GHC.Platform.Reg.Class
import GHC.CmmToAsm.Reg.Target
import GHC.CmmToAsm.Config
import GHC.CmmToAsm.Types
import GHC.CmmToAsm.Utils
import GHC.Cmm hiding (topInfoTable)
import GHC.Cmm.Dataflow.Collections
import GHC.Cmm.Dataflow.Label
import GHC.Cmm.BlockId
import GHC.Cmm.CLabel
import GHC.Cmm.Ppr.Expr ()
import GHC.Types.Unique ( pprUniqueAlways, getUnique )
import GHC.Platform
import GHC.Data.FastString
import GHC.Utils.Outputable
import GHC.Utils.Panic
import Data.Word
import Data.Int
import Data.Bits
pprNatCmmDecl :: NCGConfig -> NatCmmDecl RawCmmStatics Instr -> SDoc
pprNatCmmDecl config (CmmData section dats) =
pprSectionAlign config section
$$ pprDatas (ncgPlatform config) dats
pprNatCmmDecl config proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
let platform = ncgPlatform config in
case topInfoTable proc of
Nothing ->
pprSectionAlign config (Section Text lbl) $$
(case platformArch platform of
ArchPPC_64 ELF_V1 -> pprFunctionDescriptor platform lbl
ArchPPC_64 ELF_V2 -> pprFunctionPrologue platform lbl
_ -> pprLabel platform lbl) $$
vcat (map (pprBasicBlock config top_info) blocks) $$
ppWhen (ncgDwarfEnabled config) (pdoc platform (mkAsmTempEndLabel lbl)
<> char ':' $$
pprProcEndLabel platform lbl) $$
pprSizeDecl platform lbl
Just (CmmStaticsRaw info_lbl _) ->
pprSectionAlign config (Section Text info_lbl) $$
(if platformHasSubsectionsViaSymbols platform
then pdoc platform (mkDeadStripPreventer info_lbl) <> char ':'
else empty) $$
vcat (map (pprBasicBlock config top_info) blocks) $$
(if platformHasSubsectionsViaSymbols platform
then
text "\t.long "
<+> pdoc platform info_lbl
<+> char '-'
<+> pdoc platform (mkDeadStripPreventer info_lbl)
else empty) $$
pprSizeDecl platform info_lbl
pprSizeDecl :: Platform -> CLabel -> SDoc
pprSizeDecl platform lbl
= if osElfTarget (platformOS platform)
then text "\t.size" <+> prettyLbl <> text ", .-" <> codeLbl
else empty
where
prettyLbl = pdoc platform lbl
codeLbl
| platformArch platform == ArchPPC_64 ELF_V1 = char '.' <> prettyLbl
| otherwise = prettyLbl
pprFunctionDescriptor :: Platform -> CLabel -> SDoc
pprFunctionDescriptor platform lab = pprGloblDecl platform lab
$$ text "\t.section \".opd\", \"aw\""
$$ text "\t.align 3"
$$ pdoc platform lab <> char ':'
$$ text "\t.quad ."
<> pdoc platform lab
<> text ",.TOC.@tocbase,0"
$$ text "\t.previous"
$$ text "\t.type"
<+> pdoc platform lab
<> text ", @function"
$$ char '.' <> pdoc platform lab <> char ':'
pprFunctionPrologue :: Platform -> CLabel ->SDoc
pprFunctionPrologue platform lab = pprGloblDecl platform lab
$$ text ".type "
<> pdoc platform lab
<> text ", @function"
$$ pdoc platform lab <> char ':'
$$ text "0:\taddis\t" <> pprReg toc
<> text ",12,.TOC.-0b@ha"
$$ text "\taddi\t" <> pprReg toc
<> char ',' <> pprReg toc <> text ",.TOC.-0b@l"
$$ text "\t.localentry\t" <> pdoc platform lab
<> text ",.-" <> pdoc platform lab
pprProcEndLabel :: Platform -> CLabel
-> SDoc
pprProcEndLabel platform lbl =
pdoc platform (mkAsmTempProcEndLabel lbl) <> char ':'
pprBasicBlock :: NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr
-> SDoc
pprBasicBlock config info_env (BasicBlock blockid instrs)
= maybe_infotable $$
pprLabel platform asmLbl $$
vcat (map (pprInstr platform) instrs) $$
ppWhen (ncgDwarfEnabled config) (
pdoc platform (mkAsmTempEndLabel asmLbl) <> char ':'
<> pprProcEndLabel platform asmLbl
)
where
asmLbl = blockLbl blockid
platform = ncgPlatform config
maybe_infotable = case mapLookup blockid info_env of
Nothing -> empty
Just (CmmStaticsRaw info_lbl info) ->
pprAlignForSection platform Text $$
vcat (map (pprData platform) info) $$
pprLabel platform info_lbl
pprDatas :: Platform -> RawCmmStatics -> SDoc
pprDatas platform (CmmStaticsRaw alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])
| lbl == mkIndStaticInfoLabel
, let labelInd (CmmLabelOff l _) = Just l
labelInd (CmmLabel l) = Just l
labelInd _ = Nothing
, Just ind' <- labelInd ind
, alias `mayRedirectTo` ind'
= pprGloblDecl platform alias
$$ text ".equiv" <+> pdoc platform alias <> comma <> pdoc platform (CmmLabel ind')
pprDatas platform (CmmStaticsRaw lbl dats) = vcat (pprLabel platform lbl : map (pprData platform) dats)
pprData :: Platform -> CmmStatic -> SDoc
pprData platform d = case d of
CmmString str -> pprString str
CmmFileEmbed path -> pprFileEmbed path
CmmUninitialised bytes -> text ".space " <> int bytes
CmmStaticLit lit -> pprDataItem platform lit
pprGloblDecl :: Platform -> CLabel -> SDoc
pprGloblDecl platform lbl
| not (externallyVisibleCLabel lbl) = empty
| otherwise = text ".globl " <> pdoc platform lbl
pprTypeAndSizeDecl :: Platform -> CLabel -> SDoc
pprTypeAndSizeDecl platform lbl
= if platformOS platform == OSLinux && externallyVisibleCLabel lbl
then text ".type " <>
pdoc platform lbl <> text ", @object"
else empty
pprLabel :: Platform -> CLabel -> SDoc
pprLabel platform lbl =
pprGloblDecl platform lbl
$$ pprTypeAndSizeDecl platform lbl
$$ (pdoc platform lbl <> char ':')
pprReg :: Reg -> SDoc
pprReg r
= case r of
RegReal (RealRegSingle i) -> ppr_reg_no i
RegReal (RealRegPair{}) -> panic "PPC.pprReg: no reg pairs on this arch"
RegVirtual (VirtualRegI u) -> text "%vI_" <> pprUniqueAlways u
RegVirtual (VirtualRegHi u) -> text "%vHi_" <> pprUniqueAlways u
RegVirtual (VirtualRegF u) -> text "%vF_" <> pprUniqueAlways u
RegVirtual (VirtualRegD u) -> text "%vD_" <> pprUniqueAlways u
where
ppr_reg_no :: Int -> SDoc
ppr_reg_no i
| i <= 31 = int i
| i <= 63 = int (i32)
| otherwise = text "very naughty powerpc register"
pprFormat :: Format -> SDoc
pprFormat x
= ptext (case x of
II8 -> sLit "b"
II16 -> sLit "h"
II32 -> sLit "w"
II64 -> sLit "d"
FF32 -> sLit "fs"
FF64 -> sLit "fd")
pprCond :: Cond -> SDoc
pprCond c
= ptext (case c of {
ALWAYS -> sLit "";
EQQ -> sLit "eq"; NE -> sLit "ne";
LTT -> sLit "lt"; GE -> sLit "ge";
GTT -> sLit "gt"; LE -> sLit "le";
LU -> sLit "lt"; GEU -> sLit "ge";
GU -> sLit "gt"; LEU -> sLit "le"; })
pprImm :: Platform -> Imm -> SDoc
pprImm platform = \case
ImmInt i -> int i
ImmInteger i -> integer i
ImmCLbl l -> pdoc platform l
ImmIndex l i -> pdoc platform l <> char '+' <> int i
ImmLit s -> s
ImmFloat f -> float $ fromRational f
ImmDouble d -> double $ fromRational d
ImmConstantSum a b -> pprImm platform a <> char '+' <> pprImm platform b
ImmConstantDiff a b -> pprImm platform a <> char '-' <> lparen <> pprImm platform b <> rparen
LO (ImmInt i) -> pprImm platform (LO (ImmInteger (toInteger i)))
LO (ImmInteger i) -> pprImm platform (ImmInteger (toInteger lo16))
where
lo16 = fromInteger (i .&. 0xffff) :: Int16
LO i -> pprImm platform i <> text "@l"
HI i -> pprImm platform i <> text "@h"
HA (ImmInt i) -> pprImm platform (HA (ImmInteger (toInteger i)))
HA (ImmInteger i) -> pprImm platform (ImmInteger ha16)
where
ha16 = if lo16 >= 0x8000 then hi16+1 else hi16
hi16 = (i `shiftR` 16)
lo16 = i .&. 0xffff
HA i -> pprImm platform i <> text "@ha"
HIGHERA i -> pprImm platform i <> text "@highera"
HIGHESTA i -> pprImm platform i <> text "@highesta"
pprAddr :: Platform -> AddrMode -> SDoc
pprAddr platform = \case
AddrRegReg r1 r2 -> pprReg r1 <> char ',' <+> pprReg r2
AddrRegImm r1 (ImmInt i) -> hcat [ int i, char '(', pprReg r1, char ')' ]
AddrRegImm r1 (ImmInteger i) -> hcat [ integer i, char '(', pprReg r1, char ')' ]
AddrRegImm r1 imm -> hcat [ pprImm platform imm, char '(', pprReg r1, char ')' ]
pprSectionAlign :: NCGConfig -> Section -> SDoc
pprSectionAlign config sec@(Section seg _) =
pprSectionHeader config sec $$
pprAlignForSection (ncgPlatform config) seg
pprAlignForSection :: Platform -> SectionType -> SDoc
pprAlignForSection platform seg =
let ppc64 = not $ target32Bit platform
in ptext $ case seg of
Text -> sLit ".align 2"
Data
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
ReadOnlyData
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
RelocatableReadOnlyData
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
UninitialisedData
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
ReadOnlyData16 -> sLit ".align 4"
CString
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
OtherSection _ -> panic "PprMach.pprSectionAlign: unknown section"
pprDataItem :: Platform -> CmmLit -> SDoc
pprDataItem platform lit
= vcat (ppr_item (cmmTypeFormat $ cmmLitType platform lit) lit)
where
imm = litToImm lit
archPPC_64 = not $ target32Bit platform
ppr_item II8 _ = [text "\t.byte\t" <> pprImm platform imm]
ppr_item II16 _ = [text "\t.short\t" <> pprImm platform imm]
ppr_item II32 _ = [text "\t.long\t" <> pprImm platform imm]
ppr_item II64 _
| archPPC_64 = [text "\t.quad\t" <> pprImm platform imm]
ppr_item II64 (CmmInt x _)
| not archPPC_64 =
[text "\t.long\t"
<> int (fromIntegral
(fromIntegral (x `shiftR` 32) :: Word32)),
text "\t.long\t"
<> int (fromIntegral (fromIntegral x :: Word32))]
ppr_item FF32 _ = [text "\t.float\t" <> pprImm platform imm]
ppr_item FF64 _ = [text "\t.double\t" <> pprImm platform imm]
ppr_item _ _
= panic "PPC.Ppr.pprDataItem: no match"
pprInstr :: Platform -> Instr -> SDoc
pprInstr platform instr = case instr of
COMMENT _
-> empty
LOCATION file line col _name
-> text "\t.loc" <+> ppr file <+> ppr line <+> ppr col
DELTA d
-> pprInstr platform (COMMENT (mkFastString ("\tdelta = " ++ show d)))
NEWBLOCK _
-> panic "PprMach.pprInstr: NEWBLOCK"
LDATA _ _
-> panic "PprMach.pprInstr: LDATA"
LD fmt reg addr
-> hcat [
char '\t',
text "l",
ptext (case fmt of
II8 -> sLit "bz"
II16 -> sLit "hz"
II32 -> sLit "wz"
II64 -> sLit "d"
FF32 -> sLit "fs"
FF64 -> sLit "fd"
),
case addr of AddrRegImm _ _ -> empty
AddrRegReg _ _ -> char 'x',
char '\t',
pprReg reg,
text ", ",
pprAddr platform addr
]
LDFAR fmt reg (AddrRegImm source off)
-> vcat
[ pprInstr platform (ADDIS (tmpReg platform) source (HA off))
, pprInstr platform (LD fmt reg (AddrRegImm (tmpReg platform) (LO off)))
]
LDFAR _ _ _
-> panic "PPC.Ppr.pprInstr LDFAR: no match"
LDR fmt reg1 addr
-> hcat [
text "\tl",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC.Ppr.Instr LDR: no match",
text "arx\t",
pprReg reg1,
text ", ",
pprAddr platform addr
]
LA fmt reg addr
-> hcat [
char '\t',
text "l",
ptext (case fmt of
II8 -> sLit "ba"
II16 -> sLit "ha"
II32 -> sLit "wa"
II64 -> sLit "d"
FF32 -> sLit "fs"
FF64 -> sLit "fd"
),
case addr of AddrRegImm _ _ -> empty
AddrRegReg _ _ -> char 'x',
char '\t',
pprReg reg,
text ", ",
pprAddr platform addr
]
ST fmt reg addr
-> hcat [
char '\t',
text "st",
pprFormat fmt,
case addr of AddrRegImm _ _ -> empty
AddrRegReg _ _ -> char 'x',
char '\t',
pprReg reg,
text ", ",
pprAddr platform addr
]
STFAR fmt reg (AddrRegImm source off)
-> vcat [ pprInstr platform (ADDIS (tmpReg platform) source (HA off))
, pprInstr platform (ST fmt reg (AddrRegImm (tmpReg platform) (LO off)))
]
STFAR _ _ _
-> panic "PPC.Ppr.pprInstr STFAR: no match"
STU fmt reg addr
-> hcat [
char '\t',
text "st",
pprFormat fmt,
char 'u',
case addr of AddrRegImm _ _ -> empty
AddrRegReg _ _ -> char 'x',
char '\t',
pprReg reg,
text ", ",
pprAddr platform addr
]
STC fmt reg1 addr
-> hcat [
text "\tst",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC.Ppr.Instr STC: no match",
text "cx.\t",
pprReg reg1,
text ", ",
pprAddr platform addr
]
LIS reg imm
-> hcat [
char '\t',
text "lis",
char '\t',
pprReg reg,
text ", ",
pprImm platform imm
]
LI reg imm
-> hcat [
char '\t',
text "li",
char '\t',
pprReg reg,
text ", ",
pprImm platform imm
]
MR reg1 reg2
| reg1 == reg2 -> empty
| otherwise -> hcat [
char '\t',
case targetClassOfReg platform reg1 of
RcInteger -> text "mr"
_ -> text "fmr",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
CMP fmt reg ri
-> hcat [
char '\t',
op,
char '\t',
pprReg reg,
text ", ",
pprRI platform ri
]
where
op = hcat [
text "cmp",
pprFormat fmt,
case ri of
RIReg _ -> empty
RIImm _ -> char 'i'
]
CMPL fmt reg ri
-> hcat [
char '\t',
op,
char '\t',
pprReg reg,
text ", ",
pprRI platform ri
]
where
op = hcat [
text "cmpl",
pprFormat fmt,
case ri of
RIReg _ -> empty
RIImm _ -> char 'i'
]
BCC cond blockid prediction
-> hcat [
char '\t',
text "b",
pprCond cond,
pprPrediction prediction,
char '\t',
pdoc platform lbl
]
where lbl = mkLocalBlockLabel (getUnique blockid)
pprPrediction p = case p of
Nothing -> empty
Just True -> char '+'
Just False -> char '-'
BCCFAR cond blockid prediction
-> vcat [
hcat [
text "\tb",
pprCond (condNegate cond),
neg_prediction,
text "\t$+8"
],
hcat [
text "\tb\t",
pdoc platform lbl
]
]
where lbl = mkLocalBlockLabel (getUnique blockid)
neg_prediction = case prediction of
Nothing -> empty
Just True -> char '-'
Just False -> char '+'
JMP lbl _
| isForeignLabel lbl -> panic "PPC.Ppr.pprInstr: JMP to ForeignLabel"
| otherwise ->
hcat [
char '\t',
text "b",
char '\t',
pdoc platform lbl
]
MTCTR reg
-> hcat [
char '\t',
text "mtctr",
char '\t',
pprReg reg
]
BCTR _ _ _
-> hcat [
char '\t',
text "bctr"
]
BL lbl _
-> case platformOS platform of
OSAIX ->
hcat [
text "\tbl\t.",
pdoc platform lbl
]
_ ->
hcat [
text "\tbl\t",
pdoc platform lbl
]
BCTRL _
-> hcat [
char '\t',
text "bctrl"
]
ADD reg1 reg2 ri
-> pprLogic platform (sLit "add") reg1 reg2 ri
ADDIS reg1 reg2 imm
-> hcat [
char '\t',
text "addis",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm platform imm
]
ADDO reg1 reg2 reg3
-> pprLogic platform (sLit "addo") reg1 reg2 (RIReg reg3)
ADDC reg1 reg2 reg3
-> pprLogic platform (sLit "addc") reg1 reg2 (RIReg reg3)
ADDE reg1 reg2 reg3
-> pprLogic platform (sLit "adde") reg1 reg2 (RIReg reg3)
ADDZE reg1 reg2
-> pprUnary (sLit "addze") reg1 reg2
SUBF reg1 reg2 reg3
-> pprLogic platform (sLit "subf") reg1 reg2 (RIReg reg3)
SUBFO reg1 reg2 reg3
-> pprLogic platform (sLit "subfo") reg1 reg2 (RIReg reg3)
SUBFC reg1 reg2 ri
-> hcat [
char '\t',
text "subf",
case ri of
RIReg _ -> empty
RIImm _ -> char 'i',
text "c\t",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprRI platform ri
]
SUBFE reg1 reg2 reg3
-> pprLogic platform (sLit "subfe") reg1 reg2 (RIReg reg3)
MULL fmt reg1 reg2 ri
-> pprMul platform fmt reg1 reg2 ri
MULLO fmt reg1 reg2 reg3
-> hcat [
char '\t',
text "mull",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC: illegal format",
text "o\t",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprReg reg3
]
MFOV fmt reg
-> vcat [
hcat [
char '\t',
text "mfxer",
char '\t',
pprReg reg
],
hcat [
char '\t',
text "extr",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC: illegal format",
text "i\t",
pprReg reg,
text ", ",
pprReg reg,
text ", 1, ",
case fmt of
II32 -> text "1"
II64 -> text "33"
_ -> panic "PPC: illegal format"
]
]
MULHU fmt reg1 reg2 reg3
-> hcat [
char '\t',
text "mulh",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC: illegal format",
text "u\t",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprReg reg3
]
DIV fmt sgn reg1 reg2 reg3
-> pprDiv fmt sgn reg1 reg2 reg3
AND reg1 reg2 (RIImm imm)
-> hcat [
char '\t',
text "andi.",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm platform imm
]
AND reg1 reg2 ri
-> pprLogic platform (sLit "and") reg1 reg2 ri
ANDC reg1 reg2 reg3
-> pprLogic platform (sLit "andc") reg1 reg2 (RIReg reg3)
NAND reg1 reg2 reg3
-> pprLogic platform (sLit "nand") reg1 reg2 (RIReg reg3)
OR reg1 reg2 ri
-> pprLogic platform (sLit "or") reg1 reg2 ri
XOR reg1 reg2 ri
-> pprLogic platform (sLit "xor") reg1 reg2 ri
ORIS reg1 reg2 imm
-> hcat [
char '\t',
text "oris",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm platform imm
]
XORIS reg1 reg2 imm
-> hcat [
char '\t',
text "xoris",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm platform imm
]
EXTS fmt reg1 reg2
-> hcat [
char '\t',
text "exts",
pprFormat fmt,
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
CNTLZ fmt reg1 reg2
-> hcat [
char '\t',
text "cntlz",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC: illegal format",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
NEG reg1 reg2
-> pprUnary (sLit "neg") reg1 reg2
NOT reg1 reg2
-> pprUnary (sLit "not") reg1 reg2
SR II32 reg1 reg2 (RIImm (ImmInt i))
| i < 0 || i > 31 -> pprInstr platform (XOR reg1 reg2 (RIReg reg2))
SL II32 reg1 reg2 (RIImm (ImmInt i))
| i < 0 || i > 31 -> pprInstr platform (XOR reg1 reg2 (RIReg reg2))
SRA II32 reg1 reg2 (RIImm (ImmInt i))
| i > 31 -> pprInstr platform (SRA II32 reg1 reg2 (RIImm (ImmInt 31)))
SL fmt reg1 reg2 ri
-> let op = case fmt of
II32 -> "slw"
II64 -> "sld"
_ -> panic "PPC.Ppr.pprInstr: shift illegal size"
in pprLogic platform (sLit op) reg1 reg2 (limitShiftRI fmt ri)
SR fmt reg1 reg2 ri
-> let op = case fmt of
II32 -> "srw"
II64 -> "srd"
_ -> panic "PPC.Ppr.pprInstr: shift illegal size"
in pprLogic platform (sLit op) reg1 reg2 (limitShiftRI fmt ri)
SRA fmt reg1 reg2 ri
-> let op = case fmt of
II32 -> "sraw"
II64 -> "srad"
_ -> panic "PPC.Ppr.pprInstr: shift illegal size"
in pprLogic platform (sLit op) reg1 reg2 (limitShiftRI fmt ri)
RLWINM reg1 reg2 sh mb me
-> hcat [
text "\trlwinm\t",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
int sh,
text ", ",
int mb,
text ", ",
int me
]
CLRLI fmt reg1 reg2 n
-> hcat [
text "\tclrl",
pprFormat fmt,
text "i ",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
int n
]
CLRRI fmt reg1 reg2 n
-> hcat [
text "\tclrr",
pprFormat fmt,
text "i ",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
int n
]
FADD fmt reg1 reg2 reg3
-> pprBinaryF (sLit "fadd") fmt reg1 reg2 reg3
FSUB fmt reg1 reg2 reg3
-> pprBinaryF (sLit "fsub") fmt reg1 reg2 reg3
FMUL fmt reg1 reg2 reg3
-> pprBinaryF (sLit "fmul") fmt reg1 reg2 reg3
FDIV fmt reg1 reg2 reg3
-> pprBinaryF (sLit "fdiv") fmt reg1 reg2 reg3
FABS reg1 reg2
-> pprUnary (sLit "fabs") reg1 reg2
FNEG reg1 reg2
-> pprUnary (sLit "fneg") reg1 reg2
FCMP reg1 reg2
-> hcat [
char '\t',
text "fcmpu\t0, ",
pprReg reg1,
text ", ",
pprReg reg2
]
FCTIWZ reg1 reg2
-> pprUnary (sLit "fctiwz") reg1 reg2
FCTIDZ reg1 reg2
-> pprUnary (sLit "fctidz") reg1 reg2
FCFID reg1 reg2
-> pprUnary (sLit "fcfid") reg1 reg2
FRSP reg1 reg2
-> pprUnary (sLit "frsp") reg1 reg2
CRNOR dst src1 src2
-> hcat [
text "\tcrnor\t",
int dst,
text ", ",
int src1,
text ", ",
int src2
]
MFCR reg
-> hcat [
char '\t',
text "mfcr",
char '\t',
pprReg reg
]
MFLR reg
-> hcat [
char '\t',
text "mflr",
char '\t',
pprReg reg
]
FETCHPC reg
-> vcat [
text "\tbcl\t20,31,1f",
hcat [ text "1:\tmflr\t", pprReg reg ]
]
HWSYNC
-> text "\tsync"
ISYNC
-> text "\tisync"
LWSYNC
-> text "\tlwsync"
NOP
-> text "\tnop"
pprLogic :: Platform -> PtrString -> Reg -> Reg -> RI -> SDoc
pprLogic platform op reg1 reg2 ri = hcat [
char '\t',
ptext op,
case ri of
RIReg _ -> empty
RIImm _ -> char 'i',
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprRI platform ri
]
pprMul :: Platform -> Format -> Reg -> Reg -> RI -> SDoc
pprMul platform fmt reg1 reg2 ri = hcat [
char '\t',
text "mull",
case ri of
RIReg _ -> case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC: illegal format"
RIImm _ -> char 'i',
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprRI platform ri
]
pprDiv :: Format -> Bool -> Reg -> Reg -> Reg -> SDoc
pprDiv fmt sgn reg1 reg2 reg3 = hcat [
char '\t',
text "div",
case fmt of
II32 -> char 'w'
II64 -> char 'd'
_ -> panic "PPC: illegal format",
if sgn then empty else char 'u',
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprReg reg3
]
pprUnary :: PtrString -> Reg -> Reg -> SDoc
pprUnary op reg1 reg2 = hcat [
char '\t',
ptext op,
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
pprBinaryF :: PtrString -> Format -> Reg -> Reg -> Reg -> SDoc
pprBinaryF op fmt reg1 reg2 reg3 = hcat [
char '\t',
ptext op,
pprFFormat fmt,
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprReg reg3
]
pprRI :: Platform -> RI -> SDoc
pprRI _ (RIReg r) = pprReg r
pprRI platform (RIImm r) = pprImm platform r
pprFFormat :: Format -> SDoc
pprFFormat FF64 = empty
pprFFormat FF32 = char 's'
pprFFormat _ = panic "PPC.Ppr.pprFFormat: no match"
limitShiftRI :: Format -> RI -> RI
limitShiftRI II64 (RIImm (ImmInt i)) | i > 63 || i < 0 =
panic $ "PPC.Ppr: Shift by " ++ show i ++ " bits is not allowed."
limitShiftRI II32 (RIImm (ImmInt i)) | i > 31 || i < 0 =
panic $ "PPC.Ppr: 32 bit: Shift by " ++ show i ++ " bits is not allowed."
limitShiftRI _ x = x