Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -1014,10 +1014,41 @@ return Builder.CreateVectorSplat(NumElements, Src, "splat"); } - // Allow bitcast from vector to integer/fp of the same size. - if (isa(SrcTy) || - isa(DstTy)) - return Builder.CreateBitCast(Src, DstTy, "conv"); + if (isa(SrcTy) || isa(DstTy)) { + // Allow bitcast from vector to integer/fp of the same size. + unsigned SrcSize = SrcTy->getPrimitiveSizeInBits(); + unsigned DstSize = DstTy->getPrimitiveSizeInBits(); + if (SrcSize == DstSize) + return Builder.CreateBitCast(Src, DstTy, "conv"); + + // Conversions between vectors of different sizes are not allowed except + // when vectors of half are involved. Operations on storage-only half + // vectors require promoting half vector operands to float vectors and + // truncating the result, which is either an int or float vector, to a + // short or half vector. + + // Source and destination are both expected to be vectors. + llvm::Type *SrcElementTy = SrcTy->getVectorElementType(); + llvm::Type *DstElementTy = DstTy->getVectorElementType(); + + assert(((SrcElementTy->isIntegerTy() && + DstElementTy->isIntegerTy()) || + (SrcElementTy->isFloatingPointTy() && + DstElementTy->isFloatingPointTy())) && + "unexpected conversion between a floating-point vector and an " + "integer vector"); + + // Truncate an i32 vector to an i16 vector. + if (SrcElementTy->isIntegerTy()) + return Builder.CreateIntCast(Src, DstTy, false, "conv"); + + // Truncate a float vector to a half vector. + if (SrcSize > DstSize) + return Builder.CreateFPTrunc(Src, DstTy, "conv"); + + // Promote a half vector to a float vector. + return Builder.CreateFPExt(Src, DstTy, "conv"); + } // Finally, we have the arithmetic types: real int/float. Value *Res = nullptr; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -7503,6 +7503,14 @@ return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false); } +/// This helper function returns true if QT is a vector type that has element +/// type ElementType. +static bool isVector(QualType QT, QualType ElementType) { + if (const VectorType *VT = QT->getAs()) + return VT->getElementType() == ElementType; + return false; +} + /// CheckAssignmentConstraints (C99 6.5.16) - This routine currently /// has code to accommodate several GCC extensions when type checking /// pointers. Here are some objectionable examples that GCC considers warnings: @@ -8131,6 +8139,25 @@ return false; } +/// Convert vector E to a vector with the same number of elements but different +/// element type. +static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) { + const auto *VecTy = E->getType()->getAs(); + assert(VecTy && "Expression E must be a vector"); + QualType NewVecTy = S.Context.getVectorType(ElementType, + VecTy->getNumElements(), + VecTy->getVectorKind()); + + // Look through the implicit cast. Return the subexpression if its type is + // NewVecTy. + if (auto *ICE = dyn_cast(E)) + if (ICE->getSubExpr()->getType() == NewVecTy) + return ICE->getSubExpr(); + + auto Cast = ElementType->isIntegerType() ? CK_IntegralCast : CK_FloatingCast; + return S.ImpCastExprToType(E, NewVecTy, Cast); +} + /// Test if a (constant) integer Int can be casted to another integer type /// IntTy without losing precision. static bool canConvertIntToOtherIntTy(Sema &S, ExprResult *Int, @@ -11465,6 +11492,41 @@ return nullptr; } +// This helper function promotes a binary operator's operands (which are of a +// half vector type) to a vector of floats and then truncates the result to +// a vector of either half or short. +static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, + BinaryOperatorKind Opc, QualType ResultTy, + ExprValueKind VK, ExprObjectKind OK, + bool IsCompAssign, SourceLocation OpLoc, + FPOptions FPFeatures) { + auto &Context = S.getASTContext(); + assert((isVector(ResultTy, Context.HalfTy) || + isVector(ResultTy, Context.ShortTy)) && + "Result must be a vector of half or short"); + assert(isVector(LHS.get()->getType(), Context.HalfTy) && + isVector(RHS.get()->getType(), Context.HalfTy) && + "both operands expected to be a half vector"); + + RHS = convertVector(RHS.get(), Context.FloatTy, S); + QualType BinOpResTy = RHS.get()->getType(); + + // If Opc is a comparison, ResultType is a vector of shorts. In that case, + // change BinOpResTy to a vector of ints. + if (isVector(ResultTy, Context.ShortTy)) + BinOpResTy = S.GetSignedVectorType(BinOpResTy); + + if (IsCompAssign) + return new (Context) CompoundAssignOperator( + LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy, + OpLoc, FPFeatures); + + LHS = convertVector(LHS.get(), Context.FloatTy, S); + auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, + VK, OK, OpLoc, FPFeatures); + return convertVector(BO, ResultTy->getAs()->getElementType(), S); +} + static std::pair CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr) { @@ -11485,6 +11547,14 @@ return std::make_pair(LHS, RHS); } +/// Returns true if conversion between vectors of halfs and vectors of floats +/// is needed. +static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, + QualType SrcType) { + return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && + Ctx.getLangOpts().HalfArgsAndReturns && isVector(SrcType, Ctx.HalfTy); +} + /// CreateBuiltinBinOp - Creates a new built-in binary operation with /// operator @p Opc at location @c TokLoc. This routine only supports /// built-in operations; ActOnBinOp handles overloaded operators. @@ -11516,6 +11586,7 @@ QualType CompResultTy; // Type of computation result ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; + bool ConvertHalfVec = false; std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr); if (!LHS.isUsable() || !RHS.isUsable()) @@ -11567,6 +11638,7 @@ break; case BO_Mul: case BO_Div: + ConvertHalfVec = true; ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false, Opc == BO_Div); break; @@ -11574,9 +11646,11 @@ ResultTy = CheckRemainderOperands(LHS, RHS, OpLoc); break; case BO_Add: + ConvertHalfVec = true; ResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc); break; case BO_Sub: + ConvertHalfVec = true; ResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc); break; case BO_Shl: @@ -11587,10 +11661,12 @@ case BO_LT: case BO_GE: case BO_GT: + ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true); break; case BO_EQ: case BO_NE: + ConvertHalfVec = true; ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false); break; case BO_And: @@ -11602,10 +11678,12 @@ break; case BO_LAnd: case BO_LOr: + ConvertHalfVec = true; ResultTy = CheckLogicalOperands(LHS, RHS, OpLoc, Opc); break; case BO_MulAssign: case BO_DivAssign: + ConvertHalfVec = true; CompResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; @@ -11619,11 +11697,13 @@ ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_AddAssign: + ConvertHalfVec = true; CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); break; case BO_SubAssign: + ConvertHalfVec = true; CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy); if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); @@ -11656,6 +11736,16 @@ if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + // Some of the binary operations require promoting operands of half vector to + // float vectors and truncating the result back to half vector. For now, we do + // this only when HalfArgsAndReturn is set (that is, when the target is arm or + // arm64). + assert(isVector(RHS.get()->getType(), Context.HalfTy) == + isVector(LHS.get()->getType(), Context.HalfTy) && + "both sides are half vectors or neither sides are"); + ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, + LHS.get()->getType()); + // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); CheckArrayAccess(RHS.get()); @@ -11678,14 +11768,26 @@ dyn_cast(LHS.get()->IgnoreParenCasts())) DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get()); - if (CompResultTy.isNull()) + // Opc is not a compound assignment if CompResultTy is null. + if (CompResultTy.isNull()) { + if (ConvertHalfVec) + return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, + OpLoc, FPFeatures); return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, FPFeatures); + } + + // Handle compound assignments. if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; OK = LHS.get()->getObjectKind(); } + + if (ConvertHalfVec) + return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, + OpLoc, FPFeatures); + return new (Context) CompoundAssignOperator( LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc, FPFeatures); @@ -12043,6 +12145,7 @@ ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resultType; + bool ConvertHalfVec = false; if (getLangOpts().OpenCL) { QualType Ty = InputExpr->getType(); // The only legal unary operation for atomics is '&'. @@ -12082,6 +12185,16 @@ case UO_Minus: Input = UsualUnaryConversions(Input.get()); if (Input.isInvalid()) return ExprError(); + // Unary plus and minus require promoting an operand of half vector to a + // float vector and truncating the result back to a half vector. For now, we + // do this only when HalfArgsAndReturns is set (that is, when the target is + // arm or arm64). + ConvertHalfVec = + needsConversionOfHalfVec(true, Context, Input.get()->getType()); + + // If the operand is a half vector, promote it to a float vector. + if (ConvertHalfVec) + Input = convertVector(Input.get(), Context.FloatTy, *this); resultType = Input.get()->getType(); if (resultType->isDependentType()) break; @@ -12219,8 +12332,12 @@ if (Opc != UO_AddrOf && Opc != UO_Deref) CheckArrayAccess(Input.get()); - return new (Context) + auto *UO = new (Context) UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc); + // Convert the result back to a half vector. + if (ConvertHalfVec) + return convertVector(UO, Context.HalfTy, *this); + return UO; } /// \brief Determine whether the given expression is a qualified member Index: test/CodeGen/fp16vec-ops.c =================================================================== --- /dev/null +++ test/CodeGen/fp16vec-ops.c @@ -0,0 +1,162 @@ +// REQUIRES: arm-registered-target +// RUN: %clang_cc1 -triple arm64-apple-ios9 -emit-llvm -o - -fallow-half-arguments-and-returns %s | FileCheck %s --check-prefix=CHECK +// RUN: %clang_cc1 -triple armv7-apple-ios9 -emit-llvm -o - -fallow-half-arguments-and-returns %s | FileCheck %s --check-prefix=CHECK + +typedef __fp16 half4 __attribute__ ((vector_size (8))); +typedef short short4 __attribute__ ((vector_size (8))); + +half4 hv0, hv1; +short4 sv0; + +// CHECK-LABEL: testFP16Vec0 +// CHECK: %[[V0:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV:.*]] = fpext <4 x half> %[[V0]] to <4 x float> +// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV1:.*]] = fpext <4 x half> %[[V1]] to <4 x float> +// CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV]], %[[CONV1]] +// CHECK: %[[CONV2:.*]] = fptrunc <4 x float> %[[ADD]] to <4 x half> +// CHECK: store <4 x half> %[[CONV2]], <4 x half>* @hv0, align 8 +// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV3:.*]] = fpext <4 x half> %[[V2]] to <4 x float> +// CHECK: %[[V3:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV4:.*]] = fpext <4 x half> %[[V3]] to <4 x float> +// CHECK: %[[SUB:.*]] = fsub <4 x float> %[[CONV3]], %[[CONV4]] +// CHECK: %[[CONV5:.*]] = fptrunc <4 x float> %[[SUB]] to <4 x half> +// CHECK: store <4 x half> %[[CONV5]], <4 x half>* @hv0, align 8 +// CHECK: %[[V4:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV6:.*]] = fpext <4 x half> %[[V4]] to <4 x float> +// CHECK: %[[V5:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV7:.*]] = fpext <4 x half> %[[V5]] to <4 x float> +// CHECK: %[[MUL:.*]] = fmul <4 x float> %[[CONV6]], %[[CONV7]] +// CHECK: %[[CONV8:.*]] = fptrunc <4 x float> %[[MUL]] to <4 x half> +// CHECK: store <4 x half> %[[CONV8]], <4 x half>* @hv0, align 8 +// CHECK: %[[V6:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV9:.*]] = fpext <4 x half> %[[V6]] to <4 x float> +// CHECK: %[[V7:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV10:.*]] = fpext <4 x half> %[[V7]] to <4 x float> +// CHECK: %[[DIV:.*]] = fdiv <4 x float> %[[CONV9]], %[[CONV10]] +// CHECK: %[[CONV11:.*]] = fptrunc <4 x float> %[[DIV]] to <4 x half> +// CHECK: store <4 x half> %[[CONV11]], <4 x half>* @hv0, align 8 + +void testFP16Vec0() { + hv0 = hv0 + hv1; + hv0 = hv0 - hv1; + hv0 = hv0 * hv1; + hv0 = hv0 / hv1; +} + +// CHECK-LABEL: testFP16Vec1 +// CHECK: %[[V0:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV:.*]] = fpext <4 x half> %[[V0]] to <4 x float> +// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV1:.*]] = fpext <4 x half> %[[V1]] to <4 x float> +// CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV1]], %[[CONV]] +// CHECK: %[[CONV2:.*]] = fptrunc <4 x float> %[[ADD]] to <4 x half> +// CHECK: store <4 x half> %[[CONV2]], <4 x half>* @hv0, align 8 +// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV3:.*]] = fpext <4 x half> %[[V2]] to <4 x float> +// CHECK: %[[V3:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV4:.*]] = fpext <4 x half> %[[V3]] to <4 x float> +// CHECK: %[[SUB:.*]] = fsub <4 x float> %[[CONV4]], %[[CONV3]] +// CHECK: %[[CONV5:.*]] = fptrunc <4 x float> %[[SUB]] to <4 x half> +// CHECK: store <4 x half> %[[CONV5]], <4 x half>* @hv0, align 8 +// CHECK: %[[V4:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV6:.*]] = fpext <4 x half> %[[V4]] to <4 x float> +// CHECK: %[[V5:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV7:.*]] = fpext <4 x half> %[[V5]] to <4 x float> +// CHECK: %[[MUL:.*]] = fmul <4 x float> %[[CONV7]], %[[CONV6]] +// CHECK: %[[CONV8:.*]] = fptrunc <4 x float> %[[MUL]] to <4 x half> +// CHECK: store <4 x half> %[[CONV8]], <4 x half>* @hv0, align 8 +// CHECK: %[[V6:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV9:.*]] = fpext <4 x half> %[[V6]] to <4 x float> +// CHECK: %[[V7:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV10:.*]] = fpext <4 x half> %[[V7]] to <4 x float> +// CHECK: %[[DIV:.*]] = fdiv <4 x float> %[[CONV10]], %[[CONV9]] +// CHECK: %[[CONV11:.*]] = fptrunc <4 x float> %[[DIV]] to <4 x half> +// CHECK: store <4 x half> %[[CONV11]], <4 x half>* @hv0, align 8 + +void testFP16Vec1() { + hv0 += hv1; + hv0 -= hv1; + hv0 *= hv1; + hv0 /= hv1; +} + +// CHECK-LABEL: testFP16Vec2 +// CHECK: %[[CADDR:.*]] = alloca i32, align 4 +// CHECK: store i32 %[[C:.*]], i32* %[[CADDR]], align 4 +// CHECK: %[[V0:.*]] = load i32, i32* %[[CADDR]], align 4 +// CHECK: %[[TOBOOL:.*]] = icmp ne i32 %[[V0]], 0 +// CHECK: br i1 %[[TOBOOL]], label %{{.*}}, label %{{.*}} +// +// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: br label %{{.*}} +// +// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: br label %{{.*}} +// +// CHECK: %[[COND:.*]] = phi <4 x half> [ %[[V1]], %{{.*}} ], [ %[[V2]], %{{.*}} ] +// CHECK: store <4 x half> %[[COND]], <4 x half>* @hv0, align 8 + +void testFP16Vec2(int c) { + hv0 = c ? hv0 : hv1; +} + +// CHECK-LABEL: testFP16Vec3 +// CHECK: %[[V0:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV:.*]] = fpext <4 x half> %[[V0]] to <4 x float> +// CHECK: %[[V1:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV1:.*]] = fpext <4 x half> %[[V1]] to <4 x float> +// CHECK: %[[CMP:.*]] = fcmp oeq <4 x float> %[[CONV]], %[[CONV1]] +// CHECK: %[[SEXT:.*]] = sext <4 x i1> %[[CMP]] to <4 x i32> +// CHECK: %[[CONV2:.*]] = trunc <4 x i32> %[[SEXT]] to <4 x i16> +// CHECK: store <4 x i16> %[[CONV2]], <4 x i16>* @sv0, align 8 +// CHECK: %[[V2:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV3:.*]] = fpext <4 x half> %[[V2]] to <4 x float> +// CHECK: %[[V3:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV4:.*]] = fpext <4 x half> %[[V3]] to <4 x float> +// CHECK: %[[CMP5:.*]] = fcmp une <4 x float> %[[CONV3]], %[[CONV4]] +// CHECK: %[[SEXT6:.*]] = sext <4 x i1> %[[CMP5]] to <4 x i32> +// CHECK: %[[CONV7:.*]] = trunc <4 x i32> %[[SEXT6]] to <4 x i16> +// CHECK: store <4 x i16> %[[CONV7]], <4 x i16>* @sv0, align 8 +// CHECK: %[[V4:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV8:.*]] = fpext <4 x half> %[[V4]] to <4 x float> +// CHECK: %[[V5:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV9:.*]] = fpext <4 x half> %[[V5]] to <4 x float> +// CHECK: %[[CMP10:.*]] = fcmp olt <4 x float> %[[CONV8]], %[[CONV9]] +// CHECK: %[[SEXT11:.*]] = sext <4 x i1> %[[CMP10]] to <4 x i32> +// CHECK: %[[CONV12:.*]] = trunc <4 x i32> %[[SEXT11]] to <4 x i16> +// CHECK: store <4 x i16> %[[CONV12]], <4 x i16>* @sv0, align 8 +// CHECK: %[[V6:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV13:.*]] = fpext <4 x half> %[[V6]] to <4 x float> +// CHECK: %[[V7:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV14:.*]] = fpext <4 x half> %[[V7]] to <4 x float> +// CHECK: %[[CMP15:.*]] = fcmp ogt <4 x float> %[[CONV13]], %[[CONV14]] +// CHECK: %[[SEXT16:.*]] = sext <4 x i1> %[[CMP15]] to <4 x i32> +// CHECK: %[[CONV17:.*]] = trunc <4 x i32> %[[SEXT16]] to <4 x i16> +// CHECK: store <4 x i16> %[[CONV17]], <4 x i16>* @sv0, align 8 +// CHECK: %[[V8:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV18:.*]] = fpext <4 x half> %[[V8]] to <4 x float> +// CHECK: %[[V9:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV19:.*]] = fpext <4 x half> %[[V9]] to <4 x float> +// CHECK: %[[CMP20:.*]] = fcmp ole <4 x float> %[[CONV18]], %[[CONV19]] +// CHECK: %[[SEXT21:.*]] = sext <4 x i1> %[[CMP20]] to <4 x i32> +// CHECK: %[[CONV22:.*]] = trunc <4 x i32> %[[SEXT21]] to <4 x i16> +// CHECK: store <4 x i16> %[[CONV22]], <4 x i16>* @sv0, align 8 +// CHECK: %[[V10:.*]] = load <4 x half>, <4 x half>* @hv0, align 8 +// CHECK: %[[CONV23:.*]] = fpext <4 x half> %[[V10]] to <4 x float> +// CHECK: %[[V11:.*]] = load <4 x half>, <4 x half>* @hv1, align 8 +// CHECK: %[[CONV24:.*]] = fpext <4 x half> %[[V11]] to <4 x float> +// CHECK: %[[CMP25:.*]] = fcmp oge <4 x float> %[[CONV23]], %[[CONV24]] +// CHECK: %[[SEXT26:.*]] = sext <4 x i1> %[[CMP25]] to <4 x i32> +// CHECK: %[[CONV27:.*]] = trunc <4 x i32> %[[SEXT26]] to <4 x i16> +// CHECK: store <4 x i16> %[[CONV27]], <4 x i16>* @sv0, align 8 + +void testFP16Vec3() { + sv0 = hv0 == hv1; + sv0 = hv0 != hv1; + sv0 = hv0 < hv1; + sv0 = hv0 > hv1; + sv0 = hv0 <= hv1; + sv0 = hv0 >= hv1; +} Index: test/Sema/fp16vec-sema.c =================================================================== --- /dev/null +++ test/Sema/fp16vec-sema.c @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +typedef __fp16 half4 __attribute__ ((vector_size (8))); +typedef float float4 __attribute__ ((vector_size (16))); +typedef short short4 __attribute__ ((vector_size (8))); +typedef int int4 __attribute__ ((vector_size (16))); + +half4 hv0, hv1; +float4 fv0, fv1; +short4 sv0; +int4 iv0; + +void testFP16Vec(int c) { + hv0 = hv0 + hv1; + hv0 = hv0 - hv1; + hv0 = hv0 * hv1; + hv0 = hv0 / hv1; + hv0 = c ? hv0 : hv1; + hv0 += hv1; + hv0 -= hv1; + hv0 *= hv1; + hv0 /= hv1; + sv0 = hv0 == hv1; + sv0 = hv0 != hv1; + sv0 = hv0 < hv1; + sv0 = hv0 > hv1; + sv0 = hv0 <= hv1; + sv0 = hv0 >= hv1; + sv0 = hv0 || hv1; // expected-error{{logical expression with vector types 'half4' (vector of 4 '__fp16' values) and 'half4' is only supported in C++}} + sv0 = hv0 && hv1; // expected-error{{logical expression with vector types 'half4' (vector of 4 '__fp16' values) and 'half4' is only supported in C++}} + + // Implicit conversion between half vectors and float vectors are not allowed. + hv0 = fv0; // expected-error{{assigning to}} + fv0 = hv0; // expected-error{{assigning to}} + hv0 = (half4)fv0; // expected-error{{invalid conversion between}} + fv0 = (float4)hv0; // expected-error{{invalid conversion between}} + hv0 = fv0 + fv1; // expected-error{{assigning to}} + fv0 = hv0 + hv1; // expected-error{{assigning to}} + hv0 = hv0 + fv1; // expected-error{{cannot convert between vector}} + hv0 = c ? hv0 : fv1; // expected-error{{cannot convert between vector}} + sv0 = hv0 == fv1; // expected-error{{cannot convert between vector}} + sv0 = hv0 < fv1; // expected-error{{cannot convert between vector}} + sv0 = hv0 || fv1; // expected-error{{cannot convert between vector}} expected-error{{invalid operands to binary expression}} + iv0 = hv0 == hv1; // expected-error{{assigning to}} + + // FIXME: clang currently disallows using these operators on vectors, which is + // allowed by gcc. + sv0 = !hv0; // expected-error{{invalid argument type}} + hv0++; // expected-error{{cannot increment value of type}} + ++hv0; // expected-error{{cannot increment value of type}} +}