module PPC.Ppr (pprNatCmmDecl) where
import GhcPrelude
import PPC.Regs
import PPC.Instr
import PPC.Cond
import PprBase
import Instruction
import Format
import Reg
import RegClass
import TargetReg
import Cmm hiding (topInfoTable)
import Hoopl.Collections
import Hoopl.Label
import BlockId
import CLabel
import Unique ( pprUniqueAlways, getUnique )
import Platform
import FastString
import Outputable
import DynFlags
import Data.Word
import Data.Int
import Data.Bits
pprNatCmmDecl :: NatCmmDecl CmmStatics Instr -> SDoc
pprNatCmmDecl (CmmData section dats) =
pprSectionAlign section $$ pprDatas dats
pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
case topInfoTable proc of
Nothing ->
sdocWithPlatform $ \platform ->
case blocks of
[] ->
pprLabel lbl
blocks ->
pprSectionAlign (Section Text lbl) $$
(case platformArch platform of
ArchPPC_64 ELF_V1 -> pprFunctionDescriptor lbl
ArchPPC_64 ELF_V2 -> pprFunctionPrologue lbl
_ -> pprLabel lbl) $$
vcat (map (pprBasicBlock top_info) blocks)
Just (Statics info_lbl _) ->
sdocWithPlatform $ \platform ->
pprSectionAlign (Section Text info_lbl) $$
(if platformHasSubsectionsViaSymbols platform
then ppr (mkDeadStripPreventer info_lbl) <> char ':'
else empty) $$
vcat (map (pprBasicBlock top_info) blocks) $$
(if platformHasSubsectionsViaSymbols platform
then
text "\t.long "
<+> ppr info_lbl
<+> char '-'
<+> ppr (mkDeadStripPreventer info_lbl)
else empty)
pprFunctionDescriptor :: CLabel -> SDoc
pprFunctionDescriptor lab = pprGloblDecl lab
$$ text "\t.section \".opd\", \"aw\""
$$ text "\t.align 3"
$$ ppr lab <> char ':'
$$ text "\t.quad ."
<> ppr lab
<> text ",.TOC.@tocbase,0"
$$ text "\t.previous"
$$ text "\t.type"
<+> ppr lab
<> text ", @function"
$$ char '.' <> ppr lab <> char ':'
pprFunctionPrologue :: CLabel ->SDoc
pprFunctionPrologue lab = pprGloblDecl lab
$$ text ".type "
<> ppr lab
<> text ", @function"
$$ ppr 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" <> ppr lab
<> text ",.-" <> ppr lab
pprBasicBlock :: LabelMap CmmStatics -> NatBasicBlock Instr -> SDoc
pprBasicBlock info_env (BasicBlock blockid instrs)
= maybe_infotable $$
pprLabel (blockLbl blockid) $$
vcat (map pprInstr instrs)
where
maybe_infotable = case mapLookup blockid info_env of
Nothing -> empty
Just (Statics info_lbl info) ->
pprAlignForSection Text $$
vcat (map pprData info) $$
pprLabel info_lbl
pprDatas :: CmmStatics -> SDoc
pprDatas (Statics lbl dats) = vcat (pprLabel lbl : map pprData dats)
pprData :: CmmStatic -> SDoc
pprData (CmmString str) = pprASCII str
pprData (CmmUninitialised bytes) = keyword <> int bytes
where keyword = sdocWithPlatform $ \platform ->
case platformOS platform of
OSDarwin -> text ".space "
OSAIX -> text ".space "
_ -> text ".skip "
pprData (CmmStaticLit lit) = pprDataItem lit
pprGloblDecl :: CLabel -> SDoc
pprGloblDecl lbl
| not (externallyVisibleCLabel lbl) = empty
| otherwise = text ".globl " <> ppr lbl
pprTypeAndSizeDecl :: CLabel -> SDoc
pprTypeAndSizeDecl lbl
= sdocWithPlatform $ \platform ->
if platformOS platform == OSLinux && externallyVisibleCLabel lbl
then text ".type " <>
ppr lbl <> text ", @object"
else empty
pprLabel :: CLabel -> SDoc
pprLabel lbl = pprGloblDecl lbl
$$ pprTypeAndSizeDecl lbl
$$ (ppr lbl <> char ':')
pprASCII :: [Word8] -> SDoc
pprASCII str
= vcat (map do1 str) $$ do1 0
where
do1 :: Word8 -> SDoc
do1 w = text "\t.byte\t" <> int (fromIntegral w)
instance Outputable Instr where
ppr instr = pprInstr instr
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
RegVirtual (VirtualRegSSE u) -> text "%vSSE_" <> pprUniqueAlways u
where
ppr_reg_no :: Int -> SDoc
ppr_reg_no i =
sdocWithPlatform $ \platform ->
case platformOS platform of
OSDarwin ->
ptext
(case i of {
0 -> sLit "r0"; 1 -> sLit "r1";
2 -> sLit "r2"; 3 -> sLit "r3";
4 -> sLit "r4"; 5 -> sLit "r5";
6 -> sLit "r6"; 7 -> sLit "r7";
8 -> sLit "r8"; 9 -> sLit "r9";
10 -> sLit "r10"; 11 -> sLit "r11";
12 -> sLit "r12"; 13 -> sLit "r13";
14 -> sLit "r14"; 15 -> sLit "r15";
16 -> sLit "r16"; 17 -> sLit "r17";
18 -> sLit "r18"; 19 -> sLit "r19";
20 -> sLit "r20"; 21 -> sLit "r21";
22 -> sLit "r22"; 23 -> sLit "r23";
24 -> sLit "r24"; 25 -> sLit "r25";
26 -> sLit "r26"; 27 -> sLit "r27";
28 -> sLit "r28"; 29 -> sLit "r29";
30 -> sLit "r30"; 31 -> sLit "r31";
32 -> sLit "f0"; 33 -> sLit "f1";
34 -> sLit "f2"; 35 -> sLit "f3";
36 -> sLit "f4"; 37 -> sLit "f5";
38 -> sLit "f6"; 39 -> sLit "f7";
40 -> sLit "f8"; 41 -> sLit "f9";
42 -> sLit "f10"; 43 -> sLit "f11";
44 -> sLit "f12"; 45 -> sLit "f13";
46 -> sLit "f14"; 47 -> sLit "f15";
48 -> sLit "f16"; 49 -> sLit "f17";
50 -> sLit "f18"; 51 -> sLit "f19";
52 -> sLit "f20"; 53 -> sLit "f21";
54 -> sLit "f22"; 55 -> sLit "f23";
56 -> sLit "f24"; 57 -> sLit "f25";
58 -> sLit "f26"; 59 -> sLit "f27";
60 -> sLit "f28"; 61 -> sLit "f29";
62 -> sLit "f30"; 63 -> sLit "f31";
_ -> sLit "very naughty powerpc register"
})
_
| 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"
_ -> panic "PPC.Ppr.pprFormat: no match")
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 :: Imm -> SDoc
pprImm (ImmInt i) = int i
pprImm (ImmInteger i) = integer i
pprImm (ImmCLbl l) = ppr l
pprImm (ImmIndex l i) = ppr l <> char '+' <> int i
pprImm (ImmLit s) = s
pprImm (ImmFloat _) = text "naughty float immediate"
pprImm (ImmDouble _) = text "naughty double immediate"
pprImm (ImmConstantSum a b) = pprImm a <> char '+' <> pprImm b
pprImm (ImmConstantDiff a b) = pprImm a <> char '-'
<> lparen <> pprImm b <> rparen
pprImm (LO (ImmInt i)) = pprImm (LO (ImmInteger (toInteger i)))
pprImm (LO (ImmInteger i)) = pprImm (ImmInteger (toInteger lo16))
where
lo16 = fromInteger (i .&. 0xffff) :: Int16
pprImm (LO i)
= sdocWithPlatform $ \platform ->
if platformOS platform == OSDarwin
then hcat [ text "lo16(", pprImm i, rparen ]
else pprImm i <> text "@l"
pprImm (HI i)
= sdocWithPlatform $ \platform ->
if platformOS platform == OSDarwin
then hcat [ text "hi16(", pprImm i, rparen ]
else pprImm i <> text "@h"
pprImm (HA (ImmInt i)) = pprImm (HA (ImmInteger (toInteger i)))
pprImm (HA (ImmInteger i)) = pprImm (ImmInteger ha16)
where
ha16 = if lo16 >= 0x8000 then hi16+1 else hi16
hi16 = (i `shiftR` 16)
lo16 = i .&. 0xffff
pprImm (HA i)
= sdocWithPlatform $ \platform ->
if platformOS platform == OSDarwin
then hcat [ text "ha16(", pprImm i, rparen ]
else pprImm i <> text "@ha"
pprImm (HIGHERA i)
= sdocWithPlatform $ \platform ->
if platformOS platform == OSDarwin
then panic "PPC.pprImm: highera not implemented on Darwin"
else pprImm i <> text "@highera"
pprImm (HIGHESTA i)
= sdocWithPlatform $ \platform ->
if platformOS platform == OSDarwin
then panic "PPC.pprImm: highesta not implemented on Darwin"
else pprImm i <> text "@highesta"
pprAddr :: AddrMode -> SDoc
pprAddr (AddrRegReg r1 r2)
= pprReg r1 <> char ',' <+> pprReg r2
pprAddr (AddrRegImm r1 (ImmInt i))
= hcat [ int i, char '(', pprReg r1, char ')' ]
pprAddr (AddrRegImm r1 (ImmInteger i))
= hcat [ integer i, char '(', pprReg r1, char ')' ]
pprAddr (AddrRegImm r1 imm)
= hcat [ pprImm imm, char '(', pprReg r1, char ')' ]
pprSectionAlign :: Section -> SDoc
pprSectionAlign sec@(Section seg _) =
sdocWithPlatform $ \platform ->
pprSectionHeader platform sec $$
pprAlignForSection seg
pprAlignForSection :: SectionType -> SDoc
pprAlignForSection seg =
sdocWithPlatform $ \platform ->
let osDarwin = platformOS platform == OSDarwin
ppc64 = not $ target32Bit platform
in ptext $ case seg of
Text -> sLit ".align 2"
Data
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
ReadOnlyData
| osDarwin -> sLit ".align 2"
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
RelocatableReadOnlyData
| osDarwin -> sLit ".align 2"
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
UninitialisedData
| osDarwin -> sLit ".align 2"
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
ReadOnlyData16
| osDarwin -> sLit ".align 4"
| otherwise -> sLit ".align 4"
CString
| osDarwin -> sLit ".align 2"
| ppc64 -> sLit ".align 3"
| otherwise -> sLit ".align 2"
OtherSection _ -> panic "PprMach.pprSectionAlign: unknown section"
pprDataItem :: CmmLit -> SDoc
pprDataItem lit
= sdocWithDynFlags $ \dflags ->
vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit dflags)
where
imm = litToImm lit
archPPC_64 dflags = not $ target32Bit $ targetPlatform dflags
ppr_item II8 _ _ = [text "\t.byte\t" <> pprImm imm]
ppr_item II32 _ _ = [text "\t.long\t" <> pprImm imm]
ppr_item II64 _ dflags
| archPPC_64 dflags = [text "\t.quad\t" <> pprImm imm]
ppr_item FF32 (CmmFloat r _) _
= let bs = floatToBytes (fromRational r)
in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs
ppr_item FF64 (CmmFloat r _) _
= let bs = doubleToBytes (fromRational r)
in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs
ppr_item II16 _ _ = [text "\t.short\t" <> pprImm imm]
ppr_item II64 (CmmInt x _) dflags
| not(archPPC_64 dflags) =
[text "\t.long\t"
<> int (fromIntegral
(fromIntegral (x `shiftR` 32) :: Word32)),
text "\t.long\t"
<> int (fromIntegral (fromIntegral x :: Word32))]
ppr_item _ _ _
= panic "PPC.Ppr.pprDataItem: no match"
pprInstr :: Instr -> SDoc
pprInstr (COMMENT _) = empty
pprInstr (DELTA d)
= pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))
pprInstr (NEWBLOCK _)
= panic "PprMach.pprInstr: NEWBLOCK"
pprInstr (LDATA _ _)
= panic "PprMach.pprInstr: LDATA"
pprInstr (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"
_ -> panic "PPC.Ppr.pprInstr: no match"
),
case addr of AddrRegImm _ _ -> empty
AddrRegReg _ _ -> char 'x',
char '\t',
pprReg reg,
text ", ",
pprAddr addr
]
pprInstr (LDFAR fmt reg (AddrRegImm source off)) =
sdocWithPlatform $ \platform -> vcat [
pprInstr (ADDIS (tmpReg platform) source (HA off)),
pprInstr (LD fmt reg (AddrRegImm (tmpReg platform) (LO off)))
]
pprInstr (LDFAR _ _ _) =
panic "PPC.Ppr.pprInstr LDFAR: no match"
pprInstr (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 addr
]
pprInstr (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"
_ -> panic "PPC.Ppr.pprInstr: no match"
),
case addr of AddrRegImm _ _ -> empty
AddrRegReg _ _ -> char 'x',
char '\t',
pprReg reg,
text ", ",
pprAddr addr
]
pprInstr (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 addr
]
pprInstr (STFAR fmt reg (AddrRegImm source off)) =
sdocWithPlatform $ \platform -> vcat [
pprInstr (ADDIS (tmpReg platform) source (HA off)),
pprInstr (ST fmt reg (AddrRegImm (tmpReg platform) (LO off)))
]
pprInstr (STFAR _ _ _) =
panic "PPC.Ppr.pprInstr STFAR: no match"
pprInstr (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 addr
]
pprInstr (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 addr
]
pprInstr (LIS reg imm) = hcat [
char '\t',
text "lis",
char '\t',
pprReg reg,
text ", ",
pprImm imm
]
pprInstr (LI reg imm) = hcat [
char '\t',
text "li",
char '\t',
pprReg reg,
text ", ",
pprImm imm
]
pprInstr (MR reg1 reg2)
| reg1 == reg2 = empty
| otherwise = hcat [
char '\t',
sdocWithPlatform $ \platform ->
case targetClassOfReg platform reg1 of
RcInteger -> text "mr"
_ -> text "fmr",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
pprInstr (CMP fmt reg ri) = hcat [
char '\t',
op,
char '\t',
pprReg reg,
text ", ",
pprRI ri
]
where
op = hcat [
text "cmp",
pprFormat fmt,
case ri of
RIReg _ -> empty
RIImm _ -> char 'i'
]
pprInstr (CMPL fmt reg ri) = hcat [
char '\t',
op,
char '\t',
pprReg reg,
text ", ",
pprRI ri
]
where
op = hcat [
text "cmpl",
pprFormat fmt,
case ri of
RIReg _ -> empty
RIImm _ -> char 'i'
]
pprInstr (BCC cond blockid prediction) = hcat [
char '\t',
text "b",
pprCond cond,
pprPrediction prediction,
char '\t',
ppr lbl
]
where lbl = mkLocalBlockLabel (getUnique blockid)
pprPrediction p = case p of
Nothing -> empty
Just True -> char '+'
Just False -> char '-'
pprInstr (BCCFAR cond blockid prediction) = vcat [
hcat [
text "\tb",
pprCond (condNegate cond),
neg_prediction,
text "\t$+8"
],
hcat [
text "\tb\t",
ppr lbl
]
]
where lbl = mkLocalBlockLabel (getUnique blockid)
neg_prediction = case prediction of
Nothing -> empty
Just True -> char '-'
Just False -> char '+'
pprInstr (JMP lbl)
| isForeignLabel lbl = panic "PPC.Ppr.pprInstr: JMP to ForeignLabel"
| otherwise =
hcat [
char '\t',
text "b",
char '\t',
ppr lbl
]
pprInstr (MTCTR reg) = hcat [
char '\t',
text "mtctr",
char '\t',
pprReg reg
]
pprInstr (BCTR _ _) = hcat [
char '\t',
text "bctr"
]
pprInstr (BL lbl _) = do
sdocWithPlatform $ \platform -> case platformOS platform of
OSAIX ->
hcat [
text "\tbl\t.",
ppr lbl
]
_ ->
hcat [
text "\tbl\t",
ppr lbl
]
pprInstr (BCTRL _) = hcat [
char '\t',
text "bctrl"
]
pprInstr (ADD reg1 reg2 ri) = pprLogic (sLit "add") reg1 reg2 ri
pprInstr (ADDIS reg1 reg2 imm) = hcat [
char '\t',
text "addis",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm imm
]
pprInstr (ADDO reg1 reg2 reg3) = pprLogic (sLit "addo") reg1 reg2 (RIReg reg3)
pprInstr (ADDC reg1 reg2 reg3) = pprLogic (sLit "addc") reg1 reg2 (RIReg reg3)
pprInstr (ADDE reg1 reg2 reg3) = pprLogic (sLit "adde") reg1 reg2 (RIReg reg3)
pprInstr (ADDZE reg1 reg2) = pprUnary (sLit "addze") reg1 reg2
pprInstr (SUBF reg1 reg2 reg3) = pprLogic (sLit "subf") reg1 reg2 (RIReg reg3)
pprInstr (SUBFO reg1 reg2 reg3) = pprLogic (sLit "subfo") reg1 reg2 (RIReg reg3)
pprInstr (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 ri
]
pprInstr (SUBFE reg1 reg2 reg3) = pprLogic (sLit "subfe") reg1 reg2 (RIReg reg3)
pprInstr (MULL fmt reg1 reg2 ri) = pprMul fmt reg1 reg2 ri
pprInstr (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
]
pprInstr (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"
]
]
pprInstr (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
]
pprInstr (DIV fmt sgn reg1 reg2 reg3) = pprDiv fmt sgn reg1 reg2 reg3
pprInstr (AND reg1 reg2 (RIImm imm)) = hcat [
char '\t',
text "andi.",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm imm
]
pprInstr (AND reg1 reg2 ri) = pprLogic (sLit "and") reg1 reg2 ri
pprInstr (ANDC reg1 reg2 reg3) = pprLogic (sLit "andc") reg1 reg2 (RIReg reg3)
pprInstr (NAND reg1 reg2 reg3) = pprLogic (sLit "nand") reg1 reg2 (RIReg reg3)
pprInstr (OR reg1 reg2 ri) = pprLogic (sLit "or") reg1 reg2 ri
pprInstr (XOR reg1 reg2 ri) = pprLogic (sLit "xor") reg1 reg2 ri
pprInstr (ORIS reg1 reg2 imm) = hcat [
char '\t',
text "oris",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm imm
]
pprInstr (XORIS reg1 reg2 imm) = hcat [
char '\t',
text "xoris",
char '\t',
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
pprImm imm
]
pprInstr (EXTS fmt reg1 reg2) = hcat [
char '\t',
text "exts",
pprFormat fmt,
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
pprInstr (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
]
pprInstr (NEG reg1 reg2) = pprUnary (sLit "neg") reg1 reg2
pprInstr (NOT reg1 reg2) = pprUnary (sLit "not") reg1 reg2
pprInstr (SR II32 reg1 reg2 (RIImm (ImmInt i))) | i < 0 || i > 31 =
pprInstr (XOR reg1 reg2 (RIReg reg2))
pprInstr (SL II32 reg1 reg2 (RIImm (ImmInt i))) | i < 0 || i > 31 =
pprInstr (XOR reg1 reg2 (RIReg reg2))
pprInstr (SRA II32 reg1 reg2 (RIImm (ImmInt i))) | i > 31 =
pprInstr (SRA II32 reg1 reg2 (RIImm (ImmInt 31)))
pprInstr (SL fmt reg1 reg2 ri) =
let op = case fmt of
II32 -> "slw"
II64 -> "sld"
_ -> panic "PPC.Ppr.pprInstr: shift illegal size"
in pprLogic (sLit op) reg1 reg2 (limitShiftRI fmt ri)
pprInstr (SR fmt reg1 reg2 ri) =
let op = case fmt of
II32 -> "srw"
II64 -> "srd"
_ -> panic "PPC.Ppr.pprInstr: shift illegal size"
in pprLogic (sLit op) reg1 reg2 (limitShiftRI fmt ri)
pprInstr (SRA fmt reg1 reg2 ri) =
let op = case fmt of
II32 -> "sraw"
II64 -> "srad"
_ -> panic "PPC.Ppr.pprInstr: shift illegal size"
in pprLogic (sLit op) reg1 reg2 (limitShiftRI fmt ri)
pprInstr (RLWINM reg1 reg2 sh mb me) = hcat [
text "\trlwinm\t",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
int sh,
text ", ",
int mb,
text ", ",
int me
]
pprInstr (CLRLI fmt reg1 reg2 n) = hcat [
text "\tclrl",
pprFormat fmt,
text "i ",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
int n
]
pprInstr (CLRRI fmt reg1 reg2 n) = hcat [
text "\tclrr",
pprFormat fmt,
text "i ",
pprReg reg1,
text ", ",
pprReg reg2,
text ", ",
int n
]
pprInstr (FADD fmt reg1 reg2 reg3) = pprBinaryF (sLit "fadd") fmt reg1 reg2 reg3
pprInstr (FSUB fmt reg1 reg2 reg3) = pprBinaryF (sLit "fsub") fmt reg1 reg2 reg3
pprInstr (FMUL fmt reg1 reg2 reg3) = pprBinaryF (sLit "fmul") fmt reg1 reg2 reg3
pprInstr (FDIV fmt reg1 reg2 reg3) = pprBinaryF (sLit "fdiv") fmt reg1 reg2 reg3
pprInstr (FABS reg1 reg2) = pprUnary (sLit "fabs") reg1 reg2
pprInstr (FNEG reg1 reg2) = pprUnary (sLit "fneg") reg1 reg2
pprInstr (FCMP reg1 reg2) = hcat [
char '\t',
text "fcmpu\t0, ",
pprReg reg1,
text ", ",
pprReg reg2
]
pprInstr (FCTIWZ reg1 reg2) = pprUnary (sLit "fctiwz") reg1 reg2
pprInstr (FCTIDZ reg1 reg2) = pprUnary (sLit "fctidz") reg1 reg2
pprInstr (FCFID reg1 reg2) = pprUnary (sLit "fcfid") reg1 reg2
pprInstr (FRSP reg1 reg2) = pprUnary (sLit "frsp") reg1 reg2
pprInstr (CRNOR dst src1 src2) = hcat [
text "\tcrnor\t",
int dst,
text ", ",
int src1,
text ", ",
int src2
]
pprInstr (MFCR reg) = hcat [
char '\t',
text "mfcr",
char '\t',
pprReg reg
]
pprInstr (MFLR reg) = hcat [
char '\t',
text "mflr",
char '\t',
pprReg reg
]
pprInstr (FETCHPC reg) = vcat [
text "\tbcl\t20,31,1f",
hcat [ text "1:\tmflr\t", pprReg reg ]
]
pprInstr HWSYNC = text "\tsync"
pprInstr ISYNC = text "\tisync"
pprInstr LWSYNC = text "\tlwsync"
pprInstr NOP = text "\tnop"
pprInstr (UPDATE_SP fmt amount@(ImmInt offset))
| fits16Bits offset = vcat [
pprInstr (LD fmt r0 (AddrRegImm sp (ImmInt 0))),
pprInstr (STU fmt r0 (AddrRegImm sp amount))
]
pprInstr (UPDATE_SP fmt amount)
= sdocWithPlatform $ \platform ->
let tmp = tmpReg platform in
vcat [
pprInstr (LD fmt r0 (AddrRegImm sp (ImmInt 0))),
pprInstr (ADDIS tmp sp (HA amount)),
pprInstr (ADD tmp tmp (RIImm (LO amount))),
pprInstr (STU fmt r0 (AddrRegReg sp tmp))
]
pprLogic :: LitString -> Reg -> Reg -> RI -> SDoc
pprLogic 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 ri
]
pprMul :: Format -> Reg -> Reg -> RI -> SDoc
pprMul 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 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 :: LitString -> Reg -> Reg -> SDoc
pprUnary op reg1 reg2 = hcat [
char '\t',
ptext op,
char '\t',
pprReg reg1,
text ", ",
pprReg reg2
]
pprBinaryF :: LitString -> 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 :: RI -> SDoc
pprRI (RIReg r) = pprReg r
pprRI (RIImm r) = pprImm 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