[clang] [HLSL] Create XValue in HLSL list initialization if record is a prvalue (PR #186233)

Sarah Spall via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 26 10:57:14 PDT 2026


https://github.com/spall updated https://github.com/llvm/llvm-project/pull/186233

>From 77b2990f3e344c5573977c6ff4d0f9b8e8657040 Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Wed, 11 Mar 2026 15:51:35 -0700
Subject: [PATCH 1/4] create an xvalue + add tests

---
 clang/lib/Sema/SemaHLSL.cpp                   |   5 +
 .../CodeGenHLSL/BasicFeatures/InitLists.hlsl  | 151 ++++++++++++++++++
 clang/test/SemaHLSL/Language/InitListAST.hlsl | 117 ++++++++++++++
 3 files changed, 273 insertions(+)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index e200c595ab2c2..2224fad94a26a 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -5317,6 +5317,11 @@ class InitListTransformer {
     if (auto *RD = Ty->getAsCXXRecordDecl()) {
       llvm::SmallVector<CXXRecordDecl *> RecordDecls;
       RecordDecls.push_back(RD);
+      // if this is a pr value create an xvalue so the member accesses
+      // will be xvalues
+      if (E->isPRValue())
+        E = new (Ctx)
+            MaterializeTemporaryExpr(Ty, E, /*BoundToLvalueReference=*/false);
       while (RecordDecls.back()->getNumBases()) {
         CXXRecordDecl *D = RecordDecls.back();
         assert(D->getNumBases() == 1 &&
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
index 82ed7545cfdc5..5f2d870e8312a 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -1126,6 +1126,157 @@ void case26(TwoInts TI) {
   float4 F = float4(TI, 1, 2);
   float3 F2 = float3(3, TI);
 }
+
+// Check cases with explicit casts
+
+// CHECK-LABEL: define hidden void @_Z6case279TwoFloats(ptr noundef byval(%struct.TwoFloats) align 1 %TF)
+// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
+// CHECK: [[RT:%.*]] = alloca %struct.TwoInts, align 1
+// CHECK: [[AT:%.*]] = alloca %struct.TwoFloats, align 1
+// CHECK: [[RT6:%.*]] = alloca %struct.TwoInts, align 1
+// CHECK: [[AT7:%.*]] = alloca %struct.TwoFloats, align 1
+// CHECK: [[Z:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 0
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT]], ptr align 1 %TF, i32 8, i1 false)
+// CHECK: [[G:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 0
+// CHECK: [[G1:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 1
+// CHECK: [[G2:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT]], i32 0, i32 0
+// CHECK: [[G3:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT]], i32 0, i32 1
+// CHECK: [[Zero:%.*]] = load float, ptr [[G2]], align 4
+// CHECK: [[Conv:%.*]] = fptosi float [[Zero]] to i32
+// CHECK: store i32 [[Conv]], ptr [[G]], align 4
+// CHECK: [[One:%.*]] = load float, ptr [[G3]], align 4
+// CHECK: [[Conv4:%.*]] = fptosi float [[One]] to i32
+// CHECK: store i32 [[Conv4]], ptr [[G1]], align 4
+// CHECK: [[Z5:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT]], i32 0, i32 0
+// CHECK: [[Two:%.*]] = load i32, ptr [[Z5]], align 1
+// CHECK: store i32 [[Two]], ptr [[Z]], align 1
+// CHECK: [[W:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 1
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT7]], ptr align 1 %TF, i32 8, i1 false)
+// CHECK: [[G8:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT6]], i32 0, i32 0
+// CHECK: [[G9:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT6]], i32 0, i32 1
+// CHECK: [[G10:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT7]], i32 0, i32 0
+// CHECK: [[G11:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT7]], i32 0, i32 1
+// CHECK: [[Tre:%.*]] = load float, ptr [[G10]], align 4
+// CHECK: [[Conv12:%.*]] = fptosi float [[Tre]] to i32
+// CHECK: store i32 [[Conv12]], ptr [[G8]], align 4
+// CHECK: [[Four:%.*]] = load float, ptr [[G11]], align 4
+// CHECK: [[Conv13:%.*]] = fptosi float [[Four]] to i32
+// CHECK: store i32 [[Conv13]], ptr [[G9]], align 4
+// CHECK: [[W14:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT6]], i32 0, i32 1
+// CHECK: [[Five:%.*]] = load i32, ptr [[W14]], align 1
+// CHECK: store i32 [[Five]], ptr [[W]], align 1
+// CHECK: ret void
+void case27(TwoFloats TF) {
+  TwoInts TI = {(TwoInts)TF};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case2810FourFloats(ptr noundef byval(%struct.FourFloats) align 1 %FF)
+// CHECK: [[Ints:%.*]] = alloca [2 x i32], align 4
+// CHECK: [[RT:%.*]] = alloca [2 x i32], align 4
+// CHECK: [[AT:%.*]] = alloca %struct.FourFloats, align 1
+// CHECK: [[RT7:%.*]] = alloca [2 x i32], align 4
+// CHECK: [[AT8:%.*]] = alloca %struct.FourFloats, align 1
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT]], ptr align 1 %FF, i32 16, i1 false)
+// CHECK: [[G:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT]], i32 0, i32 0
+// CHECK: [[G1:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT]], i32 0, i32 1
+// CHECK: [[G2:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 0, i32 0
+// CHECK: [[G3:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 0, i32 1
+// CHECK: [[G4:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 1
+// CHECK: [[G5:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 2
+// CHECK: [[Zero:%.*]] = load float, ptr [[G2]], align 4
+// CHECK: [[Conv:%.*]] = fptosi float [[Zero]] to i32
+// CHECK: store i32 [[Conv]], ptr [[G]], align 4
+// CHECK: [[One:%.*]] = load float, ptr [[G3]], align 4
+// CHECK: [[Conv6:%.*]] = fptosi float [[One]] to i32
+// CHECK: store i32 [[Conv6]], ptr [[G1]], align 4
+// CHECK: [[ArrIdx:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[RT]], i32 0, i32 0
+// CHECK: [[Two:%.*]] = load i32, ptr [[ArrIdx]], align 4
+// CHECK: store i32 [[Two]], ptr [[Ints]], align 4
+// CHECK: [[ArrInitEl:%.*]] = getelementptr inbounds i32, ptr [[Ints]], i32 1
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT8]], ptr align 1 %FF, i32 16, i1 false)
+// CHECK: [[G9:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT7]], i32 0, i32 0
+// CHECK: [[G10:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT7]], i32 0, i32 1
+// CHECK: [[G11:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 0, i32 0
+// CHECK: [[G12:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 0, i32 1
+// CHECK: [[G13:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 1
+// CHECK: [[G14:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 2
+// CHECK: [[Tre:%.*]] = load float, ptr [[G11]], align 4
+// CHECK: [[Conv15:%.*]] = fptosi float [[Tre]] to i32
+// CHECK: store i32 [[Conv15]], ptr [[G9]], align 4
+// CHECK: [[Four:%.*]] = load float, ptr [[G12]], align 4
+// CHECK: [[Conv16:%.*]] = fptosi float [[Four]] to i32
+// CHECK: store i32 [[Conv16]], ptr [[G10]], align 4
+// CHECK: [[ArrIdx17:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[RT7]], i32 0, i32 1
+// CHECK: [[Five:%.*]] = load i32, ptr [[ArrIdx17]], align 4
+// CHECK: store i32 [[Five]], ptr [[ArrInitEl]], align 4
+// CHECK: ret void
+void case28(FourFloats FF) {
+  int Ints[2] = {(int[2])FF};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case29v()
+// CHECK: [[Arr:%.*]] = alloca [4 x float], align 4
+// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
+// CHECK: [[RT:%.*]] = alloca %struct.TwoInts, align 1
+// CHECK: [[AT:%.*]] = alloca [4 x float], align 4
+// CHECK: [[RT8:%.*]] = alloca %struct.TwoInts, align 1
+// CHECK: [[AT9:%.*]] = alloca [4 x float], align 4
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{.*}}, i32 16, i1 false)
+// CHECK: [[Z:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 0
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AT]], ptr align 4 [[Arr]], i32 16, i1 false)
+// CHECK: [[G:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 0
+// CHECK: [[G1:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 1
+// CHECK: [[G2:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 0
+// CHECK: [[G3:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 1
+// CHECK: [[G4:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 2
+// CHECK: [[G5:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 3
+// CHECK: [[Zero:%.*]] = load float, ptr [[G2]], align 4
+// CHECK: [[Conv:%.*]] = fptosi float [[Zero]] to i32
+// CHECK: store i32 [[Conv]], ptr [[G]], align 4
+// CHECK: [[One:%.*]] = load float, ptr [[G3]], align 4
+// CHECK: [[Conv6:%.*]] = fptosi float [[One]] to i32
+// CHECK: store i32 [[Conv6]], ptr [[G1]], align 4
+// CHECK: [[Z7:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT]], i32 0, i32 0
+// CHECK: [[Two:%.*]] = load i32, ptr [[Z7]], align 1
+// CHECK: store i32 [[Two]], ptr [[Z]], align 1
+// CHECK: [[W:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 1
+// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AT9]], ptr align 4 [[Arr]], i32 16, i1 false)
+// CHECK: [[G10:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT8]], i32 0, i32 0
+// CHECK: [[G11:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT8]], i32 0, i32 1
+// CHECK: [[G12:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 0
+// CHECK: [[G13:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 1
+// CHECK: [[G14:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 2
+// CHECK: [[G15:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 3
+// CHECK: [[Tre:%.*]] = load float, ptr [[G12]], align 4
+// CHECK: [[Conv16:%.*]] = fptosi float [[Tre]] to i32
+// CHECK: store i32 [[Conv16]], ptr [[G10]], align 4
+// CHECK: [[Four:%.*]] = load float, ptr [[G13]], align 4
+// CHECK: [[Conv17:%.*]] = fptosi float [[Four]] to i32
+// CHECK: store i32 [[Conv17]], ptr [[G11]], align 4
+// CHECK: [[W18:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT8]], i32 0, i32 1
+// CHECK: [[Five:%.*]] = load i32, ptr [[W18]], align 1
+// CHECK: store i32 [[Five]], ptr [[W]], align 1
+// CHECK: ret void
+void case29() {
+  float Arr[4] = {1.0,2.0,3.0,4.0};
+  TwoInts TI = {(TwoInts)Arr};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case30v()
+// CHECK: [[F:%.*]] = alloca float, align 4
+// CHECK: [[SB:%.*]] = alloca %struct.SlicyBits, align 1
+// CHECK: store float 1.000000e+00, ptr [[F]], align 4
+// CHECK: [[A:%.*]] = load float, ptr [[F]], align 4
+// CHECK: [[Conv:%.*]] = fptosi float [[A]] to i32
+// CHECK: [[B:%.*]] = trunc i32 [[Conv]] to i8
+// CHECK: store i8 [[B]], ptr [[SB]], align 1
+// CHECK: [[W:%.*]] = getelementptr inbounds nuw %struct.SlicyBits, ptr [[SB]], i32 0, i32 1
+// CHECK: store i8 2, ptr [[W]], align 1
+// CHECK: ret void
+void case30() {
+  float F = 1.0;
+  SlicyBits SB = {(int)F, 2};
+}
 //.
 // CHECK: [[META3]] = !{}
 // CHECK: [[META4]] = !{i64 4}
diff --git a/clang/test/SemaHLSL/Language/InitListAST.hlsl b/clang/test/SemaHLSL/Language/InitListAST.hlsl
index 460ec38bb44af..63e6af61b124a 100644
--- a/clang/test/SemaHLSL/Language/InitListAST.hlsl
+++ b/clang/test/SemaHLSL/Language/InitListAST.hlsl
@@ -1059,3 +1059,120 @@ float case17() {
   float Floats[] = {Structs, Structs};
   return Floats[7];
 }
+
+// Tests which use explicit casts
+
+// CHECK-LABEL: Dumping case18
+// CHECK: VarDecl {{.*}} used TF 'TwoFloats' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used TI 'TwoInts' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .Z
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue Var {{.*}} 'TF' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .W
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue Var {{.*}} 'TF' 'TwoFloats'
+int case18() {
+  TwoFloats TF = {1.0,2.0};
+  TwoInts TI = {(TwoInts)TF};
+  return TI.Z;
+}
+
+// CHECK-LABEL: Dumping case19
+// CHECK: VarDecl {{.*}} used FF 'FourFloats' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used Ints 'int[4]' cinit
+// CHECK-NEXT: ExprWithCleanups {{.*}} 'int[4]'
+// CHECK-NEXT: InitListExpr {{.*}} 'int[4]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' xvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'int[4]' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int[4]' <HLSLElementwiseCast>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'FourFloats' lvalue Var {{.*}} 'FF' 'FourFloats'
+// CHECK-NEXT: IntegerLiteral {{.*}} '__size_t':'unsigned long' 3
+int case19() {
+  FourFloats FF = {1.0,2.0,3.0,4.0};
+  int Ints[4] = {(int[4])FF};
+  return Ints[0];
+}
+
+// CHECK-LABEL: Dumping case20
+// CHECK: VarDecl {{.*}} used Arr 'float[4]' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'float[4]'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 2.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 3.000000e+00
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 4.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used TI 'TwoInts' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .Z
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[4]' <HLSLArrayRValue> part_of_explicit_cast
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float[4]' lvalue Var {{.*}} 'Arr' 'float[4]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' xvalue .W
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoInts' xvalue
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'TwoInts' <HLSLElementwiseCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float[4]' <HLSLArrayRValue> part_of_explicit_cast
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float[4]' lvalue Var {{.*}} 'Arr' 'float[4]'
+int case20() {
+  float Arr[4] = {1.0,2.0,3.0,4.0};
+  TwoInts TI = {(TwoInts)Arr};
+  return TI.Z;
+}
+
+// CHECK-LABEL: Dumping case21
+// CHECK: VarDecl {{.*}} used F 'float' cinit
+// CHECK-NEXT: {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} used SB 'SlicyBits' cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'SlicyBits'
+// CHECK-NEXT: CStyleCastExpr {{.*}} 'int' <NoOp>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <FloatingToIntegral> part_of_explicit_cast
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue> part_of_explicit_cast
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue Var {{.*}} 'F' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+int case21() {
+  float F = 1.0;
+  SlicyBits SB = {(int)F, 2};
+  return SB.Z;
+}

>From 30eb67d9ac7dad9d4f11871280be7329916f6eb3 Mon Sep 17 00:00:00 2001
From: Sarah Spall <spall at planetbauer.com>
Date: Mon, 16 Mar 2026 11:29:30 -0700
Subject: [PATCH 2/4] Update clang/lib/Sema/SemaHLSL.cpp

Co-authored-by: Deric C. <cheung.deric at gmail.com>
---
 clang/lib/Sema/SemaHLSL.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2224fad94a26a..264e9c9bb2dd2 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -5317,8 +5317,8 @@ class InitListTransformer {
     if (auto *RD = Ty->getAsCXXRecordDecl()) {
       llvm::SmallVector<CXXRecordDecl *> RecordDecls;
       RecordDecls.push_back(RD);
-      // if this is a pr value create an xvalue so the member accesses
-      // will be xvalues
+      // If this is a prvalue create an xvalue so the member accesses
+      // will be xvalues.
       if (E->isPRValue())
         E = new (Ctx)
             MaterializeTemporaryExpr(Ty, E, /*BoundToLvalueReference=*/false);

>From 99d1d4851e753895f18907f3051cfb4209fe00a2 Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Wed, 25 Mar 2026 12:48:07 -0700
Subject: [PATCH 3/4] add XFAIL test showing assertion hit in ExprConstant.cpp
 with transformInitList usage of MaterializeTemporaryExpr

---
 .../SemaHLSL/Types/InitListConstantExpr.hlsl  | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl

diff --git a/clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl b/clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl
new file mode 100644
index 0000000000000..c2797f5c8d94e
--- /dev/null
+++ b/clang/test/SemaHLSL/Types/InitListConstantExpr.hlsl
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.6-library -finclude-default-header -fnative-half-type -fnative-int16-type -std=hlsl202x -verify %s
+
+// expected-no-diagnostics
+// XFAIL because of this issue: https://github.com/llvm/llvm-project/issues/188577
+// These tests hit an assert.
+// XFAIL: *
+
+struct Base {
+  double D;
+  uint64_t2 U;
+  int16_t I : 5;
+  uint16_t I2: 5;
+};
+
+struct B1 {
+  float A;
+  float B;
+};
+
+struct B2 : B1 {
+  int C;
+  int D;
+  bool BB;
+};
+
+export void fn() {
+
+  // splat from a vector of size 1 in an init list
+  constexpr int1 A1 = {1};
+  constexpr uint64_t2 A72[2] = {(uint64_t2[2])A1};
+  _Static_assert(A72[0][0] == 1, "Woo!");
+  _Static_assert(A72[0][1] == 1, "Woo!");
+  _Static_assert(A72[1][0] == 1, "Woo!");
+  _Static_assert(A72[1][1] == 1, "Woo!");
+
+  // splat from a scalar inside an init list
+  constexpr double D = 97.6789;
+  constexpr B1 SB0 = {(B1)(D + 3.0)};
+  _Static_assert(SB0.A == 100.6789, "Woo!");
+  _Static_assert(SB0.B == 100.6789, "Woo!");
+
+  // result type struct from struct in an init list
+  constexpr B2 SB2 = {5.5, 6.5, 1000, 5000, false};
+  constexpr Base SB3 = {(Base)SB2};
+  _Static_assert(SB3.D == 5.5, "Woo!");
+  _Static_assert(SB3.U[0] == 6, "Woo!");
+  _Static_assert(SB3.U[1] == 1000, "Woo!");
+  _Static_assert(SB3.I == 8, "Woo!");
+  _Static_assert(SB3.I2 == 0, "Woo!");
+}

>From d88443c22acdc3dac27612577352a32d16c0dd8c Mon Sep 17 00:00:00 2001
From: Sarah Spall <sarahspall at microsoft.com>
Date: Thu, 26 Mar 2026 10:56:49 -0700
Subject: [PATCH 4/4] fix test messed up during merge and regen check lines
 using script to match feedback in other pr

---
 .../CodeGenHLSL/BasicFeatures/InitLists.hlsl  | 312 +++++++++---------
 1 file changed, 163 insertions(+), 149 deletions(-)

diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
index c0fc0281a5f3f..9c42da8962c2d 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -1127,155 +1127,6 @@ void case26(TwoInts TI) {
   float3 F2 = float3(3, TI);
 }
 
-// Check cases with explicit casts
-
-// CHECK-LABEL: define hidden void @_Z6case279TwoFloats(ptr noundef byval(%struct.TwoFloats) align 1 %TF)
-// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
-// CHECK: [[RT:%.*]] = alloca %struct.TwoInts, align 1
-// CHECK: [[AT:%.*]] = alloca %struct.TwoFloats, align 1
-// CHECK: [[RT6:%.*]] = alloca %struct.TwoInts, align 1
-// CHECK: [[AT7:%.*]] = alloca %struct.TwoFloats, align 1
-// CHECK: [[Z:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 0
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT]], ptr align 1 %TF, i32 8, i1 false)
-// CHECK: [[G:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 0
-// CHECK: [[G1:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 1
-// CHECK: [[G2:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT]], i32 0, i32 0
-// CHECK: [[G3:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT]], i32 0, i32 1
-// CHECK: [[Zero:%.*]] = load float, ptr [[G2]], align 4
-// CHECK: [[Conv:%.*]] = fptosi float [[Zero]] to i32
-// CHECK: store i32 [[Conv]], ptr [[G]], align 4
-// CHECK: [[One:%.*]] = load float, ptr [[G3]], align 4
-// CHECK: [[Conv4:%.*]] = fptosi float [[One]] to i32
-// CHECK: store i32 [[Conv4]], ptr [[G1]], align 4
-// CHECK: [[Z5:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT]], i32 0, i32 0
-// CHECK: [[Two:%.*]] = load i32, ptr [[Z5]], align 1
-// CHECK: store i32 [[Two]], ptr [[Z]], align 1
-// CHECK: [[W:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 1
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT7]], ptr align 1 %TF, i32 8, i1 false)
-// CHECK: [[G8:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT6]], i32 0, i32 0
-// CHECK: [[G9:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT6]], i32 0, i32 1
-// CHECK: [[G10:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT7]], i32 0, i32 0
-// CHECK: [[G11:%.*]] = getelementptr inbounds %struct.TwoFloats, ptr [[AT7]], i32 0, i32 1
-// CHECK: [[Tre:%.*]] = load float, ptr [[G10]], align 4
-// CHECK: [[Conv12:%.*]] = fptosi float [[Tre]] to i32
-// CHECK: store i32 [[Conv12]], ptr [[G8]], align 4
-// CHECK: [[Four:%.*]] = load float, ptr [[G11]], align 4
-// CHECK: [[Conv13:%.*]] = fptosi float [[Four]] to i32
-// CHECK: store i32 [[Conv13]], ptr [[G9]], align 4
-// CHECK: [[W14:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT6]], i32 0, i32 1
-// CHECK: [[Five:%.*]] = load i32, ptr [[W14]], align 1
-// CHECK: store i32 [[Five]], ptr [[W]], align 1
-// CHECK: ret void
-void case27(TwoFloats TF) {
-  TwoInts TI = {(TwoInts)TF};
-}
-
-// CHECK-LABEL: define hidden void @_Z6case2810FourFloats(ptr noundef byval(%struct.FourFloats) align 1 %FF)
-// CHECK: [[Ints:%.*]] = alloca [2 x i32], align 4
-// CHECK: [[RT:%.*]] = alloca [2 x i32], align 4
-// CHECK: [[AT:%.*]] = alloca %struct.FourFloats, align 1
-// CHECK: [[RT7:%.*]] = alloca [2 x i32], align 4
-// CHECK: [[AT8:%.*]] = alloca %struct.FourFloats, align 1
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT]], ptr align 1 %FF, i32 16, i1 false)
-// CHECK: [[G:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT]], i32 0, i32 0
-// CHECK: [[G1:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT]], i32 0, i32 1
-// CHECK: [[G2:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 0, i32 0
-// CHECK: [[G3:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 0, i32 1
-// CHECK: [[G4:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 1
-// CHECK: [[G5:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT]], i32 0, i32 2
-// CHECK: [[Zero:%.*]] = load float, ptr [[G2]], align 4
-// CHECK: [[Conv:%.*]] = fptosi float [[Zero]] to i32
-// CHECK: store i32 [[Conv]], ptr [[G]], align 4
-// CHECK: [[One:%.*]] = load float, ptr [[G3]], align 4
-// CHECK: [[Conv6:%.*]] = fptosi float [[One]] to i32
-// CHECK: store i32 [[Conv6]], ptr [[G1]], align 4
-// CHECK: [[ArrIdx:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[RT]], i32 0, i32 0
-// CHECK: [[Two:%.*]] = load i32, ptr [[ArrIdx]], align 4
-// CHECK: store i32 [[Two]], ptr [[Ints]], align 4
-// CHECK: [[ArrInitEl:%.*]] = getelementptr inbounds i32, ptr [[Ints]], i32 1
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AT8]], ptr align 1 %FF, i32 16, i1 false)
-// CHECK: [[G9:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT7]], i32 0, i32 0
-// CHECK: [[G10:%.*]] = getelementptr inbounds [2 x i32], ptr [[RT7]], i32 0, i32 1
-// CHECK: [[G11:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 0, i32 0
-// CHECK: [[G12:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 0, i32 1
-// CHECK: [[G13:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 1
-// CHECK: [[G14:%.*]] = getelementptr inbounds %struct.FourFloats, ptr [[AT8]], i32 0, i32 2
-// CHECK: [[Tre:%.*]] = load float, ptr [[G11]], align 4
-// CHECK: [[Conv15:%.*]] = fptosi float [[Tre]] to i32
-// CHECK: store i32 [[Conv15]], ptr [[G9]], align 4
-// CHECK: [[Four:%.*]] = load float, ptr [[G12]], align 4
-// CHECK: [[Conv16:%.*]] = fptosi float [[Four]] to i32
-// CHECK: store i32 [[Conv16]], ptr [[G10]], align 4
-// CHECK: [[ArrIdx17:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[RT7]], i32 0, i32 1
-// CHECK: [[Five:%.*]] = load i32, ptr [[ArrIdx17]], align 4
-// CHECK: store i32 [[Five]], ptr [[ArrInitEl]], align 4
-// CHECK: ret void
-void case28(FourFloats FF) {
-  int Ints[2] = {(int[2])FF};
-}
-
-// CHECK-LABEL: define hidden void @_Z6case29v()
-// CHECK: [[Arr:%.*]] = alloca [4 x float], align 4
-// CHECK: [[TI:%.*]] = alloca %struct.TwoInts, align 1
-// CHECK: [[RT:%.*]] = alloca %struct.TwoInts, align 1
-// CHECK: [[AT:%.*]] = alloca [4 x float], align 4
-// CHECK: [[RT8:%.*]] = alloca %struct.TwoInts, align 1
-// CHECK: [[AT9:%.*]] = alloca [4 x float], align 4
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Arr]], ptr align 4 {{.*}}, i32 16, i1 false)
-// CHECK: [[Z:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 0
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AT]], ptr align 4 [[Arr]], i32 16, i1 false)
-// CHECK: [[G:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 0
-// CHECK: [[G1:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT]], i32 0, i32 1
-// CHECK: [[G2:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 0
-// CHECK: [[G3:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 1
-// CHECK: [[G4:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 2
-// CHECK: [[G5:%.*]] = getelementptr inbounds [4 x float], ptr [[AT]], i32 0, i32 3
-// CHECK: [[Zero:%.*]] = load float, ptr [[G2]], align 4
-// CHECK: [[Conv:%.*]] = fptosi float [[Zero]] to i32
-// CHECK: store i32 [[Conv]], ptr [[G]], align 4
-// CHECK: [[One:%.*]] = load float, ptr [[G3]], align 4
-// CHECK: [[Conv6:%.*]] = fptosi float [[One]] to i32
-// CHECK: store i32 [[Conv6]], ptr [[G1]], align 4
-// CHECK: [[Z7:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT]], i32 0, i32 0
-// CHECK: [[Two:%.*]] = load i32, ptr [[Z7]], align 1
-// CHECK: store i32 [[Two]], ptr [[Z]], align 1
-// CHECK: [[W:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[TI]], i32 0, i32 1
-// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AT9]], ptr align 4 [[Arr]], i32 16, i1 false)
-// CHECK: [[G10:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT8]], i32 0, i32 0
-// CHECK: [[G11:%.*]] = getelementptr inbounds %struct.TwoInts, ptr [[RT8]], i32 0, i32 1
-// CHECK: [[G12:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 0
-// CHECK: [[G13:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 1
-// CHECK: [[G14:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 2
-// CHECK: [[G15:%.*]] = getelementptr inbounds [4 x float], ptr [[AT9]], i32 0, i32 3
-// CHECK: [[Tre:%.*]] = load float, ptr [[G12]], align 4
-// CHECK: [[Conv16:%.*]] = fptosi float [[Tre]] to i32
-// CHECK: store i32 [[Conv16]], ptr [[G10]], align 4
-// CHECK: [[Four:%.*]] = load float, ptr [[G13]], align 4
-// CHECK: [[Conv17:%.*]] = fptosi float [[Four]] to i32
-// CHECK: store i32 [[Conv17]], ptr [[G11]], align 4
-// CHECK: [[W18:%.*]] = getelementptr inbounds nuw %struct.TwoInts, ptr [[RT8]], i32 0, i32 1
-// CHECK: [[Five:%.*]] = load i32, ptr [[W18]], align 1
-// CHECK: store i32 [[Five]], ptr [[W]], align 1
-// CHECK: ret void
-void case29() {
-  float Arr[4] = {1.0,2.0,3.0,4.0};
-  TwoInts TI = {(TwoInts)Arr};
-}
-
-// CHECK-LABEL: define hidden void @_Z6case30v()
-// CHECK: [[F:%.*]] = alloca float, align 4
-// CHECK: [[SB:%.*]] = alloca %struct.SlicyBits, align 1
-// CHECK: store float 1.000000e+00, ptr [[F]], align 4
-// CHECK: [[A:%.*]] = load float, ptr [[F]], align 4
-// CHECK: [[Conv:%.*]] = fptosi float [[A]] to i32
-// CHECK: [[B:%.*]] = trunc i32 [[Conv]] to i8
-// CHECK: store i8 [[B]], ptr [[SB]], align 1
-// CHECK: [[W:%.*]] = getelementptr inbounds nuw %struct.SlicyBits, ptr [[SB]], i32 0, i32 1
-// CHECK: store i8 2, ptr [[W]], align 1
-// CHECK: ret void
-void case30() {
-  float F = 1.0;
-  SlicyBits SB = {(int)F, 2};
 using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]];
 
 struct CustomResource {
@@ -1295,6 +1146,169 @@ struct CustomResource {
 void case27(CustomResource a) {
   CustomResource b = {a};
 }
+
+// Check cases with explicit casts
+
+// CHECK-LABEL: define hidden void @_Z6case289TwoFloats(
+// CHECK-SAME: ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 1 [[TF:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP:%.*]] = alloca [[STRUCT_TWOFLOATS]], align 1
+// CHECK-NEXT:    [[REF_TMP6:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP7:%.*]] = alloca [[STRUCT_TWOFLOATS]], align 1
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP]], ptr align 1 [[TF]], i32 8, i1 false)
+// CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], ptr [[AGG_TEMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], ptr [[AGG_TEMP]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[GEP2]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[GEP]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[GEP3]], align 4
+// CHECK-NEXT:    [[CONV4:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV4]], ptr [[GEP1]], align 4
+// CHECK-NEXT:    [[Z5:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[Z5]], align 1
+// CHECK-NEXT:    store i32 [[TMP2]], ptr [[Z]], align 1
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP7]], ptr align 1 [[TF]], i32 8, i1 false)
+// CHECK-NEXT:    [[GEP8:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP6]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP9:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP6]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP10:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], ptr [[AGG_TEMP7]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP11:%.*]] = getelementptr inbounds [[STRUCT_TWOFLOATS]], ptr [[AGG_TEMP7]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[GEP10]], align 4
+// CHECK-NEXT:    [[CONV12:%.*]] = fptosi float [[TMP3]] to i32
+// CHECK-NEXT:    store i32 [[CONV12]], ptr [[GEP8]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load float, ptr [[GEP11]], align 4
+// CHECK-NEXT:    [[CONV13:%.*]] = fptosi float [[TMP4]] to i32
+// CHECK-NEXT:    store i32 [[CONV13]], ptr [[GEP9]], align 4
+// CHECK-NEXT:    [[W14:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[REF_TMP6]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[W14]], align 1
+// CHECK-NEXT:    store i32 [[TMP5]], ptr [[W]], align 1
+// CHECK-NEXT:    ret void
+//
+void case28(TwoFloats TF) {
+  TwoInts TI = {(TwoInts)TF};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case2910FourFloats(
+// CHECK-SAME: ptr noundef byval([[STRUCT_FOURFLOATS:%.*]]) align 1 [[FF:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[INTS:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT:    [[AGG_TEMP:%.*]] = alloca [[STRUCT_FOURFLOATS]], align 1
+// CHECK-NEXT:    [[REF_TMP7:%.*]] = alloca [2 x i32], align 4
+// CHECK-NEXT:    [[AGG_TEMP8:%.*]] = alloca [[STRUCT_FOURFLOATS]], align 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP]], ptr align 1 [[FF]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [2 x i32], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [2 x i32], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP]], i32 0, i32 0, i32 0
+// CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP]], i32 0, i32 0, i32 1
+// CHECK-NEXT:    [[GEP4:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP5:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[GEP2]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[GEP]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[GEP3]], align 4
+// CHECK-NEXT:    [[CONV6:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV6]], ptr [[GEP1]], align 4
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// CHECK-NEXT:    store i32 [[TMP2]], ptr [[INTS]], align 4
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds i32, ptr [[INTS]], i32 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[AGG_TEMP8]], ptr align 1 [[FF]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP9:%.*]] = getelementptr inbounds [2 x i32], ptr [[REF_TMP7]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP10:%.*]] = getelementptr inbounds [2 x i32], ptr [[REF_TMP7]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP11:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 0, i32 0
+// CHECK-NEXT:    [[GEP12:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 0, i32 1
+// CHECK-NEXT:    [[GEP13:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP14:%.*]] = getelementptr inbounds [[STRUCT_FOURFLOATS]], ptr [[AGG_TEMP8]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[GEP11]], align 4
+// CHECK-NEXT:    [[CONV15:%.*]] = fptosi float [[TMP3]] to i32
+// CHECK-NEXT:    store i32 [[CONV15]], ptr [[GEP9]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load float, ptr [[GEP12]], align 4
+// CHECK-NEXT:    [[CONV16:%.*]] = fptosi float [[TMP4]] to i32
+// CHECK-NEXT:    store i32 [[CONV16]], ptr [[GEP10]], align 4
+// CHECK-NEXT:    [[ARRAYIDX17:%.*]] = getelementptr inbounds nuw [2 x i32], ptr [[REF_TMP7]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[ARRAYIDX17]], align 4
+// CHECK-NEXT:    store i32 [[TMP5]], ptr [[ARRAYINIT_ELEMENT]], align 4
+// CHECK-NEXT:    ret void
+//
+void case29(FourFloats FF) {
+  int Ints[2] = {(int[2])FF};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case30v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[ARR:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT:    [[TI:%.*]] = alloca [[STRUCT_TWOINTS:%.*]], align 1
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT:    [[REF_TMP8:%.*]] = alloca [[STRUCT_TWOINTS]], align 1
+// CHECK-NEXT:    [[AGG_TEMP9:%.*]] = alloca [4 x float], align 4
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARR]], ptr align 4 @__const._Z6case30v.Arr, i32 16, i1 false)
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TEMP]], ptr align 4 [[ARR]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP4:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP]], i32 0, i32 2
+// CHECK-NEXT:    [[GEP5:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[GEP2]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[GEP]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[GEP3]], align 4
+// CHECK-NEXT:    [[CONV6:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV6]], ptr [[GEP1]], align 4
+// CHECK-NEXT:    [[Z7:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[Z7]], align 1
+// CHECK-NEXT:    store i32 [[TMP2]], ptr [[Z]], align 1
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_TEMP9]], ptr align 4 [[ARR]], i32 16, i1 false)
+// CHECK-NEXT:    [[GEP10:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP8]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP11:%.*]] = getelementptr inbounds [[STRUCT_TWOINTS]], ptr [[REF_TMP8]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP12:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP9]], i32 0, i32 0
+// CHECK-NEXT:    [[GEP13:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP9]], i32 0, i32 1
+// CHECK-NEXT:    [[GEP14:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP9]], i32 0, i32 2
+// CHECK-NEXT:    [[GEP15:%.*]] = getelementptr inbounds [4 x float], ptr [[AGG_TEMP9]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[GEP12]], align 4
+// CHECK-NEXT:    [[CONV16:%.*]] = fptosi float [[TMP3]] to i32
+// CHECK-NEXT:    store i32 [[CONV16]], ptr [[GEP10]], align 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load float, ptr [[GEP13]], align 4
+// CHECK-NEXT:    [[CONV17:%.*]] = fptosi float [[TMP4]] to i32
+// CHECK-NEXT:    store i32 [[CONV17]], ptr [[GEP11]], align 4
+// CHECK-NEXT:    [[W18:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[REF_TMP8]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[W18]], align 1
+// CHECK-NEXT:    store i32 [[TMP5]], ptr [[W]], align 1
+// CHECK-NEXT:    ret void
+//
+void case30() {
+  float Arr[4] = {1.0,2.0,3.0,4.0};
+  TwoInts TI = {(TwoInts)Arr};
+}
+
+// CHECK-LABEL: define hidden void @_Z6case31v(
+// CHECK-SAME: ) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[F:%.*]] = alloca float, align 4
+// CHECK-NEXT:    [[SB:%.*]] = alloca [[STRUCT_SLICYBITS:%.*]], align 1
+// CHECK-NEXT:    store float 1.000000e+00, ptr [[F]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[F]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[CONV]] to i8
+// CHECK-NEXT:    store i8 [[TMP1]], ptr [[SB]], align 1
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_SLICYBITS]], ptr [[SB]], i32 0, i32 1
+// CHECK-NEXT:    store i8 2, ptr [[W]], align 1
+// CHECK-NEXT:    ret void
+//
+void case31() {
+  float F = 1.0;
+  SlicyBits SB = {(int)F, 2};
+}
 //.
 // CHECK: [[META3]] = !{}
 // CHECK: [[META4]] = !{i64 4}



More information about the cfe-commits mailing list