1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 19:12:56 +02:00
llvm-mirror/test/TableGen/self-reference.td
Nicolai Haehnle 29fbaf4ec4 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 17:12:53 +00:00

99 lines
2.0 KiB
TableGen

// RUN: llvm-tblgen %s | FileCheck %s
// XFAIL: vg_leak
// CHECK: --- Defs ---
// CHECK: def A0 {
// CHECK: dag a = (ops A0);
// CHECK: }
// CHECK: def B0 {
// CHECK: dag a = (ops);
// CHECK: A b = B0;
// CHECK: }
// CHECK: def C0 {
// CHECK: dag q = (ops C0);
// CHECK: }
// CHECK: def D0 {
// CHECK: D d = D0;
// CHECK: }
// CHECK: def E0 {
// CHECK: E e = E0;
// CHECK: }
// CHECK: def F0 {
// CHECK: Fa as_a = F0;
// CHECK: Fb as_b = F0;
// CHECK: }
// CHECK: def F0x {
// CHECK: Fc as_c = F0;
// CHECK: }
def ops;
class A<dag d> {
dag a = d;
}
// This type of self-reference is used in various places defining register
// classes.
def A0 : A<(ops A0)>;
class B<string self> {
A b = !cast<A>(self);
}
// A stronger form of this type of self-reference is used at least in the
// SystemZ backend to define a record which is a ComplexPattern and an Operand
// at the same time.
def B0 : A<(ops)>, B<"B0">;
// Casting C0 to C by name here is tricky, because it happens while (or rather:
// before) adding C as a superclass. However, SystemZ uses this pattern.
class C<string self> {
dag q = (ops !cast<C>(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")>;
// Ensure that records end up with the correct type even when direct self-
// references are involved.
class Fa;
class Fb<Fa x> {
Fa as_a = x;
}
class Fc<Fb x> {
Fb as_b = x;
}
def F0 : Fa, Fb<F0>, Fc<F0>;
def F0x {
Fc as_c = F0;
}