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.
16461646``!and( ``\ *a *\ ``, `` *b *\ ``, ...) ``
16471647 This operator does a bitwise AND on *a *, *b *, etc., and produces the
16481648 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.
16501651
16511652``!cast< ``\ *type *\ ``>( ``\ *a *\ ``) ``
16521653 This operator performs a cast on *a * and produces the result.
@@ -1872,7 +1873,8 @@ and non-0 as true.
18721873``!or( ``\ *a *\ ``, `` *b *\ ``, ...) ``
18731874 This operator does a bitwise OR on *a *, *b *, etc., and produces the
18741875 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.
18761878
18771879``!range([ ``\ *start *\ ``,] `` *end *\ ``[, ``\ *step *\ ``]) ``
18781880 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 {
15431543 const Init *lhs = LHS->resolveReferences (R);
15441544 const Init *rhs = RHS->resolveReferences (R);
15451545
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+
15461563 if (LHS != lhs || RHS != rhs)
15471564 return (BinOpInit::get (getOpcode (), lhs, rhs, getType ()))
15481565 ->Fold (R.getCurrentRecord ());
Original file line number Diff line number Diff line change @@ -67,6 +67,20 @@ def rec7 {
6767 bits<3> flags = { true, false, true };
6868}
6969
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+
7084#ifdef ERROR1
7185// ERROR1: Record name '1' is not a string
7286
You can’t perform that action at this time.
0 commit comments