[llvm] e8b70e9 - [TableGen] Make `!and` and `!or` short-circuit (#113963)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 7 10:22:06 PST 2024
Author: Min-Yih Hsu
Date: 2024-11-07T10:22:03-08:00
New Revision: e8b70e97447dc0d93a277b0373345d3a1bae1aa9
URL: https://github.com/llvm/llvm-project/commit/e8b70e97447dc0d93a277b0373345d3a1bae1aa9
DIFF: https://github.com/llvm/llvm-project/commit/e8b70e97447dc0d93a277b0373345d3a1bae1aa9.diff
LOG: [TableGen] Make `!and` and `!or` short-circuit (#113963)
The idea is that by preemptively simplifying the result of `!and` and `!or`, we can fold
some of the conditional operators, like `!if` or `!cond`, as early as
possible.
Added:
Modified:
llvm/docs/TableGen/ProgRef.rst
llvm/lib/TableGen/Record.cpp
llvm/test/TableGen/true-false.td
Removed:
################################################################################
diff --git a/llvm/docs/TableGen/ProgRef.rst b/llvm/docs/TableGen/ProgRef.rst
index 5cf48d6ed29786..03fe1157b4042e 100644
--- a/llvm/docs/TableGen/ProgRef.rst
+++ b/llvm/docs/TableGen/ProgRef.rst
@@ -1646,7 +1646,8 @@ and non-0 as true.
``!and(``\ *a*\ ``,`` *b*\ ``, ...)``
This operator does a bitwise AND on *a*, *b*, etc., and produces the
result. A logical AND can be performed if all the arguments are either
- 0 or 1.
+ 0 or 1. This operator is short-circuit to 0 when the left-most operand
+ is 0.
``!cast<``\ *type*\ ``>(``\ *a*\ ``)``
This operator performs a cast on *a* and produces the result.
@@ -1872,7 +1873,8 @@ and non-0 as true.
``!or(``\ *a*\ ``,`` *b*\ ``, ...)``
This operator does a bitwise OR on *a*, *b*, etc., and produces the
result. A logical OR can be performed if all the arguments are either
- 0 or 1.
+ 0 or 1. This operator is short-circuit to -1 (all ones) the left-most
+ operand is -1.
``!range([``\ *start*\ ``,]`` *end*\ ``[,``\ *step*\ ``])``
This operator produces half-open range sequence ``[start : end : step)`` as
diff --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index 1d71482b020b22..feef51f3d203cd 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -1543,6 +1543,23 @@ const Init *BinOpInit::resolveReferences(Resolver &R) const {
const Init *lhs = LHS->resolveReferences(R);
const Init *rhs = RHS->resolveReferences(R);
+ unsigned Opc = getOpcode();
+ if (Opc == AND || Opc == OR) {
+ // Short-circuit. Regardless whether this is a logical or bitwise
+ // AND/OR.
+ // Ideally we could also short-circuit `!or(true, ...)`, but it's
+ //
diff icult to do it right without knowing if rest of the operands
+ // are all `bit` or not. Therefore, we're only implementing a relatively
+ // limited version of short-circuit against all ones (`true` is casted
+ // to 1 rather than all ones before we evaluate `!or`).
+ if (const auto *LHSi = dyn_cast_or_null<IntInit>(
+ lhs->convertInitializerTo(IntRecTy::get(getRecordKeeper())))) {
+ if ((Opc == AND && !LHSi->getValue()) ||
+ (Opc == OR && LHSi->getValue() == -1))
+ return LHSi;
+ }
+ }
+
if (LHS != lhs || RHS != rhs)
return (BinOpInit::get(getOpcode(), lhs, rhs, getType()))
->Fold(R.getCurrentRecord());
diff --git a/llvm/test/TableGen/true-false.td b/llvm/test/TableGen/true-false.td
index 597ad9f5ecc8e7..5a59f20b21d252 100644
--- a/llvm/test/TableGen/true-false.td
+++ b/llvm/test/TableGen/true-false.td
@@ -67,6 +67,20 @@ def rec7 {
bits<3> flags = { true, false, true };
}
+// `!and` and `!or` should be short-circuit such that `!tail` on empty list will never
+// be evaluated.
+// CHECK: def rec8
+// CHECK: list<int> newSeq = [];
+// CHECK: list<int> newSeq2 = [];
+
+class Foo <list<int> seq = []> {
+ bit unresolved = !ne(!find(NAME, "BAR"), -1);
+ list<int> newSeq = !if(!and(false, unresolved), !tail(seq), seq);
+ list<int> newSeq2 = !if(!or(-1, unresolved), seq, !tail(seq));
+}
+
+def rec8 : Foo<>;
+
#ifdef ERROR1
// ERROR1: Record name '1' is not a string
More information about the llvm-commits
mailing list