1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 05:01:59 +01:00

[GlobalISel] Return an Expected<RuleMatcher> for each SDAG pattern. NFC.

Instead of emitting the matcher code directly, return the rule matcher
and the skip reason as an Expected<RuleMatcher>.

This will let us record all matchers and process them before emission.

It's a somewhat unconventional use of Error, but it's nicer than, say,
std::pair, because of the bool conversions.

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

llvm-svn: 294706
This commit is contained in:
Ahmed Bougacha 2017-02-10 04:00:17 +00:00
parent 48adc2bf85
commit aba6cb82df

View File

@ -35,6 +35,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineValueType.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
@ -54,35 +55,7 @@ static cl::opt<bool> WarnOnSkippedPatterns(
cl::init(false));
namespace {
class GlobalISelEmitter {
public:
explicit GlobalISelEmitter(RecordKeeper &RK);
void run(raw_ostream &OS);
private:
const RecordKeeper &RK;
const CodeGenDAGPatterns CGP;
const CodeGenTarget &Target;
/// Keep track of the equivalence between SDNodes and Instruction.
/// This is defined using 'GINodeEquiv' in the target description.
DenseMap<Record *, const CodeGenInstruction *> NodeEquivs;
void gatherNodeEquivs();
const CodeGenInstruction *findNodeEquiv(Record *N);
struct SkipReason {
std::string Reason;
};
/// Analyze pattern \p P, possibly emitting matching code for it to \p OS.
/// Otherwise, return a reason why this pattern was skipped for emission.
Optional<SkipReason> runOnPattern(const PatternToMatch &P,
raw_ostream &OS);
};
} // end anonymous namespace
class RuleMatcher;
//===- Helper functions ---------------------------------------------------===//
@ -381,6 +354,28 @@ public:
//===- GlobalISelEmitter class --------------------------------------------===//
class GlobalISelEmitter {
public:
explicit GlobalISelEmitter(RecordKeeper &RK);
void run(raw_ostream &OS);
private:
const RecordKeeper &RK;
const CodeGenDAGPatterns CGP;
const CodeGenTarget &Target;
/// Keep track of the equivalence between SDNodes and Instruction.
/// This is defined using 'GINodeEquiv' in the target description.
DenseMap<Record *, const CodeGenInstruction *> NodeEquivs;
void gatherNodeEquivs();
const CodeGenInstruction *findNodeEquiv(Record *N);
/// Analyze pattern \p P, returning a matcher for it if possible.
/// Otherwise, return an Error explaining why we don't support it.
Expected<RuleMatcher> runOnPattern(const PatternToMatch &P);
};
void GlobalISelEmitter::gatherNodeEquivs() {
assert(NodeEquivs.empty());
for (Record *Equiv : RK.getAllDerivedDefinitions("GINodeEquiv"))
@ -397,9 +392,12 @@ GlobalISelEmitter::GlobalISelEmitter(RecordKeeper &RK)
//===- Emitter ------------------------------------------------------------===//
Optional<GlobalISelEmitter::SkipReason>
GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
/// Helper function to let the emitter report skip reason error messages.
static Error failedImport(const Twine &Reason) {
return make_error<StringError>(Reason, inconvertibleErrorCode());
}
Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// Keep track of the matchers and actions to emit.
RuleMatcher M;
M.addAction<DebugCommentAction>(P);
@ -407,11 +405,11 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
// First, analyze the whole pattern.
// If the entire pattern has a predicate (e.g., target features), ignore it.
if (!P.getPredicates()->getValues().empty())
return SkipReason{"Pattern has a predicate"};
return failedImport("Pattern has a predicate");
// Physreg imp-defs require additional logic. Ignore the pattern.
if (!P.getDstRegs().empty())
return SkipReason{"Pattern defines a physical register"};
return failedImport("Pattern defines a physical register");
// Next, analyze the pattern operators.
TreePatternNode *Src = P.getSrcPattern();
@ -419,19 +417,19 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
// If the root of either pattern isn't a simple operator, ignore it.
if (!isTrivialOperatorNode(Dst))
return SkipReason{"Dst pattern root isn't a trivial operator"};
return failedImport("Dst pattern root isn't a trivial operator");
if (!isTrivialOperatorNode(Src))
return SkipReason{"Src pattern root isn't a trivial operator"};
return failedImport("Src pattern root isn't a trivial operator");
Record *DstOp = Dst->getOperator();
if (!DstOp->isSubClassOf("Instruction"))
return SkipReason{"Pattern operator isn't an instruction"};
return failedImport("Pattern operator isn't an instruction");
auto &DstI = Target.getInstruction(DstOp);
auto SrcGIOrNull = findNodeEquiv(Src->getOperator());
if (!SrcGIOrNull)
return SkipReason{"Pattern operator lacks an equivalent Instruction"};
return failedImport("Pattern operator lacks an equivalent Instruction");
auto &SrcGI = *SrcGIOrNull;
// The operators look good: match the opcode and mutate it to the new one.
@ -442,22 +440,22 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
// Next, analyze the children, only accepting patterns that don't require
// any change to operands.
if (Src->getNumChildren() != Dst->getNumChildren())
return SkipReason{"Src/dst patterns have a different # of children"};
return failedImport("Src/dst patterns have a different # of children");
unsigned OpIdx = 0;
// Start with the defined operands (i.e., the results of the root operator).
if (DstI.Operands.NumDefs != Src->getExtTypes().size())
return SkipReason{"Src pattern results and dst MI defs are different"};
return failedImport("Src pattern results and dst MI defs are different");
for (const EEVT::TypeSet &Ty : Src->getExtTypes()) {
Record *DstIOpRec = DstI.Operands[OpIdx].Rec;
if (!DstIOpRec->isSubClassOf("RegisterClass"))
return SkipReason{"Dst MI def isn't a register class"};
return failedImport("Dst MI def isn't a register class");
auto OpTyOrNone = MVTToLLT(Ty.getConcrete());
if (!OpTyOrNone)
return SkipReason{"Dst operand has an unsupported type"};
return failedImport("Dst operand has an unsupported type");
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx);
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
@ -473,14 +471,14 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
// Patterns can reorder operands. Ignore those for now.
if (SrcChild->getName() != DstChild->getName())
return SkipReason{"Src/dst pattern children not in same order"};
return failedImport("Src/dst pattern children not in same order");
// The only non-leaf child we accept is 'bb': it's an operator because
// BasicBlockSDNode isn't inline, but in MI it's just another operand.
if (!SrcChild->isLeaf()) {
if (DstChild->isLeaf() ||
SrcChild->getOperator() != DstChild->getOperator())
return SkipReason{"Src/dst pattern child operator mismatch"};
return failedImport("Src/dst pattern child operator mismatch");
if (SrcChild->getOperator()->isSubClassOf("SDNode")) {
auto &ChildSDNI = CGP.getSDNodeInfo(SrcChild->getOperator());
@ -489,26 +487,26 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
continue;
}
}
return SkipReason{"Src pattern child isn't a leaf node"};
return failedImport("Src pattern child isn't a leaf node");
}
if (SrcChild->getLeafValue() != DstChild->getLeafValue())
return SkipReason{"Src/dst pattern child leaf mismatch"};
return failedImport("Src/dst pattern child leaf mismatch");
// Otherwise, we're looking for a bog-standard RegisterClass operand.
if (SrcChild->hasAnyPredicate())
return SkipReason{"Src pattern child has predicate"};
return failedImport("Src pattern child has predicate");
auto *ChildRec = cast<DefInit>(SrcChild->getLeafValue())->getDef();
if (!ChildRec->isSubClassOf("RegisterClass"))
return SkipReason{"Src pattern child isn't a RegisterClass"};
return failedImport("Src pattern child isn't a RegisterClass");
ArrayRef<EEVT::TypeSet> ChildTypes = SrcChild->getExtTypes();
if (ChildTypes.size() != 1)
return SkipReason{"Src pattern child has multiple results"};
return failedImport("Src pattern child has multiple results");
auto OpTyOrNone = MVTToLLT(ChildTypes.front().getConcrete());
if (!OpTyOrNone)
return SkipReason{"Src operand has an unsupported type"};
return failedImport("Src operand has an unsupported type");
OperandMatcher &OM = InsnMatcher.addOperand(OpIdx);
OM.addPredicate<LLTOperandMatcher>(*OpTyOrNone);
@ -517,10 +515,8 @@ GlobalISelEmitter::runOnPattern(const PatternToMatch &P, raw_ostream &OS) {
++OpIdx;
}
// We're done with this pattern! Emit the processed result.
M.emit(OS);
++NumPatternEmitted;
return None;
// We're done with this pattern! It's eligible for GISel emission; return it.
return std::move(M);
}
void GlobalISelEmitter::run(raw_ostream &OS) {
@ -537,18 +533,30 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// Look through the SelectionDAG patterns we found, possibly emitting some.
for (const PatternToMatch &Pat : CGP.ptms()) {
++NumPatternTotal;
if (auto SkipReason = runOnPattern(Pat, OS)) {
auto MatcherOrErr = runOnPattern(Pat);
// The pattern analysis can fail, indicating an unsupported pattern.
// Report that if we've been asked to do so.
if (auto Err = MatcherOrErr.takeError()) {
if (WarnOnSkippedPatterns) {
PrintWarning(Pat.getSrcRecord()->getLoc(),
"Skipped pattern: " + SkipReason->Reason);
"Skipped pattern: " + toString(std::move(Err)));
} else {
consumeError(std::move(Err));
}
++NumPatternSkipped;
continue;
}
MatcherOrErr->emit(OS);
++NumPatternEmitted;
}
OS << " return false;\n}\n";
}
} // end anonymous namespace
//===----------------------------------------------------------------------===//
namespace llvm {