Skip to content

Commit d8df118

Browse files
authored
[HLSL] Array by-value assignment (#109323)
Make Constant Arrays in HLSL assignable. Closes #109043
1 parent f6b2a22 commit d8df118

File tree

8 files changed

+282
-4
lines changed

8 files changed

+282
-4
lines changed

clang/include/clang/AST/CanonicalType.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ class CanProxyBase {
299299
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType)
300300
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType)
301301
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType)
302+
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantArrayType)
302303
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation)
303304
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation)
304305
LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasIntegerRepresentation)

clang/lib/AST/ExprClassification.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
704704
return Cl::CM_ConstAddrSpace;
705705

706706
// Arrays are not modifiable, only their elements are.
707-
if (CT->isArrayType())
707+
if (CT->isArrayType() &&
708+
!(Ctx.getLangOpts().HLSL && CT->isConstantArrayType()))
708709
return Cl::CM_ArrayType;
709710
// Incomplete types are not modifiable.
710711
if (CT->isIncompleteType())

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5797,11 +5797,26 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
57975797
return EmitComplexAssignmentLValue(E);
57985798

57995799
case TEK_Aggregate:
5800+
// If the lang opt is HLSL and the LHS is a constant array
5801+
// then we are performing a copy assignment and call a special
5802+
// function because EmitAggExprToLValue emits to a temporary LValue
5803+
if (getLangOpts().HLSL && E->getLHS()->getType()->isConstantArrayType())
5804+
return EmitHLSLArrayAssignLValue(E);
5805+
58005806
return EmitAggExprToLValue(E);
58015807
}
58025808
llvm_unreachable("bad evaluation kind");
58035809
}
58045810

5811+
// This function implements trivial copy assignment for HLSL's
5812+
// assignable constant arrays.
5813+
LValue CodeGenFunction::EmitHLSLArrayAssignLValue(const BinaryOperator *E) {
5814+
LValue TrivialAssignmentRHS = EmitLValue(E->getRHS());
5815+
LValue LHS = EmitLValue(E->getLHS());
5816+
EmitAggregateAssign(LHS, TrivialAssignmentRHS, E->getLHS()->getType());
5817+
return LHS;
5818+
}
5819+
58055820
LValue CodeGenFunction::EmitCallExprLValue(const CallExpr *E,
58065821
llvm::CallBase **CallOrInvoke) {
58075822
RValue RV = EmitCallExpr(E, ReturnValueSlot(), CallOrInvoke);

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4296,6 +4296,7 @@ class CodeGenFunction : public CodeGenTypeCache {
42964296
LValue EmitCastLValue(const CastExpr *E);
42974297
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
42984298
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
4299+
LValue EmitHLSLArrayAssignLValue(const BinaryOperator *E);
42994300
void EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, CallArgList &Args,
43004301
QualType Ty);
43014302

clang/lib/Sema/SemaOverload.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,16 +2232,21 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
22322232
// just strip the qualifiers because they don't matter.
22332233
FromType = FromType.getUnqualifiedType();
22342234
} else if (S.getLangOpts().HLSL && FromType->isConstantArrayType() &&
2235-
ToType->isArrayParameterType()) {
2235+
ToType->isConstantArrayType()) {
22362236
// HLSL constant array parameters do not decay, so if the argument is a
22372237
// constant array and the parameter is an ArrayParameterType we have special
22382238
// handling here.
2239-
FromType = S.Context.getArrayParameterType(FromType);
2239+
if (ToType->isArrayParameterType()) {
2240+
FromType = S.Context.getArrayParameterType(FromType);
2241+
SCS.First = ICK_HLSL_Array_RValue;
2242+
} else {
2243+
SCS.First = ICK_Identity;
2244+
}
2245+
22402246
if (S.Context.getCanonicalType(FromType) !=
22412247
S.Context.getCanonicalType(ToType))
22422248
return false;
22432249

2244-
SCS.First = ICK_HLSL_Array_RValue;
22452250
SCS.setAllToTypes(ToType);
22462251
return true;
22472252
} else if (FromType->isArrayType()) {
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s
2+
3+
// CHECK-LABEL: arr_assign1
4+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
5+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]'
6+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]'
7+
void arr_assign1() {
8+
int Arr[2] = {0, 1};
9+
int Arr2[2] = {0, 0};
10+
Arr = Arr2;
11+
}
12+
13+
// CHECK-LABEL: arr_assign2
14+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
15+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]'
16+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
17+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]'
18+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr3' 'int[2]'
19+
void arr_assign2() {
20+
int Arr[2] = {0, 1};
21+
int Arr2[2] = {0, 0};
22+
int Arr3[2] = {2, 2};
23+
Arr = Arr2 = Arr3;
24+
}
25+
26+
// CHECK-LABEL: arr_assign3
27+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue '='
28+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2][2]'
29+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2][2]'
30+
void arr_assign3() {
31+
int Arr[2][2] = {{0, 1}, {2, 3}};
32+
int Arr2[2][2] = {{0, 0}, {1, 1}};
33+
Arr = Arr2;
34+
}
35+
36+
// CHECK-LABEL: arr_assign4
37+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue '='
38+
// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue
39+
// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int *' <ArrayToPointerDecay>
40+
// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue
41+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
42+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]'
43+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]'
44+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0
45+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6
46+
void arr_assign4() {
47+
int Arr[2] = {0, 1};
48+
int Arr2[2] = {0, 0};
49+
(Arr = Arr2)[0] = 6;
50+
}
51+
52+
// CHECK-LABEL: arr_assign5
53+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue '='
54+
// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue
55+
// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int *' <ArrayToPointerDecay>
56+
// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue
57+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
58+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2]'
59+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
60+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2]'
61+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr3' 'int[2]'
62+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0
63+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6
64+
void arr_assign5() {
65+
int Arr[2] = {0, 1};
66+
int Arr2[2] = {0, 0};
67+
int Arr3[2] = {3, 4};
68+
(Arr = Arr2 = Arr3)[0] = 6;
69+
}
70+
71+
// CHECK-LABEL: arr_assign6
72+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue '='
73+
// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int' lvalue
74+
// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int *' <ArrayToPointerDecay>
75+
// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue
76+
// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int (*)[2]' <ArrayToPointerDecay>
77+
// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue
78+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue '='
79+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2][2]'
80+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2][2]'
81+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0
82+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0
83+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6
84+
void arr_assign6() {
85+
int Arr[2][2] = {{0, 1}, {2, 3}};
86+
int Arr2[2][2] = {{0, 0}, {1, 1}};
87+
(Arr = Arr2)[0][0] = 6;
88+
}
89+
90+
// CHECK-LABEL: arr_assign7
91+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue '='
92+
// CHECK: ArraySubscriptExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]' lvalue
93+
// CHECK: ImplicitCastExpr 0x{{[0-9a-f]+}} {{.*}} 'int (*)[2]' <ArrayToPointerDecay>
94+
// CHECK: ParenExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue
95+
// CHECK: BinaryOperator 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue '='
96+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr' 'int[2][2]'
97+
// CHECK: DeclRefExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2][2]' lvalue Var 0x{{[0-9a-f]+}} 'Arr2' 'int[2][2]'
98+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 0
99+
// CHECK: InitListExpr 0x{{[0-9a-f]+}} {{.*}} 'int[2]'
100+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6
101+
// CHECK: IntegerLiteral 0x{{[0-9a-f]+}} {{.*}} 'int' 6
102+
void arr_assign7() {
103+
int Arr[2][2] = {{0, 1}, {2, 3}};
104+
int Arr2[2][2] = {{0, 0}, {1, 1}};
105+
(Arr = Arr2)[0] = {6, 6};
106+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s --enable-var-scope
2+
3+
// CHECK-LABEL: define void {{.*}}arr_assign1
4+
// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4
5+
// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4
6+
// CHECK-NOT: alloca
7+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false)
8+
// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false)
9+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false)
10+
// CHECK-NEXT: ret void
11+
void arr_assign1() {
12+
int Arr[2] = {0, 1};
13+
int Arr2[2] = {0, 0};
14+
Arr = Arr2;
15+
}
16+
17+
// CHECK-LABEL: define void {{.*}}arr_assign2
18+
// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4
19+
// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4
20+
// CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4
21+
// CHECK-NOT: alloca
22+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false)
23+
// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false)
24+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 8, i1 false)
25+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr2]], ptr align 4 [[Arr3]], i32 8, i1 false)
26+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false)
27+
// CHECK-NEXT: ret void
28+
void arr_assign2() {
29+
int Arr[2] = {0, 1};
30+
int Arr2[2] = {0, 0};
31+
int Arr3[2] = {3, 4};
32+
Arr = Arr2 = Arr3;
33+
}
34+
35+
// CHECK-LABEL: define void {{.*}}arr_assign3
36+
// CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4
37+
// CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4
38+
// CHECK-NOT: alloca
39+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 16, i1 false)
40+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr4]], ptr align 4 {{@.*}}, i32 16, i1 false)
41+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 [[Arr4]], i32 16, i1 false)
42+
// CHECK-NEXT: ret void
43+
void arr_assign3() {
44+
int Arr2[2][2] = {{0, 0}, {1, 1}};
45+
int Arr3[2][2] = {{1, 1}, {0, 0}};
46+
Arr2 = Arr3;
47+
}
48+
49+
// CHECK-LABEL: define void {{.*}}arr_assign4
50+
// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4
51+
// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4
52+
// CHECK-NOT: alloca
53+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false)
54+
// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false)
55+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false)
56+
// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[Arr]], i32 0, i32 0
57+
// CHECK-NEXT: store i32 6, ptr [[Idx]], align 4
58+
// CHECK-NEXT: ret void
59+
void arr_assign4() {
60+
int Arr[2] = {0, 1};
61+
int Arr2[2] = {0, 0};
62+
(Arr = Arr2)[0] = 6;
63+
}
64+
65+
// CHECK-LABEL: define void {{.*}}arr_assign5
66+
// CHECK: [[Arr:%.*]] = alloca [2 x i32], align 4
67+
// CHECK-NEXT: [[Arr2:%.*]] = alloca [2 x i32], align 4
68+
// CHECK-NEXT: [[Arr3:%.*]] = alloca [2 x i32], align 4
69+
// CHECK-NOT: alloca
70+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{@.*}}, i32 8, i1 false)
71+
// CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 [[Arr2]], i8 0, i32 8, i1 false)
72+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 8, i1 false)
73+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr2]], ptr align 4 [[Arr3]], i32 8, i1 false)
74+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 [[Arr2]], i32 8, i1 false)
75+
// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x i32], ptr [[Arr]], i32 0, i32 0
76+
// CHECK-NEXT: store i32 6, ptr [[Idx]], align 4
77+
// CHECK-NEXT: ret void
78+
void arr_assign5() {
79+
int Arr[2] = {0, 1};
80+
int Arr2[2] = {0, 0};
81+
int Arr3[2] = {3, 4};
82+
(Arr = Arr2 = Arr3)[0] = 6;
83+
}
84+
85+
// CHECK-LABEL: define void {{.*}}arr_assign6
86+
// CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4
87+
// CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4
88+
// CHECK-NOT: alloca
89+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 16, i1 false)
90+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr4]], ptr align 4 {{@.*}}, i32 16, i1 false)
91+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 [[Arr4]], i32 16, i1 false)
92+
// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[Arr3]], i32 0, i32 0
93+
// CHECK-NEXT: [[Idx2:%.*]] = getelementptr inbounds [2 x i32], ptr [[Idx]], i32 0, i32 0
94+
// CHECK-NEXT: store i32 6, ptr [[Idx2]], align 4
95+
// CHECK-NEXT: ret void
96+
void arr_assign6() {
97+
int Arr[2][2] = {{0, 0}, {1, 1}};
98+
int Arr2[2][2] = {{1, 1}, {0, 0}};
99+
(Arr = Arr2)[0][0] = 6;
100+
}
101+
102+
// CHECK-LABEL: define void {{.*}}arr_assign7
103+
// CHECK: [[Arr3:%.*]] = alloca [2 x [2 x i32]], align 4
104+
// CHECK-NEXT: [[Arr4:%.*]] = alloca [2 x [2 x i32]], align 4
105+
// CHECK-NEXT: [[Tmp:%.*]] = alloca [2 x i32], align 4
106+
// CHECK-NOT: alloca
107+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 {{@.*}}, i32 16, i1 false)
108+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr4]], ptr align 4 {{@.*}}, i32 16, i1 false)
109+
// CHECK-NEXT: store i32 6, ptr [[Tmp]], align 4
110+
// CHECK-NEXT: [[AIE:%.*]] = getelementptr inbounds i32, ptr [[Tmp]], i32 1
111+
// CHECK-NEXT: store i32 6, ptr [[AIE]], align 4
112+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr3]], ptr align 4 [[Arr4]], i32 16, i1 false)
113+
// CHECK-NEXT: [[Idx:%.*]] = getelementptr inbounds [2 x [2 x i32]], ptr [[Arr3]], i32 0, i32 0
114+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Idx]], ptr align 4 [[Tmp]], i32 8, i1 false)
115+
// CHECK-NEXT: ret void
116+
void arr_assign7() {
117+
int Arr[2][2] = {{0, 1}, {2, 3}};
118+
int Arr2[2][2] = {{0, 0}, {1, 1}};
119+
(Arr = Arr2)[0] = {6, 6};
120+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -verify
2+
3+
void test_wrong_size1() {
4+
int Arr[2] = {0, 1};
5+
int Arr2[3] = {1, 2, 0};
6+
Arr = Arr2;
7+
// expected-error@-1 {{assigning to 'int[2]' from incompatible type 'int[3]'}}
8+
}
9+
10+
void test_wrong_size2() {
11+
int Arr[2] = {0, 1};
12+
int Arr2[3] = {1, 2, 0};
13+
Arr2 = Arr;
14+
// expected-error@-1 {{assigning to 'int[3]' from incompatible type 'int[2]'}}
15+
}
16+
17+
void test_wrong_size3() {
18+
int Arr[2][2] = {{0, 1}, {2, 3}};
19+
int Arr2[2] = {4, 5};
20+
Arr = Arr2;
21+
// expected-error@-1 {{assigning to 'int[2][2]' from incompatible type 'int[2]'}}
22+
}
23+
24+
void test_wrong_size4() {
25+
int Arr[2][2] = {{0, 1}, {2, 3}};
26+
int Arr2[2] = {4, 5};
27+
Arr2 = Arr;
28+
// expected-error@-1 {{assigning to 'int[2]' from incompatible type 'int[2][2]'}}
29+
}

0 commit comments

Comments
 (0)