Index: CMakeLists.txt =================================================================== --- CMakeLists.txt +++ CMakeLists.txt @@ -324,6 +324,8 @@ ${CMAKE_CURRENT_SOURCE_DIR}/include/clang/Basic/Version.inc.in ${CMAKE_CURRENT_BINARY_DIR}/include/clang/Basic/Version.inc) +include(InitFixedPointBits) + # Add appropriate flags for GCC if (LLVM_COMPILER_IS_GCC_COMPATIBLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual") Index: cmake/modules/InitFixedPointBits.cmake =================================================================== --- /dev/null +++ cmake/modules/InitFixedPointBits.cmake @@ -0,0 +1,88 @@ +# Set default values of fixed point types for typical desktop processors i +# described in ISO/IEC JTC1 SC22 WG14 N1169 +# Fractional bits of _Accum types +if(NOT DEFINED SACCUM_FBIT) + set(SACCUM_FBIT 7) +endif() +if(NOT DEFINED ACCUM_FBIT) + set(ACCUM_FBIT 15) +endif() +if(NOT DEFINED LACCUM_FBIT) + set(LACCUM_FBIT 31) +endif() +if(NOT DEFINED USACCUM_FBIT) + set(USACCUM_FBIT 8) +endif() +if(NOT DEFINED UACCUM_FBIT) + set(UACCUM_FBIT 16) +endif() +if(NOT DEFINED ULACCUM_FBIT) + set(ULACCUM_FBIT 32) +endif() + +# Fractional bits of _Fract types +if(NOT DEFINED SFRACT_FBIT) + set(SFRACT_FBIT 7) +endif() +if(NOT DEFINED FRACT_FBIT) + set(FRACT_FBIT 15) +endif() +if(NOT DEFINED LFRACT_FBIT) + set(LFRACT_FBIT 31) +endif() +if(NOT DEFINED USFRACT_FBIT) + set(USFRACT_FBIT 8) +endif() +if(NOT DEFINED UFRACT_FBIT) + set(UFRACT_FBIT 16) +endif() +if(NOT DEFINED ULFRACT_FBIT) + set(ULFRACT_FBIT 32) +endif() + +# Integral bits of _Accum types +if(NOT DEFINED SACCUM_IBIT) + set(SACCUM_IBIT 8) +endif() +if(NOT DEFINED ACCUM_IBIT) + set(ACCUM_IBIT 16) +endif() +if(NOT DEFINED LACCUM_IBIT) + set(LACCUM_IBIT 32) +endif() +if(NOT DEFINED USACCUM_IBIT) + set(USACCUM_IBIT 8) +endif() +if(NOT DEFINED UACCUM_IBIT) + set(UACCUM_IBIT 16) +endif() +if(NOT DEFINED ULACCUM_IBIT) + set(ULACCUM_IBIT 32) +endif() + +# Checks for each bit size +# Each unsigned fract type has either the same number of fractional bits as, +# or one more fractional bit than, its corresponding signed fract type. +# TODO: Implement remaining checks in clause 6.2.6.3. +function(check_diff_at_most_1 sfract_fbits ufract_fbits) + if(sfract_fbits EQUAL ufract_fbits) + return() + endif() + math(EXPR diff "${ufract_fbits} - ${sfract_fbits}") + if(diff EQUAL 1) + return() + endif() + message(FATAL_ERROR "Each unsigned fract type has either the same number of " + "fractional bits as, or one more fractional bit than, its corresponding " + "signed fract type.") +endfunction() + +check_diff_at_most_1(${SFRACT_FBIT} ${USFRACT_FBIT}) +check_diff_at_most_1(${FRACT_FBIT} ${UFRACT_FBIT}) +check_diff_at_most_1(${LFRACT_FBIT} ${ULFRACT_FBIT}) + +# Configure the FixedPoint.h file. +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/include/clang/Basic/FixedPoint.h.in + ${CMAKE_CURRENT_BINARY_DIR}/include/clang/Basic/FixedPoint.h) + Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -1344,6 +1344,43 @@ } }; +class FixedPointLiteral : public Expr, public APIntStorage { + SourceLocation Loc; + + /// \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); + + // Store the int as is without any bit shifting. + static FixedPointLiteral *CreateFromRawInt(const ASTContext &C, + const llvm::APInt &V, + QualType type, SourceLocation l); + + 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; + } + + // 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/OperationKinds.def =================================================================== --- include/clang/AST/OperationKinds.def +++ include/clang/AST/OperationKinds.def @@ -197,6 +197,10 @@ /// float f = i; CAST_OPERATION(IntegralToFloating) +/// CK_IntegralToFixedPoint - Integral to fixed point. +/// (short _Accum) i; +CAST_OPERATION(IntegralToFixedPoint) + /// CK_FloatingToIntegral - Floating point to integral. Rounds /// towards zero, discarding any fractional component. /// (int) f 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 @@ -1916,7 +1916,8 @@ STK_Integral, STK_Floating, STK_IntegralComplex, - STK_FloatingComplex + STK_FloatingComplex, + STK_FixedPoint }; /// Given that this is a scalar type, classify it. @@ -2106,6 +2107,22 @@ /// enumeration types whose underlying type is a unsigned integer type. bool isUnsignedIntegerOrEnumerationType() const; + // Return true if this is a fixed point type according to ISO/IEC JTC1 SC22 + // WG14 N1169. + bool isFixedPointType() const; + + // Return true if this is a saturated fixed point type according to + // ISO/IEC JTC1 SC22 WG14 N1169. + bool isSaturatedFixedPointType() const; + + // Return true if this is a fixed point type that is signed according + // to ISO/IEC JTC1 SC22 WG14 N1169. [short _Fract, _Accum, long _Fract...] + bool isSignedFixedPointType() const; + + // Return true if this is a fixed point type that is unsigned according + // to ISO/IEC JTC1 SC22 WG14 N1169. + bool isUnsignedFixedPointType() const; + /// Return true if this is not a variable sized type, /// according to the rules of C99 6.7.5p3. It is not legal to call this on /// incomplete types. @@ -6286,6 +6303,50 @@ return false; } +inline bool Type::isFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return BT->getKind() >= BuiltinType::ShortAccum && + BT->getKind() <= BuiltinType::SatULongFract; + } + return false; +} + +inline bool Type::isSaturatedFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return BT->getKind() >= BuiltinType::SatShortAccum && + BT->getKind() <= BuiltinType::SatULongFract; + } + return false; +} + +inline bool Type::isSignedFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return ((BT->getKind() >= BuiltinType::ShortAccum && + BT->getKind() <= BuiltinType::LongAccum) || + (BT->getKind() >= BuiltinType::ShortFract && + BT->getKind() <= BuiltinType::LongFract) || + (BT->getKind() >= BuiltinType::SatShortAccum && + BT->getKind() <= BuiltinType::SatLongAccum) || + (BT->getKind() >= BuiltinType::SatShortFract && + BT->getKind() <= BuiltinType::SatLongFract)); + } + return false; +} + +inline bool Type::isUnsignedFixedPointType() const { + if (const auto *BT = dyn_cast(CanonicalType)) { + return ((BT->getKind() >= BuiltinType::UShortAccum && + BT->getKind() <= BuiltinType::ULongAccum) || + (BT->getKind() >= BuiltinType::UShortFract && + BT->getKind() <= BuiltinType::ULongFract) || + (BT->getKind() >= BuiltinType::SatUShortAccum && + BT->getKind() <= BuiltinType::SatULongAccum) || + (BT->getKind() >= BuiltinType::SatUShortFract && + BT->getKind() <= BuiltinType::SatULongFract)); + } + return false; +} + inline bool Type::isScalarType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() > BuiltinType::Void && Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -168,6 +168,11 @@ InGroup; def ext_clang_diagnose_if : Extension<"'diagnose_if' is a clang extension">, InGroup; +def err_integral_part_on_fract : Error<"a _Fract type cannot have an " + "integral part">; +def err_integral_part_of_accum_too_large : Error< + "the integral part of this literal is too large for this " + "%select{signed|unsigned}0 _Accum type">; def err_fixed_point_only_allowed_in_c : Error< "Fixed point types are only allowed in C">; Index: include/clang/Basic/FixedPoint.h.in =================================================================== --- /dev/null +++ include/clang/Basic/FixedPoint.h.in @@ -0,0 +1,28 @@ +#ifndef LLVM_CLANG_BASIC_FIXEDPOINT_H +#define LLVM_CLANG_BASIC_FIXEDPOINT_H + +// Fractional bits of _Accum types +#define BUILTIN_SACCUM_FBIT @SACCUM_FBIT@ +#define BUILTIN_ACCUM_FBIT @ACCUM_FBIT@ +#define BUILTIN_LACCUM_FBIT @LACCUM_FBIT@ +#define BUILTIN_USACCUM_FBIT @USACCUM_FBIT@ +#define BUILTIN_UACCUM_FBIT @UACCUM_FBIT@ +#define BUILTIN_ULACCUM_FBIT @ULACCUM_FBIT@ + +// Fractional bits of _Fract types +#define BUILTIN_SFRACT_FBIT @SFRACT_FBIT@ +#define BUILTIN_FRACT_FBIT @FRACT_FBIT@ +#define BUILTIN_LFRACT_FBIT @LFRACT_FBIT@ +#define BUILTIN_USFRACT_FBIT @USFRACT_FBIT@ +#define BUILTIN_UFRACT_FBIT @UFRACT_FBIT@ +#define BUILTIN_ULFRACT_FBIT @ULFRACT_FBIT@ + +// Integral bits of _Accum types +#define BUILTIN_SACCUM_IBIT @SACCUM_IBIT@ +#define BUILTIN_ACCUM_IBIT @ACCUM_IBIT@ +#define BUILTIN_LACCUM_IBIT @LACCUM_IBIT@ +#define BUILTIN_USACCUM_IBIT @USACCUM_IBIT@ +#define BUILTIN_UACCUM_IBIT @UACCUM_IBIT@ +#define BUILTIN_ULACCUM_IBIT @ULACCUM_IBIT@ + +#endif 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/Lex/LiteralSupport.h =================================================================== --- include/clang/Lex/LiteralSupport.h +++ include/clang/Lex/LiteralSupport.h @@ -69,6 +69,17 @@ bool isFloat128 : 1; // 1.0q uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. + enum FixedPointType { FPT_UNSPECIFIED, FPT_ACCUM, FPT_FRACT }; + + // We use separate fields for fixed point sizes b/c the isHalf/isLong booleans + // assume that this literal is an integral type instead of fixed point type. + enum FixedPointSize { FPS_UNSPECIFIED, FPS_SHORT, FPS_LONG }; + + enum FixedPointType fixedPointType; + enum FixedPointSize fixedPointSize; + + bool isFixedPointLiteral() const { return fixedPointType != FPT_UNSPECIFIED; } + bool isIntegerLiteral() const { return !saw_period && !saw_exponent; } @@ -157,7 +168,6 @@ ptr++; return ptr; } - }; /// CharLiteralParser - Perform interpretation and semantic analysis of a Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1785,6 +1785,8 @@ case BuiltinType::Short: case BuiltinType::ShortAccum: case BuiltinType::UShortAccum: + case BuiltinType::ShortFract: + case BuiltinType::UShortFract: Width = Target->getShortWidth(); Align = Target->getShortAlign(); break; @@ -1792,6 +1794,8 @@ case BuiltinType::Int: case BuiltinType::Accum: case BuiltinType::UAccum: + case BuiltinType::Fract: + case BuiltinType::UFract: Width = Target->getIntWidth(); Align = Target->getIntAlign(); break; @@ -1799,6 +1803,8 @@ case BuiltinType::Long: case BuiltinType::LongAccum: case BuiltinType::ULongAccum: + case BuiltinType::LongFract: + case BuiltinType::ULongFract: Width = Target->getLongWidth(); Align = Target->getLongAlign(); break; 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,14 @@ OS << " " << Node->getValue().toString(10, isSigned); } +void ASTDumper::VisitFixedPointLiteral(const FixedPointLiteral *Node) { + VisitExpr(Node); + + bool isSigned = Node->getType()->isSignedFixedPointType(); + ColorScope Color(*this, ValueColor); + OS << " " << Node->getValue().toString(10, isSigned); +} + 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,50 @@ return new (C) IntegerLiteral(Empty); } +FixedPointLiteral::FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l) + : Expr(FixedPointLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false, false), + Loc(l) { + assert(type->isFixedPointType() && "Illegal type in FixedPointLiteral"); + + const auto *BT = type->getAs(); + assert(BT && "Not a fixed point type!"); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + case BuiltinType::UShortAccum: + case BuiltinType::ShortFract: + case BuiltinType::UShortFract: + assert(V.getBitWidth() == C.getIntWidth(type) && + "Short fixed point type is not the correct size for constant."); + break; + case BuiltinType::Accum: + case BuiltinType::UAccum: + case BuiltinType::Fract: + case BuiltinType::UFract: + assert(V.getBitWidth() == C.getIntWidth(type) && + "Fixed point type is not the correct size for constant."); + break; + case BuiltinType::LongAccum: + case BuiltinType::ULongAccum: + case BuiltinType::LongFract: + case BuiltinType::ULongFract: + assert(V.getBitWidth() == C.getIntWidth(type) && + "Long fixed point type is not the correct size for constant."); + break; + } + setValue(C, V); +} + +FixedPointLiteral *FixedPointLiteral::CreateFromRawInt(const ASTContext &C, + const llvm::APInt &V, + QualType type, + SourceLocation l) { + return new (C) FixedPointLiteral(C, V, type, l); +} + FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V, bool isexact, QualType Type, SourceLocation L) : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, @@ -1609,6 +1653,7 @@ case CK_ZeroToOCLEvent: case CK_ZeroToOCLQueue: case CK_IntToOCLSampler: + case CK_IntegralToFixedPoint: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; @@ -2990,6 +3035,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 @@ -7209,6 +7209,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 @@ -9060,6 +9127,9 @@ QualType SrcType = SubExpr->getType(); switch (E->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "IntExprEvaluator::VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_BaseToDerived: case CK_DerivedToBase: case CK_UncheckedDerivedToBase: @@ -9236,6 +9306,39 @@ return Success(E->getValue(), E); } +bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + switch (E->getOpcode()) { + default: + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + 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() && + !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1), + E->getType())) + return false; + return Success(-Value, E); + } + case UO_Not: { + if (!Visit(E->getSubExpr())) return false; + if (!Result.isInt()) return Error(E); + return Success(~Result.getInt(), E); + } + case UO_LNot: { + bool bres; + if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info)) + return false; + return Success(!bres, E); + } + } +} + //===----------------------------------------------------------------------===// // Float Evaluation //===----------------------------------------------------------------------===// @@ -9553,6 +9656,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "ComplexExprEvaluator::VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_BitCast: case CK_BaseToDerived: case CK_DerivedToBase: @@ -10087,6 +10193,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)) @@ -10523,6 +10631,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 @@ -3437,6 +3437,8 @@ recurse: switch (E->getStmtClass()) { + case Expr::FixedPointLiteralClass: + llvm_unreachable("Unknown mangling for FixedPointLiteralClass"); case Expr::NoStmtClass: #define ABSTRACT_STMT(Type) #define EXPR(Type, Base) Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -1525,6 +1525,54 @@ } } +void StmtPrinter::VisitFixedPointLiteral(FixedPointLiteral *Node) { + if (Policy.ConstantsAsWritten && printExprAsWritten(OS, Node, Context)) + return; + bool isSigned = Node->getType()->isSignedFixedPointType(); + OS << Node->getValue().toString(10, isSigned); + + 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 @@ -1929,6 +1929,7 @@ if (BT->getKind() == BuiltinType::NullPtr) return STK_CPointer; if (BT->isInteger()) return STK_Integral; if (BT->isFloatingPoint()) return STK_Floating; + if (BT->isFixedPointType()) return STK_FixedPoint; llvm_unreachable("unknown scalar builtin type"); } else if (isa(T)) { return STK_CPointer; Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -4044,6 +4044,9 @@ /// cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { switch (E->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "CodeGenFunction::EmitCastLValue CK_IntegralToFixedPoint"); // TODO case CK_ToVoid: case CK_BitCast: case CK_ArrayToPointerDecay: Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -671,6 +671,9 @@ if (const auto *ECE = dyn_cast(E)) CGF.CGM.EmitExplicitCastExprType(ECE, &CGF); switch (E->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "AggExprEmitter::VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_Dynamic: { // FIXME: Can this actually happen? We have no test coverage for it. assert(isa(E) && "CK_Dynamic without a dynamic_cast?"); @@ -681,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/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -446,6 +446,9 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op, QualType DestTy) { switch (CK) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "ComplexExprEmitter::EmitCast CK_IntegralToFixedPoint"); // TODO case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!"); // Atomic to non-atomic casts may be more than a no-op for some platforms and Index: lib/CodeGen/CGExprConstant.cpp =================================================================== --- lib/CodeGen/CGExprConstant.cpp +++ lib/CodeGen/CGExprConstant.cpp @@ -686,6 +686,8 @@ Expr *subExpr = E->getSubExpr(); switch (E->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable("VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_ToUnion: { // GCC cast to union extension assert(E->getType()->isUnionType() && Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -23,6 +23,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/Optional.h" @@ -387,6 +388,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()); } @@ -1772,6 +1776,58 @@ return Builder.CreateVectorSplat(NumElements, Elt, "splat"); } + case CK_IntegralToFixedPoint: { + assert(DestTy->isFixedPointType()); + assert(E->getType()->isIntegerType()); + + unsigned fbits; + const auto *BT = DestTy->getAs(); + switch (BT->getKind()) { + default: + llvm_unreachable("Not a fixed point type!"); + case BuiltinType::ShortAccum: + fbits = BUILTIN_SACCUM_FBIT; + break; + case BuiltinType::Accum: + fbits = BUILTIN_ACCUM_FBIT; + break; + case BuiltinType::LongAccum: + fbits = BUILTIN_LACCUM_FBIT; + break; + case BuiltinType::UShortAccum: + fbits = BUILTIN_USACCUM_FBIT; + break; + case BuiltinType::UAccum: + fbits = BUILTIN_UACCUM_FBIT; + break; + case BuiltinType::ULongAccum: + fbits = BUILTIN_ULACCUM_FBIT; + break; + case BuiltinType::ShortFract: + fbits = BUILTIN_SFRACT_FBIT; + break; + case BuiltinType::Fract: + fbits = BUILTIN_FRACT_FBIT; + break; + case BuiltinType::LongFract: + fbits = BUILTIN_LFRACT_FBIT; + break; + case BuiltinType::UShortFract: + fbits = BUILTIN_USFRACT_FBIT; + break; + case BuiltinType::UFract: + fbits = BUILTIN_UFRACT_FBIT; + break; + case BuiltinType::ULongFract: + fbits = BUILTIN_ULFRACT_FBIT; + break; + } + + return Builder.CreateShl( + EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()), + fbits, "fixed_point_shl"); + } + case CK_IntegralCast: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: lib/Edit/RewriteObjCFoundationAPI.cpp =================================================================== --- lib/Edit/RewriteObjCFoundationAPI.cpp +++ lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1002,6 +1002,9 @@ if (const ImplicitCastExpr *ICE = dyn_cast(Arg)) { switch (ICE->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "rewriteToNumericBoxedExpression CK_IntegralToFixedPoint"); // TODO case CK_LValueToRValue: case CK_NoOp: case CK_UserDefinedConversion: Index: lib/Lex/LiteralSupport.cpp =================================================================== --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -547,6 +547,8 @@ isFloat16 = false; isFloat128 = false; MicrosoftInteger = 0; + fixedPointType = FPT_UNSPECIFIED; + fixedPointSize = FPS_UNSPECIFIED; hadError = false; if (*s == '0') { // parse radix @@ -572,12 +574,40 @@ // integer constant. bool isFPConstant = isFloatingLiteral(); + // Initial scan to lookahead for fixed point suffix. If we find one, we can + // ignore some of the rules that break in association with isFPConstant since + // fixed point types can be provided as decimals. + bool treatFPConstantAsFixedPoint = false; + for (const char *c = s; c != ThisTokEnd; ++c) { + if (*c == 'r' || *c == 'k' || *c == 'R' || *c == 'K') { + treatFPConstantAsFixedPoint = true; + break; + } + } + // Loop over all of the characters of the suffix. If we see something bad, // we break out of the loop. for (; s != ThisTokEnd; ++s) { switch (*s) { + case 'R': + case 'r': + if (fixedPointType != FPT_UNSPECIFIED) break; // Cannot repeat + fixedPointType = FPT_FRACT; + continue; + case 'K': + case 'k': + if (fixedPointType != FPT_UNSPECIFIED) break; // Cannot repeat + fixedPointType = FPT_ACCUM; + continue; case 'h': // FP Suffix for "half". case 'H': + // Floating point instances for fixed point types (hr, hk) + if (treatFPConstantAsFixedPoint) { + if (fixedPointSize != FPS_UNSPECIFIED) break; + fixedPointSize = FPS_SHORT; + continue; + } + // 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. @@ -607,12 +637,24 @@ continue; // Success. case 'u': case 'U': + if (treatFPConstantAsFixedPoint) { + if (isUnsigned) break; // Cannot repeat + isUnsigned = true; + continue; + } + if (isFPConstant) break; // Error for floating constant. if (isUnsigned) break; // Cannot be repeated. isUnsigned = true; continue; // Success. case 'l': case 'L': + if (treatFPConstantAsFixedPoint) { + if (fixedPointSize != FPS_UNSPECIFIED) break; // Cannot repeat + fixedPointSize = FPS_LONG; + continue; + } + if (isLong || isLongLong) break; // Cannot be repeated. if (isHalf || isFloat || isFloat128) break; // LH, LF, LQ invalid. Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -529,6 +529,9 @@ case Type::STK_Floating: return CK_FloatingToBoolean; case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean; case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean; + case Type::STK_FixedPoint: + llvm_unreachable( + "Sema::ScalarTypeToBooleanCastKind for fixed point"); // TODO } llvm_unreachable("unknown scalar type kind"); } Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -1294,6 +1294,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 @@ -26,6 +26,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/FixedPoint.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -1217,6 +1218,46 @@ CK_IntegralRealToComplex); return ComplexType; } +/// \brief Handle arithmetic conversion from integer to fixed point. Helper +/// function of UsualArithmeticConversions() +static QualType handleIntToFixedPointConversion(Sema &S, + ExprResult &FixedPointExpr, + ExprResult &IntExpr, + QualType FixedPointTy, + QualType IntTy) { + assert(IntTy->isIntegerType()); + assert(FixedPointTy->isFixedPointType()); + + IntExpr = + S.ImpCastExprToType(IntExpr.get(), FixedPointTy, CK_IntegralToFixedPoint); + return FixedPointTy; +} + +/// \brief Handle arithmethic conversion with fixed point types. Helper +/// function of UsualArithmeticConversions(). +static QualType handleFixedPointConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, + bool IsCompAssign) { + // At this point, the only other type we should be able to convert to is + // integer types since all prior types were handled beforehand in + // UsualArithmeticConventions(). + bool LHSFixed = LHSType->isFixedPointType(); + bool RHSFixed = RHSType->isFixedPointType(); + + if (LHSFixed && RHSFixed) { + // Cast up the smaller operand to the bigger + llvm_unreachable("Unhandled conversion between fixed point types"); // TODO + } else if (LHSFixed) { + assert(RHSType->isIntegerType()); + return handleIntToFixedPointConversion(S, LHS, RHS, LHSType, RHSType); + } else if (RHSFixed) { + assert(LHSType->isIntegerType()); + return handleIntToFixedPointConversion(S, RHS, LHS, RHSType, LHSType); + } else { + llvm_unreachable("Expected LHS and RHS to both be fixed point types."); + } +} /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this @@ -1290,6 +1331,12 @@ return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, IsCompAssign); + // Handle floating point types + if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) { + return handleFixedPointConversion(*this, LHS, RHS, LHSType, RHSType, + IsCompAssign); + } + // Finally, we have two differing integer types. return handleIntegerConversion (*this, LHS, RHS, LHSType, RHSType, IsCompAssign); @@ -3139,33 +3186,40 @@ Context.IntTy, Loc); } -static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal, - QualType Ty, SourceLocation Loc) { - const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty); - - using llvm::APFloat; - APFloat Val(Format); - - APFloat::opStatus result = Literal.GetFloatValue(Val); - +static void HandleFloatOverflow(Sema &S, QualType Ty, SourceLocation Loc, + const llvm::APFloat::opStatus &result, + const llvm::APFloat &Val, + const llvm::fltSemantics &Format) { // Overflow is always an error, but underflow is only an error if // we underflowed to zero (APFloat reports denormals as underflow). - if ((result & APFloat::opOverflow) || - ((result & APFloat::opUnderflow) && Val.isZero())) { + if ((result & llvm::APFloat::opOverflow) || + ((result & llvm::APFloat::opUnderflow) && Val.isZero())) { unsigned diagnostic; SmallString<20> buffer; - if (result & APFloat::opOverflow) { + if (result & llvm::APFloat::opOverflow) { diagnostic = diag::warn_float_overflow; - APFloat::getLargest(Format).toString(buffer); + llvm::APFloat::getLargest(Format).toString(buffer); } else { diagnostic = diag::warn_float_underflow; - APFloat::getSmallest(Format).toString(buffer); + llvm::APFloat::getSmallest(Format).toString(buffer); } S.Diag(Loc, diagnostic) << Ty << StringRef(buffer.data(), buffer.size()); } +} + +static Expr *BuildFloatingLiteral(Sema &S, NumericLiteralParser &Literal, + QualType Ty, SourceLocation Loc) { + const llvm::fltSemantics &Format = S.Context.getFloatTypeSemantics(Ty); + + using llvm::APFloat; + APFloat Val(Format); + + APFloat::opStatus result = Literal.GetFloatValue(Val); + + HandleFloatOverflow(S, Ty, Loc, result, Val, Format); bool isExact = (result == APFloat::opOK); return FloatingLiteral::Create(S.Context, Val, isExact, Ty, Loc); @@ -3321,7 +3375,164 @@ Expr *Res; - if (Literal.isFloatingLiteral()) { + if (Literal.isFixedPointLiteral()) { + constexpr auto FPS_UNSPECIFIED = NumericLiteralParser::FPS_UNSPECIFIED; + constexpr auto FPS_SHORT = NumericLiteralParser::FPS_SHORT; + constexpr auto FPS_LONG = NumericLiteralParser::FPS_LONG; + constexpr auto FPT_ACCUM = NumericLiteralParser::FPT_ACCUM; + constexpr auto FPT_FRACT = NumericLiteralParser::FPT_FRACT; + + QualType floatingTy = Context.DoubleTy; + const llvm::fltSemantics &Format = + Context.getFloatTypeSemantics(floatingTy); + bool isSigned = !Literal.isUnsigned; + + unsigned fbits; + unsigned ibits = 0; // Defaults to 0 for _Fract type + unsigned bit_width; + QualType Ty; + + switch (Literal.fixedPointSize) { + case FPS_UNSPECIFIED: + bit_width = Context.getTargetInfo().getIntWidth(); + break; + case FPS_SHORT: + bit_width = Context.getTargetInfo().getShortWidth(); + break; + case FPS_LONG: + bit_width = Context.getTargetInfo().getLongWidth(); + break; + } + + if (Literal.fixedPointType == FPT_ACCUM) { + if (isSigned) { + switch (Literal.fixedPointSize) { + case FPS_UNSPECIFIED: + fbits = BUILTIN_ACCUM_FBIT; + ibits = BUILTIN_ACCUM_IBIT; + Ty = Context.AccumTy; + break; + case FPS_SHORT: + fbits = BUILTIN_SACCUM_FBIT; + ibits = BUILTIN_SACCUM_IBIT; + Ty = Context.ShortAccumTy; + break; + case FPS_LONG: + fbits = BUILTIN_LACCUM_FBIT; + ibits = BUILTIN_LACCUM_IBIT; + Ty = Context.LongAccumTy; + break; + } + } else { + switch (Literal.fixedPointSize) { + case FPS_UNSPECIFIED: + fbits = BUILTIN_UACCUM_FBIT; + ibits = BUILTIN_UACCUM_IBIT; + Ty = Context.UnsignedAccumTy; + break; + case FPS_SHORT: + fbits = BUILTIN_USACCUM_FBIT; + ibits = BUILTIN_USACCUM_IBIT; + Ty = Context.UnsignedShortAccumTy; + break; + case FPS_LONG: + fbits = BUILTIN_ULACCUM_FBIT; + ibits = BUILTIN_ULACCUM_IBIT; + Ty = Context.UnsignedLongAccumTy; + break; + } + } + } else if (Literal.fixedPointType == FPT_FRACT) { + if (isSigned) { + switch (Literal.fixedPointSize) { + case FPS_UNSPECIFIED: + fbits = BUILTIN_FRACT_FBIT; + Ty = Context.FractTy; + break; + case FPS_SHORT: + fbits = BUILTIN_SFRACT_FBIT; + Ty = Context.ShortFractTy; + break; + case FPS_LONG: + fbits = BUILTIN_LFRACT_FBIT; + Ty = Context.LongFractTy; + break; + } + } else { + switch (Literal.fixedPointSize) { + case FPS_UNSPECIFIED: + fbits = BUILTIN_UFRACT_FBIT; + Ty = Context.UnsignedFractTy; + break; + case FPS_SHORT: + fbits = BUILTIN_USFRACT_FBIT; + Ty = Context.UnsignedShortFractTy; + break; + case FPS_LONG: + fbits = BUILTIN_ULFRACT_FBIT; + Ty = Context.UnsignedLongFractTy; + break; + } + } + } else { + llvm_unreachable("Expected the literal to be a fixed point type"); + } + + if (isSigned) { + assert( + (fbits + ibits + 1 <= bit_width) && + "The total fractional, integral, and sign bits exceed the bit width"); + } else { + assert((fbits + ibits <= bit_width) && + "The total fractional and integral bits exceed the bit width"); + } + + using llvm::APFloat; + APFloat Val(Format); + APFloat::opStatus result = Literal.GetFloatValue(Val); + + HandleFloatOverflow(*this, floatingTy, Tok.getLocation(), result, Val, + Format); + + // TODO: Check sizes to make sure we don't overflow or fit a value that + // can't fit into the number of bits we have. + double float_val = Val.convertToDouble(); + assert(float_val > 0); + double int_part; + double fract_part = modf(float_val, &int_part); + uint64_t int_part_as_int = static_cast(int_part); + + if (Literal.fixedPointType == FPT_FRACT && int_part_as_int) { + Diag(Tok.getLocation(), diag::err_integral_part_on_fract); + } else { + // Make sure the integral part fits into the integral bits we have. + uint64_t max_int_val = 0; + if (isSigned) { + max_int_val = 1 << (ibits - 1); // min signed is -2^(n-1) + } else { + max_int_val = (1 << ibits) - 1; + } + + // TODO: What should be done for literals with no unsigned suffix whose + // value is equal to the absolute value of the smallest possible value for + // that type. Ie. 128.0hk -> -128.0hk? What happens is user writes + // "-128.0hk" since we are only interpretting a literal and do now know of + // the unary operator? + if (int_part_as_int > max_int_val) { + Diag(Tok.getLocation(), diag::err_integral_part_of_accum_too_large) + << (isSigned ? 0 : 1); + } + } + + uint64_t fract_part_as_int = + static_cast(fabs(fract_part) * (1 << fbits)); + uint64_t final_fixed_point_as_int = + (int_part_as_int << fbits) + fract_part_as_int; + + llvm::APInt ResultVal(bit_width, final_fixed_point_as_int, isSigned); + Res = FixedPointLiteral::CreateFromRawInt(Context, ResultVal, Ty, + Tok.getLocation()); + } else if (Literal.isFloatingLiteral()) { QualType Ty; if (Literal.isHalf){ if (getOpenCLOptions().isEnabled("cl_khr_fp16")) @@ -5802,13 +6013,21 @@ case Type::STK_FloatingComplex: case Type::STK_IntegralComplex: case Type::STK_MemberPointer: + case Type::STK_FixedPoint: llvm_unreachable("illegal cast from pointer"); } llvm_unreachable("Should have returned before this"); + case Type::STK_FixedPoint: + llvm_unreachable( + "Sema::PrepareScalarCast from STK_FixedPoint to anything"); // TODO + case Type::STK_Bool: // casting from bool is like casting from an integer case Type::STK_Integral: switch (DestTy->getScalarTypeKind()) { + case Type::STK_FixedPoint: + llvm_unreachable( + "Sema::PrepareScalarCast from STK_Integral to STK_FixedPoint"); // TODO case Type::STK_CPointer: case Type::STK_ObjCObjectPointer: case Type::STK_BlockPointer: @@ -5839,6 +6058,9 @@ case Type::STK_Floating: switch (DestTy->getScalarTypeKind()) { + case Type::STK_FixedPoint: + llvm_unreachable( + "Sema::PrepareScalarCast from STK_Floating to STK_FixedPoint"); // TODO case Type::STK_Floating: return CK_FloatingCast; case Type::STK_Bool: @@ -5866,6 +6088,10 @@ case Type::STK_FloatingComplex: switch (DestTy->getScalarTypeKind()) { + case Type::STK_FixedPoint: + llvm_unreachable( + "Sema::PrepareScalarCast from STK_FloatingComplex to " + "STK_FixedPoint"); // TODO case Type::STK_FloatingComplex: return CK_FloatingComplexCast; case Type::STK_IntegralComplex: @@ -5895,6 +6121,10 @@ case Type::STK_IntegralComplex: switch (DestTy->getScalarTypeKind()) { + case Type::STK_FixedPoint: + llvm_unreachable( + "Sema::PrepareScalarCast from STK_IntegralComplex to " + "STK_FixedPoint"); // TODO case Type::STK_FloatingComplex: return CK_IntegralComplexToFloatingComplex; case Type::STK_IntegralComplex: @@ -12893,7 +13123,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,10 @@ Code = serialization::EXPR_INTEGER_LITERAL; } +void ASTStmtWriter::VisitFixedPointLiteral(FixedPointLiteral *E) { + llvm_unreachable("ASTStmtWriter::VisitFixedPointLiteral"); +} + 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 @@ -1436,6 +1436,7 @@ case Stmt::AddrLabelExprClass: case Stmt::AttributedStmtClass: case Stmt::IntegerLiteralClass: + case Stmt::FixedPointLiteralClass: case Stmt::CharacterLiteralClass: case Stmt::ImplicitValueInitExprClass: case Stmt::CXXScalarValueInitExprClass: Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -321,6 +321,9 @@ const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { + case CK_IntegralToFixedPoint: + llvm_unreachable( + "ExprEngine::VisitCast CK_IntegralToFixedPoint"); // TODO case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); case CK_ToVoid: Index: test/Frontend/fixed_point.c =================================================================== --- test/Frontend/fixed_point.c +++ test/Frontend/fixed_point.c @@ -79,4 +79,9 @@ //CHECK-NEXT: |-VarDecl {{.*}} sat_long_accum '_Sat long _Accum' //CHECK-NEXT: |-VarDecl {{.*}} sat_short_fract '_Sat short _Fract' //CHECK-NEXT: |-VarDecl {{.*}} sat_fract '_Sat _Fract' -//CHECK-NEXT: `-VarDecl {{.*}} sat_long_fract '_Sat long _Fract' +//CHECK-NEXT: |-VarDecl {{.*}} sat_long_fract '_Sat long _Fract' + +signed short _Accum s_short_accum2 = 2.5hk; + +//CHECK-NEXT: `-VarDecl {{.*}} s_short_accum2 'short _Accum' cinit +//CHECK-NEXT: `-FixedPointLiteral {{.*}} 'short _Accum' 320 Index: test/Frontend/fixed_point_declarations.c =================================================================== --- /dev/null +++ test/Frontend/fixed_point_declarations.c @@ -0,0 +1,33 @@ +// RUN: %clang -S -emit-llvm %s -o - | FileCheck %s + +// Primary fixed point types +signed short _Accum s_short_accum; // CHECK-DAG: @s_short_accum = common dso_local global i16 0, align 2 +signed _Accum s_accum; // CHECK-DAG: @s_accum = common dso_local global i32 0, align 4 +signed long _Accum s_long_accum; // CHECK-DAG: @s_long_accum = common dso_local global i64 0, align 8 +unsigned short _Accum u_short_accum; // CHECK-DAG: @u_short_accum = common dso_local global i16 0, align 2 +unsigned _Accum u_accum; // CHECK-DAG: @u_accum = common dso_local global i32 0, align 4 +unsigned long _Accum u_long_accum; // CHECK-DAG: @u_long_accum = common dso_local global i64 0, align 8 +signed short _Fract s_short_fract; // CHECK-DAG: @s_short_fract = common dso_local global i16 0, align 2 +signed _Fract s_fract; // CHECK-DAG: @s_fract = common dso_local global i32 0, align 4 +signed long _Fract s_long_fract; // CHECK-DAG: @s_long_fract = common dso_local global i64 0, align 8 +unsigned short _Fract u_short_fract; // CHECK-DAG: @u_short_fract = common dso_local global i16 0, align 2 +unsigned _Fract u_fract; // CHECK-DAG: @u_fract = common dso_local global i32 0, align 4 +unsigned long _Fract u_long_fract; // CHECK-DAG: @u_long_fract = common dso_local global i64 0, align 8 + +// There are 7 bits allocated to the fractional part and 8 +// bits allocated to the integral part of a short _Accum by default. + +signed short _Accum s_short_accum2 = 2.5hk; // CHECK-DAG: @s_short_accum2 = dso_local global i16 320, align 2 +short _Fract short_fract = 0.33333333333hr; // CHECK-DAG: @short_fract = dso_local global i16 42, align 2 + +void func() { + s_short_accum = s_short_accum2; + // CHECK-DAG: %0 = load i16, i16* @s_short_accum2, align 2 + // CHECK-DAG: store i16 %0, i16* @s_short_accum, align 2 + + s_short_accum == 0; + // CHECK-DAG: %1 = load i16, i16* @s_short_accum, align 2 + // CHECK-DAG: %cmp = icmp eq i16 %1, 0 + + s_accum == 2; +} Index: test/Frontend/fixed_point_errors.c =================================================================== --- test/Frontend/fixed_point_errors.c +++ test/Frontend/fixed_point_errors.c @@ -1,14 +1,23 @@ // RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s -long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} -unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} -long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} -unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +long long _Accum longlong_accum; // expected-error{{'long long _Accum' is invalid}} +unsigned long long _Accum u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +long long _Fract longlong_fract; // expected-error{{'long long _Fract' is invalid}} +unsigned long long _Fract u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} _Sat int i; // expected-error{{'int' cannot be saturated. Only _Fract and _Accum can.}} _Sat _Sat _Fract fract; // expected-warning{{duplicate '_Sat' declaration specifier}} -_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} +_Sat long long _Accum sat_longlong_accum; // expected-error{{'long long _Accum' is invalid}} _Sat unsigned long long _Accum sat_u_longlong_accum; // expected-error{{'long long _Accum' is invalid}} -_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} +_Sat long long _Fract sat_longlong_fract; // expected-error{{'long long _Fract' is invalid}} _Sat unsigned long long _Fract sat_u_longlong_fract; // expected-error{{'long long _Fract' is invalid}} + +short _Fract fract2 = 1.2hr; // expected-error{{a _Fract type cannot have an integral part}} + +signed short _Accum s_short_accum = 129.0hk; // expected-error{{the integral part of this literal is too large for this signed _Accum type}} +unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} +signed _Accum s_accum = 32770.0k; // expected-error{{the integral part of this literal is too large for this signed _Accum type}} +unsigned _Accum u_accum = 65536.0uk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}} +short _Accum short_accum = 129.0hk; // expected-error{{the integral part of this literal is too large for this signed _Accum type}} +_Accum accum = 32770.0k; // expected-error{{the integral part of this literal is too large for this signed _Accum type}} Index: test/Frontend/fixed_point_validation.c =================================================================== --- /dev/null +++ test/Frontend/fixed_point_validation.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -S -emit-llvm -o - %s | lli + +// Run simple validation tests + +#define assert(b) if (!(b)) { return 1; } + +int main(){ + short _Accum s_accum; + short _Accum s_accum2 = 2.0hk; + short _Fract s_fract = 0.999hr; + short _Fract s_fract2 = -0.999hr; + + assert(s_accum == 0); + + s_accum = s_accum2; + + assert(s_accum == s_accum2); + assert(s_accum == 2); +} Index: tools/libclang/CXCursor.cpp =================================================================== --- tools/libclang/CXCursor.cpp +++ tools/libclang/CXCursor.cpp @@ -305,6 +305,10 @@ K = CXCursor_IntegerLiteral; break; + case Stmt::FixedPointLiteralClass: + llvm_unreachable("No cursor for FixedPointLiteralClass"); + break; + case Stmt::FloatingLiteralClass: K = CXCursor_FloatingLiteral; break;