TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-21 18:12:53 +01:00
|
|
|
// RUN: llvm-tblgen %s | FileCheck %s
|
|
|
|
// XFAIL: vg_leak
|
|
|
|
|
|
|
|
// CHECK: --- Defs ---
|
|
|
|
|
|
|
|
// CHECK: def A00 {
|
|
|
|
// CHECK: int sum = 7;
|
|
|
|
// CHECK: }
|
|
|
|
|
|
|
|
// CHECK: def A01 {
|
|
|
|
// CHECK: int sum = 8;
|
|
|
|
// CHECK: }
|
|
|
|
|
2018-06-21 15:35:44 +02:00
|
|
|
// CHECK-NOT: def B0
|
|
|
|
|
|
|
|
// CHECK: def B12 {
|
|
|
|
// CHECK: int val = 9;
|
|
|
|
// CHECK: }
|
|
|
|
|
|
|
|
// CHECK: def B20 {
|
|
|
|
// CHECK: int val = 7;
|
|
|
|
// CHECK: }
|
|
|
|
|
|
|
|
// CHECK: def B24 {
|
|
|
|
// CHECK: int val = 11;
|
|
|
|
// CHECK: }
|
|
|
|
|
|
|
|
// CHECK: def B25 {
|
|
|
|
// CHECK: int val = 12;
|
|
|
|
// CHECK: }
|
|
|
|
|
|
|
|
// CHECK: def C04
|
|
|
|
// CHECK: def C05
|
|
|
|
|
|
|
|
// CHECK: def D0A
|
|
|
|
// CHECK-NOT: def D0B
|
|
|
|
// CHECK: def D1A
|
|
|
|
// CHECK: def D1B
|
|
|
|
|
|
|
|
// CHECK: def E01
|
|
|
|
// CHECK: def E02
|
|
|
|
// CHECK-NOT: def E0C
|
|
|
|
|
|
|
|
// CHECK: def E18
|
|
|
|
// CHECK: def E19
|
|
|
|
// CHECK: def E1C33
|
|
|
|
// CHECK: def E1C34
|
|
|
|
// CHECK: def E1C55
|
|
|
|
// CHECK: def E1C56
|
|
|
|
|
|
|
|
// CHECK-NOT: def F0
|
|
|
|
// CHECK-NOT: def F1
|
|
|
|
// CHECK-NOT: def F2_0_0
|
|
|
|
// CHECK: def F2_1_0
|
|
|
|
// CHECK-NOT: def F2_1_2
|
|
|
|
// CHECK: def F2_2_0
|
|
|
|
// CHECK: def F2_2_1
|
|
|
|
// CHECK-NOT: def F2_2_2
|
|
|
|
|
2021-01-29 16:24:30 +01:00
|
|
|
// CHECK: def G0
|
|
|
|
// CHECK: def H0_G0_0
|
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-21 18:12:53 +01:00
|
|
|
multiclass A<int x> {
|
|
|
|
foreach i = [0, 1] in {
|
|
|
|
def NAME#i {
|
|
|
|
int sum = !add(x, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defm A0 : A<7>;
|
2018-06-21 15:35:44 +02:00
|
|
|
|
|
|
|
multiclass B<int x, list<int> lst> {
|
|
|
|
foreach i = lst in {
|
|
|
|
def NAME#i {
|
|
|
|
int val = !add(x, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defm B0 : B<7, []>;
|
|
|
|
defm B1 : B<7, [2]>;
|
|
|
|
defm B2 : B<7, [0, 4, 5]>;
|
|
|
|
|
|
|
|
multiclass C<int x> {
|
|
|
|
foreach i = [x, !add(x, 1)] in {
|
|
|
|
def NAME#i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defm C0 : C<4>;
|
|
|
|
|
|
|
|
multiclass D<bit b> {
|
|
|
|
def A;
|
|
|
|
|
|
|
|
foreach _ = !if(b, [0], []<int>) in
|
|
|
|
def B;
|
|
|
|
}
|
|
|
|
|
|
|
|
defm D0 : D<0>;
|
|
|
|
defm D1 : D<1>;
|
|
|
|
|
|
|
|
multiclass E<list<int> lst, int x>
|
|
|
|
: C<x> {
|
|
|
|
foreach i = lst in
|
|
|
|
defm C#i : C<i>;
|
|
|
|
}
|
|
|
|
|
|
|
|
defm E0 : E<[], 1>;
|
|
|
|
defm E1 : E<[3, 5], 8>;
|
|
|
|
|
|
|
|
multiclass F<list<int> lst> {
|
|
|
|
foreach i = lst in
|
|
|
|
foreach j = !foldl([]<int>, lst, lhs, x,
|
|
|
|
!if(!lt(x, i), !listconcat(lhs, [x]), lhs)) in
|
|
|
|
def _#i#_#j;
|
|
|
|
}
|
|
|
|
|
|
|
|
defm F0 : F<[]>;
|
|
|
|
defm F1 : F<[0]>;
|
|
|
|
defm F2 : F<[0, 1, 2]>;
|
2021-01-29 16:24:30 +01:00
|
|
|
|
|
|
|
// If multiclass argument comes from loop variable,
|
|
|
|
// and field of argument is placed at foreach statement,
|
|
|
|
// the record field must be resolved correctly.
|
|
|
|
class G {
|
|
|
|
list<int> val = [0];
|
|
|
|
}
|
|
|
|
|
|
|
|
multiclass H<G g> {
|
|
|
|
foreach n = g.val in
|
|
|
|
def _#g#_#n;
|
|
|
|
}
|
|
|
|
|
|
|
|
def G0 : G;
|
|
|
|
|
|
|
|
foreach g = [G0] in
|
|
|
|
defm H0 : H<g>;
|