[clang] [clang][bytecode] Implement more binary operators for fixed point types (PR #110423)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 29 05:20:36 PDT 2024


https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/110423

None

>From d3142de6b640915ce69c4a11edc50a241949eccf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sun, 29 Sep 2024 14:18:26 +0200
Subject: [PATCH] [clang][bytecode] Implement more binary operators for fixed
 point types

---
 clang/lib/AST/ByteCode/Compiler.cpp     |  8 +++--
 clang/lib/AST/ByteCode/FixedPoint.h     | 39 +++++++++++++++++++++----
 clang/lib/AST/ByteCode/Interp.h         | 12 +++++++-
 clang/lib/AST/ByteCode/Opcodes.td       |  7 ++++-
 clang/test/AST/ByteCode/fixed-point.cpp | 16 ++++++++++
 5 files changed, 72 insertions(+), 10 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index db5b21f5b1aacd..378a78fb1316e8 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -1547,7 +1547,6 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
     return this->emitEQFixedPoint(E);
   case BO_NE:
     return this->emitNEFixedPoint(E);
-#if 0
   case BO_LT:
     return this->emitLTFixedPoint(E);
   case BO_LE:
@@ -1556,9 +1555,14 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
     return this->emitGTFixedPoint(E);
   case BO_GE:
     return this->emitGEFixedPoint(E);
-#endif
   case BO_Add:
     return ConvertResult(this->emitAddFixedPoint(E));
+  case BO_Sub:
+    return ConvertResult(this->emitSubFixedPoint(E));
+  case BO_Mul:
+    return ConvertResult(this->emitMulFixedPoint(E));
+  case BO_Div:
+    return ConvertResult(this->emitDivFixedPoint(E));
 
   default:
     return this->emitInvalid(E);
diff --git a/clang/lib/AST/ByteCode/FixedPoint.h b/clang/lib/AST/ByteCode/FixedPoint.h
index c97a42401eaef3..b27ecfadd85146 100644
--- a/clang/lib/AST/ByteCode/FixedPoint.h
+++ b/clang/lib/AST/ByteCode/FixedPoint.h
@@ -58,9 +58,9 @@ class FixedPoint final {
   bool isNegative() const { return V.getValue().isNegative(); }
   bool isPositive() const { return V.getValue().isNonNegative(); }
   bool isMin() const {
-    return V.getValue() == APSInt::getMinValue(V.getSemantics().getWidth(),
-                                               !V.getSemantics().isSigned());
+    return V == llvm::APFixedPoint::getMin(V.getSemantics());
   }
+  bool isMinusOne() const { return V.isSigned() && V.getValue() == -1; }
 
   FixedPoint truncate(unsigned BitWidth) const { return *this; }
 
@@ -82,9 +82,12 @@ class FixedPoint final {
   }
 
   ComparisonCategoryResult compare(const FixedPoint &Other) const {
-    if (Other.V == V)
+    int c = V.compare(Other.V);
+    if (c == 0)
       return ComparisonCategoryResult::Equal;
-    return ComparisonCategoryResult::Unordered;
+    else if (c < 0)
+      return ComparisonCategoryResult::Less;
+    return ComparisonCategoryResult::Greater;
   }
 
   static bool neg(const FixedPoint &A, FixedPoint *R) {
@@ -101,16 +104,40 @@ class FixedPoint final {
   }
   static bool sub(const FixedPoint A, const FixedPoint B, unsigned Bits,
                   FixedPoint *R) {
-    return true;
+    bool Overflow = false;
+    *R = FixedPoint(A.V.sub(B.V, &Overflow));
+    return Overflow;
   }
   static bool mul(const FixedPoint A, const FixedPoint B, unsigned Bits,
                   FixedPoint *R) {
-    return true;
+    bool Overflow = false;
+    *R = FixedPoint(A.V.mul(B.V, &Overflow));
+    return Overflow;
   }
   static bool div(const FixedPoint A, const FixedPoint B, unsigned Bits,
                   FixedPoint *R) {
+    bool Overflow = false;
+    *R = FixedPoint(A.V.div(B.V, &Overflow));
+    return Overflow;
+  }
+  static bool rem(const FixedPoint A, const FixedPoint B, unsigned Bits,
+                  FixedPoint *R) {
+    llvm_unreachable("Rem doesn't exist for fixed point values");
+    return true;
+  }
+  static bool bitAnd(const FixedPoint A, const FixedPoint B, unsigned Bits,
+                     FixedPoint *R) {
+    return true;
+  }
+  static bool bitOr(const FixedPoint A, const FixedPoint B, unsigned Bits,
+                    FixedPoint *R) {
+    return true;
+  }
+  static bool bitXor(const FixedPoint A, const FixedPoint B, unsigned Bits,
+                     FixedPoint *R) {
     return true;
   }
+
   static bool increment(const FixedPoint &A, FixedPoint *R) { return true; }
   static bool decrement(const FixedPoint &A, FixedPoint *R) { return true; }
 };
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 4d9d460c75174f..62e4917d72b4d1 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -374,10 +374,13 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
     S.Stk.push<T>(Result);
     return true;
   }
-
   // If for some reason evaluation continues, use the truncated results.
   S.Stk.push<T>(Result);
 
+  // Short-circuit fixed-points here since the error handling is easier.
+  if constexpr (std::is_same_v<T, FixedPoint>)
+    return handleFixedPointOverflow(S, OpPC, Result);
+
   // Slow path - compute the result using another bit of precision.
   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
 
@@ -687,6 +690,13 @@ bool Div(InterpState &S, CodePtr OpPC) {
     S.Stk.push<T>(Result);
     return true;
   }
+
+  if constexpr (std::is_same_v<T, FixedPoint>) {
+    if (handleFixedPointOverflow(S, OpPC, Result)) {
+      S.Stk.push<T>(Result);
+      return true;
+    }
+  }
   return false;
 }
 
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 601ff95d973a27..e88335e67c19ff 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -84,6 +84,11 @@ def IntegerTypeClass : TypeClass {
                Uint32, Sint64, Uint64, IntAP, IntAPS];
 }
 
+def IntegerAndFixedTypeClass : TypeClass {
+  let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
+               Uint32, Sint64, Uint64, IntAP, IntAPS, FixedPoint];
+}
+
 def FixedSizeIntegralTypeClass : TypeClass {
   let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
                Uint32, Sint64, Uint64, Bool];
@@ -146,7 +151,7 @@ class FloatOpcode : Opcode {
 }
 
 class IntegerOpcode : Opcode {
-  let Types = [IntegerTypeClass];
+  let Types = [IntegerAndFixedTypeClass];
   let HasGroup = 1;
 }
 
diff --git a/clang/test/AST/ByteCode/fixed-point.cpp b/clang/test/AST/ByteCode/fixed-point.cpp
index 0c5b7c23e2bdef..48673d8be6f601 100644
--- a/clang/test/AST/ByteCode/fixed-point.cpp
+++ b/clang/test/AST/ByteCode/fixed-point.cpp
@@ -50,6 +50,13 @@ namespace BinOps {
 
   static_assert(A + 100000 == 14.0k); // both-error {{is not an integral constant expression}} \
                                       // both-note {{is outside the range of representable values}}
+
+  static_assert((A - A) == 0);
+  constexpr short _Accum mul_ovf1 = 255.0hk * 4.5hk; // both-error {{must be initialized by a constant expression}} \
+                                                     // both-note {{value 123.5 is outside the range of representable values of type 'short _Accum'}}
+  constexpr short _Accum div_ovf1 = 255.0hk / 0.5hk; // both-error {{must be initialized by a constant expression}} \
+                                                     // both-note {{value -2.0 is outside the range of representable values of type 'short _Accum'}}
+
 }
 
 namespace FixedPointCasts {
@@ -57,3 +64,12 @@ namespace FixedPointCasts {
   constexpr _Accum A = B;
   constexpr _Fract C = A;
 }
+
+namespace Cmp {
+  constexpr _Accum A = 13.0k;
+  constexpr _Accum B = 14.0k;
+  static_assert(B > A);
+  static_assert(B >= A);
+  static_assert(A < B);
+  static_assert(A <= B);
+}



More information about the cfe-commits mailing list