Skip to content

Commit d3d7c3c

Browse files
llvm-beanzhekota
andauthored
[HLSL] Fix vector list initialization (#161421)
This simplifies and cleans up the vector list initialization behavior. This simplifies the work we do in SemaInit by just relying on SemaHLSL's initialization list flattening. This change fixes some outstanding limitations by supporting structure to vector initialization, but re-introduces HLSL's limitations around overload resolution in initializers. --------- Co-authored-by: Helena Kotas <[email protected]>
1 parent 68a7196 commit d3d7c3c

File tree

6 files changed

+185
-115
lines changed

6 files changed

+185
-115
lines changed

clang/include/clang/Sema/Initialization.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,9 @@ class InitializationSequence {
11261126

11271127
// A designated initializer was provided for a non-aggregate type.
11281128
FK_DesignatedInitForNonAggregate,
1129+
1130+
/// HLSL intialization list flattening failed.
1131+
FK_HLSLInitListFlatteningFailed,
11291132
};
11301133

11311134
private:

clang/lib/Sema/SemaInit.cpp

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3920,6 +3920,7 @@ bool InitializationSequence::isAmbiguous() const {
39203920
case FK_AddressOfUnaddressableFunction:
39213921
case FK_ParenthesizedListInitFailed:
39223922
case FK_DesignatedInitForNonAggregate:
3923+
case FK_HLSLInitListFlatteningFailed:
39233924
return false;
39243925

39253926
case FK_ReferenceInitOverloadFailed:
@@ -4882,8 +4883,10 @@ static void TryListInitialization(Sema &S,
48824883
bool TreatUnavailableAsInvalid) {
48834884
QualType DestType = Entity.getType();
48844885

4885-
if (S.getLangOpts().HLSL && !S.HLSL().transformInitList(Entity, InitList))
4886+
if (S.getLangOpts().HLSL && !S.HLSL().transformInitList(Entity, InitList)) {
4887+
Sequence.SetFailed(InitializationSequence::FK_HLSLInitListFlatteningFailed);
48864888
return;
4889+
}
48874890

48884891
// C++ doesn't allow scalar initialization with more than one argument.
48894892
// But C99 complex numbers are scalars and it makes sense there.
@@ -6817,33 +6820,18 @@ void InitializationSequence::InitializeFrom(Sema &S,
68176820
assert(Args.size() >= 1 && "Zero-argument case handled above");
68186821

68196822
// For HLSL ext vector types we allow list initialization behavior for C++
6820-
// constructor syntax. This is accomplished by converting initialization
6821-
// arguments an InitListExpr late.
6823+
// functional cast expressions which look like constructor syntax. This is
6824+
// accomplished by converting initialization arguments to InitListExpr.
68226825
if (S.getLangOpts().HLSL && Args.size() > 1 && DestType->isExtVectorType() &&
68236826
(SourceType.isNull() ||
68246827
!Context.hasSameUnqualifiedType(SourceType, DestType))) {
6825-
6826-
llvm::SmallVector<Expr *> InitArgs;
6827-
for (auto *Arg : Args) {
6828-
if (Arg->getType()->isExtVectorType()) {
6829-
const auto *VTy = Arg->getType()->castAs<ExtVectorType>();
6830-
unsigned Elm = VTy->getNumElements();
6831-
for (unsigned Idx = 0; Idx < Elm; ++Idx) {
6832-
InitArgs.emplace_back(new (Context) ArraySubscriptExpr(
6833-
Arg,
6834-
IntegerLiteral::Create(
6835-
Context, llvm::APInt(Context.getIntWidth(Context.IntTy), Idx),
6836-
Context.IntTy, SourceLocation()),
6837-
VTy->getElementType(), Arg->getValueKind(), Arg->getObjectKind(),
6838-
SourceLocation()));
6839-
}
6840-
} else
6841-
InitArgs.emplace_back(Arg);
6842-
}
6843-
InitListExpr *ILE = new (Context) InitListExpr(
6844-
S.getASTContext(), SourceLocation(), InitArgs, SourceLocation());
6828+
InitListExpr *ILE = new (Context)
6829+
InitListExpr(S.getASTContext(), Args.front()->getBeginLoc(), Args,
6830+
Args.back()->getEndLoc());
6831+
ILE->setType(DestType);
68456832
Args[0] = ILE;
6846-
AddListInitializationStep(DestType);
6833+
TryListInitialization(S, Entity, Kind, ILE, *this,
6834+
TreatUnavailableAsInvalid);
68476835
return;
68486836
}
68496837

@@ -9301,6 +9289,14 @@ bool InitializationSequence::Diagnose(Sema &S,
93019289
break;
93029290
}
93039291

9292+
case InitializationSequence::FK_HLSLInitListFlatteningFailed: {
9293+
// Unlike C/C++ list initialization, there is no fallback if it fails. This
9294+
// allows us to diagnose the failure when it happens in the
9295+
// TryListInitialization call instead of delaying the diagnosis, which is
9296+
// beneficial because the flattening is also expensive.
9297+
break;
9298+
}
9299+
93049300
case FK_ExplicitConstructor: {
93059301
S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor)
93069302
<< Args[0]->getSourceRange();
@@ -9499,6 +9495,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
94999495
case FK_DesignatedInitForNonAggregate:
95009496
OS << "designated initializer for non-aggregate type";
95019497
break;
9498+
9499+
case FK_HLSLInitListFlatteningFailed:
9500+
OS << "HLSL initialization list flattening failed";
9501+
break;
95029502
}
95039503
OS << '\n';
95049504
return;

clang/test/AST/HLSL/vector-constructors.hlsl

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ void entry() {
1414
// parameters to an initialization list
1515
// CHECK-LABEL: VarDecl {{.*}} used Vec2 'float2':'vector<float, 2>' cinit
1616
// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2':'vector<float, 2>' functional cast to float2 <NoOp>
17-
// CHECK-NEXT: InitListExpr {{.*}} 'float2':'vector<float, 2>'
17+
// CHECK-NEXT: InitListExpr {{0x[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>'
1818
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
1919
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
2020

@@ -28,11 +28,11 @@ void entry() {
2828
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
2929
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue
3030
// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'Vec2' 'float2':'vector<float, 2>'
31-
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
31+
// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0
3232
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
3333
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue
3434
// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'Vec2' 'float2':'vector<float, 2>'
35-
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
35+
// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 1
3636
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
3737

3838
// CHECK: VarDecl {{.*}} 'float3':'vector<float, 3>' cinit
@@ -93,25 +93,6 @@ void entry() {
9393
// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .f {{.*}}
9494
// CHECK-NEXT: DeclRefExpr {{.*}} 'struct S' lvalue Var {{.*}} 's' 'struct S'
9595

96-
struct T {
97-
operator float() const { return 1.0f; }
98-
} t;
99-
float2 foo5 = float2(t, t); // user-defined cast operator
100-
101-
// CHECK-LABEL: VarDecl {{.*}} foo5 'float2'
102-
// CHECK-NEXT: CXXFunctionalCastExpr
103-
// CHECK-NEXT: InitListExpr
104-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <UserDefinedConversion>
105-
// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float'
106-
// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator float {{.*}}
107-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const T' lvalue <NoOp>
108-
// CHECK-NEXT: DeclRefExpr {{.*}} 'struct T' lvalue Var {{.*}} 't' 'struct T'
109-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <UserDefinedConversion>
110-
// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float'
111-
// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator float {{.*}}
112-
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const T' lvalue <NoOp>
113-
// CHECK-NEXT: DeclRefExpr {{.*}} 'struct T' lvalue Var {{.*}} 't' 'struct T'
114-
11596
typedef float2 second_level_of_typedefs;
11697
second_level_of_typedefs foo6 = float2(1.0f, 2.0f);
11798

clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl

Lines changed: 124 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,6 @@ struct EmptyDerived : Empty {};
6161

6262
struct UnnamedDerived : UnnamedOnly {};
6363

64-
// CHECK-DAG: [[ConstE:@.*]] = private unnamed_addr constant %struct.Empty undef, align 1
65-
// CHECK-DAG: [[ConstUO:@.*]] = private unnamed_addr constant %struct.UnnamedOnly undef, align 1
66-
// CHECK-DAG: [[ConstED:@.*]] = private unnamed_addr constant %struct.EmptyDerived undef, align 1
67-
// CHECK-DAG: [[ConstUD:@.*]] = private unnamed_addr constant %struct.UnnamedDerived undef, align 1
6864

6965
// Case 1: Extraneous braces get ignored in literal instantiation.
7066
// CHECK-LABEL: define hidden void @_Z5case1v(
@@ -911,15 +907,15 @@ TwoFloats case15(SlicyBits SB) {
911907
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca ptr, align 4
912908
// CHECK-NEXT: store ptr [[X]], ptr [[X_ADDR]], align 4
913909
// CHECK-NEXT: [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
914-
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X_ADDR]], align 4
910+
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X_ADDR]], align 4, !nonnull [[META3:![0-9]+]], !align [[META4:![0-9]+]]
915911
// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[TMP0]], align 4
916912
// CHECK-NEXT: store float [[TMP1]], ptr [[X1]], align 1
917913
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
918-
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[X_ADDR]], align 4
914+
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[X_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
919915
// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[TMP2]], align 4
920916
// CHECK-NEXT: [[MUL:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP3]], 1.500000e+00
921917
// CHECK-NEXT: store float [[MUL]], ptr [[Y]], align 1
922-
// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[X_ADDR]], align 4
918+
// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[X_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
923919
// CHECK-NEXT: [[TMP5:%.*]] = load float, ptr [[TMP4]], align 4
924920
// CHECK-NEXT: [[MUL2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP5]], 2.000000e+00
925921
// CHECK-NEXT: store float [[MUL2]], ptr [[TMP4]], align 4
@@ -964,94 +960,173 @@ FourFloats case16() {
964960
}
965961

966962

963+
// CHECK-LABEL: define hidden noundef i32 @_Z12case17Helperi(
964+
// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] {
965+
// CHECK-NEXT: [[ENTRY:.*:]]
966+
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
967+
// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
968+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
969+
// CHECK-NEXT: ret i32 [[TMP0]]
970+
//
967971
int case17Helper(int x) {
968972
return x;
969973
}
970974

971975
// InitList with OpaqueValueExpr
972-
// CHECK-LABEL: define hidden void {{.*}}case17
973-
// CHECK: [[X:%.*]] = alloca <2 x i32>, align 8
974-
// CHECK-NEXT: [[C:%.*]] = call noundef i32 {{.*}}case17Helper{{.*}}(i32 noundef 0)
975-
// CHECK-NEXT: [[C1:%.*]] = call noundef i32 {{.*}}case17Helper{{.*}}(i32 noundef 1)
976-
// CHECK-NEXT: [[VI:%.*]] = insertelement <2 x i32> poison, i32 [[C]], i32 0
977-
// CHECK-NEXT: [[VI2:%.*]] = insertelement <2 x i32> [[VI]], i32 [[C1]], i32 1
978-
// CHECK-NEXT: store <2 x i32> [[VI2]], ptr [[X]], align 8
979-
// CHECK-NEXT: ret void
976+
// CHECK-LABEL: define hidden void @_Z6case17v(
977+
// CHECK-SAME: ) #[[ATTR0]] {
978+
// CHECK-NEXT: [[ENTRY:.*:]]
979+
// CHECK-NEXT: [[X:%.*]] = alloca <2 x i32>, align 8
980+
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z12case17Helperi(i32 noundef 0) #[[ATTR2]]
981+
// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z12case17Helperi(i32 noundef 1) #[[ATTR2]]
982+
// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <2 x i32> poison, i32 [[CALL]], i32 0
983+
// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <2 x i32> [[VECINIT]], i32 [[CALL1]], i32 1
984+
// CHECK-NEXT: store <2 x i32> [[VECINIT2]], ptr [[X]], align 8
985+
// CHECK-NEXT: ret void
986+
//
980987
void case17() {
981988
int2 X = {case17Helper(0), case17Helper(1)};
982989
}
983990

984991
// InitList with Struct with unnamed bitfield on LHS
985-
// CHECK-LABEL: case18
986-
// CHECK: [[U:%.*]] = alloca %struct.Unnamed, align 1
987-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[U]], ptr align 1 {{.*}}, i32 5, i1 false)
992+
// CHECK-LABEL: define hidden void @_Z6case18v(
993+
// CHECK-SAME: ) #[[ATTR0]] {
994+
// CHECK-NEXT: [[ENTRY:.*:]]
995+
// CHECK-NEXT: [[U:%.*]] = alloca [[STRUCT_UNNAMED:%.*]], align 1
996+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[U]], ptr align 1 @__const._Z6case18v.U, i32 5, i1 false)
997+
// CHECK-NEXT: ret void
998+
//
988999
void case18() {
9891000
Unnamed U = {1};
9901001
}
9911002

9921003
// InitList with Struct with unnamed bitfield on RHS
993-
// CHECK-LABEL: case19
994-
// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
995-
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 0
996-
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw %struct.Unnamed, ptr %U, i32 0, i32 0
997-
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[A]], align 1
998-
// CHECK-NEXT: store i32 [[L]], ptr [[Z]], align 1
999-
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 1
1000-
// CHECK-NEXT: store i32 1, ptr [[W]], align 1
1004+
// CHECK-LABEL: define hidden void @_Z6case197Unnamed(
1005+
// CHECK-SAME: ptr noundef byval([[STRUCT_UNNAMED:%.*]]) align 1 [[U:%.*]]) #[[ATTR0]] {
1006+
// CHECK-NEXT: [[ENTRY:.*:]]
1007+
// CHECK-NEXT: [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
1008+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
1009+
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_UNNAMED]], ptr [[U]], i32 0, i32 0
1010+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1
1011+
// CHECK-NEXT: store i32 [[TMP0]], ptr [[Z]], align 1
1012+
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
1013+
// CHECK-NEXT: store i32 1, ptr [[W]], align 1
1014+
// CHECK-NEXT: ret void
1015+
//
10011016
void case19(Unnamed U) {
10021017
TwoInts TI = {U, 1};
10031018
}
10041019

10051020
// InitList with Empty Struct on LHS
1006-
// CHECK-LABEL: case20
1007-
// CHECK: [[E:%.*]] = alloca %struct.Empty, align 1
1008-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[E]], ptr align 1 [[ConstE]], i32 1, i1 false)
1021+
// CHECK-LABEL: define hidden void @_Z6case20v(
1022+
// CHECK-SAME: ) #[[ATTR0]] {
1023+
// CHECK-NEXT: [[ENTRY:.*:]]
1024+
// CHECK-NEXT: [[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1
1025+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[E]], ptr align 1 @__const._Z6case20v.E, i32 1, i1 false)
1026+
// CHECK-NEXT: ret void
1027+
//
10091028
void case20() {
10101029
Empty E = {};
10111030
}
10121031

10131032
// InitList with Empty Struct on RHS
1014-
// CHECK-LABEL: case21
1015-
// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
1016-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %TI, ptr align 1 {{.*}}, i32 8, i1 false)
1033+
// CHECK-LABEL: define hidden void @_Z6case215Empty(
1034+
// CHECK-SAME: ptr noundef byval([[STRUCT_EMPTY:%.*]]) align 1 [[E:%.*]]) #[[ATTR0]] {
1035+
// CHECK-NEXT: [[ENTRY:.*:]]
1036+
// CHECK-NEXT: [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
1037+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI]], ptr align 1 @__const._Z6case215Empty.TI, i32 8, i1 false)
1038+
// CHECK-NEXT: ret void
1039+
//
10171040
void case21(Empty E) {
10181041
TwoInts TI = {E, 1, 2};
10191042
}
10201043

10211044
// InitList with Struct with only unnamed bitfield on LHS
1022-
// CHECK-LABEL: case22
1023-
// CHECK: [[UO:%.*]] = alloca %struct.UnnamedOnly, align 1
1024-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[UO]], ptr align 1 [[ConstUO]], i32 1, i1 false)
1045+
// CHECK-LABEL: define hidden void @_Z6case22v(
1046+
// CHECK-SAME: ) #[[ATTR0]] {
1047+
// CHECK-NEXT: [[ENTRY:.*:]]
1048+
// CHECK-NEXT: [[UO:%.*]] = alloca [[STRUCT_UNNAMEDONLY:%.*]], align 1
1049+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[UO]], ptr align 1 @__const._Z6case22v.UO, i32 1, i1 false)
1050+
// CHECK-NEXT: ret void
1051+
//
10251052
void case22() {
1026-
UnnamedOnly UO = {};
1053+
UnnamedOnly UO = {};
10271054
}
10281055

10291056
// InitList with Struct with only unnamed bitfield on RHS
1030-
// CHECK-LABEL: case23
1031-
// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
1032-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI]], ptr align 1 {{.*}}, i32 8, i1 false)
1057+
// CHECK-LABEL: define hidden void @_Z6case2311UnnamedOnly(
1058+
// CHECK-SAME: ptr noundef byval([[STRUCT_UNNAMEDONLY:%.*]]) align 1 [[UO:%.*]]) #[[ATTR0]] {
1059+
// CHECK-NEXT: [[ENTRY:.*:]]
1060+
// CHECK-NEXT: [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
1061+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI]], ptr align 1 @__const._Z6case2311UnnamedOnly.TI, i32 8, i1 false)
1062+
// CHECK-NEXT: ret void
1063+
//
10331064
void case23(UnnamedOnly UO) {
10341065
TwoInts TI = {UO, 1, 2};
10351066
}
10361067

10371068
// InitList with Derived empty struct on LHS
10381069
// InitList with Derived unnamed bitfield on LHS
1039-
// CHECK-LABEL: case24
1040-
// CHECK: [[ED:%.*]] = alloca %struct.EmptyDerived, align 1
1041-
// CHECK-NEXT: [[UD:%.*]] = alloca %struct.UnnamedDerived, align 1
1042-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %ED, ptr align 1 [[ConstED]], i32 1, i1 false)
1043-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %UD, ptr align 1 [[ConstUD]], i32 1, i1 false)
1070+
// CHECK-LABEL: define hidden void @_Z6case24v(
1071+
// CHECK-SAME: ) #[[ATTR0]] {
1072+
// CHECK-NEXT: [[ENTRY:.*:]]
1073+
// CHECK-NEXT: [[ED:%.*]] = alloca [[STRUCT_EMPTYDERIVED:%.*]], align 1
1074+
// CHECK-NEXT: [[UD:%.*]] = alloca [[STRUCT_UNNAMEDDERIVED:%.*]], align 1
1075+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[ED]], ptr align 1 @__const._Z6case24v.ED, i32 1, i1 false)
1076+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[UD]], ptr align 1 @__const._Z6case24v.UD, i32 1, i1 false)
1077+
// CHECK-NEXT: ret void
1078+
//
10441079
void case24() {
10451080
EmptyDerived ED = {};
10461081
UnnamedDerived UD = {};
10471082
}
10481083

1049-
// CHECK-LABEL: case25
1050-
// CHECK: [[TI1:%.*]] = alloca %struct.TwoInts, align 1
1051-
// CHECK-NEXT: [[TI2:%.*]] = alloca %struct.TwoInts, align 1
1052-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %TI1, ptr align 1 {{.*}}, i32 8, i1 false)
1053-
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %TI2, ptr align 1 {{.*}}, i32 8, i1 false)
1084+
// CHECK-LABEL: define hidden void @_Z6case2512EmptyDerived14UnnamedDerived(
1085+
// CHECK-SAME: ptr noundef byval([[STRUCT_EMPTYDERIVED:%.*]]) align 1 [[ED:%.*]], ptr noundef byval([[STRUCT_UNNAMEDDERIVED:%.*]]) align 1 [[UD:%.*]]) #[[ATTR0]] {
1086+
// CHECK-NEXT: [[ENTRY:.*:]]
1087+
// CHECK-NEXT: [[TI1:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
1088+
// CHECK-NEXT: [[TI2:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
1089+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI1]], ptr align 1 @__const._Z6case2512EmptyDerived14UnnamedDerived.TI1, i32 8, i1 false)
1090+
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI2]], ptr align 1 @__const._Z6case2512EmptyDerived14UnnamedDerived.TI2, i32 8, i1 false)
1091+
// CHECK-NEXT: ret void
1092+
//
10541093
void case25(EmptyDerived ED, UnnamedDerived UD) {
10551094
TwoInts TI1 = {ED, 1, 2};
10561095
TwoInts TI2 = {UD, 1, 2};
10571096
}
1097+
1098+
// CHECK-LABEL: define hidden void @_Z6case267TwoInts(
1099+
// CHECK-SAME: ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 1 [[TI:%.*]]) #[[ATTR0]] {
1100+
// CHECK-NEXT: [[ENTRY:.*:]]
1101+
// CHECK-NEXT: [[F:%.*]] = alloca <4 x float>, align 16
1102+
// CHECK-NEXT: [[F2:%.*]] = alloca <3 x float>, align 16
1103+
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
1104+
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[Z]], align 1
1105+
// CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[TMP0]] to float
1106+
// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x float> poison, float [[CONV]], i32 0
1107+
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
1108+
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[W]], align 1
1109+
// CHECK-NEXT: [[CONV1:%.*]] = sitofp i32 [[TMP1]] to float
1110+
// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x float> [[VECINIT]], float [[CONV1]], i32 1
1111+
// CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x float> [[VECINIT2]], float 1.000000e+00, i32 2
1112+
// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x float> [[VECINIT3]], float 2.000000e+00, i32 3
1113+
// CHECK-NEXT: store <4 x float> [[VECINIT4]], ptr [[F]], align 16
1114+
// CHECK-NEXT: [[Z5:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
1115+
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[Z5]], align 1
1116+
// CHECK-NEXT: [[CONV6:%.*]] = sitofp i32 [[TMP2]] to float
1117+
// CHECK-NEXT: [[VECINIT7:%.*]] = insertelement <3 x float> <float 3.000000e+00, float poison, float poison>, float [[CONV6]], i32 1
1118+
// CHECK-NEXT: [[W8:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
1119+
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[W8]], align 1
1120+
// CHECK-NEXT: [[CONV9:%.*]] = sitofp i32 [[TMP3]] to float
1121+
// CHECK-NEXT: [[VECINIT10:%.*]] = insertelement <3 x float> [[VECINIT7]], float [[CONV9]], i32 2
1122+
// CHECK-NEXT: store <3 x float> [[VECINIT10]], ptr [[F2]], align 16
1123+
// CHECK-NEXT: ret void
1124+
//
1125+
void case26(TwoInts TI) {
1126+
float4 F = float4(TI, 1, 2);
1127+
float3 F2 = float3(3, TI);
1128+
}
1129+
//.
1130+
// CHECK: [[META3]] = !{}
1131+
// CHECK: [[META4]] = !{i64 4}
1132+
//.

0 commit comments

Comments
 (0)