Skip to content

Commit a29afb7

Browse files
authored
[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
1 parent a858836 commit a29afb7

File tree

12 files changed

+172
-93
lines changed

12 files changed

+172
-93
lines changed

clang/lib/AST/Expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1924,7 +1924,6 @@ bool CastExpr::CastConsistency() const {
19241924
case CK_FixedPointToIntegral:
19251925
case CK_IntegralToFixedPoint:
19261926
case CK_MatrixCast:
1927-
case CK_HLSLVectorTruncation:
19281927
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
19291928
goto CheckNoBasePath;
19301929

@@ -1945,6 +1944,7 @@ bool CastExpr::CastConsistency() const {
19451944
case CK_BuiltinFnToFnPtr:
19461945
case CK_FixedPointToBoolean:
19471946
case CK_HLSLArrayRValue:
1947+
case CK_HLSLVectorTruncation:
19481948
CheckNoBasePath:
19491949
assert(path_empty() && "Cast kind should not have a base path!");
19501950
break;

clang/lib/AST/ExprConstant.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10935,6 +10935,15 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
1093510935

1093610936
return true;
1093710937
}
10938+
case CK_HLSLVectorTruncation: {
10939+
APValue Val;
10940+
SmallVector<APValue, 4> Elements;
10941+
if (!EvaluateVector(SE, Val, Info))
10942+
return Error(E);
10943+
for (unsigned I = 0; I < NElts; I++)
10944+
Elements.push_back(Val.getVectorElt(I));
10945+
return Success(Elements, E);
10946+
}
1093810947
default:
1093910948
return ExprEvaluatorBaseTy::VisitCastExpr(E);
1094010949
}
@@ -14478,7 +14487,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
1447814487
case CK_FixedPointCast:
1447914488
case CK_IntegralToFixedPoint:
1448014489
case CK_MatrixCast:
14481-
case CK_HLSLVectorTruncation:
1448214490
llvm_unreachable("invalid cast kind for integral value");
1448314491

1448414492
case CK_BitCast:
@@ -14651,6 +14659,12 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
1465114659
return false;
1465214660
return Success(Value, E);
1465314661
}
14662+
case CK_HLSLVectorTruncation: {
14663+
APValue Val;
14664+
if (!EvaluateVector(SubExpr, Val, Info))
14665+
return Error(E);
14666+
return Success(Val.getVectorElt(0), E);
14667+
}
1465414668
}
1465514669

1465614670
llvm_unreachable("unknown cast resulting in integral value");
@@ -15177,6 +15191,12 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
1517715191
Result = V.getComplexFloatReal();
1517815192
return true;
1517915193
}
15194+
case CK_HLSLVectorTruncation: {
15195+
APValue Val;
15196+
if (!EvaluateVector(SubExpr, Val, Info))
15197+
return Error(E);
15198+
return Success(Val.getVectorElt(0), E);
15199+
}
1518015200
}
1518115201
}
1518215202

clang/lib/CodeGen/CGExprScalar.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2709,14 +2709,19 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
27092709
return CGF.CGM.createOpenCLIntToSamplerConversion(E, CGF);
27102710

27112711
case CK_HLSLVectorTruncation: {
2712-
assert(DestTy->isVectorType() && "Expected dest type to be vector type");
2712+
assert((DestTy->isVectorType() || DestTy->isBuiltinType()) &&
2713+
"Destination type must be a vector or builtin type.");
27132714
Value *Vec = Visit(const_cast<Expr *>(E));
2714-
SmallVector<int, 16> Mask;
2715-
unsigned NumElts = DestTy->castAs<VectorType>()->getNumElements();
2716-
for (unsigned I = 0; I != NumElts; ++I)
2717-
Mask.push_back(I);
2715+
if (auto *VecTy = DestTy->getAs<VectorType>()) {
2716+
SmallVector<int> Mask;
2717+
unsigned NumElts = VecTy->getNumElements();
2718+
for (unsigned I = 0; I != NumElts; ++I)
2719+
Mask.push_back(I);
27182720

2719-
return Builder.CreateShuffleVector(Vec, Mask, "trunc");
2721+
return Builder.CreateShuffleVector(Vec, Mask, "trunc");
2722+
}
2723+
llvm::Value *Zero = llvm::Constant::getNullValue(CGF.SizeTy);
2724+
return Builder.CreateExtractElement(Vec, Zero, "cast.vtrunc");
27202725
}
27212726

27222727
} // end of switch

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4313,8 +4313,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
43134313
// from type to the elements of the to type without resizing the vector.
43144314
static QualType adjustVectorType(ASTContext &Context, QualType FromTy,
43154315
QualType ToType, QualType *ElTy = nullptr) {
4316-
auto *ToVec = ToType->castAs<VectorType>();
4317-
QualType ElType = ToVec->getElementType();
4316+
QualType ElType = ToType;
4317+
if (auto *ToVec = ToType->getAs<VectorType>())
4318+
ElType = ToVec->getElementType();
4319+
43184320
if (ElTy)
43194321
*ElTy = ElType;
43204322
if (!FromTy->isVectorType())
@@ -4475,7 +4477,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
44754477
case ICK_Integral_Conversion: {
44764478
QualType ElTy = ToType;
44774479
QualType StepTy = ToType;
4478-
if (ToType->isVectorType())
4480+
if (FromType->isVectorType() || ToType->isVectorType())
44794481
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
44804482
if (ElTy->isBooleanType()) {
44814483
assert(FromType->castAs<EnumType>()->getDecl()->isFixed() &&
@@ -4495,7 +4497,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
44954497
case ICK_Floating_Promotion:
44964498
case ICK_Floating_Conversion: {
44974499
QualType StepTy = ToType;
4498-
if (ToType->isVectorType())
4500+
if (FromType->isVectorType() || ToType->isVectorType())
44994501
StepTy = adjustVectorType(Context, FromType, ToType);
45004502
From = ImpCastExprToType(From, StepTy, CK_FloatingCast, VK_PRValue,
45014503
/*BasePath=*/nullptr, CCK)
@@ -4527,7 +4529,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
45274529
case ICK_Floating_Integral: {
45284530
QualType ElTy = ToType;
45294531
QualType StepTy = ToType;
4530-
if (ToType->isVectorType())
4532+
if (FromType->isVectorType() || ToType->isVectorType())
45314533
StepTy = adjustVectorType(Context, FromType, ToType, &ElTy);
45324534
if (ElTy->isRealFloatingType())
45334535
From = ImpCastExprToType(From, StepTy, CK_IntegralToFloating, VK_PRValue,
@@ -4669,11 +4671,11 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
46694671
}
46704672
QualType ElTy = FromType;
46714673
QualType StepTy = ToType;
4672-
if (FromType->isVectorType()) {
4673-
if (getLangOpts().HLSL)
4674-
StepTy = adjustVectorType(Context, FromType, ToType);
4674+
if (FromType->isVectorType())
46754675
ElTy = FromType->castAs<VectorType>()->getElementType();
4676-
}
4676+
if (getLangOpts().HLSL &&
4677+
(FromType->isVectorType() || ToType->isVectorType()))
4678+
StepTy = adjustVectorType(Context, FromType, ToType);
46774679

46784680
From = ImpCastExprToType(From, StepTy, ScalarTypeToBooleanCastKind(ElTy),
46794681
VK_PRValue,
@@ -4828,8 +4830,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
48284830
// TODO: Support HLSL matrices.
48294831
assert((!From->getType()->isMatrixType() && !ToType->isMatrixType()) &&
48304832
"Dimension conversion for matrix types is not implemented yet.");
4831-
assert(ToType->isVectorType() &&
4832-
"Dimension conversion is only supported for vector types.");
4833+
assert((ToType->isVectorType() || ToType->isBuiltinType()) &&
4834+
"Dimension conversion output must be vector or scalar type.");
48334835
switch (SCS.Dimension) {
48344836
case ICK_HLSL_Vector_Splat: {
48354837
// Vector splat from any arithmetic type to a vector.
@@ -4841,18 +4843,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
48414843
}
48424844
case ICK_HLSL_Vector_Truncation: {
48434845
// Note: HLSL built-in vectors are ExtVectors. Since this truncates a
4844-
// vector to a smaller vector, this can only operate on arguments where
4845-
// the source and destination types are ExtVectors.
4846-
assert(From->getType()->isExtVectorType() && ToType->isExtVectorType() &&
4847-
"HLSL vector truncation should only apply to ExtVectors");
4846+
// vector to a smaller vector or to a scalar, this can only operate on
4847+
// arguments where the source type is an ExtVector and the destination
4848+
// type is destination type is either an ExtVectorType or a builtin scalar
4849+
// type.
48484850
auto *FromVec = From->getType()->castAs<VectorType>();
4849-
auto *ToVec = ToType->castAs<VectorType>();
4850-
QualType ElType = FromVec->getElementType();
4851-
QualType TruncTy =
4852-
Context.getExtVectorType(ElType, ToVec->getNumElements());
4851+
QualType TruncTy = FromVec->getElementType();
4852+
if (auto *ToVec = ToType->getAs<VectorType>())
4853+
TruncTy = Context.getExtVectorType(TruncTy, ToVec->getNumElements());
48534854
From = ImpCastExprToType(From, TruncTy, CK_HLSLVectorTruncation,
48544855
From->getValueKind())
48554856
.get();
4857+
48564858
break;
48574859
}
48584860
case ICK_Identity:

clang/lib/Sema/SemaOverload.cpp

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,26 +2032,42 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType,
20322032
if (S.Context.hasSameUnqualifiedType(FromType, ToType))
20332033
return false;
20342034

2035+
// HLSL allows implicit truncation of vector types.
2036+
if (S.getLangOpts().HLSL) {
2037+
auto *ToExtType = ToType->getAs<ExtVectorType>();
2038+
auto *FromExtType = FromType->getAs<ExtVectorType>();
2039+
2040+
// If both arguments are vectors, handle possible vector truncation and
2041+
// element conversion.
2042+
if (ToExtType && FromExtType) {
2043+
unsigned FromElts = FromExtType->getNumElements();
2044+
unsigned ToElts = ToExtType->getNumElements();
2045+
if (FromElts < ToElts)
2046+
return false;
2047+
if (FromElts == ToElts)
2048+
ElConv = ICK_Identity;
2049+
else
2050+
ElConv = ICK_HLSL_Vector_Truncation;
2051+
2052+
QualType FromElTy = FromExtType->getElementType();
2053+
QualType ToElTy = ToExtType->getElementType();
2054+
if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
2055+
return true;
2056+
return IsVectorElementConversion(S, FromElTy, ToElTy, ICK, From);
2057+
}
2058+
if (FromExtType && !ToExtType) {
2059+
ElConv = ICK_HLSL_Vector_Truncation;
2060+
QualType FromElTy = FromExtType->getElementType();
2061+
if (S.Context.hasSameUnqualifiedType(FromElTy, ToType))
2062+
return true;
2063+
return IsVectorElementConversion(S, FromElTy, ToType, ICK, From);
2064+
}
2065+
// Fallthrough for the case where ToType is a vector and FromType is not.
2066+
}
2067+
20352068
// There are no conversions between extended vector types, only identity.
20362069
if (auto *ToExtType = ToType->getAs<ExtVectorType>()) {
20372070
if (auto *FromExtType = FromType->getAs<ExtVectorType>()) {
2038-
// HLSL allows implicit truncation of vector types.
2039-
if (S.getLangOpts().HLSL) {
2040-
unsigned FromElts = FromExtType->getNumElements();
2041-
unsigned ToElts = ToExtType->getNumElements();
2042-
if (FromElts < ToElts)
2043-
return false;
2044-
if (FromElts == ToElts)
2045-
ElConv = ICK_Identity;
2046-
else
2047-
ElConv = ICK_HLSL_Vector_Truncation;
2048-
2049-
QualType FromElTy = FromExtType->getElementType();
2050-
QualType ToElTy = ToExtType->getElementType();
2051-
if (S.Context.hasSameUnqualifiedType(FromElTy, ToElTy))
2052-
return true;
2053-
return IsVectorElementConversion(S, FromElTy, ToElTy, ICK, From);
2054-
}
20552071
// There are no conversions between extended vector types other than the
20562072
// identity conversion.
20572073
return false;

clang/test/CodeGenHLSL/BasicFeatures/standard_conversion_sequences.hlsl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,27 @@ void d4_to_b2() {
117117
vector<double,4> d4 = 9.0;
118118
vector<bool, 2> b2 = d4;
119119
}
120+
121+
// CHECK-LABEL: d4_to_d1
122+
// CHECK: [[d4:%.*]] = alloca <4 x double>
123+
// CHECK: [[d1:%.*]] = alloca <1 x double>
124+
// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
125+
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
126+
// CHECK: [[vecd1:%.*]] = shufflevector <4 x double> [[vecd4]], <4 x double> poison, <1 x i32> zeroinitializer
127+
// CHECK: store <1 x double> [[vecd1]], ptr [[d1:%.*]], align 8
128+
void d4_to_d1() {
129+
vector<double,4> d4 = 9.0;
130+
vector<double,1> d1 = d4;
131+
}
132+
133+
// CHECK-LABEL: d4_to_dScalar
134+
// CHECK: [[d4:%.*]] = alloca <4 x double>
135+
// CHECK: [[d:%.*]] = alloca double
136+
// CHECK: store <4 x double> <double 9.000000e+00, double 9.000000e+00, double 9.000000e+00, double 9.000000e+00>, ptr [[d4]]
137+
// CHECK: [[vecd4:%.*]] = load <4 x double>, ptr [[d4]]
138+
// CHECK: [[d4x:%.*]] = extractelement <4 x double> [[vecd4]], i32 0
139+
// CHECK: store double [[d4x]], ptr [[d]]
140+
void d4_to_dScalar() {
141+
vector<double,4> d4 = 9.0;
142+
double d = d4;
143+
}

clang/test/CodeGenHLSL/builtins/dot.hlsl

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -155,18 +155,6 @@ float test_dot_float3(float3 p0, float3 p1) { return dot(p0, p1); }
155155
// CHECK: ret float %hlsl.dot
156156
float test_dot_float4(float4 p0, float4 p1) { return dot(p0, p1); }
157157

158-
// CHECK: %hlsl.dot = call float @llvm.[[ICF]].fdot.v2f32(<2 x float> %splat.splat, <2 x float>
159-
// CHECK: ret float %hlsl.dot
160-
float test_dot_float2_splat(float p0, float2 p1) { return dot(p0, p1); }
161-
162-
// CHECK: %hlsl.dot = call float @llvm.[[ICF]].fdot.v3f32(<3 x float> %splat.splat, <3 x float>
163-
// CHECK: ret float %hlsl.dot
164-
float test_dot_float3_splat(float p0, float3 p1) { return dot(p0, p1); }
165-
166-
// CHECK: %hlsl.dot = call float @llvm.[[ICF]].fdot.v4f32(<4 x float> %splat.splat, <4 x float>
167-
// CHECK: ret float %hlsl.dot
168-
float test_dot_float4_splat(float p0, float4 p1) { return dot(p0, p1); }
169-
170158
// CHECK: %hlsl.dot = fmul double
171159
// CHECK: ret double %hlsl.dot
172160
double test_dot_double(double p0, double p1) { return dot(p0, p1); }

clang/test/CodeGenHLSL/builtins/lerp.hlsl

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,3 @@ float3 test_lerp_float3(float3 p0) { return lerp(p0, p0, p0); }
5656
// CHECK: %hlsl.lerp = call <4 x float> @llvm.[[TARGET]].lerp.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}})
5757
// CHECK: ret <4 x float> %hlsl.lerp
5858
float4 test_lerp_float4(float4 p0) { return lerp(p0, p0, p0); }
59-
60-
// CHECK: %[[b:.*]] = load <2 x float>, ptr %p1.addr, align 8
61-
// CHECK: %[[c:.*]] = load <2 x float>, ptr %p1.addr, align 8
62-
// CHECK: %hlsl.lerp = call <2 x float> @llvm.[[TARGET]].lerp.v2f32(<2 x float> %splat.splat, <2 x float> %[[b]], <2 x float> %[[c]])
63-
// CHECK: ret <2 x float> %hlsl.lerp
64-
float2 test_lerp_float2_splat(float p0, float2 p1) { return lerp(p0, p1, p1); }
65-
66-
// CHECK: %[[b:.*]] = load <3 x float>, ptr %p1.addr, align 16
67-
// CHECK: %[[c:.*]] = load <3 x float>, ptr %p1.addr, align 16
68-
// CHECK: %hlsl.lerp = call <3 x float> @llvm.[[TARGET]].lerp.v3f32(<3 x float> %splat.splat, <3 x float> %[[b]], <3 x float> %[[c]])
69-
// CHECK: ret <3 x float> %hlsl.lerp
70-
float3 test_lerp_float3_splat(float p0, float3 p1) { return lerp(p0, p1, p1); }
71-
72-
// CHECK: %[[b:.*]] = load <4 x float>, ptr %p1.addr, align 16
73-
// CHECK: %[[c:.*]] = load <4 x float>, ptr %p1.addr, align 16
74-
// CHECK: %hlsl.lerp = call <4 x float> @llvm.[[TARGET]].lerp.v4f32(<4 x float> %splat.splat, <4 x float> %[[b]], <4 x float> %[[c]])
75-
// CHECK: ret <4 x float> %hlsl.lerp
76-
float4 test_lerp_float4_splat(float p0, float4 p1) { return lerp(p0, p1, p1); }

clang/test/CodeGenHLSL/builtins/mad.hlsl

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -263,21 +263,3 @@ uint64_t3 test_mad_uint64_t3(uint64_t3 p0, uint64_t3 p1, uint64_t3 p2) { return
263263
// SPIR_CHECK: mul nuw <4 x i64> %{{.*}}, %{{.*}}
264264
// SPIR_CHECK: add nuw <4 x i64> %{{.*}}, %{{.*}}
265265
uint64_t4 test_mad_uint64_t4(uint64_t4 p0, uint64_t4 p1, uint64_t4 p2) { return mad(p0, p1, p2); }
266-
267-
// CHECK: %[[p1:.*]] = load <2 x float>, ptr %p1.addr, align 8
268-
// CHECK: %[[p2:.*]] = load <2 x float>, ptr %p2.addr, align 8
269-
// CHECK: %hlsl.fmad = call <2 x float> @llvm.fmuladd.v2f32(<2 x float> %splat.splat, <2 x float> %[[p1]], <2 x float> %[[p2]])
270-
// CHECK: ret <2 x float> %hlsl.fmad
271-
float2 test_mad_float2_splat(float p0, float2 p1, float2 p2) { return mad(p0, p1, p2); }
272-
273-
// CHECK: %[[p1:.*]] = load <3 x float>, ptr %p1.addr, align 16
274-
// CHECK: %[[p2:.*]] = load <3 x float>, ptr %p2.addr, align 16
275-
// CHECK: %hlsl.fmad = call <3 x float> @llvm.fmuladd.v3f32(<3 x float> %splat.splat, <3 x float> %[[p1]], <3 x float> %[[p2]])
276-
// CHECK: ret <3 x float> %hlsl.fmad
277-
float3 test_mad_float3_splat(float p0, float3 p1, float3 p2) { return mad(p0, p1, p2); }
278-
279-
// CHECK: %[[p1:.*]] = load <4 x float>, ptr %p1.addr, align 16
280-
// CHECK: %[[p2:.*]] = load <4 x float>, ptr %p2.addr, align 16
281-
// CHECK: %hlsl.fmad = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %splat.splat, <4 x float> %[[p1]], <4 x float> %[[p2]])
282-
// CHECK: ret <4 x float> %hlsl.fmad
283-
float4 test_mad_float4_splat(float p0, float4 p1, float4 p2) { return mad(p0, p1, p2); }

clang/test/SemaHLSL/TruncationOverloadResolution.hlsl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,42 @@ void Case2(float4 F) {
2424
Half2Double2(F); // expected-warning{{implicit conversion truncates vector: 'float4' (aka 'vector<float, 4>') to 'vector<double, 2>' (vector of 2 'double' values)}}
2525
}
2626

27+
// Case 3: Allow truncation down to vector<T,1> or T.
28+
void Half(half H);
29+
void Float(float F);
30+
void Double(double D);
31+
32+
void Half1(half1 H);
33+
void Float1(float1 F);
34+
void Double1(double1 D);
35+
36+
void Case3(half3 H, float3 F, double3 D) {
37+
Half(H); // expected-warning{{implicit conversion turns vector to scalar: 'half3' (aka 'vector<half, 3>') to 'half'}}
38+
Half(F); // expected-warning{{implicit conversion turns vector to scalar: 'float3' (aka 'vector<float, 3>') to 'half'}}
39+
Half(D); // expected-warning{{implicit conversion turns vector to scalar: 'double3' (aka 'vector<double, 3>') to 'half'}}
40+
41+
Float(H); // expected-warning{{implicit conversion turns vector to scalar: 'half3' (aka 'vector<half, 3>') to 'float'}}
42+
Float(F); // expected-warning{{implicit conversion turns vector to scalar: 'float3' (aka 'vector<float, 3>') to 'float'}}
43+
Float(D); // expected-warning{{implicit conversion turns vector to scalar: 'double3' (aka 'vector<double, 3>') to 'float'}}
44+
45+
Double(H); // expected-warning{{implicit conversion turns vector to scalar: 'half3' (aka 'vector<half, 3>') to 'double'}}
46+
Double(F); // expected-warning{{implicit conversion turns vector to scalar: 'float3' (aka 'vector<float, 3>') to 'double'}}
47+
Double(D); // expected-warning{{implicit conversion turns vector to scalar: 'double3' (aka 'vector<double, 3>') to 'double'}}
48+
49+
Half1(H); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<half, 1>' (vector of 1 'half' value)}}
50+
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)}}
51+
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)}}
52+
53+
Float1(H); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<float, 1>' (vector of 1 'float' value)}}
54+
Float1(F); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'vector<float, 1>' (vector of 1 'float' value)}}
55+
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)}}
56+
57+
Double1(H); // expected-warning{{implicit conversion truncates vector: 'half3' (aka 'vector<half, 3>') to 'vector<double, 1>' (vector of 1 'double' value)}}
58+
Double1(F); // expected-warning{{implicit conversion truncates vector: 'float3' (aka 'vector<float, 3>') to 'vector<double, 1>' (vector of 1 'double' value)}}
59+
Double1(D); // expected-warning{{implicit conversion truncates vector: 'double3' (aka 'vector<double, 3>') to 'vector<double, 1>' (vector of 1 'double' value)}}
60+
}
61+
62+
2763
#if ERROR
2864
// Case 3: Two promotions or two conversions are ambiguous.
2965
void Float2Double2(double2 D); // expected-note{{candidate function}}

clang/test/SemaHLSL/Types/BuiltinVector/ScalarSwizzleErrors.hlsl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -x hlsl -finclude-default-header -verify %s
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -verify %s
22

33
int2 ToTwoInts(int V) {
44
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) {
1616
return V.; // expected-error{{expected unqualified-id}}
1717
}
1818

19+
float ScalarLValue(float2 V) {
20+
(float)V = 4.0; // expected-error{{assignment to cast is illegal, lvalue casts are not supported}}
21+
}
22+
1923
// These cases produce no error.
2024

2125
float2 HowManyFloats(float V) {

0 commit comments

Comments
 (0)