-
Notifications
You must be signed in to change notification settings - Fork 13.9k
[HLSL] Allow arrays to copy-initialize #127557
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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 llvm#127551
@llvm/pr-subscribers-hlsl @llvm/pr-subscribers-clang Author: Chris B (llvm-beanz) ChangesThis 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 Full diff: https://github.com/llvm/llvm-project/pull/127557.diff 4 Files Affected:
diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 8972957ded9f5..3ab8598e513c6 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -2778,37 +2778,45 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
: CheckedConversionKind::CStyleCast;
QualType SrcTy = SrcExpr.get()->getType();
- // This case should not trigger on regular vector cast, vector truncation
- if (Self.getLangOpts().HLSL &&
- Self.HLSL().CanPerformElementwiseCast(SrcExpr.get(), DestType)) {
- if (SrcTy->isConstantArrayType())
- SrcExpr = Self.ImpCastExprToType(
- SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy),
- CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK);
- Kind = CK_HLSLElementwiseCast;
- return;
- }
-
- // This case should not trigger on regular vector splat
- // If the relative order of this and the HLSLElementWise cast checks
- // are changed, it might change which cast handles what in a few cases
- if (Self.getLangOpts().HLSL &&
- Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) {
- const VectorType *VT = SrcTy->getAs<VectorType>();
- // change splat from vec1 case to splat from scalar
- if (VT && VT->getNumElements() == 1)
- SrcExpr = Self.ImpCastExprToType(
- SrcExpr.get(), VT->getElementType(), CK_HLSLVectorTruncation,
- SrcExpr.get()->getValueKind(), nullptr, CCK);
- // Inserting a scalar cast here allows for a simplified codegen in
- // the case the destTy is a vector
- if (const VectorType *DVT = DestType->getAs<VectorType>())
- SrcExpr = Self.ImpCastExprToType(
- SrcExpr.get(), DVT->getElementType(),
- Self.PrepareScalarCast(SrcExpr, DVT->getElementType()),
- SrcExpr.get()->getValueKind(), nullptr, CCK);
- Kind = CK_HLSLAggregateSplatCast;
- return;
+ // HLSL has several unique forms of C-style casts which support aggregate to
+ // aggregate casting.
+ if (Self.getLangOpts().HLSL) {
+ // This case should not trigger on regular vector cast, vector truncation
+ if (Self.HLSL().CanPerformElementwiseCast(SrcExpr.get(), DestType)) {
+ if (SrcTy->isConstantArrayType())
+ SrcExpr = Self.ImpCastExprToType(
+ SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy),
+ CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK);
+ Kind = CK_HLSLElementwiseCast;
+ return;
+ }
+
+ // This case should not trigger on regular vector splat
+ // If the relative order of this and the HLSLElementWise cast checks
+ // are changed, it might change which cast handles what in a few cases
+ if (Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) {
+ const VectorType *VT = SrcTy->getAs<VectorType>();
+ // change splat from vec1 case to splat from scalar
+ if (VT && VT->getNumElements() == 1)
+ SrcExpr = Self.ImpCastExprToType(
+ SrcExpr.get(), VT->getElementType(), CK_HLSLVectorTruncation,
+ SrcExpr.get()->getValueKind(), nullptr, CCK);
+ // Inserting a scalar cast here allows for a simplified codegen in
+ // the case the destTy is a vector
+ if (const VectorType *DVT = DestType->getAs<VectorType>())
+ SrcExpr = Self.ImpCastExprToType(
+ SrcExpr.get(), DVT->getElementType(),
+ Self.PrepareScalarCast(SrcExpr, DVT->getElementType()),
+ SrcExpr.get()->getValueKind(), nullptr, CCK);
+ Kind = CK_HLSLAggregateSplatCast;
+ return;
+ }
+ if (DestType->isArrayType()) {
+ Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+ << 4 << SrcTy << DestType;
+ SrcExpr = ExprError();
+ return;
+ }
}
if (ValueKind == VK_PRValue && !DestType->isRecordType() &&
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 6a76e6d74a4b0..a34005bf376aa 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -6585,6 +6585,18 @@ void InitializationSequence::InitializeFrom(Sema &S,
}
}
+ if (S.getLangOpts().HLSL && Initializer && isa<ConstantArrayType>(DestAT)) {
+ QualType SrcType = Entity.getType();
+ if (SrcType->isArrayParameterType())
+ SrcType =
+ cast<ArrayParameterType>(SrcType)->getConstantArrayType(Context);
+ if (S.Context.hasSameUnqualifiedType(DestType, SrcType)) {
+ TryArrayCopy(S, Kind, Entity, Initializer, DestType, *this,
+ TreatUnavailableAsInvalid);
+ return;
+ }
+ }
+
// Some kinds of initialization permit an array to be initialized from
// another array of the same type, and perform elementwise initialization.
if (Initializer && isa<ConstantArrayType>(DestAT) &&
diff --git a/clang/test/SemaHLSL/Language/AssignArray.hlsl b/clang/test/SemaHLSL/Language/AssignArray.hlsl
new file mode 100644
index 0000000000000..1f813e7a350b1
--- /dev/null
+++ b/clang/test/SemaHLSL/Language/AssignArray.hlsl
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library %s -ast-dump | FileCheck %s
+
+typedef vector<int,4> int8[2];
+
+export void fn(int8 A) {
+ int8 a = {A};
+// CHECK-LABEL: VarDecl {{.*}} b 'int8':'vector<int, 4>[2]' cinit
+// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue Var {{.*}} 'a' 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector<int, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4> *' <ArrayToPointerDecay>
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int8':'vector<int, 4>[2]' lvalue Var {{.*}} 'a' 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
+ int8 b = a;
+
+// CHECK-LABEL: VarDecl {{.*}} c 'int8':'vector<int, 4>[2]' cinit
+// CHECK-NEXT: ArrayInitLoopExpr {{.*}} 'int8':'vector<int, 4>[2]'
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 4>[2]' lvalue ParmVar {{.*}} 'A' 'vector<int, 4>[2]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4>' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'vector<int, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<int, 4> *' <ArrayToPointerDecay>
+// CHECK-NEXT: OpaqueValueExpr {{.*}} 'vector<int, 4>[2]' lvalue
+// CHECK-NEXT: DeclRefExpr {{.*}} 'vector<int, 4>[2]' lvalue ParmVar {{.*}} 'A' 'vector<int, 4>[2]'
+// CHECK-NEXT: ArrayInitIndexExpr {{.*}} 'unsigned long'
+ int8 c = A;
+}
+
+
+
+
diff --git a/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl b/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
index 9417249383469..30591507b3260 100644
--- a/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
+++ b/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
@@ -4,7 +4,7 @@ export void cantCast() {
int A[3] = {1,2,3};
int B[4] = {1,2,3,4};
B = (int[4])A;
- // expected-error@-1 {{C-style cast from 'int *' to 'int[4]' is not allowed}}
+ // expected-error@-1 {{C-style cast from 'int[3]' to 'int[4]' is not allowed}}
}
struct S {
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -6585,6 +6585,18 @@ void InitializationSequence::InitializeFrom(Sema &S, | |||
} | |||
} | |||
|
|||
if (S.getLangOpts().HLSL && Initializer && isa<ConstantArrayType>(DestAT)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to consolidate this if statement with the one below, unless HLSL Arrays can always be copy initialized, then it might be nicer left separate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this a bit. canPerformArrayCopy
fails in cases that would otherwise be valid in HLSL. At least for HLSL today we can always copy an array if the source and destination type are the same, so we don't need to check that.
clang/lib/Sema/SemaCast.cpp
Outdated
} | ||
if (DestType->isArrayType()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A blank line here would be aesthetically pleasing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also use a comment... Added both.
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