[clang][Interp] Implement add and sub compound assign operators
authorTimm Bäder <tbaeder@redhat.com>
Sat, 22 Oct 2022 13:32:27 +0000 (15:32 +0200)
committerTimm Bäder <tbaeder@redhat.com>
Sun, 30 Oct 2022 07:11:04 +0000 (08:11 +0100)
Differential Revision: https://reviews.llvm.org/D136528

clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/test/AST/Interp/literals.cpp

index 30ae7fb..2edd16b 100644 (file)
@@ -414,6 +414,57 @@ bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral(
   return this->emitConst(E, E->getValue());
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
+    const CompoundAssignOperator *E) {
+  const Expr *LHS = E->getLHS();
+  const Expr *RHS = E->getRHS();
+  Optional<PrimType> LT = classify(E->getLHS()->getType());
+  Optional<PrimType> RT = classify(E->getRHS()->getType());
+
+  if (!LT || !RT)
+    return false;
+
+  assert(!E->getType()->isPointerType() &&
+         "Support pointer arithmethic in compound assignment operators");
+
+  // Get LHS pointer, load its value and get RHS value.
+  if (!visit(LHS))
+    return false;
+  if (!this->emitLoad(*LT, E))
+    return false;
+  if (!visit(RHS))
+    return false;
+
+  // Perform operation.
+  switch (E->getOpcode()) {
+  case BO_AddAssign:
+    if (!this->emitAdd(*LT, E))
+      return false;
+    break;
+  case BO_SubAssign:
+    if (!this->emitSub(*LT, E))
+      return false;
+    break;
+
+  case BO_MulAssign:
+  case BO_DivAssign:
+  case BO_RemAssign:
+  case BO_ShlAssign:
+  case BO_ShrAssign:
+  case BO_AndAssign:
+  case BO_XorAssign:
+  case BO_OrAssign:
+  default:
+    llvm_unreachable("Unimplemented compound assign operator");
+  }
+
+  // And store the result in LHS.
+  if (DiscardResult)
+    return this->emitStorePop(*LT, E);
+  return this->emitStore(*LT, E);
+}
+
 template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
   OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
   return this->Visit(E);
index 489e8bd..4c7550a 100644 (file)
@@ -85,6 +85,7 @@ public:
   bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
   bool VisitStringLiteral(const StringLiteral *E);
   bool VisitCharacterLiteral(const CharacterLiteral *E);
+  bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
 
 protected:
   bool visitExpr(const Expr *E) override;
index 1c6aa4e..afb98e3 100644 (file)
@@ -415,5 +415,43 @@ namespace IncDec {
                                          // expected-note {{in call to 'UnderFlow()'}} \
                                          // ref-error {{not an integral constant expression}} \
                                          // ref-note {{in call to 'UnderFlow()'}}
+
+  constexpr int getTwo() {
+    int i = 1;
+    return (i += 1);
+  }
+  static_assert(getTwo() == 2, "");
+
+  constexpr int sub(int a) {
+    return (a -= 2);
+  }
+  static_assert(sub(7) == 5, "");
+
+  constexpr int add(int a, int b) {
+    a += b; // expected-note {{is outside the range of representable values}} \
+            // ref-note {{is outside the range of representable values}} 
+    return a;
+  }
+  static_assert(add(1, 2) == 3, "");
+  static_assert(add(INT_MAX, 1) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                           // expected-note {{in call to 'add}} \
+                                           // ref-error {{not an integral constant expression}} \
+                                           // ref-note {{in call to 'add}}
+
+  constexpr int sub(int a, int b) {
+    a -= b; // expected-note {{is outside the range of representable values}} \
+            // ref-note {{is outside the range of representable values}} 
+    return a;
+  }
+  static_assert(sub(10, 20) == -10, "");
+  static_assert(sub(INT_MIN, 1) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                           // expected-note {{in call to 'sub}} \
+                                           // ref-error {{not an integral constant expression}} \
+                                           // ref-note {{in call to 'sub}}
+
+  constexpr int subAll(int a) {
+    return (a -= a);
+  }
+  static_assert(subAll(213) == 0, "");
 };
 #endif