From 763d8b2ef7fe7926c0f82fc725ee8d2cb40c51a9 Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Tue, 16 Sep 2014 17:14:13 +0000 Subject: [PATCH] [TableGen] Fully resolve class-instance values before defs in multiclasses By class-instance values I mean 'Class' in 'Class.Field' or in 'Other>' (syntactically s SimpleValue). This is to differentiate from unnamed/anonymous record definitions (syntactically an ObjectBody) which are not affected by this change. Consider the testcase: class Struct { int I = !shl(i, 1); int J = !shl(I, 1); } class Class { int Class_J = s.J; } multiclass MultiClass { def Def : Class>; } defm Defm : MultiClass<2>; Before this fix, DefmDef.Class_J yields !shl(I, 1) instead of 8. This is the sequence of events. We start with this: multiclass MultiClass { def Def : Class>; } During ParseDef the anonymous object for the class-instance value is created: multiclass Multiclass { def anonymous_0 : Struct; def Def : Class; } Then class Struct is added to anonymous_0. Also Class is added to Def: multiclass Multiclass { def anonymous_0 { int I = !shl(i, 1); int J = !shl(I, 1); } def Def { int Class_J = NAME#anonymous_0.J; } } So far so good but then we move on to instantiating this in the defm by substituting the template arg 'i'. This is how the anonymous prototype looks after fully instantiating. defm Defm = { def Defmanonymous_0 { int I = 4; int J = !shl(I, 1); } Note that we only resolved the reference to the template arg. The non-template-arg reference in 'J' has not been resolved yet. Then we go on to instantiating the Def prototype: def DefmDef { int Class_J = NAME#anonymous_0.J; } Which is resolved to Defmanonymous_0.J and then to !shl(I, 1). When we fully resolve each record in a defm, Defmanonymous_0.J does get set to 8 but that's too late for its use. The patch adds a new attribute to the Record class that indicates that this def is actually a class-instance value that may be *used* by other defs in a multiclass. (This is unlike regular defs which don't reference each other and thus can be resolved indepedently.) They are then fully resolved before the other defs while the multiclass is instantiated. I added vg_leak to the new test. I am not sure if this is necessary but I don't think I have a way to test it. I can also check in without the XFAIL and let the bots test this part. Also tested that X86.td.expanded and AAarch64.td.expanded were unchange before and after this change. (This issue triggering this problem is a WIP patch.) Part of git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217886 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/TableGen/Record.h | 29 ++++++++++++++++++++++++++--- lib/TableGen/TGParser.cpp | 9 +++++++++ test/TableGen/ClassInstanceValue.td | 19 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 test/TableGen/ClassInstanceValue.td 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 + // is used here as a template argument to another class: + // + // multiclass MultiClass { + // def Def : Class>; + // + // 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 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 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 = !shl(i, 1); + int J = !shl(I, 1); +} + +class Class { + int Class_J = s.J; +} + +multiclass MultiClass { + def Def : Class>; +// CHECK: Class_J = 8 +// CHECK-NOT: Class_J = !shl(I, 1) +} + +defm Defm : MultiClass<2>;