Index: include/clang/AST/OperationKinds.def =================================================================== --- include/clang/AST/OperationKinds.def +++ include/clang/AST/OperationKinds.def @@ -206,6 +206,10 @@ /// (short _Accum) i CAST_OPERATION(IntegralToFixedPoint) +/// CK_FixedPointToFloating - Fixed point to floating point. +/// (float) 2.5hk +CAST_OPERATION(FixedPointToFloating) + /// CK_FloatingToIntegral - Floating point to integral. Rounds /// towards zero, discarding any fractional component. /// (int) f Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7321,6 +7321,8 @@ "expression result unused; assign into a variable to force a volatile load">, InGroup>; +def err_typecheck_fixed_point_cast : Error<"Cannot convert fixed point type to %0">; + def ext_cxx14_attr : Extension< "use of the %0 attribute is a C++14 extension">, InGroup; def ext_cxx17_attr : Extension< Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -1653,6 +1653,7 @@ case CK_IntToOCLSampler: case CK_IntegralToFixedPoint: case CK_FixedPointCast: + case CK_FixedPointToFloating: assert(!getType()->isBooleanType() && "unheralded conversion to bool"); goto CheckNoBasePath; Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -9163,6 +9163,7 @@ QualType SrcType = SubExpr->getType(); switch (E->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_IntegralToFixedPoint: llvm_unreachable("IntExprEvaluator::VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_BaseToDerived: @@ -9758,6 +9759,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_IntegralToFixedPoint: llvm_unreachable("ComplexExprEvaluator::VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_BitCast: Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -4044,6 +4044,7 @@ /// cast from scalar to union. LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { switch (E->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_IntegralToFixedPoint: llvm_unreachable("CodeGenFunction::EmitCastLValue CK_IntegralToFixedPoint"); // TODO case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_ToVoid: Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -671,6 +671,7 @@ if (const auto *ECE = dyn_cast(E)) CGF.CGM.EmitExplicitCastExprType(ECE, &CGF); switch (E->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_IntegralToFixedPoint: llvm_unreachable("AggExprEmitter::VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_Dynamic: { Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -448,6 +448,7 @@ switch (CK) { case CK_IntegralToFixedPoint: llvm_unreachable("ComplexExprEmitter::EmitCast CK_IntegralToFixedPoint"); // TODO case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); 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,7 @@ Expr *subExpr = E->getSubExpr(); switch (E->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_IntegralToFixedPoint: llvm_unreachable("VisitCastExpr CK_IntegralToFixedPoint"); // TODO case CK_ToUnion: { Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -1851,6 +1851,14 @@ getFixedPointFBits(DestTy), "int_to_fixed"); } + case CK_FixedPointToFloating: { + assert(DestTy->isFloatingType()); + assert(E->getType()->isFixedPointType()); + unsigned fbits = getFixedPointFBits(E->getType()); + return Builder.CreateFDiv(EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()), + llvm::ConstantFP::get(CGF.CGM.FloatTy, (1ULL << fbits) * 1.0)); + } + case CK_IntegralCast: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: lib/Edit/RewriteObjCFoundationAPI.cpp =================================================================== --- lib/Edit/RewriteObjCFoundationAPI.cpp +++ lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1004,6 +1004,7 @@ switch (ICE->getCastKind()) { case CK_IntegralToFixedPoint: llvm_unreachable("rewriteToNumericBoxedExpression CK_IntegralToFixedPoint"); // TODO case CK_FixedPointCast: llvm_unreachable("rewriteToNumericBoxedExpression CK_FixedPointCast"); // TODO + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_LValueToRValue: case CK_NoOp: case CK_UserDefinedConversion: Index: lib/Sema/SemaCast.cpp =================================================================== --- lib/Sema/SemaCast.cpp +++ lib/Sema/SemaCast.cpp @@ -2601,6 +2601,20 @@ return; } } + + if (SrcType->isFixedPointType()) { + switch (DestType->getScalarTypeKind()) { + default: + Self.Diag(SrcExpr.get()->getLocStart(), + diag::err_typecheck_fixed_point_cast) + << DestType; + return; + case Type::STK_Floating: + case Type::STK_Integral: + case Type::STK_FixedPoint: + break; // Allow + } + } DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1029,6 +1029,18 @@ return result; } +/// \brief Handle arithmetic conversion from fixed point to floating. Helper function +/// of UsualArithmeticConversions() +static QualType handleFixedPointToFloatConversion(Sema &S, ExprResult &FloatExpr, + ExprResult &FixedPointExpr, + QualType FloatTy, QualType FixedPointTy) { + assert(FloatTy->isFloatingType()); + assert(FixedPointTy->isFixedPointType()); + + FixedPointExpr = S.ImpCastExprToType(FixedPointExpr.get(), FloatTy, CK_FixedPointToFloating); + return FloatTy; +} + /// \brief Handle arithmethic conversion with floating point types. Helper /// function of UsualArithmeticConversions() static QualType handleFloatConversion(Sema &S, ExprResult &LHS, @@ -1057,11 +1069,22 @@ if (LHSType->isHalfType() && !S.getLangOpts().NativeHalfType) LHSType = S.Context.FloatTy; + if (RHSType->isFixedPointType()) { + return handleFixedPointToFloatConversion(S, LHS, RHS, LHSType, + RHSType); + } + return handleIntToFloatConversion(S, LHS, RHS, LHSType, RHSType, /*convertFloat=*/!IsCompAssign, /*convertInt=*/ true); } assert(RHSFloat); + + if (LHSType->isFixedPointType()) { + return handleFixedPointToFloatConversion(S, RHS, LHS, RHSType, + LHSType); + } + return handleIntToFloatConversion(S, RHS, LHS, RHSType, LHSType, /*convertInt=*/ true, /*convertFloat=*/!IsCompAssign); @@ -1218,6 +1241,7 @@ CK_IntegralRealToComplex); return ComplexType; } + /// \brief Handle arithmetic conversion from integer to fixed point. Helper function /// of UsualArithmeticConversions() static QualType handleIntToFixedPointConversion(Sema &S, ExprResult &FixedPointExpr, @@ -6028,7 +6052,14 @@ } llvm_unreachable("Should have returned before this"); - case Type::STK_FixedPoint: llvm_unreachable("Sema::PrepareScalarCast from STK_FixedPoint to anything"); // TODO + case Type::STK_FixedPoint: { + switch (DestTy->getScalarTypeKind()) { + default: llvm_unreachable("Unable to convert from fixed point type"); + case Type::STK_Integral: llvm_unreachable("Unimplemented scalar cast from fixed point to int"); // TODO + case Type::STK_Floating: return CK_FixedPointToFloating; + case Type::STK_FixedPoint: llvm_unreachable("Unimplemented scalar cast from fixed point to fixed point"); // TODO + } + } case Type::STK_Bool: // casting from bool is like casting from an integer case Type::STK_Integral: Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -321,6 +321,7 @@ const LocationContext *LCtx = Pred->getLocationContext(); switch (CastE->getCastKind()) { + case CK_FixedPointToFloating: llvm_unreachable("Unimplemented logic for CK_FixedPointToFloating"); case CK_IntegralToFixedPoint: llvm_unreachable("ExprEngine::VisitCast CK_IntegralToFixedPoint"); // TODO case CK_FixedPointCast: llvm_unreachable("CK_FixedPointCast"); // TODO case CK_LValueToRValue: Index: test/Frontend/fixed_point_validation.c =================================================================== --- test/Frontend/fixed_point_validation.c +++ test/Frontend/fixed_point_validation.c @@ -30,6 +30,7 @@ // Run simple validation tests #define assert(b) if (!(b)) { return 1; } +#define abs(x) x < 0 ? -x : x int main(){ short _Accum s_accum = 0.0hk; @@ -264,4 +265,18 @@ assert(5.0hk >> 2 == 1.25hk); assert(-5.0hk >> 2 == -1.25k); assert(0.0hr >> 2 == 0); + + /**************** Float conversions ***************/ + + float f = (float)2.5k; + assert(f > 2.4999 && f < 2.5001); // High precision since the fractional value can be evenly + // represented. + assert((float)2.333hk != 2.333f); + + float base = 2.333f; + float saccum_diff = abs(base - 2.333hk); + float accum_diff = abs(base - 2.333k); + float laccum_diff = abs(base - 2.333lk); + assert(accum_diff < saccum_diff); + assert(laccum_diff < accum_diff); }