Skip to content

Commit

Permalink
[X86] Remove the _alt forms of XOP VPCOM instructions. Use a combinat…
Browse files Browse the repository at this point in the history
…ion of custom printing and custom parsing to achieve the same result and more

Previously we had a regular form of the instruction used when the immediate was 0-7. And _alt form that allowed the full 8 bit immediate. Codegen would always use the 0-7 form since the immediate was always checked to be in range. Assembly parsing would use the 0-7 form when a mnemonic like vpcomtrueb was used. If the immediate was specified directly the _alt form was used. The disassembler would prefer to use the 0-7 form instruction when the immediate was in range and the _alt form otherwise. This way disassembly would print the most readable form when possible.

The assembly parsing for things like vpcomtrueb relied on splitting the mnemonic into 3 pieces. A "vpcom" prefix, an immediate representing the "true", and a suffix of "b". The tablegenerated printing code would similarly print a "vpcom" prefix, decode the immediate into a string, and then print "b".

The _alt form on the other hand parsed and printed like any other instruction with no specialness.

With this patch we drop to one form and solve the disassembly printing issue by doing custom printing when the immediate is 0-7. The parsing code has been tweaked to turn "vpcomtrueb" into "vpcomb" and then the immediate for the "true" is inserted either before or after the other operands depending on at&t or intel syntax.

I'd rather not do the custom printing, but I tried using an InstAlias for each possible mnemonic for all 8 immediates for all 16 combinations of element size, signedness, and memory/register. The code emitted into printAliasInstr ended up checking the number of operands, the register class of each operand, and the immediate for all 256 aliases. This was repeated for both the at&t and intel printer. Despite a lot of common checks between all of the aliases, when compiled with clang at least this commonality was not well optimized. Nor do all the checks seem necessary. Since I want to do a similar thing for vcmpps/pd/ss/sd which have 32 immediate values and 3 encoding flavors, 3 register sizes, etc. This didn't seem to scale well for clang binary size. So custom printing seemed a better trade off.

I also considered just using the InstAlias for the matching and not the printing. But that seemed like it would add a lot of extra rows to the matcher table. Especially given that the 32 immediates for vpcmpps have 46 strings associated with them.

Differential Revision: https://reviews.llvm.org/D59398

llvm-svn: 356343
  • Loading branch information
topperc committed Mar 17, 2019
1 parent e30aa6a commit 12509d8
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 135 deletions.
44 changes: 31 additions & 13 deletions llvm/lib/Target/X86/AsmParser/X86AsmParser.cpp
Expand Up @@ -2414,13 +2414,15 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
}
}

unsigned ComparisonCode = ~0U;

// FIXME: Hack to recognize vpcom<comparison code>{ub,uw,ud,uq,b,w,d,q}.
if (PatchedName.startswith("vpcom") &&
(PatchedName.endswith("b") || PatchedName.endswith("w") ||
PatchedName.endswith("d") || PatchedName.endswith("q"))) {
unsigned CCIdx = PatchedName.drop_back().back() == 'u' ? 2 : 1;
unsigned ComparisonCode = StringSwitch<unsigned>(
PatchedName.slice(5, PatchedName.size() - CCIdx))
(PatchedName.back() == 'b' || PatchedName.back() == 'w' ||
PatchedName.back() == 'd' || PatchedName.back() == 'q')) {
unsigned SuffixSize = PatchedName.drop_back().back() == 'u' ? 2 : 1;
unsigned CC = StringSwitch<unsigned>(
PatchedName.slice(5, PatchedName.size() - SuffixSize))
.Case("lt", 0x0)
.Case("le", 0x1)
.Case("gt", 0x2)
Expand All @@ -2430,14 +2432,16 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
.Case("false", 0x6)
.Case("true", 0x7)
.Default(~0U);
if (ComparisonCode != ~0U) {
Operands.push_back(X86Operand::CreateToken("vpcom", NameLoc));

const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode,
getParser().getContext());
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));

PatchedName = PatchedName.substr(PatchedName.size() - CCIdx);
if (CC != ~0U) {
switch (PatchedName.back()) {
default: llvm_unreachable("Unexpected character!");
case 'b': PatchedName = SuffixSize == 2 ? "vpcomub" : "vpcomb"; break;
case 'w': PatchedName = SuffixSize == 2 ? "vpcomuw" : "vpcomw"; break;
case 'd': PatchedName = SuffixSize == 2 ? "vpcomud" : "vpcomd"; break;
case 'q': PatchedName = SuffixSize == 2 ? "vpcomuq" : "vpcomq"; break;
}
// Set up the immediate to push into the operands later.
ComparisonCode = CC;
}
}

Expand Down Expand Up @@ -2510,6 +2514,13 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,

Operands.push_back(X86Operand::CreateToken(PatchedName, NameLoc));

// Push the immediate if we extracted one from the mnemonic.
if (ComparisonCode != ~0U && !isParsingIntelSyntax()) {
const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode,
getParser().getContext());
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
}

// This does the actual operand parsing. Don't parse any more if we have a
// prefix juxtaposed with an operation like "lock incl 4(%rax)", because we
// just want to parse the "lock" as the first instruction and the "incl" as
Expand Down Expand Up @@ -2544,6 +2555,13 @@ bool X86AsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
return TokError("unexpected token in argument list");
}

// Push the immediate if we extracted one from the mnemonic.
if (ComparisonCode != ~0U && isParsingIntelSyntax()) {
const MCExpr *ImmOp = MCConstantExpr::create(ComparisonCode,
getParser().getContext());
Operands.push_back(X86Operand::CreateImm(ImmOp, NameLoc, NameLoc));
}

// Consume the EndOfStatement or the prefix separator Slash
if (getLexer().is(AsmToken::EndOfStatement) ||
(isPrefix && getLexer().is(AsmToken::Slash)))
Expand Down
16 changes: 0 additions & 16 deletions llvm/lib/Target/X86/Disassembler/X86Disassembler.cpp
Expand Up @@ -459,22 +459,6 @@ static void translateImmediate(MCInst &mcInst, uint64_t immediate,
case X86::CMPSDrr: NewOpc = X86::CMPSDrr_alt; break;
case X86::CMPSSrm: NewOpc = X86::CMPSSrm_alt; break;
case X86::CMPSSrr: NewOpc = X86::CMPSSrr_alt; break;
case X86::VPCOMBri: NewOpc = X86::VPCOMBri_alt; break;
case X86::VPCOMBmi: NewOpc = X86::VPCOMBmi_alt; break;
case X86::VPCOMWri: NewOpc = X86::VPCOMWri_alt; break;
case X86::VPCOMWmi: NewOpc = X86::VPCOMWmi_alt; break;
case X86::VPCOMDri: NewOpc = X86::VPCOMDri_alt; break;
case X86::VPCOMDmi: NewOpc = X86::VPCOMDmi_alt; break;
case X86::VPCOMQri: NewOpc = X86::VPCOMQri_alt; break;
case X86::VPCOMQmi: NewOpc = X86::VPCOMQmi_alt; break;
case X86::VPCOMUBri: NewOpc = X86::VPCOMUBri_alt; break;
case X86::VPCOMUBmi: NewOpc = X86::VPCOMUBmi_alt; break;
case X86::VPCOMUWri: NewOpc = X86::VPCOMUWri_alt; break;
case X86::VPCOMUWmi: NewOpc = X86::VPCOMUWmi_alt; break;
case X86::VPCOMUDri: NewOpc = X86::VPCOMUDri_alt; break;
case X86::VPCOMUDmi: NewOpc = X86::VPCOMUDmi_alt; break;
case X86::VPCOMUQri: NewOpc = X86::VPCOMUQri_alt; break;
case X86::VPCOMUQmi: NewOpc = X86::VPCOMUQmi_alt; break;
}
// Switch opcode to the one that doesn't get special printing.
mcInst.setOpcode(NewOpc);
Expand Down
44 changes: 43 additions & 1 deletion llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.cpp
Expand Up @@ -67,13 +67,55 @@ void X86ATTInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
OS << "\tdata32";
}
// Try to print any aliases first.
else if (!printAliasInstr(MI, OS))
else if (!printAliasInstr(MI, OS) &&
!printVecCompareInstr(MI, OS))
printInstruction(MI, OS);

// Next always print the annotation.
printAnnotation(OS, Annot);
}

bool X86ATTInstPrinter::printVecCompareInstr(const MCInst *MI,
raw_ostream &OS) {
if (MI->getNumOperands() == 0 ||
!MI->getOperand(MI->getNumOperands() - 1).isImm())
return false;

unsigned Imm = MI->getOperand(MI->getNumOperands() - 1).getImm();

const MCInstrDesc &Desc = MII.get(MI->getOpcode());

// Custom print the vector compare instructions to get the immediate
// translated into the mnemonic.
switch (MI->getOpcode()) {
case X86::VPCOMBmi: case X86::VPCOMBri:
case X86::VPCOMDmi: case X86::VPCOMDri:
case X86::VPCOMQmi: case X86::VPCOMQri:
case X86::VPCOMUBmi: case X86::VPCOMUBri:
case X86::VPCOMUDmi: case X86::VPCOMUDri:
case X86::VPCOMUQmi: case X86::VPCOMUQri:
case X86::VPCOMUWmi: case X86::VPCOMUWri:
case X86::VPCOMWmi: case X86::VPCOMWri:
if (Imm >= 0 && Imm <= 7) {
printVPCOMMnemonic(MI, OS);

if ((Desc.TSFlags & X86II::FormMask) == X86II::MRMSrcMem)
printi128mem(MI, 2, OS);
else
printOperand(MI, 2, OS);

OS << ", ";
printOperand(MI, 1, OS);
OS << ", ";
printOperand(MI, 0, OS);
return true;
}
break;
}

return false;
}

void X86ATTInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/X86/InstPrinter/X86ATTInstPrinter.h
Expand Up @@ -26,6 +26,7 @@ class X86ATTInstPrinter final : public X86InstPrinterCommon {
void printRegName(raw_ostream &OS, unsigned RegNo) const override;
void printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot,
const MCSubtargetInfo &STI) override;
bool printVecCompareInstr(const MCInst *MI, raw_ostream &OS);

// Autogenerated by tblgen, returns true if we successfully printed an
// alias.
Expand Down
38 changes: 26 additions & 12 deletions llvm/lib/Target/X86/InstPrinter/X86InstPrinterCommon.cpp
Expand Up @@ -64,19 +64,33 @@ void X86InstPrinterCommon::printSSEAVXCC(const MCInst *MI, unsigned Op,
}
}

void X86InstPrinterCommon::printXOPCC(const MCInst *MI, unsigned Op,
raw_ostream &O) {
int64_t Imm = MI->getOperand(Op).getImm();
void X86InstPrinterCommon::printVPCOMMnemonic(const MCInst *MI,
raw_ostream &OS) {
OS << "vpcom";

int64_t Imm = MI->getOperand(MI->getNumOperands() - 1).getImm();
switch (Imm) {
default: llvm_unreachable("Invalid xopcc argument!");
case 0: O << "lt"; break;
case 1: O << "le"; break;
case 2: O << "gt"; break;
case 3: O << "ge"; break;
case 4: O << "eq"; break;
case 5: O << "neq"; break;
case 6: O << "false"; break;
case 7: O << "true"; break;
default: llvm_unreachable("Invalid vpcom argument!");
case 0: OS << "lt"; break;
case 1: OS << "le"; break;
case 2: OS << "gt"; break;
case 3: OS << "ge"; break;
case 4: OS << "eq"; break;
case 5: OS << "neq"; break;
case 6: OS << "false"; break;
case 7: OS << "true"; break;
}

switch (MI->getOpcode()) {
default: llvm_unreachable("Unexpected opcode!");
case X86::VPCOMBmi: case X86::VPCOMBri: OS << "b\t"; break;
case X86::VPCOMDmi: case X86::VPCOMDri: OS << "d\t"; break;
case X86::VPCOMQmi: case X86::VPCOMQri: OS << "q\t"; break;
case X86::VPCOMUBmi: case X86::VPCOMUBri: OS << "ub\t"; break;
case X86::VPCOMUDmi: case X86::VPCOMUDri: OS << "ud\t"; break;
case X86::VPCOMUQmi: case X86::VPCOMUQri: OS << "uq\t"; break;
case X86::VPCOMUWmi: case X86::VPCOMUWri: OS << "uw\t"; break;
case X86::VPCOMWmi: case X86::VPCOMWri: OS << "w\t"; break;
}
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/X86/InstPrinter/X86InstPrinterCommon.h
Expand Up @@ -24,7 +24,7 @@ class X86InstPrinterCommon : public MCInstPrinter {

virtual void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) = 0;
void printSSEAVXCC(const MCInst *MI, unsigned Op, raw_ostream &OS);
void printXOPCC(const MCInst *MI, unsigned Op, raw_ostream &OS);
void printVPCOMMnemonic(const MCInst *MI, raw_ostream &OS);
void printRoundingControl(const MCInst *MI, unsigned Op, raw_ostream &O);
void printPCRelImm(const MCInst *MI, unsigned OpNo, raw_ostream &O);
protected:
Expand Down
41 changes: 40 additions & 1 deletion llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.cpp
Expand Up @@ -45,7 +45,8 @@ void X86IntelInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
if (MI->getOpcode() == X86::DATA16_PREFIX &&
STI.getFeatureBits()[X86::Mode16Bit]) {
OS << "\tdata32";
} else if (!printAliasInstr(MI, OS))
} else if (!printAliasInstr(MI, OS) &&
!printVecCompareInstr(MI, OS))
printInstruction(MI, OS);

// Next always print the annotation.
Expand All @@ -56,6 +57,44 @@ void X86IntelInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
EmitAnyX86InstComments(MI, *CommentStream, MII);
}

bool X86IntelInstPrinter::printVecCompareInstr(const MCInst *MI, raw_ostream &OS) {
if (MI->getNumOperands() == 0 ||
!MI->getOperand(MI->getNumOperands() - 1).isImm())
return false;

unsigned Imm = MI->getOperand(MI->getNumOperands() - 1).getImm();

const MCInstrDesc &Desc = MII.get(MI->getOpcode());

// Custom print the vector compare instructions to get the immediate
// translated into the mnemonic.
switch (MI->getOpcode()) {
case X86::VPCOMBmi: case X86::VPCOMBri:
case X86::VPCOMDmi: case X86::VPCOMDri:
case X86::VPCOMQmi: case X86::VPCOMQri:
case X86::VPCOMUBmi: case X86::VPCOMUBri:
case X86::VPCOMUDmi: case X86::VPCOMUDri:
case X86::VPCOMUQmi: case X86::VPCOMUQri:
case X86::VPCOMUWmi: case X86::VPCOMUWri:
case X86::VPCOMWmi: case X86::VPCOMWri:
if (Imm >= 0 && Imm <= 7) {
printVPCOMMnemonic(MI, OS);
printOperand(MI, 0, OS);
OS << ", ";
printOperand(MI, 1, OS);
OS << ", ";
if ((Desc.TSFlags & X86II::FormMask) == X86II::MRMSrcMem)
printi128mem(MI, 2, OS);
else
printOperand(MI, 2, OS);
return true;
}
break;
}

return false;
}

void X86IntelInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const MCOperand &Op = MI->getOperand(OpNo);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/X86/InstPrinter/X86IntelInstPrinter.h
Expand Up @@ -27,6 +27,7 @@ class X86IntelInstPrinter final : public X86InstPrinterCommon {
void printRegName(raw_ostream &OS, unsigned RegNo) const override;
void printInst(const MCInst *MI, raw_ostream &OS, StringRef Annot,
const MCSubtargetInfo &STI) override;
bool printVecCompareInstr(const MCInst *MI, raw_ostream &OS);

// Autogenerated by tblgen, returns true if we successfully printed an
// alias.
Expand Down
5 changes: 0 additions & 5 deletions llvm/lib/Target/X86/X86InstrInfo.td
Expand Up @@ -617,11 +617,6 @@ def AVX512ICC : Operand<i8> {
let OperandType = "OPERAND_IMMEDIATE";
}

def XOPCC : Operand<i8> {
let PrintMethod = "printXOPCC";
let OperandType = "OPERAND_IMMEDIATE";
}

class ImmSExtAsmOperandClass : AsmOperandClass {
let SuperClasses = [ImmAsmOperand];
let RenderMethod = "addImmOperands";
Expand Down
26 changes: 6 additions & 20 deletions llvm/lib/Target/X86/X86InstrXOP.td
Expand Up @@ -246,36 +246,22 @@ multiclass xopvpcom<bits<8> opc, string Suffix, SDNode OpNode, ValueType vt128,
let ExeDomain = SSEPackedInt in { // SSE integer instructions
let isCommutable = 1 in
def ri : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, XOPCC:$cc),
!strconcat("vpcom${cc}", Suffix,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
(ins VR128:$src1, VR128:$src2, u8imm:$cc),
!strconcat("vpcom", Suffix,
"\t{$cc, $src2, $src1, $dst|$dst, $src1, $src2, $cc}"),
[(set VR128:$dst,
(vt128 (OpNode (vt128 VR128:$src1), (vt128 VR128:$src2),
imm:$cc)))]>,
XOP_4V, Sched<[sched]>;
def mi : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, i128mem:$src2, XOPCC:$cc),
!strconcat("vpcom${cc}", Suffix,
"\t{$src2, $src1, $dst|$dst, $src1, $src2}"),
(ins VR128:$src1, i128mem:$src2, u8imm:$cc),
!strconcat("vpcom", Suffix,
"\t{$cc, $src2, $src1, $dst|$dst, $src1, $src2, $cc}"),
[(set VR128:$dst,
(vt128 (OpNode (vt128 VR128:$src1),
(vt128 (load addr:$src2)),
imm:$cc)))]>,
XOP_4V, Sched<[sched.Folded, sched.ReadAfterFold]>;
let isAsmParserOnly = 1, hasSideEffects = 0 in {
def ri_alt : IXOPi8<opc, MRMSrcReg, (outs VR128:$dst),
(ins VR128:$src1, VR128:$src2, u8imm:$src3),
!strconcat("vpcom", Suffix,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[]>, XOP_4V, Sched<[sched]>, NotMemoryFoldable;
let mayLoad = 1 in
def mi_alt : IXOPi8<opc, MRMSrcMem, (outs VR128:$dst),
(ins VR128:$src1, i128mem:$src2, u8imm:$src3),
!strconcat("vpcom", Suffix,
"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}"),
[]>, XOP_4V, Sched<[sched.Folded, sched.ReadAfterFold]>,
NotMemoryFoldable;
}
}

def : Pat<(OpNode (load addr:$src2),
Expand Down

0 comments on commit 12509d8

Please sign in to comment.