Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -1126,6 +1126,9 @@ class InitializationSequence {

// A designated initializer was provided for a non-aggregate type.
FK_DesignatedInitForNonAggregate,

/// HLSL intialization list flattening failed.
FK_HLSLInitListFlatteningFailed,
};

private:
Expand Down
48 changes: 24 additions & 24 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3920,6 +3920,7 @@ bool InitializationSequence::isAmbiguous() const {
case FK_AddressOfUnaddressableFunction:
case FK_ParenthesizedListInitFailed:
case FK_DesignatedInitForNonAggregate:
case FK_HLSLInitListFlatteningFailed:
return false;

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

if (S.getLangOpts().HLSL && !S.HLSL().transformInitList(Entity, InitList))
if (S.getLangOpts().HLSL && !S.HLSL().transformInitList(Entity, InitList)) {
Sequence.SetFailed(InitializationSequence::FK_HLSLInitListFlatteningFailed);
return;
}

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

// For HLSL ext vector types we allow list initialization behavior for C++
// constructor syntax. This is accomplished by converting initialization
// arguments an InitListExpr late.
// functional cast expressions which look like constructor syntax. This is
// accomplished by converting initialization arguments to InitListExpr.
if (S.getLangOpts().HLSL && Args.size() > 1 && DestType->isExtVectorType() &&
(SourceType.isNull() ||
!Context.hasSameUnqualifiedType(SourceType, DestType))) {

llvm::SmallVector<Expr *> InitArgs;
for (auto *Arg : Args) {
if (Arg->getType()->isExtVectorType()) {
const auto *VTy = Arg->getType()->castAs<ExtVectorType>();
unsigned Elm = VTy->getNumElements();
for (unsigned Idx = 0; Idx < Elm; ++Idx) {
InitArgs.emplace_back(new (Context) ArraySubscriptExpr(
Arg,
IntegerLiteral::Create(
Context, llvm::APInt(Context.getIntWidth(Context.IntTy), Idx),
Context.IntTy, SourceLocation()),
VTy->getElementType(), Arg->getValueKind(), Arg->getObjectKind(),
SourceLocation()));
}
} else
InitArgs.emplace_back(Arg);
}
InitListExpr *ILE = new (Context) InitListExpr(
S.getASTContext(), SourceLocation(), InitArgs, SourceLocation());
InitListExpr *ILE = new (Context)
InitListExpr(S.getASTContext(), Args.front()->getBeginLoc(), Args,
Args.back()->getEndLoc());
ILE->setType(DestType);
Args[0] = ILE;
AddListInitializationStep(DestType);
TryListInitialization(S, Entity, Kind, ILE, *this,
TreatUnavailableAsInvalid);
return;
}

Expand Down Expand Up @@ -9302,6 +9290,14 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}

case InitializationSequence::FK_HLSLInitListFlatteningFailed: {
// Unlike C/C++ list initialization, there is no fallback if it fails. This
// allows us to diagnose the failure when it happens in the
// TryListInitialization call instead of delaying the diagnosis, which is
// beneficial because the flattening is also expensive.
break;
}

case FK_ExplicitConstructor: {
S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor)
<< Args[0]->getSourceRange();
Expand Down Expand Up @@ -9500,6 +9496,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
case FK_DesignatedInitForNonAggregate:
OS << "designated initializer for non-aggregate type";
break;

case FK_HLSLInitListFlatteningFailed:
OS << "HLSL initialization list flattening failed";
break;
}
OS << '\n';
return;
Expand Down
25 changes: 3 additions & 22 deletions clang/test/AST/HLSL/vector-constructors.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ void entry() {
// parameters to an initialization list
// CHECK-LABEL: VarDecl {{.*}} used Vec2 'float2':'vector<float, 2>' cinit
// CHECK-NEXT: CXXFunctionalCastExpr {{.*}} 'float2':'vector<float, 2>' functional cast to float2 <NoOp>
// CHECK-NEXT: InitListExpr {{.*}} 'float2':'vector<float, 2>'
// CHECK-NEXT: InitListExpr {{0x[0-9a-fA-F]+}} <col:{{[0-9]+}}, col:{{[0-9]+}}> 'float2':'vector<float, 2>'
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00

Expand All @@ -28,11 +28,11 @@ void entry() {
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue
// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'Vec2' 'float2':'vector<float, 2>'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue
// CHECK-NEXT: DeclRefExpr {{.*}} 'float2':'vector<float, 2>' lvalue Var {{.*}} 'Vec2' 'float2':'vector<float, 2>'
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 1
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00

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

struct T {
operator float() const { return 1.0f; }
} t;
float2 foo5 = float2(t, t); // user-defined cast operator

// CHECK-LABEL: VarDecl {{.*}} foo5 'float2'
// CHECK-NEXT: CXXFunctionalCastExpr
// CHECK-NEXT: InitListExpr
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float'
// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator float {{.*}}
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const T' lvalue <NoOp>
// CHECK-NEXT: DeclRefExpr {{.*}} 'struct T' lvalue Var {{.*}} 't' 'struct T'
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <UserDefinedConversion>
// CHECK-NEXT: CXXMemberCallExpr {{.*}} 'float'
// CHECK-NEXT: MemberExpr {{.*}} '<bound member function type>' .operator float {{.*}}
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'const T' lvalue <NoOp>
// CHECK-NEXT: DeclRefExpr {{.*}} 'struct T' lvalue Var {{.*}} 't' 'struct T'

typedef float2 second_level_of_typedefs;
second_level_of_typedefs foo6 = float2(1.0f, 2.0f);

Expand Down
173 changes: 124 additions & 49 deletions clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ struct EmptyDerived : Empty {};

struct UnnamedDerived : UnnamedOnly {};

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

// Case 1: Extraneous braces get ignored in literal instantiation.
// CHECK-LABEL: define hidden void @_Z5case1v(
Expand Down Expand Up @@ -911,15 +907,15 @@ TwoFloats case15(SlicyBits SB) {
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca ptr, align 4
// CHECK-NEXT: store ptr [[X]], ptr [[X_ADDR]], align 4
// CHECK-NEXT: [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[X_ADDR]], align 4, !nonnull [[META3:![0-9]+]], !align [[META4:![0-9]+]]
// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[TMP0]], align 4
// CHECK-NEXT: store float [[TMP1]], ptr [[X1]], align 1
// CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[X_ADDR]], align 4
// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[X_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[TMP2]], align 4
// CHECK-NEXT: [[MUL:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP3]], 1.500000e+00
// CHECK-NEXT: store float [[MUL]], ptr [[Y]], align 1
// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[X_ADDR]], align 4
// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[X_ADDR]], align 4, !nonnull [[META3]], !align [[META4]]
// CHECK-NEXT: [[TMP5:%.*]] = load float, ptr [[TMP4]], align 4
// CHECK-NEXT: [[MUL2:%.*]] = fmul reassoc nnan ninf nsz arcp afn float [[TMP5]], 2.000000e+00
// CHECK-NEXT: store float [[MUL2]], ptr [[TMP4]], align 4
Expand Down Expand Up @@ -964,94 +960,173 @@ FourFloats case16() {
}


// CHECK-LABEL: define hidden noundef i32 @_Z12case17Helperi(
// CHECK-SAME: i32 noundef [[X:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[X]], ptr [[X_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
// CHECK-NEXT: ret i32 [[TMP0]]
//
int case17Helper(int x) {
return x;
}

// InitList with OpaqueValueExpr
// CHECK-LABEL: define hidden void {{.*}}case17
// CHECK: [[X:%.*]] = alloca <2 x i32>, align 8
// CHECK-NEXT: [[C:%.*]] = call noundef i32 {{.*}}case17Helper{{.*}}(i32 noundef 0)
// CHECK-NEXT: [[C1:%.*]] = call noundef i32 {{.*}}case17Helper{{.*}}(i32 noundef 1)
// CHECK-NEXT: [[VI:%.*]] = insertelement <2 x i32> poison, i32 [[C]], i32 0
// CHECK-NEXT: [[VI2:%.*]] = insertelement <2 x i32> [[VI]], i32 [[C1]], i32 1
// CHECK-NEXT: store <2 x i32> [[VI2]], ptr [[X]], align 8
// CHECK-NEXT: ret void
// CHECK-LABEL: define hidden void @_Z6case17v(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[X:%.*]] = alloca <2 x i32>, align 8
// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z12case17Helperi(i32 noundef 0) #[[ATTR2]]
// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z12case17Helperi(i32 noundef 1) #[[ATTR2]]
// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <2 x i32> poison, i32 [[CALL]], i32 0
// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <2 x i32> [[VECINIT]], i32 [[CALL1]], i32 1
// CHECK-NEXT: store <2 x i32> [[VECINIT2]], ptr [[X]], align 8
// CHECK-NEXT: ret void
//
void case17() {
int2 X = {case17Helper(0), case17Helper(1)};
}

// InitList with Struct with unnamed bitfield on LHS
// CHECK-LABEL: case18
// CHECK: [[U:%.*]] = alloca %struct.Unnamed, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[U]], ptr align 1 {{.*}}, i32 5, i1 false)
// CHECK-LABEL: define hidden void @_Z6case18v(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[U:%.*]] = alloca [[STRUCT_UNNAMED:%.*]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[U]], ptr align 1 @__const._Z6case18v.U, i32 5, i1 false)
// CHECK-NEXT: ret void
//
void case18() {
Unnamed U = {1};
}

// InitList with Struct with unnamed bitfield on RHS
// CHECK-LABEL: case19
// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 0
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw %struct.Unnamed, ptr %U, i32 0, i32 0
// CHECK-NEXT: [[L:%.*]] = load i32, ptr [[A]], align 1
// CHECK-NEXT: store i32 [[L]], ptr [[Z]], align 1
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 1
// CHECK-NEXT: store i32 1, ptr [[W]], align 1
// CHECK-LABEL: define hidden void @_Z6case197Unnamed(
// CHECK-SAME: ptr noundef byval([[STRUCT_UNNAMED:%.*]]) align 1 [[U:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
// CHECK-NEXT: [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_UNNAMED]], ptr [[U]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 1
// CHECK-NEXT: store i32 [[TMP0]], ptr [[Z]], align 1
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
// CHECK-NEXT: store i32 1, ptr [[W]], align 1
// CHECK-NEXT: ret void
//
void case19(Unnamed U) {
TwoInts TI = {U, 1};
}

// InitList with Empty Struct on LHS
// CHECK-LABEL: case20
// CHECK: [[E:%.*]] = alloca %struct.Empty, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[E]], ptr align 1 [[ConstE]], i32 1, i1 false)
// CHECK-LABEL: define hidden void @_Z6case20v(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[E:%.*]] = alloca [[STRUCT_EMPTY:%.*]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[E]], ptr align 1 @__const._Z6case20v.E, i32 1, i1 false)
// CHECK-NEXT: ret void
//
void case20() {
Empty E = {};
}

// InitList with Empty Struct on RHS
// CHECK-LABEL: case21
// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %TI, ptr align 1 {{.*}}, i32 8, i1 false)
// CHECK-LABEL: define hidden void @_Z6case215Empty(
// CHECK-SAME: ptr noundef byval([[STRUCT_EMPTY:%.*]]) align 1 [[E:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI]], ptr align 1 @__const._Z6case215Empty.TI, i32 8, i1 false)
// CHECK-NEXT: ret void
//
void case21(Empty E) {
TwoInts TI = {E, 1, 2};
}

// InitList with Struct with only unnamed bitfield on LHS
// CHECK-LABEL: case22
// CHECK: [[UO:%.*]] = alloca %struct.UnnamedOnly, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[UO]], ptr align 1 [[ConstUO]], i32 1, i1 false)
// CHECK-LABEL: define hidden void @_Z6case22v(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[UO:%.*]] = alloca [[STRUCT_UNNAMEDONLY:%.*]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[UO]], ptr align 1 @__const._Z6case22v.UO, i32 1, i1 false)
// CHECK-NEXT: ret void
//
void case22() {
UnnamedOnly UO = {};
UnnamedOnly UO = {};
}

// InitList with Struct with only unnamed bitfield on RHS
// CHECK-LABEL: case23
// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI]], ptr align 1 {{.*}}, i32 8, i1 false)
// CHECK-LABEL: define hidden void @_Z6case2311UnnamedOnly(
// CHECK-SAME: ptr noundef byval([[STRUCT_UNNAMEDONLY:%.*]]) align 1 [[UO:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI]], ptr align 1 @__const._Z6case2311UnnamedOnly.TI, i32 8, i1 false)
// CHECK-NEXT: ret void
//
void case23(UnnamedOnly UO) {
TwoInts TI = {UO, 1, 2};
}

// InitList with Derived empty struct on LHS
// InitList with Derived unnamed bitfield on LHS
// CHECK-LABEL: case24
// CHECK: [[ED:%.*]] = alloca %struct.EmptyDerived, align 1
// CHECK-NEXT: [[UD:%.*]] = alloca %struct.UnnamedDerived, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %ED, ptr align 1 [[ConstED]], i32 1, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %UD, ptr align 1 [[ConstUD]], i32 1, i1 false)
// CHECK-LABEL: define hidden void @_Z6case24v(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[ED:%.*]] = alloca [[STRUCT_EMPTYDERIVED:%.*]], align 1
// CHECK-NEXT: [[UD:%.*]] = alloca [[STRUCT_UNNAMEDDERIVED:%.*]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[ED]], ptr align 1 @__const._Z6case24v.ED, i32 1, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[UD]], ptr align 1 @__const._Z6case24v.UD, i32 1, i1 false)
// CHECK-NEXT: ret void
//
void case24() {
EmptyDerived ED = {};
UnnamedDerived UD = {};
}

// CHECK-LABEL: case25
// CHECK: [[TI1:%.*]] = alloca %struct.TwoInts, align 1
// CHECK-NEXT: [[TI2:%.*]] = alloca %struct.TwoInts, align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %TI1, ptr align 1 {{.*}}, i32 8, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 %TI2, ptr align 1 {{.*}}, i32 8, i1 false)
// CHECK-LABEL: define hidden void @_Z6case2512EmptyDerived14UnnamedDerived(
// CHECK-SAME: ptr noundef byval([[STRUCT_EMPTYDERIVED:%.*]]) align 1 [[ED:%.*]], ptr noundef byval([[STRUCT_UNNAMEDDERIVED:%.*]]) align 1 [[UD:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[TI1:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
// CHECK-NEXT: [[TI2:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI1]], ptr align 1 @__const._Z6case2512EmptyDerived14UnnamedDerived.TI1, i32 8, i1 false)
// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[TI2]], ptr align 1 @__const._Z6case2512EmptyDerived14UnnamedDerived.TI2, i32 8, i1 false)
// CHECK-NEXT: ret void
//
void case25(EmptyDerived ED, UnnamedDerived UD) {
TwoInts TI1 = {ED, 1, 2};
TwoInts TI2 = {UD, 1, 2};
}

// CHECK-LABEL: define hidden void @_Z6case267TwoInts(
// CHECK-SAME: ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 1 [[TI:%.*]]) #[[ATTR0]] {
// CHECK-NEXT: [[ENTRY:.*:]]
// CHECK-NEXT: [[F:%.*]] = alloca <4 x float>, align 16
// CHECK-NEXT: [[F2:%.*]] = alloca <3 x float>, align 16
// CHECK-NEXT: [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[Z]], align 1
// CHECK-NEXT: [[CONV:%.*]] = sitofp i32 [[TMP0]] to float
// CHECK-NEXT: [[VECINIT:%.*]] = insertelement <4 x float> poison, float [[CONV]], i32 0
// CHECK-NEXT: [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[W]], align 1
// CHECK-NEXT: [[CONV1:%.*]] = sitofp i32 [[TMP1]] to float
// CHECK-NEXT: [[VECINIT2:%.*]] = insertelement <4 x float> [[VECINIT]], float [[CONV1]], i32 1
// CHECK-NEXT: [[VECINIT3:%.*]] = insertelement <4 x float> [[VECINIT2]], float 1.000000e+00, i32 2
// CHECK-NEXT: [[VECINIT4:%.*]] = insertelement <4 x float> [[VECINIT3]], float 2.000000e+00, i32 3
// CHECK-NEXT: store <4 x float> [[VECINIT4]], ptr [[F]], align 16
// CHECK-NEXT: [[Z5:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[Z5]], align 1
// CHECK-NEXT: [[CONV6:%.*]] = sitofp i32 [[TMP2]] to float
// CHECK-NEXT: [[VECINIT7:%.*]] = insertelement <3 x float> <float 3.000000e+00, float poison, float poison>, float [[CONV6]], i32 1
// CHECK-NEXT: [[W8:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[W8]], align 1
// CHECK-NEXT: [[CONV9:%.*]] = sitofp i32 [[TMP3]] to float
// CHECK-NEXT: [[VECINIT10:%.*]] = insertelement <3 x float> [[VECINIT7]], float [[CONV9]], i32 2
// CHECK-NEXT: store <3 x float> [[VECINIT10]], ptr [[F2]], align 16
// CHECK-NEXT: ret void
//
void case26(TwoInts TI) {
float4 F = float4(TI, 1, 2);
float3 F2 = float3(3, TI);
}
//.
// CHECK: [[META3]] = !{}
// CHECK: [[META4]] = !{i64 4}
//.
Loading