llvm.org GIT mirror llvm / 763d8b2
[TableGen] Fully resolve class-instance values before defs in multiclasses By class-instance values I mean 'Class<Arg>' in 'Class<Arg>.Field' or in 'Other<Class<Arg>>' (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> { 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>>; } 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<int i> { def Def : Class<Struct<i>>; } During ParseDef the anonymous object for the class-instance value is created: multiclass Multiclass<int i> { def anonymous_0 : Struct<i>; def Def : Class<NAME#anonymous_0>; } Then class Struct<i> is added to anonymous_0. Also Class<NAME#anonymous_0> is added to Def: multiclass Multiclass<int i> { 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 <rdar://problem/17688758> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217886 91177308-0d34-0410-b5e6-96231b3b80d8 Adam Nemet 6 years ago
3 changed file(s) with 54 addition(s) and 3 deletion(s). Raw diff Collapse all Expand all
14001400 DefInit *TheInit;
14011401 bool IsAnonymous;
14021402
1403 // Class-instance values can be used by other defs. For example, Struct
1404 // is used here as a template argument to another class:
1405 //
1406 // multiclass MultiClass {
1407 // def Def : Class>;
1408 //
1409 // These need to get fully resolved before instantiating any other
1410 // definitions that usie them (e.g. Def). However, inside a multiclass they
1411 // can't be immediately resolved so we mark them ResolveFirst to fully
1412 // resolve them later as soon as the multiclass is instantiated.
1413 bool ResolveFirst;
1414
14031415 void init();
14041416 void checkName();
14051417
14081420 explicit Record(const std::string &N, ArrayRef locs,
14091421 RecordKeeper &records, bool Anonymous = false) :
14101422 ID(LastID++), Name(StringInit::get(N)), Locs(locs.begin(), locs.end()),
1411 TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous) {
1423 TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous),
1424 ResolveFirst(false) {
14121425 init();
14131426 }
14141427 explicit Record(Init *N, ArrayRef locs, RecordKeeper &records,
14151428 bool Anonymous = false) :
14161429 ID(LastID++), Name(N), Locs(locs.begin(), locs.end()),
1417 TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous) {
1430 TrackedRecords(records), TheInit(nullptr), IsAnonymous(Anonymous),
1431 ResolveFirst(false) {
14181432 init();
14191433 }
14201434
14241438 ID(LastID++), Name(O.Name), Locs(O.Locs), TemplateArgs(O.TemplateArgs),
14251439 Values(O.Values), SuperClasses(O.SuperClasses),
14261440 SuperClassRanges(O.SuperClassRanges), TrackedRecords(O.TrackedRecords),
1427 TheInit(O.TheInit), IsAnonymous(O.IsAnonymous) { }
1441 TheInit(O.TheInit), IsAnonymous(O.IsAnonymous),
1442 ResolveFirst(O.ResolveFirst) { }
14281443
14291444 ~Record() {}
14301445
15501565
15511566 bool isAnonymous() const {
15521567 return IsAnonymous;
1568 }
1569
1570 bool isResolveFirst() const {
1571 return ResolveFirst;
1572 }
1573
1574 void setResolveFirst(bool b) {
1575 ResolveFirst = b;
15531576 }
15541577
15551578 void dump() const;
12631263 NewRec->resolveReferences();
12641264 Records.addDef(NewRec);
12651265 } else {
1266 // This needs to get resolved once the multiclass template arguments are
1267 // known before any use.
1268 NewRec->setResolveFirst(true);
12661269 // Otherwise, we're inside a multiclass, add it to the multiclass.
12671270 CurMultiClass->DefPrototypes.push_back(NewRec);
12681271
26012604 if (ResolveMulticlassDef(*MC, CurRec, DefProto, DefmLoc))
26022605 return Error(SubClassLoc, "could not instantiate def");
26032606
2607 // Defs that can be used by other definitions should be fully resolved
2608 // before any use.
2609 if (DefProto->isResolveFirst() && !CurMultiClass) {
2610 CurRec->resolveReferences();
2611 CurRec->setResolveFirst(false);
2612 }
26042613 NewRecDefs.push_back(CurRec);
26052614 }
26062615
0 // RUN: llvm-tblgen %s | FileCheck %s
1 // XFAIL: vg_leak
2
3 class Struct {
4 int I = !shl(i, 1);
5 int J = !shl(I, 1);
6 }
7
8 class Class {
9 int Class_J = s.J;
10 }
11
12 multiclass MultiClass {
13 def Def : Class>;
14 // CHECK: Class_J = 8
15 // CHECK-NOT: Class_J = !shl(I, 1)
16 }
17
18 defm Defm : MultiClass<2>;