mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[TableGen] Fix anonymous record self-reference in foreach and multiclass
If we instantiate self-referenced anonymous records in foreach and multiclass, the NAME value will point to incorrect record. It's because anonymous name is resolved too early. This patch adds AnonymousNameInit to represent an anonymous record name. When instantiating an anonymous record, it will update the referred name. Differential Revision: https://reviews.llvm.org/D95309
This commit is contained in:
parent
c54bcb01a6
commit
c233f2a4f7
@ -301,6 +301,7 @@ protected:
|
||||
IK_CondOpInit,
|
||||
IK_FoldOpInit,
|
||||
IK_IsAOpInit,
|
||||
IK_AnonymousNameInit,
|
||||
IK_StringInit,
|
||||
IK_VarInit,
|
||||
IK_VarListElementInit,
|
||||
@ -576,6 +577,36 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// "anonymous_n" - Represent an anonymous record name
|
||||
class AnonymousNameInit : public TypedInit {
|
||||
unsigned Value;
|
||||
|
||||
explicit AnonymousNameInit(unsigned V)
|
||||
: TypedInit(IK_AnonymousNameInit, StringRecTy::get()), Value(V) {}
|
||||
|
||||
public:
|
||||
AnonymousNameInit(const AnonymousNameInit &) = delete;
|
||||
AnonymousNameInit &operator=(const AnonymousNameInit &) = delete;
|
||||
|
||||
static bool classof(const Init *I) {
|
||||
return I->getKind() == IK_AnonymousNameInit;
|
||||
}
|
||||
|
||||
static AnonymousNameInit *get(unsigned);
|
||||
|
||||
unsigned getValue() const { return Value; }
|
||||
|
||||
StringInit *getNameInit() const;
|
||||
|
||||
std::string getAsString() const override;
|
||||
|
||||
Init *resolveReferences(Resolver &R) const override;
|
||||
|
||||
Init *getBit(unsigned Bit) const override {
|
||||
llvm_unreachable("Illegal bit reference off string");
|
||||
}
|
||||
};
|
||||
|
||||
/// "foo" - Represent an initialization by a string value.
|
||||
class StringInit : public TypedInit {
|
||||
public:
|
||||
@ -1618,7 +1649,7 @@ public:
|
||||
///
|
||||
/// This is a final resolve: any error messages, e.g. due to undefined
|
||||
/// !cast references, are generated now.
|
||||
void resolveReferences();
|
||||
void resolveReferences(Init *NewName = nullptr);
|
||||
|
||||
/// Apply the resolver to the name of the record as well as to the
|
||||
/// initializers of all fields of the record except SkipVal.
|
||||
@ -2002,10 +2033,13 @@ public:
|
||||
class RecordResolver final : public Resolver {
|
||||
DenseMap<Init *, Init *> Cache;
|
||||
SmallVector<Init *, 4> Stack;
|
||||
Init *Name = nullptr;
|
||||
|
||||
public:
|
||||
explicit RecordResolver(Record &R) : Resolver(&R) {}
|
||||
|
||||
void setName(Init *NewName) { Name = NewName; }
|
||||
|
||||
Init *resolve(Init *VarName) override;
|
||||
|
||||
bool keepUnsetBits() const override { return true; }
|
||||
|
@ -502,6 +502,28 @@ IntInit::convertInitializerBitRange(ArrayRef<unsigned> Bits) const {
|
||||
return BitsInit::get(NewBits);
|
||||
}
|
||||
|
||||
AnonymousNameInit *AnonymousNameInit::get(unsigned V) {
|
||||
return new (Allocator) AnonymousNameInit(V);
|
||||
}
|
||||
|
||||
StringInit *AnonymousNameInit::getNameInit() const {
|
||||
return StringInit::get(getAsString());
|
||||
}
|
||||
|
||||
std::string AnonymousNameInit::getAsString() const {
|
||||
return "anonymous_" + utostr(Value);
|
||||
}
|
||||
|
||||
Init *AnonymousNameInit::resolveReferences(Resolver &R) const {
|
||||
auto *Old = const_cast<Init *>(static_cast<const Init *>(this));
|
||||
auto *New = R.resolve(Old);
|
||||
New = New ? New : Old;
|
||||
if (R.isFinal())
|
||||
if (auto *Anonymous = dyn_cast<AnonymousNameInit>(New))
|
||||
return Anonymous->getNameInit();
|
||||
return New;
|
||||
}
|
||||
|
||||
StringInit *StringInit::get(StringRef V, StringFormat Fmt) {
|
||||
static StringMap<StringInit*, BumpPtrAllocator &> StringPool(Allocator);
|
||||
static StringMap<StringInit*, BumpPtrAllocator &> CodePool(Allocator);
|
||||
@ -701,7 +723,9 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
|
||||
|
||||
// Self-references are allowed, but their resolution is delayed until
|
||||
// the final resolve to ensure that we get the correct type for them.
|
||||
if (Name == CurRec->getNameInit()) {
|
||||
auto *Anonymous = dyn_cast<AnonymousNameInit>(CurRec->getNameInit());
|
||||
if (Name == CurRec->getNameInit() ||
|
||||
(Anonymous && Name == Anonymous->getNameInit())) {
|
||||
if (!IsFinal)
|
||||
break;
|
||||
D = CurRec;
|
||||
@ -2304,6 +2328,12 @@ void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const {
|
||||
}
|
||||
|
||||
void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
|
||||
Init *OldName = getNameInit();
|
||||
Init *NewName = Name->resolveReferences(R);
|
||||
if (NewName != OldName) {
|
||||
// Re-register with RecordKeeper.
|
||||
setName(NewName);
|
||||
}
|
||||
for (RecordVal &Value : Values) {
|
||||
if (SkipVal == &Value) // Skip resolve the same field as the given one
|
||||
continue;
|
||||
@ -2324,16 +2354,11 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Init *OldName = getNameInit();
|
||||
Init *NewName = Name->resolveReferences(R);
|
||||
if (NewName != OldName) {
|
||||
// Re-register with RecordKeeper.
|
||||
setName(NewName);
|
||||
}
|
||||
}
|
||||
|
||||
void Record::resolveReferences() {
|
||||
void Record::resolveReferences(Init *NewName) {
|
||||
RecordResolver R(*this);
|
||||
R.setName(NewName);
|
||||
R.setFinal(true);
|
||||
resolveReferences(R);
|
||||
}
|
||||
@ -2588,7 +2613,7 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const RecordKeeper &RK) {
|
||||
/// GetNewAnonymousName - Generate a unique anonymous name that can be used as
|
||||
/// an identifier.
|
||||
Init *RecordKeeper::getNewAnonymousName() {
|
||||
return StringInit::get("anonymous_" + utostr(AnonCounter++));
|
||||
return AnonymousNameInit::get(AnonCounter++);
|
||||
}
|
||||
|
||||
// These functions implement the phase timing facility. Starting a timer
|
||||
@ -2702,6 +2727,10 @@ Init *RecordResolver::resolve(Init *VarName) {
|
||||
Val = Val->resolveReferences(*this);
|
||||
Stack.pop_back();
|
||||
}
|
||||
} else if (Name && VarName == getCurrentRecord()->getNameInit()) {
|
||||
Stack.push_back(VarName);
|
||||
Val = Name->resolveReferences(*this);
|
||||
Stack.pop_back();
|
||||
}
|
||||
|
||||
Cache[VarName] = Val;
|
||||
|
@ -439,6 +439,7 @@ bool TGParser::resolve(const std::vector<RecordsEntry> &Source,
|
||||
|
||||
/// Resolve the record fully and add it to the record keeper.
|
||||
bool TGParser::addDefOne(std::unique_ptr<Record> Rec) {
|
||||
Init *NewName = nullptr;
|
||||
if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) {
|
||||
if (!Rec->isAnonymous()) {
|
||||
PrintError(Rec->getLoc(),
|
||||
@ -446,10 +447,10 @@ bool TGParser::addDefOne(std::unique_ptr<Record> Rec) {
|
||||
PrintNote(Prev->getLoc(), "location of previous definition");
|
||||
return true;
|
||||
}
|
||||
Rec->setName(Records.getNewAnonymousName());
|
||||
NewName = Records.getNewAnonymousName();
|
||||
}
|
||||
|
||||
Rec->resolveReferences();
|
||||
Rec->resolveReferences(NewName);
|
||||
checkConcrete(*Rec);
|
||||
|
||||
CheckRecordAsserts(*Rec);
|
||||
|
@ -32,6 +32,19 @@
|
||||
// CHECK: Fc as_c = F0;
|
||||
// CHECK: }
|
||||
|
||||
// CHECK: def anonymous_0 {
|
||||
// CHECK: G g = anonymous_0;
|
||||
// CHECK: }
|
||||
// CHECK: def anonymous_1 {
|
||||
// CHECK: G g = anonymous_1;
|
||||
// CHECK: }
|
||||
// CHECK: def anonymous_2 {
|
||||
// CHECK: G g = anonymous_2;
|
||||
// CHECK: }
|
||||
// CHECK: def anonymous_5 {
|
||||
// CHECK: G g = anonymous_5;
|
||||
// CHECK: }
|
||||
|
||||
def ops;
|
||||
|
||||
class A<dag d> {
|
||||
@ -96,3 +109,18 @@ def F0 : Fa, Fb<F0>, Fc<F0>;
|
||||
def F0x {
|
||||
Fc as_c = F0;
|
||||
}
|
||||
|
||||
// anonymous record self-reference in foreach and multiclass
|
||||
class G {
|
||||
G g = !cast<G>(NAME);
|
||||
}
|
||||
|
||||
foreach _ = [1, 2] in
|
||||
def : G;
|
||||
|
||||
multiclass H {
|
||||
def : G;
|
||||
}
|
||||
|
||||
defm : H;
|
||||
defm : H;
|
||||
|
Loading…
x
Reference in New Issue
Block a user