File tree Expand file tree Collapse file tree 3 files changed +35
-2
lines changed Expand file tree Collapse file tree 3 files changed +35
-2
lines changed Original file line number Diff line number Diff line change @@ -1646,7 +1646,8 @@ and non-0 as true.
1646
1646
``!and( ``\ *a *\ ``, `` *b *\ ``, ...) ``
1647
1647
This operator does a bitwise AND on *a *, *b *, etc., and produces the
1648
1648
result. A logical AND can be performed if all the arguments are either
1649
- 0 or 1.
1649
+ 0 or 1. This operator is short-circuit to 0 when the left-most operand
1650
+ is 0.
1650
1651
1651
1652
``!cast< ``\ *type *\ ``>( ``\ *a *\ ``) ``
1652
1653
This operator performs a cast on *a * and produces the result.
@@ -1872,7 +1873,8 @@ and non-0 as true.
1872
1873
``!or( ``\ *a *\ ``, `` *b *\ ``, ...) ``
1873
1874
This operator does a bitwise OR on *a *, *b *, etc., and produces the
1874
1875
result. A logical OR can be performed if all the arguments are either
1875
- 0 or 1.
1876
+ 0 or 1. This operator is short-circuit to -1 (all ones) the left-most
1877
+ operand is -1.
1876
1878
1877
1879
``!range([ ``\ *start *\ ``,] `` *end *\ ``[, ``\ *step *\ ``]) ``
1878
1880
This operator produces half-open range sequence ``[start : end : step) `` as
Original file line number Diff line number Diff line change @@ -1543,6 +1543,23 @@ const Init *BinOpInit::resolveReferences(Resolver &R) const {
1543
1543
const Init *lhs = LHS->resolveReferences (R);
1544
1544
const Init *rhs = RHS->resolveReferences (R);
1545
1545
1546
+ unsigned Opc = getOpcode ();
1547
+ if (Opc == AND || Opc == OR) {
1548
+ // Short-circuit. Regardless whether this is a logical or bitwise
1549
+ // AND/OR.
1550
+ // Ideally we could also short-circuit `!or(true, ...)`, but it's
1551
+ // difficult to do it right without knowing if rest of the operands
1552
+ // are all `bit` or not. Therefore, we're only implementing a relatively
1553
+ // limited version of short-circuit against all ones (`true` is casted
1554
+ // to 1 rather than all ones before we evaluate `!or`).
1555
+ if (const auto *LHSi = dyn_cast_or_null<IntInit>(
1556
+ lhs->convertInitializerTo (IntRecTy::get (getRecordKeeper ())))) {
1557
+ if ((Opc == AND && !LHSi->getValue ()) ||
1558
+ (Opc == OR && LHSi->getValue () == -1 ))
1559
+ return LHSi;
1560
+ }
1561
+ }
1562
+
1546
1563
if (LHS != lhs || RHS != rhs)
1547
1564
return (BinOpInit::get (getOpcode (), lhs, rhs, getType ()))
1548
1565
->Fold (R.getCurrentRecord ());
Original file line number Diff line number Diff line change @@ -67,6 +67,20 @@ def rec7 {
67
67
bits<3> flags = { true, false, true };
68
68
}
69
69
70
+ // `!and` and `!or` should be short-circuit such that `!tail` on empty list will never
71
+ // be evaluated.
72
+ // CHECK: def rec8
73
+ // CHECK: list<int> newSeq = [];
74
+ // CHECK: list<int> newSeq2 = [];
75
+
76
+ class Foo <list<int> seq = []> {
77
+ bit unresolved = !ne(!find(NAME, "BAR"), -1);
78
+ list<int> newSeq = !if(!and(false, unresolved), !tail(seq), seq);
79
+ list<int> newSeq2 = !if(!or(-1, unresolved), seq, !tail(seq));
80
+ }
81
+
82
+ def rec8 : Foo<>;
83
+
70
84
#ifdef ERROR1
71
85
// ERROR1: Record name '1' is not a string
72
86
You can’t perform that action at this time.
0 commit comments