[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