[clang] d2ea8ae - [clang][Interp] Implement logical and/or operators
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 25 21:53:29 PST 2023
Author: Timm Bäder
Date: 2023-01-26T06:52:35+01:00
New Revision: d2ea8ae5d43e05791a201e7ca233d3f637254597
URL: https://github.com/llvm/llvm-project/commit/d2ea8ae5d43e05791a201e7ca233d3f637254597
DIFF: https://github.com/llvm/llvm-project/commit/d2ea8ae5d43e05791a201e7ca233d3f637254597.diff
LOG: [clang][Interp] Implement logical and/or operators
Differential Revision: https://reviews.llvm.org/D140809
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/test/AST/Interp/cond.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index a2f0a77142ad8..aaab980ac81bc 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -187,6 +187,10 @@ bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
+ // Need short-circuiting for these.
+ if (BO->isLogicalOp())
+ return this->VisitLogicalBinOp(BO);
+
const Expr *LHS = BO->getLHS();
const Expr *RHS = BO->getRHS();
@@ -270,8 +274,9 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
return Discard(this->emitShr(*LT, *RT, BO));
case BO_Xor:
return Discard(this->emitBitXor(*T, BO));
- case BO_LAnd:
case BO_LOr:
+ case BO_LAnd:
+ llvm_unreachable("Already handled earlier");
default:
return this->bail(BO);
}
@@ -329,6 +334,65 @@ bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
return this->bail(E);
}
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
+ assert(E->isLogicalOp());
+ BinaryOperatorKind Op = E->getOpcode();
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+
+ if (Op == BO_LOr) {
+ // Logical OR. Visit LHS and only evaluate RHS if LHS was FALSE.
+ LabelTy LabelTrue = this->getLabel();
+ LabelTy LabelEnd = this->getLabel();
+
+ if (!this->visit(LHS))
+ return false;
+ if (!this->jumpTrue(LabelTrue))
+ return false;
+
+ if (!this->visit(RHS))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+
+ this->emitLabel(LabelTrue);
+ this->emitConstBool(true, E);
+ this->fallthrough(LabelEnd);
+ this->emitLabel(LabelEnd);
+
+ if (DiscardResult)
+ return this->emitPopBool(E);
+
+ return true;
+ }
+
+ // Logical AND.
+ // Visit LHS. Only visit RHS if LHS was TRUE.
+ LabelTy LabelFalse = this->getLabel();
+ LabelTy LabelEnd = this->getLabel();
+
+ if (!this->visit(LHS))
+ return false;
+ if (!this->jumpFalse(LabelFalse))
+ return false;
+
+ if (!this->visit(RHS))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+
+ this->emitLabel(LabelFalse);
+ this->emitConstBool(false, E);
+ this->fallthrough(LabelEnd);
+ this->emitLabel(LabelEnd);
+
+ if (DiscardResult)
+ return this->emitPopBool(E);
+
+ return true;
+}
+
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
std::optional<PrimType> T = classify(E);
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index ed33e0285a8f1..0a64ff3513dd8 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -61,6 +61,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitFloatingLiteral(const FloatingLiteral *E);
bool VisitParenExpr(const ParenExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitLogicalBinOp(const BinaryOperator *E);
bool VisitPointerArithBinOp(const BinaryOperator *E);
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
bool VisitCallExpr(const CallExpr *E);
diff --git a/clang/test/AST/Interp/cond.cpp b/clang/test/AST/Interp/cond.cpp
index 1fc69ed333e15..8679c116f57bb 100644
--- a/clang/test/AST/Interp/cond.cpp
+++ b/clang/test/AST/Interp/cond.cpp
@@ -9,3 +9,29 @@ constexpr int cond_then_else(int a, int b) {
return a - b;
}
}
+
+constexpr int dontCallMe(unsigned m) {
+ if (m == 0) return 0;
+ return dontCallMe(m - 2);
+}
+
+// Can't call this because it will run into infinite recursion.
+constexpr int assertNotReached() {
+ return dontCallMe(3);
+}
+
+static_assert(true || true, "");
+static_assert(true || false, "");
+static_assert(false || true, "");
+static_assert(!(false || false), "");
+
+static_assert(true || assertNotReached(), "");
+static_assert(true || true || true || false, "");
+
+static_assert(true && true, "");
+static_assert(!(true && false), "");
+static_assert(!(false && true), "");
+static_assert(!(false && false), "");
+
+static_assert(!(false && assertNotReached()), "");
+static_assert(!(true && true && true && false), "");
More information about the cfe-commits
mailing list