Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions llvm/lib/TableGen/Record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,23 @@ const Init *BinOpInit::resolveReferences(Resolver &R) const {
const Init *lhs = LHS->resolveReferences(R);
const Init *rhs = RHS->resolveReferences(R);

if (getOpcode() == AND) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need similar short circuit for OR as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I had thought this before. The problem is that since !or is for both logical and bitwise operation, we can't short circuit something like this !or(true, <unknown / unresolved>) until the second operand is resolved (in which case it's not a short circuit anymore) because we're not sure if the second operand is a int (bitwise OR) or a bit (logical OR).

That said, I think a separate logical OR / AND like you suggested might help us to apply short-circuit with more confidence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I had thought this before. The problem is that since !or is for both logical and bitwise operation, we can't short circuit something like this !or(true, <unknown / unresolved>) until the second operand is resolved (in which case it's not a short circuit anymore) because we're not sure if the second operand is a int (bitwise OR) or a bit (logical OR).

I just made a blunder and forgot that !or(<all ones>, ...) can also be short-circuited. I'll add this case into this patch as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The short-circuit for !or against all ones was just added.

// Short-circuit. Regardless whether this is a logical or bitwise
// AND.
if (lhs != LHS)
if (const auto *LHSi = dyn_cast_or_null<IntInit>(
lhs->convertInitializerTo(IntRecTy::get(getRecordKeeper())))) {
if (!LHSi->getValue())
return LHSi;
}
if (rhs != RHS)
if (const auto *RHSi = dyn_cast_or_null<IntInit>(
rhs->convertInitializerTo(IntRecTy::get(getRecordKeeper())))) {
if (!RHSi->getValue())
return RHSi;
}
}

if (LHS != lhs || RHS != rhs)
return (BinOpInit::get(getOpcode(), lhs, rhs, getType()))
->Fold(R.getCurrentRecord());
Expand Down
14 changes: 14 additions & 0 deletions llvm/test/TableGen/true-false.td
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,20 @@ def rec7 {
bits<3> flags = { true, false, true };
}

// The `!and` 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 containsStr = !ne(!find(NAME, "BAR"), -1);
list<int> newSeq = !if(!and(!not(!empty(seq)), containsStr), !tail(seq), seq);
list<int> newSeq2 = !if(!and(containsStr, !not(!empty(seq))), !tail(seq), seq);
}

def rec8 : Foo<>;

#ifdef ERROR1
// ERROR1: Record name '1' is not a string

Expand Down
Loading