[clang] [clang][bytecode] Implement fixed-point shifts (PR #110429)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sun Sep 29 09:40:17 PDT 2024


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

None

>From c3ae3ce5d129f9c2655ea291c57cc3009ed31b01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sun, 29 Sep 2024 18:38:52 +0200
Subject: [PATCH] [clang][bytecode] Implement fixed-point shifts

---
 clang/lib/AST/ByteCode/Compiler.cpp      |  4 +++
 clang/lib/AST/ByteCode/FixedPoint.h      | 17 +++++++++++
 clang/lib/AST/ByteCode/Interp.h          | 36 ++++++++++++++++++++++++
 clang/lib/AST/ByteCode/Opcodes.td        |  3 ++
 clang/test/Frontend/fixed_point_errors.c |  1 +
 5 files changed, 61 insertions(+)

diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 378a78fb1316e8..c24c4b6db2a5bf 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -1563,6 +1563,10 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
     return ConvertResult(this->emitMulFixedPoint(E));
   case BO_Div:
     return ConvertResult(this->emitDivFixedPoint(E));
+  case BO_Shl:
+    return ConvertResult(this->emitShiftFixedPoint(/*Left=*/true, E));
+  case BO_Shr:
+    return ConvertResult(this->emitShiftFixedPoint(/*Left=*/false, E));
 
   default:
     return this->emitInvalid(E);
diff --git a/clang/lib/AST/ByteCode/FixedPoint.h b/clang/lib/AST/ByteCode/FixedPoint.h
index b27ecfadd85146..ab8d6d7f02b52f 100644
--- a/clang/lib/AST/ByteCode/FixedPoint.h
+++ b/clang/lib/AST/ByteCode/FixedPoint.h
@@ -68,6 +68,7 @@ class FixedPoint final {
                          bool *Overflow) const {
     return FixedPoint(V.convert(Sem, Overflow));
   }
+  llvm::FixedPointSemantics getSemantics() const { return V.getSemantics(); }
 
   llvm::APFloat toFloat(const llvm::fltSemantics *Sem) const {
     return V.convertToFloat(*Sem);
@@ -120,6 +121,22 @@ class FixedPoint final {
     *R = FixedPoint(A.V.div(B.V, &Overflow));
     return Overflow;
   }
+
+  static bool shiftLeft(const FixedPoint A, const FixedPoint B, unsigned OpBits,
+                        FixedPoint *R) {
+    unsigned Amt = B.V.getValue().getLimitedValue(OpBits);
+    bool Overflow;
+    *R = FixedPoint(A.V.shl(Amt, &Overflow));
+    return Overflow;
+  }
+  static bool shiftRight(const FixedPoint A, const FixedPoint B,
+                         unsigned OpBits, FixedPoint *R) {
+    unsigned Amt = B.V.getValue().getLimitedValue(OpBits);
+    bool Overflow;
+    *R = FixedPoint(A.V.shr(Amt, &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");
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 62e4917d72b4d1..68c04587a4919e 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2579,6 +2579,42 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
   return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);
 }
 
+static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {
+  const auto &RHS = S.Stk.pop<FixedPoint>();
+  const auto &LHS = S.Stk.pop<FixedPoint>();
+  llvm::FixedPointSemantics LHSSema = LHS.getSemantics();
+
+  unsigned ShiftBitWidth =
+      LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;
+
+  // Embedded-C 4.1.6.2.2:
+  //   The right operand must be nonnegative and less than the total number
+  //   of (nonpadding) bits of the fixed-point operand ...
+  if (RHS.isNegative()) {
+    S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)
+        << RHS.toAPSInt();
+  } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(
+                 ShiftBitWidth)) != RHS.toAPSInt()) {
+    const Expr *E = S.Current->getExpr(OpPC);
+    S.CCEDiag(E, diag::note_constexpr_large_shift)
+        << RHS.toAPSInt() << E->getType() << ShiftBitWidth;
+  }
+
+  FixedPoint Result;
+  if (Left) {
+    if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&
+        !handleFixedPointOverflow(S, OpPC, Result))
+      return false;
+  } else {
+    if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&
+        !handleFixedPointOverflow(S, OpPC, Result))
+      return false;
+  }
+
+  S.Stk.push<FixedPoint>(Result);
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // NoRet
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index e88335e67c19ff..61b6f2e8daa2fb 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -698,6 +698,9 @@ def CastFixedPointIntegral : Opcode {
   let Types = [FixedSizeIntegralTypes];
   let HasGroup = 1;
 }
+def ShiftFixedPoint : Opcode {
+  let Args = [ArgBool];
+}
 
 def PtrPtrCast : Opcode {
   let Args = [ArgBool];
diff --git a/clang/test/Frontend/fixed_point_errors.c b/clang/test/Frontend/fixed_point_errors.c
index 6a711936f23975..3472f595089a14 100644
--- a/clang/test/Frontend/fixed_point_errors.c
+++ b/clang/test/Frontend/fixed_point_errors.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -verify -ffixed-point %s
+// RUN: %clang_cc1 -verify -ffixed-point %s -fexperimental-new-constant-interpreter
 
 /* We do not yet support long long. No recommended bit widths are given for this
  * size. */



More information about the cfe-commits mailing list