1
0
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:
Matt Arsenault 2019-05-22 21:28:20 +00:00
parent 9fa10045c2
commit 4af0733112
9 changed files with 243 additions and 31 deletions

View File

@ -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();

View File

@ -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);

View 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 {
}

View 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 {
}

View 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 {
}

View 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 {
}

View 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;
}

View 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 {
}

View 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;
}