module X86.Ppr (
pprNatCmmDecl,
pprData,
pprInstr,
pprFormat,
pprImm,
pprDataItem,
)
where
#include "HsVersions.h"
import GhcPrelude
import X86.Regs
import X86.Instr
import X86.Cond
import Instruction
import Format
import Reg
import PprBase
import Hoopl.Collections
import Hoopl.Label
import BasicTypes (Alignment, mkAlignment, alignmentBytes)
import DynFlags
import Cmm hiding (topInfoTable)
import BlockId
import CLabel
import Unique ( pprUniqueAlways )
import GHC.Platform
import FastString
import Outputable
import Data.Word
import Data.Bits
pprProcAlignment :: SDoc
pprProcAlignment = sdocWithDynFlags $ \dflags ->
(maybe empty (pprAlign . mkAlignment) (cmmProcAlignment dflags))
pprNatCmmDecl :: NatCmmDecl (Alignment, CmmStatics) Instr -> SDoc
pprNatCmmDecl (CmmData section dats) =
pprSectionAlign section $$ pprDatas dats
pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
sdocWithDynFlags $ \dflags ->
pprProcAlignment $$
case topInfoTable proc of
Nothing ->
pprSectionAlign (Section Text lbl) $$
pprProcAlignment $$
pprLabel lbl $$
vcat (map (pprBasicBlock top_info) blocks) $$
(if debugLevel dflags > 0
then ppr (mkAsmTempEndLabel lbl) <> char ':' else empty) $$
pprSizeDecl lbl
Just (Statics info_lbl _) ->
sdocWithPlatform $ \platform ->
pprSectionAlign (Section Text info_lbl) $$
pprProcAlignment $$
(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) $$
pprSizeDecl info_lbl
pprSizeDecl :: CLabel -> SDoc
pprSizeDecl lbl
= sdocWithPlatform $ \platform ->
if osElfTarget (platformOS platform)
then text "\t.size" <+> ppr lbl <> ptext (sLit ", .-") <> ppr lbl
else empty
pprBasicBlock :: LabelMap CmmStatics -> NatBasicBlock Instr -> SDoc
pprBasicBlock info_env (BasicBlock blockid instrs)
= sdocWithDynFlags $ \dflags ->
maybe_infotable dflags $
pprLabel asmLbl $$
vcat (map pprInstr instrs) $$
(if debugLevel dflags > 0
then ppr (mkAsmTempEndLabel asmLbl) <> char ':' else empty)
where
asmLbl = blockLbl blockid
maybe_infotable dflags c = case mapLookup blockid info_env of
Nothing -> c
Just (Statics infoLbl info) ->
pprAlignForSection Text $$
infoTableLoc $$
vcat (map pprData info) $$
pprLabel infoLbl $$
c $$
(if debugLevel dflags > 0
then ppr (mkAsmTempEndLabel infoLbl) <> char ':' else empty)
infoTableLoc = case instrs of
(l@LOCATION{} : _) -> pprInstr l
_other -> empty
pprDatas :: (Alignment, CmmStatics) -> SDoc
pprDatas (_, Statics 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 alias
$$ text ".equiv" <+> ppr alias <> comma <> ppr (CmmLabel ind')
pprDatas (align, (Statics lbl dats))
= vcat (pprAlign align : pprLabel lbl : map pprData dats)
pprData :: CmmStatic -> SDoc
pprData (CmmString str) = pprBytes str
pprData (CmmUninitialised bytes)
= sdocWithPlatform $ \platform ->
if platformOS platform == OSDarwin then text ".space " <> int bytes
else text ".skip " <> int bytes
pprData (CmmStaticLit lit) = pprDataItem lit
pprGloblDecl :: CLabel -> SDoc
pprGloblDecl lbl
| not (externallyVisibleCLabel lbl) = empty
| otherwise = text ".globl " <> ppr lbl
pprLabelType' :: DynFlags -> CLabel -> SDoc
pprLabelType' dflags lbl =
if isCFunctionLabel lbl || functionOkInfoTable then
text "@function"
else
text "@object"
where
functionOkInfoTable = tablesNextToCode dflags &&
isInfoTableLabel lbl && not (isConInfoTableLabel lbl)
pprTypeDecl :: CLabel -> SDoc
pprTypeDecl lbl
= sdocWithPlatform $ \platform ->
if osElfTarget (platformOS platform) && externallyVisibleCLabel lbl
then
sdocWithDynFlags $ \df ->
text ".type " <> ppr lbl <> ptext (sLit ", ") <> pprLabelType' df lbl
else empty
pprLabel :: CLabel -> SDoc
pprLabel lbl = pprGloblDecl lbl
$$ pprTypeDecl lbl
$$ (ppr lbl <> char ':')
pprAlign :: Alignment -> SDoc
pprAlign alignment
= sdocWithPlatform $ \platform ->
text ".align " <> int (alignmentOn platform)
where
bytes = alignmentBytes alignment
alignmentOn platform = if platformOS platform == OSDarwin
then log2 bytes
else bytes
log2 :: Int -> Int
log2 1 = 0
log2 2 = 1
log2 4 = 2
log2 8 = 3
log2 n = 1 + log2 (n `quot` 2)
instance Outputable Instr where
ppr instr = pprInstr instr
pprReg :: Format -> Reg -> SDoc
pprReg f r
= case r of
RegReal (RealRegSingle i) ->
sdocWithPlatform $ \platform ->
if target32Bit platform then ppr32_reg_no f i
else ppr64_reg_no f i
RegReal (RealRegPair _ _) -> panic "X86.Ppr: 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
ppr32_reg_no :: Format -> Int -> SDoc
ppr32_reg_no II8 = ppr32_reg_byte
ppr32_reg_no II16 = ppr32_reg_word
ppr32_reg_no _ = ppr32_reg_long
ppr32_reg_byte i = ptext
(case i of {
0 -> sLit "%al"; 1 -> sLit "%bl";
2 -> sLit "%cl"; 3 -> sLit "%dl";
_ -> sLit $ "very naughty I386 byte register: " ++ show i
})
ppr32_reg_word i = ptext
(case i of {
0 -> sLit "%ax"; 1 -> sLit "%bx";
2 -> sLit "%cx"; 3 -> sLit "%dx";
4 -> sLit "%si"; 5 -> sLit "%di";
6 -> sLit "%bp"; 7 -> sLit "%sp";
_ -> sLit "very naughty I386 word register"
})
ppr32_reg_long i = ptext
(case i of {
0 -> sLit "%eax"; 1 -> sLit "%ebx";
2 -> sLit "%ecx"; 3 -> sLit "%edx";
4 -> sLit "%esi"; 5 -> sLit "%edi";
6 -> sLit "%ebp"; 7 -> sLit "%esp";
_ -> ppr_reg_float i
})
ppr64_reg_no :: Format -> Int -> SDoc
ppr64_reg_no II8 = ppr64_reg_byte
ppr64_reg_no II16 = ppr64_reg_word
ppr64_reg_no II32 = ppr64_reg_long
ppr64_reg_no _ = ppr64_reg_quad
ppr64_reg_byte i = ptext
(case i of {
0 -> sLit "%al"; 1 -> sLit "%bl";
2 -> sLit "%cl"; 3 -> sLit "%dl";
4 -> sLit "%sil"; 5 -> sLit "%dil";
6 -> sLit "%bpl"; 7 -> sLit "%spl";
8 -> sLit "%r8b"; 9 -> sLit "%r9b";
10 -> sLit "%r10b"; 11 -> sLit "%r11b";
12 -> sLit "%r12b"; 13 -> sLit "%r13b";
14 -> sLit "%r14b"; 15 -> sLit "%r15b";
_ -> sLit $ "very naughty x86_64 byte register: " ++ show i
})
ppr64_reg_word i = ptext
(case i of {
0 -> sLit "%ax"; 1 -> sLit "%bx";
2 -> sLit "%cx"; 3 -> sLit "%dx";
4 -> sLit "%si"; 5 -> sLit "%di";
6 -> sLit "%bp"; 7 -> sLit "%sp";
8 -> sLit "%r8w"; 9 -> sLit "%r9w";
10 -> sLit "%r10w"; 11 -> sLit "%r11w";
12 -> sLit "%r12w"; 13 -> sLit "%r13w";
14 -> sLit "%r14w"; 15 -> sLit "%r15w";
_ -> sLit "very naughty x86_64 word register"
})
ppr64_reg_long i = ptext
(case i of {
0 -> sLit "%eax"; 1 -> sLit "%ebx";
2 -> sLit "%ecx"; 3 -> sLit "%edx";
4 -> sLit "%esi"; 5 -> sLit "%edi";
6 -> sLit "%ebp"; 7 -> sLit "%esp";
8 -> sLit "%r8d"; 9 -> sLit "%r9d";
10 -> sLit "%r10d"; 11 -> sLit "%r11d";
12 -> sLit "%r12d"; 13 -> sLit "%r13d";
14 -> sLit "%r14d"; 15 -> sLit "%r15d";
_ -> sLit "very naughty x86_64 register"
})
ppr64_reg_quad i = ptext
(case i of {
0 -> sLit "%rax"; 1 -> sLit "%rbx";
2 -> sLit "%rcx"; 3 -> sLit "%rdx";
4 -> sLit "%rsi"; 5 -> sLit "%rdi";
6 -> sLit "%rbp"; 7 -> sLit "%rsp";
8 -> sLit "%r8"; 9 -> sLit "%r9";
10 -> sLit "%r10"; 11 -> sLit "%r11";
12 -> sLit "%r12"; 13 -> sLit "%r13";
14 -> sLit "%r14"; 15 -> sLit "%r15";
_ -> ppr_reg_float i
})
ppr_reg_float :: Int -> PtrString
ppr_reg_float i = case i of
16 -> sLit "%xmm0" ; 17 -> sLit "%xmm1"
18 -> sLit "%xmm2" ; 19 -> sLit "%xmm3"
20 -> sLit "%xmm4" ; 21 -> sLit "%xmm5"
22 -> sLit "%xmm6" ; 23 -> sLit "%xmm7"
24 -> sLit "%xmm8" ; 25 -> sLit "%xmm9"
26 -> sLit "%xmm10"; 27 -> sLit "%xmm11"
28 -> sLit "%xmm12"; 29 -> sLit "%xmm13"
30 -> sLit "%xmm14"; 31 -> sLit "%xmm15"
_ -> sLit "very naughty x86 register"
pprFormat :: Format -> SDoc
pprFormat x
= ptext (case x of
II8 -> sLit "b"
II16 -> sLit "w"
II32 -> sLit "l"
II64 -> sLit "q"
FF32 -> sLit "ss"
FF64 -> sLit "sd"
)
pprFormat_x87 :: Format -> SDoc
pprFormat_x87 x
= ptext $ case x of
FF32 -> sLit "s"
FF64 -> sLit "l"
_ -> panic "X86.Ppr.pprFormat_x87"
pprCond :: Cond -> SDoc
pprCond c
= ptext (case c of {
GEU -> sLit "ae"; LU -> sLit "b";
EQQ -> sLit "e"; GTT -> sLit "g";
GE -> sLit "ge"; GU -> sLit "a";
LTT -> sLit "l"; LE -> sLit "le";
LEU -> sLit "be"; NE -> sLit "ne";
NEG -> sLit "s"; POS -> sLit "ns";
CARRY -> sLit "c"; OFLO -> sLit "o";
PARITY -> sLit "p"; NOTPARITY -> sLit "np";
ALWAYS -> sLit "mp"})
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
pprAddr :: AddrMode -> SDoc
pprAddr (ImmAddr imm off)
= let pp_imm = pprImm imm
in
if (off == 0) then
pp_imm
else if (off < 0) then
pp_imm <> int off
else
pp_imm <> char '+' <> int off
pprAddr (AddrBaseIndex base index displacement)
= sdocWithPlatform $ \platform ->
let
pp_disp = ppr_disp displacement
pp_off p = pp_disp <> char '(' <> p <> char ')'
pp_reg r = pprReg (archWordFormat (target32Bit platform)) r
in
case (base, index) of
(EABaseNone, EAIndexNone) -> pp_disp
(EABaseReg b, EAIndexNone) -> pp_off (pp_reg b)
(EABaseRip, EAIndexNone) -> pp_off (text "%rip")
(EABaseNone, EAIndex r i) -> pp_off (comma <> pp_reg r <> comma <> int i)
(EABaseReg b, EAIndex r i) -> pp_off (pp_reg b <> comma <> pp_reg r
<> comma <> int i)
_ -> panic "X86.Ppr.pprAddr: no match"
where
ppr_disp (ImmInt 0) = empty
ppr_disp imm = pprImm imm
pprSectionAlign :: Section -> SDoc
pprSectionAlign (Section (OtherSection _) _) =
panic "X86.Ppr.pprSectionAlign: unknown section"
pprSectionAlign sec@(Section seg _) =
sdocWithPlatform $ \platform ->
pprSectionHeader platform sec $$
pprAlignForSection seg
pprAlignForSection :: SectionType -> SDoc
pprAlignForSection seg =
sdocWithPlatform $ \platform ->
text ".align " <>
case platformOS platform of
OSDarwin
| target32Bit platform ->
case seg of
ReadOnlyData16 -> int 4
CString -> int 1
_ -> int 2
| otherwise ->
case seg of
ReadOnlyData16 -> int 4
CString -> int 1
_ -> int 3
_
| target32Bit platform ->
case seg of
Text -> text "4,0x90"
ReadOnlyData16 -> int 16
CString -> int 1
_ -> int 4
| otherwise ->
case seg of
ReadOnlyData16 -> int 16
CString -> int 1
_ -> int 8
pprDataItem :: CmmLit -> SDoc
pprDataItem lit = sdocWithDynFlags $ \dflags -> pprDataItem' dflags lit
pprDataItem' :: DynFlags -> CmmLit -> SDoc
pprDataItem' dflags lit
= vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit)
where
platform = targetPlatform dflags
imm = litToImm lit
ppr_item II8 _ = [text "\t.byte\t" <> pprImm imm]
ppr_item II16 _ = [text "\t.word\t" <> pprImm imm]
ppr_item II32 _ = [text "\t.long\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 II64 _
= case platformOS platform of
OSDarwin
| target32Bit platform ->
case lit of
CmmInt x _ ->
[text "\t.long\t"
<> int (fromIntegral (fromIntegral x :: Word32)),
text "\t.long\t"
<> int (fromIntegral
(fromIntegral (x `shiftR` 32) :: Word32))]
_ -> panic "X86.Ppr.ppr_item: no match for II64"
| otherwise ->
[text "\t.quad\t" <> pprImm imm]
_
| target32Bit platform ->
[text "\t.quad\t" <> pprImm imm]
| otherwise ->
case lit of
CmmLabelDiffOff _ _ _ _ ->
[text "\t.long\t" <> pprImm imm,
text "\t.long\t0"]
_ ->
[text "\t.quad\t" <> pprImm imm]
ppr_item _ _
= panic "X86.Ppr.ppr_item: no match"
asmComment :: SDoc -> SDoc
asmComment c = whenPprDebug $ text "# " <> c
pprInstr :: Instr -> SDoc
pprInstr (COMMENT s)
= asmComment (ftext s)
pprInstr (LOCATION file line col _name)
= text "\t.loc " <> ppr file <+> ppr line <+> ppr col
pprInstr (DELTA d)
= asmComment $ text ("\tdelta = " ++ show d)
pprInstr (NEWBLOCK _)
= panic "PprMach.pprInstr: NEWBLOCK"
pprInstr (UNWIND lbl d)
= asmComment (text "\tunwind = " <> ppr d)
$$ ppr lbl <> colon
pprInstr (LDATA _ _)
= panic "PprMach.pprInstr: LDATA"
pprInstr (MOV format (OpImm (ImmInt 0)) dst@(OpReg _))
= pprInstr (XOR format' dst dst)
where format' = case format of
II64 -> II32
_ -> format
pprInstr (MOV format src dst)
= pprFormatOpOp (sLit "mov") format src dst
pprInstr (CMOV cc format src dst)
= pprCondOpReg (sLit "cmov") format cc src dst
pprInstr (MOVZxL II32 src dst) = pprFormatOpOp (sLit "mov") II32 src dst
pprInstr (MOVZxL formats src dst)
= pprFormatOpOpCoerce (sLit "movz") formats II32 src dst
pprInstr (MOVSxL formats src dst)
= sdocWithPlatform $ \platform ->
pprFormatOpOpCoerce (sLit "movs") formats (archWordFormat (target32Bit platform)) src dst
pprInstr (LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) (EAIndex reg2 1) (ImmInt 0))) dst@(OpReg reg3))
| reg1 == reg3
= pprFormatOpOp (sLit "add") format (OpReg reg2) dst
pprInstr (LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) (EAIndex reg2 1) (ImmInt 0))) dst@(OpReg reg3))
| reg2 == reg3
= pprFormatOpOp (sLit "add") format (OpReg reg1) dst
pprInstr (LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) EAIndexNone displ)) dst@(OpReg reg3))
| reg1 == reg3
= pprInstr (ADD format (OpImm displ) dst)
pprInstr (LEA format src dst) = pprFormatOpOp (sLit "lea") format src dst
pprInstr (ADD format (OpImm (ImmInt (1))) dst)
= pprFormatOp (sLit "dec") format dst
pprInstr (ADD format (OpImm (ImmInt 1)) dst)
= pprFormatOp (sLit "inc") format dst
pprInstr (ADD format src dst) = pprFormatOpOp (sLit "add") format src dst
pprInstr (ADC format src dst) = pprFormatOpOp (sLit "adc") format src dst
pprInstr (SUB format src dst) = pprFormatOpOp (sLit "sub") format src dst
pprInstr (SBB format src dst) = pprFormatOpOp (sLit "sbb") format src dst
pprInstr (IMUL format op1 op2) = pprFormatOpOp (sLit "imul") format op1 op2
pprInstr (ADD_CC format src dst)
= pprFormatOpOp (sLit "add") format src dst
pprInstr (SUB_CC format src dst)
= pprFormatOpOp (sLit "sub") format src dst
pprInstr (AND II64 src@(OpImm (ImmInteger mask)) dst)
| 0 <= mask && mask < 0xffffffff
= pprInstr (AND II32 src dst)
pprInstr (AND FF32 src dst) = pprOpOp (sLit "andps") FF32 src dst
pprInstr (AND FF64 src dst) = pprOpOp (sLit "andpd") FF64 src dst
pprInstr (AND format src dst) = pprFormatOpOp (sLit "and") format src dst
pprInstr (OR format src dst) = pprFormatOpOp (sLit "or") format src dst
pprInstr (XOR FF32 src dst) = pprOpOp (sLit "xorps") FF32 src dst
pprInstr (XOR FF64 src dst) = pprOpOp (sLit "xorpd") FF64 src dst
pprInstr (XOR format src dst) = pprFormatOpOp (sLit "xor") format src dst
pprInstr (POPCNT format src dst) = pprOpOp (sLit "popcnt") format src (OpReg dst)
pprInstr (LZCNT format src dst) = pprOpOp (sLit "lzcnt") format src (OpReg dst)
pprInstr (TZCNT format src dst) = pprOpOp (sLit "tzcnt") format src (OpReg dst)
pprInstr (BSF format src dst) = pprOpOp (sLit "bsf") format src (OpReg dst)
pprInstr (BSR format src dst) = pprOpOp (sLit "bsr") format src (OpReg dst)
pprInstr (PDEP format src mask dst) = pprFormatOpOpReg (sLit "pdep") format src mask dst
pprInstr (PEXT format src mask dst) = pprFormatOpOpReg (sLit "pext") format src mask dst
pprInstr (PREFETCH NTA format src ) = pprFormatOp_ (sLit "prefetchnta") format src
pprInstr (PREFETCH Lvl0 format src) = pprFormatOp_ (sLit "prefetcht0") format src
pprInstr (PREFETCH Lvl1 format src) = pprFormatOp_ (sLit "prefetcht1") format src
pprInstr (PREFETCH Lvl2 format src) = pprFormatOp_ (sLit "prefetcht2") format src
pprInstr (NOT format op) = pprFormatOp (sLit "not") format op
pprInstr (BSWAP format op) = pprFormatOp (sLit "bswap") format (OpReg op)
pprInstr (NEGI format op) = pprFormatOp (sLit "neg") format op
pprInstr (SHL format src dst) = pprShift (sLit "shl") format src dst
pprInstr (SAR format src dst) = pprShift (sLit "sar") format src dst
pprInstr (SHR format src dst) = pprShift (sLit "shr") format src dst
pprInstr (BT format imm src) = pprFormatImmOp (sLit "bt") format imm src
pprInstr (CMP format src dst)
| isFloatFormat format = pprFormatOpOp (sLit "ucomi") format src dst
| otherwise = pprFormatOpOp (sLit "cmp") format src dst
pprInstr (TEST format src dst) = sdocWithPlatform $ \platform ->
let format' = case (src,dst) of
(OpImm (ImmInteger mask), OpReg dstReg)
| 0 <= mask && mask < 128 -> minSizeOfReg platform dstReg
_ -> format
in pprFormatOpOp (sLit "test") format' src dst
where
minSizeOfReg platform (RegReal (RealRegSingle i))
| target32Bit platform && i <= 3 = II8
| target32Bit platform && i <= 7 = II16
| not (target32Bit platform) && i <= 15 = II8
minSizeOfReg _ _ = format
pprInstr (PUSH format op) = pprFormatOp (sLit "push") format op
pprInstr (POP format op) = pprFormatOp (sLit "pop") format op
pprInstr NOP = text "\tnop"
pprInstr (CLTD II8) = text "\tcbtw"
pprInstr (CLTD II16) = text "\tcwtd"
pprInstr (CLTD II32) = text "\tcltd"
pprInstr (CLTD II64) = text "\tcqto"
pprInstr (CLTD x) = panic $ "pprInstr: " ++ show x
pprInstr (SETCC cond op) = pprCondInstr (sLit "set") cond (pprOperand II8 op)
pprInstr (JXX cond blockid)
= pprCondInstr (sLit "j") cond (ppr lab)
where lab = blockLbl blockid
pprInstr (JXX_GBL cond imm) = pprCondInstr (sLit "j") cond (pprImm imm)
pprInstr (JMP (OpImm imm) _) = text "\tjmp " <> pprImm imm
pprInstr (JMP op _) = sdocWithPlatform $ \platform ->
text "\tjmp *"
<> pprOperand (archWordFormat (target32Bit platform)) op
pprInstr (JMP_TBL op _ _ _) = pprInstr (JMP op [])
pprInstr (CALL (Left imm) _) = text "\tcall " <> pprImm imm
pprInstr (CALL (Right reg) _) = sdocWithPlatform $ \platform ->
text "\tcall *"
<> pprReg (archWordFormat (target32Bit platform)) reg
pprInstr (IDIV fmt op) = pprFormatOp (sLit "idiv") fmt op
pprInstr (DIV fmt op) = pprFormatOp (sLit "div") fmt op
pprInstr (IMUL2 fmt op) = pprFormatOp (sLit "imul") fmt op
pprInstr (MUL format op1 op2) = pprFormatOpOp (sLit "mul") format op1 op2
pprInstr (MUL2 format op) = pprFormatOp (sLit "mul") format op
pprInstr (FDIV format op1 op2) = pprFormatOpOp (sLit "div") format op1 op2
pprInstr (SQRT format op1 op2) = pprFormatOpReg (sLit "sqrt") format op1 op2
pprInstr (CVTSS2SD from to) = pprRegReg (sLit "cvtss2sd") from to
pprInstr (CVTSD2SS from to) = pprRegReg (sLit "cvtsd2ss") from to
pprInstr (CVTTSS2SIQ fmt from to) = pprFormatFormatOpReg (sLit "cvttss2si") FF32 fmt from to
pprInstr (CVTTSD2SIQ fmt from to) = pprFormatFormatOpReg (sLit "cvttsd2si") FF64 fmt from to
pprInstr (CVTSI2SS fmt from to) = pprFormatOpReg (sLit "cvtsi2ss") fmt from to
pprInstr (CVTSI2SD fmt from to) = pprFormatOpReg (sLit "cvtsi2sd") fmt from to
pprInstr (FETCHGOT reg)
= vcat [ text "\tcall 1f",
hcat [ text "1:\tpopl\t", pprReg II32 reg ],
hcat [ text "\taddl\t$_GLOBAL_OFFSET_TABLE_+(.-1b), ",
pprReg II32 reg ]
]
pprInstr (FETCHPC reg)
= vcat [ text "\tcall 1f",
hcat [ text "1:\tpopl\t", pprReg II32 reg ]
]
pprInstr g@(X87Store fmt addr)
= pprX87 g (hcat [gtab,
text "fstp", pprFormat_x87 fmt, gsp, pprAddr addr])
pprInstr (LOCK i) = text "\tlock" $$ pprInstr i
pprInstr MFENCE = text "\tmfence"
pprInstr (XADD format src dst) = pprFormatOpOp (sLit "xadd") format src dst
pprInstr (CMPXCHG format src dst)
= pprFormatOpOp (sLit "cmpxchg") format src dst
gtab :: SDoc
gtab = char '\t'
gsp :: SDoc
gsp = char ' '
pprX87 :: Instr -> SDoc -> SDoc
pprX87 fake actual
= (char '#' <> pprX87Instr fake) $$ actual
pprX87Instr :: Instr -> SDoc
pprX87Instr (X87Store fmt dst) = pprFormatAddr (sLit "gst") fmt dst
pprX87Instr _ = panic "X86.Ppr.pprX87Instr: no match"
pprDollImm :: Imm -> SDoc
pprDollImm i = text "$" <> pprImm i
pprOperand :: Format -> Operand -> SDoc
pprOperand f (OpReg r) = pprReg f r
pprOperand _ (OpImm i) = pprDollImm i
pprOperand _ (OpAddr ea) = pprAddr ea
pprMnemonic_ :: PtrString -> SDoc
pprMnemonic_ name =
char '\t' <> ptext name <> space
pprMnemonic :: PtrString -> Format -> SDoc
pprMnemonic name format =
char '\t' <> ptext name <> pprFormat format <> space
pprFormatImmOp :: PtrString -> Format -> Imm -> Operand -> SDoc
pprFormatImmOp name format imm op1
= hcat [
pprMnemonic name format,
char '$',
pprImm imm,
comma,
pprOperand format op1
]
pprFormatOp_ :: PtrString -> Format -> Operand -> SDoc
pprFormatOp_ name format op1
= hcat [
pprMnemonic_ name ,
pprOperand format op1
]
pprFormatOp :: PtrString -> Format -> Operand -> SDoc
pprFormatOp name format op1
= hcat [
pprMnemonic name format,
pprOperand format op1
]
pprFormatOpOp :: PtrString -> Format -> Operand -> Operand -> SDoc
pprFormatOpOp name format op1 op2
= hcat [
pprMnemonic name format,
pprOperand format op1,
comma,
pprOperand format op2
]
pprOpOp :: PtrString -> Format -> Operand -> Operand -> SDoc
pprOpOp name format op1 op2
= hcat [
pprMnemonic_ name,
pprOperand format op1,
comma,
pprOperand format op2
]
pprRegReg :: PtrString -> Reg -> Reg -> SDoc
pprRegReg name reg1 reg2
= sdocWithPlatform $ \platform ->
hcat [
pprMnemonic_ name,
pprReg (archWordFormat (target32Bit platform)) reg1,
comma,
pprReg (archWordFormat (target32Bit platform)) reg2
]
pprFormatOpReg :: PtrString -> Format -> Operand -> Reg -> SDoc
pprFormatOpReg name format op1 reg2
= sdocWithPlatform $ \platform ->
hcat [
pprMnemonic name format,
pprOperand format op1,
comma,
pprReg (archWordFormat (target32Bit platform)) reg2
]
pprCondOpReg :: PtrString -> Format -> Cond -> Operand -> Reg -> SDoc
pprCondOpReg name format cond op1 reg2
= hcat [
char '\t',
ptext name,
pprCond cond,
space,
pprOperand format op1,
comma,
pprReg format reg2
]
pprFormatFormatOpReg :: PtrString -> Format -> Format -> Operand -> Reg -> SDoc
pprFormatFormatOpReg name format1 format2 op1 reg2
= hcat [
pprMnemonic name format2,
pprOperand format1 op1,
comma,
pprReg format2 reg2
]
pprFormatOpOpReg :: PtrString -> Format -> Operand -> Operand -> Reg -> SDoc
pprFormatOpOpReg name format op1 op2 reg3
= hcat [
pprMnemonic name format,
pprOperand format op1,
comma,
pprOperand format op2,
comma,
pprReg format reg3
]
pprFormatAddr :: PtrString -> Format -> AddrMode -> SDoc
pprFormatAddr name format op
= hcat [
pprMnemonic name format,
comma,
pprAddr op
]
pprShift :: PtrString -> Format -> Operand -> Operand -> SDoc
pprShift name format src dest
= hcat [
pprMnemonic name format,
pprOperand II8 src,
comma,
pprOperand format dest
]
pprFormatOpOpCoerce :: PtrString -> Format -> Format -> Operand -> Operand -> SDoc
pprFormatOpOpCoerce name format1 format2 op1 op2
= hcat [ char '\t', ptext name, pprFormat format1, pprFormat format2, space,
pprOperand format1 op1,
comma,
pprOperand format2 op2
]
pprCondInstr :: PtrString -> Cond -> SDoc -> SDoc
pprCondInstr name cond arg
= hcat [ char '\t', ptext name, pprCond cond, space, arg]