[HLSL] Allow truncation to scalar (#104844)
HLSL allows implicit conversions to truncate vectors to scalar pr-values. These conversions are scored as vector truncations and should warn appropriately. This change allows forming a truncation cast to a pr-value, but not an l-value. Truncating a vector to a scalar is performed by loading the first element of the vector and disregarding the remaining elements. Fixes #102964
This commit is contained in:
parent
a85883662a
commit
a29afb754f
@ -1924,7 +1924,6 @@ bool CastExpr::CastConsistency() const {
|
||||
case CK_FixedPointToIntegral:
|
||||
case CK_IntegralToFixedPoint:
|
||||
case CK_MatrixCast:
|
||||
case CK_HLSLVectorTruncation:
|
||||
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
|
||||
goto CheckNoBasePath;
|
||||
|
||||
@ -1945,6 +1944,7 @@ bool CastExpr::CastConsistency() const {
|
||||
case CK_BuiltinFnToFnPtr:
|
||||
case CK_FixedPointToBoolean:
|
||||
case CK_HLSLArrayRValue:
|
||||
case CK_HLSLVectorTruncation:
|
||||
CheckNoBasePath:
|
||||
assert(path_empty() && "Cast kind should not have a base path!");
|
||||
break;
|
||||
|
||||
@ -10935,6 +10935,15 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
|
||||
return true;
|
||||
}
|
||||
case CK_HLSLVectorTruncation: {
|
||||
APValue Val;
|
||||
SmallVector<APValue, 4> Elements;
|
||||
if (!EvaluateVector(SE, Val, Info))
|
||||
return Error(E);
|
||||
for (unsigned I = 0; I < NElts; I++)
|
||||
Elements.push_back(Val.getVectorElt(I));
|
||||
return Success(Elements, E);
|
||||
}
|
||||
default:
|
||||
return ExprEvaluatorBaseTy::VisitCastExpr(E);
|
||||
}
|
||||
@ -14478,7 +14487,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
case CK_FixedPointCast:
|
||||
case CK_IntegralToFixedPoint:
|
||||
case CK_MatrixCast:
|
||||
case CK_HLSLVectorTruncation:
|
||||
llvm_unreachable("invalid cast kind for integral value");
|
||||
|
||||
case CK_BitCast:
|
||||
@ -14651,6 +14659,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
return false;
|
||||
return Success(Value, E);
|
||||
}
|
||||
case CK_HLSLVectorTruncation: {
|
||||
APValue Val;
|
||||
if (!EvaluateVector(SubExpr, Val, Info))
|
||||
return Error(E);
|
||||
return Success(Val.getVectorElt(0), E);
|
||||
}
|
||||
}
|
||||
|
||||
llvm_unreachable("unknown cast resulting in integral value");
|
||||
@ -15177,6 +15191,12 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
|
||||
Result = V.getComplexFloatReal();
|
||||
return true;
|
||||
}
|
||||
case CK_HLSLVectorTruncation: {
|
||||
APValue Val;
|
||||
if (!EvaluateVector(SubExpr, Val, Info))
|
||||
return Error(E);
|
||||
return Success(Val.getVectorElt(0), E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2709,14 +2709,19 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
|
||||
return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
|
||||
|
||||
case CK_HLSLVectorTruncation: {
|
||||
assert(DestTy->isVectorType() && "Expected dest type to be vector type");
|
||||
assert((DestTy->isVectorType() || DestTy->isBuiltinType()) &&
|
||||
"Destination type must be a vector or builtin type.");
|
||||
Value *Vec = Visit(const_cast<Expr *>(E));
|
||||
SmallVector<int, 16> Mask;
|
||||
unsigned NumElts = DestTy->castAs<VectorType>()->getNumElements();
|
||||
for (unsigned I = 0; I != NumElts; ++I)
|
||||
Mask.push_back(I);
|
||||
if (auto *VecTy = DestTy->getAs<VectorType>()) {
|
||||
SmallVector<int> Mask;
|
||||
unsigned NumElts = VecTy->getNumElements();
|
||||
for (unsigned I = 0; I != NumElts; ++I)
|
||||
Mask.push_back(I);
|
||||
|
||||
return Builder.CreateShuffleVector(Vec, Mask, "trunc");
|
||||
return Builder.CreateShuffleVector(Vec, Mask, "trunc");
|
||||
}
|
||||
llvm::Value *Zero = llvm::Constant::getNullValue(CGF.SizeTy);
|
||||
return Builder.CreateExtractElement(Vec, Zero, "cast.vtrunc");
|
||||
}
|
||||
|
||||
} // end of switch
|
||||
|
||||
@ -4313,8 +4313,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
// from type to the elements of the to type without resizing the vector.
|
||||
static QualType adjustVectorType(ASTContext &Context, QualType FromTy,
|
||||
QualType ToType, QualType *ElTy = nullptr) {
|
||||
auto *ToVec = ToType->castAs<VectorType>();
|
||||
QualType ElType = ToVec->getElementType();
|
||||
QualType ElType = ToType;
|
||||
if (auto *ToVec = ToType->getAs<VectorType>())
|
||||
ElType = ToVec->getElementType();
|
||||
|
||||
if (ElTy)
|
||||
*ElTy = ElType;
|
||||
if (!FromTy->isVectorType())
|
||||
@ -4475,7 +4477,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
case ICK_Integral_Conversion: {
|
||||
QualType ElTy = ToType;
|
||||
QualType StepTy = ToType;
|
||||
if (ToType->isVectorType())
|
||||
if (FromType->isVectorType() || ToType->isVectorType())
|
||||
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
|
||||
if (ElTy->isBooleanType()) {
|
||||
assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
|
||||
@ -4495,7 +4497,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
case ICK_Floating_Promotion:
|
||||
case ICK_Floating_Conversion: {
|
||||
QualType StepTy = ToType;
|
||||
if (ToType->isVectorType())
|
||||
if (FromType->isVectorType() || ToType->isVectorType())
|
||||
StepTy = adjustVectorType(Context, FromType, ToType);
|
||||
From = ImpCastExprToType(From, StepTy, CK_FloatingCast, VK_PRValue,
|
||||
/*BasePath=*/nullptr, CCK)
|
||||
@ -4527,7 +4529,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
case ICK_Floating_Integral: {
|
||||
QualType ElTy = ToType;
|
||||
QualType StepTy = ToType;
|
||||
if (ToType->isVectorType())
|
||||
if (FromType->isVectorType() || ToType->isVectorType())
|
||||
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
|
||||
if (ElTy->isRealFloatingType())
|
||||
From = ImpCastExprToType(From, StepTy, CK_IntegralToFloating, VK_PRValue,
|
||||
@ -4669,11 +4671,11 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
}
|
||||
QualType ElTy = FromType;
|
||||
QualType StepTy = ToType;
|
||||
if (FromType->isVectorType()) {
|
||||
if (getLangOpts().HLSL)
|
||||
StepTy = adjustVectorType(Context, FromType, ToType);
|
||||
if (FromType->isVectorType())
|
||||
ElTy = FromType->castAs<VectorType>()->getElementType();
|
||||
}
|
||||
if (getLangOpts().HLSL &&
|
||||
(FromType->isVectorType() || ToType->isVectorType()))
|
||||
StepTy = adjustVectorType(Context, FromType, ToType);
|
||||
|
||||
From = ImpCastExprToType(From, StepTy, ScalarTypeToBooleanCastKind(ElTy),
|
||||
VK_PRValue,
|
||||
@ -4828,8 +4830,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
// TODO: Support HLSL matrices.
|
||||
assert((!From->getType()->isMatrixType() && !ToType->isMatrixType()) &&
|
||||
"Dimension conversion for matrix types is not implemented yet.");
|
||||
assert(ToType->isVectorType() &&
|
||||
"Dimension conversion is only supported for vector types.");
|
||||
assert((ToType->isVectorType() || ToType->isBuiltinType()) &&
|
||||
"Dimension conversion output must be vector or scalar type.");
|
||||
switch (SCS.Dimension) {
|
||||
case ICK_HLSL_Vector_Splat: {
|
||||
// Vector splat from any arithmetic type to a vector.
|
||||
@ -4841,18 +4843,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
|
||||
}
|
||||
case ICK_HLSL_Vector_Truncation: {
|
||||
// Note: HLSL built-in vectors are ExtVectors. Since this truncates a
|
||||
// vector to a smaller vector, this can only operate on arguments where
|
||||
// the source and destination types are ExtVectors.
|
||||
assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
|
||||
"HLSL vector truncation should only apply to ExtVectors");
|
||||
// vector to a smaller vector or to a scalar, this can only operate on
|
||||
// arguments where the source type is an ExtVector and the destination
|
||||
// type is destination type is either an ExtVectorType or a builtin scalar
|
||||
// type.
|
||||
auto *FromVec = From->getType()->castAs<VectorType>();
|
||||
auto *ToVec = ToType->castAs<VectorType>();
|
||||
QualType ElType = FromVec->getElementType();
|
||||
QualType TruncTy =
|
||||
Context.getExtVectorType(ElType, ToVec->getNumElements());
|
||||
QualType TruncTy = FromVec->getElementType();
|
||||
if (auto *ToVec = ToType->getAs<VectorType>())
|
||||
TruncTy = Context.getExtVectorType(TruncTy, ToVec->getNumElements());
|
||||
From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
|
||||
From->getValueKind())
|
||||
.get();
|
||||
|
||||
break;
|
||||
}
|
||||
case ICK_Identity:
|
||||
|
||||
@ -2032,26 +2032,42 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
|
||||
if (S.Context.hasSameUnqualifiedType(FromType, ToType))
|
||||
return false;
|
||||
|
||||
// HLSL allows implicit truncation of vector types.
|
||||
if (S.getLangOpts().HLSL) {
|
||||
auto *ToExtType = ToType->getAs<ExtVectorType>();
|
||||
auto *FromExtType = FromType->getAs<ExtVectorType>();
|
||||
|
||||
// If both arguments are vectors, handle possible vector truncation and
|
||||
// element conversion.
|
||||
if (ToExtType && FromExtType) {
|
||||
unsigned FromElts = FromExtType->getNumElements();
|
||||
unsigned ToElts = ToExtType->getNumElements();
|
||||
if (FromElts < ToElts)
|
||||
return false;
|
||||
if (FromElts == ToElts)
|
||||
ElConv = ICK_Identity;
|
||||
else
|
||||
ElConv = ICK_HLSL_Vector_Truncation;
|
||||
|
||||
QualType FromElTy = FromExtType->getElementType();
|
||||
QualType ToElTy = ToExtType->getElementType();
|
||||
if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
|
||||
return true;
|
||||
return IsVectorElementConversion(S, FromElTy, ToElTy, ICK, From);
|
||||
}
|
||||
if (FromExtType && !ToExtType) {
|
||||
ElConv = ICK_HLSL_Vector_Truncation;
|
||||
QualType FromElTy = FromExtType->getElementType();
|
||||
if (S.Context.hasSameUnqualifiedType(FromElTy, ToType))
|
||||
return true;
|
||||
return IsVectorElementConversion(S, FromElTy, ToType, ICK, From);
|
||||
}
|
||||
// Fallthrough for the case where ToType is a vector and FromType is not.
|
||||
}
|
||||
|
||||
// There are no conversions between extended vector types, only identity.
|
||||
if (auto *ToExtType = ToType->getAs<ExtVectorType>()) {
|
||||
if (auto *FromExtType = FromType->getAs<ExtVectorType>()) {
|
||||
// HLSL allows implicit truncation of vector types.
|
||||
if (S.getLangOpts().HLSL) {
|
||||
unsigned FromElts = FromExtType->getNumElements();
|
||||
unsigned ToElts = ToExtType->getNumElements();
|
||||
if (FromElts < ToElts)
|
||||
return false;
|
||||
if (FromElts == ToElts)
|
||||
ElConv = ICK_Identity;
|
||||
else
|
||||
ElConv = ICK_HLSL_Vector_Truncation;
|
||||
|
||||
QualType FromElTy = FromExtType->getElementType();
|
||||
QualType ToElTy = ToExtType->getElementType();
|
||||
if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
|
||||
return true;
|
||||
return IsVectorElementConversion(S, FromElTy, ToElTy, ICK, From);
|
||||
}
|
||||
// There are no conversions between extended vector types other than the
|
||||
// identity conversion.
|
||||
return false;
|
||||
|
||||
@ -117,3 +117,27 @@ void d4_to_b2() {
|
||||
vector<double,4> d4 = 9.0;
|
||||
vector<bool, 2> b2 = d4;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: d4_to_d1
|
||||
// CHECK: [[d4:%.*]] = alloca <4 x double>
|
||||
// CHECK: [[d1:%.*]] = alloca <1 x double>
|
||||
// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
|
||||
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
|
||||
// CHECK: [[vecd1:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <1 x i32> zeroinitializer
|
||||
// CHECK: store <1 x double> [[vecd1]], ptr [[d1:%.*]], align 8
|
||||
void d4_to_d1() {
|
||||
vector<double,4> d4 = 9.0;
|
||||
vector<double,1> d1 = d4;
|
||||
}
|
||||
|
||||
// CHECK-LABEL: d4_to_dScalar
|
||||
// CHECK: [[d4:%.*]] = alloca <4 x double>
|
||||
// CHECK: [[d:%.*]] = alloca double
|
||||
// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
|
||||
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
|
||||
// CHECK: [[d4x:%.*]] = extractelement <4 x double> [[vecd4]], i32 0
|
||||
// CHECK: store double [[d4x]], ptr [[d]]
|
||||
void d4_to_dScalar() {
|
||||
vector<double,4> d4 = 9.0;
|
||||
double d = d4;
|
||||
}
|
||||
|
||||
@ -155,18 +155,6 @@ float test_dot_float3(float3 p0, float3 p1) { return dot(p0, p1); }
|
||||
// CHECK: ret float %hlsl.dot
|
||||
float test_dot_float4(float4 p0, float4 p1) { return dot(p0, p1); }
|
||||
|
||||
// CHECK: %hlsl.dot = call float @llvm.[[ICF]].fdot.v2f32(<2 x float> %splat.splat, <2 x float>
|
||||
// CHECK: ret float %hlsl.dot
|
||||
float test_dot_float2_splat(float p0, float2 p1) { return dot(p0, p1); }
|
||||
|
||||
// CHECK: %hlsl.dot = call float @llvm.[[ICF]].fdot.v3f32(<3 x float> %splat.splat, <3 x float>
|
||||
// CHECK: ret float %hlsl.dot
|
||||
float test_dot_float3_splat(float p0, float3 p1) { return dot(p0, p1); }
|
||||
|
||||
// CHECK: %hlsl.dot = call float @llvm.[[ICF]].fdot.v4f32(<4 x float> %splat.splat, <4 x float>
|
||||
// CHECK: ret float %hlsl.dot
|
||||
float test_dot_float4_splat(float p0, float4 p1) { return dot(p0, p1); }
|
||||
|
||||
// CHECK: %hlsl.dot = fmul double
|
||||
// CHECK: ret double %hlsl.dot
|
||||
double test_dot_double(double p0, double p1) { return dot(p0, p1); }
|
||||
|
||||
@ -56,21 +56,3 @@ float3 test_lerp_float3(float3 p0) { return lerp(p0, p0, p0); }
|
||||
// CHECK: %hlsl.lerp = call <4 x float> @llvm.[[TARGET]].lerp.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
|
||||
// CHECK: ret <4 x float> %hlsl.lerp
|
||||
float4 test_lerp_float4(float4 p0) { return lerp(p0, p0, p0); }
|
||||
|
||||
// CHECK: %[[b:.*]] = load <2 x float>, ptr %p1.addr, align 8
|
||||
// CHECK: %[[c:.*]] = load <2 x float>, ptr %p1.addr, align 8
|
||||
// CHECK: %hlsl.lerp = call <2 x float> @llvm.[[TARGET]].lerp.v2f32(<2 x float> %splat.splat, <2 x float> %[[b]], <2 x float> %[[c]])
|
||||
// CHECK: ret <2 x float> %hlsl.lerp
|
||||
float2 test_lerp_float2_splat(float p0, float2 p1) { return lerp(p0, p1, p1); }
|
||||
|
||||
// CHECK: %[[b:.*]] = load <3 x float>, ptr %p1.addr, align 16
|
||||
// CHECK: %[[c:.*]] = load <3 x float>, ptr %p1.addr, align 16
|
||||
// CHECK: %hlsl.lerp = call <3 x float> @llvm.[[TARGET]].lerp.v3f32(<3 x float> %splat.splat, <3 x float> %[[b]], <3 x float> %[[c]])
|
||||
// CHECK: ret <3 x float> %hlsl.lerp
|
||||
float3 test_lerp_float3_splat(float p0, float3 p1) { return lerp(p0, p1, p1); }
|
||||
|
||||
// CHECK: %[[b:.*]] = load <4 x float>, ptr %p1.addr, align 16
|
||||
// CHECK: %[[c:.*]] = load <4 x float>, ptr %p1.addr, align 16
|
||||
// CHECK: %hlsl.lerp = call <4 x float> @llvm.[[TARGET]].lerp.v4f32(<4 x float> %splat.splat, <4 x float> %[[b]], <4 x float> %[[c]])
|
||||
// CHECK: ret <4 x float> %hlsl.lerp
|
||||
float4 test_lerp_float4_splat(float p0, float4 p1) { return lerp(p0, p1, p1); }
|
||||
|
||||
@ -263,21 +263,3 @@ uint64_t3 test_mad_uint64_t3(uint64_t3 p0, uint64_t3 p1, uint64_t3 p2) { return
|
||||
// SPIR_CHECK: mul nuw <4 x i64> %{{.*}}, %{{.*}}
|
||||
// SPIR_CHECK: add nuw <4 x i64> %{{.*}}, %{{.*}}
|
||||
uint64_t4 test_mad_uint64_t4(uint64_t4 p0, uint64_t4 p1, uint64_t4 p2) { return mad(p0, p1, p2); }
|
||||
|
||||
// CHECK: %[[p1:.*]] = load <2 x float>, ptr %p1.addr, align 8
|
||||
// CHECK: %[[p2:.*]] = load <2 x float>, ptr %p2.addr, align 8
|
||||
// CHECK: %hlsl.fmad = call <2 x float> @llvm.fmuladd.v2f32(<2 x float> %splat.splat, <2 x float> %[[p1]], <2 x float> %[[p2]])
|
||||
// CHECK: ret <2 x float> %hlsl.fmad
|
||||
float2 test_mad_float2_splat(float p0, float2 p1, float2 p2) { return mad(p0, p1, p2); }
|
||||
|
||||
// CHECK: %[[p1:.*]] = load <3 x float>, ptr %p1.addr, align 16
|
||||
// CHECK: %[[p2:.*]] = load <3 x float>, ptr %p2.addr, align 16
|
||||
// CHECK: %hlsl.fmad = call <3 x float> @llvm.fmuladd.v3f32(<3 x float> %splat.splat, <3 x float> %[[p1]], <3 x float> %[[p2]])
|
||||
// CHECK: ret <3 x float> %hlsl.fmad
|
||||
float3 test_mad_float3_splat(float p0, float3 p1, float3 p2) { return mad(p0, p1, p2); }
|
||||
|
||||
// CHECK: %[[p1:.*]] = load <4 x float>, ptr %p1.addr, align 16
|
||||
// CHECK: %[[p2:.*]] = load <4 x float>, ptr %p2.addr, align 16
|
||||
// CHECK: %hlsl.fmad = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %splat.splat, <4 x float> %[[p1]], <4 x float> %[[p2]])
|
||||
// CHECK: ret <4 x float> %hlsl.fmad
|
||||
float4 test_mad_float4_splat(float p0, float4 p1, float4 p2) { return mad(p0, p1, p2); }
|
||||
|
||||
@ -24,6 +24,42 @@ void Case2(float4 F) {
|
||||
Half2Double2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector<float, 4>') to 'vector<double, 2>' (vector of 2 'double' values)}}
|
||||
}
|
||||
|
||||
// Case 3: Allow truncation down to vector<T,1> or T.
|
||||
void Half(half H);
|
||||
void Float(float F);
|
||||
void Double(double D);
|
||||
|
||||
void Half1(half1 H);
|
||||
void Float1(float1 F);
|
||||
void Double1(double1 D);
|
||||
|
||||
void Case3(half3 H, float3 F, double3 D) {
|
||||
Half(H); // expected-warning{{implicit conversion turns vector to scalar: 'half3' (aka 'vector<half, 3>') to 'half'}}
|
||||
Half(F); // expected-warning{{implicit conversion turns vector to scalar: 'float3' (aka 'vector<float, 3>') to 'half'}}
|
||||
Half(D); // expected-warning{{implicit conversion turns vector to scalar: 'double3' (aka 'vector<double, 3>') to 'half'}}
|
||||
|
||||
Float(H); // expected-warning{{implicit conversion turns vector to scalar: 'half3' (aka 'vector<half, 3>') to 'float'}}
|
||||
Float(F); // expected-warning{{implicit conversion turns vector to scalar: 'float3' (aka 'vector<float, 3>') to 'float'}}
|
||||
Float(D); // expected-warning{{implicit conversion turns vector to scalar: 'double3' (aka 'vector<double, 3>') to 'float'}}
|
||||
|
||||
Double(H); // expected-warning{{implicit conversion turns vector to scalar: 'half3' (aka 'vector<half, 3>') to 'double'}}
|
||||
Double(F); // expected-warning{{implicit conversion turns vector to scalar: 'float3' (aka 'vector<float, 3>') to 'double'}}
|
||||
Double(D); // expected-warning{{implicit conversion turns vector to scalar: 'double3' (aka 'vector<double, 3>') to 'double'}}
|
||||
|
||||
Half1(H); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<half, 1>' (vector of 1 'half' value)}}
|
||||
Half1(F); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'vector<half, 1>' (vector of 1 'half' value)}} expected-warning{{implicit conversion loses floating-point precision: 'float3' (aka 'vector<float, 3>') to 'vector<half, 1>' (vector of 1 'half' value)}}
|
||||
Half1(D); // expected-warning{{implicit conversion truncates vector: 'double3' (aka 'vector<double, 3>') to 'vector<half, 1>' (vector of 1 'half' value)}} expected-warning{{implicit conversion loses floating-point precision: 'double3' (aka 'vector<double, 3>') to 'vector<half, 1>' (vector of 1 'half' value)}}
|
||||
|
||||
Float1(H); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<float, 1>' (vector of 1 'float' value)}}
|
||||
Float1(F); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'vector<float, 1>' (vector of 1 'float' value)}}
|
||||
Float1(D); // expected-warning{{implicit conversion truncates vector: 'double3' (aka 'vector<double, 3>') to 'vector<float, 1>' (vector of 1 'float' value)}} expected-warning{{implicit conversion loses floating-point precision: 'double3' (aka 'vector<double, 3>') to 'vector<float, 1>' (vector of 1 'float' value)}}
|
||||
|
||||
Double1(H); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<double, 1>' (vector of 1 'double' value)}}
|
||||
Double1(F); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'vector<double, 1>' (vector of 1 'double' value)}}
|
||||
Double1(D); // expected-warning{{implicit conversion truncates vector: 'double3' (aka 'vector<double, 3>') to 'vector<double, 1>' (vector of 1 'double' value)}}
|
||||
}
|
||||
|
||||
|
||||
#if ERROR
|
||||
// Case 3: Two promotions or two conversions are ambiguous.
|
||||
void Float2Double2(double2 D); // expected-note{{candidate function}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -x hlsl -finclude-default-header -verify %s
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
|
||||
|
||||
int2 ToTwoInts(int V) {
|
||||
return V.xy; // expected-error{{vector component access exceeds type 'vector<int, 1>' (vector of 1 'int' value)}}
|
||||
@ -16,6 +16,10 @@ float2 WhatIsHappening(float V) {
|
||||
return V.; // expected-error{{expected unqualified-id}}
|
||||
}
|
||||
|
||||
float ScalarLValue(float2 V) {
|
||||
(float)V = 4.0; // expected-error{{assignment to cast is illegal, lvalue casts are not supported}}
|
||||
}
|
||||
|
||||
// These cases produce no error.
|
||||
|
||||
float2 HowManyFloats(float V) {
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -std=hlsl202x -verify %s
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
// Note: these tests are a bit awkward because at time of writing we don't have a
|
||||
// good way to constexpr `any` for bool vector conditions, and the condition for
|
||||
// _Static_assert must be an integral constant.
|
||||
export void fn() {
|
||||
// This compiling successfully verifies that the vector constant expression
|
||||
// gets truncated to an integer at compile time for instantiation.
|
||||
_Static_assert(((int)1.xxxx) + 0 == 1, "Woo!");
|
||||
|
||||
// This compiling successfully verifies that the vector constant expression
|
||||
// gets truncated to a float at compile time for instantiation.
|
||||
_Static_assert(((float)1.0.xxxx) + 0.0 == 1.0, "Woo!");
|
||||
|
||||
// This compiling successfully verifies that a vector can be truncated to a
|
||||
// smaller vector, then truncated to a float as a constant expression.
|
||||
_Static_assert(((float2)float4(6, 5, 4, 3)).x == 6, "Woo!");
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user