Index: include/clang/AST/OperationKinds.h =================================================================== --- include/clang/AST/OperationKinds.h +++ include/clang/AST/OperationKinds.h @@ -185,7 +185,15 @@ /// CK_FloatingToBoolean - Floating point to boolean. /// (bool) f CK_FloatingToBoolean, - + + // CK_BooleanToSignedIntegral - Convert a boolean to -1 or 0 for true and + // false, respectively. + CK_BooleanToSignedIntegral, + + // CK_BooleanToSignedFloating - Convert a boolean to -1.0 or 0.0 for true and + // false, respectively. + CK_BooleanToSignedFloating, + /// CK_FloatingCast - Casting between floating types of different size. /// (double) f /// (float) ld Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -8569,6 +8569,10 @@ bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind); + /// \brief Prepare `SplattedExpr` for a vector splat operation, adding + /// implicit casts if necessary. + ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); + // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -1566,6 +1566,8 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingCast: @@ -1659,6 +1661,10 @@ return "VectorSplat"; case CK_IntegralCast: return "IntegralCast"; + case CK_BooleanToSignedFloating: + return "BooleanToSignedFloating"; + case CK_BooleanToSignedIntegral: + return "BooleanToSignedIntegral"; case CK_IntegralToBoolean: return "IntegralToBoolean"; case CK_IntegralToFloating: Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -7748,6 +7748,7 @@ case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: + case CK_BooleanToSignedFloating: case CK_FloatingRealToComplex: case CK_FloatingComplexToReal: case CK_FloatingComplexCast: @@ -7781,12 +7782,16 @@ case CK_PointerToBoolean: case CK_IntegralToBoolean: case CK_FloatingToBoolean: + case CK_BooleanToSignedIntegral: case CK_FloatingComplexToBoolean: case CK_IntegralComplexToBoolean: { bool BoolResult; if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info)) return false; - return Success(BoolResult, E); + uint64_t IntResult = BoolResult; + if (BoolResult && E->getCastKind() == CK_BooleanToSignedIntegral) + IntResult = (uint64_t)-1; + return Success(IntResult, E); } case CK_IntegralCast: { @@ -8096,6 +8101,15 @@ default: return ExprEvaluatorBaseTy::VisitCastExpr(E); + case CK_BooleanToSignedFloating: { + bool BoolResult; + if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info)) + return false; + APSInt IntResult(1, /*IsSigned=*/true); + IntResult = BoolResult; + return HandleIntToFloatCast(Info, E, SubExpr->getType(), IntResult, + E->getType(), Result); + } case CK_IntegralToFloating: { APSInt IntResult; return EvaluateInteger(SubExpr, IntResult, Info) && @@ -8223,6 +8237,8 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp +++ lib/CodeGen/CGExpr.cpp @@ -3337,6 +3337,8 @@ case CK_PointerToBoolean: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: lib/CodeGen/CGExprAgg.cpp =================================================================== --- lib/CodeGen/CGExprAgg.cpp +++ lib/CodeGen/CGExprAgg.cpp @@ -721,6 +721,8 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: lib/CodeGen/CGExprComplex.cpp =================================================================== --- lib/CodeGen/CGExprComplex.cpp +++ lib/CodeGen/CGExprComplex.cpp @@ -462,6 +462,8 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: lib/CodeGen/CGExprConstant.cpp =================================================================== --- lib/CodeGen/CGExprConstant.cpp +++ lib/CodeGen/CGExprConstant.cpp @@ -735,6 +735,8 @@ case CK_PointerToBoolean: case CK_NullToPointer: case CK_IntegralCast: + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: case CK_IntegralToPointer: case CK_IntegralToBoolean: case CK_IntegralToFloating: Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -810,14 +810,15 @@ // A scalar can be splatted to an extended vector of the same element type if (DstType->isExtVectorType() && !SrcType->isVectorType()) { - // Cast the scalar to element type - QualType EltTy = DstType->getAs()->getElementType(); - llvm::Value *Elt = EmitScalarConversion( - Src, SrcType, EltTy, Loc, CGF.getContext().getLangOpts().OpenCL); + // Sema should add casts to make sure that the source expression's type is + // the same as the vector's element type (sans qualifiers) + assert(DstType->castAs()->getElementType().getTypePtr() == + SrcType.getTypePtr() && + "Splatted expr doesn't match with vector element type?"); // Splat the element across to all elements unsigned NumElements = cast(DstTy)->getNumElements(); - return Builder.CreateVectorSplat(NumElements, Elt, "splat"); + return Builder.CreateVectorSplat(NumElements, Src, "splat"); } // Allow bitcast from vector to integer/fp of the same size. @@ -1540,15 +1541,7 @@ } case CK_VectorSplat: { llvm::Type *DstTy = ConvertType(DestTy); - // Need an IgnoreImpCasts here as by default a boolean will be promoted to - // an int, which will not perform the sign extension, so if we know we are - // going to cast to a vector we have to strip the implicit cast off. - Value *Elt = Visit(const_cast(E->IgnoreImpCasts())); - Elt = EmitScalarConversion(Elt, E->IgnoreImpCasts()->getType(), - DestTy->getAs()->getElementType(), - CE->getExprLoc(), - CGF.getContext().getLangOpts().OpenCL); - + Value *Elt = Visit(const_cast(E)); // Splat the element across to all elements unsigned NumElements = cast(DstTy)->getNumElements(); return Builder.CreateVectorSplat(NumElements, Elt, "splat"); @@ -1560,6 +1553,11 @@ case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()); + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: + return EmitScalarConversion(Visit(E), E->getType(), DestTy, + CE->getExprLoc(), + /*TreatBooleanAsSigned=*/true); case CK_IntegralToBoolean: return EmitIntToBoolConversion(Visit(E)); case CK_PointerToBoolean: Index: lib/Edit/RewriteObjCFoundationAPI.cpp =================================================================== --- lib/Edit/RewriteObjCFoundationAPI.cpp +++ lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1077,6 +1077,10 @@ case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: return false; + + case CK_BooleanToSignedFloating: + case CK_BooleanToSignedIntegral: + llvm_unreachable("OpenCL-specific cast in Objective-C?"); } } Index: lib/Sema/SemaCast.cpp =================================================================== --- lib/Sema/SemaCast.cpp +++ lib/Sema/SemaCast.cpp @@ -2101,6 +2101,7 @@ && (SrcExpr.get()->getType()->isIntegerType() || SrcExpr.get()->getType()->isFloatingType())) { Kind = CK_VectorSplat; + SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get()); return; } @@ -2335,6 +2336,7 @@ if (DestVecTy->getVectorKind() == VectorType::AltiVecVector && (SrcType->isIntegerType() || SrcType->isFloatingType())) { Kind = CK_VectorSplat; + SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get()); } else if (Self.CheckVectorCast(OpRange, DestType, SrcType, Kind)) { SrcExpr = ExprError(); } Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -6234,7 +6234,8 @@ IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE)); - bool isIntegerCast = (CE->getCastKind() == CK_IntegralCast); + bool isIntegerCast = CE->getCastKind() == CK_IntegralCast || + CE->getCastKind() == CK_BooleanToSignedIntegral; // Assume that non-integer casts can span the full range of the type. if (!isIntegerCast) Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -5597,6 +5597,31 @@ return false; } +ExprResult Sema::prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr) { + QualType DestElemTy = VectorTy->castAs()->getElementType(); + + if (DestElemTy == SplattedExpr->getType()) + return SplattedExpr; + + assert(DestElemTy->isFloatingType() || + DestElemTy->isIntegralOrEnumerationType()); + + CastKind CK; + if (getLangOpts().OpenCL && SplattedExpr->getType()->isBooleanType()) { + // OpenCL requires that we convert `true` boolean expressions to -1, but + // only when splatting vectors. + CK = DestElemTy->isFloatingType() ? CK_BooleanToSignedFloating + : CK_BooleanToSignedIntegral; + } else { + ExprResult CastExprRes = SplattedExpr; + CK = PrepareScalarCast(CastExprRes, DestElemTy); + if (CastExprRes.isInvalid()) + return ExprError(); + SplattedExpr = CastExprRes.get(); + } + return ImpCastExprToType(SplattedExpr, DestElemTy, CK); +} + ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); @@ -5627,15 +5652,8 @@ diag::err_invalid_conversion_between_vector_and_scalar) << DestTy << SrcTy << R; - QualType DestElemTy = DestTy->getAs()->getElementType(); - ExprResult CastExprRes = CastExpr; - CastKind CK = PrepareScalarCast(CastExprRes, DestElemTy); - if (CastExprRes.isInvalid()) - return ExprError(); - CastExpr = ImpCastExprToType(CastExprRes.get(), DestElemTy, CK).get(); - Kind = CK_VectorSplat; - return CastExpr; + return prepareVectorSplat(DestTy, CastExpr); } ExprResult @@ -6976,13 +6994,9 @@ if (RHSType->isExtVectorType()) return Incompatible; if (RHSType->isArithmeticType()) { - // CK_VectorSplat does T -> vector T, so first cast to the - // element type. - QualType elType = cast(LHSType)->getElementType(); - if (elType != RHSType && ConvertRHS) { - Kind = PrepareScalarCast(RHS, elType); - RHS = ImpCastExprToType(RHS.get(), elType, Kind); - } + // CK_VectorSplat does T -> vector T, so first cast to the element type. + if (ConvertRHS) + RHS = prepareVectorSplat(LHSType, RHS.get()); Kind = CK_VectorSplat; return Compatible; } @@ -8200,7 +8214,7 @@ if (RHS.isInvalid()) return QualType(); QualType LHSType = LHS.get()->getType(); - const VectorType *LHSVecTy = LHSType->getAs(); + const VectorType *LHSVecTy = LHSType->castAs(); QualType LHSEleType = LHSVecTy->getElementType(); // Note that RHS might not be a vector. Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -3350,20 +3350,13 @@ VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; - case ICK_Vector_Splat: + case ICK_Vector_Splat: { // Vector splat from any arithmetic type to a vector. - // Cast to the element type. - { - QualType elType = ToType->getAs()->getElementType(); - if (elType != From->getType()) { - ExprResult E = From; - From = ImpCastExprToType(From, elType, - PrepareScalarCast(E, elType)).get(); - } - From = ImpCastExprToType(From, ToType, CK_VectorSplat, - VK_RValue, /*BasePath=*/nullptr, CCK).get(); - } + Expr *Elem = prepareVectorSplat(ToType, From).get(); + From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_RValue, + /*BasePath=*/nullptr, CCK).get(); break; + } case ICK_Complex_Real: // Case 1. x -> _Complex y Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -258,6 +258,8 @@ case CK_IntegralCast: case CK_IntegralToBoolean: case CK_IntegralToFloating: + case CK_BooleanToSignedIntegral: + case CK_BooleanToSignedFloating: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: Index: lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -317,6 +317,8 @@ case CK_BitCast: case CK_AddressSpaceConversion: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: + case CK_BooleanToSignedFloating: case CK_NullToPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: @@ -345,6 +347,10 @@ // Delegate to SValBuilder to process. SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy); + // Negate the result if we're treating the boolean as a signed i1 + if (CastE->getCastKind() == CK_BooleanToSignedFloating || + CastE->getCastKind() == CK_BooleanToSignedIntegral) + V = evalMinus(V); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; Index: test/CodeGenCXX/builtins-systemz-zvector.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/builtins-systemz-zvector.cpp @@ -0,0 +1,50 @@ +// REQUIRES: systemz-registered-target +// RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \ +// RUN: -fzvector -fno-lax-vector-conversions -std=c++11 \ +// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s + +bool gb; + +// There was an issue where we weren't properly converting constexprs to +// vectors with elements of the appropriate width. (e.g. +// (vector signed short)0 would be lowered as [4 x i32] in some cases) + +// CHECK-LABEL: @_Z8testIntsDv4_i +void testInts(vector int VI) { + constexpr vector int CI1 = (vector int)0LL; + // CHECK: icmp + gb = (VI == CI1)[0]; + + // Likewise for float inits. + constexpr vector int CI2 = (vector int)char(0); + // CHECK: icmp + gb = (VI == CI2)[0]; + + constexpr vector int CF1 = (vector int)0.0; + // CHECK: icmp + gb = (VI == CF1)[0]; + + constexpr vector int CF2 = (vector int)0.0f; + // CHECK: icmp + gb = (VI == CF2)[0]; +} + +// CHECK-LABEL: @_Z10testFloatsDv2_d +void testFloats(vector double VD) { + constexpr vector double CI1 = (vector double)0LL; + // CHECK: fcmp + gb = (VD == CI1)[0]; + + // Likewise for float inits. + constexpr vector double CI2 = (vector double)char(0); + // CHECK: fcmp + gb = (VD == CI2)[0]; + + constexpr vector double CF1 = (vector double)0.0; + // CHECK: fcmp + gb = (VD == CF1)[0]; + + constexpr vector double CF2 = (vector double)0.0f; + // CHECK: fcmp + gb = (VD == CF2)[0]; +} Index: test/CodeGenOpenCL/bool_cast.cl =================================================================== --- test/CodeGenOpenCL/bool_cast.cl +++ test/CodeGenOpenCL/bool_cast.cl @@ -2,7 +2,9 @@ typedef unsigned char uchar4 __attribute((ext_vector_type(4))); typedef unsigned int int4 __attribute((ext_vector_type(4))); +typedef float float4 __attribute((ext_vector_type(4))); +// CHECK-LABEL: define void @ker() void kernel ker() { bool t = true; int4 vec4 = (int4)t; @@ -24,4 +26,8 @@ unsigned char c; c = (unsigned char)true; // CHECK: store i8 1, i8* %c, align 1 + + float4 vf; + vf = (float4)true; +// CHECK: store <4 x float> }