summaryrefslogtreecommitdiff
path: root/compiler/GHC/CmmToAsm/X86/Ppr.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/CmmToAsm/X86/Ppr.hs')
-rw-r--r--compiler/GHC/CmmToAsm/X86/Ppr.hs978
1 files changed, 528 insertions, 450 deletions
diff --git a/compiler/GHC/CmmToAsm/X86/Ppr.hs b/compiler/GHC/CmmToAsm/X86/Ppr.hs
index a5b9041974..5aa216f6ba 100644
--- a/compiler/GHC/CmmToAsm/X86/Ppr.hs
+++ b/compiler/GHC/CmmToAsm/X86/Ppr.hs
@@ -28,6 +28,7 @@ import GHC.CmmToAsm.X86.Regs
import GHC.CmmToAsm.X86.Instr
import GHC.CmmToAsm.X86.Cond
import GHC.CmmToAsm.Instr
+import GHC.CmmToAsm.Config
import GHC.CmmToAsm.Format
import GHC.Platform.Reg
import GHC.CmmToAsm.Ppr
@@ -69,36 +70,36 @@ import Data.Bits
-- .subsections_via_symbols and -dead_strip can be found at
-- <https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html#//apple_ref/doc/uid/TP30000823-TPXREF101>
-pprProcAlignment :: SDoc
-pprProcAlignment = sdocWithDynFlags $ \dflags ->
- (maybe empty (pprAlign . mkAlignment) (cmmProcAlignment dflags))
+pprProcAlignment :: NCGConfig -> SDoc
+pprProcAlignment config = maybe empty (pprAlign platform . mkAlignment) (ncgProcAlignment config)
+ where
+ platform = ncgPlatform config
-pprNatCmmDecl :: NatCmmDecl (Alignment, RawCmmStatics) Instr -> SDoc
-pprNatCmmDecl (CmmData section dats) =
- pprSectionAlign section $$ pprDatas dats
+pprNatCmmDecl :: NCGConfig -> NatCmmDecl (Alignment, RawCmmStatics) Instr -> SDoc
+pprNatCmmDecl config (CmmData section dats) =
+ pprSectionAlign config section $$ pprDatas config dats
-pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
- sdocWithDynFlags $ \dflags ->
- pprProcAlignment $$
+pprNatCmmDecl config proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
+ let platform = ncgPlatform config in
+ pprProcAlignment config $$
case topInfoTable proc of
Nothing ->
-- special case for code without info table:
- pprSectionAlign (Section Text lbl) $$
- pprProcAlignment $$
- pprLabel lbl $$ -- blocks guaranteed not null, so label needed
- vcat (map (pprBasicBlock top_info) blocks) $$
- (if debugLevel dflags > 0
+ pprSectionAlign config (Section Text lbl) $$
+ pprProcAlignment config $$
+ pprLabel platform lbl $$ -- blocks guaranteed not null, so label needed
+ vcat (map (pprBasicBlock config top_info) blocks) $$
+ (if ncgDebugLevel config > 0
then ppr (mkAsmTempEndLabel lbl) <> char ':' else empty) $$
- pprSizeDecl lbl
+ pprSizeDecl platform lbl
Just (RawCmmStatics info_lbl _) ->
- sdocWithPlatform $ \platform ->
- pprSectionAlign (Section Text info_lbl) $$
- pprProcAlignment $$
+ pprSectionAlign config (Section Text info_lbl) $$
+ pprProcAlignment config $$
(if platformHasSubsectionsViaSymbols platform
then ppr (mkDeadStripPreventer info_lbl) <> char ':'
else empty) $$
- vcat (map (pprBasicBlock top_info) blocks) $$
+ vcat (map (pprBasicBlock config top_info) blocks) $$
-- above: Even the first block gets a label, because with branch-chain
-- elimination, it might be the target of a goto.
(if platformHasSubsectionsViaSymbols platform
@@ -108,51 +109,49 @@ pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =
<+> char '-'
<+> ppr (mkDeadStripPreventer info_lbl)
else empty) $$
- pprSizeDecl info_lbl
+ pprSizeDecl platform info_lbl
-- | Output the ELF .size directive.
-pprSizeDecl :: CLabel -> SDoc
-pprSizeDecl lbl
- = sdocWithPlatform $ \platform ->
- if osElfTarget (platformOS platform)
+pprSizeDecl :: Platform -> CLabel -> SDoc
+pprSizeDecl platform lbl
+ = if osElfTarget (platformOS platform)
then text "\t.size" <+> ppr lbl <> ptext (sLit ", .-") <> ppr lbl
else empty
-pprBasicBlock :: LabelMap RawCmmStatics -> NatBasicBlock Instr -> SDoc
-pprBasicBlock info_env (BasicBlock blockid instrs)
+pprBasicBlock :: NCGConfig -> LabelMap RawCmmStatics -> NatBasicBlock Instr -> SDoc
+pprBasicBlock config info_env (BasicBlock blockid instrs)
= maybe_infotable $
- pprLabel asmLbl $$
- vcat (map pprInstr instrs) $$
- (sdocOption sdocDebugLevel $ \level ->
- if level > 0
- then ppr (mkAsmTempEndLabel asmLbl) <> char ':'
- else empty
+ pprLabel platform asmLbl $$
+ vcat (map (pprInstr platform) instrs) $$
+ (if ncgDebugLevel config > 0
+ then ppr (mkAsmTempEndLabel asmLbl) <> char ':'
+ else empty
)
where
asmLbl = blockLbl blockid
+ platform = ncgPlatform config
maybe_infotable c = case mapLookup blockid info_env of
Nothing -> c
Just (RawCmmStatics infoLbl info) ->
- pprAlignForSection Text $$
+ pprAlignForSection platform Text $$
infoTableLoc $$
- vcat (map pprData info) $$
- pprLabel infoLbl $$
+ vcat (map (pprData config) info) $$
+ pprLabel platform infoLbl $$
c $$
- (sdocOption sdocDebugLevel $ \level ->
- if level > 0
- then ppr (mkAsmTempEndLabel infoLbl) <> char ':'
- else empty
+ (if ncgDebugLevel config > 0
+ then ppr (mkAsmTempEndLabel infoLbl) <> char ':'
+ else empty
)
-- Make sure the info table has the right .loc for the block
-- coming right after it. See [Note: Info Offset]
infoTableLoc = case instrs of
- (l@LOCATION{} : _) -> pprInstr l
+ (l@LOCATION{} : _) -> pprInstr platform l
_other -> empty
-pprDatas :: (Alignment, RawCmmStatics) -> SDoc
+pprDatas :: NCGConfig -> (Alignment, RawCmmStatics) -> SDoc
-- See note [emit-time elimination of static indirections] in CLabel.
-pprDatas (_, RawCmmStatics alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])
+pprDatas _config (_, RawCmmStatics alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind, _, _])
| lbl == mkIndStaticInfoLabel
, let labelInd (CmmLabelOff l _) = Just l
labelInd (CmmLabel l) = Just l
@@ -162,18 +161,21 @@ pprDatas (_, RawCmmStatics alias [CmmStaticLit (CmmLabel lbl), CmmStaticLit ind,
= pprGloblDecl alias
$$ text ".equiv" <+> ppr alias <> comma <> ppr (CmmLabel ind')
-pprDatas (align, (RawCmmStatics lbl dats))
- = vcat (pprAlign align : pprLabel lbl : map pprData dats)
+pprDatas config (align, (RawCmmStatics lbl dats))
+ = vcat (pprAlign platform align : pprLabel platform lbl : map (pprData config) dats)
+ where
+ platform = ncgPlatform config
-pprData :: CmmStatic -> SDoc
-pprData (CmmString str) = pprBytes str
+pprData :: NCGConfig -> CmmStatic -> SDoc
+pprData _config (CmmString str) = pprBytes str
-pprData (CmmUninitialised bytes)
- = sdocWithPlatform $ \platform ->
- if platformOS platform == OSDarwin then text ".space " <> int bytes
- else text ".skip " <> int bytes
+pprData config (CmmUninitialised bytes)
+ = let platform = ncgPlatform config
+ in if platformOS platform == OSDarwin
+ then text ".space " <> int bytes
+ else text ".skip " <> int bytes
-pprData (CmmStaticLit lit) = pprDataItem lit
+pprData config (CmmStaticLit lit) = pprDataItem config lit
pprGloblDecl :: CLabel -> SDoc
pprGloblDecl lbl
@@ -238,24 +240,23 @@ pprLabelType' dflags lbl =
isInfoTableLabel lbl && not (isConInfoTableLabel lbl)
-pprTypeDecl :: CLabel -> SDoc
-pprTypeDecl lbl
- = sdocWithPlatform $ \platform ->
- if osElfTarget (platformOS platform) && externallyVisibleCLabel lbl
+pprTypeDecl :: Platform -> CLabel -> SDoc
+pprTypeDecl platform lbl
+ = 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 ':')
+pprLabel :: Platform -> CLabel -> SDoc
+pprLabel platform lbl =
+ pprGloblDecl lbl
+ $$ pprTypeDecl platform lbl
+ $$ (ppr lbl <> char ':')
-pprAlign :: Alignment -> SDoc
-pprAlign alignment
- = sdocWithPlatform $ \platform ->
- text ".align " <> int (alignmentOn platform)
+pprAlign :: Platform -> Alignment -> SDoc
+pprAlign platform alignment
+ = text ".align " <> int (alignmentOn platform)
where
bytes = alignmentBytes alignment
alignmentOn platform = if platformOS platform == OSDarwin
@@ -269,18 +270,15 @@ pprAlign alignment
log2 8 = 3
log2 n = 1 + log2 (n `quot` 2)
--- -----------------------------------------------------------------------------
--- pprInstr: print an 'Instr'
-
instance Outputable Instr where
- ppr instr = pprInstr instr
+ ppr instr = sdocWithDynFlags $ \dflags ->
+ pprInstr (targetPlatform dflags) instr
-pprReg :: Format -> Reg -> SDoc
-pprReg f r
+pprReg :: Platform -> Format -> Reg -> SDoc
+pprReg platform 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"
@@ -439,8 +437,8 @@ pprImm (ImmConstantDiff a b) = pprImm a <> char '-'
-pprAddr :: AddrMode -> SDoc
-pprAddr (ImmAddr imm off)
+pprAddr :: Platform -> AddrMode -> SDoc
+pprAddr _platform (ImmAddr imm off)
= let pp_imm = pprImm imm
in
if (off == 0) then
@@ -450,12 +448,11 @@ pprAddr (ImmAddr imm off)
else
pp_imm <> char '+' <> int off
-pprAddr (AddrBaseIndex base index displacement)
- = sdocWithPlatform $ \platform ->
- let
+pprAddr platform (AddrBaseIndex base index displacement)
+ = let
pp_disp = ppr_disp displacement
pp_off p = pp_disp <> char '(' <> p <> char ')'
- pp_reg r = pprReg (archWordFormat (target32Bit platform)) r
+ pp_reg r = pprReg platform (archWordFormat (target32Bit platform)) r
in
case (base, index) of
(EABaseNone, EAIndexNone) -> pp_disp
@@ -471,18 +468,16 @@ pprAddr (AddrBaseIndex base index displacement)
ppr_disp imm = pprImm imm
-- | Print section header and appropriate alignment for that section.
-pprSectionAlign :: Section -> SDoc
-pprSectionAlign (Section (OtherSection _) _) =
+pprSectionAlign :: NCGConfig -> Section -> SDoc
+pprSectionAlign _config (Section (OtherSection _) _) =
panic "X86.Ppr.pprSectionAlign: unknown section"
-pprSectionAlign sec@(Section seg _) =
- sdocWithPlatform $ \platform ->
- pprSectionHeader platform sec $$
- pprAlignForSection seg
+pprSectionAlign config sec@(Section seg _) =
+ pprSectionHeader config sec $$
+ pprAlignForSection (ncgPlatform config) seg
-- | Print appropriate alignment for the given section type.
-pprAlignForSection :: SectionType -> SDoc
-pprAlignForSection seg =
- sdocWithPlatform $ \platform ->
+pprAlignForSection :: Platform -> SectionType -> SDoc
+pprAlignForSection platform seg =
text ".align " <>
case platformOS platform of
-- Darwin: alignments are given as shifts.
@@ -511,14 +506,14 @@ pprAlignForSection seg =
CString -> int 1
_ -> int 8
-pprDataItem :: CmmLit -> SDoc
-pprDataItem lit = sdocWithDynFlags $ \dflags -> pprDataItem' dflags lit
+pprDataItem :: NCGConfig -> CmmLit -> SDoc
+pprDataItem config lit = sdocWithDynFlags $ \dflags -> pprDataItem' dflags config lit
-pprDataItem' :: DynFlags -> CmmLit -> SDoc
-pprDataItem' dflags lit
+pprDataItem' :: DynFlags -> NCGConfig -> CmmLit -> SDoc
+pprDataItem' dflags config lit
= vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit)
where
- platform = targetPlatform dflags
+ platform = ncgPlatform config
imm = litToImm lit
-- These seem to be common:
@@ -577,38 +572,38 @@ pprDataItem' dflags lit
asmComment :: SDoc -> SDoc
asmComment c = whenPprDebug $ text "# " <> c
-pprInstr :: Instr -> SDoc
+pprInstr :: Platform -> Instr -> SDoc
+pprInstr platform i = case i of
+ COMMENT s
+ -> asmComment (ftext s)
-pprInstr (COMMENT s)
- = asmComment (ftext s)
+ LOCATION file line col _name
+ -> text "\t.loc " <> ppr file <+> ppr line <+> ppr col
-pprInstr (LOCATION file line col _name)
- = text "\t.loc " <> ppr file <+> ppr line <+> ppr col
+ DELTA d
+ -> asmComment $ text ("\tdelta = " ++ show d)
-pprInstr (DELTA d)
- = asmComment $ text ("\tdelta = " ++ show d)
+ NEWBLOCK _
+ -> panic "pprInstr: NEWBLOCK"
-pprInstr (NEWBLOCK _)
- = panic "PprMach.pprInstr: NEWBLOCK"
+ UNWIND lbl d
+ -> asmComment (text "\tunwind = " <> ppr d)
+ $$ ppr lbl <> colon
-pprInstr (UNWIND lbl d)
- = asmComment (text "\tunwind = " <> ppr d)
- $$ ppr lbl <> colon
-
-pprInstr (LDATA _ _)
- = panic "PprMach.pprInstr: LDATA"
+ LDATA _ _
+ -> panic "pprInstr: LDATA"
{-
-pprInstr (SPILL reg slot)
- = hcat [
- text "\tSPILL",
- char ' ',
- pprUserReg reg,
- comma,
- text "SLOT" <> parens (int slot)]
-
-pprInstr (RELOAD slot reg)
- = hcat [
+ SPILL reg slot
+ -> hcat [
+ text "\tSPILL",
+ char ' ',
+ pprUserReg reg,
+ comma,
+ text "SLOT" <> parens (int slot)]
+
+ RELOAD slot reg
+ -> hcat [
text "\tRELOAD",
char ' ',
text "SLOT" <> parens (int slot),
@@ -616,120 +611,170 @@ pprInstr (RELOAD slot reg)
pprUserReg reg]
-}
--- Replace 'mov $0x0,%reg' by 'xor %reg,%reg', which is smaller and cheaper.
--- The code generator catches most of these already, but not all.
-pprInstr (MOV format (OpImm (ImmInt 0)) dst@(OpReg _))
- = pprInstr (XOR format' dst dst)
- where format' = case format of
- II64 -> II32 -- 32-bit version is equivalent, and smaller
- _ -> format
-pprInstr (MOV format src dst)
- = pprFormatOpOp (sLit "mov") format src dst
+ -- Replace 'mov $0x0,%reg' by 'xor %reg,%reg', which is smaller and cheaper.
+ -- The code generator catches most of these already, but not all.
+ MOV format (OpImm (ImmInt 0)) dst@(OpReg _)
+ -> pprInstr platform (XOR format' dst dst)
+ where format' = case format of
+ II64 -> II32 -- 32-bit version is equivalent, and smaller
+ _ -> format
+
+ MOV format src dst
+ -> pprFormatOpOp (sLit "mov") format src dst
-pprInstr (CMOV cc format src dst)
- = pprCondOpReg (sLit "cmov") format cc src dst
+ CMOV cc format src dst
+ -> pprCondOpReg (sLit "cmov") format cc src dst
-pprInstr (MOVZxL II32 src dst) = pprFormatOpOp (sLit "mov") II32 src dst
+ MOVZxL II32 src dst
+ -> pprFormatOpOp (sLit "mov") II32 src dst
-- 32-to-64 bit zero extension on x86_64 is accomplished by a simple
-- movl. But we represent it as a MOVZxL instruction, because
-- the reg alloc would tend to throw away a plain reg-to-reg
-- move, and we still want it to do that.
-pprInstr (MOVZxL formats src dst)
- = pprFormatOpOpCoerce (sLit "movz") formats II32 src dst
+ MOVZxL formats src dst
+ -> pprFormatOpOpCoerce (sLit "movz") formats II32 src dst
-- zero-extension only needs to extend to 32 bits: on x86_64,
-- the remaining zero-extension to 64 bits is automatic, and the 32-bit
-- instruction is shorter.
-pprInstr (MOVSxL formats src dst)
- = sdocWithPlatform $ \platform ->
- pprFormatOpOpCoerce (sLit "movs") formats (archWordFormat (target32Bit platform)) src dst
-
--- here we do some patching, since the physical registers are only set late
--- in the code generation.
-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
-
-{- A hack. The Intel documentation says that "The two and three
- operand forms [of IMUL] may also be used with unsigned operands
- because the lower half of the product is the same regardless if
- (sic) the operands are signed or unsigned. The CF and OF flags,
- however, cannot be used to determine if the upper half of the
- result is non-zero." So there.
--}
+ MOVSxL formats src dst
+ -> pprFormatOpOpCoerce (sLit "movs") formats (archWordFormat (target32Bit platform)) src dst
+
+ -- here we do some patching, since the physical registers are only set late
+ -- in the code generation.
+ LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) (EAIndex reg2 1) (ImmInt 0))) dst@(OpReg reg3)
+ | reg1 == reg3
+ -> pprFormatOpOp (sLit "add") format (OpReg reg2) dst
+
+ LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) (EAIndex reg2 1) (ImmInt 0))) dst@(OpReg reg3)
+ | reg2 == reg3
+ -> pprFormatOpOp (sLit "add") format (OpReg reg1) dst
+
+ LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) EAIndexNone displ)) dst@(OpReg reg3)
+ | reg1 == reg3
+ -> pprInstr platform (ADD format (OpImm displ) dst)
+
+ LEA format src dst
+ -> pprFormatOpOp (sLit "lea") format src dst
+
+ ADD format (OpImm (ImmInt (-1))) dst
+ -> pprFormatOp (sLit "dec") format dst
+
+ ADD format (OpImm (ImmInt 1)) dst
+ -> pprFormatOp (sLit "inc") format dst
+
+ ADD format src dst
+ -> pprFormatOpOp (sLit "add") format src dst
+
+ ADC format src dst
+ -> pprFormatOpOp (sLit "adc") format src dst
+
+ SUB format src dst
+ -> pprFormatOpOp (sLit "sub") format src dst
+
+ SBB format src dst
+ -> pprFormatOpOp (sLit "sbb") format src dst
+
+ IMUL format op1 op2
+ -> pprFormatOpOp (sLit "imul") format op1 op2
+
+ ADD_CC format src dst
+ -> pprFormatOpOp (sLit "add") format src dst
+
+ SUB_CC format src dst
+ -> pprFormatOpOp (sLit "sub") format src dst
+
+ -- Use a 32-bit instruction when possible as it saves a byte.
+ -- Notably, extracting the tag bits of a pointer has this form.
+ -- TODO: we could save a byte in a subsequent CMP instruction too,
+ -- but need something like a peephole pass for this
+ AND II64 src@(OpImm (ImmInteger mask)) dst
+ | 0 <= mask && mask < 0xffffffff
+ -> pprInstr platform (AND II32 src dst)
+
+ AND FF32 src dst
+ -> pprOpOp (sLit "andps") FF32 src dst
+
+ AND FF64 src dst
+ -> pprOpOp (sLit "andpd") FF64 src dst
+
+ AND format src dst
+ -> pprFormatOpOp (sLit "and") format src dst
+
+ OR format src dst
+ -> pprFormatOpOp (sLit "or") format src dst
+
+ XOR FF32 src dst
+ -> pprOpOp (sLit "xorps") FF32 src dst
+
+ XOR FF64 src dst
+ -> pprOpOp (sLit "xorpd") FF64 src dst
+
+ XOR format src dst
+ -> pprFormatOpOp (sLit "xor") format src dst
+
+ POPCNT format src dst
+ -> pprOpOp (sLit "popcnt") format src (OpReg dst)
+
+ LZCNT format src dst
+ -> pprOpOp (sLit "lzcnt") format src (OpReg dst)
+
+ TZCNT format src dst
+ -> pprOpOp (sLit "tzcnt") format src (OpReg dst)
+
+ BSF format src dst
+ -> pprOpOp (sLit "bsf") format src (OpReg dst)
+
+ BSR format src dst
+ -> pprOpOp (sLit "bsr") format src (OpReg dst)
+
+ PDEP format src mask dst
+ -> pprFormatOpOpReg (sLit "pdep") format src mask dst
+
+ PEXT format src mask dst
+ -> pprFormatOpOpReg (sLit "pext") format src mask dst
+
+ PREFETCH NTA format src
+ -> pprFormatOp_ (sLit "prefetchnta") format src
+
+ PREFETCH Lvl0 format src
+ -> pprFormatOp_ (sLit "prefetcht0") format src
--- Use a 32-bit instruction when possible as it saves a byte.
--- Notably, extracting the tag bits of a pointer has this form.
--- TODO: we could save a byte in a subsequent CMP instruction too,
--- but need something like a peephole pass for this
-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 -- SSE2
- | otherwise = pprFormatOpOp (sLit "cmp") format src dst
-
-pprInstr (TEST format src dst) = sdocWithPlatform $ \platform ->
- let format' = case (src,dst) of
+ PREFETCH Lvl1 format src
+ -> pprFormatOp_ (sLit "prefetcht1") format src
+
+ PREFETCH Lvl2 format src
+ -> pprFormatOp_ (sLit "prefetcht2") format src
+
+ NOT format op
+ -> pprFormatOp (sLit "not") format op
+
+ BSWAP format op
+ -> pprFormatOp (sLit "bswap") format (OpReg op)
+
+ NEGI format op
+ -> pprFormatOp (sLit "neg") format op
+
+ SHL format src dst
+ -> pprShift (sLit "shl") format src dst
+
+ SAR format src dst
+ -> pprShift (sLit "sar") format src dst
+
+ SHR format src dst
+ -> pprShift (sLit "shr") format src dst
+
+ BT format imm src
+ -> pprFormatImmOp (sLit "bt") format imm src
+
+ CMP format src dst
+ | isFloatFormat format -> pprFormatOpOp (sLit "ucomi") format src dst -- SSE2
+ | otherwise -> pprFormatOpOp (sLit "cmp") format src dst
+
+ TEST format src dst
+ -> pprFormatOpOp (sLit "test") format' src dst
+ where
-- Match instructions like 'test $0x3,%esi' or 'test $0x7,%rbx'.
-- We can replace them by equivalent, but smaller instructions
-- by reducing the size of the immediate operand as far as possible.
@@ -740,275 +785,308 @@ pprInstr (TEST format src dst) = sdocWithPlatform $ \platform ->
-- to be completely equivalent to the original; in particular so
-- that the signed comparison condition bits are the same as they
-- would be if doing a full word comparison. See #13425.
- (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 -- al, bl, cl, dl
- | target32Bit platform && i <= 7 = II16 -- si, di, bp, sp
- | not (target32Bit platform) && i <= 15 = II8 -- al .. r15b
- minSizeOfReg _ _ = format -- other
-
-pprInstr (PUSH format op) = pprFormatOp (sLit "push") format op
-pprInstr (POP format op) = pprFormatOp (sLit "pop") format op
+ format' = case (src,dst) of
+ (OpImm (ImmInteger mask), OpReg dstReg)
+ | 0 <= mask && mask < 128 -> minSizeOfReg platform dstReg
+ _ -> format
+ minSizeOfReg platform (RegReal (RealRegSingle i))
+ | target32Bit platform && i <= 3 = II8 -- al, bl, cl, dl
+ | target32Bit platform && i <= 7 = II16 -- si, di, bp, sp
+ | not (target32Bit platform) && i <= 15 = II8 -- al .. r15b
+ minSizeOfReg _ _ = format -- other
+
+ PUSH format op
+ -> pprFormatOp (sLit "push") format op
+
+ POP format op
+ -> pprFormatOp (sLit "pop") format op
-- both unused (SDM):
--- pprInstr PUSHA = text "\tpushal"
--- pprInstr POPA = text "\tpopal"
-
-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
-
--- x86_64 only
-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
-
- -- FETCHGOT for PIC on ELF platforms
-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 ]
- ]
-
- -- FETCHPC for PIC on Darwin/x86
- -- get the instruction pointer into a register
- -- (Terminology note: the IP is called Program Counter on PPC,
- -- and it's a good thing to use the same name on both platforms)
-pprInstr (FETCHPC reg)
- = vcat [ text "\tcall 1f",
- hcat [ text "1:\tpopl\t", pprReg II32 reg ]
- ]
-
+-- PUSHA -> text "\tpushal"
+-- POPA -> text "\tpopal"
--- the
--- GST fmt src addr ==> FLD dst ; FSTPsz addr
-pprInstr g@(X87Store fmt addr)
- = pprX87 g (hcat [gtab,
- text "fstp", pprFormat_x87 fmt, gsp, pprAddr addr])
+ NOP
+ -> text "\tnop"
+ CLTD II8
+ -> text "\tcbtw"
--- Atomics
+ CLTD II16
+ -> text "\tcwtd"
-pprInstr (LOCK i) = text "\tlock" $$ pprInstr i
+ CLTD II32
+ -> text "\tcltd"
-pprInstr MFENCE = text "\tmfence"
+ CLTD II64
+ -> text "\tcqto"
-pprInstr (XADD format src dst) = pprFormatOpOp (sLit "xadd") format src dst
+ CLTD x
+ -> panic $ "pprInstr: CLTD " ++ show x
-pprInstr (CMPXCHG format src dst)
- = pprFormatOpOp (sLit "cmpxchg") format src dst
+ SETCC cond op
+ -> pprCondInstr (sLit "set") cond (pprOperand platform II8 op)
+ JXX cond blockid
+ -> pprCondInstr (sLit "j") cond (ppr lab)
+ where lab = blockLbl blockid
+ JXX_GBL cond imm
+ -> pprCondInstr (sLit "j") cond (pprImm imm)
---------------------------
--- some left over
+ JMP (OpImm imm) _
+ -> text "\tjmp " <> pprImm imm
+ JMP op _
+ -> text "\tjmp *" <> pprOperand platform (archWordFormat (target32Bit platform)) op
+ JMP_TBL op _ _ _
+ -> pprInstr platform (JMP op [])
-gtab :: SDoc
-gtab = char '\t'
+ CALL (Left imm) _
+ -> text "\tcall " <> pprImm imm
-gsp :: SDoc
-gsp = char ' '
+ CALL (Right reg) _
+ -> text "\tcall *" <> pprReg platform (archWordFormat (target32Bit platform)) reg
+ IDIV fmt op
+ -> pprFormatOp (sLit "idiv") fmt op
+ DIV fmt op
+ -> pprFormatOp (sLit "div") fmt op
-pprX87 :: Instr -> SDoc -> SDoc
-pprX87 fake actual
- = (char '#' <> pprX87Instr fake) $$ actual
+ IMUL2 fmt op
+ -> pprFormatOp (sLit "imul") fmt op
-pprX87Instr :: Instr -> SDoc
-pprX87Instr (X87Store fmt dst) = pprFormatAddr (sLit "gst") fmt dst
-pprX87Instr _ = panic "X86.Ppr.pprX87Instr: no match"
+ -- x86_64 only
+ MUL format op1 op2
+ -> pprFormatOpOp (sLit "mul") format op1 op2
-pprDollImm :: Imm -> SDoc
-pprDollImm i = text "$" <> pprImm i
+ MUL2 format op
+ -> pprFormatOp (sLit "mul") format op
+ FDIV format op1 op2
+ -> pprFormatOpOp (sLit "div") format op1 op2
-pprOperand :: Format -> Operand -> SDoc
-pprOperand f (OpReg r) = pprReg f r
-pprOperand _ (OpImm i) = pprDollImm i
-pprOperand _ (OpAddr ea) = pprAddr ea
+ SQRT format op1 op2
+ -> pprFormatOpReg (sLit "sqrt") format op1 op2
+ CVTSS2SD from to
+ -> pprRegReg (sLit "cvtss2sd") from to
-pprMnemonic_ :: PtrString -> SDoc
-pprMnemonic_ name =
- char '\t' <> ptext name <> space
+ CVTSD2SS from to
+ -> pprRegReg (sLit "cvtsd2ss") from to
+ CVTTSS2SIQ fmt from to
+ -> pprFormatFormatOpReg (sLit "cvttss2si") FF32 fmt from to
-pprMnemonic :: PtrString -> Format -> SDoc
-pprMnemonic name format =
- char '\t' <> ptext name <> pprFormat format <> space
+ CVTTSD2SIQ fmt from to
+ -> pprFormatFormatOpReg (sLit "cvttsd2si") FF64 fmt from to
+ CVTSI2SS fmt from to
+ -> pprFormatOpReg (sLit "cvtsi2ss") fmt from to
-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
- ]
+ CVTSI2SD fmt from to
+ -> pprFormatOpReg (sLit "cvtsi2sd") fmt from to
+ -- FETCHGOT for PIC on ELF platforms
+ FETCHGOT reg
+ -> vcat [ text "\tcall 1f",
+ hcat [ text "1:\tpopl\t", pprReg platform II32 reg ],
+ hcat [ text "\taddl\t$_GLOBAL_OFFSET_TABLE_+(.-1b), ",
+ pprReg platform II32 reg ]
+ ]
-pprOpOp :: PtrString -> Format -> Operand -> Operand -> SDoc
-pprOpOp name format op1 op2
- = hcat [
- pprMnemonic_ name,
- pprOperand format op1,
- comma,
- pprOperand format op2
- ]
+ -- FETCHPC for PIC on Darwin/x86
+ -- get the instruction pointer into a register
+ -- (Terminology note: the IP is called Program Counter on PPC,
+ -- and it's a good thing to use the same name on both platforms)
+ FETCHPC reg
+ -> vcat [ text "\tcall 1f",
+ hcat [ text "1:\tpopl\t", pprReg platform II32 reg ]
+ ]
+ -- the
+ -- GST fmt src addr ==> FLD dst ; FSTPsz addr
+ g@(X87Store fmt addr)
+ -> pprX87 g (hcat [gtab, text "fstp", pprFormat_x87 fmt, gsp, pprAddr platform addr])
+ -- Atomics
+ LOCK i
+ -> text "\tlock" $$ pprInstr platform i
-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
- ]
+ MFENCE
+ -> text "\tmfence"
+ XADD format src dst
+ -> pprFormatOpOp (sLit "xadd") format src dst
+ CMPXCHG format src dst
+ -> pprFormatOpOp (sLit "cmpxchg") format src dst
-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, -- src is 8-bit sized
- 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
- ]
+ where
+ gtab :: SDoc
+ gtab = char '\t'
-pprCondInstr :: PtrString -> Cond -> SDoc -> SDoc
-pprCondInstr name cond arg
- = hcat [ char '\t', ptext name, pprCond cond, space, arg]
+ 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 :: Platform -> Format -> Operand -> SDoc
+ pprOperand platform f op = case op of
+ OpReg r -> pprReg platform f r
+ OpImm i -> pprDollImm i
+ OpAddr ea -> pprAddr platform 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 platform format op1
+ ]
+
+
+ pprFormatOp_ :: PtrString -> Format -> Operand -> SDoc
+ pprFormatOp_ name format op1
+ = hcat [
+ pprMnemonic_ name ,
+ pprOperand platform format op1
+ ]
+
+ pprFormatOp :: PtrString -> Format -> Operand -> SDoc
+ pprFormatOp name format op1
+ = hcat [
+ pprMnemonic name format,
+ pprOperand platform format op1
+ ]
+
+
+ pprFormatOpOp :: PtrString -> Format -> Operand -> Operand -> SDoc
+ pprFormatOpOp name format op1 op2
+ = hcat [
+ pprMnemonic name format,
+ pprOperand platform format op1,
+ comma,
+ pprOperand platform format op2
+ ]
+
+
+ pprOpOp :: PtrString -> Format -> Operand -> Operand -> SDoc
+ pprOpOp name format op1 op2
+ = hcat [
+ pprMnemonic_ name,
+ pprOperand platform format op1,
+ comma,
+ pprOperand platform format op2
+ ]
+
+ pprRegReg :: PtrString -> Reg -> Reg -> SDoc
+ pprRegReg name reg1 reg2
+ = hcat [
+ pprMnemonic_ name,
+ pprReg platform (archWordFormat (target32Bit platform)) reg1,
+ comma,
+ pprReg platform (archWordFormat (target32Bit platform)) reg2
+ ]
+
+
+ pprFormatOpReg :: PtrString -> Format -> Operand -> Reg -> SDoc
+ pprFormatOpReg name format op1 reg2
+ = hcat [
+ pprMnemonic name format,
+ pprOperand platform format op1,
+ comma,
+ pprReg platform (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 platform format op1,
+ comma,
+ pprReg platform format reg2
+ ]
+
+ pprFormatFormatOpReg :: PtrString -> Format -> Format -> Operand -> Reg -> SDoc
+ pprFormatFormatOpReg name format1 format2 op1 reg2
+ = hcat [
+ pprMnemonic name format2,
+ pprOperand platform format1 op1,
+ comma,
+ pprReg platform format2 reg2
+ ]
+
+ pprFormatOpOpReg :: PtrString -> Format -> Operand -> Operand -> Reg -> SDoc
+ pprFormatOpOpReg name format op1 op2 reg3
+ = hcat [
+ pprMnemonic name format,
+ pprOperand platform format op1,
+ comma,
+ pprOperand platform format op2,
+ comma,
+ pprReg platform format reg3
+ ]
+
+
+
+ pprFormatAddr :: PtrString -> Format -> AddrMode -> SDoc
+ pprFormatAddr name format op
+ = hcat [
+ pprMnemonic name format,
+ comma,
+ pprAddr platform op
+ ]
+
+ pprShift :: PtrString -> Format -> Operand -> Operand -> SDoc
+ pprShift name format src dest
+ = hcat [
+ pprMnemonic name format,
+ pprOperand platform II8 src, -- src is 8-bit sized
+ comma,
+ pprOperand platform 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 platform format1 op1,
+ comma,
+ pprOperand platform format2 op2
+ ]
+
+
+ pprCondInstr :: PtrString -> Cond -> SDoc -> SDoc
+ pprCondInstr name cond arg
+ = hcat [ char '\t', ptext name, pprCond cond, space, arg]