[llvm] [RISCV][NFC] Use !range bang operator (PR #66494)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 15 03:54:28 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v
            
<details>
<summary>Changes</summary>
To simplify some code.

This PR is stacked on #66489.

--
Full diff: https://github.com/llvm/llvm-project/pull/66494.diff

7 Files Affected:

- (modified) llvm/docs/TableGen/ProgRef.rst (+7-5) 
- (modified) llvm/include/llvm/TableGen/Record.h (+1-1) 
- (modified) llvm/lib/TableGen/Record.cpp (+29-2) 
- (modified) llvm/lib/TableGen/TGParser.cpp (+100-58) 
- (modified) llvm/lib/Target/RISCV/RISCVRegisterInfo.td (+4-5) 
- (modified) llvm/test/TableGen/range-op-fail.td (+2-2) 
- (modified) llvm/test/TableGen/range-op.td (+16) 


<pre>
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index aa29d830ec90772..299143a8982be88 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -1831,11 +1831,13 @@ and non-0 as true.
     result. A logical OR can be performed if all the arguments are either
     0 or 1.
 
-``!range([``\ *a*\ ``,``] *b*\ ``)``
-    This operator produces half-open range sequence ``[a : b)`` as ``list&lt;int&gt;``.
-    *a* is ``0`` by default. ``!range(4)`` is equivalent to ``!range(0, 4)``.
-    The result is `[0, 1, 2, 3]`.
-    If *a* ``&gt;=`` *b*, then the result is `[]&lt;list&lt;int&gt;&gt;`.
+``!range([``\ *start*\ ``,]`` *end*\ ``[, ``\ *step*\ ``])``
+    This operator produces half-open range sequence ``[start : end : step)`` as
+    ``list&lt;int&gt;``. *start* is ``0`` and *step* is ``1`` by default. *step* can
+    be negative and cannot be 0. If *start* ``&lt;`` *end* and *step* is negative,
+    or *start* ``&gt;`` *end* and *step* is positive, the result is an empty list
+    ``[]&lt;list&lt;int&gt;&gt;``. For example, ``!range(4)`` is equivalent to
+    ``!range(0, 4, 1)`` and the result is `[0, 1, 2, 3]`.
 
 ``!range(``\ *list*\ ``)``
     Equivalent to ``!range(0, !size(list))``.
diff --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index 06e4abb27e59983..7d743d24f4801ba 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -911,7 +911,6 @@ class BinOpInit : public OpInit, public FoldingSetNode {
     LISTREMOVE,
     LISTELEM,
     LISTSLICE,
-    RANGE,
     RANGEC,
     STRCONCAT,
     INTERLEAVE,
@@ -988,6 +987,7 @@ class TernOpInit : public OpInit, public FoldingSetNode {
     FILTER,
     IF,
     DAG,
+    RANGE,
     SUBSTR,
     FIND,
     SETDAGARG,
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 20db470855a102b..ac8c12ace98bb60 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -1287,7 +1287,6 @@ Init *BinOpInit::Fold(Record *CurRec) const {
     }
     return ListInit::get(Args, TheList-&gt;getElementType());
   }
-  case RANGE:
   case RANGEC: {
     auto *LHSi = dyn_cast&lt;IntInit&gt;(LHS);
     auto *RHSi = dyn_cast&lt;IntInit&gt;(RHS);
@@ -1488,7 +1487,6 @@ std::string BinOpInit::getAsString() const {
   case LISTCONCAT: Result = &quot;!listconcat&quot;; break;
   case LISTSPLAT: Result = &quot;!listsplat&quot;; break;
   case LISTREMOVE: Result = &quot;!listremove&quot;; break;
-  case RANGE: Result = &quot;!range&quot;; break;
   case STRCONCAT: Result = &quot;!strconcat&quot;; break;
   case INTERLEAVE: Result = &quot;!interleave&quot;; break;
   case SETDAGOP: Result = &quot;!setdagop&quot;; break;
@@ -1704,6 +1702,34 @@ Init *TernOpInit::Fold(Record *CurRec) const {
     break;
   }
 
+  case RANGE: {
+    auto *LHSi = dyn_cast&lt;IntInit&gt;(LHS);
+    auto *MHSi = dyn_cast&lt;IntInit&gt;(MHS);
+    auto *RHSi = dyn_cast&lt;IntInit&gt;(RHS);
+    if (!LHSi || !MHSi || !RHSi)
+      break;
+
+    auto Start = LHSi-&gt;getValue();
+    auto End = MHSi-&gt;getValue();
+    auto Step = RHSi-&gt;getValue();
+    if (Step == 0)
+      PrintError(CurRec-&gt;getLoc(), &quot;Step of !range can&#x27;t be 0&quot;);
+
+    SmallVector&lt;Init *, 8&gt; Args;
+    if (Start &lt; End &amp;&amp; Step &gt; 0) {
+      Args.reserve((End - Start) / Step);
+      for (auto I = Start; I &lt; End; I += Step)
+        Args.push_back(IntInit::get(getRecordKeeper(), I));
+    } else if (Start &gt; End &amp;&amp; Step &lt; 0) {
+      Args.reserve((Start - End) / -Step);
+      for (auto I = Start; I &gt; End; I += Step)
+        Args.push_back(IntInit::get(getRecordKeeper(), I));
+    } else {
+      // Empty set
+    }
+    return ListInit::get(Args, LHSi-&gt;getType());
+  }
+
   case SUBSTR: {
     StringInit *LHSs = dyn_cast&lt;StringInit&gt;(LHS);
     IntInit *MHSi = dyn_cast&lt;IntInit&gt;(MHS);
@@ -1823,6 +1849,7 @@ std::string TernOpInit::getAsString() const {
   case FILTER: Result = &quot;!filter&quot;; UnquotedLHS = true; break;
   case FOREACH: Result = &quot;!foreach&quot;; UnquotedLHS = true; break;
   case IF: Result = &quot;!if&quot;; break;
+  case RANGE: Result = &quot;!range&quot;; break;
   case SUBST: Result = &quot;!subst&quot;; break;
   case SUBSTR: Result = &quot;!substr&quot;; break;
   case FIND: Result = &quot;!find&quot;; break;
diff --git a/llvm/lib/TableGen/TGParser.cpp b/llvm/lib/TableGen/TGParser.cpp
index b4bc9272fa324af..ae2f07cd94530da 100644
--- a/llvm/lib/TableGen/TGParser.cpp
+++ b/llvm/lib/TableGen/TGParser.cpp
@@ -1408,7 +1408,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
   case tgtok::XListConcat:
   case tgtok::XListSplat:
   case tgtok::XListRemove:
-  case tgtok::XRange:
   case tgtok::XStrConcat:
   case tgtok::XInterleave:
   case tgtok::XGetDagArg:
@@ -1441,7 +1440,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
     case tgtok::XListSplat:  Code = BinOpInit::LISTSPLAT; break;
     case tgtok::XListRemove: Code = BinOpInit::LISTREMOVE; break;
-    case tgtok::XRange:      Code = BinOpInit::RANGE; break;
     case tgtok::XStrConcat:  Code = BinOpInit::STRCONCAT; break;
     case tgtok::XInterleave: Code = BinOpInit::INTERLEAVE; break;
     case tgtok::XSetDagOp:   Code = BinOpInit::SETDAGOP; break;
@@ -1508,10 +1506,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
       // We don&#x27;t know the list type until we parse the first argument.
       ArgType = ItemType;
       break;
-    case tgtok::XRange:
-      Type = IntRecTy::get(Records)-&gt;getListTy();
-      // ArgType may be either Int or List.
-      break;
     case tgtok::XStrConcat:
       Type = StringRecTy::get(Records);
       ArgType = StringRecTy::get(Records);
@@ -1596,27 +1590,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
             return nullptr;
           }
           break;
-        case BinOpInit::RANGE:
-          if (InitList.size() == 1) {
-            if (isa&lt;ListRecTy&gt;(ArgType)) {
-              ArgType = nullptr; // Detect error if 2nd arg were present.
-            } else if (isa&lt;IntRecTy&gt;(ArgType)) {
-              // Assume 2nd arg should be IntRecTy
-            } else {
-              Error(InitLoc,
-                    Twine(&quot;expected list or int, got value of type &#x27;&quot;) +
-                        ArgType-&gt;getAsString() + &quot;&#x27;&quot;);
-              return nullptr;
-            }
-          } else {
-            // Don&#x27;t come here unless 1st arg is ListRecTy.
-            assert(isa&lt;ListRecTy&gt;(cast&lt;TypedInit&gt;(InitList[0])-&gt;getType()));
-            Error(InitLoc,
-                  Twine(&quot;expected one list, got extra value of type &#x27;&quot;) +
-                      ArgType-&gt;getAsString() + &quot;&#x27;&quot;);
-            return nullptr;
-          }
-          break;
         case BinOpInit::EQ:
         case BinOpInit::NE:
           if (!ArgType-&gt;typeIsConvertibleTo(IntRecTy::get(Records)) &amp;&amp;
@@ -1726,37 +1699,6 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     if (Code == BinOpInit::LISTREMOVE)
       Type = ArgType;
 
-    if (Code == BinOpInit::RANGE) {
-      Init *LHS, *RHS;
-      auto ArgCount = InitList.size();
-      assert(ArgCount &gt;= 1);
-      auto *Arg0 = cast&lt;TypedInit&gt;(InitList[0]);
-      auto *Arg0Ty = Arg0-&gt;getType();
-      if (ArgCount == 1) {
-        if (isa&lt;ListRecTy&gt;(Arg0Ty)) {
-          // (0, !size(arg))
-          LHS = IntInit::get(Records, 0);
-          RHS = UnOpInit::get(UnOpInit::SIZE, Arg0, IntRecTy::get(Records))
-                    -&gt;Fold(CurRec);
-        } else {
-          assert(isa&lt;IntRecTy&gt;(Arg0Ty));
-          // (0, arg)
-          LHS = IntInit::get(Records, 0);
-          RHS = Arg0;
-        }
-      } else if (ArgCount == 2) {
-        assert(isa&lt;IntRecTy&gt;(Arg0Ty));
-        auto *Arg1 = cast&lt;TypedInit&gt;(InitList[1]);
-        assert(isa&lt;IntRecTy&gt;(Arg1-&gt;getType()));
-        LHS = Arg0;
-        RHS = Arg1;
-      } else {
-        Error(OpLoc, &quot;expected at most two values of integer&quot;);
-        return nullptr;
-      }
-      return BinOpInit::get(Code, LHS, RHS, Type)-&gt;Fold(CurRec);
-    }
-
     // We allow multiple operands to associative operators like !strconcat as
     // shorthand for nesting them.
     if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT ||
@@ -1783,6 +1725,105 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
     return ParseOperationForEachFilter(CurRec, ItemType);
   }
 
+  case tgtok::XRange: {
+    SMLoc OpLoc = Lex.getLoc();
+    Lex.Lex(); // eat the operation
+
+    if (!consume(tgtok::l_paren)) {
+      TokError(&quot;expected &#x27;(&#x27; after !range operator&quot;);
+      return nullptr;
+    }
+
+    SmallVector&lt;Init *, 2&gt; Args;
+    bool FirstArgIsList = false;
+    for (;;) {
+      if (Args.size() &gt;= 3) {
+        TokError(&quot;expected at most three values of integer&quot;);
+        return nullptr;
+      }
+
+      SMLoc InitLoc = Lex.getLoc();
+      Args.push_back(ParseValue(CurRec));
+      if (!Args.back())
+        return nullptr;
+
+      TypedInit *ArgBack = dyn_cast&lt;TypedInit&gt;(Args.back());
+      if (!ArgBack) {
+        Error(OpLoc, Twine(&quot;expected value to be a typed value, got &#x27;&quot; +
+                           Args.back()-&gt;getAsString() + &quot;&#x27;&quot;));
+        return nullptr;
+      }
+
+      RecTy *ArgBackType = ArgBack-&gt;getType();
+      if (!FirstArgIsList || Args.size() == 1) {
+        if (Args.size() == 1 &amp;&amp; isa&lt;ListRecTy&gt;(ArgBackType)) {
+          FirstArgIsList = true; // Detect error if 2nd arg were present.
+        } else if (isa&lt;IntRecTy&gt;(ArgBackType)) {
+          // Assume 2nd arg should be IntRecTy
+        } else {
+          if (Args.size() != 1)
+            Error(InitLoc, Twine(&quot;expected value of type &#x27;int&#x27;, got &#x27;&quot; +
+                                 ArgBackType-&gt;getAsString() + &quot;&#x27;&quot;));
+          else
+            Error(InitLoc, Twine(&quot;expected list or int, got value of type &#x27;&quot;) +
+                               ArgBackType-&gt;getAsString() + &quot;&#x27;&quot;);
+          return nullptr;
+        }
+      } else {
+        // Don&#x27;t come here unless 1st arg is ListRecTy.
+        assert(isa&lt;ListRecTy&gt;(cast&lt;TypedInit&gt;(Args[0])-&gt;getType()));
+        Error(InitLoc, Twine(&quot;expected one list, got extra value of type &#x27;&quot;) +
+                           ArgBackType-&gt;getAsString() + &quot;&#x27;&quot;);
+        return nullptr;
+      }
+      if (!consume(tgtok::comma))
+        break;
+    }
+
+    if (!consume(tgtok::r_paren)) {
+      TokError(&quot;expected &#x27;)&#x27; in operator&quot;);
+      return nullptr;
+    }
+
+    Init *LHS, *MHS, *RHS;
+    auto ArgCount = Args.size();
+    assert(ArgCount &gt;= 1);
+    auto *Arg0 = cast&lt;TypedInit&gt;(Args[0]);
+    auto *Arg0Ty = Arg0-&gt;getType();
+    if (ArgCount == 1) {
+      if (isa&lt;ListRecTy&gt;(Arg0Ty)) {
+        // (0, !size(arg), 1)
+        LHS = IntInit::get(Records, 0);
+        MHS = UnOpInit::get(UnOpInit::SIZE, Arg0, IntRecTy::get(Records))
+                  -&gt;Fold(CurRec);
+        RHS = IntInit::get(Records, 1);
+      } else {
+        assert(isa&lt;IntRecTy&gt;(Arg0Ty));
+        // (0, arg, 1)
+        LHS = IntInit::get(Records, 0);
+        MHS = Arg0;
+        RHS = IntInit::get(Records, 1);
+      }
+    } else {
+      assert(isa&lt;IntRecTy&gt;(Arg0Ty));
+      auto *Arg1 = cast&lt;TypedInit&gt;(Args[1]);
+      assert(isa&lt;IntRecTy&gt;(Arg1-&gt;getType()));
+      LHS = Arg0;
+      MHS = Arg1;
+      if (ArgCount == 3) {
+        // (start, end, step)
+        auto *Arg2 = cast&lt;TypedInit&gt;(Args[2]);
+        assert(isa&lt;IntRecTy&gt;(Arg2-&gt;getType()));
+        RHS = Arg2;
+      } else
+        // (start, end, 1)
+        RHS = IntInit::get(Records, 1);
+    }
+    return TernOpInit::get(TernOpInit::RANGE, LHS, MHS, RHS,
+                           IntRecTy::get(Records)-&gt;getListTy())
+        -&gt;Fold(CurRec);
+  }
+
   case tgtok::XSetDagArg:
   case tgtok::XSetDagName:
   case tgtok::XDag:
@@ -2534,6 +2575,7 @@ Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) {
 ///   SimpleValue ::= LISTREMOVETOK &#x27;(&#x27; Value &#x27;,&#x27; Value &#x27;)&#x27;
 ///   SimpleValue ::= RANGE &#x27;(&#x27; Value &#x27;)&#x27;
 ///   SimpleValue ::= RANGE &#x27;(&#x27; Value &#x27;,&#x27; Value &#x27;)&#x27;
+///   SimpleValue ::= RANGE &#x27;(&#x27; Value &#x27;,&#x27; Value &#x27;,&#x27; Value &#x27;)&#x27;
 ///   SimpleValue ::= STRCONCATTOK &#x27;(&#x27; Value &#x27;,&#x27; Value &#x27;)&#x27;
 ///   SimpleValue ::= COND &#x27;(&#x27; [Value &#x27;:&#x27; Value,]+ &#x27;)&#x27;
 ///
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
index 1a6145f92908134..b639a33e3a0bc49 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.td
@@ -350,7 +350,7 @@ class NFList&lt;int lmul&gt; {
 // Generate [start, end) SubRegIndex list.
 class SubRegSet&lt;int nf, int lmul&gt; {
   list&lt;SubRegIndex&gt; L = !foldl([]&lt;SubRegIndex&gt;,
-                               [0, 1, 2, 3, 4, 5, 6, 7],
+                               !range(0, 8),
                                AccList, i,
                                !listconcat(AccList,
                                  !if(!lt(i, nf),
@@ -420,8 +420,7 @@ foreach Index = 0-31 in {
   def V#Index : RISCVReg&lt;Index, &quot;v&quot;#Index&gt;, DwarfRegNum&lt;[!add(Index, 96)]&gt;;
 }
 
-foreach Index = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,
-                 24, 26, 28, 30] in {
+foreach Index = !range(0, 32, 2) in {
   def V#Index#M2 : RISCVRegWithSubRegs&lt;Index, &quot;v&quot;#Index,
                      [!cast&lt;Register&gt;(&quot;V&quot;#Index),
                       !cast&lt;Register&gt;(&quot;V&quot;#!add(Index, 1))]&gt;,
@@ -430,7 +429,7 @@ foreach Index = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22,
   }
 }
 
-foreach Index = [0, 4, 8, 12, 16, 20, 24, 28] in {
+foreach Index = !range(0, 32, 4) in {
   def V#Index#M4 : RISCVRegWithSubRegs&lt;Index, &quot;v&quot;#Index,
                      [!cast&lt;Register&gt;(&quot;V&quot;#Index#&quot;M2&quot;),
                       !cast&lt;Register&gt;(&quot;V&quot;#!add(Index, 2)#&quot;M2&quot;)]&gt;,
@@ -439,7 +438,7 @@ foreach Index = [0, 4, 8, 12, 16, 20, 24, 28] in {
   }
 }
 
-foreach Index = [0, 8, 16, 24] in {
+foreach Index = !range(0, 32, 8) in {
   def V#Index#M8 : RISCVRegWithSubRegs&lt;Index, &quot;v&quot;#Index,
                      [!cast&lt;Register&gt;(&quot;V&quot;#Index#&quot;M4&quot;),
                       !cast&lt;Register&gt;(&quot;V&quot;#!add(Index, 4)#&quot;M4&quot;)]&gt;,
diff --git a/llvm/test/TableGen/range-op-fail.td b/llvm/test/TableGen/range-op-fail.td
index 3238d60abe7f89c..e20bc2eefa692b4 100644
--- a/llvm/test/TableGen/range-op-fail.td
+++ b/llvm/test/TableGen/range-op-fail.td
@@ -16,8 +16,8 @@ defvar errs = !range(0, list_int);
 
 #ifdef ERR_TOO_MANY_ARGS
 // RUN: not llvm-tblgen %s -DERR_TOO_MANY_ARGS 2&gt;&amp;1 | FileCheck -DFILE=%s %s --check-prefix=ERR_TOO_MANY_ARGS
-// ERR_TOO_MANY_ARGS: [[FILE]]:[[@LINE+1]]:15: error: expected at most two values of integer
-defvar errs = !range(0, 42, 255);
+// ERR_TOO_MANY_ARGS: [[FILE]]:[[@LINE+1]]:34: error: expected at most three values of integer
+defvar errs = !range(0, 42, 255, 233);
 #endif
 
 #ifdef ERR_UNEXPECTED_TYPE_0
diff --git a/llvm/test/TableGen/range-op.td b/llvm/test/TableGen/range-op.td
index b7e587d47b8cba5..55af93a3aedb5d6 100644
--- a/llvm/test/TableGen/range-op.td
+++ b/llvm/test/TableGen/range-op.td
@@ -11,10 +11,26 @@ def range_op_ranges {
   // CHECK: list&lt;int&gt; idxs4 = [4, 5, 6, 7];
   list&lt;int&gt; idxs4 = !range(4, 8);
 
+  // !range(m, n, s) generates half-open interval &quot;[m,n)&quot; with step s
+  // CHECK: list&lt;int&gt; step = [0, 2, 4, 6];
+  list&lt;int&gt; step = !range(0, 8, 2);
+
+  // Step can be negative.
+  // CHECK: list&lt;int&gt; negative_step = [8, 6, 4, 2];
+  list&lt;int&gt; negative_step = !range(8, 0, -2);
+
   // !range(m, n) generates empty set if m &gt;= n
   // CHECK: list&lt;int&gt; idxs84 = [];
   list&lt;int&gt; idxs84 = !range(8, 4);
 
+  // !range(m, n, s) generates empty set if m &lt; n and s &lt; 0
+  // CHECK: list&lt;int&gt; emptycase0 = [];
+  list&lt;int&gt; emptycase0 = !range(4, 8, -1);
+
+  // !range(m, n, s) generates empty set if m &gt; n and s &gt; 0
+  // CHECK: list&lt;int&gt; emptycase1 = [];
+  list&lt;int&gt; emptycase1 = !range(8, 4, 1);
+
   // !range(list) generates index values for the list. (Not a copy of the list)
   // CHECK: list&lt;int&gt; idxsl = [0, 1, 2, 3];
   list&lt;int&gt; idxsl = !range(idxs4);
</pre>
</details>


https://github.com/llvm/llvm-project/pull/66494


More information about the llvm-commits mailing list