generalize alias support to allow the result of an alias to

add fixed immediate values.  Move the aad and aam aliases to
use this, and document it.

llvm-svn: 118350
This commit is contained in:
Chris Lattner 2010-11-06 19:25:43 +00:00
parent 161bf7de25
commit b6f8e8248d
6 changed files with 100 additions and 43 deletions

View File

@ -1998,7 +1998,15 @@ def : InstAlias<"clrq $reg", (XOR64rr GR64:$reg, GR64:$reg)>;
<p>This example also shows that tied operands are only listed once. In the X86
backend, XOR8rr has two input GR8's and one output GR8 (where an input is tied
to the output). InstAliases take a flattened operand list without duplicates
for tied operands.</p>
for tied operands. The result of an instruction alias can also use immediates,
which are added as simple immediate operands in the result, for example:</p>
<div class="doc_code">
<pre>
def : InstAlias&lt;"aad", (AAD8i8 10)&gt;;
</pre>
</div>
<p>Instruction aliases can also have a Requires clause to make them
subtarget specific.</p>

View File

@ -752,6 +752,22 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
if (getLexer().is(AsmToken::EndOfStatement))
Parser.Lex(); // Consume the EndOfStatement
// This is a terrible hack to handle "out[bwl]? %al, (%dx)" ->
// "outb %al, %dx". Out doesn't take a memory form, but this is a widely
// documented form in various unofficial manuals, so a lot of code uses it.
if ((Name == "outb" || Name == "outw" || Name == "outl" || Name == "out") &&
Operands.size() == 3) {
X86Operand &Op = *(X86Operand*)Operands.back();
if (Op.isMem() && Op.Mem.SegReg == 0 &&
isa<MCConstantExpr>(Op.Mem.Disp) &&
cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
SMLoc Loc = Op.getEndLoc();
Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
delete &Op;
}
}
// FIXME: Hack to handle recognize s{hr,ar,hl} $1, <op>. Canonicalize to
// "shift <op>".
if ((Name.startswith("shr") || Name.startswith("sar") ||
@ -781,20 +797,6 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
X86Operand::CreateImm(One, NameLoc, NameLoc));
}
// FIXME: Hack to handle "out[bwl]? %al, (%dx)" -> "outb %al, %dx".
if ((Name == "outb" || Name == "outw" || Name == "outl" || Name == "out") &&
Operands.size() == 3) {
X86Operand &Op = *(X86Operand*)Operands.back();
if (Op.isMem() && Op.Mem.SegReg == 0 &&
isa<MCConstantExpr>(Op.Mem.Disp) &&
cast<MCConstantExpr>(Op.Mem.Disp)->getValue() == 0 &&
Op.Mem.BaseReg == MatchRegisterName("dx") && Op.Mem.IndexReg == 0) {
SMLoc Loc = Op.getEndLoc();
Operands.back() = X86Operand::CreateReg(Op.Mem.BaseReg, Loc, Loc);
delete &Op;
}
}
// FIXME: Hack to handle "f{mul*,add*,sub*,div*} $op, st(0)" the same as
// "f{mul*,add*,sub*,div*} $op"
if ((Name.startswith("fmul") || Name.startswith("fadd") ||
@ -839,13 +841,6 @@ ParseInstruction(StringRef Name, SMLoc NameLoc,
NameLoc, NameLoc));
}
// FIXME: Hack to handle recognize "aa[dm]" -> "aa[dm] $0xA".
if ((Name.startswith("aad") || Name.startswith("aam")) &&
Operands.size() == 1) {
const MCExpr *A = MCConstantExpr::Create(0xA, getParser().getContext());
Operands.push_back(X86Operand::CreateImm(A, NameLoc, NameLoc));
}
return false;
}

View File

@ -1367,6 +1367,10 @@ defm : IntegerCondCodeMnemonicAlias<"cmov", "q">;
// Assembler Instruction Aliases
//===----------------------------------------------------------------------===//
// aad/aam default to base 10 if no operand is specified.
def : InstAlias<"aad", (AAD8i8 10)>;
def : InstAlias<"aam", (AAM8i8 10)>;
// clr aliases.
def : InstAlias<"clrb $reg", (XOR8rr GR8 :$reg, GR8 :$reg)>;
def : InstAlias<"clrw $reg", (XOR16rr GR16:$reg, GR16:$reg)>;

View File

@ -270,7 +270,11 @@ struct MatchableInfo {
/// TiedOperand - This represents a result operand that is a duplicate of
/// a previous result operand.
TiedOperand
TiedOperand,
/// ImmOperand - This represents an immediate value that is dumped into
/// the operand.
ImmOperand
} Kind;
union {
@ -281,6 +285,9 @@ struct MatchableInfo {
/// TiedOperandNum - This is the (earlier) result operand that should be
/// copied from.
unsigned TiedOperandNum;
/// ImmVal - This is the immediate value added to the instruction.
int64_t ImmVal;
};
/// OpInfo - This is the information about the instruction operand that is
@ -304,6 +311,15 @@ struct MatchableInfo {
X.OpInfo = Op;
return X;
}
static ResOperand getImmOp(int64_t Val,
const CGIOperandList::OperandInfo *Op) {
ResOperand X;
X.Kind = ImmOperand;
X.ImmVal = Val;
X.OpInfo = Op;
return X;
}
};
/// TheDef - This is the definition of the instruction or InstAlias that this
@ -538,16 +554,6 @@ void MatchableInfo::dump() {
AsmOperand &Op = AsmOperands[i];
errs() << " op[" << i << "] = " << Op.Class->ClassName << " - ";
errs() << '\"' << Op.Token << "\"\n";
#if 0
if (!Op.OperandInfo) {
errs() << "(singleton register)\n";
continue;
}
const CGIOperandList::OperandInfo &OI = *Op.OperandInfo;
errs() << OI.Name << " " << OI.Rec->getName()
<< " (" << OI.MIOperandNo << ", " << OI.MINumOperands << ")\n";
#endif
}
}
@ -1174,7 +1180,8 @@ void AsmMatcherInfo::BuildAliasOperandReference(MatchableInfo *II,
// Set up the operand class.
for (unsigned i = 0, e = CGA.ResultOperands.size(); i != e; ++i)
if (CGA.ResultOperands[i].Name == OperandName) {
if (CGA.ResultOperands[i].isRecord() &&
CGA.ResultOperands[i].getName() == OperandName) {
// It's safe to go with the first one we find, because CodeGenInstAlias
// validates that all operands with the same name have the same record.
unsigned ResultIdx =CGA.getResultInstOperandIndexForResultOperandIndex(i);
@ -1236,15 +1243,22 @@ void MatchableInfo::BuildAliasResultOperands() {
// Find out what operand from the asmparser that this MCInst operand comes
// from.
int SrcOperand = FindAsmOperandNamed(CGA.ResultOperands[AliasOpNo++].Name);
if (SrcOperand != -1) {
ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
continue;
if (CGA.ResultOperands[AliasOpNo].isRecord()) {
StringRef Name = CGA.ResultOperands[AliasOpNo++].getName();
int SrcOperand = FindAsmOperandNamed(Name);
if (SrcOperand != -1) {
ResOperands.push_back(ResOperand::getRenderedOp(SrcOperand, &OpInfo));
continue;
}
throw TGError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpInfo.Name +
"' that doesn't appear in asm string!");
}
throw TGError(TheDef->getLoc(), "Instruction '" +
TheDef->getName() + "' has operand '" + OpInfo.Name +
"' that doesn't appear in asm string!");
int64_t ImmVal = CGA.ResultOperands[AliasOpNo++].getImm();
ResOperands.push_back(ResOperand::getImmOp(ImmVal, &OpInfo));
continue;
}
}
@ -1291,7 +1305,6 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
// Generate code to populate each result operand.
switch (OpInfo.Kind) {
default: assert(0 && "Unknown result operand kind");
case MatchableInfo::ResOperand::RenderAsmOperand: {
// This comes from something we parsed.
MatchableInfo::AsmOperand &Op = II.AsmOperands[OpInfo.AsmOperandNum];
@ -1322,6 +1335,12 @@ static void EmitConvertToMCInst(CodeGenTarget &Target,
Signature += "__Tie" + utostr(TiedOp);
break;
}
case MatchableInfo::ResOperand::ImmOperand: {
int64_t Val = OpInfo.ImmVal;
CaseOS << " Inst.addOperand(MCOperand::CreateImm(" << Val << "));\n";
Signature += "__imm" + itostr(Val);
break;
}
}
}

View File

@ -449,6 +449,21 @@ CodeGenInstAlias::CodeGenInstAlias(Record *R, CodeGenTarget &T) : TheDef(R) {
++AliasOpNo;
continue;
}
if (IntInit *II = dynamic_cast<IntInit*>(Arg)) {
// Integer arguments can't have names.
if (!Result->getArgName(AliasOpNo).empty())
throw TGError(R->getLoc(), "result argument #" + utostr(AliasOpNo) +
" must not have a name!");
if (ResultInst->Operands[i].MINumOperands != 1 ||
!ResultInst->Operands[i].Rec->isSubClassOf("Operand"))
throw TGError(R->getLoc(), "invalid argument class " +
ResultInst->Operands[i].Rec->getName() +
" for integer result operand!");
ResultOperands.push_back(ResultOperand(II->getValue()));
++AliasOpNo;
continue;
}
throw TGError(R->getLoc(), "result of inst alias has unknown operand type");
}

View File

@ -267,10 +267,26 @@ namespace llvm {
struct ResultOperand {
private:
StringRef Name;
Record *R;
ResultOperand(StringRef N, Record *r) : Name(N), R(r) {}
int64_t Imm;
public:
enum {
K_Record,
K_Imm
} Kind;
ResultOperand(StringRef N, Record *r) : Name(N), R(r), Kind(K_Record) {}
ResultOperand(int64_t I) : Imm(I), Kind(K_Imm) {}
bool isRecord() const { return Kind == K_Record; }
bool isImm() const { return Kind == K_Imm; }
StringRef getName() const { assert(isRecord()); return Name; }
Record *getRecord() const { assert(isRecord()); return R; }
int64_t getImm() const { assert(isImm()); return Imm; }
};
/// ResultOperands - The decoded operands for the result instruction.