summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorJakob Stoklund Olesen <stoklund@2pi.dk>2011-06-04 04:11:37 +0000
committerJakob Stoklund Olesen <stoklund@2pi.dk>2011-06-04 04:11:37 +0000
commit1de99829b6bebe3310682efac8be2a9a95323220 (patch)
tree3c7002ad1d2f0b8dd9c00a9280063415bb5f42b3 /utils
parent404b53e38ca7a77c6e86596ace68f3167cd33922 (diff)
downloadllvm-1de99829b6bebe3310682efac8be2a9a95323220.tar.gz
llvm-1de99829b6bebe3310682efac8be2a9a95323220.tar.bz2
llvm-1de99829b6bebe3310682efac8be2a9a95323220.tar.xz
Teach TableGen to evaluate DAG expressions as set operations.
A TableGen backend can define how certain classes can be expanded into ordered sets of defs, typically by evaluating a specific field in the record. The SetTheory class can then evaluate DAG expressions that refer to these named sets. A number of standard set and list operations are predefined, and the backend can add more specialized operators if needed. The -print-sets backend is used by SetTheory.td to provide examples. This is intended to simplify how register classes are defined: def GR32_NOSP : RegisterClass<"X86", [i32], 32, (sub GR32, ESP)>; git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132621 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/CMakeLists.txt1
-rw-r--r--utils/TableGen/SetTheory.cpp272
-rw-r--r--utils/TableGen/SetTheory.h133
-rw-r--r--utils/TableGen/TableGen.cpp21
4 files changed, 426 insertions, 1 deletions
diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt
index 514b191299..db5823729a 100644
--- a/utils/TableGen/CMakeLists.txt
+++ b/utils/TableGen/CMakeLists.txt
@@ -34,6 +34,7 @@ add_llvm_utility(tblgen
OptParserEmitter.cpp
Record.cpp
RegisterInfoEmitter.cpp
+ SetTheory.cpp
StringMatcher.cpp
SubtargetEmitter.cpp
TGLexer.cpp
diff --git a/utils/TableGen/SetTheory.cpp b/utils/TableGen/SetTheory.cpp
new file mode 100644
index 0000000000..d2f1b22a10
--- /dev/null
+++ b/utils/TableGen/SetTheory.cpp
@@ -0,0 +1,272 @@
+//===- SetTheory.cpp - Generate ordered sets from DAG expressions ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SetTheory class that computes ordered sets of
+// Records from DAG expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SetTheory.h"
+#include "Record.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+// Define the standard operators.
+namespace {
+
+typedef SetTheory::RecSet RecSet;
+typedef SetTheory::RecVec RecVec;
+
+// (add a, b, ...) Evaluate and union all arguments.
+struct AddOp : public SetTheory::Operator {
+ void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
+ ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts);
+ }
+};
+
+// (sub Add, Sub, ...) Set difference.
+struct SubOp : public SetTheory::Operator {
+ void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
+ if (Expr->arg_size() < 2)
+ throw "Set difference needs at least two arguments: " +
+ Expr->getAsString();
+ RecSet Add, Sub;
+ ST.evaluate(*Expr->arg_begin(), Add);
+ ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Sub);
+ for (RecSet::iterator I = Add.begin(), E = Add.end(); I != E; ++I)
+ if (!Sub.count(*I))
+ Elts.insert(*I);
+ }
+};
+
+// (and S1, S2) Set intersection.
+struct AndOp : public SetTheory::Operator {
+ void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
+ if (Expr->arg_size() != 2)
+ throw "Set intersection requires two arguments: " + Expr->getAsString();
+ RecSet S1, S2;
+ ST.evaluate(Expr->arg_begin()[0], S1);
+ ST.evaluate(Expr->arg_begin()[1], S2);
+ for (RecSet::iterator I = S1.begin(), E = S1.end(); I != E; ++I)
+ if (S2.count(*I))
+ Elts.insert(*I);
+ }
+};
+
+// SetIntBinOp - Abstract base class for (Op S, N) operators.
+struct SetIntBinOp : public SetTheory::Operator {
+ virtual void apply(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts) =0;
+
+ void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
+ if (Expr->arg_size() != 2)
+ throw "Operator requires (Op Set, Int) arguments: " + Expr->getAsString();
+ RecSet Set;
+ ST.evaluate(Expr->arg_begin()[0], Set);
+ IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[1]);
+ if (!II)
+ throw "Second argument must be an integer: " + Expr->getAsString();
+ apply(ST, Expr, Set, II->getValue(), Elts);
+ }
+};
+
+// (shl S, N) Shift left, remove the first N elements.
+struct ShlOp : public SetIntBinOp {
+ void apply(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts) {
+ if (N < 0)
+ throw "Positive shift required: " + Expr->getAsString();
+ if (unsigned(N) < Set.size())
+ Elts.insert(Set.begin() + N, Set.end());
+ }
+};
+
+// (trunc S, N) Truncate after the first N elements.
+struct TruncOp : public SetIntBinOp {
+ void apply(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts) {
+ if (N < 0)
+ throw "Positive length required: " + Expr->getAsString();
+ if (unsigned(N) > Set.size())
+ N = Set.size();
+ Elts.insert(Set.begin(), Set.begin() + N);
+ }
+};
+
+// Left/right rotation.
+struct RotOp : public SetIntBinOp {
+ const bool Reverse;
+
+ RotOp(bool Rev) : Reverse(Rev) {}
+
+ void apply(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts) {
+ if (Reverse)
+ N = -N;
+ // N > 0 -> rotate left, N < 0 -> rotate right.
+ if (Set.empty())
+ return;
+ if (N < 0)
+ N = Set.size() - (-N % Set.size());
+ else
+ N %= Set.size();
+ Elts.insert(Set.begin() + N, Set.end());
+ Elts.insert(Set.begin(), Set.begin() + N);
+ }
+};
+
+// (decimate S, N) Pick every N'th element of S.
+struct DecimateOp : public SetIntBinOp {
+ void apply(SetTheory &ST, DagInit *Expr,
+ RecSet &Set, int64_t N,
+ RecSet &Elts) {
+ if (N <= 0)
+ throw "Positive stride required: " + Expr->getAsString();
+ for (unsigned I = 0; I < Set.size(); I += N)
+ Elts.insert(Set[I]);
+ }
+};
+
+// (sequence "Format", From, To) Generate a sequence of records by name.
+struct SequenceOp : public SetTheory::Operator {
+ RecordKeeper &Records;
+
+ SequenceOp(RecordKeeper&R) : Records(R) {}
+
+ void apply(SetTheory &ST, DagInit *Expr, RecSet &Elts) {
+ if (Expr->arg_size() != 3)
+ throw "Bad args to (sequence \"Format\", From, To): " +
+ Expr->getAsString();
+ std::string Format;
+ if (StringInit *SI = dynamic_cast<StringInit*>(Expr->arg_begin()[0]))
+ Format = SI->getValue();
+ else
+ throw "Format must be a string: " + Expr->getAsString();
+
+ int64_t From, To;
+ if (IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[1]))
+ From = II->getValue();
+ else
+ throw "From must be an integer: " + Expr->getAsString();
+ if (IntInit *II = dynamic_cast<IntInit*>(Expr->arg_begin()[2]))
+ To = II->getValue();
+ else
+ throw "From must be an integer: " + Expr->getAsString();
+
+ int Step = From <= To ? 1 : -1;
+ for (To += Step; From != To; From += Step) {
+ std::string Name;
+ raw_string_ostream OS(Name);
+ OS << format(Format.c_str(), From);
+ Record *Rec = Records.getDef(OS.str());
+ if (!Rec)
+ throw "No def named '" + Name + "': " + Expr->getAsString();
+ // Try to reevaluate Rec in case it is a set.
+ if (const RecVec *Result = ST.expand(Rec))
+ Elts.insert(Result->begin(), Result->end());
+ else
+ Elts.insert(Rec);
+ }
+ }
+};
+
+// Expand a Def into a set by evaluating one of its fields.
+struct FieldExpander : public SetTheory::Expander {
+ StringRef FieldName;
+
+ FieldExpander(StringRef fn) : FieldName(fn) {}
+
+ void expand(SetTheory &ST, Record *Def, RecSet &Elts) {
+ ST.evaluate(Def->getValueInit(FieldName), Elts);
+ }
+};
+} // end anonymous namespace
+
+SetTheory::SetTheory(RecordKeeper *Records) {
+ addOperator("add", new AddOp);
+ addOperator("sub", new SubOp);
+ addOperator("and", new AndOp);
+ addOperator("shl", new ShlOp);
+ addOperator("trunc", new TruncOp);
+ addOperator("rotl", new RotOp(false));
+ addOperator("rotr", new RotOp(true));
+ addOperator("decimate", new DecimateOp);
+ if (Records)
+ addOperator("sequence", new SequenceOp(*Records));
+}
+
+void SetTheory::addOperator(StringRef Name, Operator *Op) {
+ Operators[Name] = Op;
+}
+
+void SetTheory::addExpander(StringRef ClassName, Expander *E) {
+ Expanders[ClassName] = E;
+}
+
+void SetTheory::addFieldExpander(StringRef ClassName, StringRef FieldName) {
+ addExpander(ClassName, new FieldExpander(FieldName));
+}
+
+void SetTheory::evaluate(Init *Expr, RecSet &Elts) {
+ // A def in a list can be a just an element, or it may expand.
+ if (DefInit *Def = dynamic_cast<DefInit*>(Expr)) {
+ if (const RecVec *Result = expand(Def->getDef()))
+ return Elts.insert(Result->begin(), Result->end());
+ Elts.insert(Def->getDef());
+ return;
+ }
+
+ // Lists simply expand.
+ if (ListInit *LI = dynamic_cast<ListInit*>(Expr))
+ return evaluate(LI->begin(), LI->end(), Elts);
+
+ // Anything else must be a DAG.
+ DagInit *DagExpr = dynamic_cast<DagInit*>(Expr);
+ if (!DagExpr)
+ throw "Invalid set element: " + Expr->getAsString();
+ DefInit *OpInit = dynamic_cast<DefInit*>(DagExpr->getOperator());
+ if (!OpInit)
+ throw "Bad set expression: " + Expr->getAsString();
+ Operator *Op = Operators.lookup(OpInit->getDef()->getName());
+ if (!Op)
+ throw "Unknown set operator: " + Expr->getAsString();
+ Op->apply(*this, DagExpr, Elts);
+}
+
+const RecVec *SetTheory::expand(Record *Set) {
+ // Check existing entries for Set and return early.
+ ExpandMap::iterator I = Expansions.find(Set);
+ if (I != Expansions.end())
+ return &I->second;
+
+ // This is the first time we see Set. Find a suitable expander.
+ try {
+ const std::vector<Record*> &SC = Set->getSuperClasses();
+ for (unsigned i = 0, e = SC.size(); i != e; ++i)
+ if (Expander *Exp = Expanders.lookup(SC[i]->getName())) {
+ // This breaks recursive definitions.
+ RecVec &EltVec = Expansions[Set];
+ RecSet Elts;
+ Exp->expand(*this, Set, Elts);
+ EltVec.assign(Elts.begin(), Elts.end());
+ return &EltVec;
+ }
+ } catch (const std::string &Error) {
+ throw TGError(Set->getLoc(), Error);
+ }
+
+ // Set is not expandable.
+ return 0;
+}
+
diff --git a/utils/TableGen/SetTheory.h b/utils/TableGen/SetTheory.h
new file mode 100644
index 0000000000..c648d46e60
--- /dev/null
+++ b/utils/TableGen/SetTheory.h
@@ -0,0 +1,133 @@
+//===- SetTheory.h - Generate ordered sets from DAG expressions -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SetTheory class that computes ordered sets of
+// Records from DAG expressions. Operators for standard set operations are
+// predefined, and it is possible to add special purpose set operators as well.
+//
+// The user may define named sets as Records of predefined classes. Set
+// expanders can be added to a SetTheory instance to teach it how to find the
+// elements of such a named set.
+//
+// These are the predefined operators. The argument lists can be individual
+// elements (defs), other sets (defs of expandable classes), lists, or DAG
+// expressions that are evaluated recursively.
+//
+// - (add S1, S2 ...) Union sets. This is also how sets are created from element
+// lists.
+//
+// - (sub S1, S2, ...) Set difference. Every element in S1 except for the
+// elements in S2, ...
+//
+// - (and S1, S2) Set intersection. Every element in S1 that is also in S2.
+//
+// - (shl S, N) Shift left. Remove the first N elements from S.
+//
+// - (trunc S, N) Truncate. The first N elements of S.
+//
+// - (rotl S, N) Rotate left. Same as (add (shl S, N), (trunc S, N)).
+//
+// - (rotr S, N) Rotate right.
+//
+// - (decimate S, N) Decimate S by picking every N'th element, starting with
+// the first one. For instance, (decimate S, 2) returns the even elements of
+// S.
+//
+// - (sequence "Format", From, To) Generate a sequence of defs with printf.
+// For instance, (sequence "R%u", 0, 3) -> [ R0, R1, R2, R3 ]
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SETTHEORY_H
+#define SETTHEORY_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/SetVector.h"
+#include <map>
+#include <vector>
+
+namespace llvm {
+
+class DagInit;
+struct Init;
+class Record;
+class RecordKeeper;
+
+class SetTheory {
+public:
+ typedef std::vector<Record*> RecVec;
+ typedef SmallSetVector<Record*, 16> RecSet;
+
+ /// Operator - A callback representing a DAG operator.
+ struct Operator {
+ /// apply - Apply this operator to Expr's arguments and insert the result
+ /// in Elts.
+ virtual void apply(SetTheory&, DagInit *Expr, RecSet &Elts) =0;
+ };
+
+ /// Expander - A callback function that can transform a Record representing a
+ /// set into a fully expanded list of elements. Expanders provide a way for
+ /// users to define named sets that can be used in DAG expressions.
+ struct Expander {
+ virtual void expand(SetTheory&, Record*, RecSet &Elts) =0;
+ };
+
+private:
+ // Map set defs to their fully expanded contents. This serves as a memoization
+ // cache and it makes it possible to return const references on queries.
+ typedef std::map<Record*, RecVec> ExpandMap;
+ ExpandMap Expansions;
+
+ // Known DAG operators by name.
+ StringMap<Operator*> Operators;
+
+ // Typed expanders by class name.
+ StringMap<Expander*> Expanders;
+
+public:
+ /// Create a SetTheory instance with only the standard operators.
+ /// A 'sequence' operator will only be added if a RecordKeeper is given.
+ SetTheory(RecordKeeper *Records = 0);
+
+ /// addExpander - Add an expander for Records with the named super class.
+ void addExpander(StringRef ClassName, Expander*);
+
+ /// addFieldExpander - Add an expander for ClassName that simply evaluates
+ /// FieldName in the Record to get the set elements. That is all that is
+ /// needed for a class like:
+ ///
+ /// class Set<dag d> {
+ /// dag Elts = d;
+ /// }
+ ///
+ void addFieldExpander(StringRef ClassName, StringRef FieldName);
+
+ /// addOperator - Add a DAG operator.
+ void addOperator(StringRef Name, Operator*);
+
+ /// evaluate - Evaluate Expr and append the resulting set to Elts.
+ void evaluate(Init *Expr, RecSet &Elts);
+
+ /// evaluate - Evaluate a sequence of Inits and append to Elts.
+ template<typename Iter>
+ void evaluate(Iter begin, Iter end, RecSet &Elts) {
+ while (begin != end)
+ evaluate(*begin++, Elts);
+ }
+
+ /// expand - Expand a record into a set of elements if possible. Return a
+ /// pointer to the expanded elements, or NULL if Set cannot be expanded
+ /// further.
+ const RecVec *expand(Record *Set);
+};
+
+} // end namespace llvm
+
+#endif
+
diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp
index fb941c44dc..925b134ca4 100644
--- a/utils/TableGen/TableGen.cpp
+++ b/utils/TableGen/TableGen.cpp
@@ -37,6 +37,7 @@
#include "RegisterInfoEmitter.h"
#include "ARMDecoderEmitter.h"
#include "SubtargetEmitter.h"
+#include "SetTheory.h"
#include "TGParser.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/CommandLine.h"
@@ -80,7 +81,8 @@ enum ActionType {
GenArmNeon,
GenArmNeonSema,
GenArmNeonTest,
- PrintEnums
+ PrintEnums,
+ PrintSets
};
namespace {
@@ -162,6 +164,8 @@ namespace {
"Generate ARM NEON tests for clang"),
clEnumValN(PrintEnums, "print-enums",
"Print enum values for a class"),
+ clEnumValN(PrintSets, "print-sets",
+ "Print expanded sets for testing DAG exprs"),
clEnumValEnd));
cl::opt<std::string>
@@ -374,6 +378,21 @@ int main(int argc, char **argv) {
Out.os() << "\n";
break;
}
+ case PrintSets:
+ {
+ SetTheory Sets(&Records);
+ Sets.addFieldExpander("Set", "Elements");
+ std::vector<Record*> Recs = Records.getAllDerivedDefinitions("Set");
+ for (unsigned i = 0, e = Recs.size(); i != e; ++i) {
+ Out.os() << Recs[i]->getName() << " = [";
+ const std::vector<Record*> *Elts = Sets.expand(Recs[i]);
+ assert(Elts && "Couldn't expand Set instance");
+ for (unsigned ei = 0, ee = Elts->size(); ei != ee; ++ei)
+ Out.os() << ' ' << (*Elts)[ei]->getName();
+ Out.os() << " ]\n";
+ }
+ break;
+ }
default:
assert(1 && "Invalid Action");
return 1;