summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/TableGen/Record.h29
-rw-r--r--lib/TableGen/TGParser.cpp9
-rw-r--r--test/TableGen/ClassInstanceValue.td19
3 files changed, 54 insertions, 3 deletions
diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h
index d4bc5572482..8c5452e511c 100644
--- a/include/llvm/TableGen/Record.h
+++ b/include/llvm/TableGen/Record.h
@@ -1401,6 +1401,18 @@ class Record {
DefInit *TheInit;
bool IsAnonymous;
+ // Class-instance values can be used by other defs. For example, Struct<i>
+ // is used here as a template argument to another class:
+ //
+ // multiclass MultiClass<int i> {
+ // def Def : Class<Struct<i>>;
+ //
+ // These need to get fully resolved before instantiating any other
+ // definitions that usie them (e.g. Def). However, inside a multiclass they
+ // can't be immediately resolved so we mark them ResolveFirst to fully
+ // resolve them later as soon as the multiclass is instantiated.
+ bool ResolveFirst;
+
void init();
void checkName();
@@ -1409,13 +1421,15 @@ public:
explicit Record(const std::string &N, ArrayRef<SMLoc> locs,
RecordKeeper &records, bool Anonymous = false) :
ID(LastID++), Name(StringInit::get(N)), Locs(locs.begin(), locs.end()),
- TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous) {
+ TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous),
+ ResolveFirst(false) {
init();
}
explicit Record(Init *N, ArrayRef<SMLoc> locs, RecordKeeper &records,
bool Anonymous = false) :
ID(LastID++), Name(N), Locs(locs.begin(), locs.end()),
- TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous) {
+ TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous),
+ ResolveFirst(false) {
init();
}
@@ -1425,7 +1439,8 @@ public:
ID(LastID++), Name(O.Name), Locs(O.Locs), TemplateArgs(O.TemplateArgs),
Values(O.Values), SuperClasses(O.SuperClasses),
SuperClassRanges(O.SuperClassRanges), TrackedRecords(O.TrackedRecords),
- TheInit(O.TheInit), IsAnonymous(O.IsAnonymous) { }
+ TheInit(O.TheInit), IsAnonymous(O.IsAnonymous),
+ ResolveFirst(O.ResolveFirst) { }
~Record() {}
@@ -1553,6 +1568,14 @@ public:
return IsAnonymous;
}
+ bool isResolveFirst() const {
+ return ResolveFirst;
+ }
+
+ void setResolveFirst(bool b) {
+ ResolveFirst = b;
+ }
+
void dump() const;
//===--------------------------------------------------------------------===//
diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp
index 15039792042..f2910019ed9 100644
--- a/lib/TableGen/TGParser.cpp
+++ b/lib/TableGen/TGParser.cpp
@@ -1264,6 +1264,9 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
NewRec->resolveReferences();
Records.addDef(NewRec);
} else {
+ // This needs to get resolved once the multiclass template arguments are
+ // known before any use.
+ NewRec->setResolveFirst(true);
// Otherwise, we're inside a multiclass, add it to the multiclass.
CurMultiClass->DefPrototypes.push_back(NewRec);
@@ -2602,6 +2605,12 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
if (ResolveMulticlassDef(*MC, CurRec, DefProto, DefmLoc))
return Error(SubClassLoc, "could not instantiate def");
+ // Defs that can be used by other definitions should be fully resolved
+ // before any use.
+ if (DefProto->isResolveFirst() && !CurMultiClass) {
+ CurRec->resolveReferences();
+ CurRec->setResolveFirst(false);
+ }
NewRecDefs.push_back(CurRec);
}
diff --git a/test/TableGen/ClassInstanceValue.td b/test/TableGen/ClassInstanceValue.td
new file mode 100644
index 00000000000..b6c4c93cb09
--- /dev/null
+++ b/test/TableGen/ClassInstanceValue.td
@@ -0,0 +1,19 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+class Struct<int i> {
+ int I = !shl(i, 1);
+ int J = !shl(I, 1);
+}
+
+class Class<Struct s> {
+ int Class_J = s.J;
+}
+
+multiclass MultiClass<int i> {
+ def Def : Class<Struct<i>>;
+// CHECK: Class_J = 8
+// CHECK-NOT: Class_J = !shl(I, 1)
+}
+
+defm Defm : MultiClass<2>;