diff --git a/clang/lib/AST/ByteCode/Boolean.h b/clang/lib/AST/ByteCode/Boolean.h index f1914ddb9970d..c568b557574e2 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 44195a3dc33de..db5b21f5b1aac 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -697,6 +697,11 @@ bool Compiler::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::VisitFixedPointBinOp(const BinaryOperator *E) { llvm_unreachable("unhandled binop opcode"); } +template +bool Compiler::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 bool Compiler::VisitImplicitValueInitExpr( const ImplicitValueInitExpr *E) { @@ -3805,7 +3829,7 @@ bool Compiler::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::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 T = classify(SubExpr->getType()); switch (E->getOpcode()) { diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 5349b184572b6..22e078f3fe546 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -133,6 +133,7 @@ class Compiler : public ConstStmtVisitor, 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 0fb4576c72126..c97a42401eaef 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 >> - 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 798e0f3e96fa0..fd9a256843a0e 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 89635f9c61e93..4d9d460c75174 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 +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(); 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(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(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(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(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(Result); return true; @@ -2401,6 +2365,20 @@ static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, return true; } +template ::T> +static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) { + const auto &Fixed = S.Stk.pop(); + + bool Overflow; + APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow); + + if (Overflow && !handleOverflow(S, OpPC, Int)) + return false; + + S.Stk.push(Int); + return true; +} + static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) { const auto &Ptr = S.Stk.peek(); diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index 2955bc5cf8084..601ff95d973a2 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 d515b7fe1594a..0c5b7c23e2bde 100644 --- a/clang/test/AST/ByteCode/fixed-point.cpp +++ b/clang/test/AST/ByteCode/fixed-point.cpp @@ -26,6 +26,12 @@ namespace IntToFixedPointCast { static_assert(sf == -1); } +namespace FixedPointToIntCasts { + constexpr _Accum A = -13.0k; + 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 e6e89ded534fe..889486e5eb806 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