ahatanak updated this revision to Diff 115304.
ahatanak added a comment.
Rebase.
https://reviews.llvm.org/D32520
Files:
include/clang/Sema/Sema.h
lib/CodeGen/CGExprScalar.cpp
lib/Sema/SemaExpr.cpp
test/CodeGen/fp16vec-ops.c
test/Sema/fp16vec-sema.c
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}}
+}
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: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -7405,16 +7405,26 @@
Sema::AssignConvertType
Sema::CheckAssignmentConstraints(SourceLocation Loc,
- QualType LHSType, QualType RHSType) {
+ QualType LHSType, QualType RHSType,
+ bool IsCompAssign) {
// Fake up an opaque expression. We don't actually care about what
// cast operations are required, so if CheckAssignmentConstraints
// adds casts to this they'll be wasted, but fortunately that doesn't
// usually happen on valid code.
OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue);
ExprResult RHSPtr = &RHSExpr;
CastKind K = CK_Invalid;
- return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false);
+ return CheckAssignmentConstraints(LHSType, RHSPtr, K, /*ConvertRHS=*/false,
+ IsCompAssign);
+}
+
+/// 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<VectorType>())
+ return VT->getElementType() == ElementType;
+ return false;
}
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
@@ -7436,7 +7446,8 @@
/// Sets 'Kind' for any result kind except Incompatible.
Sema::AssignConvertType
Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
- CastKind &Kind, bool ConvertRHS) {
+ CastKind &Kind, bool ConvertRHS,
+ bool IsCompAssign) {
QualType RHSType = RHS.get()->getType();
QualType OrigLHSType = LHSType;
@@ -7496,6 +7507,18 @@
// Conversions to or from vector type.
if (LHSType->isVectorType() || RHSType->isVectorType()) {
if (LHSType->isVectorType() && RHSType->isVectorType()) {
+ // If this is a compound assignment, allow converting the RHS to the type
+ // of the LHS.
+ if (IsCompAssign && isVector(LHSType, Context.HalfTy)) {
+ assert(isVector(RHSType, Context.FloatTy) &&
+ "RHS is not a vector of floats");
+ assert(LHSType->getAs<VectorType>()->getNumElements() ==
+ RHSType->getAs<VectorType>()->getNumElements() &&
+ "LHS and RHS have different number of elements");
+ Kind = CK_FloatingCast;
+ return Compatible;
+ }
+
// Allow assignments of an AltiVec vector type to an equivalent GCC
// vector type and vice versa
if (Context.areCompatibleVectorTypes(LHSType, RHSType)) {
@@ -8045,6 +8068,25 @@
return false;
}
+/// Convert E, which is a vector, to a vector that has a different element
+/// type.
+static ExprResult convertVector(Expr *E, QualType ElementType, Sema &S) {
+ const auto *VecTy = E->getType()->getAs<VectorType>();
+ 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<ImplicitCastExpr>(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,
@@ -10541,7 +10583,8 @@
}
} else {
// Compound assignment "x += y"
- ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
+ ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType,
+ /*CompAssign*/true);
}
if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType,
@@ -11269,6 +11312,34 @@
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");
+ RHS = convertVector(RHS.get(), Context.FloatTy, S);
+ QualType BinOpResTy = RHS.get()->getType();
+ 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<VectorType>()->getElementType(), S);
+}
+
/// 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.
@@ -11300,6 +11371,7 @@
QualType CompResultTy; // Type of computation result
ExprValueKind VK = VK_RValue;
ExprObjectKind OK = OK_Ordinary;
+ bool ConvertHalfVec = false;
if (!getLangOpts().CPlusPlus) {
// C cannot handle TypoExpr nodes on either side of a binop because it
@@ -11363,16 +11435,19 @@
break;
case BO_Mul:
case BO_Div:
+ ConvertHalfVec = true;
ResultTy = CheckMultiplyDivideOperands(LHS, RHS, OpLoc, false,
Opc == BO_Div);
break;
case BO_Rem:
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:
@@ -11383,10 +11458,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:
@@ -11398,10 +11475,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;
@@ -11415,11 +11494,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);
@@ -11452,6 +11533,16 @@
if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid())
return ExprError();
+ // Some of the binary operations require promoting operands of half vector
+ // and truncating the result. For now, we do this only when HalfArgsAndReturn
+ // is set (that is, when the target is arm or arm64).
+ bool LHSHalfVec = isVector(LHS.get()->getType(), Context.HalfTy);
+ assert(isVector(RHS.get()->getType(), Context.HalfTy) == LHSHalfVec &&
+ "both sides are half vectors or neither sides are");
+ ConvertHalfVec = ConvertHalfVec && LHSHalfVec &&
+ !Context.getLangOpts().NativeHalfType &&
+ Context.getLangOpts().HalfArgsAndReturns;
+
// Check for array bounds violations for both sides of the BinaryOperator
CheckArrayAccess(LHS.get());
CheckArrayAccess(RHS.get());
@@ -11474,14 +11565,24 @@
dyn_cast<ObjCIvarRefExpr>(LHS.get()->IgnoreParenCasts()))
DiagnoseDirectIsaAccess(*this, OIRE, OpLoc, RHS.get());
- if (CompResultTy.isNull())
+ 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);
+ }
+
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);
@@ -11832,6 +11933,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 '&'.
@@ -11871,6 +11973,17 @@
case UO_Minus:
Input = UsualUnaryConversions(Input.get());
if (Input.isInvalid()) return ExprError();
+ // Unary plus and minus require promoting an operand of half vector and
+ // truncating the result. For now, we do this only when HalfArgsAndReturns
+ // is set (that is, when the target is arm or arm64).
+ ConvertHalfVec =
+ !Context.getLangOpts().NativeHalfType &&
+ Context.getLangOpts().HalfArgsAndReturns &&
+ isVector(Input.get()->getType(), Context.HalfTy);
+
+ // 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;
@@ -12008,8 +12121,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: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -1014,10 +1014,48 @@
return Builder.CreateVectorSplat(NumElements, Src, "splat");
}
- // Allow bitcast from vector to integer/fp of the same size.
- if (isa<llvm::VectorType>(SrcTy) ||
- isa<llvm::VectorType>(DstTy))
- return Builder.CreateBitCast(Src, DstTy, "conv");
+ if (isa<llvm::VectorType>(SrcTy) || isa<llvm::VectorType>(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();
+
+ // Truncate an i32 vector to an i16 vector.
+ if (SrcElementTy->isIntegerTy()) {
+ assert(SrcElementTy == CGF.Int32Ty &&
+ "Src is expected to be an i32 vector");
+ assert(DstElementTy == CGF.Int16Ty &&
+ "Dst is expected to be an i16 vector");
+ return Builder.CreateIntCast(Src, DstTy, false, "conv");
+ }
+
+ assert(SrcElementTy->isFloatingPointTy() &&
+ DstElementTy->isFloatingPointTy() &&
+ "Source and destination must be floating point vectors");
+
+ // Truncate a float vector to a half vector.
+ if (SrcSize > DstSize) {
+ assert(SrcElementTy->isFloatTy() && DstElementTy->isHalfTy() &&
+ "float vector to half vector conversion expected");
+ return Builder.CreateFPTrunc(Src, DstTy, "conv");
+ }
+
+ // Promote a half vector to a float vector.
+ assert(SrcElementTy->isHalfTy() && DstElementTy->isFloatTy() &&
+ "half vector to float vector conversion expected");
+ return Builder.CreateFPExt(Src, DstTy, "conv");
+ }
// Finally, we have the arithmetic types: real int/float.
Value *Res = nullptr;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -9373,15 +9373,17 @@
/// C99 6.5.16.
AssignConvertType CheckAssignmentConstraints(SourceLocation Loc,
QualType LHSType,
- QualType RHSType);
+ QualType RHSType,
+ bool IsCompAssign = false);
/// Check assignment constraints and optionally prepare for a conversion of
/// the RHS to the LHS type. The conversion is prepared for if ConvertRHS
/// is true.
AssignConvertType CheckAssignmentConstraints(QualType LHSType,
ExprResult &RHS,
CastKind &Kind,
- bool ConvertRHS = true);
+ bool ConvertRHS = true,
+ bool IsCompAssign = false);
/// Check assignment constraints for an assignment of RHS to LHSType.
///
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits