From db01c3adc6f921a27e2bd39847140c401860aa56 Mon Sep 17 00:00:00 2001 From: Leonard Chan Date: Wed, 20 Jun 2018 17:19:40 +0000 Subject: [PATCH] [Fixed Point Arithmetic] Fixed Point Precision Bits and Fixed Point Literals This diff includes the logic for setting the precision bits for each primary fixed point type in the target info and logic for initializing a fixed point literal. Fixed point literals are declared using the suffixes ``` hr: short _Fract uhr: unsigned short _Fract r: _Fract ur: unsigned _Fract lr: long _Fract ulr: unsigned long _Fract hk: short _Accum uhk: unsigned short _Accum k: _Accum uk: unsigned _Accum ``` Errors are also thrown for illegal literal values ``` unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} ``` Differential Revision: https://reviews.llvm.org/D46915 llvm-svn: 335148 --- clang/include/clang-c/Index.h | 7 +- clang/include/clang/AST/ASTContext.h | 3 + clang/include/clang/AST/Expr.h | 41 ++++++ clang/include/clang/AST/RecursiveASTVisitor.h | 1 + clang/include/clang/AST/Type.h | 7 + clang/include/clang/Basic/DiagnosticCommonKinds.td | 2 + clang/include/clang/Basic/LangOptions.def | 2 + clang/include/clang/Basic/StmtNodes.td | 1 + clang/include/clang/Basic/TargetInfo.h | 103 +++++++++++++ clang/include/clang/Driver/Options.td | 4 + clang/include/clang/Lex/LiteralSupport.h | 17 ++- clang/lib/AST/ASTContext.cpp | 89 +++++++++++ clang/lib/AST/ASTDumper.cpp | 8 + clang/lib/AST/Expr.cpp | 31 ++++ clang/lib/AST/ExprClassification.cpp | 1 + clang/lib/AST/ExprConstant.cpp | 101 +++++++++++++ clang/lib/AST/ItaniumMangle.cpp | 1 + clang/lib/AST/StmtPrinter.cpp | 22 +++ clang/lib/AST/StmtProfile.cpp | 6 + clang/lib/AST/Type.cpp | 16 ++ clang/lib/Basic/TargetInfo.cpp | 83 ++++++++++- clang/lib/Basic/Targets.cpp | 2 + clang/lib/CodeGen/CGExprAgg.cpp | 4 +- clang/lib/CodeGen/CGExprScalar.cpp | 3 + clang/lib/Driver/ToolChains/Clang.cpp | 5 + clang/lib/Frontend/CompilerInvocation.cpp | 4 + clang/lib/Lex/LiteralSupport.cpp | 153 ++++++++++++++++++- clang/lib/Sema/SemaExceptionSpec.cpp | 1 + clang/lib/Sema/SemaExpr.cpp | 49 ++++++- clang/lib/Sema/TreeTransform.h | 6 + clang/lib/Serialization/ASTReaderStmt.cpp | 6 + clang/lib/Serialization/ASTWriterStmt.cpp | 7 + clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + clang/test/Frontend/fixed_point.c | 162 ++++++++++++++++++++- clang/test/Frontend/fixed_point_bit_widths.c | 72 ++++----- clang/test/Frontend/fixed_point_declarations.c | 113 ++++++++++++++ clang/test/Frontend/fixed_point_errors.c | 57 ++++++++ clang/test/Frontend/fixed_point_same_fbits.c | 28 ++++ clang/tools/libclang/CIndex.cpp | 2 + clang/tools/libclang/CXCursor.cpp | 4 + 40 files changed, 1175 insertions(+), 50 deletions(-) create mode 100644 clang/test/Frontend/fixed_point_declarations.c create mode 100644 clang/test/Frontend/fixed_point_same_fbits.c diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 4afcd2b..0ad9001 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2170,7 +2170,12 @@ enum CXCursorKind { */ CXCursor_ObjCAvailabilityCheckExpr = 148, - CXCursor_LastExpr = CXCursor_ObjCAvailabilityCheckExpr, + /** + * Fixed point literal + */ + CXCursor_FixedPointLiteral = 149, + + CXCursor_LastExpr = CXCursor_FixedPointLiteral, /* Statements */ CXCursor_FirstStmt = 200, diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a488ff0..ac317a7 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1947,6 +1947,9 @@ public: return getQualifiedType(type.getUnqualifiedType(), Qs); } + unsigned char getFixedPointScale(QualType Ty) const; + unsigned char getFixedPointIBits(QualType Ty) const; + DeclarationNameInfo getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const; diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index c51ba8d..d71fda7 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1351,6 +1351,47 @@ public: } }; +class FixedPointLiteral : public Expr, public APIntStorage { + SourceLocation Loc; + unsigned Scale; + + /// \brief Construct an empty integer literal. + explicit FixedPointLiteral(EmptyShell Empty) + : Expr(FixedPointLiteralClass, Empty) {} + + public: + FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type, + SourceLocation l, unsigned Scale); + + // Store the int as is without any bit shifting. + static FixedPointLiteral *CreateFromRawInt(const ASTContext &C, + const llvm::APInt &V, + QualType type, SourceLocation l, + unsigned Scale); + + SourceLocation getLocStart() const LLVM_READONLY { return Loc; } + SourceLocation getLocEnd() const LLVM_READONLY { return Loc; } + + /// \brief Retrieve the location of the literal. + SourceLocation getLocation() const { return Loc; } + + void setLocation(SourceLocation Location) { Loc = Location; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FixedPointLiteralClass; + } + + std::string getValueAsString(unsigned Radix) const; + + // Iterators + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + class CharacterLiteral : public Expr { public: enum CharacterKind { diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1858de8..3e6090d 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2585,6 +2585,7 @@ DEF_TRAVERSE_STMT(CoyieldExpr, { // These literals (all of them) do not need any action. DEF_TRAVERSE_STMT(IntegerLiteral, {}) +DEF_TRAVERSE_STMT(FixedPointLiteral, {}) DEF_TRAVERSE_STMT(CharacterLiteral, {}) DEF_TRAVERSE_STMT(FloatingLiteral, {}) DEF_TRAVERSE_STMT(ImaginaryLiteral, {}) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index ff26757..5e1fc37 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -30,6 +30,7 @@ #include "clang/Basic/Specifiers.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/None.h" @@ -6546,6 +6547,12 @@ QualType DecayedType::getPointeeType() const { return cast(Decayed)->getPointeeType(); } +// Get the decimal string representation of a fixed point type, represented +// as a scaled integer. +void FixedPointValueToString(SmallVectorImpl &Str, + const llvm::APSInt &Val, + unsigned Scale, unsigned Radix); + } // namespace clang #endif // LLVM_CLANG_AST_TYPE_H diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 93f2623..61a7354 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -168,6 +168,8 @@ def ext_clang_enable_if : Extension<"'enable_if' is a clang extension">, InGroup; def ext_clang_diagnose_if : Extension<"'diagnose_if' is a clang extension">, InGroup; +def err_too_large_for_fixed_point : Error< + "this value is too large for this fixed point type">; def err_fixed_point_not_enabled : Error<"compile with " "'-ffixed-point' to enable fixed point types">; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index f9246bd..d7d66be 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -305,6 +305,8 @@ ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest, COMPATIBLE_VALUE_LANGOPT(FunctionAlignment, 5, 0, "Default alignment for functions") LANGOPT(FixedPoint, 1, 0, "fixed point types") +LANGOPT(SameFBits, 1, 0, + "unsigned and signed fixed point type having the same number of fractional bits") #undef LANGOPT #undef COMPATIBLE_LANGOPT diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 0d21845..506da07 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -57,6 +57,7 @@ def Expr : Stmt<1>; def PredefinedExpr : DStmt; def DeclRefExpr : DStmt; def IntegerLiteral : DStmt; +def FixedPointLiteral : DStmt; def FloatingLiteral : DStmt; def ImaginaryLiteral : DStmt; def StringLiteral : DStmt; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 24eb67a..9bb4db7 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -74,12 +74,32 @@ protected: unsigned char LargeArrayMinWidth, LargeArrayAlign; unsigned char LongWidth, LongAlign; unsigned char LongLongWidth, LongLongAlign; + + // Fixed point bit widths unsigned char ShortAccumWidth, ShortAccumAlign; unsigned char AccumWidth, AccumAlign; unsigned char LongAccumWidth, LongAccumAlign; unsigned char ShortFractWidth, ShortFractAlign; unsigned char FractWidth, FractAlign; unsigned char LongFractWidth, LongFractAlign; + + // If true, unsigned fixed point types have the same number of fractional bits + // as their signed counterparts. Otherwise, unsigned fixed point types have + // one more fractional bit than its corresponding signed type. This is false + // by default. + bool SameFBits; + + // Fixed point integral and fractional bit sizes + // Saturated types share the same integral/fractional bits as their + // corresponding unsaturated types. + // For simplicity, the fractional bits in a _Fract type will be one less the + // width of that _Fract type. This leaves all signed _Fract types having no + // padding and unsigned _Fract types will only have 1 bit of padding after the + // sign if SameFBits is set. + unsigned char ShortAccumScale; + unsigned char AccumScale; + unsigned char LongAccumScale; + unsigned char SuitableAlign; unsigned char DefaultAlignForAttributeAligned; unsigned char MinGlobalAlign; @@ -394,6 +414,84 @@ public: unsigned getLongFractWidth() const { return LongFractWidth; } unsigned getLongFractAlign() const { return LongFractAlign; } + /// getShortAccumScale/IBits - Return the number of fractional/integral bits + /// in a 'signed short _Accum' type. + unsigned getShortAccumScale() const { return ShortAccumScale; } + unsigned getShortAccumIBits() const { + return ShortAccumWidth - ShortAccumScale - 1; + } + + /// getAccumScale/IBits - Return the number of fractional/integral bits + /// in a 'signed _Accum' type. + unsigned getAccumScale() const { return AccumScale; } + unsigned getAccumIBits() const { return AccumWidth - AccumScale - 1; } + + /// getLongAccumScale/IBits - Return the number of fractional/integral bits + /// in a 'signed long _Accum' type. + unsigned getLongAccumScale() const { return LongAccumScale; } + unsigned getLongAccumIBits() const { + return LongAccumWidth - LongAccumScale - 1; + } + + /// getUnsignedShortAccumScale/IBits - Return the number of + /// fractional/integral bits in a 'unsigned short _Accum' type. + unsigned getUnsignedShortAccumScale() const { + return SameFBits ? ShortAccumScale : ShortAccumScale + 1; + } + unsigned getUnsignedShortAccumIBits() const { + return SameFBits ? getShortAccumIBits() + : ShortAccumWidth - getUnsignedShortAccumScale(); + } + + /// getUnsignedAccumScale/IBits - Return the number of fractional/integral + /// bits in a 'unsigned _Accum' type. + unsigned getUnsignedAccumScale() const { + return SameFBits ? AccumScale : AccumScale + 1; + } + unsigned getUnsignedAccumIBits() const { + return SameFBits ? getAccumIBits() : AccumWidth - getUnsignedAccumScale(); + } + + /// getUnsignedLongAccumScale/IBits - Return the number of fractional/integral + /// bits in a 'unsigned long _Accum' type. + unsigned getUnsignedLongAccumScale() const { + return SameFBits ? LongAccumScale : LongAccumScale + 1; + } + unsigned getUnsignedLongAccumIBits() const { + return SameFBits ? getLongAccumIBits() + : LongAccumWidth - getUnsignedLongAccumScale(); + } + + /// getShortFractScale - Return the number of fractional bits + /// in a 'signed short _Fract' type. + unsigned getShortFractScale() const { return ShortFractWidth - 1; } + + /// getFractScale - Return the number of fractional bits + /// in a 'signed _Fract' type. + unsigned getFractScale() const { return FractWidth - 1; } + + /// getLongFractScale - Return the number of fractional bits + /// in a 'signed long _Fract' type. + unsigned getLongFractScale() const { return LongFractWidth - 1; } + + /// getUnsignedShortFractScale - Return the number of fractional bits + /// in a 'unsigned short _Fract' type. + unsigned getUnsignedShortFractScale() const { + return SameFBits ? getShortFractScale() : getShortFractScale() + 1; + } + + /// getUnsignedFractScale - Return the number of fractional bits + /// in a 'unsigned _Fract' type. + unsigned getUnsignedFractScale() const { + return SameFBits ? getFractScale() : getFractScale() + 1; + } + + /// getUnsignedLongFractScale - Return the number of fractional bits + /// in a 'unsigned long _Fract' type. + unsigned getUnsignedLongFractScale() const { + return SameFBits ? getLongFractScale() : getLongFractScale() + 1; + } + /// Determine whether the __int128 type is supported on this target. virtual bool hasInt128Type() const { return (getPointerWidth(0) >= 64) || getTargetOpts().ForceEnableInt128; @@ -1189,6 +1287,11 @@ protected: virtual ArrayRef getGCCAddlRegNames() const { return None; } + + private: + // Assert the values for the fractional and integral bits for each fixed point + // type follow the restrictions given in clause 6.2.6.3 of N1169. + void CheckFixedPointBits() const; }; } // end namespace clang diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index cd02a5a..089a9b3 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -893,6 +893,10 @@ def ffixed_point : Flag<["-"], "ffixed-point">, Group, Flags<[CC1Option]>, HelpText<"Enable fixed point types">; def fno_fixed_point : Flag<["-"], "fno-fixed-point">, Group, HelpText<"Disable fixed point types">; +def fsame_fbits : Flag<["-"], "fsame-fbits">, Group, + Flags<[CC1Option]>, + HelpText<"Force each unsigned fixed point type to have the same number of fractional bits as its corresponding signed type">; +def fno_same_fbits : Flag<["-"], "fno-same-fbits">, Group; // Begin sanitizer flags. These should all be core options exposed in all driver // modes. diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index 4f32fa8..1b6bf6b 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -50,7 +50,7 @@ class NumericLiteralParser { unsigned radix; - bool saw_exponent, saw_period, saw_ud_suffix; + bool saw_exponent, saw_period, saw_ud_suffix, saw_fixed_point_suffix; SmallString<32> UDSuffixBuf; @@ -69,11 +69,16 @@ public: bool isFloat128 : 1; // 1.0q uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. + bool isFract : 1; // 1.0hr/r/lr/uhr/ur/ulr + bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk + + bool isFixedPointLiteral() const { return saw_fixed_point_suffix; } + bool isIntegerLiteral() const { - return !saw_period && !saw_exponent; + return !saw_period && !saw_exponent && !isFixedPointLiteral(); } bool isFloatingLiteral() const { - return saw_period || saw_exponent; + return (saw_period || saw_exponent) && !isFixedPointLiteral(); } bool hasUDSuffix() const { @@ -105,6 +110,12 @@ public: /// literal exactly, and false otherwise. llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result); + /// GetFixedPointValue - Convert this numeric literal value into a + /// scaled integer that represents this value. Returns true if an overflow + /// occurred when calculating the integral part of the scaled integer or + /// calculating the digit sequence of the exponent. + bool GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale); + private: void ParseNumberStartingWithZero(SourceLocation TokLoc); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index de32de5..96b7b56 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10162,3 +10162,92 @@ clang::LazyGenerationalUpdatePtr< clang::LazyGenerationalUpdatePtr< const Decl *, Decl *, &ExternalASTSource::CompleteRedeclChain>::makeValue( const clang::ASTContext &Ctx, Decl *Value); + +unsigned char ASTContext::getFixedPointScale(QualType Ty) const { + assert(Ty->isFixedPointType()); + + const auto *BT = Ty->getAs(); + const TargetInfo &Target = getTargetInfo(); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + case BuiltinType::SatShortAccum: + return Target.getShortAccumScale(); + case BuiltinType::Accum: + case BuiltinType::SatAccum: + return Target.getAccumScale(); + case BuiltinType::LongAccum: + case BuiltinType::SatLongAccum: + return Target.getLongAccumScale(); + case BuiltinType::UShortAccum: + case BuiltinType::SatUShortAccum: + return Target.getUnsignedShortAccumScale(); + case BuiltinType::UAccum: + case BuiltinType::SatUAccum: + return Target.getUnsignedAccumScale(); + case BuiltinType::ULongAccum: + case BuiltinType::SatULongAccum: + return Target.getUnsignedLongAccumScale(); + case BuiltinType::ShortFract: + case BuiltinType::SatShortFract: + return Target.getShortFractScale(); + case BuiltinType::Fract: + case BuiltinType::SatFract: + return Target.getFractScale(); + case BuiltinType::LongFract: + case BuiltinType::SatLongFract: + return Target.getLongFractScale(); + case BuiltinType::UShortFract: + case BuiltinType::SatUShortFract: + return Target.getUnsignedShortFractScale(); + case BuiltinType::UFract: + case BuiltinType::SatUFract: + return Target.getUnsignedFractScale(); + case BuiltinType::ULongFract: + case BuiltinType::SatULongFract: + return Target.getUnsignedLongFractScale(); + } +} + +unsigned char ASTContext::getFixedPointIBits(QualType Ty) const { + assert(Ty->isFixedPointType()); + + const auto *BT = Ty->getAs(); + const TargetInfo &Target = getTargetInfo(); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + case BuiltinType::SatShortAccum: + return Target.getShortAccumIBits(); + case BuiltinType::Accum: + case BuiltinType::SatAccum: + return Target.getAccumIBits(); + case BuiltinType::LongAccum: + case BuiltinType::SatLongAccum: + return Target.getLongAccumIBits(); + case BuiltinType::UShortAccum: + case BuiltinType::SatUShortAccum: + return Target.getUnsignedShortAccumIBits(); + case BuiltinType::UAccum: + case BuiltinType::SatUAccum: + return Target.getUnsignedAccumIBits(); + case BuiltinType::ULongAccum: + case BuiltinType::SatULongAccum: + return Target.getUnsignedLongAccumIBits(); + case BuiltinType::ShortFract: + case BuiltinType::SatShortFract: + case BuiltinType::Fract: + case BuiltinType::SatFract: + case BuiltinType::LongFract: + case BuiltinType::SatLongFract: + case BuiltinType::UShortFract: + case BuiltinType::SatUShortFract: + case BuiltinType::UFract: + case BuiltinType::SatUFract: + case BuiltinType::ULongFract: + case BuiltinType::SatULongFract: + return 0; + } +} diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index cf512b9..6d9f240 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -525,6 +525,7 @@ namespace { void VisitPredefinedExpr(const PredefinedExpr *Node); void VisitCharacterLiteral(const CharacterLiteral *Node); void VisitIntegerLiteral(const IntegerLiteral *Node); + void VisitFixedPointLiteral(const FixedPointLiteral *Node); void VisitFloatingLiteral(const FloatingLiteral *Node); void VisitStringLiteral(const StringLiteral *Str); void VisitInitListExpr(const InitListExpr *ILE); @@ -2177,6 +2178,13 @@ void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) { OS << " " << Node->getValue().toString(10, isSigned); } +void ASTDumper::VisitFixedPointLiteral(const FixedPointLiteral *Node) { + VisitExpr(Node); + + ColorScope Color(*this, ValueColor); + OS << " " << Node->getValueAsString(/*Radix=*/10); +} + void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) { VisitExpr(Node); ColorScope Color(*this, ValueColor); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index b2593ef..47cf026 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -755,6 +755,36 @@ IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) { return new (C) IntegerLiteral(Empty); } +FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l, + unsigned Scale) + : Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false, false), + Loc(l), Scale(Scale) { + assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral"); + assert(V.getBitWidth() == C.getTypeInfo(type).Width && + "Fixed point type is not the correct size for constant."); + setValue(C, V); +} + +FixedPointLiteral *FixedPointLiteral::CreateFromRawInt(const ASTContext &C, + const llvm::APInt &V, + QualType type, + SourceLocation l, + unsigned Scale) { + return new (C) FixedPointLiteral(C, V, type, l, Scale); +} + +std::string FixedPointLiteral::getValueAsString(unsigned Radix) const { + // Currently the longest decimal number that can be printed is the max for an + // unsigned long _Accum: 4294967295.99999999976716935634613037109375 + // which is 43 characters. + SmallString<64> S; + FixedPointValueToString( + S, llvm::APSInt::getUnsigned(getValue().getZExtValue()), Scale, Radix); + return S.str(); +} + FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, @@ -2991,6 +3021,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ObjCIvarRefExprClass: case PredefinedExprClass: case IntegerLiteralClass: + case FixedPointLiteralClass: case FloatingLiteralClass: case ImaginaryLiteralClass: case StringLiteralClass: diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 297267b..c5b3b36 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -161,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ShuffleVectorExprClass: case Expr::ConvertVectorExprClass: case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::AddrLabelExprClass: case Expr::CXXDeleteExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2079f90..c700da6 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7220,6 +7220,73 @@ public: // FIXME: Missing: array subscript of vector, member of vector }; + +class FixedPointExprEvaluator + : public ExprEvaluatorBase { + APValue &Result; + + public: + FixedPointExprEvaluator(EvalInfo &info, APValue &result) + : ExprEvaluatorBaseTy(info), Result(result) {} + + bool Success(const llvm::APSInt &SI, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(SI.isSigned() == E->getType()->isSignedFixedPointType() && + "Invalid evaluation result."); + assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(SI); + return true; + } + bool Success(const llvm::APSInt &SI, const Expr *E) { + return Success(SI, E, Result); + } + + bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(APSInt(I)); + Result.getInt().setIsUnsigned(E->getType()->isUnsignedFixedPointType()); + return true; + } + bool Success(const llvm::APInt &I, const Expr *E) { + return Success(I, E, Result); + } + + bool Success(uint64_t Value, const Expr *E, APValue &Result) { + assert(E->getType()->isFixedPointType() && "Invalid evaluation result."); + Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); + return true; + } + bool Success(uint64_t Value, const Expr *E) { + return Success(Value, E, Result); + } + + bool Success(CharUnits Size, const Expr *E) { + return Success(Size.getQuantity(), E); + } + + bool Success(const APValue &V, const Expr *E) { + if (V.isLValue() || V.isAddrLabelDiff()) { + Result = V; + return true; + } + return Success(V.getInt(), E); + } + + bool ZeroInitialization(const Expr *E) { return Success(0, E); } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + bool VisitFixedPointLiteral(const FixedPointLiteral *E) { + return Success(E->getValue(), E); + } + + bool VisitUnaryOperator(const UnaryOperator *E); +}; } // end anonymous namespace /// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and @@ -9460,6 +9527,37 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { return Success(E->getValue(), E); } +bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + switch (E->getOpcode()) { + default: + // Invalid unary operators + return Error(E); + case UO_Plus: + // The result is just the value. + return Visit(E->getSubExpr()); + case UO_Minus: { + if (!Visit(E->getSubExpr())) return false; + if (!Result.isInt()) return Error(E); + const APSInt &Value = Result.getInt(); + if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) { + SmallString<64> S; + FixedPointValueToString(S, Value, + Info.Ctx.getTypeInfo(E->getType()).Width, + /*Radix=*/10); + Info.CCEDiag(E, diag::note_constexpr_overflow) << S << E->getType(); + if (Info.noteUndefinedBehavior()) return false; + } + return Success(-Value, E); + } + case UO_LNot: { + bool bres; + if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info)) + return false; + return Success(!bres, E); + } + } +} + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -10311,6 +10409,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { if (!EvaluateComplex(E, C, Info)) return false; C.moveInto(Result); + } else if (T->isFixedPointType()) { + if (!FixedPointExprEvaluator(Info, Result).Visit(E)) return false; } else if (T->isMemberPointerType()) { MemberPtr P; if (!EvaluateMemberPointer(E, P, Info)) @@ -10759,6 +10859,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::GenericSelectionExprClass: return CheckICE(cast(E)->getResultExpr(), Ctx); case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::ObjCBoolLiteralExprClass: case Expr::CXXBoolLiteralExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 54ceffa..86b9fb5 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3501,6 +3501,7 @@ recurse: case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: + case Expr::FixedPointLiteralClass: { if (!NullOut) { // As bad as this diagnostic is, it's better than crashing. diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 38ec663..dad57de 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1529,6 +1529,28 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { } } +void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) { + if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context)) + return; + OS << Node->getValueAsString(/*Radix=*/10); + + switch (Node->getType()->getAs()->getKind()) { + default: llvm_unreachable("Unexpected type for fixed point literal!"); + case BuiltinType::ShortFract: OS << "hr"; break; + case BuiltinType::ShortAccum: OS << "hk"; break; + case BuiltinType::UShortFract: OS << "uhr"; break; + case BuiltinType::UShortAccum: OS << "uhk"; break; + case BuiltinType::Fract: OS << "r"; break; + case BuiltinType::Accum: OS << "k"; break; + case BuiltinType::UFract: OS << "ur"; break; + case BuiltinType::UAccum: OS << "uk"; break; + case BuiltinType::LongFract: OS << "lr"; break; + case BuiltinType::LongAccum: OS << "lk"; break; + case BuiltinType::ULongFract: OS << "ulr"; break; + case BuiltinType::ULongAccum: OS << "ulk"; break; + } +} + static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, bool PrintSuffix) { SmallString<16> Str; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 91c7aa9..791ec56 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1007,6 +1007,12 @@ void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) { ID.AddInteger(S->getType()->castAs()->getKind()); } +void StmtProfiler::VisitFixedPointLiteral(const FixedPointLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); + ID.AddInteger(S->getType()->castAs()->getKind()); +} + void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) { VisitExpr(S); ID.AddInteger(S->getKind()); diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 5c37c10..eb65220 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3986,3 +3986,19 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const { return getClass()->getAsCXXRecordDecl()->getMostRecentNonInjectedDecl(); } + +void clang::FixedPointValueToString(SmallVectorImpl &Str, + const llvm::APSInt &Val, unsigned Scale, + unsigned Radix) { + llvm::APSInt ScaleVal = llvm::APSInt::getUnsigned(1ULL << Scale); + llvm::APSInt IntPart = Val / ScaleVal; + llvm::APSInt FractPart = Val % ScaleVal; + llvm::APSInt RadixInt = llvm::APSInt::getUnsigned(Radix); + + IntPart.toString(Str, Radix); + Str.push_back('.'); + do { + (FractPart * RadixInt / ScaleVal).toString(Str, Radix); + FractPart = (FractPart * RadixInt) % ScaleVal; + } while (FractPart.getExtValue()); +} diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 8dfcbcc..31bc7a4 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -40,12 +40,24 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { IntWidth = IntAlign = 32; LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; + + // Fixed point default bit widths ShortAccumWidth = ShortAccumAlign = 16; AccumWidth = AccumAlign = 32; LongAccumWidth = LongAccumAlign = 64; - ShortFractWidth = ShortFractAlign = 16; - FractWidth = FractAlign = 32; - LongFractWidth = LongFractAlign = 64; + ShortFractWidth = ShortFractAlign = 8; + FractWidth = FractAlign = 16; + LongFractWidth = LongFractAlign = 32; + + // Fixed point default integral and fractional bit sizes + // We give the _Accum 1 fewer fractional bits than their corresponding _Fract + // types by default to have the same number of fractional bits between _Accum + // and _Fract types. + SameFBits = false; + ShortAccumScale = 7; + AccumScale = 15; + LongAccumScale = 31; + SuitableAlign = 64; DefaultAlignForAttributeAligned = 128; MinGlobalAlign = 0; @@ -362,6 +374,11 @@ void TargetInfo::adjust(LangOptions &Opts) { if (Opts.NewAlignOverride) NewAlign = Opts.NewAlignOverride * getCharWidth(); + + // Each unsigned fixed point type has the same number of fractional bits as + // its corresponding signed type. + SameFBits |= Opts.SameFBits; + CheckFixedPointBits(); } bool TargetInfo::initFeatureMap( @@ -716,3 +733,63 @@ bool TargetInfo::validateInputConstraint( return true; } + +void TargetInfo::CheckFixedPointBits() const { + // Check that the number of fractional and integral bits (and maybe sign) can + // fit into the bits given for a fixed point type. + assert(ShortAccumScale + getShortAccumIBits() + 1 <= ShortAccumWidth); + assert(AccumScale + getAccumIBits() + 1 <= AccumWidth); + assert(LongAccumScale + getLongAccumIBits() + 1 <= LongAccumWidth); + assert(getUnsignedShortAccumScale() + getUnsignedShortAccumIBits() <= + ShortAccumWidth); + assert(getUnsignedAccumScale() + getUnsignedAccumIBits() <= AccumWidth); + assert(getUnsignedLongAccumScale() + getUnsignedLongAccumIBits() <= + LongAccumWidth); + + assert(getShortFractScale() + 1 <= ShortFractWidth); + assert(getFractScale() + 1 <= FractWidth); + assert(getLongFractScale() + 1 <= LongFractWidth); + assert(getUnsignedShortFractScale() <= ShortFractWidth); + assert(getUnsignedFractScale() <= FractWidth); + assert(getUnsignedLongFractScale() <= LongFractWidth); + + // Each unsigned fract type has either the same number of fractional bits + // as, or one more fractional bit than, its corresponding signed fract type. + assert(getShortFractScale() == getUnsignedShortFractScale() || + getShortFractScale() == getUnsignedShortFractScale() - 1); + assert(getFractScale() == getUnsignedFractScale() || + getFractScale() == getUnsignedFractScale() - 1); + assert(getLongFractScale() == getUnsignedLongFractScale() || + getLongFractScale() == getUnsignedLongFractScale() - 1); + + // When arranged in order of increasing rank (see 6.3.1.3a), the number of + // fractional bits is nondecreasing for each of the following sets of + // fixed-point types: + // - signed fract types + // - unsigned fract types + // - signed accum types + // - unsigned accum types. + assert(getLongFractScale() >= getFractScale() && + getFractScale() >= getShortFractScale()); + assert(getUnsignedLongFractScale() >= getUnsignedFractScale() && + getUnsignedFractScale() >= getUnsignedShortFractScale()); + assert(LongAccumScale >= AccumScale && AccumScale >= ShortAccumScale); + assert(getUnsignedLongAccumScale() >= getUnsignedAccumScale() && + getUnsignedAccumScale() >= getUnsignedShortAccumScale()); + + // When arranged in order of increasing rank (see 6.3.1.3a), the number of + // integral bits is nondecreasing for each of the following sets of + // fixed-point types: + // - signed accum types + // - unsigned accum types + assert(getLongAccumIBits() >= getAccumIBits() && + getAccumIBits() >= getShortAccumIBits()); + assert(getUnsignedLongAccumIBits() >= getUnsignedAccumIBits() && + getUnsignedAccumIBits() >= getUnsignedShortAccumIBits()); + + // Each signed accum type has at least as many integral bits as its + // corresponding unsigned accum type. + assert(getShortAccumIBits() >= getUnsignedShortAccumIBits()); + assert(getAccumIBits() >= getUnsignedAccumIBits()); + assert(getLongAccumIBits() >= getUnsignedLongAccumIBits()); +} diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 2e4b722..1ef2fe3 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -652,5 +652,7 @@ TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, if (!Target->validateTarget(Diags)) return nullptr; + Target->CheckFixedPointBits(); + return Target.release(); } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index d350a86..2917404 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -684,12 +684,12 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { CGF.EmitDynamicCast(LV.getAddress(), cast(E)); else CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast"); - + if (!Dest.isIgnored()) CGF.CGM.ErrorUnsupported(E, "lvalue dynamic_cast with a destination"); break; } - + case CK_ToUnion: { // Evaluate even if the destination is ignored. if (Dest.isIgnored()) { diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 0edd1cb..f4c0c75 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -387,6 +387,9 @@ public: Value *VisitIntegerLiteral(const IntegerLiteral *E) { return Builder.getInt(E->getValue()); } + Value *VisitFixedPointLiteral(const FixedPointLiteral *E) { + return Builder.getInt(E->getValue()); + } Value *VisitFloatingLiteral(const FloatingLiteral *E) { return llvm::ConstantFP::get(VMContext, E->getValue()); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a5943de..bce2083 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3766,6 +3766,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, /*Default=*/false)) Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + if (Args.hasFlag(options::OPT_fsame_fbits, + options::OPT_fno_same_fbits, + /*Default=*/false)) + Args.AddLastArg(CmdArgs, options::OPT_fsame_fbits); + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 2aa74c3..1f9d6b0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2338,6 +2338,10 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.FixedPoint = Args.hasFlag(OPT_ffixed_point, OPT_fno_fixed_point, /*Default=*/false) && !Opts.CPlusPlus; + Opts.SameFBits = + Args.hasFlag(OPT_fsame_fbits, OPT_fno_same_fbits, + /*Default=*/false) && + Opts.FixedPoint; // Handle exception personalities Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions, diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index af64ffe..e414f85 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -538,6 +538,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, saw_exponent = false; saw_period = false; saw_ud_suffix = false; + saw_fixed_point_suffix = false; isLong = false; isUnsigned = false; isLongLong = false; @@ -547,6 +548,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isFloat16 = false; isFloat128 = false; MicrosoftInteger = 0; + isFract = false; + isAccum = false; hadError = false; if (*s == '0') { // parse radix @@ -568,6 +571,14 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, SuffixBegin = s; checkSeparator(TokLoc, s, CSK_AfterDigits); + // Initial scan to lookahead for fixed point suffix. + for (const char *c = s; c != ThisTokEnd; ++c) { + if (*c == 'r' || *c == 'k' || *c == 'R' || *c == 'K') { + saw_fixed_point_suffix = true; + break; + } + } + // Parse the suffix. At this point we can classify whether we have an FP or // integer constant. bool isFPConstant = isFloatingLiteral(); @@ -576,11 +587,21 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, // we break out of the loop. for (; s != ThisTokEnd; ++s) { switch (*s) { + case 'R': + case 'r': + if (isFract || isAccum) break; + isFract = true; + continue; + case 'K': + case 'k': + if (isFract || isAccum) break; + isAccum = true; + continue; case 'h': // FP Suffix for "half". case 'H': // OpenCL Extension v1.2 s9.5 - h or H suffix for half type. - if (!PP.getLangOpts().Half) break; - if (!isFPConstant) break; // Error for integer constant. + if (!(PP.getLangOpts().Half || PP.getLangOpts().FixedPoint)) break; + if (isIntegerLiteral()) break; // Error for integer constant. if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid. isHalf = true; continue; // Success. @@ -693,6 +714,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isHalf = false; isImaginary = false; MicrosoftInteger = 0; + saw_fixed_point_suffix = false; + isFract = false; + isAccum = false; } saw_ud_suffix = true; @@ -707,6 +731,11 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, hadError = true; } } + + if (!hadError && saw_fixed_point_suffix) { + assert(isFract || isAccum); + assert(radix == 16 || radix == 10); + } } /// ParseDecimalOrOctalCommon - This method is called for decimal or octal @@ -1012,6 +1041,126 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { return Result.convertFromString(Str, APFloat::rmNearestTiesToEven); } +static inline bool IsExponentPart(char c) { + return c == 'p' || c == 'P' || c == 'e' || c == 'E'; +} + +bool NumericLiteralParser::GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale) { + assert(radix == 16 || radix == 10); + + // Find how many digits are needed to store the whole literal. + unsigned NumDigits = SuffixBegin - DigitsBegin; + if (saw_period) --NumDigits; + + // Initial scan of the exponent if it exists + bool ExpOverflowOccurred = false; + bool NegativeExponent = false; + const char *ExponentBegin; + uint64_t Exponent = 0; + int64_t BaseShift = 0; + if (saw_exponent) { + const char *Ptr = DigitsBegin; + + while (!IsExponentPart(*Ptr)) ++Ptr; + ExponentBegin = Ptr; + ++Ptr; + NegativeExponent = *Ptr == '-'; + if (NegativeExponent) ++Ptr; + + unsigned NumExpDigits = SuffixBegin - Ptr; + if (alwaysFitsInto64Bits(radix, NumExpDigits)) { + llvm::StringRef ExpStr(Ptr, NumExpDigits); + llvm::APInt ExpInt(/*numBits=*/64, ExpStr, /*radix=*/10); + Exponent = ExpInt.getZExtValue(); + } else { + ExpOverflowOccurred = true; + } + + if (NegativeExponent) BaseShift -= Exponent; + else BaseShift += Exponent; + } + + // Number of bits needed for decimal literal is + // ceil(NumDigits * log2(10)) Integral part + // + Scale Fractional part + // + ceil(Exponent * log2(10)) Exponent + // -------------------------------------------------- + // ceil((NumDigits + Exponent) * log2(10)) + Scale + // + // But for simplicity in handling integers, we can round up log2(10) to 4, + // making: + // 4 * (NumDigits + Exponent) + Scale + // + // Number of digits needed for hexadecimal literal is + // 4 * NumDigits Integral part + // + Scale Fractional part + // + Exponent Exponent + // -------------------------------------------------- + // (4 * NumDigits) + Scale + Exponent + uint64_t NumBitsNeeded; + if (radix == 10) + NumBitsNeeded = 4 * (NumDigits + Exponent) + Scale; + else + NumBitsNeeded = 4 * NumDigits + Exponent + Scale; + + if (NumBitsNeeded > std::numeric_limits::max()) + ExpOverflowOccurred = true; + llvm::APInt Val(static_cast(NumBitsNeeded), 0, /*isSigned=*/false); + + bool FoundDecimal = false; + + int64_t FractBaseShift = 0; + const char *End = saw_exponent ? ExponentBegin : SuffixBegin; + for (const char *Ptr = DigitsBegin; Ptr < End; ++Ptr) { + if (*Ptr == '.') { + FoundDecimal = true; + continue; + } + + // Normal reading of an integer + unsigned C = llvm::hexDigitValue(*Ptr); + assert(C < radix && "NumericLiteralParser ctor should have rejected this"); + + Val *= radix; + Val += C; + + if (FoundDecimal) + // Keep track of how much we will need to adjust this value by from the + // number of digits past the radix point. + --FractBaseShift; + } + + // For a radix of 16, we will be multiplying by 2 instead of 16. + if (radix == 16) FractBaseShift *= 4; + BaseShift += FractBaseShift; + + Val <<= Scale; + + uint64_t Base = (radix == 16) ? 2 : 10; + if (BaseShift > 0) { + for (int64_t i = 0; i < BaseShift; ++i) { + Val *= Base; + } + } else if (BaseShift < 0) { + for (int64_t i = BaseShift; i < 0 && !Val.isNullValue(); ++i) + Val = Val.udiv(Base); + } + + bool IntOverflowOccurred = false; + auto MaxVal = llvm::APInt::getMaxValue(StoreVal.getBitWidth()); + if (Val.getBitWidth() > StoreVal.getBitWidth()) { + IntOverflowOccurred |= Val.ugt(MaxVal.zext(Val.getBitWidth())); + StoreVal = Val.trunc(StoreVal.getBitWidth()); + } else if (Val.getBitWidth() < StoreVal.getBitWidth()) { + IntOverflowOccurred |= Val.zext(MaxVal.getBitWidth()).ugt(MaxVal); + StoreVal = Val.zext(StoreVal.getBitWidth()); + } else { + StoreVal = Val; + } + + return IntOverflowOccurred || ExpOverflowOccurred; +} + /// \verbatim /// user-defined-character-literal: [C++11 lex.ext] /// character-literal ud-suffix diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index a81c17b..8dce6d5 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1258,6 +1258,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ImaginaryLiteralClass: case Expr::ImplicitValueInitExprClass: case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::ObjCEncodeExprClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index aeedd6b..88059e9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3326,7 +3326,52 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Expr *Res; - if (Literal.isFloatingLiteral()) { + if (Literal.isFixedPointLiteral()) { + QualType Ty; + + if (Literal.isAccum) { + if (Literal.isHalf) { + Ty = Context.ShortAccumTy; + } else if (Literal.isLong) { + Ty = Context.LongAccumTy; + } else { + Ty = Context.AccumTy; + } + } else if (Literal.isFract) { + if (Literal.isHalf) { + Ty = Context.ShortFractTy; + } else if (Literal.isLong) { + Ty = Context.LongFractTy; + } else { + Ty = Context.FractTy; + } + } + + if (Literal.isUnsigned) Ty = Context.getCorrespondingUnsignedType(Ty); + + bool isSigned = !Literal.isUnsigned; + unsigned scale = Context.getFixedPointScale(Ty); + unsigned ibits = Context.getFixedPointIBits(Ty); + unsigned bit_width = Context.getTypeInfo(Ty).Width; + + llvm::APInt Val(bit_width, 0, isSigned); + bool Overflowed = Literal.GetFixedPointValue(Val, scale); + + // Do not use bit_width since some types may have padding like _Fract or + // unsigned _Accums if SameFBits is set. + auto MaxVal = llvm::APInt::getMaxValue(ibits + scale).zextOrSelf(bit_width); + if (Literal.isFract && Val == MaxVal + 1) + // Clause 6.4.4 - The value of a constant shall be in the range of + // representable values for its type, with exception for constants of a + // fract type with a value of exactly 1; such a constant shall denote + // the maximal value for the type. + --Val; + else if (Val.ugt(MaxVal) || Overflowed) + Diag(Tok.getLocation(), diag::err_too_large_for_fixed_point); + + Res = FixedPointLiteral::CreateFromRawInt(Context, Val, Ty, + Tok.getLocation(), scale); + } else if (Literal.isFloatingLiteral()) { QualType Ty; if (Literal.isHalf){ if (getOpenCLOptions().isEnabled("cl_khr_fp16")) @@ -13122,7 +13167,7 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, CondExpr = CondICE.get(); CondIsTrue = condEval.getZExtValue(); - // If the condition is > zero, then the AST type is the same as the LSHExpr. + // If the condition is > zero, then the AST type is the same as the LHSExpr. Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr; resType = ActiveExpr->getType(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index cdf7dc4..66c947a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -8888,6 +8888,12 @@ TreeTransform::TransformIntegerLiteral(IntegerLiteral *E) { return E; } +template +ExprResult TreeTransform::TransformFixedPointLiteral( + FixedPointLiteral *E) { + return E; +} + template ExprResult TreeTransform::TransformFloatingLiteral(FloatingLiteral *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 62d8cd0..2b7de79 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -533,6 +533,12 @@ void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { E->setValue(Record.getContext(), Record.readAPInt()); } +void ASTStmtReader::VisitFixedPointLiteral(FixedPointLiteral *E) { + VisitExpr(E); + E->setLocation(ReadSourceLocation()); + E->setValue(Record.getContext(), Record.readAPInt()); +} + void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { VisitExpr(E); E->setRawSemantics(static_cast(Record.readInt())); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 665b879..b79e80e 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -444,6 +444,13 @@ void ASTStmtWriter::VisitIntegerLiteral(IntegerLiteral *E) { Code = serialization::EXPR_INTEGER_LITERAL; } +void ASTStmtWriter::VisitFixedPointLiteral(FixedPointLiteral *E) { + VisitExpr(E); + Record.AddSourceLocation(E->getLocation()); + Record.AddAPInt(E->getValue()); + Code = serialization::EXPR_INTEGER_LITERAL; +} + void ASTStmtWriter::VisitFloatingLiteral(FloatingLiteral *E) { VisitExpr(E); Record.push_back(E->getRawSemantics()); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 939b219..8ec78cf 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1297,6 +1297,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::AddrLabelExprClass: case Stmt::AttributedStmtClass: case Stmt::IntegerLiteralClass: + case Stmt::FixedPointLiteralClass: case Stmt::CharacterLiteralClass: case Stmt::ImplicitValueInitExprClass: case Stmt::CXXScalarValueInitExprClass: diff --git a/clang/test/Frontend/fixed_point.c b/clang/test/Frontend/fixed_point.c index bc8cf2d..3a67718 100644 --- a/clang/test/Frontend/fixed_point.c +++ b/clang/test/Frontend/fixed_point.c @@ -236,4 +236,164 @@ SatlF_t SatlF_type; //CHECK-NEXT: |-VarDecl {{.*}} SatlA_type 'SatlA_t':'_Sat long _Accum' //CHECK-NEXT: |-VarDecl {{.*}} SatsF_type 'SatsF_t':'_Sat short _Fract' //CHECK-NEXT: |-VarDecl {{.*}} SatF_type 'SatF_t':'_Sat _Fract' -//CHECK-NEXT: `-VarDecl {{.*}} SatlF_type 'SatlF_t':'_Sat long _Fract' +//CHECK-NEXT: |-VarDecl {{.*}} SatlF_type 'SatlF_t':'_Sat long _Fract' + +// Fixed point literal exponent syntax +_Accum decexp1 = 1.575e1k; +_Accum decexp2 = 1.575E1k; +_Accum decexp3 = 1575e-2k; +_Accum decexp4 = 1575E-2k; + +_Accum hexexp1 = 0x0.3p10k; +_Accum hexexp2 = 0x0.3P10k; +_Accum hexexp3 = 0x30000p-10k; +_Accum hexexp4 = 0x30000P-10k; + +_Accum zeroexp1 = 1e0k; +_Accum zeroexp2 = 1e-0k; + +//CHECK-NEXT: |-VarDecl {{.*}} decexp1 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75 +//CHECK-NEXT: |-VarDecl {{.*}} decexp2 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75 +//CHECK-NEXT: |-VarDecl {{.*}} decexp3 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75 +//CHECK-NEXT: |-VarDecl {{.*}} decexp4 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 15.75 + +//CHECK-NEXT: |-VarDecl {{.*}} hexexp1 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0 +//CHECK-NEXT: |-VarDecl {{.*}} hexexp2 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0 +//CHECK-NEXT: |-VarDecl {{.*}} hexexp3 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0 +//CHECK-NEXT: |-VarDecl {{.*}} hexexp4 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 192.0 + +//CHECK-NEXT: |-VarDecl {{.*}} zeroexp1 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0 +//CHECK-NEXT: |-VarDecl {{.*}} zeroexp2 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0 + +// Fixed point literal values +_Accum literal1 = 2.5k; // Precise decimal +_Accum literal2 = 0.0k; // Zero +_Accum literal3 = 1.1k; // Imprecise decimal +_Accum literal4 = 1.11k; +_Accum literal5 = 1.111k; +_Accum literal6 = 1.1111k; +_Accum literal7 = 1.11111k; // After some point after the radix, adding any more + // digits to the literal will not result in any + // further precision since the nth digit added may + // be less than the precision that can be + // represented by the fractional bits of the type. + // This results in the same value being stored for + // the type. + +//CHECK-NEXT: |-VarDecl {{.*}} literal1 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 2.5 +//CHECK-NEXT: |-VarDecl {{.*}} literal2 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.0 +//CHECK-NEXT: |-VarDecl {{.*}} literal3 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0999755859375 +//CHECK-NEXT: |-VarDecl {{.*}} literal4 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.1099853515625 +//CHECK-NEXT: |-VarDecl {{.*}} literal5 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.110992431640625 +//CHECK-NEXT: |-VarDecl {{.*}} literal6 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.111083984375 +//CHECK-NEXT: |-VarDecl {{.*}} literal7 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.111083984375 + +long _Accum longaccumliteral = 0.99999999lk; +long _Accum longaccumliteral2 = 0.999999999lk; +long _Accum verylongaccumliteral = 0.99999999999999999999999999lk; +long _Fract longfractliteral = 0.99999999lr; +long _Fract longfractliteral2 = 0.999999999lr; +long _Fract verylongfractliteral = 0.99999999999999999999999999lr; + +//CHECK-NEXT: |-VarDecl {{.*}} longaccumliteral 'long _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.999999989755451679229736328125 +//CHECK-NEXT: |-VarDecl {{.*}} longaccumliteral2 'long _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.9999999986030161380767822265625 +//CHECK-NEXT: |-VarDecl {{.*}} verylongaccumliteral 'long _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.9999999995343387126922607421875 +//CHECK-NEXT: |-VarDecl {{.*}} longfractliteral 'long _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.999999989755451679229736328125 +//CHECK-NEXT: |-VarDecl {{.*}} longfractliteral2 'long _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.9999999986030161380767822265625 +//CHECK-NEXT: |-VarDecl {{.*}} verylongfractliteral 'long _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.9999999995343387126922607421875 + +unsigned _Accum uliteral1 = 2.5uk; // Unsigned +_Accum literal8 = -2.5k; // Negative + +//CHECK-NEXT: |-VarDecl {{.*}} uliteral1 'unsigned _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned _Accum' 2.5 +//CHECK-NEXT: |-VarDecl {{.*}} literal8 '_Accum' cinit +//CHECK-NEXT: `-UnaryOperator {{.*}} '_Accum' prefix '-' +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 2.5 + +short _Accum literalexact1 = 0.9921875hk; // Exact value +_Accum literalexact2 = 0.999969482421875k; + +//CHECK-NEXT: |-VarDecl {{.*}} literalexact1 'short _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 0.9921875 +//CHECK-NEXT: |-VarDecl {{.*}} literalexact2 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.999969482421875 + +// Unfortunately we do not have enough space to store the exact decimal value of +// 0.9999999995343387126922607421875 ((1 << 31) - 1), but we can still use a +// large number of 9s to get the max fractional value. +long _Accum long_accum_max = 0.999999999999999999999999999lk; + +//CHECK-NEXT: |-VarDecl {{.*}} long_accum_max 'long _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.9999999995343387126922607421875 + +// Epsilon +short _Accum short_accum_eps = 0.0078125hk; +short _Accum short_accum_eps2 = 0.0078124hk; // Less than epsilon floors to zero +_Accum accum_eps = 0.000030517578125k; +_Accum accum_eps2 = 0.000030517578124k; +long _Accum long_accum_eps = 0x1p-31lk; +long _Accum long_accum_eps2 = 0x0.99999999p-31lk; + +//CHECK-NEXT: |-VarDecl {{.*}} short_accum_eps 'short _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 0.0078125 +//CHECK-NEXT: |-VarDecl {{.*}} short_accum_eps2 'short _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 0.0 +//CHECK-NEXT: |-VarDecl {{.*}} accum_eps '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.000030517578125 +//CHECK-NEXT: |-VarDecl {{.*}} accum_eps2 '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 0.0 +//CHECK-NEXT: |-VarDecl {{.*}} long_accum_eps 'long _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.0000000004656612873077392578125 +//CHECK-NEXT: |-VarDecl {{.*}} long_accum_eps2 'long _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Accum' 0.0 + +// Fract literals can be one but evaluate to the respective Fract max +short _Fract short_fract_one = 1.0hr; +_Fract fract_one = 1.0r; +long _Fract long_fract_one = 1.0lr; +unsigned short _Fract u_short_fract_one = 1.0uhr; +unsigned _Fract u_fract_one = 1.0ur; +unsigned long _Fract u_long_fract_one = 1.0ulr; + +//CHECK-NEXT: |-VarDecl {{.*}} short_fract_one 'short _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Fract' 0.9921875 +//CHECK-NEXT: |-VarDecl {{.*}} fract_one '_Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Fract' 0.999969482421875 +//CHECK-NEXT: |-VarDecl {{.*}} long_fract_one 'long _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'long _Fract' 0.9999999995343387126922607421875 + +//CHECK-NEXT: |-VarDecl {{.*}} u_short_fract_one 'unsigned short _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned short _Fract' 0.99609375 +//CHECK-NEXT: |-VarDecl {{.*}} u_fract_one 'unsigned _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned _Fract' 0.9999847412109375 +//CHECK-NEXT: |-VarDecl {{.*}} u_long_fract_one 'unsigned long _Fract' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'unsigned long _Fract' 0.99999999976716935634613037109375 + +_Accum literallast = 1.0k; // One + +//CHECK-NEXT: `-VarDecl {{.*}} literallast '_Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} '_Accum' 1.0 diff --git a/clang/test/Frontend/fixed_point_bit_widths.c b/clang/test/Frontend/fixed_point_bit_widths.c index 8973a33..ac8db49 100644 --- a/clang/test/Frontend/fixed_point_bit_widths.c +++ b/clang/test/Frontend/fixed_point_bit_widths.c @@ -44,12 +44,12 @@ int align_SsF = __alignof(signed short _Fract); int align_SF = __alignof(signed _Fract); int align_SlF = __alignof(signed long _Fract); -// CHECK-NEXT: @size_SsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @size_SF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @size_SlF = {{.*}}global i{{[0-9]+}} 8 -// CHECK-NEXT: @align_SsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @align_SF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @align_SlF = {{.*}}global i{{[0-9]+}} 8 +// CHECK-NEXT: @size_SsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @size_SF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @size_SlF = {{.*}}global i{{[0-9]+}} 4 +// CHECK-NEXT: @align_SsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @align_SF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @align_SlF = {{.*}}global i{{[0-9]+}} 4 /* Primary unsigned _Fract */ @@ -60,12 +60,12 @@ int align_UsF = __alignof(unsigned short _Fract); int align_UF = __alignof(unsigned _Fract); int align_UlF = __alignof(unsigned long _Fract); -// CHECK-NEXT: @size_UsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @size_UF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @size_UlF = {{.*}}global i{{[0-9]+}} 8 -// CHECK-NEXT: @align_UsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @align_UF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @align_UlF = {{.*}}global i{{[0-9]+}} 8 +// CHECK-NEXT: @size_UsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @size_UF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @size_UlF = {{.*}}global i{{[0-9]+}} 4 +// CHECK-NEXT: @align_UsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @align_UF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @align_UlF = {{.*}}global i{{[0-9]+}} 4 /* Aliased _Accum */ @@ -92,12 +92,12 @@ int align_sF = __alignof(short _Fract); int align_F = __alignof(_Fract); int align_lF = __alignof(long _Fract); -// CHECK-NEXT: @size_sF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @size_F = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @size_lF = {{.*}}global i{{[0-9]+}} 8 -// CHECK-NEXT: @align_sF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @align_F = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @align_lF = {{.*}}global i{{[0-9]+}} 8 +// CHECK-NEXT: @size_sF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @size_F = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @size_lF = {{.*}}global i{{[0-9]+}} 4 +// CHECK-NEXT: @align_sF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @align_F = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @align_lF = {{.*}}global i{{[0-9]+}} 4 /* Saturated signed _Accum */ @@ -140,12 +140,12 @@ int align_SatSsF = __alignof(_Sat signed short _Fract); int align_SatSF = __alignof(_Sat signed _Fract); int align_SatSlF = __alignof(_Sat signed long _Fract); -// CHECK-NEXT: @size_SatSsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @size_SatSF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @size_SatSlF = {{.*}}global i{{[0-9]+}} 8 -// CHECK-NEXT: @align_SatSsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @align_SatSF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @align_SatSlF = {{.*}}global i{{[0-9]+}} 8 +// CHECK-NEXT: @size_SatSsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @size_SatSF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @size_SatSlF = {{.*}}global i{{[0-9]+}} 4 +// CHECK-NEXT: @align_SatSsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @align_SatSF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @align_SatSlF = {{.*}}global i{{[0-9]+}} 4 /* Saturated unsigned _Fract */ @@ -156,12 +156,12 @@ int align_SatUsF = __alignof(_Sat unsigned short _Fract); int align_SatUF = __alignof(_Sat unsigned _Fract); int align_SatUlF = __alignof(_Sat unsigned long _Fract); -// CHECK-NEXT: @size_SatUsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @size_SatUF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @size_SatUlF = {{.*}}global i{{[0-9]+}} 8 -// CHECK-NEXT: @align_SatUsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @align_SatUF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @align_SatUlF = {{.*}}global i{{[0-9]+}} 8 +// CHECK-NEXT: @size_SatUsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @size_SatUF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @size_SatUlF = {{.*}}global i{{[0-9]+}} 4 +// CHECK-NEXT: @align_SatUsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @align_SatUF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @align_SatUlF = {{.*}}global i{{[0-9]+}} 4 /* Aliased saturated signed _Accum */ @@ -188,9 +188,9 @@ int align_SatsF = __alignof(_Sat short _Fract); int align_SatF = __alignof(_Sat _Fract); int align_SatlF = __alignof(_Sat long _Fract); -// CHECK-NEXT: @size_SatsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @size_SatF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @size_SatlF = {{.*}}global i{{[0-9]+}} 8 -// CHECK-NEXT: @align_SatsF = {{.*}}global i{{[0-9]+}} 2 -// CHECK-NEXT: @align_SatF = {{.*}}global i{{[0-9]+}} 4 -// CHECK-NEXT: @align_SatlF = {{.*}}global i{{[0-9]+}} 8 +// CHECK-NEXT: @size_SatsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @size_SatF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @size_SatlF = {{.*}}global i{{[0-9]+}} 4 +// CHECK-NEXT: @align_SatsF = {{.*}}global i{{[0-9]+}} 1 +// CHECK-NEXT: @align_SatF = {{.*}}global i{{[0-9]+}} 2 +// CHECK-NEXT: @align_SatlF = {{.*}}global i{{[0-9]+}} 4 diff --git a/clang/test/Frontend/fixed_point_declarations.c b/clang/test/Frontend/fixed_point_declarations.c new file mode 100644 index 0000000..47f7e9f --- /dev/null +++ b/clang/test/Frontend/fixed_point_declarations.c @@ -0,0 +1,113 @@ +// RUN: %clang -ffixed-point -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang -ffixed-point -S -emit-llvm %s -o - --target=x86_64-scei-ps4-ubuntu-fast | FileCheck %s + +// Primary fixed point types +signed short _Accum s_short_accum; // CHECK-DAG: @s_short_accum = {{.*}}global i16 0, align 2 +signed _Accum s_accum; // CHECK-DAG: @s_accum = {{.*}}global i32 0, align 4 +signed long _Accum s_long_accum; // CHECK-DAG: @s_long_accum = {{.*}}global i64 0, align 8 +unsigned short _Accum u_short_accum; // CHECK-DAG: @u_short_accum = {{.*}}global i16 0, align 2 +unsigned _Accum u_accum; // CHECK-DAG: @u_accum = {{.*}}global i32 0, align 4 +unsigned long _Accum u_long_accum; // CHECK-DAG: @u_long_accum = {{.*}}global i64 0, align 8 +signed short _Fract s_short_fract; // CHECK-DAG: @s_short_fract = {{.*}}global i8 0, align 1 +signed _Fract s_fract; // CHECK-DAG: @s_fract = {{.*}}global i16 0, align 2 +signed long _Fract s_long_fract; // CHECK-DAG: @s_long_fract = {{.*}}global i32 0, align 4 +unsigned short _Fract u_short_fract; // CHECK-DAG: @u_short_fract = {{.*}}global i8 0, align 1 +unsigned _Fract u_fract; // CHECK-DAG: @u_fract = {{.*}}global i16 0, align 2 +unsigned long _Fract u_long_fract; // CHECK-DAG: @u_long_fract = {{.*}}global i32 0, align 4 + +// Aliased +short _Accum short_accum; // CHECK-DAG: @short_accum = {{.*}}global i16 0, align 2 +_Accum accum; // CHECK-DAG: @accum = {{.*}}global i32 0, align 4 +long _Accum long_accum; // CHECK-DAG: @long_accum = {{.*}}global i64 0, align 8 +short _Fract short_fract; // CHECK-DAG: @short_fract = {{.*}}global i8 0, align 1 +_Fract fract; // CHECK-DAG: @fract = {{.*}}global i16 0, align 2 +long _Fract long_fract; // CHECK-DAG: @long_fract = {{.*}}global i32 0, align 4 + +// Primary saturated +_Sat signed short _Accum sat_s_short_accum; // CHECK-DAG: @sat_s_short_accum = {{.*}}global i16 0, align 2 +_Sat signed _Accum sat_s_accum; // CHECK-DAG: @sat_s_accum = {{.*}}global i32 0, align 4 +_Sat signed long _Accum sat_s_long_accum; // CHECK-DAG: @sat_s_long_accum = {{.*}}global i64 0, align 8 +_Sat unsigned short _Accum sat_u_short_accum; // CHECK-DAG: @sat_u_short_accum = {{.*}}global i16 0, align 2 +_Sat unsigned _Accum sat_u_accum; // CHECK-DAG: @sat_u_accum = {{.*}}global i32 0, align 4 +_Sat unsigned long _Accum sat_u_long_accum; // CHECK-DAG: @sat_u_long_accum = {{.*}}global i64 0, align 8 +_Sat signed short _Fract sat_s_short_fract; // CHECK-DAG: @sat_s_short_fract = {{.*}}global i8 0, align 1 +_Sat signed _Fract sat_s_fract; // CHECK-DAG: @sat_s_fract = {{.*}}global i16 0, align 2 +_Sat signed long _Fract sat_s_long_fract; // CHECK-DAG: @sat_s_long_fract = {{.*}}global i32 0, align 4 +_Sat unsigned short _Fract sat_u_short_fract; // CHECK-DAG: @sat_u_short_fract = {{.*}}global i8 0, align 1 +_Sat unsigned _Fract sat_u_fract; // CHECK-DAG: @sat_u_fract = {{.*}}global i16 0, align 2 +_Sat unsigned long _Fract sat_u_long_fract; // CHECK-DAG: @sat_u_long_fract = {{.*}}global i32 0, align 4 + +// Aliased saturated +_Sat short _Accum sat_short_accum; // CHECK-DAG: @sat_short_accum = {{.*}}global i16 0, align 2 +_Sat _Accum sat_accum; // CHECK-DAG: @sat_accum = {{.*}}global i32 0, align 4 +_Sat long _Accum sat_long_accum; // CHECK-DAG: @sat_long_accum = {{.*}}global i64 0, align 8 +_Sat short _Fract sat_short_fract; // CHECK-DAG: @sat_short_fract = {{.*}}global i8 0, align 1 +_Sat _Fract sat_fract; // CHECK-DAG: @sat_fract = {{.*}}global i16 0, align 2 +_Sat long _Fract sat_long_fract; // CHECK-DAG: @sat_long_fract = {{.*}}global i32 0, align 4 + +/* Fixed point literals */ +short _Accum short_accum_literal = 2.5hk; // CHECK-DAG: @short_accum_literal = {{.*}}global i16 320, align 2 +_Accum accum_literal = 2.5k; // CHECK-DAG: @accum_literal = {{.*}}global i32 81920, align 4 +long _Accum long_accum_literal = 2.5lk; // CHECK-DAG: @long_accum_literal = {{.*}}global i64 5368709120, align 8 +short _Fract short_fract_literal = 0.5hr; // CHECK-DAG: @short_fract_literal = {{.*}}global i8 64, align 1 +_Fract fract_literal = 0.5r; // CHECK-DAG: @fract_literal = {{.*}}global i16 16384, align 2 +long _Fract long_fract_literal = 0.5lr; // CHECK-DAG: @long_fract_literal = {{.*}}global i32 1073741824, align 4 + +unsigned short _Accum u_short_accum_literal = 2.5uhk; // CHECK-DAG: @u_short_accum_literal = {{.*}}global i16 640, align 2 +unsigned _Accum u_accum_literal = 2.5uk; // CHECK-DAG: @u_accum_literal = {{.*}}global i32 163840, align 4 +unsigned long _Accum u_long_accum_literal = 2.5ulk; // CHECK-DAG: @u_long_accum_literal = {{.*}}global i64 10737418240, align 8 +unsigned short _Fract u_short_fract_literal = 0.5uhr; // CHECK-DAG: @u_short_fract_literal = {{.*}}global i8 -128, align 1 +unsigned _Fract u_fract_literal = 0.5ur; // CHECK-DAG: @u_fract_literal = {{.*}}global i16 -32768, align 2 +unsigned long _Fract u_long_fract_literal = 0.5ulr; // CHECK-DAG: @u_long_fract_literal = {{.*}}global i32 -2147483648, align 4 + +// Max literal values +short _Accum short_accum_max = 255.9999999999999999hk; // CHECK-DAG: @short_accum_max = {{.*}}global i16 32767, align 2 +_Accum accum_max = 65535.9999999999999999k; // CHECK-DAG: @accum_max = {{.*}}global i32 2147483647, align 4 +long _Accum long_accum_max = 4294967295.9999999999999999lk; // CHECK-DAG: @long_accum_max = {{.*}}global i64 9223372036854775807, align 8 +unsigned short _Accum u_short_accum_max = 255.9999999999999999uhk; // CHECK-DAG: @u_short_accum_max = {{.*}}global i16 -1, align 2 +unsigned _Accum u_accum_max = 65535.9999999999999999uk; // CHECK-DAG: @u_accum_max = {{.*}}global i32 -1, align 4 +unsigned long _Accum u_long_accum_max = 4294967295.9999999999999999ulk; // CHECK-DAG: @u_long_accum_max = {{.*}}global i64 -1, align 8 + +short _Fract short_fract_max = 0.9999999999999999hr; // CHECK-DAG: @short_fract_max = {{.*}}global i8 127, align 1 +_Fract fract_max = 0.9999999999999999r; // CHECK-DAG: @fract_max = {{.*}}global i16 32767, align 2 +long _Fract long_fract_max = 0.9999999999999999lr; // CHECK-DAG: @long_fract_max = {{.*}}global i32 2147483647, align 4 +unsigned short _Fract u_short_fract_max = 0.9999999999999999uhr; // CHECK-DAG: @u_short_fract_max = {{.*}}global i8 -1, align 1 +unsigned _Fract u_fract_max = 0.9999999999999999ur; // CHECK-DAG: @u_fract_max = {{.*}}global i16 -1, align 2 +unsigned long _Fract u_long_fract_max = 0.9999999999999999ulr; // CHECK-DAG: @u_long_fract_max = {{.*}}global i32 -1, align 4 + +// Fracts may be exactly one but evaluate to the Fract max +short _Fract short_fract_one = 1.0hr; // CHECK-DAG: @short_fract_one = {{.*}}global i8 127, align 1 +_Fract fract_one = 1.0r; // CHECK-DAG: @fract_one = {{.*}}global i16 32767, align 2 +long _Fract long_fract_one = 1.0lr; // CHECK-DAG: @long_fract_one = {{.*}}global i32 2147483647, align 4 +unsigned short _Fract u_short_fract_one = 1.0uhr; // CHECK-DAG: @u_short_fract_one = {{.*}}global i8 -1, align 1 +unsigned _Fract u_fract_one = 1.0ur; // CHECK-DAG: @u_fract_one = {{.*}}global i16 -1, align 2 +unsigned long _Fract u_long_fract_one = 1.0ulr; // CHECK-DAG: @u_long_fract_one = {{.*}}global i32 -1, align 4 + +short _Fract short_fract_exp_one = 0.1e1hr; // CHECK-DAG: @short_fract_exp_one = {{.*}}global i8 127, align 1 +_Fract fract_exp_one = 0.1e1r; // CHECK-DAG: @fract_exp_one = {{.*}}global i16 32767, align 2 +long _Fract long_fract_exp_one = 0.1e1lr; // CHECK-DAG: @long_fract_exp_one = {{.*}}global i32 2147483647, align 4 +unsigned short _Fract u_short_fract_exp_one = 0.1e1uhr; // CHECK-DAG: @u_short_fract_exp_one = {{.*}}global i8 -1, align 1 +unsigned _Fract u_fract_exp_one = 0.1e1ur; // CHECK-DAG: @u_fract_exp_one = {{.*}}global i16 -1, align 2 +unsigned long _Fract u_long_fract_exp_one = 0.1e1ulr; // CHECK-DAG: @u_long_fract_exp_one = {{.*}}global i32 -1, align 4 + +short _Fract short_fract_hex_exp_one = 0x0.8p1hr; // CHECK-DAG: @short_fract_hex_exp_one = {{.*}}global i8 127, align 1 +_Fract fract_hex_exp_one = 0x0.8p1r; // CHECK-DAG: @fract_hex_exp_one = {{.*}}global i16 32767, align 2 +long _Fract long_fract_hex_exp_one = 0x0.8p1lr; // CHECK-DAG: @long_fract_hex_exp_one = {{.*}}global i32 2147483647, align 4 +unsigned short _Fract u_short_fract_hex_exp_one = 0x0.8p1uhr; // CHECK-DAG: @u_short_fract_hex_exp_one = {{.*}}global i8 -1, align 1 +unsigned _Fract u_fract_hex_exp_one = 0x0.8p1ur; // CHECK-DAG: @u_fract_hex_exp_one = {{.*}}global i16 -1, align 2 +unsigned long _Fract u_long_fract_hex_exp_one = 0x0.8p1ulr; // CHECK-DAG: @u_long_fract_hex_exp_one = {{.*}}global i32 -1, align 4 + +// Expsilon values +short _Accum short_accum_eps = 0x1p-7hk; // CHECK-DAG: @short_accum_eps = {{.*}}global i16 1, align 2 +_Accum accum_eps = 0x1p-15k; // CHECK-DAG: @accum_eps = {{.*}}global i32 1, align 4 +long _Accum long_accum_eps = 0x1p-31lk; // CHECK-DAG: @long_accum_eps = {{.*}}global i64 1, align 8 +unsigned short _Accum u_short_accum_eps = 0x1p-8uhk; // CHECK-DAG: @u_short_accum_eps = {{.*}}global i16 1, align 2 +unsigned _Accum u_accum_eps = 0x1p-16uk; // CHECK-DAG: @u_accum_eps = {{.*}}global i32 1, align 4 +unsigned long _Accum u_long_accum_eps = 0x1p-32ulk; // CHECK-DAG: @u_long_accum_eps = {{.*}}global i64 1, align 8 + +short _Fract short_fract_eps = 0x1p-7hr; // CHECK-DAG: @short_fract_eps = {{.*}}global i8 1, align 1 +_Fract fract_eps = 0x1p-15r; // CHECK-DAG: @fract_eps = {{.*}}global i16 1, align 2 +long _Fract long_fract_eps = 0x1p-31lr; // CHECK-DAG: @long_fract_eps = {{.*}}global i32 1, align 4 +unsigned short _Fract u_short_fract_eps = 0x1p-8uhr; // CHECK-DAG: @u_short_fract_eps = {{.*}}global i8 1, align 1 +unsigned _Fract u_fract_eps = 0x1p-16ur; // CHECK-DAG: @u_fract_eps = {{.*}}global i16 1, align 2 +unsigned long _Fract u_long_fract_eps = 0x1p-32ulr; // CHECK-DAG: @u_long_fract_eps = {{.*}}global i32 1, align 4 diff --git a/clang/test/Frontend/fixed_point_errors.c b/clang/test/Frontend/fixed_point_errors.c index 7f0e009..f55fc82 100644 --- a/clang/test/Frontend/fixed_point_errors.c +++ b/clang/test/Frontend/fixed_point_errors.c @@ -78,6 +78,50 @@ _Sat char c; // expected-error{{'_Sat' specifier is only valid on ' _Sat int i; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'int'}} _Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} + +/* Literals that cannot fit into types */ +signed short _Accum s_short_accum = 256.0hk; // expected-error{{this value is too large for this fixed point type}} +unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{this value is too large for this fixed point type}} +signed _Accum s_accum = 65536.0k; // expected-error{{this value is too large for this fixed point type}} +unsigned _Accum u_accum = 65536.0uk; // expected-error{{this value is too large for this fixed point type}} +signed long _Accum s_long_accum = 4294967296.0lk; // expected-error{{this value is too large for this fixed point type}} +unsigned long _Accum u_long_accum = 4294967296.0ulk; // expected-error{{this value is too large for this fixed point type}} + +// Large values from decimal exponents +short _Accum short_accum_exp = 2.56e2hk; // expected-error{{this value is too large for this fixed point type}} +_Accum accum_exp = 6.5536e4k; // expected-error{{this value is too large for this fixed point type}} +long _Accum long_accum_exp = 4.294967296e9lk; // expected-error{{this value is too large for this fixed point type}} +unsigned short _Accum u_short_accum_exp = 2.56e2uhk; // expected-error{{this value is too large for this fixed point type}} +unsigned _Accum u_accum_exp = 6.5536e4uk; // expected-error{{this value is too large for this fixed point type}} +unsigned long _Accum u_long_accum_exp = 4.294967296e9ulk; // expected-error{{this value is too large for this fixed point type}} + +// Large value from hexidecimal exponents +short _Accum short_accum_hex_exp = 0x1p8hk; // expected-error{{this value is too large for this fixed point type}} +_Accum accum_hex_exp = 0x1p16k; // expected-error{{this value is too large for this fixed point type}} +long _Accum long_accum_hex_exp = 0x1p32lk; // expected-error{{this value is too large for this fixed point type}} +unsigned short _Accum u_short_accum_hex_exp = 0x1p8uhk; // expected-error{{this value is too large for this fixed point type}} +unsigned _Accum u_accum_hex_exp = 0x1p16uk; // expected-error{{this value is too large for this fixed point type}} +unsigned long _Accum u_long_accum_hex_exp = 0x1p32ulk; // expected-error{{this value is too large for this fixed point type}} + +// Very large exponent +_Accum x = 1e1000000000000000000000000000000000k; // expected-error{{this value is too large for this fixed point type}} + +/* Although _Fract's cannot equal 1, _Fract literals written as 1 are allowed + * and the underlying value represents the max value for that _Fract type. */ +short _Fract short_fract_above_1 = 1.1hr; // expected-error{{this value is too large for this fixed point type}} +_Fract fract_above_1 = 1.1r; // expected-error{{this value is too large for this fixed point type}} +long _Fract long_fract_above_1 = 1.1lr; // expected-error{{this value is too large for this fixed point type}} +unsigned short _Fract u_short_fract_above_1 = 1.1uhr; // expected-error{{this value is too large for this fixed point type}} +unsigned _Fract u_fract_above_1 = 1.1ur; // expected-error{{this value is too large for this fixed point type}} +unsigned long _Fract u_long_fract_above_1 = 1.1ulr; // expected-error{{this value is too large for this fixed point type}} + +short _Fract short_fract_hex_exp = 0x0.fp1hr; // expected-error{{this value is too large for this fixed point type}} +_Fract fract_hex_exp = 0x0.fp1r; // expected-error{{this value is too large for this fixed point type}} +long _Fract long_fract_hex_exp = 0x0.fp1lr; // expected-error{{this value is too large for this fixed point type}} +unsigned short _Fract u_short_fract_hex_exp = 0x0.fp1uhr; // expected-error{{this value is too large for this fixed point type}} +unsigned _Fract u_fract_hex_exp = 0x0.fp1ur; // expected-error{{this value is too large for this fixed point type}} +unsigned long _Fract u_long_fract_hex_exp = 0x0.fp1ulr; // expected-error{{this value is too large for this fixed point type}} + /* Do not allow typedef to be used with typedef'd types */ typedef short _Fract shortfract_t; typedef short _Accum shortaccum_t; @@ -91,3 +135,16 @@ _Sat fract_t td_sat_fract; // expected-error{{'_Sat' specifier _Sat accum_t td_sat_accum; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'type-name'}} _Sat longfract_t td_sat_long_fract; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'type-name'}} _Sat longaccum_t td_sat_long_accum; // expected-error{{'_Sat' specifier is only valid on '_Fract' or '_Accum', not 'type-name'}} + +/* Bad suffixes */ +_Accum fk = 1.0fk; // expected-error{{invalid suffix 'fk' on integer constant}} +_Accum kk = 1.0kk; // expected-error{{invalid suffix 'kk' on integer constant}} +_Accum rk = 1.0rk; // expected-error{{invalid suffix 'rk' on integer constant}} +_Accum rk = 1.0rr; // expected-error{{invalid suffix 'rr' on integer constant}} +_Accum qk = 1.0qr; // expected-error{{invalid suffix 'qr' on integer constant}} + +/* Using wrong exponent notation */ +_Accum dec_with_hex_exp1 = 0.1p10k; // expected-error{{invalid suffix 'p10k' on integer constant}} +_Accum dec_with_hex_exp2 = 0.1P10k; // expected-error{{invalid suffix 'P10k' on integer constant}} +_Accum hex_with_dex_exp1 = 0x0.1e10k; // expected-error{{hexadecimal floating constant requires an exponent}} +_Accum hex_with_dex_exp2 = 0x0.1E10k; // expected-error{{hexadecimal floating constant requires an exponent}} diff --git a/clang/test/Frontend/fixed_point_same_fbits.c b/clang/test/Frontend/fixed_point_same_fbits.c new file mode 100644 index 0000000..ad88d1a --- /dev/null +++ b/clang/test/Frontend/fixed_point_same_fbits.c @@ -0,0 +1,28 @@ +// RUN: %clang -ffixed-point -S -emit-llvm -o - %s | FileCheck %s -check-prefix=DEFAULT +// RUN: %clang -ffixed-point -fsame-fbits -S -emit-llvm -o - %s | FileCheck %s -check-prefix=SAME + +/* The scale for unsigned fixed point types should be the same as that of signed + * fixed point types when -fsame-fbits is enabled. */ + +void func() { + unsigned short _Accum u_short_accum = 0.5uhk; + unsigned _Accum u_accum = 0.5uk; + unsigned long _Accum u_long_accum = 0.5ulk; + unsigned short _Fract u_short_fract = 0.5uhr; + unsigned _Fract u_fract = 0.5ur; + unsigned long _Fract u_long_fract = 0.5ulr; + +// DEFAULT: store i16 128, i16* %u_short_accum, align 2 +// DEFAULT: store i32 32768, i32* %u_accum, align 4 +// DEFAULT: store i64 2147483648, i64* %u_long_accum, align 8 +// DEFAULT: store i8 -128, i8* %u_short_fract, align 1 +// DEFAULT: store i16 -32768, i16* %u_fract, align 2 +// DEFAULT: store i32 -2147483648, i32* %u_long_fract, align 4 + +// SAME: store i16 64, i16* %u_short_accum, align 2 +// SAME: store i32 16384, i32* %u_accum, align 4 +// SAME: store i64 1073741824, i64* %u_long_accum, align 8 +// SAME: store i8 64, i8* %u_short_fract, align 1 +// SAME: store i16 16384, i16* %u_fract, align 2 +// SAME: store i32 1073741824, i32* %u_long_fract, align 4 +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 1c291d7..c2aac1f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -5061,6 +5061,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("VariableRef"); case CXCursor_IntegerLiteral: return cxstring::createRef("IntegerLiteral"); + case CXCursor_FixedPointLiteral: + return cxstring::createRef("FixedPointLiteral"); case CXCursor_FloatingLiteral: return cxstring::createRef("FloatingLiteral"); case CXCursor_ImaginaryLiteral: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index bce9351..b4ad059 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -305,6 +305,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, K = CXCursor_IntegerLiteral; break; + case Stmt::FixedPointLiteralClass: + K = CXCursor_FixedPointLiteral; + break; + case Stmt::FloatingLiteralClass: K = CXCursor_FloatingLiteral; break; -- 2.7.4