[clang] 80bbc05 - [clang][Interp] Implement inv and neg unary operations

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 19 07:05:40 PDT 2022


Author: Timm Bäder
Date: 2022-08-19T16:05:00+02:00
New Revision: 80bbc05436d9c98d65b9b3a5f3907346ef3cb095

URL: https://github.com/llvm/llvm-project/commit/80bbc05436d9c98d65b9b3a5f3907346ef3cb095
DIFF: https://github.com/llvm/llvm-project/commit/80bbc05436d9c98d65b9b3a5f3907346ef3cb095.diff

LOG: [clang][Interp] Implement inv and neg unary operations

Implement negating and inverting values. Also implement
IntegralToBoolean casts so the operations are easier to test.

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/Boolean.h
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/Integral.h
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Opcodes.td
    clang/test/AST/Interp/literals.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h
index 2baa717311bc4..cc3d4686f8f75 100644
--- a/clang/lib/AST/Interp/Boolean.h
+++ b/clang/lib/AST/Interp/Boolean.h
@@ -49,6 +49,7 @@ class Boolean {
   explicit operator unsigned() const { return V; }
   explicit operator int64_t() const { return V; }
   explicit operator uint64_t() const { return V; }
+  explicit operator int() const { return V; }
 
   APSInt toAPSInt() const {
     return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
@@ -134,6 +135,16 @@ class Boolean {
     *R = Boolean(A.V && B.V);
     return false;
   }
+
+  static bool inv(Boolean A, Boolean *R) {
+    *R = Boolean(!A.V);
+    return false;
+  }
+
+  static bool neg(Boolean A, Boolean *R) {
+    *R = Boolean(A.V);
+    return false;
+  }
 };
 
 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Boolean &B) {

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 732d4d5c15a28..8f53f0e1d6f5b 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -116,13 +116,36 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
   case CK_NullToPointer:
     return this->Visit(SubExpr);
 
+  case CK_IntegralCast: {
+    Optional<PrimType> FromT = classify(SubExpr->getType());
+    Optional<PrimType> ToT = classify(CE->getType());
+    if (!FromT || !ToT)
+      return false;
+
+    if (!this->Visit(SubExpr))
+      return false;
+
+    return this->emitCast(*FromT, *ToT, CE);
+  }
+
   case CK_ToVoid:
     return discard(SubExpr);
 
-  default: {
-    // TODO: implement other casts.
-    return this->bail(CE);
-  }
+  case CK_IntegralToBoolean:
+    // Compare integral from Subexpr with 0
+    if (Optional<PrimType> T = classify(SubExpr->getType())) {
+      if (!this->Visit(SubExpr))
+        return false;
+
+      if (!this->emitConst(SubExpr, 0))
+        return false;
+
+      return this->emitNE(*T, SubExpr);
+    }
+    return false;
+
+  default:
+    assert(false && "Cast not implemented");
   }
 }
 
@@ -583,6 +606,40 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
   return this->emitNullPtr(E);
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
+  if (!this->Visit(E->getSubExpr()))
+    return false;
+
+  switch (E->getOpcode()) {
+  case UO_PostInc: // x++
+  case UO_PostDec: // x--
+  case UO_PreInc:  // --x
+  case UO_PreDec:  // ++x
+    return false;
+
+  case UO_LNot: // !x
+    return this->emitInvBool(E);
+  case UO_Minus: // -x
+    if (Optional<PrimType> T = classify(E->getType()))
+      return this->emitNeg(*T, E);
+    return false;
+  case UO_Plus:  // +x
+    return true; // noop
+
+  case UO_AddrOf: // &x
+  case UO_Deref:  // *x
+  case UO_Not:    // ~x
+  case UO_Real:   // __real x
+  case UO_Imag:   // __imag x
+  case UO_Extension:
+  case UO_Coawait:
+    assert(false && "Unhandled opcode");
+  }
+
+  return false;
+}
+
 template <class Emitter>
 void ByteCodeExprGen<Emitter>::emitCleanup() {
   for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 4ce1c8dbe11c1..ae023aee9390d 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -71,6 +71,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitBinaryOperator(const BinaryOperator *E);
   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
+  bool VisitUnaryOperator(const UnaryOperator *E);
 
 protected:
   bool visitExpr(const Expr *E) override;

diff  --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index 46cd611ee3892..fd2c0947a516a 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -155,9 +155,11 @@ template <unsigned Bits, bool Signed> class Integral {
     return Integral(Max);
   }
 
-  template <typename T>
-  static std::enable_if_t<std::is_integral<T>::value, Integral> from(T Value) {
-    return Integral(Value);
+  template <typename ValT> static Integral from(ValT Value) {
+    if constexpr (std::is_integral<ValT>::value)
+      return Integral(Value);
+    else
+      return Integral::from(static_cast<Integral::T>(Value));
   }
 
   template <unsigned SrcBits, bool SrcSign>
@@ -203,6 +205,11 @@ template <unsigned Bits, bool Signed> class Integral {
     return CheckMulUB(A.V, B.V, R->V);
   }
 
+  static bool neg(Integral A, Integral *R) {
+    *R = -A;
+    return false;
+  }
+
 private:
   template <typename T>
   static std::enable_if_t<std::is_signed<T>::value, bool> CheckAddUB(T A, T B,

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 475768677ed9b..ceb0db5c3c264 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -154,6 +154,36 @@ bool Mul(InterpState &S, CodePtr OpPC) {
   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
 }
 
+//===----------------------------------------------------------------------===//
+// Inv
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Inv(InterpState &S, CodePtr OpPC) {
+  using BoolT = PrimConv<PT_Bool>::T;
+  const T &Val = S.Stk.pop<T>();
+  const unsigned Bits = Val.bitWidth();
+  Boolean R;
+  Boolean::inv(BoolT::from(Val, Bits), &R);
+
+  S.Stk.push<BoolT>(R);
+  return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Neg
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Neg(InterpState &S, CodePtr OpPC) {
+  const T &Val = S.Stk.pop<T>();
+  T Result;
+  T::neg(Val, &Result);
+
+  S.Stk.push<T>(Result);
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // EQ, NE, GT, GE, LT, LE
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 638d5b3d23573..971446b06f53f 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -73,6 +73,10 @@ def PtrTypeClass : TypeClass {
   let Types = [Ptr];
 }
 
+def BoolTypeClass : TypeClass {
+  let Types = [Bool];
+}
+
 def AllTypeClass : TypeClass {
   let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types);
 }
@@ -383,6 +387,37 @@ def Sub : AluOpcode;
 def Add : AluOpcode;
 def Mul : AluOpcode;
 
+
+//===----------------------------------------------------------------------===//
+// Unary operators.
+//===----------------------------------------------------------------------===//
+
+// [Real] -> [Real]
+def Inv: Opcode {
+  let Types = [BoolTypeClass];
+  let HasGroup = 1;
+}
+
+// [Real] -> [Real]
+def Neg: Opcode {
+  let Types = [AluTypeClass];
+  let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Cast.
+//===----------------------------------------------------------------------===//
+// TODO: Expand this to handle casts between more types.
+
+def Sint32TypeClass : TypeClass {
+  let Types = [Sint32];
+}
+
+def Cast: Opcode {
+  let Types = [BoolTypeClass, Sint32TypeClass];
+  let HasGroup = 1;
+}
+
 //===----------------------------------------------------------------------===//
 // Comparison opcodes.
 //===----------------------------------------------------------------------===//

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 9aa51846019fa..ed84027f7e1eb 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1,15 +1,33 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify=ref %s
 
 static_assert(true, "");
-static_assert(false, ""); // expected-error{{failed}}
+static_assert(false, ""); // expected-error{{failed}} ref-error{{failed}}
 static_assert(nullptr == nullptr, "");
 static_assert(1 == 1, "");
-static_assert(1 == 3, ""); // expected-error{{failed}}
+static_assert(1 == 3, ""); // expected-error{{failed}} ref-error{{failed}}
 
 constexpr int number = 10;
 static_assert(number == 10, "");
-static_assert(number != 10, ""); // expected-error{{failed}}
+static_assert(number != 10, ""); // expected-error{{failed}} \
+                                 // ref-error{{failed}} \
+                                 // ref-note{{evaluates to}}
 
 constexpr bool getTrue() { return true; }
 constexpr bool getFalse() { return false; }
 constexpr void* getNull() { return nullptr; }
+
+constexpr int neg(int m) { return -m; }
+constexpr bool inv(bool b) { return !b; }
+
+static_assert(12, "");
+static_assert(12 == -(-(12)), "");
+static_assert(!false, "");
+static_assert(!!true, "");
+static_assert(!!true == !false, "");
+static_assert(true == 1, "");
+static_assert(false == 0, "");
+static_assert(!5 == false, "");
+static_assert(!0, "");
+static_assert(-true, "");
+static_assert(-false, ""); //expected-error{{failed}} ref-error{{failed}}


        


More information about the cfe-commits mailing list