[TblGen] Extend !if semantics through new feature !cond
This patch extends TableGen language with !cond operator.
Instead of embedding !if inside !if which can get cumbersome,
one can now use !cond.
Below is an example to convert an integer 'x' into a string:
!cond(!lt(x,0) : "Negative",
!eq(x,0) : "Zero",
!eq(x,1) : "One,
1 : "MoreThanOne")
Reviewed By: hfinkel, simon_tatham, greened
Differential Revision: https://reviews.llvm.org/D55758
llvm-svn: 352185
diff --git a/llvm/test/TableGen/cond-bitlist.td b/llvm/test/TableGen/cond-bitlist.td
new file mode 100644
index 0000000..bce6158
--- /dev/null
+++ b/llvm/test/TableGen/cond-bitlist.td
@@ -0,0 +1,27 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+class S<int s> {
+ bits<2> val = !cond(!eq(s, 8): {0, 0},
+ !eq(s, 16): 0b01,
+ !eq(s, 32): 2,
+ !eq(s, 64): {1, 1},
+ 1 : ?);
+}
+
+def D8 : S<8>;
+def D16 : S<16>;
+def D32 : S<32>;
+def D64 : S<64>;
+def D128: S<128>;
+// CHECK: def D128
+// CHECK-NEXT: bits<2> val = { ?, ? };
+// CHECK: def D16
+// CHECK-NEXT: bits<2> val = { 0, 1 };
+// CHECK: def D32
+// CHECK-NEXT: bits<2> val = { 1, 0 };
+// CHECK: def D64
+// CHECK-NEXT: bits<2> val = { 1, 1 };
+// CHECK: def D8
+// CHECK-NEXT: bits<2> val = { 0, 0 };
+
diff --git a/llvm/test/TableGen/cond-default.td b/llvm/test/TableGen/cond-default.td
new file mode 100644
index 0000000..816bf10
--- /dev/null
+++ b/llvm/test/TableGen/cond-default.td
@@ -0,0 +1,11 @@
+// Check that not specifying a valid condition results in error
+
+// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
+// XFAIL: vg_leak
+
+class C<int x> {
+ string s = !cond(!lt(x,0) : "negative", !gt(x,0) : "positive");
+}
+
+def Zero : C<0>;
+//CHECK: error: Zero does not have any true condition in:!cond(0: "negative", 0: "positive")
diff --git a/llvm/test/TableGen/cond-empty-list-arg.td b/llvm/test/TableGen/cond-empty-list-arg.td
new file mode 100644
index 0000000..5f4ccad
--- /dev/null
+++ b/llvm/test/TableGen/cond-empty-list-arg.td
@@ -0,0 +1,8 @@
+// RUN: llvm-tblgen %s
+// XFAIL: vg_leak
+
+class C<bit cond> {
+ bit true = 1;
+ list<int> X = !cond(cond: [1, 2, 3], true : []);
+ list<int> Y = !cond(cond: [], true : [4, 5, 6]);
+}
diff --git a/llvm/test/TableGen/cond-inheritance.td b/llvm/test/TableGen/cond-inheritance.td
new file mode 100644
index 0000000..4b4abdf
--- /dev/null
+++ b/llvm/test/TableGen/cond-inheritance.td
@@ -0,0 +1,22 @@
+// Make sure !cond gets propagated across multiple layers of inheritance.
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+class getInt<int c> {
+ int ret = !cond(c: 0, 1 : 1);
+}
+
+class I1<int c> {
+ int i = getInt<c>.ret;
+}
+
+class I2<int c> : I1<c>;
+
+def DI1: I1<1>;
+// CHECK: def DI1 { // I1
+// CHECK-NEXT: int i = 0;
+
+// CHECK: def DI2 { // I1 I2
+// CHECK-NEXT: int i = 0;
+def DI2: I2<1>;
+
diff --git a/llvm/test/TableGen/cond-let.td b/llvm/test/TableGen/cond-let.td
new file mode 100644
index 0000000..044878f
--- /dev/null
+++ b/llvm/test/TableGen/cond-let.td
@@ -0,0 +1,36 @@
+// Check support for `!cond' operator as part of a `let' statement.
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+
+class C<bits<3> x, bits<4> y, bit z> {
+ bits<16> n;
+
+ let n{11} = !cond(y{3}: 1,
+ y{2}: x{0},
+ y{1}: x{1},
+ y{0}: x{2},
+ {1} :?);
+ let n{10-9}= !cond(x{2}: y{3-2},
+ x{1}: y{2-1},
+ x{1}: y{1-0},
+ {1} : ?);
+ let n{8-6} = !cond(x{2}: 0b010, 1 : 0b110);
+ let n{5-4} = !cond(x{1}: y{3-2}, 1 : {0, 1});
+ let n{3-0} = !cond(x{0}: y{3-0}, 1 : {z, y{2}, y{1}, y{0}});
+}
+
+
+def C1 : C<{1, 0, 1}, {0, 1, 0, 1}, 0>;
+def C2 : C<{0, 1, 0}, {1, 0, 1, 0}, 1>;
+def C3 : C<{0, 0, 0}, {1, 0, 1, 0}, 0>;
+def C4 : C<{0, 0, 0}, {0, 0, 0, 0}, 0>;
+
+// CHECK: def C1
+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1 };
+// CHECK: def C2
+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0 };
+// CHECK: def C3
+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, 1, ?, ?, 1, 1, 0, 0, 1, 0, 0, 1, 0 };
+// CHECK: def C4
+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, ?, ?, ?, 1, 1, 0, 0, 1, 0, 0, 0, 0 };
diff --git a/llvm/test/TableGen/cond-list.td b/llvm/test/TableGen/cond-list.td
new file mode 100644
index 0000000..aa013ce
--- /dev/null
+++ b/llvm/test/TableGen/cond-list.td
@@ -0,0 +1,38 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+
+class A<list<list<int>> vals> {
+ list<int> first = vals[0];
+ list<int> rest = !cond(!empty(!tail(vals)): vals[0],
+ 1 : vals[1]);
+}
+
+def A_OneEl : A<[[1,2,3]]>;
+// CHECK: def A_OneEl { // A
+// CHECK-NEXT: list<int> first = [1, 2, 3];
+// CHECK-NEXT: list<int> rest = [1, 2, 3];
+// CHECK-NEXT: }
+
+def A_TwoEl : A<[[1,2,3], [4,5,6]]>;
+// CHECK: def A_TwoEl { // A
+// CHECK-NEXT: list<int> first = [1, 2, 3];
+// CHECK-NEXT: list<int> rest = [4, 5, 6];
+// CHECK-NEXT: }
+
+
+class B<list<int> v> {
+ list<int> vals = v;
+}
+class BB<list<list<int>> vals> : B<!cond(!empty(!tail(vals)): vals[0], 1 : vals[1])>;
+class BBB<list<list<int>> vals> : BB<vals>;
+
+def B_OneEl : BBB<[[1,2,3]]>;
+// CHECK: def B_OneEl { // B BB BBB
+// CHECK-NEXT: list<int> vals = [1, 2, 3];
+// CHECK-NEXT: }
+
+def B_TwoEl : BBB<[[1,2,3],[4,5,6]]>;
+// CHECK: def B_TwoEl { // B BB BBB
+// CHECK-NEXT: list<int> vals = [4, 5, 6];
+// CHECK-NEXT: }
diff --git a/llvm/test/TableGen/cond-subclass.td b/llvm/test/TableGen/cond-subclass.td
new file mode 100644
index 0000000..9f6f6e2
--- /dev/null
+++ b/llvm/test/TableGen/cond-subclass.td
@@ -0,0 +1,27 @@
+// Check that !cond with operands of different subtypes can
+// initialize a supertype variable.
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+class E<int dummy> {}
+class E1<int dummy> : E<dummy> {}
+class E2<int dummy> : E<dummy> {}
+
+class EX<int cc, E1 b, E2 c> {
+ E x = !cond(cc: b, 1 : c);
+}
+
+def E1d : E1<0>;
+def E2d : E2<0>;
+
+def EXd1 : EX<1, E1d, E2d>;
+def EXd2 : EX<0, E1d, E2d>;
+
+// CHECK: def EXd1 {
+// CHECK: E x = E1d;
+// CHECK: }
+//
+// CHECK: def EXd2 {
+// CHECK: E x = E2d;
+// CHECK: }
+
diff --git a/llvm/test/TableGen/cond-type.td b/llvm/test/TableGen/cond-type.td
new file mode 100644
index 0000000..fd2a3cc
--- /dev/null
+++ b/llvm/test/TableGen/cond-type.td
@@ -0,0 +1,11 @@
+// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s
+// XFAIL: vg_leak
+
+class A<int dummy> {}
+class B<int dummy> : A<dummy> {}
+class C<int dummy> : A<dummy> {}
+
+// CHECK: Value 'x' of type 'C' is incompatible with initializer '{{.*}}' of type 'A'
+class X<int cc, B b, C c> {
+ C x = !cond(cc: b, 1 : c);
+}
diff --git a/llvm/test/TableGen/cond-usage.td b/llvm/test/TableGen/cond-usage.td
new file mode 100644
index 0000000..055fd6d
--- /dev/null
+++ b/llvm/test/TableGen/cond-usage.td
@@ -0,0 +1,29 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+
+// Check that !cond picks the first true value
+// CHECK: class A
+// CHECK-NEXT: string S = !cond(!eq(A:x, 10): "ten", !eq(A:x, 11): "eleven", !eq(A:x, 10): "TEN", !gt(A:x, 9): "MoreThanNine", 1: "unknown");
+// CHECK: B1
+// CHECK-NEXT: string S = "unknown"
+// CHECK: B10
+// CHECK-NEXT: string S = "ten";
+// CHECK: def B11
+// CHECK-NEXT: string S = "eleven";
+// CHECK: def B12
+// CHECK-NEXT: string S = "MoreThanNine";
+// CHECK: def B9
+// CHECK-NEXT: string S = "unknown"
+
+class A<int x> {
+ string S = !cond(!eq(x,10) : "ten",
+ !eq(x,11) : "eleven",
+ !eq(x,10) : "TEN",
+ !gt(x,9) : "MoreThanNine",
+ !eq(1,1) : "unknown");
+}
+def B1 : A<1>;
+def B9 : A<9>;
+def B10 : A<10>;
+def B11 : A<11>;
+def B12 : A<12>;
diff --git a/llvm/test/TableGen/condsbit.td b/llvm/test/TableGen/condsbit.td
new file mode 100644
index 0000000..e08ac97
--- /dev/null
+++ b/llvm/test/TableGen/condsbit.td
@@ -0,0 +1,15 @@
+// check that !cond works well with bit conditional values
+// RUN: llvm-tblgen %s | FileCheck %s
+// XFAIL: vg_leak
+// CHECK: a = 6
+// CHECK: a = 5
+
+class A<bit b = 1> {
+ bit true = 1;
+ int a = !cond(b: 5, true : 6);
+ bit c = !cond(b: 0, true : 1);
+ bits<1> d = !cond(b: 0, true : 1);
+}
+
+def X : A<0>;
+def Y : A;