TableGen: Check the dynamic type of !cast<Rec>(string)

Summary:
The docs already claim that this happens, but so far it hasn't. As a
consequence, existing TableGen files get this wrong a lot, but luckily
the fixes are all reasonably straightforward.

To make this work with all the existing forms of self-references (since
the true type of a record is only built up over time), the lookup of
self-references in !cast is delayed until the final resolving step.

Change-Id: If5923a72a252ba2fbc81a889d59775df0ef31164

Reviewers: arsenm, craig.topper, tra, MartinO

Subscribers: wdng, javed.absar, llvm-commits

Differential Revision: https://reviews.llvm.org/D44475

llvm-svn: 327849
This commit is contained in:
Nicolai Haehnle 2018-03-19 14:14:20 +00:00
parent 18f1998a00
commit 4186cc7c08
8 changed files with 158 additions and 90 deletions

View File

@ -788,7 +788,7 @@ public:
// Fold - If possible, fold this to a simpler init. Return this if not
// possible to fold.
Init *Fold(Record *CurRec) const;
Init *Fold(Record *CurRec, bool IsFinal = false) const;
Init *resolveReferences(Resolver &R) const override;
@ -1497,6 +1497,9 @@ public:
/// If there are any field references that refer to fields
/// that have been filled in, we can propagate the values now.
///
/// This is a final resolve: any error messages, e.g. due to undefined
/// !cast references, are generated now.
void resolveReferences();
/// Apply the resolver to the name of the record as well as to the
@ -1786,6 +1789,7 @@ Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass,
/// Init::resolveReferences.
class Resolver {
Record *CurRec;
bool IsFinal = false;
public:
explicit Resolver(Record *CurRec) : CurRec(CurRec) {}
@ -1801,6 +1805,13 @@ public:
// result in a ? (UnsetInit). This behavior is used to represent instruction
// encodings by keeping references to unset variables within a record.
virtual bool keepUnsetBits() const { return false; }
// Whether this is the final resolve step before adding a record to the
// RecordKeeper. Error reporting during resolve and related constant folding
// should only happen when this is true.
bool isFinal() const { return IsFinal; }
void setFinal(bool Final) { IsFinal = Final; }
};
/// Resolve arbitrary mappings.
@ -1861,7 +1872,10 @@ class ShadowResolver final : public Resolver {
DenseSet<Init *> Shadowed;
public:
explicit ShadowResolver(Resolver &R) : Resolver(R.getCurrentRecord()), R(R) {}
explicit ShadowResolver(Resolver &R)
: Resolver(R.getCurrentRecord()), R(R) {
setFinal(R.isFinal());
}
void addShadow(Init *Key) { Shadowed.insert(Key); }

View File

@ -1132,27 +1132,27 @@ def setne : PatFrag<(ops node:$lhs, node:$rhs),
multiclass binary_atomic_op_ord<SDNode atomic_op> {
def #NAME#_monotonic : PatFrag<(ops node:$ptr, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingMonotonic = 1;
}
def #NAME#_acquire : PatFrag<(ops node:$ptr, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingAcquire = 1;
}
def #NAME#_release : PatFrag<(ops node:$ptr, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingRelease = 1;
}
def #NAME#_acq_rel : PatFrag<(ops node:$ptr, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingAcquireRelease = 1;
}
def #NAME#_seq_cst : PatFrag<(ops node:$ptr, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingSequentiallyConsistent = 1;
}
@ -1160,27 +1160,27 @@ multiclass binary_atomic_op_ord<SDNode atomic_op> {
multiclass ternary_atomic_op_ord<SDNode atomic_op> {
def #NAME#_monotonic : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$cmp, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$cmp, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingMonotonic = 1;
}
def #NAME#_acquire : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$cmp, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$cmp, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingAcquire = 1;
}
def #NAME#_release : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$cmp, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$cmp, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingRelease = 1;
}
def #NAME#_acq_rel : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$cmp, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$cmp, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingAcquireRelease = 1;
}
def #NAME#_seq_cst : PatFrag<(ops node:$ptr, node:$cmp, node:$val),
(!cast<SDNode>(#NAME) node:$ptr, node:$cmp, node:$val)> {
(!cast<SDPatternOperator>(#NAME) node:$ptr, node:$cmp, node:$val)> {
let IsAtomic = 1;
let IsAtomicOrderingSequentiallyConsistent = 1;
}

View File

@ -194,7 +194,7 @@ void RecordRecTy::Profile(FoldingSetNodeID &ID) const {
std::string RecordRecTy::getAsString() const {
if (NumClasses == 1)
return getClasses()[0]->getName();
return getClasses()[0]->getNameInitAsString();
std::string Str = "{";
bool First = true;
@ -202,7 +202,7 @@ std::string RecordRecTy::getAsString() const {
if (!First)
Str += ", ";
First = false;
Str += R->getName();
Str += R->getNameInitAsString();
}
Str += "}";
return Str;
@ -700,7 +700,7 @@ void UnOpInit::Profile(FoldingSetNodeID &ID) const {
ProfileUnOpInit(ID, getOpcode(), getOperand(), getType());
}
Init *UnOpInit::Fold(Record *CurRec) const {
Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {
switch (getOpcode()) {
case CAST:
if (isa<StringRecTy>(getType())) {
@ -715,12 +715,34 @@ Init *UnOpInit::Fold(Record *CurRec) const {
} else if (isa<RecordRecTy>(getType())) {
if (StringInit *Name = dyn_cast<StringInit>(LHS)) {
assert(CurRec && "NULL pointer");
if (Record *D = (CurRec->getRecords()).getDef(Name->getValue()))
return DefInit::get(D);
Record *D;
// 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()) {
if (!IsFinal)
break;
D = CurRec;
} else {
D = CurRec->getRecords().getDef(Name->getValue());
if (!D) {
if (IsFinal)
PrintFatalError(CurRec->getLoc(),
Twine("Undefined reference to record: '") +
Name->getValue() + "'\n");
break;
}
}
DefInit *DI = DefInit::get(D);
if (!DI->getType()->typeIsA(getType())) {
PrintFatalError(CurRec->getLoc(),
Twine("Expected type '") +
getType()->getAsString() + "', got '" +
DI->getType()->getAsString() + "' in: " +
getAsString() + "\n");
}
return DI;
}
}
@ -762,9 +784,9 @@ Init *UnOpInit::Fold(Record *CurRec) const {
Init *UnOpInit::resolveReferences(Resolver &R) const {
Init *lhs = LHS->resolveReferences(R);
if (LHS != lhs)
if (LHS != lhs || (R.isFinal() && getOpcode() == CAST))
return (UnOpInit::get(getOpcode(), lhs, getType()))
->Fold(R.getCurrentRecord());
->Fold(R.getCurrentRecord(), R.isFinal());
return const_cast<UnOpInit *>(this);
}
@ -1904,6 +1926,7 @@ void Record::resolveReferences(Resolver &R, const RecordVal *SkipVal) {
void Record::resolveReferences() {
RecordResolver R(*this);
R.setFinal(true);
resolveReferences(R);
}

View File

@ -8789,7 +8789,7 @@ class BaseSIMDLdStSingleTied<bit L, bit R, bits<3> opcode,
let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in
class BaseSIMDLdR<bit Q, bit R, bits<3> opcode, bit S, bits<2> size, string asm,
Operand listtype>
DAGOperand listtype>
: BaseSIMDLdStSingle<1, R, opcode, asm, "\t$Vt, [$Rn]", "",
(outs listtype:$Vt), (ins GPR64sp:$Rn),
[]> {
@ -8801,7 +8801,7 @@ class BaseSIMDLdR<bit Q, bit R, bits<3> opcode, bit S, bits<2> size, string asm,
}
let mayLoad = 1, mayStore = 0, hasSideEffects = 0 in
class BaseSIMDLdRPost<bit Q, bit R, bits<3> opcode, bit S, bits<2> size,
string asm, Operand listtype, Operand GPR64pi>
string asm, DAGOperand listtype, DAGOperand GPR64pi>
: BaseSIMDLdStSingle<1, R, opcode, asm, "\t$Vt, [$Rn], $Xm",
"$Rn = $wback",
(outs GPR64sp:$wback, listtype:$Vt),
@ -8859,46 +8859,46 @@ multiclass SIMDLdrAliases<string asm, string layout, string Count,
multiclass SIMDLdR<bit R, bits<3> opcode, bit S, string asm, string Count,
int Offset1, int Offset2, int Offset4, int Offset8> {
def v8b : BaseSIMDLdR<0, R, opcode, S, 0b00, asm,
!cast<Operand>("VecList" # Count # "8b")>;
!cast<DAGOperand>("VecList" # Count # "8b")>;
def v16b: BaseSIMDLdR<1, R, opcode, S, 0b00, asm,
!cast<Operand>("VecList" # Count #"16b")>;
!cast<DAGOperand>("VecList" # Count #"16b")>;
def v4h : BaseSIMDLdR<0, R, opcode, S, 0b01, asm,
!cast<Operand>("VecList" # Count #"4h")>;
!cast<DAGOperand>("VecList" # Count #"4h")>;
def v8h : BaseSIMDLdR<1, R, opcode, S, 0b01, asm,
!cast<Operand>("VecList" # Count #"8h")>;
!cast<DAGOperand>("VecList" # Count #"8h")>;
def v2s : BaseSIMDLdR<0, R, opcode, S, 0b10, asm,
!cast<Operand>("VecList" # Count #"2s")>;
!cast<DAGOperand>("VecList" # Count #"2s")>;
def v4s : BaseSIMDLdR<1, R, opcode, S, 0b10, asm,
!cast<Operand>("VecList" # Count #"4s")>;
!cast<DAGOperand>("VecList" # Count #"4s")>;
def v1d : BaseSIMDLdR<0, R, opcode, S, 0b11, asm,
!cast<Operand>("VecList" # Count #"1d")>;
!cast<DAGOperand>("VecList" # Count #"1d")>;
def v2d : BaseSIMDLdR<1, R, opcode, S, 0b11, asm,
!cast<Operand>("VecList" # Count #"2d")>;
!cast<DAGOperand>("VecList" # Count #"2d")>;
def v8b_POST : BaseSIMDLdRPost<0, R, opcode, S, 0b00, asm,
!cast<Operand>("VecList" # Count # "8b"),
!cast<Operand>("GPR64pi" # Offset1)>;
!cast<DAGOperand>("VecList" # Count # "8b"),
!cast<DAGOperand>("GPR64pi" # Offset1)>;
def v16b_POST: BaseSIMDLdRPost<1, R, opcode, S, 0b00, asm,
!cast<Operand>("VecList" # Count # "16b"),
!cast<Operand>("GPR64pi" # Offset1)>;
!cast<DAGOperand>("VecList" # Count # "16b"),
!cast<DAGOperand>("GPR64pi" # Offset1)>;
def v4h_POST : BaseSIMDLdRPost<0, R, opcode, S, 0b01, asm,
!cast<Operand>("VecList" # Count # "4h"),
!cast<Operand>("GPR64pi" # Offset2)>;
!cast<DAGOperand>("VecList" # Count # "4h"),
!cast<DAGOperand>("GPR64pi" # Offset2)>;
def v8h_POST : BaseSIMDLdRPost<1, R, opcode, S, 0b01, asm,
!cast<Operand>("VecList" # Count # "8h"),
!cast<Operand>("GPR64pi" # Offset2)>;
!cast<DAGOperand>("VecList" # Count # "8h"),
!cast<DAGOperand>("GPR64pi" # Offset2)>;
def v2s_POST : BaseSIMDLdRPost<0, R, opcode, S, 0b10, asm,
!cast<Operand>("VecList" # Count # "2s"),
!cast<Operand>("GPR64pi" # Offset4)>;
!cast<DAGOperand>("VecList" # Count # "2s"),
!cast<DAGOperand>("GPR64pi" # Offset4)>;
def v4s_POST : BaseSIMDLdRPost<1, R, opcode, S, 0b10, asm,
!cast<Operand>("VecList" # Count # "4s"),
!cast<Operand>("GPR64pi" # Offset4)>;
!cast<DAGOperand>("VecList" # Count # "4s"),
!cast<DAGOperand>("GPR64pi" # Offset4)>;
def v1d_POST : BaseSIMDLdRPost<0, R, opcode, S, 0b11, asm,
!cast<Operand>("VecList" # Count # "1d"),
!cast<Operand>("GPR64pi" # Offset8)>;
!cast<DAGOperand>("VecList" # Count # "1d"),
!cast<DAGOperand>("GPR64pi" # Offset8)>;
def v2d_POST : BaseSIMDLdRPost<1, R, opcode, S, 0b11, asm,
!cast<Operand>("VecList" # Count # "2d"),
!cast<Operand>("GPR64pi" # Offset8)>;
!cast<DAGOperand>("VecList" # Count # "2d"),
!cast<DAGOperand>("GPR64pi" # Offset8)>;
defm : SIMDLdrAliases<asm, "8b", Count, Offset1, 64>;
defm : SIMDLdrAliases<asm, "16b", Count, Offset1, 128>;
@ -9947,15 +9947,15 @@ multiclass LDOPregister<bits<3> opc, string op, bits<1> Acq, bits<1> Rel,
let Predicates = [HasLSE] in
multiclass LDOPregister_patterns_ord_dag<string inst, string suffix, string op,
string size, dag SrcRHS, dag DstRHS> {
def : Pat<(!cast<SDNode>(op#"_"#size#"_monotonic") GPR64sp:$Rn, SrcRHS),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_monotonic") GPR64sp:$Rn, SrcRHS),
(!cast<Instruction>(inst # suffix) DstRHS, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_acquire") GPR64sp:$Rn, SrcRHS),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_acquire") GPR64sp:$Rn, SrcRHS),
(!cast<Instruction>(inst # "A" # suffix) DstRHS, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_release") GPR64sp:$Rn, SrcRHS),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_release") GPR64sp:$Rn, SrcRHS),
(!cast<Instruction>(inst # "L" # suffix) DstRHS, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_acq_rel") GPR64sp:$Rn, SrcRHS),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_acq_rel") GPR64sp:$Rn, SrcRHS),
(!cast<Instruction>(inst # "AL" # suffix) DstRHS, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_seq_cst") GPR64sp:$Rn, SrcRHS),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_seq_cst") GPR64sp:$Rn, SrcRHS),
(!cast<Instruction>(inst # "AL" # suffix) DstRHS, GPR64sp:$Rn)>;
}
@ -9994,15 +9994,15 @@ multiclass LDOPregister_patterns_mod<string inst, string op, string mod> {
let Predicates = [HasLSE] in
multiclass CASregister_patterns_ord_dag<string inst, string suffix, string op,
string size, dag OLD, dag NEW> {
def : Pat<(!cast<SDNode>(op#"_"#size#"_monotonic") GPR64sp:$Rn, OLD, NEW),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_monotonic") GPR64sp:$Rn, OLD, NEW),
(!cast<Instruction>(inst # suffix) OLD, NEW, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_acquire") GPR64sp:$Rn, OLD, NEW),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_acquire") GPR64sp:$Rn, OLD, NEW),
(!cast<Instruction>(inst # "A" # suffix) OLD, NEW, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_release") GPR64sp:$Rn, OLD, NEW),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_release") GPR64sp:$Rn, OLD, NEW),
(!cast<Instruction>(inst # "L" # suffix) OLD, NEW, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_acq_rel") GPR64sp:$Rn, OLD, NEW),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_acq_rel") GPR64sp:$Rn, OLD, NEW),
(!cast<Instruction>(inst # "AL" # suffix) OLD, NEW, GPR64sp:$Rn)>;
def : Pat<(!cast<SDNode>(op#"_"#size#"_seq_cst") GPR64sp:$Rn, OLD, NEW),
def : Pat<(!cast<PatFrag>(op#"_"#size#"_seq_cst") GPR64sp:$Rn, OLD, NEW),
(!cast<Instruction>(inst # "AL" # suffix) OLD, NEW, GPR64sp:$Rn)>;
}

View File

@ -500,7 +500,7 @@ let AddedComplexity = SM_LOAD_PATTERN.AddedComplexity in {
class SMRD_Pattern_ci <string Instr, ValueType vt> : GCNPat <
(smrd_load (SMRDImm32 i64:$sbase, i32:$offset)),
(vt (!cast<SM_Pseudo>(Instr#"_IMM_ci") $sbase, $offset, 0))> {
(vt (!cast<InstSI>(Instr#"_IMM_ci") $sbase, $offset, 0))> {
let OtherPredicates = [isCIOnly];
}

View File

@ -115,13 +115,13 @@ class AddressingMode<string seltype, string bitsize, string dispsize,
class BDMode<string type, string bitsize, string dispsize, string suffix>
: AddressingMode<type, bitsize, dispsize, suffix, "", 2, "BDAddr",
(ops !cast<RegisterOperand>("ADDR"##bitsize),
!cast<Immediate>("disp"##dispsize##"imm"##bitsize))>;
!cast<Operand>("disp"##dispsize##"imm"##bitsize))>;
// An addressing mode with a base, displacement and index.
class BDXMode<string type, string bitsize, string dispsize, string suffix>
: AddressingMode<type, bitsize, dispsize, suffix, "", 3, "BDXAddr",
(ops !cast<RegisterOperand>("ADDR"##bitsize),
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
!cast<Operand>("disp"##dispsize##"imm"##bitsize),
!cast<RegisterOperand>("ADDR"##bitsize))>;
// A BDMode paired with an immediate length operand of LENSIZE bits.
@ -130,21 +130,21 @@ class BDLMode<string type, string bitsize, string dispsize, string suffix,
: AddressingMode<type, bitsize, dispsize, suffix, "Len"##lensize, 3,
"BDLAddr",
(ops !cast<RegisterOperand>("ADDR"##bitsize),
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
!cast<Immediate>("imm"##bitsize))>;
!cast<Operand>("disp"##dispsize##"imm"##bitsize),
!cast<Operand>("imm"##bitsize))>;
// A BDMode paired with a register length operand.
class BDRMode<string type, string bitsize, string dispsize, string suffix>
: AddressingMode<type, bitsize, dispsize, suffix, "", 3, "BDRAddr",
(ops !cast<RegisterOperand>("ADDR"##bitsize),
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
!cast<Operand>("disp"##dispsize##"imm"##bitsize),
!cast<RegisterOperand>("GR"##bitsize))>;
// An addressing mode with a base, displacement and a vector index.
class BDVMode<string bitsize, string dispsize>
: AddressOperand<bitsize, dispsize, "", "BDVAddr",
(ops !cast<RegisterOperand>("ADDR"##bitsize),
!cast<Immediate>("disp"##dispsize##"imm"##bitsize),
!cast<Operand>("disp"##dispsize##"imm"##bitsize),
!cast<RegisterOperand>("VR128"))>;
//===----------------------------------------------------------------------===//

View File

@ -10,5 +10,5 @@ class C<string name> {
B b = !cast<B>(name);
}
// CHECK: error: Invalid value of type 'A' is found when setting 'b' of type 'B'
// CHECK: error: Expected type 'B', got 'A' in: !cast<B>("A0")
def Test : C<"A0">;

View File

@ -16,6 +16,14 @@
// CHECK: dag q = (ops C0);
// CHECK: }
// CHECK: def D0 {
// CHECK: D d = D0;
// CHECK: }
// CHECK: def E0 {
// CHECK: E e = E0;
// CHECK: }
def ops;
class A<dag d> {
@ -42,3 +50,26 @@ class C<string self> {
}
def C0 : C<"C0">;
// Explore some unused corner cases.
//
// A self-reference within a class may seem icky, but it unavoidably falls out
// orthogonally of having forward class declarations and late resolve of self
// references.
class D<string self> {
D d = !cast<D>(self);
}
def D0 : D<"D0">;
class E<E x> {
E e = x;
}
// Putting the !cast directly in the def should work as well: we shouldn't
// depend on implementation details of when exactly the record is looked up.
//
// Note the difference between !cast<E>("E0") and plain E0: the latter wouldn't
// work here because E0 does not yet have E as a superclass while the template
// arguments are being parsed.
def E0 : E<!cast<E>("E0")>;