Skip to content

Commit aca08a8

Browse files
authored
[TableGen] Add assert to validate Objects list for HwModeSelect (#123794)
- Bail out of TableGen if any asserts fail before running the backend. - Add asserts to validate that the `Objects` and `Modes` lists for various `HwModeSelect` subclasses are of same length. - Eliminate equivalent check in CodeGenHWModes.cpp
1 parent 6578790 commit aca08a8

File tree

8 files changed

+64
-42
lines changed

8 files changed

+64
-42
lines changed

llvm/include/llvm/Target/Target.td

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ def DefaultMode : HwMode<"", []>;
4343
// "Objects", which is a list of the same length as the list of modes.
4444
// The n-th element on the Objects list will be associated with the n-th
4545
// element on the Modes list.
46-
class HwModeSelect<list<HwMode> Ms> {
46+
class HwModeSelect<list<HwMode> Ms, int ObjectsLength> {
4747
list<HwMode> Modes = Ms;
48+
49+
assert !eq(ObjectsLength, !size(Modes)),
50+
"The Objects and Modes lists must be the same length";
4851
}
4952

5053
// A common class that implements a counterpart of ValueType, which is
@@ -53,7 +56,7 @@ class HwModeSelect<list<HwMode> Ms> {
5356
// objects could be used. This is specifically applicable to selection
5457
// patterns.
5558
class ValueTypeByHwMode<list<HwMode> Ms, list<ValueType> Ts>
56-
: HwModeSelect<Ms>, ValueType<0, 0> {
59+
: HwModeSelect<Ms, !size(Ts)>, ValueType<0, 0> {
5760
// The length of this list must be the same as the length of Ms.
5861
list<ValueType> Objects = Ts;
5962
}
@@ -64,7 +67,9 @@ class ValueTypeByHwMode<list<HwMode> Ms, list<ValueType> Ts>
6467
// or ValueType could be used. This is specifically applicable to selection
6568
// patterns.
6669
class PtrValueTypeByHwMode<ValueTypeByHwMode scalar, int addrspace>
67-
: HwModeSelect<scalar.Modes>, PtrValueType<ValueType<0, 0>, addrspace> {
70+
: HwModeSelect<scalar.Modes, !size(scalar.Objects)>,
71+
PtrValueType<ValueType<0, 0>, addrspace> {
72+
// The length of this list must be the same as the length of Ms.
6873
list<ValueType> Objects = scalar.Objects;
6974
}
7075

@@ -78,7 +83,7 @@ class RegInfo<int RS, int SS, int SA> {
7883

7984
// The register size/alignment information, parameterized by a HW mode.
8085
class RegInfoByHwMode<list<HwMode> Ms = [], list<RegInfo> Ts = []>
81-
: HwModeSelect<Ms> {
86+
: HwModeSelect<Ms, !size(Ts)> {
8287
// The length of this list must be the same as the length of Ms.
8388
list<RegInfo> Objects = Ts;
8489
}
@@ -89,7 +94,7 @@ class SubRegRange<int size, int offset = 0> {
8994
}
9095

9196
class SubRegRangeByHwMode<list<HwMode> Ms = [], list<SubRegRange> Ts = []>
92-
: HwModeSelect<Ms> {
97+
: HwModeSelect<Ms, !size(Ts)> {
9398
// The length of this list must be the same as the length of Ms.
9499
list<SubRegRange> Objects = Ts;
95100
}
@@ -574,7 +579,7 @@ class InstructionEncoding {
574579
// an EncodingByHwMode, its Inst and Size members are ignored and Ts are used
575580
// to encode and decode based on HwMode.
576581
class EncodingByHwMode<list<HwMode> Ms = [], list<InstructionEncoding> Ts = []>
577-
: HwModeSelect<Ms> {
582+
: HwModeSelect<Ms, !size(Ts)> {
578583
// The length of this list must be the same as the length of Ms.
579584
list<InstructionEncoding> Objects = Ts;
580585
}

llvm/lib/TableGen/Main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ int llvm::TableGenMain(const char *argv0,
128128
return 1;
129129
Timer.stopTimer();
130130

131+
// Return early if any other errors were generated during parsing
132+
// (e.g., assert failures).
133+
if (ErrorsPrinted > 0)
134+
return reportError(argv0, Twine(ErrorsPrinted) + " errors.\n");
135+
131136
// Write output to memory.
132137
Timer.startBackendTimer("Backend overall");
133138
std::string OutString;

llvm/lib/TableGen/TGParser.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,13 @@ bool TGParser::SetValue(Record *CurRec, SMLoc Loc, const Init *ValName,
286286
InitType = (Twine("' of type bit initializer with length ") +
287287
Twine(BI->getNumBits())).str();
288288
else if (const auto *TI = dyn_cast<TypedInit>(V))
289-
InitType = (Twine("' of type '") + TI->getType()->getAsString()).str();
289+
InitType =
290+
(Twine("' of type '") + TI->getType()->getAsString() + "'").str();
291+
290292
return Error(Loc, "Field '" + ValName->getAsUnquotedString() +
291293
"' of type '" + RV->getType()->getAsString() +
292-
"' is incompatible with value '" +
293-
V->getAsString() + InitType + "'");
294+
"' is incompatible with value '" + V->getAsString() +
295+
InitType);
294296
}
295297
return false;
296298
}

llvm/test/TableGen/BitsInit.td

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11

2-
// RUN: not llvm-tblgen %s 2>&1 > %t
3-
// RUN: FileCheck %s < %t
2+
// RUN: llvm-tblgen %s | FileCheck %s
43

54
def a {
65
bits<2> opc = { 0, 1 };
76
bits<2> opc2 = { 1, 0 };
87
bits<1> opc3 = { 1 };
9-
bits<2> a = { opc, opc2 }; // error!
108
bits<2> b = { opc{0}, opc2{0} };
119
bits<2> c = { opc{1}, opc2{1} };
1210
bits<2> c = { opc3{0}, opc3 };
@@ -16,34 +14,25 @@ def a {
1614
// CHECK: bits<2> opc = { 0, 1 };
1715
// CHECK: bits<2> opc2 = { 1, 0 };
1816
// CHECK: bits<1> opc3 = { 1 };
19-
// CHECK: bits<2> a;
2017
// CHECK: bits<2> b = { 1, 0 };
2118
// CHECK: bits<2> c = { 1, 1 };
2219
// CHECK: }
2320

2421
def {
25-
bits<2> B1 = 0b011; // bitfield is too small, reject
2622
bits<3> B2 = 0b011; // ok
2723

28-
bits<2> C1 = 0b111; // bitfield is too small, reject
2924
bits<3> C2 = 0b111; // ok
3025

3126
bits<2> D1 = { 0, 0 }; // ok
3227
bits<2> D2 = { 0b00 }; // ok
33-
bits<3> D3 = { 0, 0 }; // type mismatch. RHS doesn't have enough bits
34-
bits<3> D4 = { 0b00 }; // type mismatch. RHS doesn't have enough bits
3528
bits<1> D5 = { 0 }; // ok
3629
bits<1> D6 = { 1 }; // ok
37-
bits<1> D7 = { 3 }; // type mismatch. LHS doesn't have enough bits
38-
bits<2> D8 = { 0 }; // type mismatch. RHS doesn't have enough bits
3930

4031
bits<8> E;
4132
let E{7...0} = {0,0,1,?,?,?,?,?};
4233
let E{3...0} = 0b0010;
4334

4435
bits<8> F1 = { 0, 1, 0b1001, 0, 0b0 }; // ok
45-
bits<7> F2 = { 0, 1, 0b1001, 0, 0b0 }; // LHS doesn't have enough bits
46-
bits<9> F3 = { 0, 1, 0b1001, 0, 0b0 }; // RHS doesn't have enough bits
4736

4837
bits<8> G1 = { 0, { 1, 0b1001, 0 }, 0b0 }; // ok
4938
bits<8> G2 = { 0, { 1, 0b1001 }, 0, 0b0 }; // ok
@@ -63,22 +52,14 @@ def {
6352
}
6453

6554
// CHECK: def {{.*}} {
66-
// CHECK: bits<2> B1;
6755
// CHECK: bits<3> B2 = { 0, 1, 1 };
68-
// CHECK: bits<2> C1;
6956
// CHECK: bits<3> C2 = { 1, 1, 1 };
7057
// CHECK: bits<2> D1 = { 0, 0 };
7158
// CHECK: bits<2> D2 = { 0, 0 };
72-
// CHECK: bits<3> D3;
73-
// CHECK: bits<3> D4;
7459
// CHECK: bits<1> D5 = { 0 };
7560
// CHECK: bits<1> D6 = { 1 };
76-
// CHECK: bits<1> D7 = { !cast<bit>(3) };
77-
// CHECK: bits<2> D8;
7861
// CHECK: bits<8> E = { 0, 0, 1, ?, 0, 0, 1, 0 };
7962
// CHECK: bits<8> F1 = { 0, 1, 1, 0, 0, 1, 0, 0 };
80-
// CHECK: bits<7> F2;
81-
// CHECK: bits<9> F3;
8263
// CHECK: bits<8> G1 = { 0, 1, 1, 0, 0, 1, 0, 0 };
8364
// CHECK: bits<8> G2 = { 0, 1, 1, 0, 0, 1, 0, 0 };
8465
// CHECK: bits<8> G3 = { 0, 1, 1, 0, 0, 1, 0, 0 };

llvm/test/TableGen/BitsInitErrors.td

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s -DFILE=%s
3+
4+
def a {
5+
bits<2> opc = { 0, 1 };
6+
bits<2> opc2 = { 1, 0 };
7+
bits<1> opc3 = { 1 };
8+
// CHECK: [[FILE]]:[[@LINE+1]]:15: error: Field 'a' of type 'bits<2>' is incompatible with value '{ opc{1}, opc{0}, opc2{1}, opc2{0} }' of type bit initializer with length 4
9+
bits<2> a = { opc, opc2 }; // error!
10+
}
11+
12+
def {
13+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'B1' of type 'bits<2>' is incompatible with value '{ 0, 1, 1 }' of type bit initializer with length 3
14+
bits<2> B1 = 0b011; // bitfield is too small, reject
15+
16+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'C1' of type 'bits<2>' is incompatible with value '{ 1, 1, 1 }' of type bit initializer with length 3
17+
bits<2> C1 = 0b111; // bitfield is too small, reject
18+
19+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'D3' of type 'bits<3>' is incompatible with value '{ 0, 0 }' of type bit initializer with length 2
20+
bits<3> D3 = { 0, 0 }; // type mismatch. RHS doesn't have enough bits
21+
22+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'D4' of type 'bits<3>' is incompatible with value '{ 0, 0 }' of type bit initializer with length 2
23+
bits<3> D4 = { 0b00 }; // type mismatch. RHS doesn't have enough bits
24+
25+
bits<1> D7 = { 3 }; // type mismatch. LHS doesn't have enough bits
26+
27+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'D8' of type 'bits<2>' is incompatible with value '{ 0 }' of type bit initializer with length 1
28+
bits<2> D8 = { 0 }; // type mismatch. RHS doesn't have enough bits
29+
30+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'F2' of type 'bits<7>' is incompatible with value '{ 0, 1, 1, 0, 0, 1, 0, 0 }' of type bit initializer with length 8
31+
bits<7> F2 = { 0, 1, 0b1001, 0, 0b0 }; // LHS doesn't have enough bits
32+
33+
// CHECK: [[FILE]]:[[@LINE+1]]:16: error: Field 'F3' of type 'bits<9>' is incompatible with value '{ 0, 1, 1, 0, 0, 1, 0, 0 }' of type bit initializer with length 8
34+
bits<9> F3 = { 0, 1, 0b1001, 0, 0b0 }; // RHS doesn't have enough bits
35+
36+
// CHECK: Initializer of 'D7' in 'anonymous_0' could not be fully resolved: { !cast<bit>(3) }
37+
}

llvm/test/TableGen/HwModeSelect.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not --crash llvm-tblgen -gen-dag-isel -I %p/../../include %s 2>&1 | FileCheck %s
1+
// RUN: not llvm-tblgen -gen-dag-isel -I %p/../../include %s 2>&1 | FileCheck %s -DFILE=%s
22

33
// The HwModeSelect class is intended to serve as a base class for other
44
// classes that are then used to select a value based on the HW mode.
@@ -24,7 +24,8 @@ def HasFeat2 : Predicate<"Subtarget->hasFeat2()">;
2424
def TestMode1 : HwMode<"+feat1", [HasFeat1]>;
2525
def TestMode2 : HwMode<"+feat2", [HasFeat2]>;
2626

27+
// CHECK: error: assertion failed: The Objects and Modes lists must be the same length
28+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: assertion failed in this record
2729
def BadDef : ValueTypeByHwMode<[TestMode1, TestMode2, DefaultMode],
2830
[i8, i16, i32, i64]>;
2931

30-
// CHECK: error: in record BadDef derived from HwModeSelect: the lists Modes and Objects should have the same size

llvm/utils/TableGen/Common/CodeGenHwModes.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,6 @@ void HwMode::dump() const { dbgs() << Name << ": " << Features << '\n'; }
4141
HwModeSelect::HwModeSelect(const Record *R, CodeGenHwModes &CGH) {
4242
std::vector<const Record *> Modes = R->getValueAsListOfDefs("Modes");
4343
std::vector<const Record *> Objects = R->getValueAsListOfDefs("Objects");
44-
if (Modes.size() != Objects.size()) {
45-
PrintError(
46-
R->getLoc(),
47-
"in record " + R->getName() +
48-
" derived from HwModeSelect: the lists Modes and Objects should "
49-
"have the same size");
50-
report_fatal_error("error in target description.");
51-
}
5244
for (auto [Mode, Object] : zip_equal(Modes, Objects)) {
5345
unsigned ModeId = CGH.getHwModeId(Mode);
5446
Items.emplace_back(ModeId, Object);

mlir/test/mlir-tblgen/attr-or-type-builder-invalid.td

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: not mlir-tblgen -gen-typedef-defs -I %S/../../include %s 2>&1 | FileCheck %s
1+
// RUN: not mlir-tblgen -gen-typedef-defs -I %S/../../include %s 2>&1 | FileCheck %s -DFILE=%s
22

33
include "mlir/IR/AttrTypeBase.td"
44
include "mlir/IR/OpBase.td"
@@ -13,14 +13,13 @@ class InvalidType<string name> : TypeDef<Test_Dialect, name> {
1313
}
1414

1515
// This definition should not generate an error due to the use in `InvalidTypeA`
16-
// CHECK-NOT: Record `TestParameter' does not have a field named `type'!
1716
def TestParameter : TypeParameter<"int", "int parameter">;
1817

1918
// Test builder uses wrong record class.
19+
// CHECK: [[FILE]]:[[@LINE+1]]:5: error: Initializer of 'typeName' in 'InvalidTypeA' could not be fully resolved: !strconcat("TestDialect", !strconcat(".", mnemonic))
2020
def InvalidTypeA : InvalidType<"InvalidTypeA"> {
2121
let parameters = (ins "int":$v0);
2222
let builders = [
23-
// CHECK: Builder DAG arguments must be either strings or defs which inherit from CArg
2423
TypeBuilder<(ins TestParameter:$arg0), [{
2524
return $_get($_ctxt, arg0);
2625
}]>

0 commit comments

Comments
 (0)