1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 04:32:44 +01:00

[TableGen][AsmMatcherEmitter] Generate assembler checks for tied operands

Summary:
This extends TableGen's AsmMatcherEmitter with code that generates
a table with tied-operand constraints. The constraints are checked
when parsing the instruction. If an operand is not equal to its tied operand,
the assembler will give an error.

Patch [2/3] in a series to add operand constraint checks for SVE's predicated ADD/SUB.

Reviewers: olista01, rengolin, mcrosier, fhahn, craig.topper, evandro, echristo

Reviewed By: fhahn

Subscribers: javed.absar, llvm-commits

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

llvm-svn: 322166
This commit is contained in:
Sander de Smalen 2018-01-10 10:10:56 +00:00
parent 82460f15a6
commit dee11fd6e7
3 changed files with 159 additions and 0 deletions

View File

@ -271,6 +271,7 @@ class MCTargetAsmParser : public MCAsmParserExtension {
public:
enum MatchResultTy {
Match_InvalidOperand,
Match_InvalidTiedOperand,
Match_MissingFeature,
Match_MnemonicFail,
Match_Success,

View File

@ -3544,6 +3544,8 @@ static std::string AArch64MnemonicSpellCheck(StringRef S, uint64_t FBS,
bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
OperandVector &Operands) {
switch (ErrCode) {
case Match_InvalidTiedOperand:
return Error(Loc, "operand must match destination register");
case Match_MissingFeature:
return Error(Loc,
"instruction requires a CPU feature not currently enabled");
@ -4063,6 +4065,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
return showMatchError(ErrorLoc, MatchResult, Operands);
}
case Match_InvalidTiedOperand:
case Match_InvalidMemoryIndexed1:
case Match_InvalidMemoryIndexed2:
case Match_InvalidMemoryIndexed4:

View File

@ -503,6 +503,20 @@ struct MatchableInfo {
/// removed.
SmallVector<AsmOperand, 8> AsmOperands;
/// AsmOperandEqualityConstraints - an array of pairs holding operand
/// constraints.
/// Each constraint is represented as a pair holding position of the token of
/// the operand asm name.
/// For example, an "AsmString" "add $Vd.s, $Vn.s, $Xn" would be
/// split in the following list of tokens:
///
/// ['add', '$Vd', '.s', '$Vn', '.s', '$Xn']
///
/// A constraint "$Vd = $Vn" (e.g. for a destructive operation) is rendered
/// as the pair {1,3} into this set (note that tokens are numbered starting
/// from 0).
SmallVector<std::pair<unsigned,unsigned>, 1> AsmOperandTiedConstraints;
/// Predicates - The required subtarget features to match this instruction.
SmallVector<const SubtargetFeatureInfo *, 4> RequiredFeatures;
@ -885,6 +899,22 @@ extractSingletonRegisterForAsmOperand(MatchableInfo::AsmOperand &Op,
// be some random non-register token, just ignore it.
}
static Optional<size_t>
getAsmOperandIdx(const SmallVectorImpl<MatchableInfo::AsmOperand> &AsmOperands,
std::string Name) {
const auto SymbolicName = std::string("$") + Name;
const auto Pos =
std::find_if(AsmOperands.begin(), AsmOperands.end(),
[&SymbolicName](const MatchableInfo::AsmOperand &A) {
return A.Token == SymbolicName;
});
if (Pos == AsmOperands.end())
return Optional<size_t>();
return Optional<size_t>(std::distance(AsmOperands.begin(), Pos));
}
void MatchableInfo::initialize(const AsmMatcherInfo &Info,
SmallPtrSetImpl<Record*> &SingletonRegisters,
AsmVariantInfo const &Variant,
@ -933,6 +963,37 @@ void MatchableInfo::initialize(const AsmMatcherInfo &Info,
HasDeprecation =
DepMask ? !DepMask->getValue()->getAsUnquotedString().empty() : false;
// Do not generate tied operand info if the instruction does not
// use the default AsmMatchConverter.
if (TheDef->getValue("AsmMatchConverter") &&
!TheDef->getValueAsString("AsmMatchConverter").empty())
return;
// Generate tied operand contraints info.
const auto &CGIOperands = getResultInst()->Operands;
for (const auto &CGIOp : CGIOperands) {
int TiedReg = CGIOp.getTiedRegister();
if (TiedReg == -1)
continue;
Optional<size_t> LHSIdx = getAsmOperandIdx(AsmOperands, CGIOp.Name);
Optional<size_t> RHSIdx =
getAsmOperandIdx(AsmOperands, CGIOperands[TiedReg].Name);
// Skipping operands with constraint but no reference in the
// AsmString. No need to throw a warning, as it's normal to have
// a $dst operand in the outs dag that is constrained to a $src
// operand in the ins dag but that does not appear in the AsmString.
if (!LHSIdx || !RHSIdx)
continue;
// Add the constraint. Using min/max as we consider constraint
// pair {A,B} and {B,A} the same
size_t AddMnemonicIdx = HasMnemonicFirst;
AsmOperandTiedConstraints.emplace_back(
std::min(*LHSIdx, *RHSIdx) + AddMnemonicIdx,
std::max(*LHSIdx, *RHSIdx) + AddMnemonicIdx);
}
}
/// Append an AsmOperand for the given substring of AsmString.
@ -2831,6 +2892,80 @@ static void emitCustomOperandParsing(raw_ostream &OS, CodeGenTarget &Target,
OS << "}\n\n";
}
static void emitAsmTiedOperandConstraints(CodeGenTarget &Target,
AsmMatcherInfo &Info,
raw_ostream &OS) {
std::string Buf;
raw_string_ostream TmpOS(Buf);
TmpOS << "namespace {\n";
TmpOS << " struct TiedAsmOpndPair {\n";
TmpOS << " unsigned Opcode;\n";
TmpOS << " unsigned Opnd1;\n";
TmpOS << " unsigned Opnd2;\n";
TmpOS << " TiedAsmOpndPair(unsigned Opcode, unsigned Opnd1, unsigned "
"Opnd2)\n";
TmpOS << " : Opcode(Opcode), Opnd1(Opnd1), Opnd2(Opnd2) {}\n";
TmpOS << " };\n";
TmpOS << "} // end anonymous namespace\n\n";
TmpOS << "static const TiedAsmOpndPair TiedAsmOperandsTable[] = {\n";
bool TableEmpty = true;
for (const auto &Inst : Target.getInstructionsByEnumValue()) {
auto It = std::find_if(Info.Matchables.begin(), Info.Matchables.end(),
[&Inst](const std::unique_ptr<MatchableInfo> &MI) {
return (MI->TheDef->getID() == Inst->TheDef->getID());
});
if (It == Info.Matchables.end())
continue;
auto &Constraints = (**It).AsmOperandTiedConstraints;
if (Constraints.empty())
continue;
std::string Namespace = Inst->TheDef->getValueAsString("Namespace");
for (const auto &C : Constraints) {
TableEmpty = false;
TmpOS << " {";
TmpOS << Namespace << "::"<< (**It).TheDef->getName() << ", ";
TmpOS << C.first << ", " << C.second;
TmpOS << "},\n";
}
}
TmpOS << "};\n\n";
if (!TableEmpty)
OS << TmpOS.str();
OS << "static bool ";
OS << "checkAsmTiedOperandConstraints(const MCInst &Inst,\n";
OS << " const OperandVector &Operands,\n";
OS << " SMLoc &Loc) {\n";
if (TableEmpty) {
OS << "return true;\n}\n\n";
return;
}
OS << " const TiedAsmOpndPair SearchValue(Inst.getOpcode(), 0, 0);\n";
OS << " const auto Range = std::equal_range(\n";
OS << " std::begin(TiedAsmOperandsTable), std::end(TiedAsmOperandsTable),\n";
OS << " SearchValue, [](const TiedAsmOpndPair &a,\n";
OS << " const TiedAsmOpndPair &b) {\n";
OS << " return (a.Opcode < b.Opcode);\n";
OS << " });\n\n";
OS << " for (auto Item = Range.first; Item != Range.second; ++Item) {\n";
OS << " MCParsedAsmOperand &Op1 = *Operands[Item->Opnd1];\n";
OS << " MCParsedAsmOperand &Op2 = *Operands[Item->Opnd2];\n";
OS << " if ((Op1.isReg() && Op2.isReg()) &&\n";
OS << " (Op1.getReg() != Op2.getReg())) {\n";
OS << " Loc = Op2.getStartLoc();\n";
OS << " return false;\n";
OS << " }\n";
OS << " }\n";
OS << " return true;\n";
OS << "}\n\n";
}
static void emitMnemonicSpellChecker(raw_ostream &OS, CodeGenTarget &Target,
unsigned VariantCount) {
OS << "static std::string " << Target.getName()
@ -3078,6 +3213,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
Info.Target.getName(), ClassName, "ComputeAvailableFeatures",
Info.SubtargetFeatures, OS);
if (!ReportMultipleNearMisses)
emitAsmTiedOperandConstraints(Target, Info, OS);
StringToOffsetTable StringTable;
size_t MaxNumOperands = 0;
@ -3501,6 +3639,14 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " if (matchingInlineAsm) {\n";
OS << " convertToMapAndConstraints(it->ConvertFn, Operands);\n";
if (!ReportMultipleNearMisses) {
OS << " SMLoc Loc;\n";
OS << " if (!checkAsmTiedOperandConstraints(Inst, Operands, Loc)) {\n";
OS << " ErrorInfo = " << (HasMnemonicFirst ? "1" : "SIndex") << ";\n";
OS << " return Match_InvalidTiedOperand;\n";
OS << " }\n";
OS << "\n";
}
OS << " return Match_Success;\n";
OS << " }\n\n";
OS << " // We have selected a definite instruction, convert the parsed\n"
@ -3575,6 +3721,15 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " }\n";
}
if (!ReportMultipleNearMisses) {
OS << " SMLoc Loc;\n";
OS << " if (!checkAsmTiedOperandConstraints(Inst, Operands, Loc)) {\n";
OS << " ErrorInfo = " << (HasMnemonicFirst ? "1" : "SIndex") << ";\n";
OS << " return Match_InvalidTiedOperand;\n";
OS << " }\n";
OS << "\n";
}
OS << " DEBUG_WITH_TYPE(\n";
OS << " \"asm-matcher\",\n";
OS << " dbgs() << \"Opcode result: complete match, selecting this opcode\\n\");\n";