[clang] 338c248 - [clang][Interp] Implement inc/dec operators for floats
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu May 4 00:05:34 PDT 2023
Author: Timm Bäder
Date: 2023-05-04T08:52:53+02:00
New Revision: 338c2489f63e1c34db047ac8e45efeeb88c8a067
URL: https://github.com/llvm/llvm-project/commit/338c2489f63e1c34db047ac8e45efeeb88c8a067
DIFF: https://github.com/llvm/llvm-project/commit/338c2489f63e1c34db047ac8e45efeeb88c8a067.diff
LOG: [clang][Interp] Implement inc/dec operators for floats
Differential Revision: https://reviews.llvm.org/D149634
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Floating.h
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/Opcodes.td
clang/test/AST/Interp/floats.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index ba6356136cab..7686a2eb71ec 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1776,6 +1776,11 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return DiscardResult ? this->emitPopPtr(E) : true;
}
+ if (T == PT_Float) {
+ return DiscardResult ? this->emitIncfPop(getRoundingMode(E), E)
+ : this->emitIncf(getRoundingMode(E), E);
+ }
+
return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E);
}
case UO_PostDec: { // x--
@@ -1789,6 +1794,11 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return DiscardResult ? this->emitPopPtr(E) : true;
}
+ if (T == PT_Float) {
+ return DiscardResult ? this->emitDecfPop(getRoundingMode(E), E)
+ : this->emitDecf(getRoundingMode(E), E);
+ }
+
return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E);
}
case UO_PreInc: { // ++x
@@ -1803,9 +1813,19 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
}
// Post-inc and pre-inc are the same if the value is to be discarded.
- if (DiscardResult)
+ if (DiscardResult) {
+ if (T == PT_Float)
+ return this->emitIncfPop(getRoundingMode(E), E);
return this->emitIncPop(*T, E);
+ }
+ if (T == PT_Float) {
+ const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType());
+ this->emitLoadFloat(E);
+ this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E);
+ this->emitAddf(getRoundingMode(E), E);
+ return this->emitStoreFloat(E);
+ }
this->emitLoad(*T, E);
this->emitConst(1, E);
this->emitAdd(*T, E);
@@ -1823,9 +1843,19 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
}
// Post-dec and pre-dec are the same if the value is to be discarded.
- if (DiscardResult)
+ if (DiscardResult) {
+ if (T == PT_Float)
+ return this->emitDecfPop(getRoundingMode(E), E);
return this->emitDecPop(*T, E);
+ }
+ if (T == PT_Float) {
+ const auto &TargetSemantics = Ctx.getFloatSemantics(E->getType());
+ this->emitLoadFloat(E);
+ this->emitConstFloat(llvm::APFloat(TargetSemantics, 1), E);
+ this->emitSubf(getRoundingMode(E), E);
+ return this->emitStoreFloat(E);
+ }
this->emitLoad(*T, E);
this->emitConst(1, E);
this->emitSub(*T, E);
diff --git a/clang/lib/AST/Interp/Floating.h b/clang/lib/AST/Interp/Floating.h
index fb0884bb3b60..90f8c1f8d4ad 100644
--- a/clang/lib/AST/Interp/Floating.h
+++ b/clang/lib/AST/Interp/Floating.h
@@ -111,12 +111,26 @@ class Floating final {
return R->F.add(B.F, RM);
}
+ static APFloat::opStatus increment(const Floating &A, llvm::RoundingMode RM,
+ Floating *R) {
+ APFloat One(A.F.getSemantics(), 1);
+ *R = Floating(A.F);
+ return R->F.add(One, RM);
+ }
+
static APFloat::opStatus sub(Floating A, Floating B, llvm::RoundingMode RM,
Floating *R) {
*R = Floating(A.F);
return R->F.subtract(B.F, RM);
}
+ static APFloat::opStatus decrement(const Floating &A, llvm::RoundingMode RM,
+ Floating *R) {
+ APFloat One(A.F.getSemantics(), 1);
+ *R = Floating(A.F);
+ return R->F.subtract(One, RM);
+ }
+
static APFloat::opStatus mul(Floating A, Floating B, llvm::RoundingMode RM,
Floating *R) {
*R = Floating(A.F);
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 2baef4293d51..64bdd872221a 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -540,6 +540,50 @@ bool DecPop(InterpState &S, CodePtr OpPC) {
return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
}
+template <IncDecOp Op, PushVal DoPush>
+bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ llvm::RoundingMode RM) {
+ Floating Value = Ptr.deref<Floating>();
+ Floating Result;
+
+ if constexpr (DoPush == PushVal::Yes)
+ S.Stk.push<Floating>(Value);
+
+ llvm::APFloat::opStatus Status;
+ if constexpr (Op == IncDecOp::Inc)
+ Status = Floating::increment(Value, RM, &Result);
+ else
+ Status = Floating::decrement(Value, RM, &Result);
+
+ Ptr.deref<Floating>() = Result;
+
+ return CheckFloatResult(S, OpPC, Status);
+}
+
+inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);
+}
+
+inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);
+}
+
+inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);
+}
+
+inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+ return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);
+}
+
/// 1) Pops the value from the stack.
/// 2) Pushes the bitwise complemented value on the stack (~V).
template <PrimType Name, class T = typename PrimConv<Name>::T>
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 717c4629fcc3..15f7312ad00e 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -499,11 +499,18 @@ def Inv: Opcode {
let HasGroup = 1;
}
+// Increment and decrement.
def Inc: IntegerOpcode;
def IncPop : IntegerOpcode;
def Dec: IntegerOpcode;
def DecPop: IntegerOpcode;
+// Float increment and decrement.
+def Incf: FloatOpcode;
+def IncfPop : FloatOpcode;
+def Decf: FloatOpcode;
+def DecfPop : FloatOpcode;
+
// [Real] -> [Real]
def Neg: Opcode {
let Types = [NonPtrTypeClass];
diff --git a/clang/test/AST/Interp/floats.cpp b/clang/test/AST/Interp/floats.cpp
index 71f585ee70a9..7d45999a997c 100644
--- a/clang/test/AST/Interp/floats.cpp
+++ b/clang/test/AST/Interp/floats.cpp
@@ -1,6 +1,15 @@
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
// RUN: %clang_cc1 -verify=ref %s
+
+constexpr void assert(bool C) {
+ if (C)
+ return;
+ // Invalid in constexpr.
+ (void)(1 / 0); // expected-warning {{undefined}} \
+ // ref-warning {{undefined}}
+}
+
constexpr int i = 2;
constexpr float f = 1.0f;
static_assert(f == 1.0f, "");
@@ -79,6 +88,30 @@ namespace compound {
static_assert(f2() == __FLT_MAX__, "");
}
+namespace unary {
+ constexpr float a() {
+ float f = 0.0;
+ assert(++f == 1.0);
+ assert(f == 1.0);
+ ++f;
+ f++;
+ assert(f == 3.0);
+ --f;
+ f--;
+ assert(f == 1.0);
+ return 1.0;
+ }
+ static_assert(a() == 1.0);
+
+ constexpr float b() {
+ float f = __FLT_MAX__;
+ f++;
+ return f;
+ }
+ static_assert(b() == __FLT_MAX__);
+}
+
+
namespace ZeroInit {
template<typename FloatT>
struct A {
More information about the cfe-commits
mailing list