mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
TableGen: Handle nontrivial foreach range bounds
This allows using anything that isn't a literal integer as the bounds for a foreach. Some of the diagnostics aren't perfect, but nobody ever accused tablegen of having good errors. For example, the existing wording suggests a bitrange is valid, but as far as I can tell this has never worked. Fixes bug 41958. llvm-svn: 361434
This commit is contained in:
parent
9fa10045c2
commit
4af0733112
@ -666,35 +666,47 @@ ParseSubMultiClassReference(MultiClass *CurMC) {
|
|||||||
/// RangePiece ::= INTVAL
|
/// RangePiece ::= INTVAL
|
||||||
/// RangePiece ::= INTVAL '-' INTVAL
|
/// RangePiece ::= INTVAL '-' INTVAL
|
||||||
/// RangePiece ::= INTVAL INTVAL
|
/// RangePiece ::= INTVAL INTVAL
|
||||||
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges) {
|
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
|
||||||
if (Lex.getCode() != tgtok::IntVal) {
|
TypedInit *FirstItem) {
|
||||||
TokError("expected integer or bitrange");
|
Init *CurVal = FirstItem;
|
||||||
return true;
|
if (!CurVal)
|
||||||
}
|
CurVal = ParseValue(nullptr);
|
||||||
int64_t Start = Lex.getCurIntVal();
|
|
||||||
|
IntInit *II = dyn_cast_or_null<IntInit>(CurVal);
|
||||||
|
if (!II)
|
||||||
|
return TokError("expected integer or bitrange");
|
||||||
|
|
||||||
|
int64_t Start = II->getValue();
|
||||||
int64_t End;
|
int64_t End;
|
||||||
|
|
||||||
if (Start < 0)
|
if (Start < 0)
|
||||||
return TokError("invalid range, cannot be negative");
|
return TokError("invalid range, cannot be negative");
|
||||||
|
|
||||||
switch (Lex.Lex()) { // eat first character.
|
switch (Lex.getCode()) {
|
||||||
default:
|
default:
|
||||||
Ranges.push_back(Start);
|
Ranges.push_back(Start);
|
||||||
return false;
|
return false;
|
||||||
case tgtok::minus:
|
case tgtok::minus: {
|
||||||
if (Lex.Lex() != tgtok::IntVal) {
|
Lex.Lex(); // eat
|
||||||
|
|
||||||
|
Init *I_End = ParseValue(nullptr);
|
||||||
|
IntInit *II_End = dyn_cast_or_null<IntInit>(I_End);
|
||||||
|
if (!II_End) {
|
||||||
TokError("expected integer value as end of range");
|
TokError("expected integer value as end of range");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
End = Lex.getCurIntVal();
|
|
||||||
|
End = II_End->getValue();
|
||||||
break;
|
break;
|
||||||
case tgtok::IntVal:
|
}
|
||||||
|
case tgtok::IntVal: {
|
||||||
End = -Lex.getCurIntVal();
|
End = -Lex.getCurIntVal();
|
||||||
|
Lex.Lex();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (End < 0)
|
if (End < 0)
|
||||||
return TokError("invalid range, cannot be negative");
|
return TokError("invalid range, cannot be negative");
|
||||||
Lex.Lex();
|
|
||||||
|
|
||||||
// Add to the range.
|
// Add to the range.
|
||||||
if (Start < End)
|
if (Start < End)
|
||||||
@ -2439,12 +2451,6 @@ VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
|
|||||||
SmallVector<unsigned, 16> Ranges;
|
SmallVector<unsigned, 16> Ranges;
|
||||||
|
|
||||||
switch (Lex.getCode()) {
|
switch (Lex.getCode()) {
|
||||||
case tgtok::IntVal: { // RangePiece.
|
|
||||||
if (ParseRangePiece(Ranges))
|
|
||||||
return nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case tgtok::l_brace: { // '{' RangeList '}'
|
case tgtok::l_brace: { // '{' RangeList '}'
|
||||||
Lex.Lex(); // eat the '{'
|
Lex.Lex(); // eat the '{'
|
||||||
ParseRangeList(Ranges);
|
ParseRangeList(Ranges);
|
||||||
@ -2459,23 +2465,35 @@ VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
|
|||||||
default: {
|
default: {
|
||||||
SMLoc ValueLoc = Lex.getLoc();
|
SMLoc ValueLoc = Lex.getLoc();
|
||||||
Init *I = ParseValue(nullptr);
|
Init *I = ParseValue(nullptr);
|
||||||
TypedInit *TI = dyn_cast<TypedInit>(I);
|
if (!I)
|
||||||
if (!TI || !isa<ListRecTy>(TI->getType())) {
|
|
||||||
std::string Type;
|
|
||||||
if (TI)
|
|
||||||
Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
|
|
||||||
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
|
|
||||||
if (CurMultiClass)
|
|
||||||
PrintNote({}, "references to multiclass template arguments cannot be "
|
|
||||||
"resolved at this time");
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
TypedInit *TI = dyn_cast<TypedInit>(I);
|
||||||
|
if (TI && isa<ListRecTy>(TI->getType())) {
|
||||||
|
ForeachListValue = I;
|
||||||
|
IterType = cast<ListRecTy>(TI->getType())->getElementType();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ForeachListValue = I;
|
|
||||||
IterType = cast<ListRecTy>(TI->getType())->getElementType();
|
if (TI) {
|
||||||
break;
|
if (ParseRangePiece(Ranges, TI))
|
||||||
|
return nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Type;
|
||||||
|
if (TI)
|
||||||
|
Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
|
||||||
|
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
|
||||||
|
if (CurMultiClass) {
|
||||||
|
PrintNote({}, "references to multiclass template arguments cannot be "
|
||||||
|
"resolved at this time");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!Ranges.empty()) {
|
if (!Ranges.empty()) {
|
||||||
assert(!IterType && "Type already initialized?");
|
assert(!IterType && "Type already initialized?");
|
||||||
IterType = IntRecTy::get();
|
IterType = IntRecTy::get();
|
||||||
|
@ -190,7 +190,8 @@ private: // Parser methods.
|
|||||||
bool ParseOptionalRangeList(SmallVectorImpl<unsigned> &Ranges);
|
bool ParseOptionalRangeList(SmallVectorImpl<unsigned> &Ranges);
|
||||||
bool ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges);
|
bool ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges);
|
||||||
void ParseRangeList(SmallVectorImpl<unsigned> &Result);
|
void ParseRangeList(SmallVectorImpl<unsigned> &Result);
|
||||||
bool ParseRangePiece(SmallVectorImpl<unsigned> &Ranges);
|
bool ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
|
||||||
|
TypedInit *FirstItem = nullptr);
|
||||||
RecTy *ParseType();
|
RecTy *ParseType();
|
||||||
Init *ParseOperation(Record *CurRec, RecTy *ItemType);
|
Init *ParseOperation(Record *CurRec, RecTy *ItemType);
|
||||||
Init *ParseOperationCond(Record *CurRec, RecTy *ItemType);
|
Init *ParseOperationCond(Record *CurRec, RecTy *ItemType);
|
||||||
|
19
test/TableGen/foreach-range-parse-errors0.td
Normal file
19
test/TableGen/foreach-range-parse-errors0.td
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck -DFILE=%s %s
|
||||||
|
|
||||||
|
class ConstantsImpl {
|
||||||
|
int Zero = 0;
|
||||||
|
int One = 1;
|
||||||
|
int Two = 2;
|
||||||
|
int Three = 3;
|
||||||
|
int Five = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
def Constants : ConstantsImpl;
|
||||||
|
|
||||||
|
// CHECK-NOT: error: Unknown token when parsing a value
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+3]]:22: error: Unknown token when parsing a value
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+2]]:22: error: expected integer value as end of range
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+1]]:22: error: expected declaration in for
|
||||||
|
foreach Index = 0 - in {
|
||||||
|
|
||||||
|
}
|
8
test/TableGen/foreach-range-parse-errors1.td
Normal file
8
test/TableGen/foreach-range-parse-errors1.td
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck -DFILE=%s %s
|
||||||
|
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+2]]:20: error: invalid range, cannot be negative
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+1]]:20: error: expected declaration in for
|
||||||
|
foreach Index = -1 - 0 in {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
13
test/TableGen/foreach-range-parse-errors2.td
Normal file
13
test/TableGen/foreach-range-parse-errors2.td
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck -DFILE=%s %s
|
||||||
|
|
||||||
|
class ConstantsImpl {
|
||||||
|
int NegOne = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
def Constants : ConstantsImpl;
|
||||||
|
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+2]]:38: error: invalid range, cannot be negative
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+1]]:38: error: expected declaration in for
|
||||||
|
foreach Index = 0 - Constants.NegOne in {
|
||||||
|
|
||||||
|
}
|
8
test/TableGen/foreach-range-parse-errors3.td
Normal file
8
test/TableGen/foreach-range-parse-errors3.td
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck -DFILE=%s %s
|
||||||
|
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+2]]:21: error: expected integer or bitrange
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+1]]:21: error: expected declaration in for
|
||||||
|
foreach Index = "0" - 1 in {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
9
test/TableGen/foreach-range-parse-errors4.td
Normal file
9
test/TableGen/foreach-range-parse-errors4.td
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck -DFILE=%s %s
|
||||||
|
// Make sure there is no crash on undefined variable
|
||||||
|
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+2]]:17: error: Variable not defined: 'foo'
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+1]]:21: error: expected declaration in for
|
||||||
|
foreach Index = foo in {
|
||||||
|
def arst#Index;
|
||||||
|
}
|
||||||
|
|
8
test/TableGen/foreach-range-parse-errors5.td
Normal file
8
test/TableGen/foreach-range-parse-errors5.td
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// RUN: not llvm-tblgen %s 2>&1 | FileCheck -DFILE=%s %s
|
||||||
|
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+2]]:23: error: expected integer or bitrange
|
||||||
|
// CHECK: [[FILE]]:[[@LINE+1]]:23: error: expected declaration in for
|
||||||
|
foreach Index = 0b110 - 0b111 in {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
128
test/TableGen/foreach-variable-range.td
Normal file
128
test/TableGen/foreach-variable-range.td
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// RUN: llvm-tblgen %s
|
||||||
|
|
||||||
|
class ConstantsImpl {
|
||||||
|
int Zero = 0;
|
||||||
|
int One = 1;
|
||||||
|
int Two = 2;
|
||||||
|
int Three = 3;
|
||||||
|
int Five = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
def Constants : ConstantsImpl;
|
||||||
|
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceA0
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceA1
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceA2
|
||||||
|
foreach Index = Constants.Zero - Constants.Two in {
|
||||||
|
def var_bound_whitespaceA#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceB0
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceB1
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceB2
|
||||||
|
foreach Index = Constants.Zero-Constants.Two in {
|
||||||
|
def var_bounds_whitespaceB#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceC0
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceC1
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceC2
|
||||||
|
foreach Index = Constants.Zero -Constants.Two in {
|
||||||
|
def var_bounds_whitespaceC#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceD0
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceD1
|
||||||
|
// CHECK-DAG: def var_bound_whitespaceD2
|
||||||
|
foreach Index = Constants.Zero- Constants.Two in {
|
||||||
|
def var_bounds_whitespaceD#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceA0
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceA1
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceA2
|
||||||
|
foreach Index = 0 - Constants.Two in {
|
||||||
|
def const_lower_whitespaceA#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceB0
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceB1
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceB2
|
||||||
|
foreach Index = 0-Constants.Two in {
|
||||||
|
def const_lower_whitespaceB#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceC0
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceC1
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceC2
|
||||||
|
foreach Index = 0 -Constants.Two in {
|
||||||
|
def const_lower_whitespaceC#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceD0
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceD1
|
||||||
|
// CHECK-DAG: def const_lower_whitespaceD2
|
||||||
|
foreach Index = 0- Constants.Two in {
|
||||||
|
def const_lower_whitespaceD#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceA0
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceA1
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceA2
|
||||||
|
foreach Index = Constants.Zero - 2 in {
|
||||||
|
def const_upper_whitespaceA#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceB0
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceB1
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceB2
|
||||||
|
foreach Index = Constants.Zero-2 in {
|
||||||
|
def const_upper_whitespaceB#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceC0
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceC1
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceC2
|
||||||
|
foreach Index = Constants.Zero -2 in {
|
||||||
|
def const_upper_whitespaceC#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceD0
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceD1
|
||||||
|
// CHECK-DAG: def const_upper_whitespaceD2
|
||||||
|
foreach Index = Constants.Zero- 2 in {
|
||||||
|
def const_upper_whitespaceD#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def multi_rangeA0
|
||||||
|
// CHECK-DAG: def multi_rangeA1
|
||||||
|
// CHECK-DAG: def multi_rangeA2
|
||||||
|
// CHECK-DAG: def multi_rangeA3
|
||||||
|
foreach Index = {Constants.Zero-Constants.One, Constants.Two-Constants.Three} in {
|
||||||
|
def multi_rangeA#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def multi_rangeB0
|
||||||
|
// CHECK-DAG: def multi_rangeB1
|
||||||
|
// CHECK-DAG: def multi_rangeB3
|
||||||
|
// CHECK-DAG: def multi_rangeB4
|
||||||
|
// CHECK-DAG: def multi_rangeB5
|
||||||
|
foreach Index = {0-Constants.One, Constants.Three-Constants.Five} in {
|
||||||
|
def multi_rangeB#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def multi_rangeC0
|
||||||
|
// CHECK-DAG: def multi_rangeC1
|
||||||
|
// CHECK-DAG: def multi_rangeC2
|
||||||
|
// CHECK-DAG: def multi_rangeC3
|
||||||
|
foreach Index = {0-Constants.One, 2-Constants.Three} in {
|
||||||
|
def multi_rangeC#Index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK-DAG: def multi_rangeD0
|
||||||
|
// CHECK-DAG: def multi_rangeD1
|
||||||
|
// CHECK-DAG: def multi_rangeD2
|
||||||
|
// CHECK-DAG: def multi_rangeD3
|
||||||
|
foreach Index = {0-1, Constants.Two-3} in {
|
||||||
|
def multi_rangeD#Index;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user