Skip to content

Commit 715edd7

Browse files
authored
[HLSL] Allow arrays to copy-initialize (#127557)
This change allows array variables to copy-initialize from other arrays. It also corrects a small error in HLSL C-Style casting that did not error on casting to arrays if elementwise and splat conversions fail. Fixes #127551
1 parent f6d74af commit 715edd7

File tree

4 files changed

+101
-34
lines changed

4 files changed

+101
-34
lines changed

clang/lib/Sema/SemaCast.cpp

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ namespace {
104104
void CheckStaticCast();
105105
void CheckDynamicCast();
106106
void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization);
107+
bool CheckHLSLCStyleCast(CheckedConversionKind CCK);
107108
void CheckCStyleCast();
108109
void CheckBuiltinBitCast();
109110
void CheckAddrspaceCast();
@@ -2776,39 +2777,9 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
27762777
CheckedConversionKind CCK = FunctionalStyle
27772778
? CheckedConversionKind::FunctionalCast
27782779
: CheckedConversionKind::CStyleCast;
2779-
2780-
QualType SrcTy = SrcExpr.get()->getType();
2781-
// This case should not trigger on regular vector cast, vector truncation
2782-
if (Self.getLangOpts().HLSL &&
2783-
Self.HLSL().CanPerformElementwiseCast(SrcExpr.get(), DestType)) {
2784-
if (SrcTy->isConstantArrayType())
2785-
SrcExpr = Self.ImpCastExprToType(
2786-
SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy),
2787-
CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK);
2788-
Kind = CK_HLSLElementwiseCast;
2789-
return;
2790-
}
2791-
2792-
// This case should not trigger on regular vector splat
2793-
// If the relative order of this and the HLSLElementWise cast checks
2794-
// are changed, it might change which cast handles what in a few cases
2795-
if (Self.getLangOpts().HLSL &&
2796-
Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) {
2797-
const VectorType *VT = SrcTy->getAs<VectorType>();
2798-
// change splat from vec1 case to splat from scalar
2799-
if (VT && VT->getNumElements() == 1)
2800-
SrcExpr = Self.ImpCastExprToType(
2801-
SrcExpr.get(), VT->getElementType(), CK_HLSLVectorTruncation,
2802-
SrcExpr.get()->getValueKind(), nullptr, CCK);
2803-
// Inserting a scalar cast here allows for a simplified codegen in
2804-
// the case the destTy is a vector
2805-
if (const VectorType *DVT = DestType->getAs<VectorType>())
2806-
SrcExpr = Self.ImpCastExprToType(
2807-
SrcExpr.get(), DVT->getElementType(),
2808-
Self.PrepareScalarCast(SrcExpr, DVT->getElementType()),
2809-
SrcExpr.get()->getValueKind(), nullptr, CCK);
2810-
Kind = CK_HLSLAggregateSplatCast;
2811-
return;
2780+
if (Self.getLangOpts().HLSL) {
2781+
if (CheckHLSLCStyleCast(CCK))
2782+
return;
28122783
}
28132784

28142785
if (ValueKind == VK_PRValue && !DestType->isRecordType() &&
@@ -2927,6 +2898,56 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
29272898
}
29282899
}
29292900

2901+
// CheckHLSLCStyleCast - Returns `true` ihe cast is handled or errored as an
2902+
// HLSL-specific cast. Returns false if the cast should be checked as a CXX
2903+
// C-Style cast.
2904+
bool CastOperation::CheckHLSLCStyleCast(CheckedConversionKind CCK) {
2905+
assert(Self.getLangOpts().HLSL && "Must be HLSL!");
2906+
QualType SrcTy = SrcExpr.get()->getType();
2907+
// HLSL has several unique forms of C-style casts which support aggregate to
2908+
// aggregate casting.
2909+
// This case should not trigger on regular vector cast, vector truncation
2910+
if (Self.HLSL().CanPerformElementwiseCast(SrcExpr.get(), DestType)) {
2911+
if (SrcTy->isConstantArrayType())
2912+
SrcExpr = Self.ImpCastExprToType(
2913+
SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy),
2914+
CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK);
2915+
Kind = CK_HLSLElementwiseCast;
2916+
return true;
2917+
}
2918+
2919+
// This case should not trigger on regular vector splat
2920+
// If the relative order of this and the HLSLElementWise cast checks
2921+
// are changed, it might change which cast handles what in a few cases
2922+
if (Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) {
2923+
const VectorType *VT = SrcTy->getAs<VectorType>();
2924+
// change splat from vec1 case to splat from scalar
2925+
if (VT && VT->getNumElements() == 1)
2926+
SrcExpr = Self.ImpCastExprToType(
2927+
SrcExpr.get(), VT->getElementType(), CK_HLSLVectorTruncation,
2928+
SrcExpr.get()->getValueKind(), nullptr, CCK);
2929+
// Inserting a scalar cast here allows for a simplified codegen in
2930+
// the case the destTy is a vector
2931+
if (const VectorType *DVT = DestType->getAs<VectorType>())
2932+
SrcExpr = Self.ImpCastExprToType(
2933+
SrcExpr.get(), DVT->getElementType(),
2934+
Self.PrepareScalarCast(SrcExpr, DVT->getElementType()),
2935+
SrcExpr.get()->getValueKind(), nullptr, CCK);
2936+
Kind = CK_HLSLAggregateSplatCast;
2937+
return true;
2938+
}
2939+
2940+
// If the destination is an array, we've exhausted the valid HLSL casts, so we
2941+
// should emit a dignostic and stop processing.
2942+
if (DestType->isArrayType()) {
2943+
Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
2944+
<< 4 << SrcTy << DestType;
2945+
SrcExpr = ExprError();
2946+
return true;
2947+
}
2948+
return false;
2949+
}
2950+
29302951
/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a
29312952
/// non-matching type. Such as enum function call to int, int call to
29322953
/// pointer; etc. Cast to 'void' is an exception.

clang/lib/Sema/SemaInit.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6585,6 +6585,18 @@ void InitializationSequence::InitializeFrom(Sema &S,
65856585
}
65866586
}
65876587

6588+
if (S.getLangOpts().HLSL && Initializer && isa<ConstantArrayType>(DestAT)) {
6589+
QualType SrcType = Entity.getType();
6590+
if (SrcType->isArrayParameterType())
6591+
SrcType =
6592+
cast<ArrayParameterType>(SrcType)->getConstantArrayType(Context);
6593+
if (S.Context.hasSameUnqualifiedType(DestType, SrcType)) {
6594+
TryArrayCopy(S, Kind, Entity, Initializer, DestType, *this,
6595+
TreatUnavailableAsInvalid);
6596+
return;
6597+
}
6598+
}
6599+
65886600
// Some kinds of initialization permit an array to be initialized from
65896601
// another array of the same type, and perform elementwise initialization.
65906602
if (Initializer && isa<ConstantArrayType>(DestAT) &&
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -ast-dump | FileCheck %s
2+
3+
typedef vector<int,4> int8[2];
4+
5+
export void fn(int8 A) {
6+
int8 a = {A};
7+
// CHECK-LABEL: VarDecl {{.*}} b 'int8':'vector<int, 4>[2]' cinit
8+
// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector<int, 4>[2]'
9+
// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue
10+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue Var {{.*}} 'a' 'int8':'vector<int, 4>[2]'
11+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
12+
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector<int, 4>' lvalue
13+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4> *' <ArrayToPointerDecay>
14+
// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue
15+
// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue Var {{.*}} 'a' 'int8':'vector<int, 4>[2]'
16+
// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
17+
int8 b = a;
18+
19+
// CHECK-LABEL: VarDecl {{.*}} c 'int8':'vector<int, 4>[2]' cinit
20+
// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector<int, 4>[2]'
21+
// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector<int, 4>[2]' lvalue
22+
// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 4>[2]' lvalue ParmVar {{.*}} 'A' 'vector<int, 4>[2]'
23+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
24+
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector<int, 4>' lvalue
25+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4> *' <ArrayToPointerDecay>
26+
// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector<int, 4>[2]' lvalue
27+
// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 4>[2]' lvalue ParmVar {{.*}} 'A' 'vector<int, 4>[2]'
28+
// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
29+
int8 c = A;
30+
}
31+
32+
33+
34+

clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export void cantCast() {
44
int A[3] = {1,2,3};
55
int B[4] = {1,2,3,4};
66
B = (int[4])A;
7-
// expected-error@-1 {{C-style cast from 'int *' to 'int[4]' is not allowed}}
7+
// expected-error@-1 {{C-style cast from 'int[3]' to 'int[4]' is not allowed}}
88
}
99

1010
struct S {

0 commit comments

Comments
 (0)