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:
parent
48adc2bf85
commit
aba6cb82df
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user