Skip to content

Commit

Permalink
[llvm][TableGen] Add a !initialized predicate to allow testing for ? (l…
Browse files Browse the repository at this point in the history
…lvm#117964)

There are cases (like in an upcoming patch to MLIR's `Property` class)
where the ? value is a useful null value. However, existing predicates
make ti difficult to test if the value in a record one is operating is ?
or not.

This commit adds the !initialized predicate, which is 1 on concrete,
non-? values and 0 on ?.

---------

Co-authored-by: Akshat Oke <[email protected]>
  • Loading branch information
krzysz00 and optimisan authored Dec 18, 2024
1 parent fb33268 commit b24caf3
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 16 deletions.
19 changes: 12 additions & 7 deletions llvm/docs/TableGen/ProgRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,13 @@ TableGen provides "bang operators" that have a wide variety of uses:
: !div !empty !eq !exists !filter
: !find !foldl !foreach !ge !getdagarg
: !getdagname !getdagop !gt !head !if
: !interleave !isa !le !listconcat !listflatten
: !listremove !listsplat !logtwo !lt !mul
: !ne !not !or !range !repr
: !setdagarg !setdagname !setdagop !shl !size
: !sra !srl !strconcat !sub !subst
: !substr !tail !tolower !toupper !xor
: !initialized !interleave !isa !le !listconcat
: !listflatten !listremove !listsplat !logtwo !lt
: !mul !ne !not !or !range
: !repr !setdagarg !setdagname !setdagop !shl
: !size !sra !srl !strconcat !sub
: !subst !substr !tail !tolower !toupper
: !xor

The ``!cond`` operator has a slightly different
syntax compared to other bang operators, so it is defined separately:
Expand Down Expand Up @@ -555,7 +556,7 @@ previous case, if the *right-hand-side* operand is an undefined name or a
global name, it is treated as a verbatim string of characters. The
left-hand-side operand is treated normally.

Values can have a trailing paste operator, in which case the left-hand-side
Values can have a trailing paste operator, in which case the left-hand-side
operand is concatenated to an empty string.

`Appendix B: Paste Operator Examples`_ presents examples of the behavior of
Expand Down Expand Up @@ -1815,6 +1816,10 @@ and non-0 as true.
``int``. If the result is not 0, the *then* expression is produced; otherwise
the *else* expression is produced.

``!initialized(``\ *a*\ ``)``
This operator produces 1 if *a* is not the uninitialized value (``?``) and 0
otherwise.

``!interleave(``\ *list*\ ``,`` *delim*\ ``)``
This operator concatenates the items in the *list*, interleaving the
*delim* string between each pair, and produces the resulting string.
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/TableGen/Record.h
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@ class UnOpInit : public OpInit, public FoldingSetNode {
LOG2,
REPR,
LISTFLATTEN,
INITIALIZED,
};

private:
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/TableGen/Record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,13 @@ const Init *UnOpInit::Fold(const Record *CurRec, bool IsFinal) const {
return NewInit;
break;

case INITIALIZED:
if (isa<UnsetInit>(LHS))
return IntInit::get(RK, 0);
if (LHS->isConcrete())
return IntInit::get(RK, 1);
break;

case NOT:
if (const auto *LHSi = dyn_cast_or_null<IntInit>(
LHS->convertInitializerTo(IntRecTy::get(RK))))
Expand Down Expand Up @@ -1052,6 +1059,9 @@ std::string UnOpInit::getAsString() const {
case TOUPPER:
Result = "!toupper";
break;
case INITIALIZED:
Result = "!initialized";
break;
}
return Result + "(" + LHS->getAsString() + ")";
}
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/TableGen/TGLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
.Case("listremove", tgtok::XListRemove)
.Case("range", tgtok::XRange)
.Case("strconcat", tgtok::XStrConcat)
.Case("initialized", tgtok::XInitialized)
.Case("interleave", tgtok::XInterleave)
.Case("substr", tgtok::XSubstr)
.Case("find", tgtok::XFind)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/TableGen/TGLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ enum TokKind {
XTail,
XSize,
XEmpty,
XInitialized,
XIf,
XCond,
XEq,
Expand Down
24 changes: 15 additions & 9 deletions llvm/lib/TableGen/TGParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -969,7 +969,7 @@ const TypedInit *TGParser::ParseSliceElements(Record *CurRec, bool Single) {
/// RangePiece ::= INTVAL
/// RangePiece ::= INTVAL '...' INTVAL
/// RangePiece ::= INTVAL '-' INTVAL
/// RangePiece ::= INTVAL INTVAL
/// RangePiece ::= INTVAL INTVAL
// The last two forms are deprecated.
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
const TypedInit *FirstItem) {
Expand Down Expand Up @@ -1203,7 +1203,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
case tgtok::XEmpty:
case tgtok::XCast:
case tgtok::XRepr:
case tgtok::XGetDagOp: { // Value ::= !unop '(' Value ')'
case tgtok::XGetDagOp:
case tgtok::XInitialized: { // Value ::= !unop '(' Value ')'
UnOpInit::UnaryOp Code;
const RecTy *Type = nullptr;

Expand Down Expand Up @@ -1291,6 +1292,11 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
}
Code = UnOpInit::GETDAGOP;
break;
case tgtok::XInitialized:
Lex.Lex(); // eat the operation
Code = UnOpInit::INITIALIZED;
Type = IntRecTy::get(Records);
break;
}
if (!consume(tgtok::l_paren)) {
TokError("expected '(' after unary operator");
Expand Down Expand Up @@ -1655,8 +1661,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
!ArgType->typeIsConvertibleTo(StringRecTy::get(Records)) &&
!ArgType->typeIsConvertibleTo(RecordRecTy::get(Records, {}))) {
Error(InitLoc, Twine("expected bit, bits, int, string, or record; "
"got value of type '") + ArgType->getAsString() +
"'");
"got value of type '") +
ArgType->getAsString() + "'");
return nullptr;
}
break;
Expand All @@ -1669,8 +1675,8 @@ const Init *TGParser::ParseOperation(Record *CurRec, const RecTy *ItemType) {
if (!ArgType->typeIsConvertibleTo(IntRecTy::get(Records)) &&
!ArgType->typeIsConvertibleTo(StringRecTy::get(Records))) {
Error(InitLoc, Twine("expected bit, bits, int, or string; "
"got value of type '") + ArgType->getAsString() +
"'");
"got value of type '") +
ArgType->getAsString() + "'");
return nullptr;
}
break;
Expand Down Expand Up @@ -2528,7 +2534,7 @@ const Init *TGParser::ParseOperationForEachFilter(Record *CurRec,
OutType = RHSt->getType()->getListTy();
} else if (Operation == tgtok::XFilter) {
OutType = InEltType->getListTy();
}
}

return (TernOpInit::get((Operation == tgtok::XForEach) ? TernOpInit::FOREACH
: TernOpInit::FILTER,
Expand Down Expand Up @@ -3548,7 +3554,7 @@ bool TGParser::ParseBody(Record *CurRec) {
SMLoc SemiLoc = Lex.getLoc();
if (consume(tgtok::semi)) {
PrintError(SemiLoc, "A class or def body should not end with a semicolon");
PrintNote("Semicolon ignored; remove to eliminate this error");
PrintNote("Semicolon ignored; remove to eliminate this error");
}

return false;
Expand Down Expand Up @@ -4218,7 +4224,7 @@ bool TGParser::ParseMultiClass() {
SMLoc SemiLoc = Lex.getLoc();
if (consume(tgtok::semi)) {
PrintError(SemiLoc, "A multiclass body should not end with a semicolon");
PrintNote("Semicolon ignored; remove to eliminate this error");
PrintNote("Semicolon ignored; remove to eliminate this error");
}
}

Expand Down
59 changes: 59 additions & 0 deletions llvm/test/TableGen/initialized.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// RUN: llvm-tblgen %s | FileCheck %s

// CHECK: class F<Y [[ARG:.+]] = ?> {
// CHECK: string ret = !if(!initialized([[ARG]].str), [[ARG]].str, "N/A");
// CHECK: }

// CHECK-LABEL: def C
// CHECK: bit c0 = 0
// CHECK: bit c1 = 1
// CHECK: bit c2 = 1
def C {
bit c0 = !initialized(?);
bit c1 = !initialized(0);
bit c2 = !initialized(1);
}

class Y {
string str = ?;
}

class F<Y y> {
string ret = !if(!initialized(y.str), y.str, "N/A");
}

def Y0 : Y;
def Y1 : Y {
let str = "foo";
}

// CHECK-LABEL: def FY0
// CHECK: string ret = "N/A";
// CHECK-LABEL: def FY1
// CHECK: string ret = "foo";
def FY0 : F<Y0>;
def FY1 : F<Y1>;

class G<Y y> {
list<string> v = [y.str];
bit isInit = !initialized(v);
}

// CHECK-LABEL: def GY0
// CHECK: isInit = 1
// CHECK-LABEL: def GY1
// CHECK: isInit = 1
def GY0 : G<Y0>;
def GY1 : G<Y1>;

class Thing;
def aThing : Thing;
class Propagate<Thing t> {
Thing ret = !if(!initialized(t), t, ?);
}
// CHECK-LABEL: def PropagateNothing
// CHECK: Thing ret = ?
// CHECK-LABEL: def PropagateThing
// CHECK: Thing ret = aThing
def PropagateNothing : Propagate<?>;
def PropagateThing : Propagate<aThing>;

0 comments on commit b24caf3

Please sign in to comment.