[clang] [clang][bytecode] Implement fixed-point-to-int casts (PR #110417)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 29 02:38:22 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
And some cleanups around overflow handling.
---
Full diff: https://github.com/llvm/llvm-project/pull/110417.diff
9 Files Affected:
- (modified) clang/lib/AST/ByteCode/Boolean.h (+1)
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+27-1)
- (modified) clang/lib/AST/ByteCode/Compiler.h (+1)
- (modified) clang/lib/AST/ByteCode/FixedPoint.h (+13-6)
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+13)
- (modified) clang/lib/AST/ByteCode/Interp.h (+38-60)
- (modified) clang/lib/AST/ByteCode/Opcodes.td (+4)
- (modified) clang/test/AST/ByteCode/fixed-point.cpp (+5)
- (modified) clang/test/Frontend/fixed_point_conversions_const.c (+3)
``````````diff
diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h
index f1914ddb9970dc..c568b557574e2b 100644
--- a/clang/lib/AST/ByteCode/Boolean.h
+++ b/clang/lib/AST/ByteCode/Boolean.h
@@ -30,6 +30,7 @@ class Boolean final {
public:
/// Zero-initializes a boolean.
Boolean() : V(false) {}
+ Boolean(const llvm::APSInt &I) : V(!I.isZero()) {}
explicit Boolean(bool V) : V(V) {}
bool operator<(Boolean RHS) const { return V < RHS.V; }
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 44195a3dc33de4..db5b21f5b1aacd 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -697,6 +697,11 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
const auto *TargetSemantics = &Ctx.getFloatSemantics(CE->getType());
return this->emitCastFixedPointFloating(TargetSemantics, CE);
}
+ case CK_FixedPointToIntegral: {
+ if (!this->visit(SubExpr))
+ return false;
+ return this->emitCastFixedPointIntegral(classifyPrim(CE->getType()), CE);
+ }
case CK_FixedPointCast: {
if (!this->visit(SubExpr))
return false;
@@ -1562,6 +1567,25 @@ bool Compiler<Emitter>::VisitFixedPointBinOp(const BinaryOperator *E) {
llvm_unreachable("unhandled binop opcode");
}
+template <class Emitter>
+bool Compiler<Emitter>::VisitFixedPointUnaryOperator(const UnaryOperator *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ assert(SubExpr->getType()->isFixedPointType());
+
+ switch (E->getOpcode()) {
+ case UO_Plus:
+ return this->delegate(SubExpr);
+ case UO_Minus:
+ if (!this->visit(SubExpr))
+ return false;
+ return this->emitNegFixedPoint(E);
+ default:
+ return false;
+ }
+
+ llvm_unreachable("Unhandled unary opcode");
+}
+
template <class Emitter>
bool Compiler<Emitter>::VisitImplicitValueInitExpr(
const ImplicitValueInitExpr *E) {
@@ -3805,7 +3829,7 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
case PT_FixedPoint: {
auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType());
- return this->emitConstFixedPoint(FixedPoint::Zero(Sem), E);
+ return this->emitConstFixedPoint(FixedPoint::zero(Sem), E);
}
llvm_unreachable("Implement");
}
@@ -5471,6 +5495,8 @@ bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
return this->VisitComplexUnaryOperator(E);
if (SubExpr->getType()->isVectorType())
return this->VisitVectorUnaryOperator(E);
+ if (SubExpr->getType()->isFixedPointType())
+ return this->VisitFixedPointUnaryOperator(E);
std::optional<PrimType> T = classify(SubExpr->getType());
switch (E->getOpcode()) {
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 5349b184572b6e..22e078f3fe546f 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -133,6 +133,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
bool VisitComplexBinOp(const BinaryOperator *E);
bool VisitVectorBinOp(const BinaryOperator *E);
bool VisitFixedPointBinOp(const BinaryOperator *E);
+ bool VisitFixedPointUnaryOperator(const UnaryOperator *E);
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
bool VisitCallExpr(const CallExpr *E);
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinID);
diff --git a/clang/lib/AST/ByteCode/FixedPoint.h b/clang/lib/AST/ByteCode/FixedPoint.h
index 0fb4576c721266..c97a42401eaef3 100644
--- a/clang/lib/AST/ByteCode/FixedPoint.h
+++ b/clang/lib/AST/ByteCode/FixedPoint.h
@@ -33,17 +33,20 @@ class FixedPoint final {
: V(APInt(0, 0ULL, false),
llvm::FixedPointSemantics(0, 0, false, false, false)) {}
- static FixedPoint Zero(llvm::FixedPointSemantics Sem) {
+ static FixedPoint zero(llvm::FixedPointSemantics Sem) {
return FixedPoint(APInt(Sem.getWidth(), 0ULL, Sem.isSigned()), Sem);
}
- operator bool() const { return V.getBoolValue(); }
- template <typename Ty, typename = std::enable_if_t<std::is_integral_v<Ty>>>
- explicit operator Ty() const {
- // FIXME
- return 0;
+ static FixedPoint from(const APSInt &I, llvm::FixedPointSemantics Sem,
+ bool *Overflow) {
+ return FixedPoint(llvm::APFixedPoint::getFromIntValue(I, Sem, Overflow));
+ }
+ static FixedPoint from(const llvm::APFloat &I, llvm::FixedPointSemantics Sem,
+ bool *Overflow) {
+ return FixedPoint(llvm::APFixedPoint::getFromFloatValue(I, Sem, Overflow));
}
+ operator bool() const { return V.getBoolValue(); }
void print(llvm::raw_ostream &OS) const { OS << V; }
APValue toAPValue(const ASTContext &) const { return APValue(V); }
@@ -70,6 +73,10 @@ class FixedPoint final {
return V.convertToFloat(*Sem);
}
+ llvm::APSInt toInt(unsigned BitWidth, bool Signed, bool *Overflow) const {
+ return V.convertToInt(BitWidth, Signed, Overflow);
+ }
+
std::string toDiagnosticString(const ASTContext &Ctx) const {
return V.toString();
}
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 798e0f3e96fa09..fd9a256843a0ec 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -1393,6 +1393,19 @@ bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
return false;
}
+bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
+ const FixedPoint &FP) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ if (S.checkingForUndefinedBehavior()) {
+ S.getASTContext().getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << FP.toDiagnosticString(S.getASTContext()) << E->getType();
+ }
+ S.CCEDiag(E, diag::note_constexpr_overflow)
+ << FP.toDiagnosticString(S.getASTContext()) << E->getType();
+ return S.noteUndefinedBehavior();
+}
+
bool Interpret(InterpState &S, APValue &Result) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 89635f9c61e932..4d9d460c75174f 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -162,6 +162,15 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
const CallExpr *CE);
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
+template <typename T>
+static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();
+ return S.noteUndefinedBehavior();
+}
+bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
+ const FixedPoint &FP);
+
enum class ShiftDir { Left, Right };
/// Checks if the shift operation is legal.
@@ -385,13 +394,10 @@ bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
<< Trunc << Type << E->getSourceRange();
}
- S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
-
- if (!S.noteUndefinedBehavior()) {
+ if (!handleOverflow(S, OpPC, Value)) {
S.Stk.pop<T>();
return false;
}
-
return true;
}
@@ -741,8 +747,7 @@ bool Neg(InterpState &S, CodePtr OpPC) {
return true;
}
- S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;
- return S.noteUndefinedBehavior();
+ return handleOverflow(S, OpPC, NegatedValue);
}
enum class PushVal : bool {
@@ -804,8 +809,7 @@ bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}
- S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
- return S.noteUndefinedBehavior();
+ return handleOverflow(S, OpPC, APResult);
}
/// 1) Pops a pointer from the stack
@@ -2170,18 +2174,8 @@ inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {
bool Overflow;
FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);
- if (Overflow) {
- const Expr *E = S.Current->getExpr(OpPC);
- if (S.checkingForUndefinedBehavior()) {
- S.getASTContext().getDiagnostics().Report(
- E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << Result.toDiagnosticString(S.getASTContext()) << E->getType();
- }
- S.CCEDiag(E, diag::note_constexpr_overflow)
- << Result.toDiagnosticString(S.getASTContext()) << E->getType();
- if (!S.noteUndefinedBehavior())
- return false;
- }
+ if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
+ return false;
S.Stk.push<FixedPoint>(Result);
return true;
@@ -2257,13 +2251,8 @@ static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,
auto Status = F.convertToInteger(Result);
// Float-to-Integral overflow check.
- if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
- const Expr *E = S.Current->getExpr(OpPC);
- QualType Type = E->getType();
-
- S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
- return S.noteUndefinedBehavior();
- }
+ if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
+ return handleOverflow(S, OpPC, F.getAPFloat());
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
@@ -2278,13 +2267,8 @@ static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,
auto Status = F.convertToInteger(Result);
// Float-to-Integral overflow check.
- if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {
- const Expr *E = S.Current->getExpr(OpPC);
- QualType Type = E->getType();
-
- S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;
- return S.noteUndefinedBehavior();
- }
+ if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())
+ return handleOverflow(S, OpPC, F.getAPFloat());
FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);
S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));
@@ -2347,20 +2331,10 @@ static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,
std::memcpy(&Sem, &FPS, sizeof(Sem));
bool Overflow;
- llvm::APFixedPoint Result =
- llvm::APFixedPoint::getFromIntValue(Int.toAPSInt(), Sem, &Overflow);
+ FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);
- if (Overflow) {
- const Expr *E = S.Current->getExpr(OpPC);
- if (S.checkingForUndefinedBehavior()) {
- S.getASTContext().getDiagnostics().Report(
- E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
- }
- S.CCEDiag(E, diag::note_constexpr_overflow) << Result << E->getType();
- if (!S.noteUndefinedBehavior())
- return false;
- }
+ if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
+ return false;
S.Stk.push<FixedPoint>(Result);
return true;
@@ -2374,20 +2348,10 @@ static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,
std::memcpy(&Sem, &FPS, sizeof(Sem));
bool Overflow;
- llvm::APFixedPoint Result =
- llvm::APFixedPoint::getFromFloatValue(Float.getAPFloat(), Sem, &Overflow);
+ FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);
- if (Overflow) {
- const Expr *E = S.Current->getExpr(OpPC);
- if (S.checkingForUndefinedBehavior()) {
- S.getASTContext().getDiagnostics().Report(
- E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
- }
- S.CCEDiag(E, diag::note_constexpr_overflow) << Result << E->getType();
- if (!S.noteUndefinedBehavior())
- return false;
- }
+ if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))
+ return false;
S.Stk.push<FixedPoint>(Result);
return true;
@@ -2401,6 +2365,20 @@ static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,
return true;
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {
+ const auto &Fixed = S.Stk.pop<FixedPoint>();
+
+ bool Overflow;
+ APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);
+
+ if (Overflow && !handleOverflow(S, OpPC, Int))
+ return false;
+
+ S.Stk.push<T>(Int);
+ return true;
+}
+
static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
const auto &Ptr = S.Stk.peek<Pointer>();
diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td
index 2955bc5cf8084c..601ff95d973a27 100644
--- a/clang/lib/AST/ByteCode/Opcodes.td
+++ b/clang/lib/AST/ByteCode/Opcodes.td
@@ -689,6 +689,10 @@ def CastFloatingFixedPoint : Opcode {
def CastFixedPointFloating : Opcode {
let Args = [ArgFltSemantics];
}
+def CastFixedPointIntegral : Opcode {
+ let Types = [FixedSizeIntegralTypes];
+ let HasGroup = 1;
+}
def PtrPtrCast : Opcode {
let Args = [ArgBool];
diff --git a/clang/test/AST/ByteCode/fixed-point.cpp b/clang/test/AST/ByteCode/fixed-point.cpp
index d515b7fe1594a9..31c4008fd4df12 100644
--- a/clang/test/AST/ByteCode/fixed-point.cpp
+++ b/clang/test/AST/ByteCode/fixed-point.cpp
@@ -26,6 +26,11 @@ namespace IntToFixedPointCast {
static_assert(sf == -1);
}
+namespace FixedPointToIntCasts {
+ constexpr int I = A;
+ static_assert(I == -13);
+}
+
namespace FloatToFixedPointCast {
constexpr _Fract sf = 1.0; // both-error {{must be initialized by a constant expression}} \
// both-note {{outside the range of representable values of type 'const _Fract'}}
diff --git a/clang/test/Frontend/fixed_point_conversions_const.c b/clang/test/Frontend/fixed_point_conversions_const.c
index e6e89ded534fe1..889486e5eb8066 100644
--- a/clang/test/Frontend/fixed_point_conversions_const.c
+++ b/clang/test/Frontend/fixed_point_conversions_const.c
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED
// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,SIGNED
+// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,UNSIGNED
+
// Between different fixed point types
short _Accum sa_const = 2.5hk;
// CHECK-DAG: @sa_const = {{.*}}global i16 320, align 2
``````````
</details>
https://github.com/llvm/llvm-project/pull/110417
More information about the cfe-commits
mailing list