[clang][AArch64][SVE] Implicit conversions for vector-scalar operations

This patch allows the same implicit conversions for vector-scalar
operations in SVE that are allowed for NEON.

Depends on D126377

Reviewed By: c-rhodes

Differential Revision: https://reviews.llvm.org/D126380
This commit is contained in:
David Truby 2022-06-13 09:54:26 +00:00
parent 988682a389
commit b4f2f7bebd
6 changed files with 175 additions and 56 deletions

View File

@ -13574,6 +13574,29 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
// Strip SVE vector types
if (SourceBT && SourceBT->isVLSTBuiltinType()) {
// Need the original target type for vector type checks
const Type *OriginalTarget = S.Context.getCanonicalType(T).getTypePtr();
// Handle conversion from scalable to fixed when msve-vector-bits is
// specified
if (S.Context.areCompatibleSveTypes(QualType(OriginalTarget, 0),
QualType(Source, 0)) ||
S.Context.areLaxCompatibleSveTypes(QualType(OriginalTarget, 0),
QualType(Source, 0)))
return;
// If the vector cast is cast between two vectors of the same size, it is
// a bitcast, not a conversion.
if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target))
return;
Source = SourceBT->getSveEltType(S.Context).getTypePtr();
}
if (TargetBT && TargetBT->isVLSTBuiltinType())
Target = TargetBT->getSveEltType(S.Context).getTypePtr();
// If the source is floating point...
if (SourceBT && SourceBT->isFloatingPoint()) {
// ...and the target is floating point...

View File

@ -10261,12 +10261,18 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
ExprResult *Vector) {
QualType ScalarTy = Scalar->get()->getType().getUnqualifiedType();
QualType VectorTy = Vector->get()->getType().getUnqualifiedType();
const auto *VT = VectorTy->castAs<VectorType>();
QualType VectorEltTy;
assert(!isa<ExtVectorType>(VT) &&
"ExtVectorTypes should not be handled here!");
QualType VectorEltTy = VT->getElementType();
if (const auto *VT = VectorTy->getAs<VectorType>()) {
assert(!isa<ExtVectorType>(VT) &&
"ExtVectorTypes should not be handled here!");
VectorEltTy = VT->getElementType();
} else if (VectorTy->isVLSTBuiltinType()) {
VectorEltTy =
VectorTy->castAs<BuiltinType>()->getSveEltType(S.getASTContext());
} else {
llvm_unreachable("Only Fixed-Length and SVE Vector types are handled here");
}
// Reject cases where the vector element type or the scalar element type are
// not integral or floating point types.
@ -10593,24 +10599,14 @@ QualType Sema::CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS,
if (Context.hasSameType(LHSType, RHSType))
return LHSType;
auto tryScalableVectorConvert = [this](ExprResult *Src, QualType SrcType,
QualType DestType) {
const QualType DestBaseType = DestType->getSveEltType(Context);
if (DestBaseType->getUnqualifiedDesugaredType() ==
SrcType->getUnqualifiedDesugaredType()) {
unsigned DiagID = diag::err_typecheck_invalid_operands;
if (!tryVectorConvertAndSplat(*this, Src, SrcType, DestBaseType, DestType,
DiagID))
return DestType;
}
return QualType();
};
if (LHSType->isVLSTBuiltinType() && !RHSType->isVLSTBuiltinType()) {
auto DestType = tryScalableVectorConvert(&RHS, RHSType, LHSType);
if (DestType == QualType())
return InvalidOperands(Loc, LHS, RHS);
return DestType;
if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS))
return LHSType;
}
if (RHSType->isVLSTBuiltinType() && !LHSType->isVLSTBuiltinType()) {
if (LHS.get()->isLValue() ||
!tryGCCVectorConvertAndSplat(*this, &LHS, &RHS))
return RHSType;
}
if ((!LHSType->isVLSTBuiltinType() && !LHSType->isRealType()) ||

View File

@ -328,6 +328,132 @@ svfloat64_t add_scalar_f64(svfloat64_t a, double b) {
return a + b;
}
// CHECK-LABEL: @add_i8_i_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = add <vscale x 16 x i8> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 16 x i8> [[ADD]]
//
svint8_t add_i8_i_lit(svint8_t a) {
return a + 0;
}
// CHECK-LABEL: @add_i8_il_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = add <vscale x 16 x i8> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 16 x i8> [[ADD]]
//
svint8_t add_i8_il_lit(svint8_t a) {
return a + 0l;
}
// CHECK-LABEL: @add_i8_ill_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = add <vscale x 16 x i8> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 16 x i8> [[ADD]]
//
svint8_t add_i8_ill_lit(svint8_t a) {
return a + 0ll;
}
// CHECK-LABEL: @add_i8_u_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = add <vscale x 16 x i8> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 16 x i8> [[ADD]]
//
svint8_t add_i8_u_lit(svint8_t a) {
return a + 0u;
}
// CHECK-LABEL: @add_i8_ul_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = add <vscale x 16 x i8> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 16 x i8> [[ADD]]
//
svint8_t add_i8_ul_lit(svint8_t a) {
return a + 0ul;
}
// CHECK-LABEL: @add_i8_ull_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = add <vscale x 16 x i8> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 16 x i8> [[ADD]]
//
svint8_t add_i8_ull_lit(svint8_t a) {
return a + 0ull;
}
// CHECK-LABEL: @add_f64_i_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_i_lit(svfloat64_t a) {
return a + 0;
}
// CHECK-LABEL: @add_f64_il_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_il_lit(svfloat64_t a) {
return a + 0l;
}
// CHECK-LABEL: @add_f64_ill_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_ill_lit(svfloat64_t a) {
return a + 0ll;
}
// CHECK-LABEL: @add_f64_u_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_u_lit(svfloat64_t a) {
return a + 0u;
}
// CHECK-LABEL: @add_f64_ul_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_ul_lit(svfloat64_t a) {
return a + 0ul;
}
// CHECK-LABEL: @add_f64_ull_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_ull_lit(svfloat64_t a) {
return a + 0ull;
}
// CHECK-LABEL: @add_f64_f_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_f_lit(svfloat64_t a) {
return a + 0.f;
}
// CHECK-LABEL: @add_f64_d_lit(
// CHECK-NEXT: entry:
// CHECK-NEXT: [[ADD:%.*]] = fadd <vscale x 2 x double> [[A:%.*]], zeroinitializer
// CHECK-NEXT: ret <vscale x 2 x double> [[ADD]]
//
svfloat64_t add_f64_d_lit(svfloat64_t a) {
return a + 0.;
}
// SUBTRACTION
// CHECK-LABEL: @sub_i8(

View File

@ -701,3 +701,11 @@ void mod(svint8_t i8, svint16_t i16, svint32_t i32, svint64_t i64,
(void)(s % f16); // expected-error{{invalid operands to binary expression}}
(void)(s % f32); // expected-error{{invalid operands to binary expression}}
}
svint8_t svi8(svint8_t a) {
return a + 256; // expected-error{{cannot convert between scalar type 'int' and vector type 'svint8_t' (aka '__SVInt8_t') as implicit conversion would cause truncation}}
}
svint8_t svi8_128(svint8_t a) {
return a + 128; // expected-warning{{implicit conversion from 'int' to 'svint8_t' (aka '__SVInt8_t') changes value from 128 to -128}}
}

View File

@ -201,23 +201,6 @@ void func(int sel) {
local_int8 &&init_int8; // expected-error {{invalid operands to binary expression}}
local_int8 || init_int8; // expected-error {{invalid operands to binary expression}}
local_int8 + 0; // expected-error {{invalid operands to binary expression}}
local_int8 - 0; // expected-error {{invalid operands to binary expression}}
local_int8 * 0; // expected-error {{invalid operands to binary expression}}
local_int8 / 0; // expected-error {{invalid operands to binary expression}}
local_int8 % 0; // expected-error {{invalid operands to binary expression}}
local_int8 & 0; // expected-error {{invalid operands to binary expression}}
local_int8 | 0; // expected-error {{invalid operands to binary expression}}
local_int8 ^ 0; // expected-error {{invalid operands to binary expression}}
local_int8 < 0; // expected-error {{invalid operands to binary expression}}
local_int8 <= 0; // expected-error {{invalid operands to binary expression}}
local_int8 == 0; // expected-error {{invalid operands to binary expression}}
local_int8 != 0; // expected-error {{invalid operands to binary expression}}
local_int8 >= 0; // expected-error {{invalid operands to binary expression}}
local_int8 > 0; // expected-error {{invalid operands to binary expression}}
local_int8 && 0; // expected-error {{invalid operands to binary expression}}
local_int8 || 0; // expected-error {{invalid operands to binary expression}}
if (local_int8) { // expected-error {{statement requires expression of scalar type}}
}
while (local_int8) { // expected-error {{statement requires expression of scalar type}}

View File

@ -213,23 +213,6 @@ void func(int sel) {
local_int8 &&init_int8; // expected-error {{invalid operands to binary expression}} expected-error {{not contextually convertible}}
local_int8 || init_int8; // expected-error {{invalid operands to binary expression}} expected-error {{not contextually convertible}}
local_int8 + 0; // expected-error {{invalid operands to binary expression}}
local_int8 - 0; // expected-error {{invalid operands to binary expression}}
local_int8 * 0; // expected-error {{invalid operands to binary expression}}
local_int8 / 0; // expected-error {{invalid operands to binary expression}}
local_int8 % 0; // expected-error {{invalid operands to binary expression}}
local_int8 & 0; // expected-error {{invalid operands to binary expression}}
local_int8 | 0; // expected-error {{invalid operands to binary expression}}
local_int8 ^ 0; // expected-error {{invalid operands to binary expression}}
local_int8 < 0; // expected-error {{invalid operands to binary expression}}
local_int8 <= 0; // expected-error {{invalid operands to binary expression}}
local_int8 == 0; // expected-error {{invalid operands to binary expression}}
local_int8 != 0; // expected-error {{invalid operands to binary expression}}
local_int8 >= 0; // expected-error {{invalid operands to binary expression}}
local_int8 > 0; // expected-error {{invalid operands to binary expression}}
local_int8 && 0; // expected-error {{invalid operands to binary expression}} expected-error {{not contextually convertible}}
local_int8 || 0; // expected-error {{invalid operands to binary expression}} expected-error {{not contextually convertible}}
if (local_int8) { // expected-error {{not contextually convertible to 'bool'}}
}
while (local_int8) { // expected-error {{not contextually convertible to 'bool'}}