[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