[TableGen] [ISel Matcher Emitter] Rework with two passes: one to size, one to emit

Differential Revision: https://reviews.llvm.org/D91632
This commit is contained in:
Paul C. Anagnostopoulos 2020-11-16 14:24:25 -05:00
parent 9930d4dff3
commit 9b7b8de6d1
2 changed files with 132 additions and 96 deletions

View File

@ -31,7 +31,7 @@ Matcher *ConvertPatternToMatcher(const PatternToMatch &Pattern,unsigned Variant,
const CodeGenDAGPatterns &CGP);
void OptimizeMatcher(std::unique_ptr<Matcher> &Matcher,
const CodeGenDAGPatterns &CGP);
void EmitMatcherTable(const Matcher *Matcher, const CodeGenDAGPatterns &CGP,
void EmitMatcherTable(Matcher *Matcher, const CodeGenDAGPatterns &CGP,
raw_ostream &OS);
@ -41,6 +41,7 @@ class Matcher {
// The next matcher node that is executed after this one. Null if this is the
// last stage of a match.
std::unique_ptr<Matcher> Next;
size_t Size; // Size in bytes of matcher and all its children (if any).
virtual void anchor();
public:
enum KindTy {
@ -85,7 +86,10 @@ public:
EmitNode, // Create a DAG node
EmitNodeXForm, // Run a SDNodeXForm
CompleteMatch, // Finish a match and update the results.
MorphNodeTo // Build a node, finish a match and update results.
MorphNodeTo, // Build a node, finish a match and update results.
// Highest enum value; watch out when adding more.
HighestKind = MorphNodeTo
};
const KindTy Kind;
@ -94,6 +98,8 @@ protected:
public:
virtual ~Matcher() {}
unsigned getSize() const { return Size; }
void setSize(unsigned sz) { Size = sz; }
KindTy getKind() const { return Kind; }
Matcher *getNext() { return Next.get(); }

View File

@ -23,6 +23,7 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
using namespace llvm;
enum {
@ -47,6 +48,8 @@ namespace {
class MatcherTableEmitter {
const CodeGenDAGPatterns &CGP;
SmallVector<unsigned, Matcher::HighestKind+1> OpcodeCounts;
DenseMap<TreePattern *, unsigned> NodePredicateMap;
std::vector<TreePredicateFn> NodePredicates;
std::vector<TreePredicateFn> NodePredicatesWithOperands;
@ -79,12 +82,15 @@ class MatcherTableEmitter {
}
public:
MatcherTableEmitter(const CodeGenDAGPatterns &cgp)
: CGP(cgp) {}
MatcherTableEmitter(const CodeGenDAGPatterns &cgp) : CGP(cgp) {
OpcodeCounts.assign(Matcher::HighestKind+1, 0);
}
unsigned EmitMatcherList(const Matcher *N, unsigned Indent,
unsigned EmitMatcherList(const Matcher *N, const unsigned Indent,
unsigned StartIdx, raw_ostream &OS);
unsigned SizeMatcherList(Matcher *N, raw_ostream &OS);
void EmitPredicateFunctions(raw_ostream &OS);
void EmitHistogram(const Matcher *N, raw_ostream &OS);
@ -95,7 +101,9 @@ private:
void EmitNodePredicatesFunction(const std::vector<TreePredicateFn> &Preds,
StringRef Decl, raw_ostream &OS);
unsigned EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
unsigned SizeMatcher(Matcher *N, raw_ostream &OS);
unsigned EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS);
unsigned getNodePredicate(TreePredicateFn Pred) {
@ -165,7 +173,7 @@ static std::string GetPatFromTreePatternNode(const TreePatternNode *N) {
return str;
}
static unsigned GetVBRSize(unsigned Val) {
static size_t GetVBRSize(unsigned Val) {
if (Val <= 127) return 1;
unsigned NumBytes = 0;
@ -219,6 +227,78 @@ static std::string getIncludePath(const Record *R) {
return str;
}
/// This function traverses the matcher tree and sizes all the nodes
/// that are children of the three kinds of nodes that have them.
unsigned MatcherTableEmitter::
SizeMatcherList(Matcher *N, raw_ostream &OS) {
unsigned Size = 0;
while (N) {
Size += SizeMatcher(N, OS);
N = N->getNext();
}
return Size;
}
/// This function sizes the children of the three kinds of nodes that
/// have them. It does so by using special cases for those three
/// nodes, but sharing the code in EmitMatcher() for the other kinds.
unsigned MatcherTableEmitter::
SizeMatcher(Matcher *N, raw_ostream &OS) {
unsigned Idx = 0;
++OpcodeCounts[N->getKind()];
switch (N->getKind()) {
// The Scope matcher has its kind, a series of child size + child,
// and a trailing zero.
case Matcher::Scope: {
ScopeMatcher *SM = cast<ScopeMatcher>(N);
assert(SM->getNext() == nullptr && "Scope matcher should not have next");
unsigned Size = 1; // Count the kind.
for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) {
const size_t ChildSize = SizeMatcherList(SM->getChild(i), OS);
assert(ChildSize != 0 && "Matcher cannot have child of size 0");
SM->getChild(i)->setSize(ChildSize);
Size += GetVBRSize(ChildSize) + ChildSize; // Count VBR and child size.
}
++Size; // Count the zero sentinel.
return Size;
}
// SwitchOpcode and SwitchType have their kind, a series of child size +
// opcode/type + child, and a trailing zero.
case Matcher::SwitchOpcode:
case Matcher::SwitchType: {
unsigned Size = 1; // Count the kind.
unsigned NumCases;
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
NumCases = SOM->getNumCases();
else
NumCases = cast<SwitchTypeMatcher>(N)->getNumCases();
for (unsigned i = 0, e = NumCases; i != e; ++i) {
Matcher *Child;
if (SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N)) {
Child = SOM->getCaseMatcher(i);
Size += 2; // Count the child's opcode.
} else {
Child = cast<SwitchTypeMatcher>(N)->getCaseMatcher(i);
++Size; // Count the child's type.
}
const size_t ChildSize = SizeMatcherList(Child, OS);
assert(ChildSize != 0 && "Matcher cannot have child of size 0");
Child->setSize(ChildSize);
Size += GetVBRSize(ChildSize) + ChildSize; // Count VBR and child size.
}
++Size; // Count the zero sentinel.
return Size;
}
default:
// Employ the matcher emitter to size other matchers.
return EmitMatcher(N, 0, Idx, OS);
}
llvm_unreachable("Unreachable");
}
static void BeginEmitFunction(raw_ostream &OS, StringRef RetType,
StringRef Decl, bool AddOverride) {
OS << "#ifdef GET_DAGISEL_DECL\n";
@ -279,19 +359,16 @@ void MatcherTableEmitter::EmitPatternMatchTable(raw_ostream &OS) {
/// EmitMatcher - Emit bytes for the specified matcher and return
/// the number of bytes emitted.
unsigned MatcherTableEmitter::
EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
EmitMatcher(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS) {
OS.indent(Indent);
switch (N->getKind()) {
case Matcher::Scope: {
const ScopeMatcher *SM = cast<ScopeMatcher>(N);
assert(SM->getNext() == nullptr && "Shouldn't have next after scope");
unsigned StartIdx = CurrentIdx;
// Emit all of the children.
SmallString<128> TmpBuf;
for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i) {
if (i == 0) {
OS << "OPC_Scope, ";
@ -304,34 +381,21 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
OS.indent(Indent);
}
// We need to encode the child and the offset of the failure code before
// emitting either of them. Handle this by buffering the output into a
// string while we get the size. Unfortunately, the offset of the
// children depends on the VBR size of the child, so for large children we
// have to iterate a bit.
unsigned ChildSize = 0;
unsigned VBRSize = 0;
do {
VBRSize = GetVBRSize(ChildSize);
TmpBuf.clear();
raw_svector_ostream OS(TmpBuf);
ChildSize = EmitMatcherList(SM->getChild(i), Indent+1,
CurrentIdx+VBRSize, OS);
} while (GetVBRSize(ChildSize) != VBRSize);
assert(ChildSize != 0 && "Should not have a zero-sized child!");
CurrentIdx += EmitVBRValue(ChildSize, OS);
size_t ChildSize = SM->getChild(i)->getSize();
size_t VBRSize = GetVBRSize(ChildSize);
EmitVBRValue(ChildSize, OS);
if (!OmitComments) {
OS << "/*->" << CurrentIdx+ChildSize << "*/";
OS << "/*->" << CurrentIdx + VBRSize + ChildSize << "*/";
if (i == 0)
OS << " // " << SM->getNumChildren() << " children in Scope";
}
OS << '\n';
OS << '\n' << TmpBuf;
CurrentIdx += ChildSize;
ChildSize = EmitMatcherList(SM->getChild(i), Indent+1,
CurrentIdx + VBRSize, OS);
assert(ChildSize == SM->getChild(i)->getSize() &&
"Emitted child size does not match calculated size");
CurrentIdx += VBRSize + ChildSize;
}
// Emit a zero as a sentinel indicating end of 'Scope'.
@ -450,7 +514,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
++CurrentIdx;
// For each case we emit the size, then the opcode, then the matcher.
SmallString<128> TmpBuf;
for (unsigned i = 0, e = NumCases; i != e; ++i) {
const Matcher *Child;
unsigned IdxSize;
@ -462,24 +525,6 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
IdxSize = 1; // size of type in table is 1 byte.
}
// We need to encode the opcode and the offset of the case code before
// emitting the case code. Handle this by buffering the output into a
// string while we get the size. Unfortunately, the offset of the
// children depends on the VBR size of the child, so for large children we
// have to iterate a bit.
unsigned ChildSize = 0;
unsigned VBRSize = 0;
do {
VBRSize = GetVBRSize(ChildSize);
TmpBuf.clear();
raw_svector_ostream OS(TmpBuf);
ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx+VBRSize+IdxSize,
OS);
} while (GetVBRSize(ChildSize) != VBRSize);
assert(ChildSize != 0 && "Should not have a zero-sized child!");
if (i != 0) {
if (!OmitComments)
OS << "/*" << format_decimal(CurrentIdx, IndexWidth) << "*/";
@ -489,20 +534,19 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
"/*SwitchOpcode*/ " : "/*SwitchType*/ ");
}
// Emit the VBR.
CurrentIdx += EmitVBRValue(ChildSize, OS);
size_t ChildSize = Child->getSize();
CurrentIdx += EmitVBRValue(ChildSize, OS) + IdxSize;
if (const SwitchOpcodeMatcher *SOM = dyn_cast<SwitchOpcodeMatcher>(N))
OS << "TARGET_VAL(" << SOM->getCaseOpcode(i).getEnumName() << "),";
else
OS << getEnumName(cast<SwitchTypeMatcher>(N)->getCaseType(i)) << ',';
CurrentIdx += IdxSize;
if (!OmitComments)
OS << "// ->" << CurrentIdx+ChildSize;
OS << "// ->" << CurrentIdx + ChildSize;
OS << '\n';
OS << TmpBuf;
ChildSize = EmitMatcherList(Child, Indent+1, CurrentIdx, OS);
assert(ChildSize == Child->getSize() &&
"Emitted child size does not match calculated size");
CurrentIdx += ChildSize;
}
@ -515,8 +559,7 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
" // EndSwitchOpcode" : " // EndSwitchType");
OS << '\n';
++CurrentIdx;
return CurrentIdx-StartIdx;
return CurrentIdx - StartIdx + 1;
}
case Matcher::CheckType:
@ -810,9 +853,10 @@ EmitMatcher(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
llvm_unreachable("Unreachable");
}
/// EmitMatcherList - Emit the bytes for the specified matcher subtree.
/// This function traverses the matcher tree and emits all the nodes.
/// The nodes have already been sized.
unsigned MatcherTableEmitter::
EmitMatcherList(const Matcher *N, unsigned Indent, unsigned CurrentIdx,
EmitMatcherList(const Matcher *N, const unsigned Indent, unsigned CurrentIdx,
raw_ostream &OS) {
unsigned Size = 0;
while (N) {
@ -841,7 +885,7 @@ void MatcherTableEmitter::EmitNodePredicatesFunction(
OS << " default: llvm_unreachable(\"Invalid predicate in table?\");\n";
for (unsigned i = 0, e = Preds.size(); i != e; ++i) {
// Emit the predicate code corresponding to this pattern.
TreePredicateFn PredFn = Preds[i];
const TreePredicateFn PredFn = Preds[i];
assert(!PredFn.isAlwaysTrue() && "No code in this predicate");
OS << " case " << i << ": {\n";
@ -975,28 +1019,6 @@ void MatcherTableEmitter::EmitPredicateFunctions(raw_ostream &OS) {
}
}
static void BuildHistogram(const Matcher *M, std::vector<unsigned> &OpcodeFreq){
for (; M != nullptr; M = M->getNext()) {
// Count this node.
if (unsigned(M->getKind()) >= OpcodeFreq.size())
OpcodeFreq.resize(M->getKind()+1);
OpcodeFreq[M->getKind()]++;
// Handle recursive nodes.
if (const ScopeMatcher *SM = dyn_cast<ScopeMatcher>(M)) {
for (unsigned i = 0, e = SM->getNumChildren(); i != e; ++i)
BuildHistogram(SM->getChild(i), OpcodeFreq);
} else if (const SwitchOpcodeMatcher *SOM =
dyn_cast<SwitchOpcodeMatcher>(M)) {
for (unsigned i = 0, e = SOM->getNumCases(); i != e; ++i)
BuildHistogram(SOM->getCaseMatcher(i), OpcodeFreq);
} else if (const SwitchTypeMatcher *STM = dyn_cast<SwitchTypeMatcher>(M)) {
for (unsigned i = 0, e = STM->getNumCases(); i != e; ++i)
BuildHistogram(STM->getCaseMatcher(i), OpcodeFreq);
}
}
}
static StringRef getOpcodeString(Matcher::KindTy Kind) {
switch (Kind) {
case Matcher::Scope: return "OPC_Scope"; break;
@ -1048,20 +1070,17 @@ void MatcherTableEmitter::EmitHistogram(const Matcher *M,
if (OmitComments)
return;
std::vector<unsigned> OpcodeFreq;
BuildHistogram(M, OpcodeFreq);
OS << " // Opcode Histogram:\n";
for (unsigned i = 0, e = OpcodeFreq.size(); i != e; ++i) {
for (unsigned i = 0, e = OpcodeCounts.size(); i != e; ++i) {
OS << " // #"
<< left_justify(getOpcodeString((Matcher::KindTy)i), HistOpcWidth)
<< " = " << OpcodeFreq[i] << '\n';
<< " = " << OpcodeCounts[i] << '\n';
}
OS << '\n';
}
void llvm::EmitMatcherTable(const Matcher *TheMatcher,
void llvm::EmitMatcherTable(Matcher *TheMatcher,
const CodeGenDAGPatterns &CGP,
raw_ostream &OS) {
OS << "#if defined(GET_DAGISEL_DECL) && defined(GET_DAGISEL_BODY)\n";
@ -1096,12 +1115,23 @@ void llvm::EmitMatcherTable(const Matcher *TheMatcher,
BeginEmitFunction(OS, "void", "SelectCode(SDNode *N)", false/*AddOverride*/);
MatcherTableEmitter MatcherEmitter(CGP);
// First we size all the children of the three kinds of matchers that have
// them. This is done by sharing the code in EmitMatcher(). but we don't
// want to emit anything, so we turn off comments and use a null stream.
bool SaveOmitComments = OmitComments;
OmitComments = true;
raw_null_ostream NullOS;
unsigned TotalSize = MatcherEmitter.SizeMatcherList(TheMatcher, NullOS);
OmitComments = SaveOmitComments;
// Now that the matchers are sized, we can emit the code for them to the
// final stream.
OS << "{\n";
OS << " // Some target values are emitted as 2 bytes, TARGET_VAL handles\n";
OS << " // this.\n";
OS << " #define TARGET_VAL(X) X & 255, unsigned(X) >> 8\n";
OS << " static const unsigned char MatcherTable[] = {\n";
unsigned TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS);
TotalSize = MatcherEmitter.EmitMatcherList(TheMatcher, 1, 0, OS);
OS << " 0\n }; // Total Array size is " << (TotalSize+1) << " bytes\n\n";
MatcherEmitter.EmitHistogram(TheMatcher, OS);