-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][bytecode] Implement fixed-point-to-int casts #110417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesAnd some cleanups around overflow handling. Full diff: https://github.com/llvm/llvm-project/pull/110417.diff 9 Files Affected:
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
|
And some cleanups around overflow handling.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
clang:frontend
Language frontend issues, e.g. anything involving "Sema"
clang
Clang issues not falling into any other category
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
And some cleanups around overflow handling.