Skip to content

Commit 13080fd

Browse files
committedMar 6, 2018
TableGen: Generalize record types to fix typeIsConvertibleTo et al.
Summary: Allow RecordRecTy to represent the type "subclass of N superclasses", where N may be zero. Furthermore, generate RecordRecTy instances only with actual classes in the list. Keeping track of multiple superclasses is required to resolve the type of a list correctly in some cases. The old code relied on the incorrect behavior of typeIsConvertibleTo, and an earlier version of this change relied on a modified ordering of superclasses (it was committed in r325884 and then reverted because unfortunately some of clang-tblgen's backends depend on the ordering). Previously, the DefInit for each Record would have a RecordRecTy of that Record as its type. Now, all defs with the same superclasses will share the same type. This allows us to be more consistent about type checks involving records: - typeIsConvertibleTo actually requires the LHS to be a subtype of the RHS - resolveTypes will return the least supertype of given record types in all cases - different record types in the two branches of an !if are handled correctly Add a test that used to be accepted without flagging the obvious type error. Change-Id: Ib366db1a4e6a079f1a0851e469b402cddae76714 Reviewers: arsenm, craig.topper, tra, MartinO Subscribers: wdng, llvm-commits Differential Revision: https://reviews.llvm.org/D43680 llvm-svn: 326783
1 parent 945a84a commit 13080fd

File tree

5 files changed

+217
-51
lines changed

5 files changed

+217
-51
lines changed
 

‎llvm/include/llvm/TableGen/Record.h

+37-8
Original file line numberDiff line numberDiff line change
@@ -223,26 +223,47 @@ class DagRecTy : public RecTy {
223223
std::string getAsString() const override;
224224
};
225225

226-
/// '[classname]' - Represent an instance of a class, such as:
227-
/// (R32 X = EAX).
228-
class RecordRecTy : public RecTy {
226+
/// '[classname]' - Type of record values that have zero or more superclasses.
227+
///
228+
/// The list of superclasses is non-redundant, i.e. only contains classes that
229+
/// are not the superclass of some other listed class.
230+
class RecordRecTy final : public RecTy, public FoldingSetNode,
231+
public TrailingObjects<RecordRecTy, Record *> {
229232
friend class Record;
230233

231-
Record *Rec;
234+
unsigned NumClasses;
232235

233-
explicit RecordRecTy(Record *R) : RecTy(RecordRecTyKind), Rec(R) {}
236+
explicit RecordRecTy(unsigned Num)
237+
: RecTy(RecordRecTyKind), NumClasses(Num) {}
234238

235239
public:
240+
RecordRecTy(const RecordRecTy &) = delete;
241+
RecordRecTy &operator=(const RecordRecTy &) = delete;
242+
243+
// Do not use sized deallocation due to trailing objects.
244+
void operator delete(void *p) { ::operator delete(p); }
245+
236246
static bool classof(const RecTy *RT) {
237247
return RT->getRecTyKind() == RecordRecTyKind;
238248
}
239249

240-
static RecordRecTy *get(Record *R);
250+
/// Get the record type with the given non-redundant list of superclasses.
251+
static RecordRecTy *get(ArrayRef<Record *> Classes);
252+
253+
void Profile(FoldingSetNodeID &ID) const;
254+
255+
ArrayRef<Record *> getClasses() const {
256+
return makeArrayRef(getTrailingObjects<Record *>(), NumClasses);
257+
}
258+
259+
using const_record_iterator = Record * const *;
241260

242-
Record *getRecord() const { return Rec; }
261+
const_record_iterator classes_begin() const { return getClasses().begin(); }
262+
const_record_iterator classes_end() const { return getClasses().end(); }
243263

244264
std::string getAsString() const override;
245265

266+
bool isSubClassOf(Record *Class) const;
246267
bool typeIsConvertibleTo(const RecTy *RHS) const override;
247268
};
248269

@@ -984,7 +1005,7 @@ class DefInit : public TypedInit {
9841005

9851006
Record *Def;
9861007

987-
DefInit(Record *D, RecordRecTy *T) : TypedInit(IK_DefInit, T), Def(D) {}
1008+
explicit DefInit(Record *D);
9881009

9891010
public:
9901011
DefInit(const DefInit &) = delete;
@@ -1189,6 +1210,9 @@ class Record {
11891210
SmallVector<SMLoc, 4> Locs;
11901211
SmallVector<Init *, 0> TemplateArgs;
11911212
SmallVector<RecordVal, 0> Values;
1213+
1214+
// All superclasses in the inheritance forest in reverse preorder (yes, it
1215+
// must be a forest; diamond-shaped inheritance is not allowed).
11921216
SmallVector<std::pair<Record *, SMRange>, 0> SuperClasses;
11931217

11941218
// Tracks Record instances. Not owned by Record.
@@ -1269,6 +1293,9 @@ class Record {
12691293
return SuperClasses;
12701294
}
12711295

1296+
/// Append the direct super classes of this record to Classes.
1297+
void getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const;
1298+
12721299
bool isTemplateArg(Init *Name) const {
12731300
for (Init *TA : TemplateArgs)
12741301
if (TA == Name) return true;
@@ -1465,8 +1492,10 @@ struct MultiClass {
14651492
};
14661493

14671494
class RecordKeeper {
1495+
friend class RecordRecTy;
14681496
using RecordMap = std::map<std::string, std::unique_ptr<Record>>;
14691497
RecordMap Classes, Defs;
1498+
FoldingSet<RecordRecTy> RecordTypePool;
14701499

14711500
public:
14721501
const RecordMap &getClasses() const { return Classes; }

‎llvm/lib/TableGen/Record.cpp

+140-36
Original file line numberDiff line numberDiff line change
@@ -125,54 +125,138 @@ std::string DagRecTy::getAsString() const {
125125
return "dag";
126126
}
127127

128-
RecordRecTy *RecordRecTy::get(Record *R) {
129-
return dyn_cast<RecordRecTy>(R->getDefInit()->getType());
128+
static void ProfileRecordRecTy(FoldingSetNodeID &ID,
129+
ArrayRef<Record *> Classes) {
130+
ID.AddInteger(Classes.size());
131+
for (Record *R : Classes)
132+
ID.AddPointer(R);
133+
}
134+
135+
RecordRecTy *RecordRecTy::get(ArrayRef<Record *> UnsortedClasses) {
136+
if (UnsortedClasses.empty()) {
137+
static RecordRecTy AnyRecord(0);
138+
return &AnyRecord;
139+
}
140+
141+
FoldingSet<RecordRecTy> &ThePool =
142+
UnsortedClasses[0]->getRecords().RecordTypePool;
143+
144+
SmallVector<Record *, 4> Classes(UnsortedClasses.begin(),
145+
UnsortedClasses.end());
146+
std::sort(Classes.begin(), Classes.end(),
147+
[](Record *LHS, Record *RHS) {
148+
return LHS->getNameInitAsString() < RHS->getNameInitAsString();
149+
});
150+
151+
FoldingSetNodeID ID;
152+
ProfileRecordRecTy(ID, Classes);
153+
154+
void *IP = nullptr;
155+
if (RecordRecTy *Ty = ThePool.FindNodeOrInsertPos(ID, IP))
156+
return Ty;
157+
158+
#ifndef NDEBUG
159+
// Check for redundancy.
160+
for (unsigned i = 0; i < Classes.size(); ++i) {
161+
for (unsigned j = 0; j < Classes.size(); ++j) {
162+
assert(i == j || !Classes[i]->isSubClassOf(Classes[j]));
163+
}
164+
assert(&Classes[0]->getRecords() == &Classes[i]->getRecords());
165+
}
166+
#endif
167+
168+
void *Mem = Allocator.Allocate(totalSizeToAlloc<Record *>(Classes.size()),
169+
alignof(RecordRecTy));
170+
RecordRecTy *Ty = new(Mem) RecordRecTy(Classes.size());
171+
std::uninitialized_copy(Classes.begin(), Classes.end(),
172+
Ty->getTrailingObjects<Record *>());
173+
ThePool.InsertNode(Ty, IP);
174+
return Ty;
175+
}
176+
177+
void RecordRecTy::Profile(FoldingSetNodeID &ID) const {
178+
ProfileRecordRecTy(ID, getClasses());
130179
}
131180

132181
std::string RecordRecTy::getAsString() const {
133-
return Rec->getName();
182+
if (NumClasses == 1)
183+
return getClasses()[0]->getName();
184+
185+
std::string Str = "{";
186+
bool First = true;
187+
for (Record *R : getClasses()) {
188+
if (!First)
189+
Str += ", ";
190+
First = false;
191+
Str += R->getName();
192+
}
193+
Str += "}";
194+
return Str;
195+
}
196+
197+
bool RecordRecTy::isSubClassOf(Record *Class) const {
198+
return llvm::any_of(getClasses(), [Class](Record *MySuperClass) {
199+
return MySuperClass == Class ||
200+
MySuperClass->isSubClassOf(Class);
201+
});
134202
}
135203

136204
bool RecordRecTy::typeIsConvertibleTo(const RecTy *RHS) const {
205+
if (this == RHS)
206+
return true;
207+
137208
const RecordRecTy *RTy = dyn_cast<RecordRecTy>(RHS);
138209
if (!RTy)
139210
return false;
140211

141-
if (RTy->getRecord() == Rec || Rec->isSubClassOf(RTy->getRecord()))
142-
return true;
212+
return llvm::all_of(RTy->getClasses(), [this](Record *TargetClass) {
213+
return isSubClassOf(TargetClass);
214+
});
215+
}
143216

144-
for (const auto &SCPair : RTy->getRecord()->getSuperClasses())
145-
if (Rec->isSubClassOf(SCPair.first))
146-
return true;
217+
static RecordRecTy *resolveRecordTypes(RecordRecTy *T1, RecordRecTy *T2) {
218+
SmallVector<Record *, 4> CommonSuperClasses;
219+
SmallVector<Record *, 4> Stack;
147220

148-
return false;
221+
Stack.insert(Stack.end(), T1->classes_begin(), T1->classes_end());
222+
223+
while (!Stack.empty()) {
224+
Record *R = Stack.back();
225+
Stack.pop_back();
226+
227+
if (T2->isSubClassOf(R)) {
228+
CommonSuperClasses.push_back(R);
229+
} else {
230+
R->getDirectSuperClasses(Stack);
231+
}
232+
}
233+
234+
return RecordRecTy::get(CommonSuperClasses);
149235
}
150236

151237
RecTy *llvm::resolveTypes(RecTy *T1, RecTy *T2) {
238+
if (T1 == T2)
239+
return T1;
240+
241+
if (RecordRecTy *RecTy1 = dyn_cast<RecordRecTy>(T1)) {
242+
if (RecordRecTy *RecTy2 = dyn_cast<RecordRecTy>(T2))
243+
return resolveRecordTypes(RecTy1, RecTy2);
244+
}
245+
152246
if (T1->typeIsConvertibleTo(T2))
153247
return T2;
154248
if (T2->typeIsConvertibleTo(T1))
155249
return T1;
156250

157-
// If one is a Record type, check superclasses
158-
if (RecordRecTy *RecTy1 = dyn_cast<RecordRecTy>(T1)) {
159-
// See if T2 inherits from a type T1 also inherits from
160-
for (const auto &SuperPair1 : RecTy1->getRecord()->getSuperClasses()) {
161-
RecordRecTy *SuperRecTy1 = RecordRecTy::get(SuperPair1.first);
162-
RecTy *NewType1 = resolveTypes(SuperRecTy1, T2);
163-
if (NewType1)
164-
return NewType1;
165-
}
166-
}
167-
if (RecordRecTy *RecTy2 = dyn_cast<RecordRecTy>(T2)) {
168-
// See if T1 inherits from a type T2 also inherits from
169-
for (const auto &SuperPair2 : RecTy2->getRecord()->getSuperClasses()) {
170-
RecordRecTy *SuperRecTy2 = RecordRecTy::get(SuperPair2.first);
171-
RecTy *NewType2 = resolveTypes(T1, SuperRecTy2);
172-
if (NewType2)
173-
return NewType2;
251+
if (ListRecTy *ListTy1 = dyn_cast<ListRecTy>(T1)) {
252+
if (ListRecTy *ListTy2 = dyn_cast<ListRecTy>(T2)) {
253+
RecTy* NewType = resolveTypes(ListTy1->getElementType(),
254+
ListTy2->getElementType());
255+
if (NewType)
256+
return NewType->getListTy();
174257
}
175258
}
259+
176260
return nullptr;
177261
}
178262

@@ -1082,9 +1166,12 @@ std::string TernOpInit::getAsString() const {
10821166
}
10831167

10841168
RecTy *TypedInit::getFieldType(StringInit *FieldName) const {
1085-
if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType()))
1086-
if (RecordVal *Field = RecordType->getRecord()->getValue(FieldName))
1087-
return Field->getType();
1169+
if (RecordRecTy *RecordType = dyn_cast<RecordRecTy>(getType())) {
1170+
for (Record *Rec : RecordType->getClasses()) {
1171+
if (RecordVal *Field = Rec->getValue(FieldName))
1172+
return Field->getType();
1173+
}
1174+
}
10881175
return nullptr;
10891176
}
10901177

@@ -1159,11 +1246,8 @@ TypedInit::convertInitializerTo(RecTy *Ty) const {
11591246
}
11601247

11611248
if (auto *SRRT = dyn_cast<RecordRecTy>(Ty)) {
1162-
// Ensure that this is compatible with Rec.
1163-
if (RecordRecTy *DRRT = dyn_cast<RecordRecTy>(getType()))
1164-
if (DRRT->getRecord()->isSubClassOf(SRRT->getRecord()) ||
1165-
DRRT->getRecord() == SRRT->getRecord())
1166-
return const_cast<TypedInit *>(this);
1249+
if (getType()->typeIsConvertibleTo(SRRT))
1250+
return const_cast<TypedInit *>(this);
11671251
return nullptr;
11681252
}
11691253

@@ -1302,13 +1386,22 @@ Init *VarListElementInit::getBit(unsigned Bit) const {
13021386
return VarBitInit::get(const_cast<VarListElementInit*>(this), Bit);
13031387
}
13041388

1389+
static RecordRecTy *makeDefInitType(Record *Rec) {
1390+
SmallVector<Record *, 4> SuperClasses;
1391+
Rec->getDirectSuperClasses(SuperClasses);
1392+
return RecordRecTy::get(SuperClasses);
1393+
}
1394+
1395+
DefInit::DefInit(Record *D)
1396+
: TypedInit(IK_DefInit, makeDefInitType(D)), Def(D) {}
1397+
13051398
DefInit *DefInit::get(Record *R) {
13061399
return R->getDefInit();
13071400
}
13081401

13091402
Init *DefInit::convertInitializerTo(RecTy *Ty) const {
13101403
if (auto *RRT = dyn_cast<RecordRecTy>(Ty))
1311-
if (getDef()->isSubClassOf(RRT->getRecord()))
1404+
if (getType()->typeIsConvertibleTo(RRT))
13121405
return const_cast<DefInit *>(this);
13131406
return nullptr;
13141407
}
@@ -1497,7 +1590,7 @@ void Record::checkName() {
14971590

14981591
DefInit *Record::getDefInit() {
14991592
if (!TheInit)
1500-
TheInit = new(Allocator) DefInit(this, new(Allocator) RecordRecTy(this));
1593+
TheInit = new(Allocator) DefInit(this);
15011594
return TheInit;
15021595
}
15031596

@@ -1517,6 +1610,17 @@ void Record::setName(Init *NewName) {
15171610
// this. See TGParser::ParseDef and TGParser::ParseDefm.
15181611
}
15191612

1613+
void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const {
1614+
ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses();
1615+
while (!SCs.empty()) {
1616+
// Superclasses are in reverse preorder, so 'back' is a direct superclass,
1617+
// and its transitive superclasses are directly preceding it.
1618+
Record *SC = SCs.back().first;
1619+
SCs = SCs.drop_back(1 + SC->getSuperClasses().size());
1620+
Classes.push_back(SC);
1621+
}
1622+
}
1623+
15201624
void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
15211625
for (RecordVal &Value : Values) {
15221626
if (SkipVal == &Value) // Skip resolve the same field as the given one

‎llvm/lib/TableGen/TGParser.cpp

+5-7
Original file line numberDiff line numberDiff line change
@@ -1178,12 +1178,10 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
11781178
return nullptr;
11791179
}
11801180

1181-
if (MHSTy->typeIsConvertibleTo(RHSTy)) {
1182-
Type = RHSTy;
1183-
} else if (RHSTy->typeIsConvertibleTo(MHSTy)) {
1184-
Type = MHSTy;
1185-
} else {
1186-
TokError("inconsistent types for !if");
1181+
Type = resolveTypes(MHSTy, RHSTy);
1182+
if (!Type) {
1183+
TokError(Twine("inconsistent types '") + MHSTy->getAsString() +
1184+
"' and '" + RHSTy->getAsString() + "' for !if");
11871185
return nullptr;
11881186
}
11891187
break;
@@ -1364,7 +1362,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
13641362
MCNameRV->getType()),
13651363
NewRec->getNameInit(),
13661364
StringRecTy::get()),
1367-
Class->getDefInit()->getType());
1365+
NewRec->getDefInit()->getType());
13681366
}
13691367

13701368
// The result of the expression is a reference to the new record.

‎llvm/test/TableGen/if-type.td

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
2+
// XFAIL: vg_leak
3+
4+
class A<int dummy> {}
5+
class B<int dummy> : A<dummy> {}
6+
class C<int dummy> : A<dummy> {}
7+
8+
// CHECK: Value 'x' of type 'C' is incompatible with initializer '{{.*}}' of type 'A'
9+
class X<int cc, B b, C c> {
10+
C x = !if(cc, b, c);
11+
}

0 commit comments

Comments
 (0)