From: Leonard Chan Date: Tue, 23 Oct 2018 17:55:35 +0000 (+0000) Subject: [Fixed Point Arithmetic] Fixed Point to Boolean Cast X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=233643a4e02d8156fdfe98bf5808c25d31673c1a;p=clang [Fixed Point Arithmetic] Fixed Point to Boolean Cast This patch is a part of https://reviews.llvm.org/D48456 in an attempt to split the casting logic up into smaller patches. This contains the code for casting from fixed point types to boolean types. Differential Revision: https://reviews.llvm.org/D53308 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@345063 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/OperationKinds.def b/include/clang/AST/OperationKinds.def index 7fe9723365..cd19091e31 100644 --- a/include/clang/AST/OperationKinds.def +++ b/include/clang/AST/OperationKinds.def @@ -201,6 +201,10 @@ CAST_OPERATION(IntegralToFloating) /// (_Accum) 0.5r CAST_OPERATION(FixedPointCast) +/// CK_FixedPointToBoolean - Fixed point to boolean. +/// (bool) 0.5r +CAST_OPERATION(FixedPointToBoolean) + /// CK_FloatingToIntegral - Floating point to integral. Rounds /// towards zero, discarding any fractional component. /// (int) f diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 0f264afbc2..e1e5c45efe 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1661,6 +1661,7 @@ bool CastExpr::CastConsistency() const { case CK_LValueBitCast: // -> bool& case CK_UserDefinedConversion: // operator bool() case CK_BuiltinFnToFnPtr: + case CK_FixedPointToBoolean: CheckNoBasePath: assert(path_empty() && "Cast kind should not have a base path!"); break; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a7da24db6a..c64e335255 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -9590,6 +9590,14 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return Success(IntResult, E); } + case CK_FixedPointToBoolean: { + // Unsigned padding does not affect this. + APValue Val; + if (!Evaluate(Val, Info, SubExpr)) + return false; + return Success(Val.getInt().getBoolValue(), E); + } + case CK_IntegralCast: { if (!Visit(SubExpr)) return false; @@ -10090,6 +10098,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AddressSpaceConversion: case CK_IntToOCLSampler: case CK_FixedPointCast: + case CK_FixedPointToBoolean: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index c4e06b3af8..a8ee16c5fe 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -4154,6 +4154,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_AddressSpaceConversion: case CK_IntToOCLSampler: case CK_FixedPointCast: + case CK_FixedPointToBoolean: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); case CK_Dependent: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 7808c84c12..42481939fa 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -851,6 +851,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_AddressSpaceConversion: case CK_IntToOCLSampler: case CK_FixedPointCast: + case CK_FixedPointToBoolean: llvm_unreachable("cast kind invalid for aggregate types"); } } diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 773568e179..c0b87c850e 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -509,6 +509,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op, case CK_AddressSpaceConversion: case CK_IntToOCLSampler: case CK_FixedPointCast: + case CK_FixedPointToBoolean: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index e1ad656de5..b8b6685cc7 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -870,6 +870,7 @@ public: case CK_FloatingToBoolean: case CK_FloatingCast: case CK_FixedPointCast: + case CK_FixedPointToBoolean: case CK_ZeroToOCLOpaqueType: return nullptr; } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index be9a92a568..0351247e94 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1015,9 +1015,26 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, QualType DstType, SourceLocation Loc, ScalarConversionOpts Opts) { - assert(!SrcType->isFixedPointType() && !DstType->isFixedPointType() && - "Use the ScalarExprEmitter::EmitFixedPoint family functions for " - "handling conversions involving fixed point types."); + // All conversions involving fixed point types should be handled by the + // EmitFixedPoint family functions. This is done to prevent bloating up this + // function more, and although fixed point numbers are represented by + // integers, we do not want to follow any logic that assumes they should be + // treated as integers. + // TODO(leonardchan): When necessary, add another if statement checking for + // conversions to fixed point types from other types. + if (SrcType->isFixedPointType()) { + if (DstType->isFixedPointType()) { + return EmitFixedPointConversion(Src, SrcType, DstType, Loc); + } else if (DstType->isBooleanType()) { + // We do not need to check the padding bit on unsigned types if unsigned + // padding is enabled because overflow into this bit is undefined + // behavior. + return Builder.CreateIsNotNull(Src); + } + + llvm_unreachable( + "Unhandled scalar conversion involving a fixed point type."); + } QualType NoncanonicalSrcType = SrcType; QualType NoncanonicalDstType = DstType; @@ -1998,8 +2015,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } case CK_FixedPointCast: - return EmitFixedPointConversion(Visit(E), E->getType(), DestTy, - CE->getExprLoc()); + return EmitScalarConversion(Visit(E), E->getType(), DestTy, + CE->getExprLoc()); + + case CK_FixedPointToBoolean: + assert(E->getType()->isFixedPointType() && + "Expected src type to be fixed point type"); + assert(DestTy->isBooleanType() && "Expected dest type to be boolean type"); + return EmitScalarConversion(Visit(E), E->getType(), DestTy, + CE->getExprLoc()); case CK_IntegralCast: { ScalarConversionOpts Opts; diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp index 5a7982a21d..7c9ab17009 100644 --- a/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1086,6 +1086,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, llvm_unreachable("OpenCL-specific cast in Objective-C?"); case CK_FixedPointCast: + case CK_FixedPointToBoolean: llvm_unreachable("Fixed point types are disabled for Objective-C"); } } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7e16202988..d5d92287ab 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -533,8 +533,7 @@ CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { 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("Unknown cast from FixedPoint to boolean"); + case Type::STK_FixedPoint: return CK_FixedPointToBoolean; } llvm_unreachable("unknown scalar type kind"); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 597f220bc4..2cee761da3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5894,10 +5894,7 @@ CastKind Sema::PrepareScalarCast(ExprResult &Src, QualType DestTy) { case Type::STK_FixedPoint: return CK_FixedPointCast; case Type::STK_Bool: - Diag(Src.get()->getExprLoc(), - diag::err_unimplemented_conversion_with_fixed_point_type) - << DestTy; - return CK_IntegralToBoolean; + return CK_FixedPointToBoolean; case Type::STK_Integral: case Type::STK_Floating: case Type::STK_IntegralComplex: @@ -12793,12 +12790,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Context.getLangOpts().CPlusPlus) { // C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9: // operand contextually converted to bool. - if (resultType->getScalarTypeKind() == Type::STK_FixedPoint) { - return ExprError( - Diag(Input.get()->getExprLoc(), - diag::err_unimplemented_conversion_with_fixed_point_type) - << resultType); - } Input = ImpCastExprToType(Input.get(), Context.BoolTy, ScalarTypeToBooleanCastKind(resultType)); } else if (Context.getLangOpts().OpenCL && diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index bdf56af96b..7a35c0acb0 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -415,7 +415,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_ZeroToOCLOpaqueType: case CK_IntToOCLSampler: case CK_LValueBitCast: - case CK_FixedPointCast: { + case CK_FixedPointCast: + case CK_FixedPointToBoolean: { state = handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred); continue; diff --git a/test/Frontend/fixed_point_to_bool.c b/test/Frontend/fixed_point_to_bool.c new file mode 100644 index 0000000000..b5bfa6f3f4 --- /dev/null +++ b/test/Frontend/fixed_point_to_bool.c @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -ffixed-point -S -emit-llvm %s -o - -fpadding-on-unsigned-fixed-point | FileCheck %s + +_Bool global_b = 1.0k; // @global_b = {{*.}}global i8 1, align 1 +_Bool global_b2 = 0.0k; // @global_b2 = {{*.}}global i8 0, align 1 + +void func() { + _Accum a = 0.5k; + unsigned _Accum ua = 0.5uk; + _Bool b; + + // CHECK: store i8 1, i8* %b, align 1 + // CHECK-NEXT: store i8 0, i8* %b, align 1 + // CHECK: store i8 1, i8* %b, align 1 + // CHECK-NEXT: store i8 0, i8* %b, align 1 + b = 0.5k; + b = 0.0k; + b = 0.5uk; + b = 0.0uk; + + // CHECK-NEXT: store i8 1, i8* %b, align 1 + // CHECK-NEXT: store i8 0, i8* %b, align 1 + // CHECK-NEXT: store i8 1, i8* %b, align 1 + // CHECK-NEXT: store i8 0, i8* %b, align 1 + b = (_Bool)0.5r; + b = (_Bool)0.0r; + b = (_Bool)0.5ur; + b = (_Bool)0.0ur; + + // CHECK-NEXT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // CHECK-NEXT: [[NOTZERO:%[0-9]+]] = icmp ne i32 [[ACCUM]], 0 + // CHECK-NEXT: %frombool = zext i1 [[NOTZERO]] to i8 + // CHECK-NEXT: store i8 %frombool, i8* %b, align 1 + b = a; + + // CHECK-NEXT: [[ACCUM:%[0-9]+]] = load i32, i32* %ua, align 4 + // CHECK-NEXT: [[NOTZERO:%[0-9]+]] = icmp ne i32 [[ACCUM]], 0 + // CHECK-NEXT: %frombool1 = zext i1 [[NOTZERO]] to i8 + // CHECK-NEXT: store i8 %frombool1, i8* %b, align 1 + b = ua; + + // CHECK-NEXT: [[ACCUM:%[0-9]+]] = load i32, i32* %a, align 4 + // CHECK-NEXT: [[NOTZERO:%[0-9]+]] = icmp ne i32 [[ACCUM]], 0 + // CHECK-NEXT: br i1 [[NOTZERO]], label %if.then, label %if.end + if (a) { + } + + // CHECK: [[ACCUM:%[0-9]+]] = load i32, i32* %ua, align 4 + // CHECK-NEXT: [[NOTZERO:%[0-9]+]] = icmp ne i32 [[ACCUM]], 0 + // CHECK-NEXT: br i1 [[NOTZERO]], label %if.then{{[0-9]+}}, label %if.end{{[0-9]+}} + if (ua) { + } +} diff --git a/test/Frontend/fixed_point_unknown_conversions.c b/test/Frontend/fixed_point_unknown_conversions.c index 94b1fc32e9..0cd3d046ca 100644 --- a/test/Frontend/fixed_point_unknown_conversions.c +++ b/test/Frontend/fixed_point_unknown_conversions.c @@ -35,7 +35,6 @@ void func() { accum_ptr = ptr; // expected-warning{{incompatible pointer types assigning to '_Accum *' from 'int *'}} accum = i2; // expected-error{{conversion between fixed point and 'int_t' (aka 'int') is not yet supported}} - b = accum; // expected-error{{conversion between fixed point and '_Bool' is not yet supported}} c = accum; // expected-error{{conversion between fixed point and 'char' is not yet supported}} i = accum; // expected-error{{conversion between fixed point and 'int' is not yet supported}} f = accum; // expected-error{{conversion between fixed point and 'float' is not yet supported}}