From 1de99829b6bebe3310682efac8be2a9a95323220 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Sat, 4 Jun 2011 04:11:37 +0000 Subject: 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 --- utils/TableGen/CMakeLists.txt | 1 + utils/TableGen/SetTheory.cpp | 272 ++++++++++++++++++++++++++++++++++++++++++ utils/TableGen/SetTheory.h | 133 +++++++++++++++++++++ utils/TableGen/TableGen.cpp | 21 +++- 4 files changed, 426 insertions(+), 1 deletion(-) create mode 100644 utils/TableGen/SetTheory.cpp create mode 100644 utils/TableGen/SetTheory.h (limited to 'utils') diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 514b191..db58237 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 0000000..d2f1b22 --- /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(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(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(Expr->arg_begin()[1])) + From = II->getValue(); + else + throw "From must be an integer: " + Expr->getAsString(); + if (IntInit *II = dynamic_cast(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(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(Expr)) + return evaluate(LI->begin(), LI->end(), Elts); + + // Anything else must be a DAG. + DagInit *DagExpr = dynamic_cast(Expr); + if (!DagExpr) + throw "Invalid set element: " + Expr->getAsString(); + DefInit *OpInit = dynamic_cast(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 &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 0000000..c648d46 --- /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 +#include + +namespace llvm { + +class DagInit; +struct Init; +class Record; +class RecordKeeper; + +class SetTheory { +public: + typedef std::vector RecVec; + typedef SmallSetVector 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 ExpandMap; + ExpandMap Expansions; + + // Known DAG operators by name. + StringMap Operators; + + // Typed expanders by class name. + StringMap 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 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 + 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 fb941c4..925b134 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 @@ -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 Recs = Records.getAllDerivedDefinitions("Set"); + for (unsigned i = 0, e = Recs.size(); i != e; ++i) { + Out.os() << Recs[i]->getName() << " = ["; + const std::vector *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; -- cgit v1.1