Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -2170,7 +2170,12 @@ */ CXCursor_ObjCAvailabilityCheckExpr = 148, - CXCursor_LastExpr = CXCursor_ObjCAvailabilityCheckExpr, + /** + * Fixed point literal + */ + CXCursor_FixedPointLiteral = 149, + + CXCursor_LastExpr = CXCursor_FixedPointLiteral, /* Statements */ CXCursor_FirstStmt = 200, Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1947,6 +1947,9 @@ return getQualifiedType(type.getUnqualifiedType(), Qs); } + unsigned char getFixedPointScale(QualType Ty) const; + unsigned char getFixedPointIBits(QualType Ty) const; + DeclarationNameInfo getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const; Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -1351,6 +1351,47 @@ } }; +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 { Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -2585,6 +2585,7 @@ // 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, {}) Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ 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 @@ 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 Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -168,6 +168,8 @@ 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">; Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -305,6 +305,8 @@ 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 Index: include/clang/Basic/StmtNodes.td =================================================================== --- include/clang/Basic/StmtNodes.td +++ include/clang/Basic/StmtNodes.td @@ -57,6 +57,7 @@ def PredefinedExpr : DStmt; def DeclRefExpr : DStmt; def IntegerLiteral : DStmt; +def FixedPointLiteral : DStmt; def FloatingLiteral : DStmt; def ImaginaryLiteral : DStmt; def StringLiteral : DStmt; Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -74,12 +74,32 @@ 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 @@ 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 @@ 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 Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -893,6 +893,10 @@ 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. Index: include/clang/Lex/LiteralSupport.h =================================================================== --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -50,7 +50,7 @@ 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 @@ 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 @@ /// 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); Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -10162,3 +10162,92 @@ 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; + } +} Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -525,6 +525,7 @@ 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 @@ 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); Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -755,6 +755,36 @@ 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 @@ case ObjCIvarRefExprClass: case PredefinedExprClass: case IntegerLiteralClass: + case FixedPointLiteralClass: case FloatingLiteralClass: case ImaginaryLiteralClass: case StringLiteralClass: Index: lib/AST/ExprClassification.cpp =================================================================== --- lib/AST/ExprClassification.cpp +++ lib/AST/ExprClassification.cpp @@ -161,6 +161,7 @@ case Expr::ShuffleVectorExprClass: case Expr::ConvertVectorExprClass: case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::AddrLabelExprClass: case Expr::CXXDeleteExprClass: Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -7220,6 +7220,73 @@ // 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 @@ 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 @@ 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 @@ case Expr::GenericSelectionExprClass: return CheckICE(cast(E)->getResultExpr(), Ctx); case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::CharacterLiteralClass: case Expr::ObjCBoolLiteralExprClass: case Expr::CXXBoolLiteralExprClass: Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -3503,6 +3503,7 @@ 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. Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -1529,6 +1529,28 @@ } } +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; Index: lib/AST/StmtProfile.cpp =================================================================== --- lib/AST/StmtProfile.cpp +++ lib/AST/StmtProfile.cpp @@ -1007,6 +1007,12 @@ 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()); Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -3986,3 +3986,19 @@ 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()); +} Index: lib/Basic/TargetInfo.cpp =================================================================== --- lib/Basic/TargetInfo.cpp +++ lib/Basic/TargetInfo.cpp @@ -40,12 +40,24 @@ 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 @@ 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 @@ 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()); +} Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -652,5 +652,7 @@ if (!Target->validateTarget(Diags)) return nullptr; + Target->CheckFixedPointBits(); + return Target.release(); } Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -684,12 +684,12 @@ 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()) { Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -387,6 +387,9 @@ 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()); } Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -3766,6 +3766,11 @@ /*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). // Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2338,6 +2338,10 @@ 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, Index: lib/Lex/LiteralSupport.cpp =================================================================== --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -538,6 +538,7 @@ 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 @@ isFloat16 = false; isFloat128 = false; MicrosoftInteger = 0; + isFract = false; + isAccum = false; hadError = false; if (*s == '0') { // parse radix @@ -568,6 +571,14 @@ 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 @@ // 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 @@ isHalf = false; isImaginary = false; MicrosoftInteger = 0; + saw_fixed_point_suffix = false; + isFract = false; + isAccum = false; } saw_ud_suffix = true; @@ -707,6 +731,11 @@ 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 @@ 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 Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1258,6 +1258,7 @@ case Expr::ImaginaryLiteralClass: case Expr::ImplicitValueInitExprClass: case Expr::IntegerLiteralClass: + case Expr::FixedPointLiteralClass: case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::ObjCEncodeExprClass: Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3326,7 +3326,52 @@ 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 @@ 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(); Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -8888,6 +8888,12 @@ return E; } +template +ExprResult TreeTransform::TransformFixedPointLiteral( + FixedPointLiteral *E) { + return E; +} + template ExprResult TreeTransform::TransformFloatingLiteral(FloatingLiteral *E) { Index: lib/Serialization/ASTReaderStmt.cpp =================================================================== --- lib/Serialization/ASTReaderStmt.cpp +++ lib/Serialization/ASTReaderStmt.cpp @@ -533,6 +533,12 @@ 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())); Index: lib/Serialization/ASTWriterStmt.cpp =================================================================== --- lib/Serialization/ASTWriterStmt.cpp +++ lib/Serialization/ASTWriterStmt.cpp @@ -444,6 +444,13 @@ 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()); Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1297,6 +1297,7 @@ case Stmt::AddrLabelExprClass: case Stmt::AttributedStmtClass: case Stmt::IntegerLiteralClass: + case Stmt::FixedPointLiteralClass: case Stmt::CharacterLiteralClass: case Stmt::ImplicitValueInitExprClass: case Stmt::CXXScalarValueInitExprClass: Index: test/Frontend/fixed_point.c =================================================================== --- test/Frontend/fixed_point.c +++ test/Frontend/fixed_point.c @@ -236,4 +236,164 @@ //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 Index: test/Frontend/fixed_point_bit_widths.c =================================================================== --- test/Frontend/fixed_point_bit_widths.c +++ test/Frontend/fixed_point_bit_widths.c @@ -44,12 +44,12 @@ 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_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_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_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_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_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 Index: test/Frontend/fixed_point_declarations.c =================================================================== --- /dev/null +++ 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 Index: test/Frontend/fixed_point_errors.c =================================================================== --- test/Frontend/fixed_point_errors.c +++ test/Frontend/fixed_point_errors.c @@ -78,6 +78,50 @@ _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 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}} Index: test/Frontend/fixed_point_same_fbits.c =================================================================== --- /dev/null +++ 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 +} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -5061,6 +5061,8 @@ 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: Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -305,6 +305,10 @@ K = CXCursor_IntegerLiteral; break; + case Stmt::FixedPointLiteralClass: + K = CXCursor_FixedPointLiteral; + break; + case Stmt::FloatingLiteralClass: K = CXCursor_FloatingLiteral; break;