[TableGen] Support to set operand custom flag by CustomConstraints.
Summary: [TableGen] Support to set operand custom flag by CustomConstraints. Test Plan: llvm/test/TableGen/ConstraintChecking8.td Reviewers: zhoujing Reviewed By: zhoujing Differential Revision: http://www.tpt.com/D636
This commit is contained in:
parent
e3ecedc1a5
commit
3685ef10e0
|
@ -33,16 +33,10 @@ namespace MCOI {
|
|||
/// This allows for a maximum of 3 constraints.
|
||||
enum OperandConstraint {
|
||||
TIED_TO = 0, // Must be allocated the same register as specified value.
|
||||
CUSTOM, // Used by target custom flag
|
||||
EARLY_CLOBBER // If present, operand is an early clobber register.
|
||||
};
|
||||
|
||||
// Define a macro to produce each constraint value.
|
||||
#define MCOI_TIED_TO(op) \
|
||||
((1 << MCOI::TIED_TO) | ((op) << (4 + MCOI::TIED_TO * 4)))
|
||||
|
||||
#define MCOI_EARLY_CLOBBER \
|
||||
(1 << MCOI::EARLY_CLOBBER)
|
||||
|
||||
/// These are flags set on operands, but should be considered
|
||||
/// private, all access should go through the MCOperandInfo accessors.
|
||||
/// See the accessors for a description of what these are.
|
||||
|
|
|
@ -626,6 +626,8 @@ class Instruction : InstructionEncoding {
|
|||
|
||||
string Constraints = ""; // OperandConstraint, e.g. $src = $dst.
|
||||
|
||||
string CustomConstraints = ""; // OperandCustomConstraint, e.g. $dst = 3.
|
||||
|
||||
/// DisableEncoding - List of operand names (e.g. "$op1,$op2") that should not
|
||||
/// be encoded into the output machineinstr.
|
||||
string DisableEncoding = "";
|
||||
|
|
|
@ -15,12 +15,13 @@ def R0 : TestReg<"R0", 0>;
|
|||
def R1 : TestReg<"R1", 1>;
|
||||
def Reg : RegisterClass<"TestTarget", [i32], 32, (sequence "R%d", 0, 1)>;
|
||||
|
||||
class TestInstructionWithConstraints<string cstr> : Encoding {
|
||||
class TestInstructionWithConstraints<string cstr, string ccstr = ""> : Encoding {
|
||||
dag OutOperandList = (outs Reg:$dest1, Reg:$dest2);
|
||||
dag InOperandList = (ins Reg:$src1, Reg:$src2);
|
||||
string AsmString = "mnemonic $dest1, $dest2, $src1, $src2";
|
||||
string AsmVariantName = "";
|
||||
let Constraints = cstr;
|
||||
let CustomConstraints = ccstr;
|
||||
field bits<1> dest1;
|
||||
field bits<1> dest2;
|
||||
field bits<1> src1;
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
include "ConstraintChecking.inc"
|
||||
|
||||
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Operand '$src1' of 'Foo' cannot have multiple constraints!
|
||||
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Operand '$src1' of 'Foo' cannot have multiple tied-to constraints!
|
||||
def Foo : TestInstructionWithConstraints<"$dest1 = $src1, $dest2 = $src1">;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: not llvm-tblgen -gen-asm-writer -I %p -I %p/../../include %s 2>&1 | FileCheck %s -DFILE=%s
|
||||
|
||||
include "ConstraintChecking.inc"
|
||||
|
||||
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Illegal format custom number in range[0, 15] for custom constraint: '$dest1 = 16'
|
||||
def Foo : TestInstructionWithConstraints<"", "$dest1 = 16">;
|
|
@ -306,12 +306,11 @@ static void ParseConstraint(StringRef CStr, CGIOperandList &Ops,
|
|||
std::pair<unsigned,unsigned> Op = Ops.ParseOperandName(Name, false);
|
||||
|
||||
// Build the string for the operand
|
||||
if (!Ops[Op.first].Constraints[Op.second].isNone())
|
||||
if (Ops[Op.first].Constraints[Op.second].isEarlyClobber())
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Operand '" + Name + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple constraints!");
|
||||
Ops[Op.first].Constraints[Op.second] =
|
||||
CGIOperandList::ConstraintInfo::getEarlyClobber();
|
||||
"' cannot have multiple @earlyclobber constraints!");
|
||||
Ops[Op.first].Constraints[Op.second].setConstraint(MCOI::EARLY_CLOBBER);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -361,28 +360,66 @@ static void ParseConstraint(StringRef CStr, CGIOperandList &Ops,
|
|||
// The constraint has to go on the operand with higher index, i.e.
|
||||
// the source one. Check there isn't another constraint there
|
||||
// already.
|
||||
if (!Ops[SrcOp.first].Constraints[SrcOp.second].isNone())
|
||||
if (Ops[SrcOp.first].Constraints[SrcOp.second].isTied())
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Operand '" + SrcOpName + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple constraints!");
|
||||
"' cannot have multiple tied-to constraints!");
|
||||
|
||||
unsigned DestFlatOpNo = Ops.getFlattenedOperandNumber(DestOp);
|
||||
auto NewConstraint = CGIOperandList::ConstraintInfo::getTied(DestFlatOpNo);
|
||||
|
||||
// Check that the earlier operand is not the target of another tie
|
||||
// before making it the target of this one.
|
||||
for (const CGIOperandList::OperandInfo &Op : Ops) {
|
||||
for (unsigned i = 0; i < Op.MINumOperands; i++)
|
||||
if (Op.Constraints[i] == NewConstraint)
|
||||
if (Op.Constraints[i].getConstraint(MCOI::TIED_TO) == (int)DestFlatOpNo)
|
||||
PrintFatalError(
|
||||
Rec->getLoc(), "Operand '" + DestOpName + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple operands tied to it!");
|
||||
}
|
||||
|
||||
Ops[SrcOp.first].Constraints[SrcOp.second] = NewConstraint;
|
||||
Ops[SrcOp.first].Constraints[SrcOp.second].setConstraint(MCOI::TIED_TO,
|
||||
DestFlatOpNo);
|
||||
}
|
||||
|
||||
static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, Record *Rec) {
|
||||
static void ParseCustomConstraint(StringRef CStr, CGIOperandList &Ops,
|
||||
Record *Rec) {
|
||||
// Only custom constraint is "CUSTOM" for now.
|
||||
StringRef::size_type pos = CStr.find_first_of('=');
|
||||
if (pos == StringRef::npos)
|
||||
PrintFatalError(Rec->getLoc(), "Unrecognized custom constraint '" + CStr +
|
||||
"' in '" + Rec->getName() + "'");
|
||||
StringRef::size_type start = CStr.find_first_not_of(" \t");
|
||||
|
||||
// CUSTOM: $dst = number
|
||||
StringRef::size_type wpos = CStr.find_first_of(" \t", start);
|
||||
if (wpos == StringRef::npos || wpos > pos)
|
||||
PrintFatalError(Rec->getLoc(), "Illegal format for custom constraint in '" +
|
||||
Rec->getName() + "': '" + CStr + "'");
|
||||
StringRef Name = CStr.substr(start, wpos - start);
|
||||
std::pair<unsigned, unsigned> Op = Ops.ParseOperandName(Name, false);
|
||||
|
||||
wpos = CStr.find_first_not_of(" \t", pos + 1);
|
||||
if (wpos == StringRef::npos)
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Illegal format for custom constraint: '" + CStr + "'");
|
||||
|
||||
unsigned CustomNum;
|
||||
if (CStr.substr(wpos).consumeInteger(0, CustomNum) || CustomNum > 15)
|
||||
PrintFatalError(Rec->getLoc(), "Illegal format custom number in range[0, "
|
||||
"15] for custom constraint: '" +
|
||||
CStr + "'");
|
||||
|
||||
// Build the string for the operand
|
||||
if (Ops[Op.first].Constraints[Op.second].isCustom())
|
||||
PrintFatalError(Rec->getLoc(),
|
||||
"Operand '" + Name + "' of '" + Rec->getName() +
|
||||
"' cannot have multiple custom constraints!");
|
||||
|
||||
Ops[Op.first].Constraints[Op.second].setConstraint(MCOI::CUSTOM, CustomNum);
|
||||
}
|
||||
|
||||
static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, Record *Rec,
|
||||
bool isCustom = false) {
|
||||
if (CStr.empty()) return;
|
||||
|
||||
StringRef delims(",");
|
||||
|
@ -394,7 +431,10 @@ static void ParseConstraints(StringRef CStr, CGIOperandList &Ops, Record *Rec) {
|
|||
if (eidx == StringRef::npos)
|
||||
eidx = CStr.size();
|
||||
|
||||
ParseConstraint(CStr.substr(bidx, eidx - bidx), Ops, Rec);
|
||||
if (isCustom)
|
||||
ParseCustomConstraint(CStr.substr(bidx, eidx - bidx), Ops, Rec);
|
||||
else
|
||||
ParseConstraint(CStr.substr(bidx, eidx - bidx), Ops, Rec);
|
||||
bidx = CStr.find_first_not_of(delims, eidx);
|
||||
}
|
||||
}
|
||||
|
@ -485,6 +525,9 @@ CodeGenInstruction::CodeGenInstruction(Record *R)
|
|||
// Parse Constraints.
|
||||
ParseConstraints(R->getValueAsString("Constraints"), Operands, R);
|
||||
|
||||
// Parse CustomConstraints.
|
||||
ParseConstraints(R->getValueAsString("CustomConstraints"), Operands, R, true);
|
||||
|
||||
// Parse the DisableEncoding field.
|
||||
Operands.ProcessDisableEncoding(
|
||||
R->getValueAsString("DisableEncoding"));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/MachineValueType.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
@ -32,44 +33,43 @@ template <typename T> class ArrayRef;
|
|||
class CGIOperandList {
|
||||
public:
|
||||
class ConstraintInfo {
|
||||
enum { None, EarlyClobber, Tied } Kind = None;
|
||||
unsigned OtherTiedOperand = 0;
|
||||
uint16_t Constraints = 0;
|
||||
|
||||
public:
|
||||
ConstraintInfo() = default;
|
||||
|
||||
static ConstraintInfo getEarlyClobber() {
|
||||
ConstraintInfo I;
|
||||
I.Kind = EarlyClobber;
|
||||
I.OtherTiedOperand = 0;
|
||||
return I;
|
||||
uint16_t getConstraintsValue() const { return Constraints; }
|
||||
|
||||
/// Returns the value of the specified operand constraint if
|
||||
/// it is present. Returns -1 if it is not present.
|
||||
int getConstraint(MCOI::OperandConstraint Constraint) const {
|
||||
if (Constraints & (1 << Constraint)) {
|
||||
unsigned ValuePos = 4 + Constraint * 4;
|
||||
return (int)(Constraints >> ValuePos) & 0x0f;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ConstraintInfo getTied(unsigned Op) {
|
||||
ConstraintInfo I;
|
||||
I.Kind = Tied;
|
||||
I.OtherTiedOperand = Op;
|
||||
return I;
|
||||
void setConstraint(MCOI::OperandConstraint Constraint,
|
||||
unsigned Value = 0) {
|
||||
assert(Value <= 15 && "Out of range [0, 15] constraint value");
|
||||
assert(getConstraint(Constraint) &&
|
||||
"Cannot have multiple same constraints");
|
||||
|
||||
// Produce each constraint value.
|
||||
Constraints |= ((1 << Constraint) | (Value << (4 + Constraint * 4)));
|
||||
}
|
||||
|
||||
bool isNone() const { return Kind == None; }
|
||||
bool isEarlyClobber() const { return Kind == EarlyClobber; }
|
||||
bool isTied() const { return Kind == Tied; }
|
||||
bool isEarlyClobber() const {
|
||||
return getConstraint(MCOI::EARLY_CLOBBER) != -1;
|
||||
}
|
||||
bool isCustom() const { return getConstraint(MCOI::CUSTOM) != -1; }
|
||||
bool isTied() const { return getConstraint(MCOI::TIED_TO) != -1; }
|
||||
|
||||
unsigned getTiedOperand() const {
|
||||
assert(isTied());
|
||||
return OtherTiedOperand;
|
||||
}
|
||||
|
||||
bool operator==(const ConstraintInfo &RHS) const {
|
||||
if (Kind != RHS.Kind)
|
||||
return false;
|
||||
if (Kind == Tied && OtherTiedOperand != RHS.OtherTiedOperand)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const ConstraintInfo &RHS) const {
|
||||
return !(*this == RHS);
|
||||
int TiedOperand = getConstraint(MCOI::TIED_TO);
|
||||
assert(TiedOperand != -1);
|
||||
return (unsigned)TiedOperand;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -131,7 +131,9 @@ template <typename T> class ArrayRef;
|
|||
int getTiedRegister() const {
|
||||
for (unsigned j = 0, e = Constraints.size(); j != e; ++j) {
|
||||
const CGIOperandList::ConstraintInfo &CI = Constraints[j];
|
||||
if (CI.isTied()) return CI.getTiedOperand();
|
||||
int TiedOperand = CI.getConstraint(MCOI::TIED_TO);
|
||||
if (TiedOperand != -1)
|
||||
return TiedOperand;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -197,16 +197,7 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) {
|
|||
// Fill in constraint info.
|
||||
Res += ", ";
|
||||
|
||||
const CGIOperandList::ConstraintInfo &Constraint =
|
||||
Op.Constraints[j];
|
||||
if (Constraint.isNone())
|
||||
Res += "0";
|
||||
else if (Constraint.isEarlyClobber())
|
||||
Res += "MCOI_EARLY_CLOBBER";
|
||||
else {
|
||||
assert(Constraint.isTied());
|
||||
Res += "MCOI_TIED_TO(" + utostr(Constraint.getTiedOperand()) + ")";
|
||||
}
|
||||
Res += utostr(Op.Constraints[j].getConstraintsValue());
|
||||
|
||||
Result.push_back(Res);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue