Skip to content

Commit

Permalink
[TableGen] Support non-def operators in !getdagop
Browse files Browse the repository at this point in the history
`!getdagop` expects the dag operator to be a def, and errors out if it's
not.

While that's true in most cases, when multiclasses are involved, the
late resolution of the dag operator can result in it not being a def
yet, but still have a proper type, wich is required to check against the
optional parameter Ty in `!getdagop<Ty>`.

e.g, in the following dag:
```
(!cast<TestInstruction>(TestInstructionAndPattern::NAME) foo)
```
the operator is a UnOpInit, but all we need here is to check its type.

This fixes a bug where !getdagop is used to query the dag operator that
is dependent on the multiclass, which is not yet resolved to a def. Once
the folding is performed, the field becomes a record that can be queried.
  • Loading branch information
francisvm committed Jan 10, 2024
1 parent 45be680 commit 76e2126
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
15 changes: 8 additions & 7 deletions llvm/lib/TableGen/Record.cpp
Expand Up @@ -923,15 +923,16 @@ Init *UnOpInit::Fold(Record *CurRec, bool IsFinal) const {

case GETDAGOP:
if (DagInit *Dag = dyn_cast<DagInit>(LHS)) {
DefInit *DI = DefInit::get(Dag->getOperatorAsDef({}));
if (!DI->getType()->typeIsA(getType())) {
// TI is not necessarily a def due to the late resolution in multiclasses,
// but has to be a TypedInit.
auto *TI = cast<TypedInit>(Dag->getOperator());
if (!TI->getType()->typeIsA(getType())) {
PrintFatalError(CurRec->getLoc(),
Twine("Expected type '") +
getType()->getAsString() + "', got '" +
DI->getType()->getAsString() + "' in: " +
getAsString() + "\n");
Twine("Expected type '") + getType()->getAsString() +
"', got '" + TI->getType()->getAsString() +
"' in: " + getAsString() + "\n");
} else {
return DI;
return Dag->getOperator();
}
}
break;
Expand Down
30 changes: 30 additions & 0 deletions llvm/test/TableGen/getsetop.td
Expand Up @@ -8,6 +8,7 @@
// RUN: not llvm-tblgen -DERROR7 %s 2>&1 | FileCheck --check-prefix=ERROR7 %s
// RUN: not llvm-tblgen -DERROR8 %s 2>&1 | FileCheck --check-prefix=ERROR8 %s
// RUN: not llvm-tblgen -DERROR9 %s 2>&1 | FileCheck --check-prefix=ERROR9 %s
// RUN: not llvm-tblgen -DERROR10 %s 2>&1 | FileCheck --check-prefix=ERROR10 %s

// !setop and !getop are deprecated in favor of !setdagop and !getdagop.
// Two tests retain the old names just to be sure they are still supported.
Expand Down Expand Up @@ -148,3 +149,32 @@ def test {
dag orig_out_of_range = !setdagarg(orig, foo, (foo qux:$a));
#endif
}

// Copy a list (Predicates) that is a field in a dag operator
// (TestInstruction), which is defined in the same multiclass
// (TestInstructionAndPattern) as the destination of the copy
// (TestPattern::Predicates).
class TestInstruction<list<int> _Predicates> {
list<int> Predicates = _Predicates;
}
#ifdef ERROR10
class OtherTestInstruction<list<int> _Predicates> {
list<int> Predicates = _Predicates;
}
// ERROR10: error: Expected type 'OtherTestInstruction', got 'TestInstruction'
class TestPattern<dag D> {
list<int> Predicates = !getdagop<OtherTestInstruction>(D).Predicates;
}
#else
class TestPattern<dag D> {
list<int> Predicates = !getdagop<TestInstruction>(D).Predicates;
}
#endif

multiclass TestInstructionAndPattern<list<int> Predicates> {
def NAME : TestInstruction<Predicates>;
def : TestPattern<(!cast<TestInstruction>(NAME) foo)>;
}
// CHECK: def testInst0 { // TestInstruction
// CHECK-NEXT: list<int> Predicates = [7];
defm testInst0 : TestInstructionAndPattern<[7]>;

0 comments on commit 76e2126

Please sign in to comment.