summaryrefslogtreecommitdiffstats
path: root/llvm/lib/TableGen
diff options
context:
space:
mode:
authorJaved Absar <javed.absar@arm.com>2019-01-25 10:25:25 +0000
committerJaved Absar <javed.absar@arm.com>2019-01-25 10:25:25 +0000
commita3e3d8528644b3e432538853804553c62fea7722 (patch)
tree797687c37a0bb0af848b5346f88d14cce00164c9 /llvm/lib/TableGen
parent7a35bdb7ec6958429bebd42f3ce40f19cdc9fbd8 (diff)
downloadbcm5719-llvm-a3e3d8528644b3e432538853804553c62fea7722.tar.gz
bcm5719-llvm-a3e3d8528644b3e432538853804553c62fea7722.zip
[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
Diffstat (limited to 'llvm/lib/TableGen')
-rw-r--r--llvm/lib/TableGen/Record.cpp131
-rw-r--r--llvm/lib/TableGen/TGLexer.cpp1
-rw-r--r--llvm/lib/TableGen/TGLexer.h2
-rw-r--r--llvm/lib/TableGen/TGParser.cpp90
-rw-r--r--llvm/lib/TableGen/TGParser.h1
5 files changed, 224 insertions, 1 deletions
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 79f8907d4b5..ab3dfce5e84 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -1693,6 +1693,137 @@ Init *FieldInit::Fold(Record *CurRec) const {
return const_cast<FieldInit *>(this);
}
+static void ProfileCondOpInit(FoldingSetNodeID &ID,
+ ArrayRef<Init *> CondRange,
+ ArrayRef<Init *> ValRange,
+ const RecTy *ValType) {
+ assert(CondRange.size() == ValRange.size() &&
+ "Number of conditions and values must match!");
+ ID.AddPointer(ValType);
+ ArrayRef<Init *>::iterator Case = CondRange.begin();
+ ArrayRef<Init *>::iterator Val = ValRange.begin();
+
+ while (Case != CondRange.end()) {
+ ID.AddPointer(*Case++);
+ ID.AddPointer(*Val++);
+ }
+}
+
+void CondOpInit::Profile(FoldingSetNodeID &ID) const {
+ ProfileCondOpInit(ID,
+ makeArrayRef(getTrailingObjects<Init *>(), NumConds),
+ makeArrayRef(getTrailingObjects<Init *>() + NumConds, NumConds),
+ ValType);
+}
+
+CondOpInit *
+CondOpInit::get(ArrayRef<Init *> CondRange,
+ ArrayRef<Init *> ValRange, RecTy *Ty) {
+ assert(CondRange.size() == ValRange.size() &&
+ "Number of conditions and values must match!");
+
+ static FoldingSet<CondOpInit> ThePool;
+ FoldingSetNodeID ID;
+ ProfileCondOpInit(ID, CondRange, ValRange, Ty);
+
+ void *IP = nullptr;
+ if (CondOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP))
+ return I;
+
+ void *Mem = Allocator.Allocate(totalSizeToAlloc<Init *>(2*CondRange.size()),
+ alignof(BitsInit));
+ CondOpInit *I = new(Mem) CondOpInit(CondRange.size(), Ty);
+
+ std::uninitialized_copy(CondRange.begin(), CondRange.end(),
+ I->getTrailingObjects<Init *>());
+ std::uninitialized_copy(ValRange.begin(), ValRange.end(),
+ I->getTrailingObjects<Init *>()+CondRange.size());
+ ThePool.InsertNode(I, IP);
+ return I;
+}
+
+Init *CondOpInit::resolveReferences(Resolver &R) const {
+ SmallVector<Init*, 4> NewConds;
+ bool Changed = false;
+ for (const Init *Case : getConds()) {
+ Init *NewCase = Case->resolveReferences(R);
+ NewConds.push_back(NewCase);
+ Changed |= NewCase != Case;
+ }
+
+ SmallVector<Init*, 4> NewVals;
+ for (const Init *Val : getVals()) {
+ Init *NewVal = Val->resolveReferences(R);
+ NewVals.push_back(NewVal);
+ Changed |= NewVal != Val;
+ }
+
+ if (Changed)
+ return (CondOpInit::get(NewConds, NewVals,
+ getValType()))->Fold(R.getCurrentRecord());
+
+ return const_cast<CondOpInit *>(this);
+}
+
+Init *CondOpInit::Fold(Record *CurRec) const {
+ for ( unsigned i = 0; i < NumConds; ++i) {
+ Init *Cond = getCond(i);
+ Init *Val = getVal(i);
+
+ if (IntInit *CondI = dyn_cast_or_null<IntInit>(
+ Cond->convertInitializerTo(IntRecTy::get()))) {
+ if (CondI->getValue())
+ return Val->convertInitializerTo(getValType());
+ } else
+ return const_cast<CondOpInit *>(this);
+ }
+
+ PrintFatalError(CurRec->getLoc(),
+ CurRec->getName() +
+ " does not have any true condition in:" +
+ this->getAsString());
+ return nullptr;
+}
+
+bool CondOpInit::isConcrete() const {
+ for (const Init *Case : getConds())
+ if (!Case->isConcrete())
+ return false;
+
+ for (const Init *Val : getVals())
+ if (!Val->isConcrete())
+ return false;
+
+ return true;
+}
+
+bool CondOpInit::isComplete() const {
+ for (const Init *Case : getConds())
+ if (!Case->isComplete())
+ return false;
+
+ for (const Init *Val : getVals())
+ if (!Val->isConcrete())
+ return false;
+
+ return true;
+}
+
+std::string CondOpInit::getAsString() const {
+ std::string Result = "!cond(";
+ for (unsigned i = 0; i < getNumConds(); i++) {
+ Result += getCond(i)->getAsString() + ": ";
+ Result += getVal(i)->getAsString();
+ if (i != getNumConds()-1)
+ Result += ", ";
+ }
+ return Result + ")";
+}
+
+Init *CondOpInit::getBit(unsigned Bit) const {
+ return VarBitInit::get(const_cast<CondOpInit *>(this), Bit);
+}
+
static void ProfileDagInit(FoldingSetNodeID &ID, Init *V, StringInit *VN,
ArrayRef<Init *> ArgRange,
ArrayRef<StringInit *> NameRange) {
diff --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 5dca134f8e8..dbbffda7b35 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -544,6 +544,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("ge", tgtok::XGe)
.Case("gt", tgtok::XGt)
.Case("if", tgtok::XIf)
+ .Case("cond", tgtok::XCond)
.Case("isa", tgtok::XIsA)
.Case("head", tgtok::XHead)
.Case("tail", tgtok::XTail)
diff --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index fcee028d3ae..0cb9ae3f567 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -50,7 +50,7 @@ namespace tgtok {
// !keywords.
XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast,
- XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, XDag,
+ XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag,
XNe, XLe, XLt, XGe, XGt,
// Integer value.
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index cfbab2cf700..22b4b16bc39 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1444,6 +1444,9 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
}
+ case tgtok::XCond:
+ return ParseOperationCond(CurRec, ItemType);
+
case tgtok::XFoldl: {
// Value ::= !foldl '(' Id ',' Id ',' Value ',' Value ',' Value ')'
Lex.Lex(); // eat the operation
@@ -1602,6 +1605,91 @@ RecTy *TGParser::ParseOperatorType() {
return Type;
}
+Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) {
+ Lex.Lex(); // eat the operation 'cond'
+
+ if (Lex.getCode() != tgtok::l_paren) {
+ TokError("expected '(' after !cond operator");
+ return nullptr;
+ }
+ Lex.Lex(); // eat the '('
+
+ // Parse through '[Case: Val,]+'
+ SmallVector<Init *, 4> Case;
+ SmallVector<Init *, 4> Val;
+ while (true) {
+ if (Lex.getCode() == tgtok::r_paren) {
+ Lex.Lex(); // eat the ')'
+ break;
+ }
+
+ Init *V = ParseValue(CurRec);
+ if (!V)
+ return nullptr;
+ Case.push_back(V);
+
+ if (Lex.getCode() != tgtok::colon) {
+ TokError("expected ':' following a condition in !cond operator");
+ return nullptr;
+ }
+ Lex.Lex(); // eat the ':'
+
+ V = ParseValue(CurRec, ItemType);
+ if (!V)
+ return nullptr;
+ Val.push_back(V);
+
+ if (Lex.getCode() == tgtok::r_paren) {
+ Lex.Lex(); // eat the ')'
+ break;
+ }
+
+ if (Lex.getCode() != tgtok::comma) {
+ TokError("expected ',' or ')' following a value in !cond operator");
+ return nullptr;
+ }
+ Lex.Lex(); // eat the ','
+ }
+
+ if (Case.size() < 1) {
+ TokError("there should be at least 1 'condition : value' in the !cond operator");
+ return nullptr;
+ }
+
+ // resolve type
+ RecTy *Type = nullptr;
+ for (Init *V : Val) {
+ RecTy *VTy = nullptr;
+ if (TypedInit *Vt = dyn_cast<TypedInit>(V))
+ VTy = Vt->getType();
+ if (BitsInit *Vbits = dyn_cast<BitsInit>(V))
+ VTy = BitsRecTy::get(Vbits->getNumBits());
+ if (isa<BitInit>(V))
+ VTy = BitRecTy::get();
+
+ if (Type == nullptr) {
+ if (!isa<UnsetInit>(V))
+ Type = VTy;
+ } else {
+ if (!isa<UnsetInit>(V)) {
+ RecTy *RType = resolveTypes(Type, VTy);
+ if (!RType) {
+ TokError(Twine("inconsistent types '") + Type->getAsString() +
+ "' and '" + VTy->getAsString() + "' for !cond");
+ return nullptr;
+ }
+ Type = RType;
+ }
+ }
+ }
+
+ if (!Type) {
+ TokError("could not determine type for !cond from its arguments");
+ return nullptr;
+ }
+ return CondOpInit::get(Case, Val, Type)->Fold(CurRec);
+}
+
/// ParseSimpleValue - Parse a tblgen value. This returns null on error.
///
/// SimpleValue ::= IDValue
@@ -1620,6 +1708,7 @@ RecTy *TGParser::ParseOperatorType() {
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
+/// SimpleValue ::= COND '(' [Value ':' Value,]+ ')'
///
Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
IDParseMode Mode) {
@@ -1932,6 +2021,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
case tgtok::XListConcat:
case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')'
case tgtok::XIf:
+ case tgtok::XCond:
case tgtok::XFoldl:
case tgtok::XForEach:
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
diff --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index 11d610083e7..38b782461bd 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -193,6 +193,7 @@ private: // Parser methods.
bool ParseRangePiece(SmallVectorImpl<unsigned> &Ranges);
RecTy *ParseType();
Init *ParseOperation(Record *CurRec, RecTy *ItemType);
+ Init *ParseOperationCond(Record *CurRec, RecTy *ItemType);
RecTy *ParseOperatorType();
Init *ParseObjectName(MultiClass *CurMultiClass);
Record *ParseClassID();
OpenPOWER on IntegriCloud