[llvm] 952c6dd - [TableGen] Add the !find bang operator

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 28 06:53:52 PDT 2021


Author: Paul C. Anagnostopoulos
Date: 2021-04-28T09:51:00-04:00
New Revision: 952c6ddd8b32a0dc4a65147e20999428191950f0

URL: https://github.com/llvm/llvm-project/commit/952c6ddd8b32a0dc4a65147e20999428191950f0
DIFF: https://github.com/llvm/llvm-project/commit/952c6ddd8b32a0dc4a65147e20999428191950f0.diff

LOG: [TableGen] Add the !find bang operator

!find searches a source string for a target string and returns the position.

Differential Revision: https://reviews.llvm.org/D101318

Added: 
    llvm/test/TableGen/find.td

Modified: 
    llvm/docs/TableGen/ProgRef.rst
    llvm/include/llvm/TableGen/Record.h
    llvm/lib/TableGen/Record.cpp
    llvm/lib/TableGen/TGLexer.cpp
    llvm/lib/TableGen/TGLexer.h
    llvm/lib/TableGen/TGParser.cpp
    llvm/lib/TableGen/TGParser.h

Removed: 
    


################################################################################
diff  --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 8a9842f5b288b..9b9ae58e110c8 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -218,13 +218,13 @@ TableGen provides "bang operators" that have a wide variety of uses:
 .. productionlist::
    BangOperator: one of
                : !add        !and         !cast        !con         !dag 
-               : !empty      !eq          !foldl       !foreach     !filter
-               : !ge         !getdagop    !gt          !head        !if
-               : !interleave !isa         !le          !listconcat  !listsplat
-               : !lt         !mul         !ne          !not         !or
-               : !setdagop   !shl         !size        !sra         !srl
-               : !strconcat  !sub         !subst       !substr      !tail
-               : !xor
+               : !empty      !eq          !filter      !find        !foldl
+               : !foreach    !ge          !getdagop    !gt          !head
+               : !if         !interleave  !isa         !le          !listconcat
+               : !listsplat  !lt          !mul         !ne          !not
+               : !or         !setdagop    !shl         !size        !sra
+               : !srl        !strconcat   !sub         !subst       !substr
+               : !tail       !xor
 
 The ``!cond`` operator has a slightly 
diff erent
 syntax compared to other bang operators, so it is defined separately:
@@ -1639,6 +1639,12 @@ and non-0 as true.
     if the value is 0, the element is not included in the new list. If the value
     is anything else, the element is included.
 
+``!find(``\ *string1*\ ``,`` *string2*\ [``,`` *start*]\ ``)``
+    This operator searches for *string2* in *string1* and produces its
+    position. The starting position of the search may be specified by *start*,
+    which can range between 0 and the length of *string1*; the default is 0.
+    If the string is not found, the result is -1.
+
 ``!foldl(``\ *init*\ ``,`` *list*\ ``,`` *acc*\ ``,`` *var*\ ``,`` *expr*\ ``)``
     This operator performs a left-fold over the items in *list*. The
     variable *acc* acts as the accumulator and is initialized to *init*.

diff  --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index d8f978f504476..717347ae03bad 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -862,7 +862,7 @@ class BinOpInit : public OpInit, public FoldingSetNode {
 /// !op (X, Y, Z) - Combine two inits.
 class TernOpInit : public OpInit, public FoldingSetNode {
 public:
-  enum TernaryOp : uint8_t { SUBST, FOREACH, FILTER, IF, DAG, SUBSTR };
+  enum TernaryOp : uint8_t { SUBST, FOREACH, FILTER, IF, DAG, SUBSTR, FIND };
 
 private:
   Init *LHS, *MHS, *RHS;

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 6e63fb3f7fffd..fc80a2648f9c9 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -1398,6 +1398,26 @@ Init *TernOpInit::Fold(Record *CurRec) const {
     }
     break;
   }
+
+  case FIND: {
+    StringInit *LHSs = dyn_cast<StringInit>(LHS);
+    StringInit *MHSs = dyn_cast<StringInit>(MHS);
+    IntInit *RHSi = dyn_cast<IntInit>(RHS);
+    if (LHSs && MHSs && RHSi) {
+      int64_t SourceSize = LHSs->getValue().size();
+      int64_t Start = RHSi->getValue();
+      if (Start < 0 || Start > SourceSize)
+        PrintError(CurRec->getLoc(),
+                   Twine("!find start position is out of range 0...") +
+                       std::to_string(SourceSize) + ": " +
+                       std::to_string(Start));
+      auto I = LHSs->getValue().find(MHSs->getValue(), Start);
+      if (I == std::string::npos)
+        return IntInit::get(-1);
+      return IntInit::get(I);
+    }
+    break;
+  }
   }
 
   return const_cast<TernOpInit *>(this);
@@ -1443,6 +1463,7 @@ std::string TernOpInit::getAsString() const {
   case IF: Result = "!if"; break;
   case SUBST: Result = "!subst"; break;
   case SUBSTR: Result = "!substr"; break;
+  case FIND: Result = "!find"; break;
   }
   return (Result + "(" +
           (UnquotedLHS ? LHS->getAsUnquotedString() : LHS->getAsString()) +

diff  --git a/llvm/lib/TableGen/TGLexer.cpp b/llvm/lib/TableGen/TGLexer.cpp
index 60a0e34ea8e8e..91229818077f8 100644
--- a/llvm/lib/TableGen/TGLexer.cpp
+++ b/llvm/lib/TableGen/TGLexer.cpp
@@ -591,6 +591,7 @@ tgtok::TokKind TGLexer::LexExclaim() {
     .Case("strconcat", tgtok::XStrConcat)
     .Case("interleave", tgtok::XInterleave)
     .Case("substr", tgtok::XSubstr)
+    .Case("find", tgtok::XFind)
     .Cases("setdagop", "setop", tgtok::XSetDagOp) // !setop is deprecated.
     .Cases("getdagop", "getop", tgtok::XGetDagOp) // !getop is deprecated.
     .Default(tgtok::Error);

diff  --git a/llvm/lib/TableGen/TGLexer.h b/llvm/lib/TableGen/TGLexer.h
index 2f322f705e0da..857ba09782e84 100644
--- a/llvm/lib/TableGen/TGLexer.h
+++ b/llvm/lib/TableGen/TGLexer.h
@@ -53,7 +53,7 @@ namespace tgtok {
 
     // Bang operators.
     XConcat, XADD, XSUB, XMUL, XNOT, XAND, XOR, XXOR, XSRA, XSRL, XSHL,
-    XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XCast,
+    XListConcat, XListSplat, XStrConcat, XInterleave, XSubstr, XFind, XCast,
     XSubst, XForEach, XFilter, XFoldl, XHead, XTail, XSize, XEmpty, XIf,
     XCond, XEq, XIsA, XDag, XNe, XLe, XLt, XGe, XGt, XSetDagOp, XGetDagOp,
 

diff  --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index 07cf89b6062e1..8d228d73f2531 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1508,6 +1508,9 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
   case tgtok::XSubstr:
     return ParseOperationSubstr(CurRec, ItemType);
 
+  case tgtok::XFind:
+    return ParseOperationFind(CurRec, ItemType);
+
   case tgtok::XCond:
     return ParseOperationCond(CurRec, ItemType);
 
@@ -1756,6 +1759,94 @@ Init *TGParser::ParseOperationSubstr(Record *CurRec, RecTy *ItemType) {
   return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
 }
 
+/// Parse the !find operation. Return null on error.
+///
+/// Substr ::= !find(string, string [, start-int]) => int
+Init *TGParser::ParseOperationFind(Record *CurRec, RecTy *ItemType) {
+  TernOpInit::TernaryOp Code = TernOpInit::FIND;
+  RecTy *Type = IntRecTy::get();
+
+  Lex.Lex(); // eat the operation
+
+  if (!consume(tgtok::l_paren)) {
+    TokError("expected '(' after !find operator");
+    return nullptr;
+  }
+
+  Init *LHS = ParseValue(CurRec);
+  if (!LHS)
+    return nullptr;
+
+  if (!consume(tgtok::comma)) {
+    TokError("expected ',' in !find operator");
+    return nullptr;
+  }
+
+  SMLoc MHSLoc = Lex.getLoc();
+  Init *MHS = ParseValue(CurRec);
+  if (!MHS)
+    return nullptr;
+
+  SMLoc RHSLoc = Lex.getLoc();
+  Init *RHS;
+  if (consume(tgtok::comma)) {
+    RHSLoc = Lex.getLoc();
+    RHS = ParseValue(CurRec);
+    if (!RHS)
+      return nullptr;
+  } else {
+    RHS = IntInit::get(0);
+  }
+
+  if (!consume(tgtok::r_paren)) {
+    TokError("expected ')' in !find operator");
+    return nullptr;
+  }
+
+  if (ItemType && !Type->typeIsConvertibleTo(ItemType)) {
+    Error(RHSLoc, Twine("expected value of type '") +
+                  ItemType->getAsString() + "', got '" +
+                  Type->getAsString() + "'");
+  }
+
+  TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
+  if (!LHSt && !isa<UnsetInit>(LHS)) {
+    TokError("could not determine type of the source string in !find");
+    return nullptr;
+  }
+  if (LHSt && !isa<StringRecTy>(LHSt->getType())) {
+    TokError(Twine("expected string, got type '") +
+             LHSt->getType()->getAsString() + "'");
+    return nullptr;
+  }
+
+  TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
+  if (!MHSt && !isa<UnsetInit>(MHS)) {
+    TokError("could not determine type of the target string in !find");
+    return nullptr;
+  }
+  if (MHSt && !isa<StringRecTy>(MHSt->getType())) {
+    Error(MHSLoc, Twine("expected string, got type '") +
+                      MHSt->getType()->getAsString() + "'");
+    return nullptr;
+  }
+
+  if (RHS) {
+    TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
+    if (!RHSt && !isa<UnsetInit>(RHS)) {
+      TokError("could not determine type of the start position in !find");
+      return nullptr;
+    }
+    if (RHSt && !isa<IntRecTy>(RHSt->getType())) {
+      TokError(Twine("expected int, got type '") +
+               RHSt->getType()->getAsString() + "'");
+      return nullptr;
+    }
+  }
+
+  return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
+}
+
 /// Parse the !foreach and !filter operations. Return null on error.
 ///
 /// ForEach ::= !foreach(ID, list-or-dag, expr) => list<expr type>
@@ -2282,7 +2373,8 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
   case tgtok::XForEach:
   case tgtok::XFilter:
   case tgtok::XSubst:
-  case tgtok::XSubstr: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
+  case tgtok::XSubstr:
+  case tgtok::XFind: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
     return ParseOperation(CurRec, ItemType);
   }
   }

diff  --git a/llvm/lib/TableGen/TGParser.h b/llvm/lib/TableGen/TGParser.h
index f4311346555d0..6e3c5186e4f66 100644
--- a/llvm/lib/TableGen/TGParser.h
+++ b/llvm/lib/TableGen/TGParser.h
@@ -262,6 +262,7 @@ class TGParser {
   RecTy *ParseType();
   Init *ParseOperation(Record *CurRec, RecTy *ItemType);
   Init *ParseOperationSubstr(Record *CurRec, RecTy *ItemType);
+  Init *ParseOperationFind(Record *CurRec, RecTy *ItemType);
   Init *ParseOperationForEachFilter(Record *CurRec, RecTy *ItemType);
   Init *ParseOperationCond(Record *CurRec, RecTy *ItemType);
   RecTy *ParseOperatorType();

diff  --git a/llvm/test/TableGen/find.td b/llvm/test/TableGen/find.td
new file mode 100644
index 0000000000000..f5448dd8684d8
--- /dev/null
+++ b/llvm/test/TableGen/find.td
@@ -0,0 +1,64 @@
+// RUN: llvm-tblgen %s | FileCheck %s
+// RUN: not llvm-tblgen -DERROR1 %s 2>&1 | FileCheck --check-prefix=ERROR1 %s
+
+// This file contains tests for the !find bang operator.
+
+defvar Sentence = "This is the end of the world.";
+
+// CHECK: def Rec01
+// CHECK-NEXT:   int FirstThe = 8
+// CHECK-NEXT:   int SameThe = 8
+// CHECK-NEXT:   int SecondThe = 19
+// CHECK-NEXT:   int ThirdThe = -1
+
+def Rec01 {
+  int FirstThe = !find(Sentence, "the");
+  int SameThe = !find(Sentence, "the", FirstThe);
+  int SecondThe = !find(Sentence, "the", !add(FirstThe, 1));
+  int ThirdThe = !find(Sentence, "the", !add(SecondThe, 1));
+}
+
+class C1<string name> {
+  string Name = name;
+  bit IsJr = !ne(!find(name, "Jr"), -1);
+}
+
+// CHECK: def Rec02
+// CHECK-NEXT:   string Name = "Sally Smith"
+// CHECK-NEXT:   bit IsJr = 0
+// CHECK: def Rec03
+// CHECK-NEXT:   string Name = "Fred Jones, Jr."
+// CHECK-NEXT:   bit IsJr = 1
+
+def Rec02 : C1<"Sally Smith">;
+def Rec03 : C1<"Fred Jones, Jr.">;
+
+// CHECK: def Rec04
+// CHECK-NEXT:   int ThisPos = 0
+// CHECK-NEXT:   int WorldPos = 23
+// CHECK-NEXT:   int TooLong = -1
+
+def Rec04 {
+  int ThisPos = !find(Sentence, "This");
+  int WorldPos = !find(Sentence, "world.");
+  int TooLong = !find(Sentence, "world.country");
+}
+
+// CHECK: def Rec05
+// CHECK-NEXT:   string Name = "Pat Snork"
+// CHECK-NEXT:   bit IsJr = 0
+// CHECK-NEXT:   bit JrOrSnork = 1
+
+def Rec05 : C1<"Pat Snork"> {
+  bit JrOrSnork = !or(IsJr, !ne(!find(Name, "Snork"), -1));
+}
+
+#ifdef ERROR1
+
+// ERROR1: !find start position is out of range 0...29: 100
+
+def Rec06 {
+  int Test1 = !find(Sentence, "the", 100);
+}
+#endif
+


        


More information about the llvm-commits mailing list