Index: cfe/trunk/include/clang/AST/ASTContext.h =================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h +++ cfe/trunk/include/clang/AST/ASTContext.h @@ -2283,9 +2283,13 @@ /// \brief Make an APSInt of the appropriate width and signedness for the /// given \p Value and integer \p Type. llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const { - llvm::APSInt Res(getIntWidth(Type), - !Type->isSignedIntegerOrEnumerationType()); + // If Type is a signed integer type larger than 64 bits, we need to be sure + // to sign extend Res appropriately. + llvm::APSInt Res(64, !Type->isSignedIntegerOrEnumerationType()); Res = Value; + unsigned Width = getIntWidth(Type); + if (Width != Res.getBitWidth()) + return Res.extOrTrunc(Width); return Res; } Index: cfe/trunk/include/clang/AST/OperationKinds.h =================================================================== --- cfe/trunk/include/clang/AST/OperationKinds.h +++ cfe/trunk/include/clang/AST/OperationKinds.h @@ -185,7 +185,11 @@ /// 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_FloatingCast - Casting between floating types of different size. /// (double) f /// (float) ld Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -8589,6 +8589,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: cfe/trunk/lib/AST/Expr.cpp =================================================================== --- cfe/trunk/lib/AST/Expr.cpp +++ cfe/trunk/lib/AST/Expr.cpp @@ -1553,6 +1553,7 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: case CK_IntegralToFloating: case CK_FloatingToIntegral: case CK_FloatingCast: @@ -1646,6 +1647,8 @@ return "VectorSplat"; case CK_IntegralCast: return "IntegralCast"; + case CK_BooleanToSignedIntegral: + return "BooleanToSignedIntegral"; case CK_IntegralToBoolean: return "IntegralToBoolean"; case CK_IntegralToFloating: Index: cfe/trunk/lib/AST/ExprConstant.cpp =================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp +++ cfe/trunk/lib/AST/ExprConstant.cpp @@ -7781,12 +7781,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: { @@ -8223,6 +8227,7 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: cfe/trunk/lib/CodeGen/CGExpr.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExpr.cpp +++ cfe/trunk/lib/CodeGen/CGExpr.cpp @@ -3365,6 +3365,7 @@ case CK_PointerToBoolean: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: cfe/trunk/lib/CodeGen/CGExprAgg.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExprAgg.cpp +++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp @@ -721,6 +721,7 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: cfe/trunk/lib/CodeGen/CGExprComplex.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExprComplex.cpp +++ cfe/trunk/lib/CodeGen/CGExprComplex.cpp @@ -462,6 +462,7 @@ case CK_ToVoid: case CK_VectorSplat: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: Index: cfe/trunk/lib/CodeGen/CGExprConstant.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp @@ -735,6 +735,7 @@ case CK_PointerToBoolean: case CK_NullToPointer: case CK_IntegralCast: + case CK_BooleanToSignedIntegral: case CK_IntegralToPointer: case CK_IntegralToBoolean: case CK_IntegralToFloating: Index: cfe/trunk/lib/CodeGen/CGExprScalar.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp @@ -811,14 +811,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. @@ -1541,15 +1542,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"); @@ -1561,6 +1554,10 @@ case CK_FloatingCast: return EmitScalarConversion(Visit(E), E->getType(), DestTy, CE->getExprLoc()); + 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: cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp =================================================================== --- cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp +++ cfe/trunk/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1077,6 +1077,9 @@ case CK_BuiltinFnToFnPtr: case CK_ZeroToOCLEvent: return false; + + case CK_BooleanToSignedIntegral: + llvm_unreachable("OpenCL-specific cast in Objective-C?"); } } Index: cfe/trunk/lib/Sema/SemaCast.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCast.cpp +++ cfe/trunk/lib/Sema/SemaCast.cpp @@ -2105,6 +2105,7 @@ && (SrcExpr.get()->getType()->isIntegerType() || SrcExpr.get()->getType()->isFloatingType())) { Kind = CK_VectorSplat; + SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get()); return; } @@ -2339,6 +2340,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: cfe/trunk/lib/Sema/SemaChecking.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp +++ cfe/trunk/lib/Sema/SemaChecking.cpp @@ -6243,7 +6243,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: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -5602,6 +5602,39 @@ 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 (VectorTy->isExtVectorType() && SplattedExpr->getType()->isBooleanType()) { + // OpenCL requires that we convert `true` boolean expressions to -1, but + // only when splatting vectors. + if (DestElemTy->isFloatingType()) { + // To avoid having to have a CK_BooleanToSignedFloating cast kind, we cast + // in two steps: boolean to signed integral, then to floating. + ExprResult CastExprRes = ImpCastExprToType(SplattedExpr, Context.IntTy, + CK_BooleanToSignedIntegral); + SplattedExpr = CastExprRes.get(); + CK = CK_IntegralToFloating; + } else { + CK = 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!"); @@ -5632,15 +5665,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 @@ -6979,13 +7005,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; } @@ -8203,7 +8225,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: cfe/trunk/lib/Sema/SemaExprCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp @@ -3353,20 +3353,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: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -258,6 +258,7 @@ case CK_IntegralCast: case CK_IntegralToBoolean: case CK_IntegralToFloating: + case CK_BooleanToSignedIntegral: case CK_FloatingToIntegral: case CK_FloatingToBoolean: case CK_FloatingCast: Index: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -316,6 +316,7 @@ case CK_ArrayToPointerDecay: case CK_BitCast: case CK_AddressSpaceConversion: + case CK_BooleanToSignedIntegral: case CK_NullToPointer: case CK_IntegralToPointer: case CK_PointerToIntegral: @@ -344,6 +345,9 @@ // 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_BooleanToSignedIntegral) + V = evalMinus(V); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; Index: cfe/trunk/test/CodeGenCXX/builtins-systemz-zvector.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/builtins-systemz-zvector.cpp +++ cfe/trunk/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: cfe/trunk/test/CodeGenCXX/vector-splat-conversion.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/vector-splat-conversion.cpp +++ cfe/trunk/test/CodeGenCXX/vector-splat-conversion.cpp @@ -1,19 +1,51 @@ // RUN: %clang_cc1 %s -triple arm64-apple-ios8.1.0 -std=c++11 -emit-llvm -o - | FileCheck %s -// rdar://20000762 typedef __attribute__((__ext_vector_type__(8))) float vector_float8; typedef vector_float8 float8; -void MandelbrotPolyCalcSIMD8() -{ - constexpr float8 v4 = 4.0; // value to compare against abs(z)^2, to see if bounded - float8 vABS; - auto vLT = vABS < v4; +// rdar://20000762 +// CHECK-LABEL: define void @_Z23MandelbrotPolyCalcSIMD8v +void MandelbrotPolyCalcSIMD8() { + constexpr float8 v4 = 4.0; // value to compare against abs(z)^2, to see if bounded + float8 vABS; + auto vLT = vABS < v4; + // CHECK: store <8 x float> + // CHECK: [[ZERO:%.*]] = load <8 x float>, <8 x float>* [[VARBS:%.*]] + // CHECK: [[CMP:%.*]] = fcmp olt <8 x float> [[ZERO]] + // CHECK: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32> + // CHECK: store <8 x i32> [[SEXT]], <8 x i32>* [[VLT:%.*]] } -// CHECK: store <8 x float> -// CHECK: [[ZERO:%.*]] = load <8 x float>, <8 x float>* [[VARBS:%.*]] -// CHECK: [[CMP:%.*]] = fcmp olt <8 x float> [[ZERO]] -// CHECK: [[SEXT:%.*]] = sext <8 x i1> [[CMP]] to <8 x i32> -// CHECK: store <8 x i32> [[SEXT]], <8 x i32>* [[VLT:%.*]] +typedef __attribute__((__ext_vector_type__(4))) int int4; +typedef __attribute__((__ext_vector_type__(4))) float float4; +typedef __attribute__((__ext_vector_type__(4))) __int128 bigint4; + +// CHECK-LABEL: define void @_Z14BoolConversionv +void BoolConversion() { + // CHECK: store <4 x i32> + int4 intsT = (int4)true; + // CHECK: store <4 x i32> zeroinitializer + int4 intsF = (int4)false; + // CHECK: store <4 x float> + float4 floatsT = (float4)true; + // CHECK: store <4 x float> zeroinitializer + float4 floatsF = (float4)false; + // CHECK: store <4 x i128> + bigint4 bigintsT = (bigint4)true; + // CHECK: store <4 x i128> zeroinitializer + bigint4 bigintsF = (bigint4)false; + + // CHECK: store <4 x i32> + constexpr int4 cIntsT = (int4)true; + // CHECK: store <4 x i32> zeroinitializer + constexpr int4 cIntsF = (int4)false; + // CHECK: store <4 x float> + constexpr float4 cFloatsT = (float4)true; + // CHECK: store <4 x float> zeroinitializer + constexpr float4 cFloatsF = (float4)false; + // CHECK: store <4 x i128> + constexpr bigint4 cBigintsT = (bigint4)true; + // CHECK: store <4 x i128> zeroinitializer + constexpr bigint4 cBigintsF = (bigint4)false; +} Index: cfe/trunk/test/CodeGenOpenCL/bool_cast.cl =================================================================== --- cfe/trunk/test/CodeGenOpenCL/bool_cast.cl +++ cfe/trunk/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> }