[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