Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -1150,7 +1150,7 @@ static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result, EvalInfo &Info); static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info); -static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); +static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); @@ -1575,7 +1575,7 @@ static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E, QualType DestType, QualType SrcType, - APSInt &Value) { + const APSInt &Value) { unsigned DestWidth = Info.Ctx.getIntWidth(DestType); APSInt Result = Value; // Figure out if this is a truncate, extend or noop cast. @@ -5619,7 +5619,54 @@ return VectorExprEvaluator(Info, Result).Visit(E); } -bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { +/// Performs implicit conversions on the APValue given for a vector splat +/// operation. This is necessary given code like `(vector float)0`. +/// +/// Returns true on success, false on failure. +static bool convertVectorSplatLiteral(EvalInfo &Info, const CastExpr *E, + APValue &Result) { + QualType DestTy = E->getType()->castAs()->getElementType(); + QualType SrcTy = E->getSubExpr()->getType(); + + // If the types are the same (ignoring qualifiers), then we don't need to do + // anything. + if (SrcTy.getTypePtr() == DestTy.getTypePtr()) + return true; + + assert((SrcTy->isIntegerType() || SrcTy->isFloatingType()) && + "unsupported literal type"); + + if (DestTy->isIntegerType()) { + if (Result.isInt()) { + Result = + APValue(HandleIntToIntCast(Info, E, DestTy, SrcTy, Result.getInt())); + return true; + } + + APSInt IntResult; + if (!HandleFloatToIntCast(Info, E, SrcTy, Result.getFloat(), DestTy, + IntResult)) + return false; + Result = APValue(std::move(IntResult)); + return true; + } + + if (DestTy->isFloatingType()) { + if (Result.isFloat()) + return HandleFloatToFloatCast(Info, E, SrcTy, DestTy, Result.getFloat()); + + APFloat FloatResult(0.0); + if (!HandleIntToFloatCast(Info, E, SrcTy, Result.getInt(), DestTy, + FloatResult)) + return false; + Result = APValue(std::move(FloatResult)); + return true; + } + + llvm_unreachable("unsupported vector element type"); +} + +bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { const VectorType *VTy = E->getType()->castAs(); unsigned NElts = VTy->getNumElements(); @@ -5632,17 +5679,20 @@ if (SETy->isIntegerType()) { APSInt IntResult; if (!EvaluateInteger(SE, IntResult, Info)) - return false; - Val = APValue(IntResult); + return false; + Val = APValue(std::move(IntResult)); } else if (SETy->isRealFloatingType()) { - APFloat F(0.0); - if (!EvaluateFloat(SE, F, Info)) - return false; - Val = APValue(F); + APFloat FloatResult(0.0); + if (!EvaluateFloat(SE, FloatResult, Info)) + return false; + Val = APValue(std::move(FloatResult)); } else { return Error(E); } + if (!convertVectorSplatLiteral(Info, E, Val)) + return Error(E); + // Splat and create vector APValue. SmallVector Elts(NElts, Val); return Success(Elts, E); Index: lib/CodeGen/CGExprConstant.cpp =================================================================== --- lib/CodeGen/CGExprConstant.cpp +++ lib/CodeGen/CGExprConstant.cpp @@ -1350,15 +1350,17 @@ return llvm::ConstantStruct::get(STy, Complex); } case APValue::Vector: { - SmallVector Inits; unsigned NumElts = Value.getVectorLength(); + SmallVector Inits(NumElts); - for (unsigned i = 0; i != NumElts; ++i) { - const APValue &Elt = Value.getVectorElt(i); + for (unsigned I = 0; I != NumElts; ++I) { + const APValue &Elt = Value.getVectorElt(I); if (Elt.isInt()) - Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt())); + Inits[I] = llvm::ConstantInt::get(VMContext, Elt.getInt()); + else if (Elt.isFloat()) + Inits[I] = llvm::ConstantFP::get(VMContext, Elt.getFloat()); else - Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat())); + llvm_unreachable("unsupported vector element type"); } return llvm::ConstantVector::get(Inits); } Index: test/CodeGenCXX/builtins-systemz-zvector.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/builtins-systemz-zvector.cpp @@ -0,0 +1,52 @@ +// 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 + +#include + +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]; +}