[clang][Interp] Implement missing compound assign operators
authorTimm Bäder <tbaeder@redhat.com>
Mon, 31 Oct 2022 11:44:38 +0000 (12:44 +0100)
committerTimm Bäder <tbaeder@redhat.com>
Thu, 19 Jan 2023 11:24:56 +0000 (12:24 +0100)
Implement mul, div, rem, etc. compound assign operators.

Differential Revision: https://reviews.llvm.org/D137071

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

index d014086..8565f63 100644 (file)
@@ -525,8 +525,8 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
     const CompoundAssignOperator *E) {
   const Expr *LHS = E->getLHS();
   const Expr *RHS = E->getRHS();
-  std::optional<PrimType> LT = classify(E->getLHS()->getType());
-  std::optional<PrimType> RT = classify(E->getRHS()->getType());
+  std::optional<PrimType> LT = classify(E->getComputationLHSType());
+  std::optional<PrimType> RT = classify(E->getComputationResultType());
 
   if (!LT || !RT)
     return false;
@@ -552,10 +552,18 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
     if (!this->emitSub(*LT, E))
       return false;
     break;
-
   case BO_MulAssign:
+    if (!this->emitMul(*LT, E))
+      return false;
+    break;
   case BO_DivAssign:
+    if (!this->emitDiv(*LT, E))
+      return false;
+    break;
   case BO_RemAssign:
+    if (!this->emitRem(*LT, E))
+      return false;
+    break;
   case BO_ShlAssign:
     if (!this->emitShl(*LT, *RT, E))
       return false;
@@ -565,8 +573,17 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
       return false;
     break;
   case BO_AndAssign:
+    if (!this->emitBitAnd(*LT, E))
+      return false;
+    break;
   case BO_XorAssign:
+    if (!this->emitBitXor(*LT, E))
+      return false;
+    break;
   case BO_OrAssign:
+    if (!this->emitBitOr(*LT, E))
+      return false;
+    break;
   default:
     llvm_unreachable("Unimplemented compound assign operator");
   }
index cd5c9da..4fc9489 100644 (file)
@@ -469,5 +469,160 @@ namespace IncDec {
     return (a -= a);
   }
   static_assert(subAll(213) == 0, "");
+
+  constexpr bool BoolOr(bool b1, bool b2) {
+    bool a;
+    a = b1;
+    a |= b2;
+    return a;
+  }
+  static_assert(BoolOr(true, true), "");
+  static_assert(BoolOr(true, false), "");
+  static_assert(BoolOr(false, true), "");
+  static_assert(!BoolOr(false, false), "");
+
+  constexpr int IntOr(unsigned a, unsigned b) {
+    unsigned r;
+    r = a;
+    r |= b;
+    return r;
+  }
+  static_assert(IntOr(10, 1) == 11, "");
+  static_assert(IntOr(1337, -1) == -1, "");
+  static_assert(IntOr(0, 12) == 12, "");
+
+  constexpr bool BoolAnd(bool b1, bool b2) {
+    bool a;
+    a = b1;
+    a &= b2;
+    return a;
+  }
+  static_assert(BoolAnd(true, true), "");
+  static_assert(!BoolAnd(true, false), "");
+  static_assert(!BoolAnd(false, true), "");
+  static_assert(!BoolAnd(false, false), "");
+
+  constexpr int IntAnd(unsigned a, unsigned b) {
+    unsigned r;
+    r = a;
+    r &= b;
+    return r;
+  }
+  static_assert(IntAnd(10, 1) == 0, "");
+  static_assert(IntAnd(1337, -1) == 1337, "");
+  static_assert(IntAnd(0, 12) == 0, "");
+
+  constexpr bool BoolXor(bool b1, bool b2) {
+    bool a;
+    a = b1;
+    a ^= b2;
+    return a;
+  }
+  static_assert(!BoolXor(true, true), "");
+  static_assert(BoolXor(true, false), "");
+  static_assert(BoolXor(false, true), "");
+  static_assert(!BoolXor(false, false), "");
+
+  constexpr int IntXor(unsigned a, unsigned b) {
+    unsigned r;
+    r = a;
+    r ^= b;
+    return r;
+  }
+  static_assert(IntXor(10, 1) == 11, "");
+  static_assert(IntXor(10, 10) == 0, "");
+  static_assert(IntXor(12, true) == 13, "");
+
+  constexpr bool BoolRem(bool b1, bool b2) {
+    bool a;
+    a = b1;
+    a %= b2;
+    return a;
+  }
+  static_assert(!BoolRem(true, true), "");
+  static_assert(!BoolRem(false, true), "");
+
+  constexpr int IntRem(int a, int b) {
+    int r;
+    r = a;
+    r %= b; // expected-note {{division by zero}} \
+            // ref-note {{division by zero}} \
+            // expected-note {{outside the range of representable values}} \
+            // ref-note {{outside the range of representable values}}
+    return r;
+  }
+  static_assert(IntRem(2, 2) == 0, "");
+  static_assert(IntRem(2, 1) == 0, "");
+  static_assert(IntRem(9, 7) == 2, "");
+  static_assert(IntRem(5, 0) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                        // expected-note {{in call to 'IntRem(5, 0)'}} \
+                                        // ref-error {{not an integral constant expression}} \
+                                        // ref-note {{in call to 'IntRem(5, 0)'}}
+
+  static_assert(IntRem(INT_MIN, -1) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                               // expected-note {{in call to 'IntRem}} \
+                                               // ref-error {{not an integral constant expression}} \
+                                               // ref-note {{in call to 'IntRem}}
+
+
+
+  constexpr bool BoolDiv(bool b1, bool b2) {
+    bool a;
+    a = b1;
+    a /= b2;
+    return a;
+  }
+  static_assert(BoolDiv(true, true), "");
+  static_assert(!BoolDiv(false, true), "");
+
+  constexpr int IntDiv(int a, int b) {
+    int r;
+    r = a;
+    r /= b; // expected-note {{division by zero}} \
+            // ref-note {{division by zero}} \
+            // expected-note {{outside the range of representable values}} \
+            // ref-note {{outside the range of representable values}}
+    return r;
+  }
+  static_assert(IntDiv(2, 2) == 1, "");
+  static_assert(IntDiv(12, 20) == 0, "");
+  static_assert(IntDiv(2, 1) == 2, "");
+  static_assert(IntDiv(9, 7) == 1, "");
+  static_assert(IntDiv(5, 0) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                        // expected-note {{in call to 'IntDiv(5, 0)'}} \
+                                        // ref-error {{not an integral constant expression}} \
+                                        // ref-note {{in call to 'IntDiv(5, 0)'}}
+
+  static_assert(IntDiv(INT_MIN, -1) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                               // expected-note {{in call to 'IntDiv}} \
+                                               // ref-error {{not an integral constant expression}} \
+                                               // ref-note {{in call to 'IntDiv}}
+
+  constexpr bool BoolMul(bool b1, bool b2) {
+    bool a;
+    a = b1;
+    a *= b2;
+    return a;
+  }
+  static_assert(BoolMul(true, true), "");
+  static_assert(!BoolMul(true, false), "");
+  static_assert(!BoolMul(false, true), "");
+  static_assert(!BoolMul(false, false), "");
+
+  constexpr int IntMul(int a, int b) {
+    int r;
+    r = a;
+    r *= b; // expected-note {{is outside the range of representable values of type 'int'}} \
+            // ref-note {{is outside the range of representable values of type 'int'}}
+    return r;
+  }
+  static_assert(IntMul(2, 2) == 4, "");
+  static_assert(IntMul(12, 20) == 240, "");
+  static_assert(IntMul(2, 1) == 2, "");
+  static_assert(IntMul(9, 7) == 63, "");
+  static_assert(IntMul(INT_MAX, 2) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                              // expected-note {{in call to 'IntMul}} \
+                                              // ref-error {{not an integral constant expression}} \
+                                              // ref-note {{in call to 'IntMul}}
 };
 #endif