82 changes: 62 additions & 20 deletions llvm/utils/TableGen/CodeEmitterGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,8 @@ class CodeEmitterGen {
std::string getInstructionCase(Record *R, CodeGenTarget &Target);
std::string getInstructionCaseForEncoding(Record *R, Record *EncodingDef,
CodeGenTarget &Target);
void AddCodeToMergeInOperand(Record *R, BitsInit *BI,
const std::string &VarName,
unsigned &NumberedOp,
bool addCodeToMergeInOperand(Record *R, BitsInit *BI,
const std::string &VarName, unsigned &NumberedOp,
std::set<unsigned> &NamedOpIndices,
std::string &Case, CodeGenTarget &Target);

Expand All @@ -79,11 +78,13 @@ int CodeEmitterGen::getVariableBit(const std::string &VarName,
return -1;
}

void CodeEmitterGen::
AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
unsigned &NumberedOp,
std::set<unsigned> &NamedOpIndices,
std::string &Case, CodeGenTarget &Target) {
// Returns true if it succeeds, false if an error.
bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
const std::string &VarName,
unsigned &NumberedOp,
std::set<unsigned> &NamedOpIndices,
std::string &Case,
CodeGenTarget &Target) {
CodeGenInstruction &CGI = Target.getInstruction(R);

// Determine if VarName actually contributes to the Inst encoding.
Expand All @@ -99,18 +100,29 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,

// If we found no bits, ignore this value, otherwise emit the call to get the
// operand encoding.
if (bit < 0) return;

if (bit < 0)
return true;

// If the operand matches by name, reference according to that
// operand number. Non-matching operands are assumed to be in
// order.
unsigned OpIdx;
if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
std::pair<unsigned, unsigned> SubOp;
if (CGI.Operands.hasSubOperandAlias(VarName, SubOp)) {
OpIdx = CGI.Operands[SubOp.first].MIOperandNo + SubOp.second;
} else if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
// Get the machine operand number for the indicated operand.
OpIdx = CGI.Operands[OpIdx].MIOperandNo;
assert(!CGI.Operands.isFlatOperandNotEmitted(OpIdx) &&
"Explicitly used operand also marked as not emitted!");
} else {
// Fall back to positional lookup. By default, we now disable positional
// lookup (and print an error, below), but even so, we'll do the lookup to
// help print a helpful diagnostic message.
//
// TODO: When we remove useDeprecatedPositionallyEncodedOperands, delete all
// this code, just leaving a "no operand named X in record Y" error.

unsigned NumberOps = CGI.Operands.size();
/// If this operand is not supposed to be emitted by the
/// generated emitter, skip it.
Expand All @@ -123,17 +135,35 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,

if (NumberedOp >=
CGI.Operands.back().MIOperandNo + CGI.Operands.back().MINumOperands) {
std::string E;
raw_string_ostream S(E);
S << "Too few operands in record " << R->getName()
<< " (no match for variable " << VarName << "):\n";
S << *R;
PrintFatalError(R, E);
if (!Target.getInstructionSet()->getValueAsBit(
"useDeprecatedPositionallyEncodedOperands")) {
PrintError(R, Twine("No operand named ") + VarName + " in record " +
R->getName() +
" (would've given 'too few operands' error with "
"useDeprecatedPositionallyEncodedOperands=true)");
} else {
PrintError(R, "Too few operands in record " + R->getName() +
" (no match for variable " + VarName + ")");
}
return false;
}

OpIdx = NumberedOp++;

if (!Target.getInstructionSet()->getValueAsBit(
"useDeprecatedPositionallyEncodedOperands")) {
std::pair<unsigned, unsigned> SO =
CGI.Operands.getSubOperandNumber(OpIdx);
std::string OpName = CGI.Operands[SO.first].Name;
PrintError(R, Twine("No operand named ") + VarName + " in record " +
R->getName() + " (would've used positional operand #" +
Twine(SO.first) + " ('" + OpName + "') sub-op #" +
Twine(SO.second) +
" with useDeprecatedPositionallyEncodedOperands=true)");
return false;
}
}

std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
std::string &EncoderMethodName = CGI.Operands[SO.first].EncoderMethodName;

Expand Down Expand Up @@ -263,6 +293,7 @@ AddCodeToMergeInOperand(Record *R, BitsInit *BI, const std::string &VarName,
}
}
}
return true;
}

std::string CodeEmitterGen::getInstructionCase(Record *R,
Expand Down Expand Up @@ -310,14 +341,25 @@ std::string CodeEmitterGen::getInstructionCaseForEncoding(Record *R, Record *Enc

// Loop over all of the fields in the instruction, determining which are the
// operands to the instruction.
bool Success = true;
for (const RecordVal &RV : EncodingDef->getValues()) {
// Ignore fixed fields in the record, we're looking for values like:
// bits<5> RST = { ?, ?, ?, ?, ? };
if (RV.isNonconcreteOK() || RV.getValue()->isComplete())
continue;

AddCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
NamedOpIndices, Case, Target);
Success &=
addCodeToMergeInOperand(R, BI, std::string(RV.getName()), NumberedOp,
NamedOpIndices, Case, Target);
}

if (!Success) {
// Dump the record, so we can see what's going on...
std::string E;
raw_string_ostream S(E);
S << "Dumping record for previous error:\n";
S << *R;
PrintNote(E);
}

StringRef PostEmitter = R->getValueAsString("PostEncoderMethod");
Expand Down
61 changes: 60 additions & 1 deletion llvm/utils/TableGen/CodeGenInstruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
ArgName = InDI->getArgNameStr(i-NumDefs);
}

DagInit *SubArgDag = dyn_cast<DagInit>(ArgInit);
if (SubArgDag)
ArgInit = SubArgDag->getOperator();

DefInit *Arg = dyn_cast<DefInit>(ArgInit);
if (!Arg)
PrintFatalError(R->getLoc(), "Illegal operand for the '" + R->getName() +
Expand Down Expand Up @@ -132,6 +136,36 @@ CGIOperandList::CGIOperandList(Record *R) : TheDef(R) {
Twine(i) +
" has the same name as a previous operand!");

if (SubArgDag) {
if (SubArgDag->getNumArgs() != NumOps) {
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
"', operand #" + Twine(i) + " has " +
Twine(SubArgDag->getNumArgs()) +
" sub-arg names, expected " +
Twine(NumOps) + ".");
}

for (unsigned j = 0; j < NumOps; ++j) {
if (!isa<UnsetInit>(SubArgDag->getArg(j)))
PrintFatalError(R->getLoc(),
"In instruction '" + R->getName() + "', operand #" +
Twine(i) + " sub-arg #" + Twine(j) +
" has unexpected operand (expected only $name).");

StringRef SubArgName = SubArgDag->getArgNameStr(j);
if (SubArgName.empty())
PrintFatalError(R->getLoc(), "In instruction '" + R->getName() +
"', operand #" + Twine(i) +
" has no name!");
if (!OperandNames.insert(std::string(SubArgName)).second)
PrintFatalError(R->getLoc(),
"In instruction '" + R->getName() + "', operand #" +
Twine(i) + " sub-arg #" + Twine(j) +
" has the same name as a previous operand!");
SubOpAliases[SubArgName] = std::make_pair(MIOperandNo, j);
}
}

OperandList.emplace_back(
Rec, std::string(ArgName), std::string(PrintMethod),
std::string(EncoderMethod), OperandNamespace + "::" + OperandType,
Expand Down Expand Up @@ -175,6 +209,17 @@ bool CGIOperandList::hasOperandNamed(StringRef Name, unsigned &OpIdx) const {
return false;
}

bool CGIOperandList::hasSubOperandAlias(
StringRef Name, std::pair<unsigned, unsigned> &SubOp) const {
assert(!Name.empty() && "Cannot search for operand with no name!");
auto SubOpIter = SubOpAliases.find(Name);
if (SubOpIter != SubOpAliases.end()) {
SubOp = SubOpIter->second;
return true;
}
return false;
}

std::pair<unsigned,unsigned>
CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
if (Op.empty() || Op[0] != '$')
Expand All @@ -195,7 +240,21 @@ CGIOperandList::ParseOperandName(StringRef Op, bool AllowWholeOp) {
OpName = OpName.substr(0, DotIdx);
}

unsigned OpIdx = getOperandNamed(OpName);
unsigned OpIdx;

if (std::pair<unsigned, unsigned> SubOp; hasSubOperandAlias(OpName, SubOp)) {
// Found a name for a piece of an operand, just return it directly.
if (!SubOpName.empty()) {
PrintFatalError(
TheDef->getLoc(),
TheDef->getName() +
": Cannot use dotted suboperand name within suboperand '" +
OpName + "'");
}
return SubOp;
}

OpIdx = getOperandNamed(OpName);

if (SubOpName.empty()) { // If no suboperand name was specified:
// If one was needed, throw.
Expand Down
7 changes: 7 additions & 0 deletions llvm/utils/TableGen/CodeGenInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define LLVM_UTILS_TABLEGEN_CODEGENINSTRUCTION_H

#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MachineValueType.h"
#include <cassert>
Expand Down Expand Up @@ -149,6 +150,9 @@ template <typename T> class ArrayRef;
/// type (which is a record).
std::vector<OperandInfo> OperandList;

/// SubOpAliases - List of alias names for suboperands.
StringMap<std::pair<unsigned, unsigned>> SubOpAliases;

// Information gleaned from the operand list.
bool isPredicable;
bool hasOptionalDef;
Expand Down Expand Up @@ -179,6 +183,9 @@ template <typename T> class ArrayRef;
/// operand. Otherwise, return false.
bool hasOperandNamed(StringRef Name, unsigned &OpIdx) const;

bool hasSubOperandAlias(StringRef Name,
std::pair<unsigned, unsigned> &SubOp) const;

/// ParseOperandName - Parse an operand name like "$foo" or "$foo.bar",
/// where $foo is a whole operand and $foo.bar refers to a suboperand.
/// This aborts if the name is invalid. If AllowWholeOp is true, references
Expand Down
65 changes: 37 additions & 28 deletions llvm/utils/TableGen/DecoderEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1982,8 +1982,12 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,
} else {
std::map<std::string, std::vector<OperandInfo>> NumberedInsnOperands;
std::set<std::string> NumberedInsnOperandsNoTie;
if (Target.getInstructionSet()->getValueAsBit(
"decodePositionallyEncodedOperands")) {
bool SupportPositionalDecoding =
Target.getInstructionSet()->getValueAsBit(
"useDeprecatedPositionallyEncodedOperands") &&
Target.getInstructionSet()->getValueAsBit(
"decodePositionallyEncodedOperands");
if (SupportPositionalDecoding) {
const std::vector<RecordVal> &Vals = Def.getValues();
unsigned NumberedOp = 0;

Expand Down Expand Up @@ -2127,40 +2131,45 @@ populateInstruction(CodeGenTarget &Target, const Record &EncodingDef,

// For each operand, see if we can figure out where it is encoded.
for (const auto &Op : InOutOperands) {
if (!NumberedInsnOperands[std::string(Op.second)].empty()) {
llvm::append_range(InsnOperands,
NumberedInsnOperands[std::string(Op.second)]);
continue;
}
if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) {
if (!NumberedInsnOperandsNoTie.count(
TiedNames[std::string(Op.second)])) {
// Figure out to which (sub)operand we're tied.
unsigned i =
CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]);
int tiedTo = CGI.Operands[i].getTiedRegister();
if (tiedTo == -1) {
i = CGI.Operands.getOperandNamed(Op.second);
tiedTo = CGI.Operands[i].getTiedRegister();
}

if (tiedTo != -1) {
std::pair<unsigned, unsigned> SO =
CGI.Operands.getSubOperandNumber(tiedTo);

InsnOperands.push_back(
NumberedInsnOperands[TiedNames[std::string(Op.second)]]
[SO.second]);
if (SupportPositionalDecoding) {
if (!NumberedInsnOperands[std::string(Op.second)].empty()) {
llvm::append_range(InsnOperands,
NumberedInsnOperands[std::string(Op.second)]);
continue;
}
if (!NumberedInsnOperands[TiedNames[std::string(Op.second)]].empty()) {
if (!NumberedInsnOperandsNoTie.count(
TiedNames[std::string(Op.second)])) {
// Figure out to which (sub)operand we're tied.
unsigned i =
CGI.Operands.getOperandNamed(TiedNames[std::string(Op.second)]);
int tiedTo = CGI.Operands[i].getTiedRegister();
if (tiedTo == -1) {
i = CGI.Operands.getOperandNamed(Op.second);
tiedTo = CGI.Operands[i].getTiedRegister();
}

if (tiedTo != -1) {
std::pair<unsigned, unsigned> SO =
CGI.Operands.getSubOperandNumber(tiedTo);

InsnOperands.push_back(
NumberedInsnOperands[TiedNames[std::string(Op.second)]]
[SO.second]);
}
}
continue;
}
continue;
}

// At this point, we can locate the decoder field, but we need to know how
// to interpret it. As a first step, require the target to provide
// callbacks for decoding register classes.

OperandInfo OpInfo = getOpInfo(cast<DefInit>(Op.first)->getDef());
Init *OpInit = Op.first;
if (DagInit *Dag = dyn_cast<DagInit>(OpInit))
OpInit = Dag->getOperator();
OperandInfo OpInfo = getOpInfo(cast<DefInit>(OpInit)->getDef());

// Some bits of the operand may be required to be 1 depending on the
// instruction's encoding. Collect those bits.
Expand Down