[clang] [HLSL] Implement HLSL intialization list support (PR #123141)

Chris B via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 15 10:48:59 PST 2025


https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/123141

>From d31eebe88483f1cba23d97ac525b71cf2d8828a3 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Wed, 15 Jan 2025 13:40:29 -0600
Subject: [PATCH 01/16] [HLSL] Implement HLSL intialization list support

This PR implements HLSL's initialization list behvaior as specified in
the draft language specifcation under
[*Decl.Init.Agg*](https://microsoft.github.io/hlsl-specs/specs/hlsl.html
#Decl.Init.Agg).

This behavior is a bit unusual for C/C++ because intermediate braces in
initializer lists are ignored and a whole array of additional
conversions occur unintuitively to how initializaiton works in C.

The implementaiton in this PR generates a valid C/C++ initialization
list AST for the HLSL initializer so that there are no changes required
to Clang's CodeGen to support this. This design will also allow us to
use Clang's rewrite to convert HLSL initializers to valid C/C++
initializers that are equivalent. It does have the downside that it
will generate often redundant accesses during codegen. The IR optimizer
is extremely good at eliminating those so this will have no impact on
the final executable performance.

There is some opportunity for optimizing the initializer list
generation that we could consider in subsequent commits. One notable
opportunity would be to identify aggregate objects that occur in the
same place in both initializers and do not require converison, those
aggregates could be initialized as aggregates rather than fully
scalarized.

Closes #56067
---
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/include/clang/Sema/SemaHLSL.h           |   5 +
 clang/lib/Sema/SemaChecking.cpp               |   9 +-
 clang/lib/Sema/SemaHLSL.cpp                   | 159 ++++
 clang/lib/Sema/SemaInit.cpp                   |   5 +
 clang/test/CodeGenHLSL/ArrayTemporary.hlsl    |   3 +-
 .../CodeGenHLSL/BasicFeatures/InitLists.hlsl  | 714 ++++++++++++++++++
 clang/test/SemaHLSL/ArrayTemporary.hlsl       |   2 +-
 clang/test/SemaHLSL/Language/InitLists.hlsl   |  69 ++
 9 files changed, 964 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
 create mode 100644 clang/test/SemaHLSL/Language/InitLists.hlsl

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c4f0fc55b4a38..f10af8f5bd6b2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12626,6 +12626,9 @@ def err_hlsl_pointers_unsupported : Error<
   "%select{pointers|references}0 are unsupported in HLSL">;
 def err_hlsl_missing_resource_class : Error<"HLSL resource needs to have [[hlsl::resource_class()]] attribute">;
 def err_hlsl_attribute_needs_intangible_type: Error<"attribute %0 can be used only on HLSL intangible type %1">;
+def err_hlsl_incorrect_num_initializers: Error<
+  "too %select{few|many}0 initializers in list for type %1 "
+  "(expected %2 but found %3)">;
 
 def err_hlsl_operator_unsupported : Error<
   "the '%select{&|*|->}0' operator is unsupported in HLSL">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h
index c9266ea50e4bf..4f4bbe95476ee 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -26,6 +26,8 @@
 namespace clang {
 class AttributeCommonInfo;
 class IdentifierInfo;
+class InitializedEntity;
+class InitializationKind;
 class ParsedAttr;
 class Scope;
 class VarDecl;
@@ -149,6 +151,9 @@ class SemaHLSL : public SemaBase {
 
   QualType getInoutParameterType(QualType Ty);
 
+  bool TransformInitList(const InitializedEntity &Entity,
+                         const InitializationKind &Kind, InitListExpr *Init);
+
 private:
   // HLSL resource type attributes need to be processed all at once.
   // This is a list to collect them.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 66c233de4ef30..e423b820c6032 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11678,9 +11678,12 @@ static void AnalyzeImplicitConversions(
 
   // Propagate whether we are in a C++ list initialization expression.
   // If so, we do not issue warnings for implicit int-float conversion
-  // precision loss, because C++11 narrowing already handles it.
-  bool IsListInit = Item.IsListInit ||
-                    (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus);
+  // precision loss, because C++11 narrowing already handles it. HLSL's
+  // initialization lists are special, so they shouldn't observe the C++
+  // behavior here.
+  bool IsListInit =
+      Item.IsListInit || (isa<InitListExpr>(OrigE) &&
+                          S.getLangOpts().CPlusPlus && !S.getLangOpts().HLSL);
 
   if (E->isTypeDependent() || E->isValueDependent())
     return;
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 9a60054a6169e..2e1d8bd43bde9 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3056,3 +3056,162 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
     }
   }
 }
+
+static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
+                            llvm::SmallVectorImpl<Expr *> &List,
+                            llvm::SmallVectorImpl<QualType> &DestTypes) {
+  if (List.size() >= DestTypes.size())
+    return false;
+  InitializedEntity Entity =
+      InitializedEntity::InitializeParameter(Ctx, DestTypes[List.size()], false);
+  ExprResult Res =
+      S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
+  if (Res.isInvalid())
+    return false;
+  Expr *Init = Res.get();
+  List.push_back(Init);
+  return true;
+}
+
+static void BuildIntializerList(Sema &S, ASTContext &Ctx, Expr *E,
+                                llvm::SmallVectorImpl<Expr *> &List,
+                                llvm::SmallVectorImpl<QualType> &DestTypes,
+                                bool &ExcessInits) {
+  if (List.size() >= DestTypes.size()) {
+    ExcessInits = true;
+    return;
+  }
+
+  // If this is an initialization list, traverse the sub initializers.
+  if (auto *Init = dyn_cast<InitListExpr>(E)) {
+    for (auto *SubInit : Init->inits())
+      BuildIntializerList(S, Ctx, SubInit, List, DestTypes, ExcessInits);
+    return;
+  }
+
+  // If this is a scalar type, just enqueue the expression.
+  QualType Ty = E->getType();
+  if (Ty->isScalarType()) {
+    (void)CastInitializer(S, Ctx, E, List, DestTypes);
+    return;
+  }
+
+  if (auto *ATy = Ty->getAs<VectorType>()) {
+    uint64_t Size = ATy->getNumElements();
+
+    if (List.size() + Size > DestTypes.size()) {
+      ExcessInits = true;
+      return;
+    }
+    QualType SizeTy = Ctx.getSizeType();
+    uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
+    for (uint64_t I = 0; I < Size; ++I) {
+      auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
+                                         SizeTy, SourceLocation());
+
+      ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
+          E, E->getBeginLoc(), Idx, E->getEndLoc());
+      if (ElExpr.isInvalid())
+        return;
+      if (!CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes))
+        return;
+    }
+    return;
+  }
+
+  if (auto *VTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
+    uint64_t Size = VTy->getZExtSize();
+    QualType SizeTy = Ctx.getSizeType();
+    uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
+    for (uint64_t I = 0; I < Size; ++I) {
+      auto *Idx = IntegerLiteral::Create(Ctx, llvm::APInt(SizeTySize, I),
+                                         SizeTy, SourceLocation());
+      ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
+          E, E->getBeginLoc(), Idx, E->getEndLoc());
+      if (ElExpr.isInvalid())
+        return;
+      BuildIntializerList(S, Ctx, ElExpr.get(), List, DestTypes, ExcessInits);
+    }
+    return;
+  }
+
+  if (auto *RTy = Ty->getAs<RecordType>()) {
+    for (auto *FD : RTy->getDecl()->fields()) {
+      DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
+      DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
+      ExprResult Res = S.BuildFieldReferenceExpr(
+          E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
+      if (Res.isInvalid())
+        return;
+      BuildIntializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
+    }
+  }
+}
+
+static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
+                               llvm::SmallVectorImpl<Expr *>::iterator &It) {
+  if (Ty->isScalarType()) {
+    return *(It++);
+  }
+  llvm::SmallVector<Expr *> Inits;
+  assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
+  if (Ty->isVectorType() || Ty->isConstantArrayType()) {
+    QualType ElTy;
+    uint64_t Size = 0;
+    if (auto *ATy = Ty->getAs<VectorType>()) {
+      ElTy = ATy->getElementType();
+      Size = ATy->getNumElements();
+    } else {
+      auto *VTy = cast<ConstantArrayType>(Ty.getTypePtr());
+      ElTy = VTy->getElementType();
+      Size = VTy->getZExtSize();
+    }
+    for (uint64_t I = 0; I < Size; ++I)
+      Inits.push_back(GenerateInitLists(Ctx, ElTy, It));
+  }
+  if (const RecordDecl *RD = Ty->getAsRecordDecl()) {
+    for (auto *FD : RD->fields()) {
+      Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
+    }
+  }
+  auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
+                                         Inits, Inits.back()->getEndLoc());
+  NewInit->setType(Ty);
+  return NewInit;
+}
+
+bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
+                                 const InitializationKind &Kind,
+                                 InitListExpr *Init) {
+  // If the initializer is a scalar, just return it.
+  if (Init->getType()->isScalarType())
+    return true;
+  ASTContext &Ctx = SemaRef.getASTContext();
+  llvm::SmallVector<QualType, 16> DestTypes;
+  // An initializer list might be attempting to initialize a reference or
+  // rvalue-reference. When checking the initializer we should look through the
+  // reference.
+  QualType InitTy = Entity.getType().getNonReferenceType();
+  BuildFlattenedTypeList(InitTy, DestTypes);
+
+  llvm::SmallVector<Expr *, 16> ArgExprs;
+  bool ExcessInits = false;
+  for (Expr *Arg : Init->inits())
+    BuildIntializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes, ExcessInits);
+
+  if (DestTypes.size() != ArgExprs.size() || ExcessInits) {
+    int TooManyOrFew = ExcessInits ? 1 : 0;
+    SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
+        << TooManyOrFew << InitTy << DestTypes.size() << ArgExprs.size();
+    return false;
+  }
+
+  auto It = ArgExprs.begin();
+  // GenerateInitLists will always return an InitListExpr here, because the
+  // scalar case is handled above.
+  auto *NewInit = cast<InitListExpr>(GenerateInitLists(Ctx, InitTy, It));
+  Init->resizeInits(Ctx, NewInit->getNumInits());
+  for (unsigned I = 0; I < NewInit->getNumInits(); ++I)
+    Init->updateInit(Ctx, I, NewInit->getInit(I));
+  return true;
+}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 18090eb1c9e9a..6a76e6d74a4b0 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -26,6 +26,7 @@
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Ownership.h"
+#include "clang/Sema/SemaHLSL.h"
 #include "clang/Sema/SemaObjC.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/FoldingSet.h"
@@ -4787,6 +4788,10 @@ static void TryListInitialization(Sema &S,
                                   bool TreatUnavailableAsInvalid) {
   QualType DestType = Entity.getType();
 
+  if (S.getLangOpts().HLSL &&
+      !S.HLSL().TransformInitList(Entity, Kind, InitList))
+    return;
+
   // C++ doesn't allow scalar initialization with more than one argument.
   // But C99 complex numbers are scalars and it makes sense there.
   if (S.getLangOpts().CPlusPlus && DestType->isScalarType() &&
diff --git a/clang/test/CodeGenHLSL/ArrayTemporary.hlsl b/clang/test/CodeGenHLSL/ArrayTemporary.hlsl
index e5db7eac37a42..91a283554459d 100644
--- a/clang/test/CodeGenHLSL/ArrayTemporary.hlsl
+++ b/clang/test/CodeGenHLSL/ArrayTemporary.hlsl
@@ -1,3 +1,4 @@
+
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
 
 void fn(float x[2]) { }
@@ -27,7 +28,7 @@ void fn2(Obj O[4]) { }
 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[Tmp]], ptr align 4 [[Arr]], i32 32, i1 false)
 // CHECK: call void {{.*}}fn2{{.*}}(ptr noundef byval([4 x %struct.Obj]) align 4 [[Tmp]])
 void call2() {
-  Obj Arr[4] = {};
+  Obj Arr[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}};
   fn2(Arr);
 }
 
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
new file mode 100644
index 0000000000000..e57724b0ec31f
--- /dev/null
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -0,0 +1,714 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -emit-llvm -finclude-default-header -o - %s | FileCheck %s
+
+struct TwoFloats {
+  float X, Y;
+};
+
+struct TwoInts {
+  int Z, W;
+};
+
+struct Doggo {
+  int4 LegState;
+  int TailState;
+  float HairCount;
+  float4 EarDirection[2];
+};
+
+struct AnimalBits {
+  int Legs[4];
+  uint State;
+  int64_t Counter;
+  float4 LeftDir;
+  float4 RightDir;
+};
+
+struct Kitteh {
+  int4 Legs;
+  int TailState;
+  float HairCount;
+  float4 Claws[2];
+};
+
+struct Zoo {
+  Doggo Dogs[2];
+  Kitteh Cats[4];
+};
+
+// Case 1: Extraneous braces get ignored in literal instantiation.
+// CHECK-LABEL: define void @_Z5case1v(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_RESULT]], ptr align 4 @__const._Z5case1v.TF1, i32 8, i1 false)
+// CHECK-NEXT:    ret void
+//
+TwoFloats case1() {
+  TwoFloats TF1 = {{{1.0, 2}}};
+  return TF1;
+}
+
+// Case 2: Valid C/C++ initializer is handled appropriately.
+// CHECK-LABEL: define void @_Z5case2v(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[AGG_RESULT]], ptr align 4 @__const._Z5case2v.TF2, i32 8, i1 false)
+// CHECK-NEXT:    ret void
+//
+TwoFloats case2() {
+  TwoFloats TF2 = {1, 2};
+  return TF2;
+}
+
+// Case 3: Simple initialization with conversion of an argument.
+// CHECK-LABEL: define void @_Z5case3i(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], i32 noundef [[VAL:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[VAL_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[TMP0]] to float
+// CHECK-NEXT:    store float [[CONV]], ptr [[X]], align 4
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    store float 2.000000e+00, ptr [[Y]], align 4
+// CHECK-NEXT:    ret void
+//
+TwoFloats case3(int Val) {
+  TwoFloats TF3 = {Val, 2};
+  return TF3;
+}
+
+// Case 4: Initialization from a scalarized vector into a structure with element
+// conversions.
+// CHECK-LABEL: define void @_Z5case4Dv2_i(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], <2 x i32> noundef [[TWOVALS:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TWOVALS_ADDR:%.*]] = alloca <2 x i32>, align 8
+// CHECK-NEXT:    store <2 x i32> [[TWOVALS]], ptr [[TWOVALS_ADDR]], align 8
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i32>, ptr [[TWOVALS_ADDR]], align 8
+// CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <2 x i32> [[TMP0]], i64 0
+// CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[VECEXT]] to float
+// CHECK-NEXT:    store float [[CONV]], ptr [[X]], align 4
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load <2 x i32>, ptr [[TWOVALS_ADDR]], align 8
+// CHECK-NEXT:    [[VECEXT1:%.*]] = extractelement <2 x i32> [[TMP1]], i64 1
+// CHECK-NEXT:    [[CONV2:%.*]] = sitofp i32 [[VECEXT1]] to float
+// CHECK-NEXT:    store float [[CONV2]], ptr [[Y]], align 4
+// CHECK-NEXT:    ret void
+//
+TwoFloats case4(int2 TwoVals) {
+  TwoFloats TF4 = {TwoVals};
+  return TF4;
+}
+
+// Case 5: Initialization from a scalarized vector of matching type.
+// CHECK-LABEL: define void @_Z5case5Dv2_i(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 4 [[AGG_RESULT:%.*]], <2 x i32> noundef [[TWOVALS:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[TWOVALS_ADDR:%.*]] = alloca <2 x i32>, align 8
+// CHECK-NEXT:    store <2 x i32> [[TWOVALS]], ptr [[TWOVALS_ADDR]], align 8
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load <2 x i32>, ptr [[TWOVALS_ADDR]], align 8
+// CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <2 x i32> [[TMP0]], i64 0
+// CHECK-NEXT:    store i32 [[VECEXT]], ptr [[Z]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load <2 x i32>, ptr [[TWOVALS_ADDR]], align 8
+// CHECK-NEXT:    [[VECEXT1:%.*]] = extractelement <2 x i32> [[TMP1]], i64 1
+// CHECK-NEXT:    store i32 [[VECEXT1]], ptr [[W]], align 4
+// CHECK-NEXT:    ret void
+//
+TwoInts case5(int2 TwoVals) {
+  TwoInts TI1 = {TwoVals};
+  return TI1;
+}
+
+// Case 6: Initialization from a scalarized structure of different type with
+// different element types.
+// CHECK-LABEL: define void @_Z5case69TwoFloats(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 4 [[TF4:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF4]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[X]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP0]] to i32
+// CHECK-NEXT:    store i32 [[CONV]], ptr [[Z]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF4]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[Y]], align 4
+// CHECK-NEXT:    [[CONV1:%.*]] = fptosi float [[TMP1]] to i32
+// CHECK-NEXT:    store i32 [[CONV1]], ptr [[W]], align 4
+// CHECK-NEXT:    ret void
+//
+TwoInts case6(TwoFloats TF4) {
+  TwoInts TI2 = {TF4};
+  return TI2;
+}
+
+// Case 7: Initialization of a complex structue, with bogus braces and element
+// conversions from a collection of scalar values, and structures.
+// CHECK-LABEL: define void @_Z5case77TwoIntsS_i9TwoFloatsS0_S0_S0_(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_DOGGO:%.*]]) align 16 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 4 [[TI1:%.*]], ptr noundef byval([[STRUCT_TWOINTS]]) align 4 [[TI2:%.*]], i32 noundef [[VAL:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 4 [[TF1:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF2:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF3:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF4:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[VAL_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[VAL]], ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    [[LEGSTATE:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[Z]], align 4
+// CHECK-NEXT:    [[VECINIT:%.*]] = insertelement <4 x i32> poison, i32 [[TMP0]], i32 0
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[W]], align 4
+// CHECK-NEXT:    [[VECINIT1:%.*]] = insertelement <4 x i32> [[VECINIT]], i32 [[TMP1]], i32 1
+// CHECK-NEXT:    [[Z2:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI2]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[Z2]], align 4
+// CHECK-NEXT:    [[VECINIT3:%.*]] = insertelement <4 x i32> [[VECINIT1]], i32 [[TMP2]], i32 2
+// CHECK-NEXT:    [[W4:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI2]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr [[W4]], align 4
+// CHECK-NEXT:    [[VECINIT5:%.*]] = insertelement <4 x i32> [[VECINIT3]], i32 [[TMP3]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT5]], ptr [[LEGSTATE]], align 16
+// CHECK-NEXT:    [[TAILSTATE:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[TMP4]], ptr [[TAILSTATE]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[AGG_RESULT]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP5:%.*]] = load i32, ptr [[VAL_ADDR]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[TMP5]] to float
+// CHECK-NEXT:    store float [[CONV]], ptr [[HAIRCOUNT]], align 4
+// CHECK-NEXT:    [[EARDIRECTION:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[AGG_RESULT]], i32 0, i32 3
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP6:%.*]] = load float, ptr [[X]], align 4
+// CHECK-NEXT:    [[VECINIT6:%.*]] = insertelement <4 x float> poison, float [[TMP6]], i32 0
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP7:%.*]] = load float, ptr [[Y]], align 4
+// CHECK-NEXT:    [[VECINIT7:%.*]] = insertelement <4 x float> [[VECINIT6]], float [[TMP7]], i32 1
+// CHECK-NEXT:    [[X8:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF2]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP8:%.*]] = load float, ptr [[X8]], align 4
+// CHECK-NEXT:    [[VECINIT9:%.*]] = insertelement <4 x float> [[VECINIT7]], float [[TMP8]], i32 2
+// CHECK-NEXT:    [[Y10:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF2]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP9:%.*]] = load float, ptr [[Y10]], align 4
+// CHECK-NEXT:    [[VECINIT11:%.*]] = insertelement <4 x float> [[VECINIT9]], float [[TMP9]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT11]], ptr [[EARDIRECTION]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds <4 x float>, ptr [[EARDIRECTION]], i32 1
+// CHECK-NEXT:    [[X12:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF3]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP10:%.*]] = load float, ptr [[X12]], align 4
+// CHECK-NEXT:    [[VECINIT13:%.*]] = insertelement <4 x float> poison, float [[TMP10]], i32 0
+// CHECK-NEXT:    [[Y14:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF3]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP11:%.*]] = load float, ptr [[Y14]], align 4
+// CHECK-NEXT:    [[VECINIT15:%.*]] = insertelement <4 x float> [[VECINIT13]], float [[TMP11]], i32 1
+// CHECK-NEXT:    [[X16:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF4]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP12:%.*]] = load float, ptr [[X16]], align 4
+// CHECK-NEXT:    [[VECINIT17:%.*]] = insertelement <4 x float> [[VECINIT15]], float [[TMP12]], i32 2
+// CHECK-NEXT:    [[Y18:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF4]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP13:%.*]] = load float, ptr [[Y18]], align 4
+// CHECK-NEXT:    [[VECINIT19:%.*]] = insertelement <4 x float> [[VECINIT17]], float [[TMP13]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT19]], ptr [[ARRAYINIT_ELEMENT]], align 16
+// CHECK-NEXT:    ret void
+//
+Doggo case7(TwoInts TI1, TwoInts TI2, int Val, TwoFloats TF1, TwoFloats TF2,
+            TwoFloats TF3, TwoFloats TF4) {
+  Doggo D1 = {TI1, TI2, {Val, Val}, {{TF1, TF2}, {TF3, TF4}}};
+  return D1;
+}
+
+// Case 8: Initialization of a structure from a different structure with
+// significantly different element types and grouping.
+// CHECK-LABEL: define void @_Z5case85Doggo(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_ANIMALBITS:%.*]]) align 16 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_DOGGO:%.*]]) align 16 [[D1:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[LEGS:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGSTATE:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr [[LEGSTATE]], align 16
+// CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <4 x i32> [[TMP0]], i64 0
+// CHECK-NEXT:    store i32 [[VECEXT]], ptr [[LEGS]], align 4
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds i32, ptr [[LEGS]], i32 1
+// CHECK-NEXT:    [[LEGSTATE1:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i32>, ptr [[LEGSTATE1]], align 16
+// CHECK-NEXT:    [[VECEXT2:%.*]] = extractelement <4 x i32> [[TMP1]], i64 1
+// CHECK-NEXT:    store i32 [[VECEXT2]], ptr [[ARRAYINIT_ELEMENT]], align 4
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT3:%.*]] = getelementptr inbounds i32, ptr [[LEGS]], i32 2
+// CHECK-NEXT:    [[LEGSTATE4:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load <4 x i32>, ptr [[LEGSTATE4]], align 16
+// CHECK-NEXT:    [[VECEXT5:%.*]] = extractelement <4 x i32> [[TMP2]], i64 2
+// CHECK-NEXT:    store i32 [[VECEXT5]], ptr [[ARRAYINIT_ELEMENT3]], align 4
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT6:%.*]] = getelementptr inbounds i32, ptr [[LEGS]], i32 3
+// CHECK-NEXT:    [[LEGSTATE7:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP3:%.*]] = load <4 x i32>, ptr [[LEGSTATE7]], align 16
+// CHECK-NEXT:    [[VECEXT8:%.*]] = extractelement <4 x i32> [[TMP3]], i64 3
+// CHECK-NEXT:    store i32 [[VECEXT8]], ptr [[ARRAYINIT_ELEMENT6]], align 4
+// CHECK-NEXT:    [[STATE:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[TAILSTATE:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr [[TAILSTATE]], align 16
+// CHECK-NEXT:    store i32 [[TMP4]], ptr [[STATE]], align 16
+// CHECK-NEXT:    [[COUNTER:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[AGG_RESULT]], i32 0, i32 2
+// CHECK-NEXT:    [[HAIRCOUNT:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP5:%.*]] = load float, ptr [[HAIRCOUNT]], align 4
+// CHECK-NEXT:    [[CONV:%.*]] = fptosi float [[TMP5]] to i64
+// CHECK-NEXT:    store i64 [[CONV]], ptr [[COUNTER]], align 8
+// CHECK-NEXT:    [[LEFTDIR:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[AGG_RESULT]], i32 0, i32 3
+// CHECK-NEXT:    [[EARDIRECTION:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP6:%.*]] = load <4 x float>, ptr [[ARRAYIDX]], align 16
+// CHECK-NEXT:    [[VECEXT9:%.*]] = extractelement <4 x float> [[TMP6]], i64 0
+// CHECK-NEXT:    [[VECINIT:%.*]] = insertelement <4 x float> poison, float [[VECEXT9]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION10:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX11:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION10]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP7:%.*]] = load <4 x float>, ptr [[ARRAYIDX11]], align 16
+// CHECK-NEXT:    [[VECEXT12:%.*]] = extractelement <4 x float> [[TMP7]], i64 1
+// CHECK-NEXT:    [[VECINIT13:%.*]] = insertelement <4 x float> [[VECINIT]], float [[VECEXT12]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION14:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX15:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION14]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP8:%.*]] = load <4 x float>, ptr [[ARRAYIDX15]], align 16
+// CHECK-NEXT:    [[VECEXT16:%.*]] = extractelement <4 x float> [[TMP8]], i64 2
+// CHECK-NEXT:    [[VECINIT17:%.*]] = insertelement <4 x float> [[VECINIT13]], float [[VECEXT16]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION18:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX19:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION18]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP9:%.*]] = load <4 x float>, ptr [[ARRAYIDX19]], align 16
+// CHECK-NEXT:    [[VECEXT20:%.*]] = extractelement <4 x float> [[TMP9]], i64 3
+// CHECK-NEXT:    [[VECINIT21:%.*]] = insertelement <4 x float> [[VECINIT17]], float [[VECEXT20]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT21]], ptr [[LEFTDIR]], align 16
+// CHECK-NEXT:    [[RIGHTDIR:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[AGG_RESULT]], i32 0, i32 4
+// CHECK-NEXT:    [[EARDIRECTION22:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX23:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION22]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP10:%.*]] = load <4 x float>, ptr [[ARRAYIDX23]], align 16
+// CHECK-NEXT:    [[VECEXT24:%.*]] = extractelement <4 x float> [[TMP10]], i64 0
+// CHECK-NEXT:    [[VECINIT25:%.*]] = insertelement <4 x float> poison, float [[VECEXT24]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION26:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX27:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION26]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP11:%.*]] = load <4 x float>, ptr [[ARRAYIDX27]], align 16
+// CHECK-NEXT:    [[VECEXT28:%.*]] = extractelement <4 x float> [[TMP11]], i64 1
+// CHECK-NEXT:    [[VECINIT29:%.*]] = insertelement <4 x float> [[VECINIT25]], float [[VECEXT28]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION30:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX31:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION30]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP12:%.*]] = load <4 x float>, ptr [[ARRAYIDX31]], align 16
+// CHECK-NEXT:    [[VECEXT32:%.*]] = extractelement <4 x float> [[TMP12]], i64 2
+// CHECK-NEXT:    [[VECINIT33:%.*]] = insertelement <4 x float> [[VECINIT29]], float [[VECEXT32]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION34:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX35:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION34]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP13:%.*]] = load <4 x float>, ptr [[ARRAYIDX35]], align 16
+// CHECK-NEXT:    [[VECEXT36:%.*]] = extractelement <4 x float> [[TMP13]], i64 3
+// CHECK-NEXT:    [[VECINIT37:%.*]] = insertelement <4 x float> [[VECINIT33]], float [[VECEXT36]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT37]], ptr [[RIGHTDIR]], align 16
+// CHECK-NEXT:    ret void
+//
+AnimalBits case8(Doggo D1) {
+  AnimalBits A1 = {D1};
+  return A1;
+}
+
+// Case 9: Everything everywhere all at once... Initializing mismatched
+// structures from different layouts, different component groupings, with no
+// top-level bracing separation.
+// CHECK-LABEL: define void @_Z5case95Doggo10AnimalBits(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_ZOO:%.*]]) align 16 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_DOGGO:%.*]]) align 16 [[D1:%.*]], ptr noundef byval([[STRUCT_ANIMALBITS:%.*]]) align 16 [[A1:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[DOGS:%.*]] = getelementptr inbounds nuw [[STRUCT_ZOO]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGSTATE:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[DOGS]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGSTATE1:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr [[LEGSTATE1]], align 16
+// CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <4 x i32> [[TMP0]], i64 0
+// CHECK-NEXT:    [[VECINIT:%.*]] = insertelement <4 x i32> poison, i32 [[VECEXT]], i32 0
+// CHECK-NEXT:    [[LEGSTATE2:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP1:%.*]] = load <4 x i32>, ptr [[LEGSTATE2]], align 16
+// CHECK-NEXT:    [[VECEXT3:%.*]] = extractelement <4 x i32> [[TMP1]], i64 1
+// CHECK-NEXT:    [[VECINIT4:%.*]] = insertelement <4 x i32> [[VECINIT]], i32 [[VECEXT3]], i32 1
+// CHECK-NEXT:    [[LEGSTATE5:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load <4 x i32>, ptr [[LEGSTATE5]], align 16
+// CHECK-NEXT:    [[VECEXT6:%.*]] = extractelement <4 x i32> [[TMP2]], i64 2
+// CHECK-NEXT:    [[VECINIT7:%.*]] = insertelement <4 x i32> [[VECINIT4]], i32 [[VECEXT6]], i32 2
+// CHECK-NEXT:    [[LEGSTATE8:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP3:%.*]] = load <4 x i32>, ptr [[LEGSTATE8]], align 16
+// CHECK-NEXT:    [[VECEXT9:%.*]] = extractelement <4 x i32> [[TMP3]], i64 3
+// CHECK-NEXT:    [[VECINIT10:%.*]] = insertelement <4 x i32> [[VECINIT7]], i32 [[VECEXT9]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT10]], ptr [[LEGSTATE]], align 16
+// CHECK-NEXT:    [[TAILSTATE:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[DOGS]], i32 0, i32 1
+// CHECK-NEXT:    [[TAILSTATE11:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr [[TAILSTATE11]], align 16
+// CHECK-NEXT:    store i32 [[TMP4]], ptr [[TAILSTATE]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[DOGS]], i32 0, i32 2
+// CHECK-NEXT:    [[HAIRCOUNT12:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP5:%.*]] = load float, ptr [[HAIRCOUNT12]], align 4
+// CHECK-NEXT:    store float [[TMP5]], ptr [[HAIRCOUNT]], align 4
+// CHECK-NEXT:    [[EARDIRECTION:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[DOGS]], i32 0, i32 3
+// CHECK-NEXT:    [[EARDIRECTION13:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION13]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP6:%.*]] = load <4 x float>, ptr [[ARRAYIDX]], align 16
+// CHECK-NEXT:    [[VECEXT14:%.*]] = extractelement <4 x float> [[TMP6]], i64 0
+// CHECK-NEXT:    [[VECINIT15:%.*]] = insertelement <4 x float> poison, float [[VECEXT14]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION16:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX17:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION16]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP7:%.*]] = load <4 x float>, ptr [[ARRAYIDX17]], align 16
+// CHECK-NEXT:    [[VECEXT18:%.*]] = extractelement <4 x float> [[TMP7]], i64 1
+// CHECK-NEXT:    [[VECINIT19:%.*]] = insertelement <4 x float> [[VECINIT15]], float [[VECEXT18]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION20:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX21:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION20]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP8:%.*]] = load <4 x float>, ptr [[ARRAYIDX21]], align 16
+// CHECK-NEXT:    [[VECEXT22:%.*]] = extractelement <4 x float> [[TMP8]], i64 2
+// CHECK-NEXT:    [[VECINIT23:%.*]] = insertelement <4 x float> [[VECINIT19]], float [[VECEXT22]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION24:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX25:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION24]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP9:%.*]] = load <4 x float>, ptr [[ARRAYIDX25]], align 16
+// CHECK-NEXT:    [[VECEXT26:%.*]] = extractelement <4 x float> [[TMP9]], i64 3
+// CHECK-NEXT:    [[VECINIT27:%.*]] = insertelement <4 x float> [[VECINIT23]], float [[VECEXT26]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT27]], ptr [[EARDIRECTION]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds <4 x float>, ptr [[EARDIRECTION]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION28:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX29:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION28]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP10:%.*]] = load <4 x float>, ptr [[ARRAYIDX29]], align 16
+// CHECK-NEXT:    [[VECEXT30:%.*]] = extractelement <4 x float> [[TMP10]], i64 0
+// CHECK-NEXT:    [[VECINIT31:%.*]] = insertelement <4 x float> poison, float [[VECEXT30]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION32:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX33:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION32]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP11:%.*]] = load <4 x float>, ptr [[ARRAYIDX33]], align 16
+// CHECK-NEXT:    [[VECEXT34:%.*]] = extractelement <4 x float> [[TMP11]], i64 1
+// CHECK-NEXT:    [[VECINIT35:%.*]] = insertelement <4 x float> [[VECINIT31]], float [[VECEXT34]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION36:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX37:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION36]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP12:%.*]] = load <4 x float>, ptr [[ARRAYIDX37]], align 16
+// CHECK-NEXT:    [[VECEXT38:%.*]] = extractelement <4 x float> [[TMP12]], i64 2
+// CHECK-NEXT:    [[VECINIT39:%.*]] = insertelement <4 x float> [[VECINIT35]], float [[VECEXT38]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION40:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX41:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION40]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP13:%.*]] = load <4 x float>, ptr [[ARRAYIDX41]], align 16
+// CHECK-NEXT:    [[VECEXT42:%.*]] = extractelement <4 x float> [[TMP13]], i64 3
+// CHECK-NEXT:    [[VECINIT43:%.*]] = insertelement <4 x float> [[VECINIT39]], float [[VECEXT42]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT43]], ptr [[ARRAYINIT_ELEMENT]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT44:%.*]] = getelementptr inbounds [[STRUCT_DOGGO]], ptr [[DOGS]], i32 1
+// CHECK-NEXT:    [[LEGSTATE45:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[ARRAYINIT_ELEMENT44]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGS:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX46:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP14:%.*]] = load i32, ptr [[ARRAYIDX46]], align 16
+// CHECK-NEXT:    [[VECINIT47:%.*]] = insertelement <4 x i32> poison, i32 [[TMP14]], i32 0
+// CHECK-NEXT:    [[LEGS48:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX49:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS48]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP15:%.*]] = load i32, ptr [[ARRAYIDX49]], align 4
+// CHECK-NEXT:    [[VECINIT50:%.*]] = insertelement <4 x i32> [[VECINIT47]], i32 [[TMP15]], i32 1
+// CHECK-NEXT:    [[LEGS51:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX52:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS51]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP16:%.*]] = load i32, ptr [[ARRAYIDX52]], align 8
+// CHECK-NEXT:    [[VECINIT53:%.*]] = insertelement <4 x i32> [[VECINIT50]], i32 [[TMP16]], i32 2
+// CHECK-NEXT:    [[LEGS54:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX55:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS54]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP17:%.*]] = load i32, ptr [[ARRAYIDX55]], align 4
+// CHECK-NEXT:    [[VECINIT56:%.*]] = insertelement <4 x i32> [[VECINIT53]], i32 [[TMP17]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT56]], ptr [[LEGSTATE45]], align 16
+// CHECK-NEXT:    [[TAILSTATE57:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[ARRAYINIT_ELEMENT44]], i32 0, i32 1
+// CHECK-NEXT:    [[STATE:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP18:%.*]] = load i32, ptr [[STATE]], align 16
+// CHECK-NEXT:    store i32 [[TMP18]], ptr [[TAILSTATE57]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT58:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[ARRAYINIT_ELEMENT44]], i32 0, i32 2
+// CHECK-NEXT:    [[COUNTER:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP19:%.*]] = load i64, ptr [[COUNTER]], align 8
+// CHECK-NEXT:    [[CONV:%.*]] = sitofp i64 [[TMP19]] to float
+// CHECK-NEXT:    store float [[CONV]], ptr [[HAIRCOUNT58]], align 4
+// CHECK-NEXT:    [[EARDIRECTION59:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[ARRAYINIT_ELEMENT44]], i32 0, i32 3
+// CHECK-NEXT:    [[LEFTDIR:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP20:%.*]] = load <4 x float>, ptr [[LEFTDIR]], align 16
+// CHECK-NEXT:    [[VECEXT60:%.*]] = extractelement <4 x float> [[TMP20]], i64 0
+// CHECK-NEXT:    [[VECINIT61:%.*]] = insertelement <4 x float> poison, float [[VECEXT60]], i32 0
+// CHECK-NEXT:    [[LEFTDIR62:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP21:%.*]] = load <4 x float>, ptr [[LEFTDIR62]], align 16
+// CHECK-NEXT:    [[VECEXT63:%.*]] = extractelement <4 x float> [[TMP21]], i64 1
+// CHECK-NEXT:    [[VECINIT64:%.*]] = insertelement <4 x float> [[VECINIT61]], float [[VECEXT63]], i32 1
+// CHECK-NEXT:    [[LEFTDIR65:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP22:%.*]] = load <4 x float>, ptr [[LEFTDIR65]], align 16
+// CHECK-NEXT:    [[VECEXT66:%.*]] = extractelement <4 x float> [[TMP22]], i64 2
+// CHECK-NEXT:    [[VECINIT67:%.*]] = insertelement <4 x float> [[VECINIT64]], float [[VECEXT66]], i32 2
+// CHECK-NEXT:    [[LEFTDIR68:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP23:%.*]] = load <4 x float>, ptr [[LEFTDIR68]], align 16
+// CHECK-NEXT:    [[VECEXT69:%.*]] = extractelement <4 x float> [[TMP23]], i64 3
+// CHECK-NEXT:    [[VECINIT70:%.*]] = insertelement <4 x float> [[VECINIT67]], float [[VECEXT69]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT70]], ptr [[EARDIRECTION59]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT71:%.*]] = getelementptr inbounds <4 x float>, ptr [[EARDIRECTION59]], i32 1
+// CHECK-NEXT:    [[RIGHTDIR:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP24:%.*]] = load <4 x float>, ptr [[RIGHTDIR]], align 16
+// CHECK-NEXT:    [[VECEXT72:%.*]] = extractelement <4 x float> [[TMP24]], i64 0
+// CHECK-NEXT:    [[VECINIT73:%.*]] = insertelement <4 x float> poison, float [[VECEXT72]], i32 0
+// CHECK-NEXT:    [[RIGHTDIR74:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP25:%.*]] = load <4 x float>, ptr [[RIGHTDIR74]], align 16
+// CHECK-NEXT:    [[VECEXT75:%.*]] = extractelement <4 x float> [[TMP25]], i64 1
+// CHECK-NEXT:    [[VECINIT76:%.*]] = insertelement <4 x float> [[VECINIT73]], float [[VECEXT75]], i32 1
+// CHECK-NEXT:    [[RIGHTDIR77:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP26:%.*]] = load <4 x float>, ptr [[RIGHTDIR77]], align 16
+// CHECK-NEXT:    [[VECEXT78:%.*]] = extractelement <4 x float> [[TMP26]], i64 2
+// CHECK-NEXT:    [[VECINIT79:%.*]] = insertelement <4 x float> [[VECINIT76]], float [[VECEXT78]], i32 2
+// CHECK-NEXT:    [[RIGHTDIR80:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP27:%.*]] = load <4 x float>, ptr [[RIGHTDIR80]], align 16
+// CHECK-NEXT:    [[VECEXT81:%.*]] = extractelement <4 x float> [[TMP27]], i64 3
+// CHECK-NEXT:    [[VECINIT82:%.*]] = insertelement <4 x float> [[VECINIT79]], float [[VECEXT81]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT82]], ptr [[ARRAYINIT_ELEMENT71]], align 16
+// CHECK-NEXT:    [[CATS:%.*]] = getelementptr inbounds nuw [[STRUCT_ZOO]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[LEGS83:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH:%.*]], ptr [[CATS]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGSTATE84:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP28:%.*]] = load <4 x i32>, ptr [[LEGSTATE84]], align 16
+// CHECK-NEXT:    [[VECEXT85:%.*]] = extractelement <4 x i32> [[TMP28]], i64 0
+// CHECK-NEXT:    [[VECINIT86:%.*]] = insertelement <4 x i32> poison, i32 [[VECEXT85]], i32 0
+// CHECK-NEXT:    [[LEGSTATE87:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP29:%.*]] = load <4 x i32>, ptr [[LEGSTATE87]], align 16
+// CHECK-NEXT:    [[VECEXT88:%.*]] = extractelement <4 x i32> [[TMP29]], i64 1
+// CHECK-NEXT:    [[VECINIT89:%.*]] = insertelement <4 x i32> [[VECINIT86]], i32 [[VECEXT88]], i32 1
+// CHECK-NEXT:    [[LEGSTATE90:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP30:%.*]] = load <4 x i32>, ptr [[LEGSTATE90]], align 16
+// CHECK-NEXT:    [[VECEXT91:%.*]] = extractelement <4 x i32> [[TMP30]], i64 2
+// CHECK-NEXT:    [[VECINIT92:%.*]] = insertelement <4 x i32> [[VECINIT89]], i32 [[VECEXT91]], i32 2
+// CHECK-NEXT:    [[LEGSTATE93:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP31:%.*]] = load <4 x i32>, ptr [[LEGSTATE93]], align 16
+// CHECK-NEXT:    [[VECEXT94:%.*]] = extractelement <4 x i32> [[TMP31]], i64 3
+// CHECK-NEXT:    [[VECINIT95:%.*]] = insertelement <4 x i32> [[VECINIT92]], i32 [[VECEXT94]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT95]], ptr [[LEGS83]], align 16
+// CHECK-NEXT:    [[TAILSTATE96:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[CATS]], i32 0, i32 1
+// CHECK-NEXT:    [[TAILSTATE97:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP32:%.*]] = load i32, ptr [[TAILSTATE97]], align 16
+// CHECK-NEXT:    store i32 [[TMP32]], ptr [[TAILSTATE96]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT98:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[CATS]], i32 0, i32 2
+// CHECK-NEXT:    [[HAIRCOUNT99:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP33:%.*]] = load float, ptr [[HAIRCOUNT99]], align 4
+// CHECK-NEXT:    store float [[TMP33]], ptr [[HAIRCOUNT98]], align 4
+// CHECK-NEXT:    [[CLAWS:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[CATS]], i32 0, i32 3
+// CHECK-NEXT:    [[EARDIRECTION100:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX101:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION100]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP34:%.*]] = load <4 x float>, ptr [[ARRAYIDX101]], align 16
+// CHECK-NEXT:    [[VECEXT102:%.*]] = extractelement <4 x float> [[TMP34]], i64 0
+// CHECK-NEXT:    [[VECINIT103:%.*]] = insertelement <4 x float> poison, float [[VECEXT102]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION104:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX105:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION104]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP35:%.*]] = load <4 x float>, ptr [[ARRAYIDX105]], align 16
+// CHECK-NEXT:    [[VECEXT106:%.*]] = extractelement <4 x float> [[TMP35]], i64 1
+// CHECK-NEXT:    [[VECINIT107:%.*]] = insertelement <4 x float> [[VECINIT103]], float [[VECEXT106]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION108:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX109:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION108]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP36:%.*]] = load <4 x float>, ptr [[ARRAYIDX109]], align 16
+// CHECK-NEXT:    [[VECEXT110:%.*]] = extractelement <4 x float> [[TMP36]], i64 2
+// CHECK-NEXT:    [[VECINIT111:%.*]] = insertelement <4 x float> [[VECINIT107]], float [[VECEXT110]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION112:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX113:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION112]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP37:%.*]] = load <4 x float>, ptr [[ARRAYIDX113]], align 16
+// CHECK-NEXT:    [[VECEXT114:%.*]] = extractelement <4 x float> [[TMP37]], i64 3
+// CHECK-NEXT:    [[VECINIT115:%.*]] = insertelement <4 x float> [[VECINIT111]], float [[VECEXT114]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT115]], ptr [[CLAWS]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT116:%.*]] = getelementptr inbounds <4 x float>, ptr [[CLAWS]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION117:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX118:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION117]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP38:%.*]] = load <4 x float>, ptr [[ARRAYIDX118]], align 16
+// CHECK-NEXT:    [[VECEXT119:%.*]] = extractelement <4 x float> [[TMP38]], i64 0
+// CHECK-NEXT:    [[VECINIT120:%.*]] = insertelement <4 x float> poison, float [[VECEXT119]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION121:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX122:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION121]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP39:%.*]] = load <4 x float>, ptr [[ARRAYIDX122]], align 16
+// CHECK-NEXT:    [[VECEXT123:%.*]] = extractelement <4 x float> [[TMP39]], i64 1
+// CHECK-NEXT:    [[VECINIT124:%.*]] = insertelement <4 x float> [[VECINIT120]], float [[VECEXT123]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION125:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX126:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION125]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP40:%.*]] = load <4 x float>, ptr [[ARRAYIDX126]], align 16
+// CHECK-NEXT:    [[VECEXT127:%.*]] = extractelement <4 x float> [[TMP40]], i64 2
+// CHECK-NEXT:    [[VECINIT128:%.*]] = insertelement <4 x float> [[VECINIT124]], float [[VECEXT127]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION129:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX130:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION129]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP41:%.*]] = load <4 x float>, ptr [[ARRAYIDX130]], align 16
+// CHECK-NEXT:    [[VECEXT131:%.*]] = extractelement <4 x float> [[TMP41]], i64 3
+// CHECK-NEXT:    [[VECINIT132:%.*]] = insertelement <4 x float> [[VECINIT128]], float [[VECEXT131]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT132]], ptr [[ARRAYINIT_ELEMENT116]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT133:%.*]] = getelementptr inbounds [[STRUCT_KITTEH]], ptr [[CATS]], i32 1
+// CHECK-NEXT:    [[LEGS134:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT133]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGS135:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX136:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS135]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP42:%.*]] = load i32, ptr [[ARRAYIDX136]], align 16
+// CHECK-NEXT:    [[VECINIT137:%.*]] = insertelement <4 x i32> poison, i32 [[TMP42]], i32 0
+// CHECK-NEXT:    [[LEGS138:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX139:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS138]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP43:%.*]] = load i32, ptr [[ARRAYIDX139]], align 4
+// CHECK-NEXT:    [[VECINIT140:%.*]] = insertelement <4 x i32> [[VECINIT137]], i32 [[TMP43]], i32 1
+// CHECK-NEXT:    [[LEGS141:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX142:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS141]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP44:%.*]] = load i32, ptr [[ARRAYIDX142]], align 8
+// CHECK-NEXT:    [[VECINIT143:%.*]] = insertelement <4 x i32> [[VECINIT140]], i32 [[TMP44]], i32 2
+// CHECK-NEXT:    [[LEGS144:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX145:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS144]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP45:%.*]] = load i32, ptr [[ARRAYIDX145]], align 4
+// CHECK-NEXT:    [[VECINIT146:%.*]] = insertelement <4 x i32> [[VECINIT143]], i32 [[TMP45]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT146]], ptr [[LEGS134]], align 16
+// CHECK-NEXT:    [[TAILSTATE147:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT133]], i32 0, i32 1
+// CHECK-NEXT:    [[STATE148:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP46:%.*]] = load i32, ptr [[STATE148]], align 16
+// CHECK-NEXT:    store i32 [[TMP46]], ptr [[TAILSTATE147]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT149:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT133]], i32 0, i32 2
+// CHECK-NEXT:    [[COUNTER150:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP47:%.*]] = load i64, ptr [[COUNTER150]], align 8
+// CHECK-NEXT:    [[CONV151:%.*]] = sitofp i64 [[TMP47]] to float
+// CHECK-NEXT:    store float [[CONV151]], ptr [[HAIRCOUNT149]], align 4
+// CHECK-NEXT:    [[CLAWS152:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT133]], i32 0, i32 3
+// CHECK-NEXT:    [[LEFTDIR153:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP48:%.*]] = load <4 x float>, ptr [[LEFTDIR153]], align 16
+// CHECK-NEXT:    [[VECEXT154:%.*]] = extractelement <4 x float> [[TMP48]], i64 0
+// CHECK-NEXT:    [[VECINIT155:%.*]] = insertelement <4 x float> poison, float [[VECEXT154]], i32 0
+// CHECK-NEXT:    [[LEFTDIR156:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP49:%.*]] = load <4 x float>, ptr [[LEFTDIR156]], align 16
+// CHECK-NEXT:    [[VECEXT157:%.*]] = extractelement <4 x float> [[TMP49]], i64 1
+// CHECK-NEXT:    [[VECINIT158:%.*]] = insertelement <4 x float> [[VECINIT155]], float [[VECEXT157]], i32 1
+// CHECK-NEXT:    [[LEFTDIR159:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP50:%.*]] = load <4 x float>, ptr [[LEFTDIR159]], align 16
+// CHECK-NEXT:    [[VECEXT160:%.*]] = extractelement <4 x float> [[TMP50]], i64 2
+// CHECK-NEXT:    [[VECINIT161:%.*]] = insertelement <4 x float> [[VECINIT158]], float [[VECEXT160]], i32 2
+// CHECK-NEXT:    [[LEFTDIR162:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP51:%.*]] = load <4 x float>, ptr [[LEFTDIR162]], align 16
+// CHECK-NEXT:    [[VECEXT163:%.*]] = extractelement <4 x float> [[TMP51]], i64 3
+// CHECK-NEXT:    [[VECINIT164:%.*]] = insertelement <4 x float> [[VECINIT161]], float [[VECEXT163]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT164]], ptr [[CLAWS152]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT165:%.*]] = getelementptr inbounds <4 x float>, ptr [[CLAWS152]], i32 1
+// CHECK-NEXT:    [[RIGHTDIR166:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP52:%.*]] = load <4 x float>, ptr [[RIGHTDIR166]], align 16
+// CHECK-NEXT:    [[VECEXT167:%.*]] = extractelement <4 x float> [[TMP52]], i64 0
+// CHECK-NEXT:    [[VECINIT168:%.*]] = insertelement <4 x float> poison, float [[VECEXT167]], i32 0
+// CHECK-NEXT:    [[RIGHTDIR169:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP53:%.*]] = load <4 x float>, ptr [[RIGHTDIR169]], align 16
+// CHECK-NEXT:    [[VECEXT170:%.*]] = extractelement <4 x float> [[TMP53]], i64 1
+// CHECK-NEXT:    [[VECINIT171:%.*]] = insertelement <4 x float> [[VECINIT168]], float [[VECEXT170]], i32 1
+// CHECK-NEXT:    [[RIGHTDIR172:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP54:%.*]] = load <4 x float>, ptr [[RIGHTDIR172]], align 16
+// CHECK-NEXT:    [[VECEXT173:%.*]] = extractelement <4 x float> [[TMP54]], i64 2
+// CHECK-NEXT:    [[VECINIT174:%.*]] = insertelement <4 x float> [[VECINIT171]], float [[VECEXT173]], i32 2
+// CHECK-NEXT:    [[RIGHTDIR175:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP55:%.*]] = load <4 x float>, ptr [[RIGHTDIR175]], align 16
+// CHECK-NEXT:    [[VECEXT176:%.*]] = extractelement <4 x float> [[TMP55]], i64 3
+// CHECK-NEXT:    [[VECINIT177:%.*]] = insertelement <4 x float> [[VECINIT174]], float [[VECEXT176]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT177]], ptr [[ARRAYINIT_ELEMENT165]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT178:%.*]] = getelementptr inbounds [[STRUCT_KITTEH]], ptr [[CATS]], i32 2
+// CHECK-NEXT:    [[LEGS179:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT178]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGSTATE180:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP56:%.*]] = load <4 x i32>, ptr [[LEGSTATE180]], align 16
+// CHECK-NEXT:    [[VECEXT181:%.*]] = extractelement <4 x i32> [[TMP56]], i64 0
+// CHECK-NEXT:    [[VECINIT182:%.*]] = insertelement <4 x i32> poison, i32 [[VECEXT181]], i32 0
+// CHECK-NEXT:    [[LEGSTATE183:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP57:%.*]] = load <4 x i32>, ptr [[LEGSTATE183]], align 16
+// CHECK-NEXT:    [[VECEXT184:%.*]] = extractelement <4 x i32> [[TMP57]], i64 1
+// CHECK-NEXT:    [[VECINIT185:%.*]] = insertelement <4 x i32> [[VECINIT182]], i32 [[VECEXT184]], i32 1
+// CHECK-NEXT:    [[LEGSTATE186:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP58:%.*]] = load <4 x i32>, ptr [[LEGSTATE186]], align 16
+// CHECK-NEXT:    [[VECEXT187:%.*]] = extractelement <4 x i32> [[TMP58]], i64 2
+// CHECK-NEXT:    [[VECINIT188:%.*]] = insertelement <4 x i32> [[VECINIT185]], i32 [[VECEXT187]], i32 2
+// CHECK-NEXT:    [[LEGSTATE189:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP59:%.*]] = load <4 x i32>, ptr [[LEGSTATE189]], align 16
+// CHECK-NEXT:    [[VECEXT190:%.*]] = extractelement <4 x i32> [[TMP59]], i64 3
+// CHECK-NEXT:    [[VECINIT191:%.*]] = insertelement <4 x i32> [[VECINIT188]], i32 [[VECEXT190]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT191]], ptr [[LEGS179]], align 16
+// CHECK-NEXT:    [[TAILSTATE192:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT178]], i32 0, i32 1
+// CHECK-NEXT:    [[TAILSTATE193:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP60:%.*]] = load i32, ptr [[TAILSTATE193]], align 16
+// CHECK-NEXT:    store i32 [[TMP60]], ptr [[TAILSTATE192]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT194:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT178]], i32 0, i32 2
+// CHECK-NEXT:    [[HAIRCOUNT195:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP61:%.*]] = load float, ptr [[HAIRCOUNT195]], align 4
+// CHECK-NEXT:    store float [[TMP61]], ptr [[HAIRCOUNT194]], align 4
+// CHECK-NEXT:    [[CLAWS196:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT178]], i32 0, i32 3
+// CHECK-NEXT:    [[EARDIRECTION197:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX198:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION197]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP62:%.*]] = load <4 x float>, ptr [[ARRAYIDX198]], align 16
+// CHECK-NEXT:    [[VECEXT199:%.*]] = extractelement <4 x float> [[TMP62]], i64 0
+// CHECK-NEXT:    [[VECINIT200:%.*]] = insertelement <4 x float> poison, float [[VECEXT199]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION201:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX202:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION201]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP63:%.*]] = load <4 x float>, ptr [[ARRAYIDX202]], align 16
+// CHECK-NEXT:    [[VECEXT203:%.*]] = extractelement <4 x float> [[TMP63]], i64 1
+// CHECK-NEXT:    [[VECINIT204:%.*]] = insertelement <4 x float> [[VECINIT200]], float [[VECEXT203]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION205:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX206:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION205]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP64:%.*]] = load <4 x float>, ptr [[ARRAYIDX206]], align 16
+// CHECK-NEXT:    [[VECEXT207:%.*]] = extractelement <4 x float> [[TMP64]], i64 2
+// CHECK-NEXT:    [[VECINIT208:%.*]] = insertelement <4 x float> [[VECINIT204]], float [[VECEXT207]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION209:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX210:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION209]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP65:%.*]] = load <4 x float>, ptr [[ARRAYIDX210]], align 16
+// CHECK-NEXT:    [[VECEXT211:%.*]] = extractelement <4 x float> [[TMP65]], i64 3
+// CHECK-NEXT:    [[VECINIT212:%.*]] = insertelement <4 x float> [[VECINIT208]], float [[VECEXT211]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT212]], ptr [[CLAWS196]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT213:%.*]] = getelementptr inbounds <4 x float>, ptr [[CLAWS196]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION214:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX215:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION214]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP66:%.*]] = load <4 x float>, ptr [[ARRAYIDX215]], align 16
+// CHECK-NEXT:    [[VECEXT216:%.*]] = extractelement <4 x float> [[TMP66]], i64 0
+// CHECK-NEXT:    [[VECINIT217:%.*]] = insertelement <4 x float> poison, float [[VECEXT216]], i32 0
+// CHECK-NEXT:    [[EARDIRECTION218:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX219:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION218]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP67:%.*]] = load <4 x float>, ptr [[ARRAYIDX219]], align 16
+// CHECK-NEXT:    [[VECEXT220:%.*]] = extractelement <4 x float> [[TMP67]], i64 1
+// CHECK-NEXT:    [[VECINIT221:%.*]] = insertelement <4 x float> [[VECINIT217]], float [[VECEXT220]], i32 1
+// CHECK-NEXT:    [[EARDIRECTION222:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX223:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION222]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP68:%.*]] = load <4 x float>, ptr [[ARRAYIDX223]], align 16
+// CHECK-NEXT:    [[VECEXT224:%.*]] = extractelement <4 x float> [[TMP68]], i64 2
+// CHECK-NEXT:    [[VECINIT225:%.*]] = insertelement <4 x float> [[VECINIT221]], float [[VECEXT224]], i32 2
+// CHECK-NEXT:    [[EARDIRECTION226:%.*]] = getelementptr inbounds nuw [[STRUCT_DOGGO]], ptr [[D1]], i32 0, i32 3
+// CHECK-NEXT:    [[ARRAYIDX227:%.*]] = getelementptr inbounds nuw [2 x <4 x float>], ptr [[EARDIRECTION226]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP69:%.*]] = load <4 x float>, ptr [[ARRAYIDX227]], align 16
+// CHECK-NEXT:    [[VECEXT228:%.*]] = extractelement <4 x float> [[TMP69]], i64 3
+// CHECK-NEXT:    [[VECINIT229:%.*]] = insertelement <4 x float> [[VECINIT225]], float [[VECEXT228]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT229]], ptr [[ARRAYINIT_ELEMENT213]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT230:%.*]] = getelementptr inbounds [[STRUCT_KITTEH]], ptr [[CATS]], i32 3
+// CHECK-NEXT:    [[LEGS231:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT230]], i32 0, i32 0
+// CHECK-NEXT:    [[LEGS232:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX233:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS232]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP70:%.*]] = load i32, ptr [[ARRAYIDX233]], align 16
+// CHECK-NEXT:    [[VECINIT234:%.*]] = insertelement <4 x i32> poison, i32 [[TMP70]], i32 0
+// CHECK-NEXT:    [[LEGS235:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX236:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS235]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP71:%.*]] = load i32, ptr [[ARRAYIDX236]], align 4
+// CHECK-NEXT:    [[VECINIT237:%.*]] = insertelement <4 x i32> [[VECINIT234]], i32 [[TMP71]], i32 1
+// CHECK-NEXT:    [[LEGS238:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX239:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS238]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP72:%.*]] = load i32, ptr [[ARRAYIDX239]], align 8
+// CHECK-NEXT:    [[VECINIT240:%.*]] = insertelement <4 x i32> [[VECINIT237]], i32 [[TMP72]], i32 2
+// CHECK-NEXT:    [[LEGS241:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 0
+// CHECK-NEXT:    [[ARRAYIDX242:%.*]] = getelementptr inbounds nuw [4 x i32], ptr [[LEGS241]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP73:%.*]] = load i32, ptr [[ARRAYIDX242]], align 4
+// CHECK-NEXT:    [[VECINIT243:%.*]] = insertelement <4 x i32> [[VECINIT240]], i32 [[TMP73]], i32 3
+// CHECK-NEXT:    store <4 x i32> [[VECINIT243]], ptr [[LEGS231]], align 16
+// CHECK-NEXT:    [[TAILSTATE244:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT230]], i32 0, i32 1
+// CHECK-NEXT:    [[STATE245:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP74:%.*]] = load i32, ptr [[STATE245]], align 16
+// CHECK-NEXT:    store i32 [[TMP74]], ptr [[TAILSTATE244]], align 16
+// CHECK-NEXT:    [[HAIRCOUNT246:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT230]], i32 0, i32 2
+// CHECK-NEXT:    [[COUNTER247:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP75:%.*]] = load i64, ptr [[COUNTER247]], align 8
+// CHECK-NEXT:    [[CONV248:%.*]] = sitofp i64 [[TMP75]] to float
+// CHECK-NEXT:    store float [[CONV248]], ptr [[HAIRCOUNT246]], align 4
+// CHECK-NEXT:    [[CLAWS249:%.*]] = getelementptr inbounds nuw [[STRUCT_KITTEH]], ptr [[ARRAYINIT_ELEMENT230]], i32 0, i32 3
+// CHECK-NEXT:    [[LEFTDIR250:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP76:%.*]] = load <4 x float>, ptr [[LEFTDIR250]], align 16
+// CHECK-NEXT:    [[VECEXT251:%.*]] = extractelement <4 x float> [[TMP76]], i64 0
+// CHECK-NEXT:    [[VECINIT252:%.*]] = insertelement <4 x float> poison, float [[VECEXT251]], i32 0
+// CHECK-NEXT:    [[LEFTDIR253:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP77:%.*]] = load <4 x float>, ptr [[LEFTDIR253]], align 16
+// CHECK-NEXT:    [[VECEXT254:%.*]] = extractelement <4 x float> [[TMP77]], i64 1
+// CHECK-NEXT:    [[VECINIT255:%.*]] = insertelement <4 x float> [[VECINIT252]], float [[VECEXT254]], i32 1
+// CHECK-NEXT:    [[LEFTDIR256:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP78:%.*]] = load <4 x float>, ptr [[LEFTDIR256]], align 16
+// CHECK-NEXT:    [[VECEXT257:%.*]] = extractelement <4 x float> [[TMP78]], i64 2
+// CHECK-NEXT:    [[VECINIT258:%.*]] = insertelement <4 x float> [[VECINIT255]], float [[VECEXT257]], i32 2
+// CHECK-NEXT:    [[LEFTDIR259:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 3
+// CHECK-NEXT:    [[TMP79:%.*]] = load <4 x float>, ptr [[LEFTDIR259]], align 16
+// CHECK-NEXT:    [[VECEXT260:%.*]] = extractelement <4 x float> [[TMP79]], i64 3
+// CHECK-NEXT:    [[VECINIT261:%.*]] = insertelement <4 x float> [[VECINIT258]], float [[VECEXT260]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT261]], ptr [[CLAWS249]], align 16
+// CHECK-NEXT:    [[ARRAYINIT_ELEMENT262:%.*]] = getelementptr inbounds <4 x float>, ptr [[CLAWS249]], i32 1
+// CHECK-NEXT:    [[RIGHTDIR263:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP80:%.*]] = load <4 x float>, ptr [[RIGHTDIR263]], align 16
+// CHECK-NEXT:    [[VECEXT264:%.*]] = extractelement <4 x float> [[TMP80]], i64 0
+// CHECK-NEXT:    [[VECINIT265:%.*]] = insertelement <4 x float> poison, float [[VECEXT264]], i32 0
+// CHECK-NEXT:    [[RIGHTDIR266:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP81:%.*]] = load <4 x float>, ptr [[RIGHTDIR266]], align 16
+// CHECK-NEXT:    [[VECEXT267:%.*]] = extractelement <4 x float> [[TMP81]], i64 1
+// CHECK-NEXT:    [[VECINIT268:%.*]] = insertelement <4 x float> [[VECINIT265]], float [[VECEXT267]], i32 1
+// CHECK-NEXT:    [[RIGHTDIR269:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP82:%.*]] = load <4 x float>, ptr [[RIGHTDIR269]], align 16
+// CHECK-NEXT:    [[VECEXT270:%.*]] = extractelement <4 x float> [[TMP82]], i64 2
+// CHECK-NEXT:    [[VECINIT271:%.*]] = insertelement <4 x float> [[VECINIT268]], float [[VECEXT270]], i32 2
+// CHECK-NEXT:    [[RIGHTDIR272:%.*]] = getelementptr inbounds nuw [[STRUCT_ANIMALBITS]], ptr [[A1]], i32 0, i32 4
+// CHECK-NEXT:    [[TMP83:%.*]] = load <4 x float>, ptr [[RIGHTDIR272]], align 16
+// CHECK-NEXT:    [[VECEXT273:%.*]] = extractelement <4 x float> [[TMP83]], i64 3
+// CHECK-NEXT:    [[VECINIT274:%.*]] = insertelement <4 x float> [[VECINIT271]], float [[VECEXT273]], i32 3
+// CHECK-NEXT:    store <4 x float> [[VECINIT274]], ptr [[ARRAYINIT_ELEMENT262]], align 16
+// CHECK-NEXT:    ret void
+//
+Zoo case9(Doggo D1, AnimalBits A1) {
+  Zoo Z1 = {D1, A1, D1, A1, D1, A1};
+  return Z1;
+}
diff --git a/clang/test/SemaHLSL/ArrayTemporary.hlsl b/clang/test/SemaHLSL/ArrayTemporary.hlsl
index 0266a198e7ec9..3d713a89adf3b 100644
--- a/clang/test/SemaHLSL/ArrayTemporary.hlsl
+++ b/clang/test/SemaHLSL/ArrayTemporary.hlsl
@@ -25,7 +25,7 @@ void fn2(Obj O[4]) { }
 // CHECK-NEXT: ImplicitCastExpr {{.*}} 'Obj[4]' <HLSLArrayRValue>
 
 void call2() {
-  Obj Arr[4] = {};
+  Obj Arr[4] = {0, 0, 0, 0, 0, 0, 0, 0};
   fn2(Arr);
 }
 
diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl
new file mode 100644
index 0000000000000..0059e5b44035f
--- /dev/null
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -0,0 +1,69 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -finclude-default-header -verify -Wdouble-promotion -Wconversion %s
+
+struct TwoFloats {
+  float X, Y;
+};
+
+struct TwoInts {
+  int Z, W;
+};
+
+struct Doggo {
+  int4 LegState;
+  int TailState;
+  float HairCount;
+  float4 EarDirection[2];
+};
+
+struct AnimalBits {
+  int Legs[4];
+  uint State;
+  int64_t Counter;
+  float4 LeftDir;
+  float4 RightDir;
+};
+
+struct Kitteh {
+  int4 Legs;
+  int TailState;
+  float HairCount;
+  float4 Claws[2];
+};
+
+struct Zoo {
+  Doggo Dogs[2];
+  Kitteh Cats[4];
+};
+
+void fn() {
+  TwoFloats TF1 = {{{1.0, 2}}};
+  TwoFloats TF2 = {1,2};
+  int Val = 1;
+  TwoFloats TF3 = {Val, 2}; // expected-warning{{implicit conversion from 'int' to 'float' may lose precision}}
+  int2 TwoVals = 1.xx;
+  int2 Something = 1.xxx; // expected-warning{{implicit conversion truncates vector: 'vector<int, 3>' (vector of 3 'int' values) to 'vector<int, 2>' (vector of 2 'int' values)}}
+  TwoFloats TF4 = {TwoVals}; // expected-warning{{implicit conversion from 'int' to 'float' may lose precision}} expected-warning{{implicit conversion from 'int' to 'float' may lose precision}}
+
+  TwoInts TI1 = {TwoVals};
+  TwoInts TI2 = {TF4}; // expected-warning{{implicit conversion turns floating-point number into integer: 'float' to 'int'}} expected-warning{{implicit conversion turns floating-point number into integer: 'float' to 'int'}}
+
+  Doggo D1 = {TI1, TI2, {Val, Val}, {{TF1, TF2}, {TF3, TF4}}}; // expected-warning{{implicit conversion from 'int' to 'float' may lose precision}}
+  AnimalBits A1 = {D1}; // expected-warning{{implicit conversion turns floating-point number into integer: 'float' to 'long'}} expected-warning{{implicit conversion changes signedness: 'int' to 'unsigned int'}}
+
+  Zoo Z1 = {D1, A1, D1, A1, D1, A1}; // #insanity
+
+  // expected-warning@#insanity{{implicit conversion from 'int64_t' (aka 'long') to 'float' may lose precision}}
+  // expected-warning@#insanity{{implicit conversion changes signedness: 'uint' (aka 'unsigned int') to 'int'}}
+  // expected-warning@#insanity{{implicit conversion from 'int64_t' (aka 'long') to 'float' may lose precision}}
+  // expected-warning@#insanity{{implicit conversion changes signedness: 'uint' (aka 'unsigned int') to 'int'}}
+  // expected-warning@#insanity{{implicit conversion from 'int64_t' (aka 'long') to 'float' may lose precision}}
+  // expected-warning@#insanity{{implicit conversion changes signedness: 'uint' (aka 'unsigned int') to 'int'}}
+}
+
+void Errs() {
+  TwoFloats F1 = {}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 0)}}
+  TwoFloats F2 = {1}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 1)}}
+  TwoFloats F3 = {1,2,3}; // expected-error{{too many initializers in list for type 'TwoFloats' (expected 2 but found 2)}}
+
+  int2 Something = {1.xxx}; // expected-error{{too many initializers in list for type 'int2' (aka 'vector<int, 2>') (expected 2 but found 0)}}
+}

>From 859ddab3bd5c648e5d598997f8278109628a7a46 Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Mon, 10 Feb 2025 15:01:47 -0600
Subject: [PATCH 02/16] Update clang/test/SemaHLSL/Language/InitLists.hlsl

Doh!

Co-authored-by: Finn Plummer <50529406+inbelic at users.noreply.github.com>
---
 clang/test/SemaHLSL/Language/InitLists.hlsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 0059e5b44035f..1f7baf35ed2e3 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -63,7 +63,7 @@ void fn() {
 void Errs() {
   TwoFloats F1 = {}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 0)}}
   TwoFloats F2 = {1}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 1)}}
-  TwoFloats F3 = {1,2,3}; // expected-error{{too many initializers in list for type 'TwoFloats' (expected 2 but found 2)}}
+  TwoFloats F3 = {1,2,3}; // expected-error{{too many initializers in list for type 'TwoFloats' (expected 2 but found 3)}}
 
   int2 Something = {1.xxx}; // expected-error{{too many initializers in list for type 'int2' (aka 'vector<int, 2>') (expected 2 but found 0)}}
 }

>From afd3e8651d0c1b5cae14580b978cddfaba2c7728 Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Mon, 10 Feb 2025 15:02:21 -0600
Subject: [PATCH 03/16] Update clang/lib/Sema/SemaHLSL.cpp

I swear I can spell...

Co-authored-by: Helena Kotas <hekotas at microsoft.com>
---
 clang/lib/Sema/SemaHLSL.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 2e1d8bd43bde9..12c81e34f9c70 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3073,7 +3073,7 @@ static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
   return true;
 }
 
-static void BuildIntializerList(Sema &S, ASTContext &Ctx, Expr *E,
+static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
                                 llvm::SmallVectorImpl<Expr *> &List,
                                 llvm::SmallVectorImpl<QualType> &DestTypes,
                                 bool &ExcessInits) {

>From e5d36ff8563fbadd4bad663d1157da38e149547b Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Mon, 10 Feb 2025 15:06:25 -0600
Subject: [PATCH 04/16] Update clang/test/SemaHLSL/Language/InitLists.hlsl

Co-authored-by: Finn Plummer <50529406+inbelic at users.noreply.github.com>
---
 clang/test/SemaHLSL/Language/InitLists.hlsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 1f7baf35ed2e3..79ba126758589 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -65,5 +65,5 @@ void Errs() {
   TwoFloats F2 = {1}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 1)}}
   TwoFloats F3 = {1,2,3}; // expected-error{{too many initializers in list for type 'TwoFloats' (expected 2 but found 3)}}
 
-  int2 Something = {1.xxx}; // expected-error{{too many initializers in list for type 'int2' (aka 'vector<int, 2>') (expected 2 but found 0)}}
+  int2 Something = {1.xxx}; // expected-error{{too many initializers in list for type 'int2' (aka 'vector<int, 2>') (expected 2 but found 3)}}
 }

>From 74f50040c51b46a08de1c8474c237e811c794db8 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Mon, 10 Feb 2025 17:25:38 -0600
Subject: [PATCH 05/16] Updates to fix diagnostics and adjust to new upstream
 changes

More updates coming to handle additional PR review.
---
 clang/lib/Sema/SemaHLSL.cpp | 39 +++++++++++++++++--------------------
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 12c81e34f9c70..77750b250b644 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3060,12 +3060,13 @@ void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
 static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
                             llvm::SmallVectorImpl<Expr *> &List,
                             llvm::SmallVectorImpl<QualType> &DestTypes) {
-  if (List.size() >= DestTypes.size())
-    return false;
-  InitializedEntity Entity =
-      InitializedEntity::InitializeParameter(Ctx, DestTypes[List.size()], false);
-  ExprResult Res =
-      S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
+  if (List.size() >= DestTypes.size()) {
+    List.push_back(E);
+    return true;
+  }
+  InitializedEntity Entity = InitializedEntity::InitializeParameter(
+      Ctx, DestTypes[List.size()], false);
+  ExprResult Res = S.PerformCopyInitialization(Entity, E->getBeginLoc(), E);
   if (Res.isInvalid())
     return false;
   Expr *Init = Res.get();
@@ -3074,18 +3075,16 @@ static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
 }
 
 static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
-                                llvm::SmallVectorImpl<Expr *> &List,
-                                llvm::SmallVectorImpl<QualType> &DestTypes,
-                                bool &ExcessInits) {
-  if (List.size() >= DestTypes.size()) {
+                                 llvm::SmallVectorImpl<Expr *> &List,
+                                 llvm::SmallVectorImpl<QualType> &DestTypes,
+                                 bool &ExcessInits) {
+  if (List.size() >= DestTypes.size())
     ExcessInits = true;
-    return;
-  }
 
   // If this is an initialization list, traverse the sub initializers.
   if (auto *Init = dyn_cast<InitListExpr>(E)) {
     for (auto *SubInit : Init->inits())
-      BuildIntializerList(S, Ctx, SubInit, List, DestTypes, ExcessInits);
+      BuildInitializerList(S, Ctx, SubInit, List, DestTypes, ExcessInits);
     return;
   }
 
@@ -3099,10 +3098,8 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
   if (auto *ATy = Ty->getAs<VectorType>()) {
     uint64_t Size = ATy->getNumElements();
 
-    if (List.size() + Size > DestTypes.size()) {
+    if (List.size() + Size > DestTypes.size())
       ExcessInits = true;
-      return;
-    }
     QualType SizeTy = Ctx.getSizeType();
     uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
     for (uint64_t I = 0; I < Size; ++I) {
@@ -3113,8 +3110,7 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
           E, E->getBeginLoc(), Idx, E->getEndLoc());
       if (ElExpr.isInvalid())
         return;
-      if (!CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes))
-        return;
+      CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes);
     }
     return;
   }
@@ -3130,7 +3126,7 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
           E, E->getBeginLoc(), Idx, E->getEndLoc());
       if (ElExpr.isInvalid())
         return;
-      BuildIntializerList(S, Ctx, ElExpr.get(), List, DestTypes, ExcessInits);
+      BuildInitializerList(S, Ctx, ElExpr.get(), List, DestTypes, ExcessInits);
     }
     return;
   }
@@ -3143,7 +3139,7 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
           E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
       if (Res.isInvalid())
         return;
-      BuildIntializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
+      BuildInitializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
     }
   }
 }
@@ -3155,6 +3151,7 @@ static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
   }
   llvm::SmallVector<Expr *> Inits;
   assert(!isa<MatrixType>(Ty) && "Matrix types not yet supported in HLSL");
+  Ty = Ty.getDesugaredType(Ctx);
   if (Ty->isVectorType() || Ty->isConstantArrayType()) {
     QualType ElTy;
     uint64_t Size = 0;
@@ -3197,7 +3194,7 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
   llvm::SmallVector<Expr *, 16> ArgExprs;
   bool ExcessInits = false;
   for (Expr *Arg : Init->inits())
-    BuildIntializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes, ExcessInits);
+    BuildInitializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes, ExcessInits);
 
   if (DestTypes.size() != ArgExprs.size() || ExcessInits) {
     int TooManyOrFew = ExcessInits ? 1 : 0;

>From bd1c29e921d137ae4e2f35aa974735dae07c5b2c Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Tue, 11 Feb 2025 14:44:59 -0600
Subject: [PATCH 06/16] Update to support classes with base classes

Also added tests for bitfield members to verify correct code generation
for initializing bitfield members or initializing new objects from
bitfields.

../clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
---
 clang/lib/AST/DeclCXX.cpp                     |   8 +
 clang/lib/Sema/SemaHLSL.cpp                   |  44 +++-
 .../CodeGenHLSL/BasicFeatures/InitLists.hlsl  | 189 ++++++++++++++++++
 clang/test/SemaHLSL/Language/InitLists.hlsl   |  20 ++
 4 files changed, 250 insertions(+), 11 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index e394e0515e599..64499576af955 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1462,6 +1462,14 @@ void CXXRecordDecl::addedMember(Decl *D) {
     if (Using->getDeclName().getCXXOverloadedOperator() == OO_Equal)
       data().HasInheritedAssignment = true;
   }
+
+  // HLSL: All user-defined data types are aggregates and use aggregate
+  // initialization. This _needs_ to change in the future. There are two
+  // relevant HLSL feature proposals that will depend on this changing:
+  // * 0005-strict-initializer-lists.md
+  // * https://github.com/microsoft/hlsl-specs/pull/325
+  if (getLangOpts().HLSL && !isImplicit())
+    data().Aggregate = true;
 }
 
 bool CXXRecordDecl::isLiteral() const {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 77750b250b644..c50dbf5ec4db8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3132,14 +3132,25 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
   }
 
   if (auto *RTy = Ty->getAs<RecordType>()) {
-    for (auto *FD : RTy->getDecl()->fields()) {
-      DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
-      DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
-      ExprResult Res = S.BuildFieldReferenceExpr(
-          E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
-      if (Res.isInvalid())
-        return;
-      BuildInitializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
+    llvm::SmallVector<const RecordType*> RecordTypes;
+    RecordTypes.push_back(RTy);
+    while(RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+      CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+      assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance");
+      RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+    }
+    while (!RecordTypes.empty()) {
+      const RecordType* RT = RecordTypes.back();
+      RecordTypes.pop_back();
+      for (auto *FD : RT->getDecl()->fields()) {
+        DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
+        DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc());
+        ExprResult Res = S.BuildFieldReferenceExpr(
+            E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
+        if (Res.isInvalid())
+          return;
+        BuildInitializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
+      }
     }
   }
 }
@@ -3166,9 +3177,20 @@ static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
     for (uint64_t I = 0; I < Size; ++I)
       Inits.push_back(GenerateInitLists(Ctx, ElTy, It));
   }
-  if (const RecordDecl *RD = Ty->getAsRecordDecl()) {
-    for (auto *FD : RD->fields()) {
-      Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
+  if (auto *RTy = Ty->getAs<RecordType>()) {
+    llvm::SmallVector<const RecordType*> RecordTypes;
+    RecordTypes.push_back(RTy);
+    while(RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+      CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
+      assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance");
+      RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
+    }
+    while (!RecordTypes.empty()) {
+      const RecordType* RT = RecordTypes.back();
+      RecordTypes.pop_back();
+      for (auto *FD : RT->getDecl()->fields()) {
+        Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));
+      }
     }
   }
   auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(),
diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
index e57724b0ec31f..97baac3272a66 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -36,6 +36,15 @@ struct Zoo {
   Kitteh Cats[4];
 };
 
+struct FourFloats : TwoFloats {
+  float Z, W;
+};
+
+struct SlicyBits {
+  int Z : 8;
+  int W : 8;
+};
+
 // Case 1: Extraneous braces get ignored in literal instantiation.
 // CHECK-LABEL: define void @_Z5case1v(
 // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0:[0-9]+]] {
@@ -712,3 +721,183 @@ Zoo case9(Doggo D1, AnimalBits A1) {
   Zoo Z1 = {D1, A1, D1, A1, D1, A1};
   return Z1;
 }
+
+// Case 10: Initialize an object with a base class from two objects.
+// CHECK-LABEL: define void @_Z6case109TwoFloatsS_(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 4 [[TF1:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF2:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF1]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[X1]], align 4
+// CHECK-NEXT:    store float [[TMP0]], ptr [[X]], align 4
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[Y2:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF1]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[Y2]], align 4
+// CHECK-NEXT:    store float [[TMP1]], ptr [[Y]], align 4
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[X3:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF2]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load float, ptr [[X3]], align 4
+// CHECK-NEXT:    store float [[TMP2]], ptr [[Z]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 2
+// CHECK-NEXT:    [[Y4:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[TF2]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[Y4]], align 4
+// CHECK-NEXT:    store float [[TMP3]], ptr [[W]], align 4
+// CHECK-NEXT:    ret void
+//
+FourFloats case10(TwoFloats TF1, TwoFloats TF2) {
+  FourFloats FF1 = {TF1, TF2};
+  return FF1;
+}
+
+// Case 11: Initialize an object with a base class from a vector splat.
+// CHECK-LABEL: define void @_Z6case11f(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], float noundef nofpclass(nan inf) [[F:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[F_ADDR:%.*]] = alloca float, align 4
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT:    [[REF_TMP1:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT:    [[REF_TMP4:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT:    [[REF_TMP7:%.*]] = alloca <4 x float>, align 16
+// CHECK-NEXT:    store float [[F]], ptr [[F_ADDR]], align 4
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS:%.*]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[F_ADDR]], align 4
+// CHECK-NEXT:    [[CAST_SPLAT:%.*]] = insertelement <1 x float> poison, float [[TMP0]], i64 0
+// CHECK-NEXT:    [[TMP1:%.*]] = shufflevector <1 x float> [[CAST_SPLAT]], <1 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT:    store <4 x float> [[TMP1]], ptr [[REF_TMP]], align 16
+// CHECK-NEXT:    [[TMP2:%.*]] = load <4 x float>, ptr [[REF_TMP]], align 16
+// CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <4 x float> [[TMP2]], i64 0
+// CHECK-NEXT:    store float [[VECEXT]], ptr [[X]], align 4
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[F_ADDR]], align 4
+// CHECK-NEXT:    [[CAST_SPLAT2:%.*]] = insertelement <1 x float> poison, float [[TMP3]], i64 0
+// CHECK-NEXT:    [[TMP4:%.*]] = shufflevector <1 x float> [[CAST_SPLAT2]], <1 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT:    store <4 x float> [[TMP4]], ptr [[REF_TMP1]], align 16
+// CHECK-NEXT:    [[TMP5:%.*]] = load <4 x float>, ptr [[REF_TMP1]], align 16
+// CHECK-NEXT:    [[VECEXT3:%.*]] = extractelement <4 x float> [[TMP5]], i64 1
+// CHECK-NEXT:    store float [[VECEXT3]], ptr [[Y]], align 4
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP6:%.*]] = load float, ptr [[F_ADDR]], align 4
+// CHECK-NEXT:    [[CAST_SPLAT5:%.*]] = insertelement <1 x float> poison, float [[TMP6]], i64 0
+// CHECK-NEXT:    [[TMP7:%.*]] = shufflevector <1 x float> [[CAST_SPLAT5]], <1 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT:    store <4 x float> [[TMP7]], ptr [[REF_TMP4]], align 16
+// CHECK-NEXT:    [[TMP8:%.*]] = load <4 x float>, ptr [[REF_TMP4]], align 16
+// CHECK-NEXT:    [[VECEXT6:%.*]] = extractelement <4 x float> [[TMP8]], i64 2
+// CHECK-NEXT:    store float [[VECEXT6]], ptr [[Z]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 2
+// CHECK-NEXT:    [[TMP9:%.*]] = load float, ptr [[F_ADDR]], align 4
+// CHECK-NEXT:    [[CAST_SPLAT8:%.*]] = insertelement <1 x float> poison, float [[TMP9]], i64 0
+// CHECK-NEXT:    [[TMP10:%.*]] = shufflevector <1 x float> [[CAST_SPLAT8]], <1 x float> poison, <4 x i32> zeroinitializer
+// CHECK-NEXT:    store <4 x float> [[TMP10]], ptr [[REF_TMP7]], align 16
+// CHECK-NEXT:    [[TMP11:%.*]] = load <4 x float>, ptr [[REF_TMP7]], align 16
+// CHECK-NEXT:    [[VECEXT9:%.*]] = extractelement <4 x float> [[TMP11]], i64 3
+// CHECK-NEXT:    store float [[VECEXT9]], ptr [[W]], align 4
+// CHECK-NEXT:    ret void
+//
+FourFloats case11(float F) {
+  FourFloats FF1 = {F.xxxx};
+  return FF1;
+}
+
+// Case 12: Initialize bitfield from two integers.
+// CHECK-LABEL: define void @_Z6case12ii(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_SLICYBITS:%.*]]) align 4 [[AGG_RESULT:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[I_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[J_ADDR:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i32 [[I]], ptr [[I_ADDR]], align 4
+// CHECK-NEXT:    store i32 [[J]], ptr [[J_ADDR]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I_ADDR]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[TMP0]] to i16
+// CHECK-NEXT:    [[BF_LOAD:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255
+// CHECK-NEXT:    [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD]], -256
+// CHECK-NEXT:    [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK-NEXT:    store i16 [[BF_SET]], ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[J_ADDR]], align 4
+// CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
+// CHECK-NEXT:    [[BF_LOAD1:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    [[BF_VALUE2:%.*]] = and i16 [[TMP3]], 255
+// CHECK-NEXT:    [[BF_SHL:%.*]] = shl i16 [[BF_VALUE2]], 8
+// CHECK-NEXT:    [[BF_CLEAR3:%.*]] = and i16 [[BF_LOAD1]], 255
+// CHECK-NEXT:    [[BF_SET4:%.*]] = or i16 [[BF_CLEAR3]], [[BF_SHL]]
+// CHECK-NEXT:    store i16 [[BF_SET4]], ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    ret void
+//
+SlicyBits case12(int I, int J) {
+  SlicyBits SB = {I, J};
+  return SB;
+}
+
+// Case 13: Initialize bitfield from a struct of two ints.
+// CHECK-LABEL: define void @_Z6case137TwoInts(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_SLICYBITS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 4 [[TI:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[Z]], align 4
+// CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[TMP0]] to i16
+// CHECK-NEXT:    [[BF_LOAD:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    [[BF_VALUE:%.*]] = and i16 [[TMP1]], 255
+// CHECK-NEXT:    [[BF_CLEAR:%.*]] = and i16 [[BF_LOAD]], -256
+// CHECK-NEXT:    [[BF_SET:%.*]] = or i16 [[BF_CLEAR]], [[BF_VALUE]]
+// CHECK-NEXT:    store i16 [[BF_SET]], ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[TI]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr [[W]], align 4
+// CHECK-NEXT:    [[TMP3:%.*]] = trunc i32 [[TMP2]] to i16
+// CHECK-NEXT:    [[BF_LOAD1:%.*]] = load i16, ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    [[BF_VALUE2:%.*]] = and i16 [[TMP3]], 255
+// CHECK-NEXT:    [[BF_SHL:%.*]] = shl i16 [[BF_VALUE2]], 8
+// CHECK-NEXT:    [[BF_CLEAR3:%.*]] = and i16 [[BF_LOAD1]], 255
+// CHECK-NEXT:    [[BF_SET4:%.*]] = or i16 [[BF_CLEAR3]], [[BF_SHL]]
+// CHECK-NEXT:    store i16 [[BF_SET4]], ptr [[AGG_RESULT]], align 4
+// CHECK-NEXT:    ret void
+//
+SlicyBits case13(TwoInts TI) {
+  SlicyBits SB = {TI};
+  return SB;
+}
+
+// Case 14: Initialize struct of ints from struct with bitfields.
+// CHECK-LABEL: define void @_Z6case149SlicyBits(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOINTS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_SLICYBITS:%.*]]) align 4 [[SB:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[BF_LOAD:%.*]] = load i16, ptr [[SB]], align 4
+// CHECK-NEXT:    [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 8
+// CHECK-NEXT:    [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8
+// CHECK-NEXT:    [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32
+// CHECK-NEXT:    store i32 [[BF_CAST]], ptr [[Z]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOINTS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[BF_LOAD1:%.*]] = load i16, ptr [[SB]], align 4
+// CHECK-NEXT:    [[BF_ASHR2:%.*]] = ashr i16 [[BF_LOAD1]], 8
+// CHECK-NEXT:    [[BF_CAST3:%.*]] = sext i16 [[BF_ASHR2]] to i32
+// CHECK-NEXT:    store i32 [[BF_CAST3]], ptr [[W]], align 4
+// CHECK-NEXT:    ret void
+//
+TwoInts case14(SlicyBits SB) {
+  TwoInts TI = {SB};
+  return TI;
+}
+
+// Case 15: Initialize struct of floats from struct with bitfields.
+// CHECK-LABEL: define void @_Z6case159SlicyBits(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_SLICYBITS:%.*]]) align 4 [[SB:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    [[BF_LOAD:%.*]] = load i16, ptr [[SB]], align 4
+// CHECK-NEXT:    [[BF_SHL:%.*]] = shl i16 [[BF_LOAD]], 8
+// CHECK-NEXT:    [[BF_ASHR:%.*]] = ashr i16 [[BF_SHL]], 8
+// CHECK-NEXT:    [[BF_CAST:%.*]] = sext i16 [[BF_ASHR]] to i32
+// CHECK-NEXT:    [[CONV:%.*]] = sitofp i32 [[BF_CAST]] to float
+// CHECK-NEXT:    store float [[CONV]], ptr [[X]], align 4
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[BF_LOAD1:%.*]] = load i16, ptr [[SB]], align 4
+// CHECK-NEXT:    [[BF_ASHR2:%.*]] = ashr i16 [[BF_LOAD1]], 8
+// CHECK-NEXT:    [[BF_CAST3:%.*]] = sext i16 [[BF_ASHR2]] to i32
+// CHECK-NEXT:    [[CONV4:%.*]] = sitofp i32 [[BF_CAST3]] to float
+// CHECK-NEXT:    store float [[CONV4]], ptr [[Y]], align 4
+// CHECK-NEXT:    ret void
+//
+TwoFloats case15(SlicyBits SB) {
+  TwoFloats TI = {SB};
+  return TI;
+}
diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 79ba126758589..5555e899ecb5d 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -35,6 +35,15 @@ struct Zoo {
   Kitteh Cats[4];
 };
 
+struct FourFloats : TwoFloats {
+  float Z, W;
+};
+
+struct SlicyBits {
+  int Z : 8;
+  int W : 8;
+};
+
 void fn() {
   TwoFloats TF1 = {{{1.0, 2}}};
   TwoFloats TF2 = {1,2};
@@ -60,6 +69,17 @@ void fn() {
   // expected-warning@#insanity{{implicit conversion changes signedness: 'uint' (aka 'unsigned int') to 'int'}}
 }
 
+void fn2() {
+  TwoFloats TF2 = {1,2};
+  FourFloats FF1 = {TF2, TF2};
+  FourFloats FF2 = {1,2,3,4};
+  FourFloats FF3 = {1.xxx, 2};
+
+  SlicyBits SB1 = {1,2};
+  TwoInts TI1 = {SB1};
+  SlicyBits SB2 = {TI1};
+}
+
 void Errs() {
   TwoFloats F1 = {}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 0)}}
   TwoFloats F2 = {1}; // expected-error{{too few initializers in list for type 'TwoFloats' (expected 2 but found 1)}}

>From 18770cc337d4c51d88fad4ac33f8c064e789d403 Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Tue, 11 Feb 2025 16:25:49 -0600
Subject: [PATCH 07/16] Update
 clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl

Co-authored-by: Helena Kotas <hekotas at microsoft.com>
---
 clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
index 97baac3272a66..48041f2e4853c 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -155,7 +155,7 @@ TwoInts case6(TwoFloats TF4) {
   return TI2;
 }
 
-// Case 7: Initialization of a complex structue, with bogus braces and element
+// Case 7: Initialization of a complex structure, with bogus braces and element
 // conversions from a collection of scalar values, and structures.
 // CHECK-LABEL: define void @_Z5case77TwoIntsS_i9TwoFloatsS0_S0_S0_(
 // CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_DOGGO:%.*]]) align 16 [[AGG_RESULT:%.*]], ptr noundef byval([[STRUCT_TWOINTS:%.*]]) align 4 [[TI1:%.*]], ptr noundef byval([[STRUCT_TWOINTS]]) align 4 [[TI2:%.*]], i32 noundef [[VAL:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS:%.*]]) align 4 [[TF1:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF2:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF3:%.*]], ptr noundef byval([[STRUCT_TWOFLOATS]]) align 4 [[TF4:%.*]]) #[[ATTR0]] {

>From ca8255b0a9f1c1a1c105a187700c98f66be8d674 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Tue, 11 Feb 2025 16:35:17 -0600
Subject: [PATCH 08/16] Fix formatting

---
 clang/lib/Sema/SemaHLSL.cpp | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index c50dbf5ec4db8..fccadc19e78e5 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3132,15 +3132,16 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
   }
 
   if (auto *RTy = Ty->getAs<RecordType>()) {
-    llvm::SmallVector<const RecordType*> RecordTypes;
+    llvm::SmallVector<const RecordType *> RecordTypes;
     RecordTypes.push_back(RTy);
-    while(RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+    while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
       CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
-      assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance");
+      assert(D->getNumBases() == 1 &&
+             "HLSL doesn't support multiple inheritance");
       RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
     }
     while (!RecordTypes.empty()) {
-      const RecordType* RT = RecordTypes.back();
+      const RecordType *RT = RecordTypes.back();
       RecordTypes.pop_back();
       for (auto *FD : RT->getDecl()->fields()) {
         DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess());
@@ -3178,15 +3179,16 @@ static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
       Inits.push_back(GenerateInitLists(Ctx, ElTy, It));
   }
   if (auto *RTy = Ty->getAs<RecordType>()) {
-    llvm::SmallVector<const RecordType*> RecordTypes;
+    llvm::SmallVector<const RecordType *> RecordTypes;
     RecordTypes.push_back(RTy);
-    while(RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
+    while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) {
       CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl();
-      assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance");
+      assert(D->getNumBases() == 1 &&
+             "HLSL doesn't support multiple inheritance");
       RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>());
     }
     while (!RecordTypes.empty()) {
-      const RecordType* RT = RecordTypes.back();
+      const RecordType *RT = RecordTypes.back();
       RecordTypes.pop_back();
       for (auto *FD : RT->getDecl()->fields()) {
         Inits.push_back(GenerateInitLists(Ctx, FD->getType(), It));

>From 2e1452da3fe6c0e88f3765e44540164e4da79031 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Tue, 11 Feb 2025 16:44:52 -0600
Subject: [PATCH 09/16] Split HLSL's comment from C++'s

---
 clang/lib/Sema/SemaChecking.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index e423b820c6032..aae61f612a4bc 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11678,8 +11678,9 @@ static void AnalyzeImplicitConversions(
 
   // Propagate whether we are in a C++ list initialization expression.
   // If so, we do not issue warnings for implicit int-float conversion
-  // precision loss, because C++11 narrowing already handles it. HLSL's
-  // initialization lists are special, so they shouldn't observe the C++
+  // precision loss, because C++11 narrowing already handles it.
+  //
+  // HLSL's initialization lists are special, so they shouldn't observe the C++
   // behavior here.
   bool IsListInit =
       Item.IsListInit || (isa<InitListExpr>(OrigE) &&

>From c5f2a1f067ca2fd5cf872eb71a78a4a3dc5a16f5 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Tue, 11 Feb 2025 22:12:13 -0600
Subject: [PATCH 10/16] Fix initialization with resources in structs

This was a bit tricker than I expected, but I think I came up with a
reasonably clever solution.

In HLSL, user-defined data types have aggregate initialization, not
constructors _except_ that some of the builtin types we do model
constructors for. This is actually useful!

In my earlier change I updated DeclCXX so that HLSL non-implicit
classes are always marged as Aggregates. This ends up being not
quite right, because there are some implicit types that should be
aggregates, and others that shouldn't. For example, the implicit
cbuffer-layout types should be aggregates so that we can flatten
them, but resources shouldn't be because we really don't want to
flatten them.

In the update, whether or not an HLSL type is an aggregate is keyed
off having non-implicit "special" members (constructors & operators).
This is more correct.

Aggregate types get flattened out for casting and initialization, while
non-Aggregate types (basically just resources) get left unflattened and
we attempt copy-initialization on them.

Next problem: I was getting some odd conflicting diagnostics when
argument conversion or copy-initialization fails, so I refactored
BuildInitializerList and CastInitializer to return success/failure so
that we can propagate that up and fail if the argument->destination
type fails without then also complaining about the number of
initializers.
---
 clang/lib/AST/DeclCXX.cpp                   |  4 +-
 clang/lib/Sema/SemaHLSL.cpp                 | 73 +++++++++++----------
 clang/test/SemaHLSL/Language/InitLists.hlsl | 24 +++++++
 3 files changed, 64 insertions(+), 37 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 64499576af955..c601b6c6dbd6a 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1468,8 +1468,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
   // relevant HLSL feature proposals that will depend on this changing:
   // * 0005-strict-initializer-lists.md
   // * https://github.com/microsoft/hlsl-specs/pull/325
-  if (getLangOpts().HLSL && !isImplicit())
-    data().Aggregate = true;
+  if (getLangOpts().HLSL)
+    data().Aggregate = data().UserDeclaredSpecialMembers == 0;
 }
 
 bool CXXRecordDecl::isLiteral() const {
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index fccadc19e78e5..5663fcc388c7e 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2589,17 +2589,20 @@ static void BuildFlattenedTypeList(QualType BaseTy,
       continue;
     }
     if (const auto *RT = dyn_cast<RecordType>(T)) {
-      const RecordDecl *RD = RT->getDecl();
-      if (RD->isUnion()) {
+      const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
+      assert(RD && "HLSL record types should all be CXXRecordDecls!");
+
+      if (RD->isStandardLayout())
+        RD = RD->getStandardLayoutBaseWithFields();
+
+      // For types that we shouldn't decompose (unios and non-aggregates), just
+      // add the type itself to the list.
+      if (RD->isUnion() || !RD->isAggregate()) {
         List.push_back(T);
         continue;
       }
-      const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD);
 
       llvm::SmallVector<QualType, 16> FieldTypes;
-      if (CXXD && CXXD->isStandardLayout())
-        RD = CXXD->getStandardLayoutBaseWithFields();
-
       for (const auto *FD : RD->fields())
         FieldTypes.push_back(FD->getType());
       // Reverse the newly added sub-range.
@@ -2608,9 +2611,9 @@ static void BuildFlattenedTypeList(QualType BaseTy,
 
       // If this wasn't a standard layout type we may also have some base
       // classes to deal with.
-      if (CXXD && !CXXD->isStandardLayout()) {
+      if (!RD->isStandardLayout()) {
         FieldTypes.clear();
-        for (const auto &Base : CXXD->bases())
+        for (const auto &Base : RD->bases())
           FieldTypes.push_back(Base.getType());
         std::reverse(FieldTypes.begin(), FieldTypes.end());
         WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
@@ -3062,6 +3065,8 @@ static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
                             llvm::SmallVectorImpl<QualType> &DestTypes) {
   if (List.size() >= DestTypes.size()) {
     List.push_back(E);
+    // This is odd, but it isn't technically a failure due to conversion, we
+    // handle mismatched counts of arguments differently.
     return true;
   }
   InitializedEntity Entity = InitializedEntity::InitializeParameter(
@@ -3074,32 +3079,26 @@ static bool CastInitializer(Sema &S, ASTContext &Ctx, Expr *E,
   return true;
 }
 
-static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
+static bool BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
                                  llvm::SmallVectorImpl<Expr *> &List,
-                                 llvm::SmallVectorImpl<QualType> &DestTypes,
-                                 bool &ExcessInits) {
-  if (List.size() >= DestTypes.size())
-    ExcessInits = true;
-
+                                 llvm::SmallVectorImpl<QualType> &DestTypes) {
   // If this is an initialization list, traverse the sub initializers.
   if (auto *Init = dyn_cast<InitListExpr>(E)) {
     for (auto *SubInit : Init->inits())
-      BuildInitializerList(S, Ctx, SubInit, List, DestTypes, ExcessInits);
-    return;
+      if (!BuildInitializerList(S, Ctx, SubInit, List, DestTypes))
+        return false;
+    return true;
   }
 
   // If this is a scalar type, just enqueue the expression.
   QualType Ty = E->getType();
-  if (Ty->isScalarType()) {
-    (void)CastInitializer(S, Ctx, E, List, DestTypes);
-    return;
-  }
+
+  if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
+    return CastInitializer(S, Ctx, E, List, DestTypes);
 
   if (auto *ATy = Ty->getAs<VectorType>()) {
     uint64_t Size = ATy->getNumElements();
 
-    if (List.size() + Size > DestTypes.size())
-      ExcessInits = true;
     QualType SizeTy = Ctx.getSizeType();
     uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
     for (uint64_t I = 0; I < Size; ++I) {
@@ -3109,10 +3108,11 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
       ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
           E, E->getBeginLoc(), Idx, E->getEndLoc());
       if (ElExpr.isInvalid())
-        return;
-      CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes);
+        return false;
+      if (!CastInitializer(S, Ctx, ElExpr.get(), List, DestTypes))
+        return false;
     }
-    return;
+    return true;
   }
 
   if (auto *VTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
@@ -3125,10 +3125,11 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
       ExprResult ElExpr = S.CreateBuiltinArraySubscriptExpr(
           E, E->getBeginLoc(), Idx, E->getEndLoc());
       if (ElExpr.isInvalid())
-        return;
-      BuildInitializerList(S, Ctx, ElExpr.get(), List, DestTypes, ExcessInits);
+        return false;
+      if (!BuildInitializerList(S, Ctx, ElExpr.get(), List, DestTypes))
+        return false;
     }
-    return;
+    return true;
   }
 
   if (auto *RTy = Ty->getAs<RecordType>()) {
@@ -3149,16 +3150,18 @@ static void BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
         ExprResult Res = S.BuildFieldReferenceExpr(
             E, false, E->getBeginLoc(), CXXScopeSpec(), FD, Found, NameInfo);
         if (Res.isInvalid())
-          return;
-        BuildInitializerList(S, Ctx, Res.get(), List, DestTypes, ExcessInits);
+          return false;
+        if (!BuildInitializerList(S, Ctx, Res.get(), List, DestTypes))
+          return false;
       }
     }
   }
+  return true;
 }
 
 static Expr *GenerateInitLists(ASTContext &Ctx, QualType Ty,
                                llvm::SmallVectorImpl<Expr *>::iterator &It) {
-  if (Ty->isScalarType()) {
+  if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType())) {
     return *(It++);
   }
   llvm::SmallVector<Expr *> Inits;
@@ -3216,12 +3219,12 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
   BuildFlattenedTypeList(InitTy, DestTypes);
 
   llvm::SmallVector<Expr *, 16> ArgExprs;
-  bool ExcessInits = false;
   for (Expr *Arg : Init->inits())
-    BuildInitializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes, ExcessInits);
+    if (!BuildInitializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes))
+      return false;
 
-  if (DestTypes.size() != ArgExprs.size() || ExcessInits) {
-    int TooManyOrFew = ExcessInits ? 1 : 0;
+  if (DestTypes.size() != ArgExprs.size()) {
+    int TooManyOrFew = ArgExprs.size() > DestTypes.size() ? 1 : 0;
     SemaRef.Diag(Init->getBeginLoc(), diag::err_hlsl_incorrect_num_initializers)
         << TooManyOrFew << InitTy << DestTypes.size() << ArgExprs.size();
     return false;
diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 5555e899ecb5d..80f1dbe7bf12b 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -44,6 +44,16 @@ struct SlicyBits {
   int W : 8;
 };
 
+struct ContainsResource { // #ContainsResource
+  int X;
+  RWBuffer<float4> B;
+};
+
+struct ContainsResourceInverted {
+  RWBuffer<float4> B;
+  int X;
+};
+
 void fn() {
   TwoFloats TF1 = {{{1.0, 2}}};
   TwoFloats TF2 = {1,2};
@@ -87,3 +97,17 @@ void Errs() {
 
   int2 Something = {1.xxx}; // expected-error{{too many initializers in list for type 'int2' (aka 'vector<int, 2>') (expected 2 but found 3)}}
 }
+
+void Err2(RWBuffer<float4> B) {
+  ContainsResource RS1 = {1, B};
+  ContainsResource RS2 = (1.xx); // expected-error{{no viable conversion from 'vector<int, 2>' (vector of 2 'int' values) to 'ContainsResource'}}
+  ContainsResource RS3 = {B, 1}; // expected-error{{no viable conversion from 'RWBuffer<float4>' (aka 'RWBuffer<vector<float, 4>>') to 'int'}}
+  ContainsResourceInverted IR = {RS1}; // expected-error{{no viable conversion from 'int' to 'hlsl::RWBuffer<vector<float, 4>>'}}
+}
+
+// expected-note@#ContainsResource{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'vector<int, 2>' (vector of 2 'int' values) to 'const ContainsResource &' for 1st argument}}
+// expected-note@#ContainsResource{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'vector<int, 2>' (vector of 2 'int' values) to 'ContainsResource &&' for 1st argument}}
+
+// These notes refer to the RWBuffer constructors that do not have source locations
+// expected-note@*{{candidate constructor (the implicit copy constructor) not viable}}
+// expected-note@*{{candidate constructor (the implicit move constructor) not viable}}

>From e923490230854f4ca7edfa0d4ec1c9fbd0885535 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 13 Feb 2025 12:00:43 -0600
Subject: [PATCH 11/16] Add OVE to capture side effecting arguments in init
 list

---
 clang/lib/Sema/SemaHLSL.cpp | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5663fcc388c7e..fba7c6f329d65 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3219,9 +3219,18 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
   BuildFlattenedTypeList(InitTy, DestTypes);
 
   llvm::SmallVector<Expr *, 16> ArgExprs;
-  for (Expr *Arg : Init->inits())
-    if (!BuildInitializerList(SemaRef, Ctx, Arg, ArgExprs, DestTypes))
+  for (unsigned I = 0; I < Init->getNumInits(); ++I) {
+    Expr *E = Init->getInit(I);
+    if (E->HasSideEffects(Ctx)) {
+      QualType Ty = E->getType();
+      if (auto *RTy = Ty->getAs<RecordType>())
+        E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
+      E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind());
+      Init->setInit(I, E);
+    }
+    if (!BuildInitializerList(SemaRef, Ctx, E, ArgExprs, DestTypes))
       return false;
+  }
 
   if (DestTypes.size() != ArgExprs.size()) {
     int TooManyOrFew = ArgExprs.size() > DestTypes.size() ? 1 : 0;

>From 019b1f906d73c94285e52afbdb832f122afe36e3 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 13 Feb 2025 16:04:09 -0600
Subject: [PATCH 12/16] Handle side-effecting argument expressions

This slightly tweaks the AST formulation to wrap any potentially
side-effecting initialization list expression in an OpaqueValueExpr so
that during codegen we can ensure it only gets emitted once.

I've made a slightly hacky but minimal change in CodeGen to then emit
OpaqueValueExprs in InitLists during aggregate initialization emission.

I weighed the tradeoff between an AST-level representation or this
CodeGen change. If HLSL were going to retain this initialization list
behavior long term, I'd probably add a new AST node to represent HLSL
initialization lists and restructure how we generate the AST, but I
think that would be a lot more code to maintain, and since the goal is
to remove this quirk from the language I don't think it is the best
solution.

The change as written isolates most of the weirdness of HLSL in
CGHLSLRuntime and is a massively smaller change than a new AST node for
initialization lists. This will also ensure that Clang's AST-based
analysis for initialization lists will continue to be accurate for HLSL
without any additional updates required.
---
 clang/lib/CodeGen/CGExpr.cpp        |  6 ++++++
 clang/lib/CodeGen/CGExprAgg.cpp     | 11 ++++++++++
 clang/lib/CodeGen/CGHLSLRuntime.cpp | 32 +++++++++++++++++++++++++++++
 clang/lib/CodeGen/CGHLSLRuntime.h   |  4 ++++
 clang/lib/CodeGen/CodeGenFunction.h |  4 ++++
 clang/lib/Sema/SemaHLSL.cpp         |  3 ++-
 6 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 0b0ffd2db853f..191912ca7d800 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5551,6 +5551,12 @@ CodeGenFunction::getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e) {
   return EmitAnyExpr(e->getSourceExpr());
 }
 
+bool CodeGenFunction::isOpaqueValueEmitted(const OpaqueValueExpr *E) {
+  if (OpaqueValueMapping::shouldBindAsLValue(E))
+    return OpaqueLValues.contains(E);
+  return OpaqueRValues.contains(E);
+}
+
 RValue CodeGenFunction::EmitRValueForField(LValue LV,
                                            const FieldDecl *FD,
                                            SourceLocation Loc) {
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index d25d0f2c2133c..9935a4bd8993d 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CGCXXABI.h"
+#include "CGHLSLRuntime.h"
 #include "CGObjCRuntime.h"
 #include "CGRecordLayout.h"
 #include "CodeGenFunction.h"
@@ -1776,6 +1777,16 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
   }
 #endif
 
+  // HLSL initialization lists in the AST are an expansion which can contain
+  // side-effecting expressions wrapped in opaque value expressions. To properly
+  // emit these we need to emit the opaque values before we emit the argument
+  // expressions themselves. This is a little hacky, but it prevents us needing
+  // to do a bigger AST-level change for a language feature that we need
+  // deprecate in the near future.
+  if (CGF.getLangOpts().HLSL && isa<InitListExpr>(ExprToVisit))
+    CGF.CGM.getHLSLRuntime().emitInitListOpaqueValues(
+        CGF, cast<InitListExpr>(ExprToVisit));
+
   AggValueSlot Dest = EnsureSlot(ExprToVisit->getType());
 
   LValue DestLV = CGF.MakeAddrLValue(Dest.getAddress(), ExprToVisit->getType());
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index 03ddc87d8d3df..856d8b1b2948d 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -14,9 +14,11 @@
 
 #include "CGHLSLRuntime.h"
 #include "CGDebugInfo.h"
+#include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/IR/GlobalVariable.h"
 #include "llvm/IR/LLVMContext.h"
@@ -617,3 +619,33 @@ llvm::Instruction *CGHLSLRuntime::getConvergenceToken(BasicBlock &BB) {
   llvm_unreachable("Convergence token should have been emitted.");
   return nullptr;
 }
+
+class OpaqueValueVisitor : public RecursiveASTVisitor<OpaqueValueVisitor> {
+public:
+  llvm::SmallPtrSet<OpaqueValueExpr *, 8> OVEs;
+  OpaqueValueVisitor() {}
+
+  bool VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+    OVEs.insert(E);
+    return true;
+  }
+};
+
+void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF,
+                                             InitListExpr *E) {
+
+  typedef CodeGenFunction::OpaqueValueMappingData OpaqueValueMappingData;
+  OpaqueValueVisitor Visitor;
+  Visitor.TraverseStmt(E);
+  for (auto *OVE : Visitor.OVEs) {
+    if (CGF.isOpaqueValueEmitted(OVE))
+      continue;
+    if (OpaqueValueMappingData::shouldBindAsLValue(OVE)) {
+      LValue LV = CGF.EmitLValue(OVE->getSourceExpr());
+      OpaqueValueMappingData::bind(CGF, OVE, LV);
+    } else {
+      RValue RV = CGF.EmitAnyExpr(OVE->getSourceExpr());
+      OpaqueValueMappingData::bind(CGF, OVE, RV);
+    }
+  }
+}
diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h
index 032b2dee82f21..8767a2ddceb96 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.h
+++ b/clang/lib/CodeGen/CGHLSLRuntime.h
@@ -55,6 +55,7 @@ class StructType;
 namespace clang {
 class VarDecl;
 class ParmVarDecl;
+class InitListExpr;
 class HLSLBufferDecl;
 class HLSLResourceBindingAttr;
 class Type;
@@ -65,6 +66,7 @@ class FunctionDecl;
 namespace CodeGen {
 
 class CodeGenModule;
+class CodeGenFunction;
 
 class CGHLSLRuntime {
 public:
@@ -161,6 +163,8 @@ class CGHLSLRuntime {
 
   llvm::Instruction *getConvergenceToken(llvm::BasicBlock &BB);
 
+  void emitInitListOpaqueValues(CodeGenFunction &CGF, InitListExpr *E);
+
 private:
   void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
                                    llvm::hlsl::ResourceClass RC,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 64cd8a3ac55e2..8c5362bcc33c4 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3011,6 +3011,10 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// otherwise create one.
   RValue getOrCreateOpaqueRValueMapping(const OpaqueValueExpr *e);
 
+  /// isOpaqueValueEmitted - Return true if the opaque value expression has
+  /// already been emitted.
+  bool isOpaqueValueEmitted(const OpaqueValueExpr *E);
+
   /// Get the index of the current ArrayInitLoopExpr, if any.
   llvm::Value *getArrayInitIndex() { return ArrayInitIndex; }
 
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index fba7c6f329d65..593e00bc9cdac 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3225,7 +3225,8 @@ bool SemaHLSL::TransformInitList(const InitializedEntity &Entity,
       QualType Ty = E->getType();
       if (auto *RTy = Ty->getAs<RecordType>())
         E = new (Ctx) MaterializeTemporaryExpr(Ty, E, E->isLValue());
-      E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind());
+      E = new (Ctx) OpaqueValueExpr(E->getBeginLoc(), Ty, E->getValueKind(),
+                                    E->getObjectKind(), E);
       Init->setInit(I, E);
     }
     if (!BuildInitializerList(SemaRef, Ctx, E, ArgExprs, DestTypes))

>From 38429f44f73227544d10d25a63c6dcc5e18c8077 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 13 Feb 2025 16:59:51 -0600
Subject: [PATCH 13/16] Add tests for side-effecting arguments and AST
 structure.

---
 .../CodeGenHLSL/BasicFeatures/InitLists.hlsl  |  60 ++
 clang/test/SemaHLSL/Language/InitListAST.hlsl | 983 ++++++++++++++++++
 2 files changed, 1043 insertions(+)
 create mode 100644 clang/test/SemaHLSL/Language/InitListAST.hlsl

diff --git a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
index 48041f2e4853c..a0590162c7087 100644
--- a/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
+++ b/clang/test/CodeGenHLSL/BasicFeatures/InitLists.hlsl
@@ -901,3 +901,63 @@ TwoFloats case15(SlicyBits SB) {
   TwoFloats TI = {SB};
   return TI;
 }
+
+// Case 16: Side-effecting initialization list arguments. The important thing
+// here is that case16 only has _one_ call to makeTwo.
+// CHECK-LABEL: define void @_Z7makeTwoRf(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_TWOFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]], ptr noalias noundef nonnull align 4 dereferenceable(4) [[X:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// 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:    [[TMP1:%.*]] = load float, ptr [[TMP0]], align 4
+// CHECK-NEXT:    store float [[TMP1]], ptr [[X1]], align 4
+// 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:    [[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 4
+// CHECK-NEXT:    [[TMP4:%.*]] = load ptr, ptr [[X_ADDR]], align 4
+// 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
+// CHECK-NEXT:    ret void
+//
+TwoFloats makeTwo(inout float X) {
+    TwoFloats TF = {X, X*1.5};
+    X *= 2;
+    return TF;
+}
+
+// CHECK-LABEL: define void @_Z6case16v(
+// CHECK-SAME: ptr dead_on_unwind noalias writable sret([[STRUCT_FOURFLOATS:%.*]]) align 4 [[AGG_RESULT:%.*]]) #[[ATTR0]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    [[X:%.*]] = alloca float, align 4
+// CHECK-NEXT:    [[REF_TMP:%.*]] = alloca [[STRUCT_TWOFLOATS:%.*]], align 4
+// CHECK-NEXT:    [[TMP:%.*]] = alloca float, align 4
+// CHECK-NEXT:    store float 0.000000e+00, ptr [[X]], align 4
+// CHECK-NEXT:    [[TMP0:%.*]] = load float, ptr [[X]], align 4
+// CHECK-NEXT:    store float [[TMP0]], ptr [[TMP]], align 4
+// CHECK-NEXT:    call void @_Z7makeTwoRf(ptr dead_on_unwind writable sret([[STRUCT_TWOFLOATS]]) align 4 [[REF_TMP]], ptr noalias noundef nonnull align 4 dereferenceable(4) [[TMP]]) #[[ATTR2:[0-9]+]]
+// CHECK-NEXT:    [[TMP1:%.*]] = load float, ptr [[TMP]], align 4
+// CHECK-NEXT:    store float [[TMP1]], ptr [[X]], align 4
+// CHECK-NEXT:    [[X1:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 0
+// CHECK-NEXT:    store float 0.000000e+00, ptr [[X1]], align 4
+// CHECK-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[X2:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK-NEXT:    [[TMP2:%.*]] = load float, ptr [[X2]], align 4
+// CHECK-NEXT:    store float [[TMP2]], ptr [[Y]], align 4
+// CHECK-NEXT:    [[Z:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 1
+// CHECK-NEXT:    [[Y3:%.*]] = getelementptr inbounds nuw [[STRUCT_TWOFLOATS]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK-NEXT:    [[TMP3:%.*]] = load float, ptr [[Y3]], align 4
+// CHECK-NEXT:    store float [[TMP3]], ptr [[Z]], align 4
+// CHECK-NEXT:    [[W:%.*]] = getelementptr inbounds nuw [[STRUCT_FOURFLOATS]], ptr [[AGG_RESULT]], i32 0, i32 2
+// CHECK-NEXT:    store float 3.000000e+00, ptr [[W]], align 4
+// CHECK-NEXT:    ret void
+//
+FourFloats case16() {
+    float X = 0;
+    FourFloats FF = {0, makeTwo(X), 3};
+    return FF;
+}
diff --git a/clang/test/SemaHLSL/Language/InitListAST.hlsl b/clang/test/SemaHLSL/Language/InitListAST.hlsl
new file mode 100644
index 0000000000000..d58582f9029fe
--- /dev/null
+++ b/clang/test/SemaHLSL/Language/InitListAST.hlsl
@@ -0,0 +1,983 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -disable-llvm-passes -finclude-default-header -ast-dump -ast-dump-filter=case %s | FileCheck %s
+
+struct TwoFloats {
+  float X, Y;
+};
+
+struct TwoInts {
+  int Z, W;
+};
+
+struct Doggo {
+  int4 LegState;
+  int TailState;
+  float HairCount;
+  float4 EarDirection[2];
+};
+
+struct AnimalBits {
+  int Legs[4];
+  uint State;
+  int64_t Counter;
+  float4 LeftDir;
+  float4 RightDir;
+};
+
+struct Kitteh {
+  int4 Legs;
+  int TailState;
+  float HairCount;
+  float4 Claws[2];
+};
+
+struct Zoo {
+  Doggo Dogs[2];
+  Kitteh Cats[4];
+};
+
+struct FourFloats : TwoFloats {
+  float Z, W;
+};
+
+struct SlicyBits {
+  int Z : 8;
+  int W : 8;
+};
+
+// Case 1: Extraneous braces get ignored in literal instantiation.
+// CHECK-LABEL: Dumping case1
+// CHECK: VarDecl {{.*}} used TF1 'TwoFloats' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.000000e+00
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+TwoFloats case1() {
+  TwoFloats TF1 = {{{1.0, 2}}};
+  return TF1;
+}
+
+// Case 2: Valid C/C++ initializer is handled appropriately.
+//CHECK-LABEL: Dumping case2
+//CHECK: VarDecl {{.*}} used TF2 'TwoFloats' nrvo cinit
+//CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
+//CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+//CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+TwoFloats case2() {
+  TwoFloats TF2 = {1, 2};
+  return TF2;
+}
+
+// Case 3: Simple initialization with conversion of an argument.
+// CHECK-LABEL: Dumping case3
+// CHECK: VarDecl {{.*}} used TF3 'TwoFloats' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'Val' 'int'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 2
+TwoFloats case3(int Val) {
+  TwoFloats TF3 = {Val, 2};
+  return TF3;
+}
+
+// Case 4: Initialization from a scalarized vector into a structure with element
+// conversions.
+// CHECK-LABEL: Dumping case4
+// CHECK: VarDecl {{.*}} used TF4 'TwoFloats' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}}'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector<int, 2>' lvalue ParmVar {{.*}} 'TwoVals' 'int2':'vector<int, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector<int, 2>' lvalue ParmVar {{.*}} 'TwoVals' 'int2':'vector<int, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+TwoFloats case4(int2 TwoVals) {
+  TwoFloats TF4 = {TwoVals};
+  return TF4;
+}
+
+// Case 5: Initialization from a scalarized vector of matching type.
+// CHECK-LABEL: Dumping case5
+// CHECK: VarDecl {{.*}} used TI1 'TwoInts' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector<int, 2>' lvalue ParmVar {{.*}} 'TwoVals' 'int2':'vector<int, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int2':'vector<int, 2>' lvalue ParmVar {{.*}} 'TwoVals' 'int2':'vector<int, 2>'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+TwoInts case5(int2 TwoVals) {
+  TwoInts TI1 = {TwoVals};
+  return TI1;
+}
+
+// Case 6: Initialization from a scalarized structure of different type with
+// different element types.
+// CHECK-LABEL: Dumping case6
+// CHECK: VarDecl {{.*}} used TI2 'TwoInts' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}}'int' <FloatingToIntegral>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF4' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <FloatingToIntegral>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF4' 'TwoFloats'
+TwoInts case6(TwoFloats TF4) {
+  TwoInts TI2 = {TF4};
+  return TI2;
+}
+
+// Case 7: Initialization of a complex structure, with bogus braces and element
+// conversions from a collection of scalar values, and structures.
+// CHECK-LABEL: Dumping case7
+// CHECK: VarDecl {{.*}} used D1 'Doggo' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .Z {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI1' 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .W {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI1' 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .Z {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI2' 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .W {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI2' 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'Val' 'int'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'Val' 'int'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF1' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF1' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF2' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF2' 'TwoFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF3' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF3' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF4' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF4' 'TwoFloats'
+Doggo case7(TwoInts TI1, TwoInts TI2, int Val, TwoFloats TF1, TwoFloats TF2,
+            TwoFloats TF3, TwoFloats TF4) {
+  Doggo D1 = {TI1, TI2, {Val, Val}, {{TF1, TF2}, {TF3, TF4}}};
+  return D1;
+}
+
+// Case 8: Initialization of a structure from a different structure with
+// significantly different element types and grouping.
+// CHECK-LABEL: Dumping case8
+// CHECK: VarDecl {{.*}} used A1 'AnimalBits' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'AnimalBits'
+// CHECK-NEXT: InitListExpr {{.*}} 'int[4]'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'unsigned int' <IntegralCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .TailState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'long' <FloatingToIntegral>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .HairCount {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+AnimalBits case8(Doggo D1) {
+  AnimalBits A1 = {D1};
+  return A1;
+}
+
+// Case 9: Everything everywhere all at once... Initializing mismatched
+// structures from different layouts, different component groupings, with no
+// top-level bracing separation.
+// CHECK-LABEL: Dumping case9
+// CHECK: VarDecl {{.*}} used Z1 'Zoo' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'Zoo'
+// CHECK-NEXT: InitListExpr {{.*}} 'Doggo[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .TailState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .HairCount {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <IntegralCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint':'unsigned int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'uint':'unsigned int' lvalue .State {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t':'long' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int64_t':'long' lvalue .Counter {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'Kitteh[4]'
+// CHECK-NEXT: InitListExpr {{.*}} 'Kitteh'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .TailState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .HairCount {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'Kitteh'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <IntegralCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint':'unsigned int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'uint':'unsigned int' lvalue .State {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t':'long' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int64_t':'long' lvalue .Counter {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'Kitteh'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'int4':'vector<int, 4>' lvalue .LegState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .TailState {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .HairCount {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float4':'vector<float, 4>' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float4 *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'float4[2]' lvalue .EarDirection {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'Doggo' lvalue ParmVar {{.*}} 'D1' 'Doggo'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'Kitteh'
+// CHECK-NEXT: InitListExpr {{.*}} 'int4':'vector<int, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'int' lvalue
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int *' <ArrayToPointerDecay>
+// CHECK-NEXT: MemberExpr {{.*}} 'int[4]' lvalue .Legs {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <IntegralCast>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'uint':'unsigned int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'uint':'unsigned int' lvalue .State {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int64_t':'long' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int64_t':'long' lvalue .Counter {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4[2]'
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .LeftDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+// CHECK-NEXT: InitListExpr {{.*}} 'float4':'vector<float, 4>'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' lvalue vectorcomponent
+// CHECK-NEXT: MemberExpr {{.*}} 'float4':'vector<float, 4>' lvalue .RightDir {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'AnimalBits' lvalue ParmVar {{.*}} 'A1' 'AnimalBits'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+Zoo case9(Doggo D1, AnimalBits A1) {
+  Zoo Z1 = {D1, A1, D1, A1, D1, A1};
+  return Z1;
+}
+
+// Case 10: Initialize an object with a base class from two objects.
+// CHECK-LABEL: Dumping case10
+// CHECK: | `-VarDecl {{.*}} used FF1 'FourFloats' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF1' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF1' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .X {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF2' 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' lvalue .Y {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoFloats' lvalue ParmVar {{.*}} 'TF2' 'TwoFloats'
+FourFloats case10(TwoFloats TF1, TwoFloats TF2) {
+  FourFloats FF1 = {TF1, TF2};
+  return FF1;
+}
+
+// Case 11: Initialize an object with a base class from a vector splat.
+// CHECK-LABEL: Dumping case11
+// CHECK: VarDecl {{.*}} used FF1 'FourFloats' nrvo cinit
+// CHECK-NEXT: ExprWithCleanups {{.*}} 'FourFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' xvalue vectorcomponent
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'vector<float, 4>' xvalue
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'vector<float, 4>' xxxx
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 1>' lvalue <VectorSplat>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'F' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' xvalue vectorcomponent
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'vector<float, 4>' xvalue
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'vector<float, 4>' xxxx
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 1>' lvalue <VectorSplat>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'F' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 1
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' xvalue vectorcomponent
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'vector<float, 4>' xvalue
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'vector<float, 4>' xxxx
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 1>' lvalue <VectorSplat>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'F' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 2
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: ArraySubscriptExpr {{.*}} 'float' xvalue vectorcomponent
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'vector<float, 4>' xvalue
+// CHECK-NEXT: ExtVectorElementExpr {{.*}} 'vector<float, 4>' xxxx
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'vector<float, 1>' lvalue <VectorSplat>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'float' lvalue ParmVar {{.*}} 'F' 'float'
+// CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned long' 3
+FourFloats case11(float F) {
+  FourFloats FF1 = {F.xxxx};
+  return FF1;
+}
+
+// Case 12: Initialize bitfield from two integers.
+// CHECK-LABEL: Dumping case12
+// CHECK: VarDecl {{.*}} used SB 'SlicyBits' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'SlicyBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'I' 'int'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'J' 'int'
+SlicyBits case12(int I, int J) {
+  SlicyBits SB = {I, J};
+  return SB;
+}
+
+// Case 13: Initialize bitfield from a struct of two ints.
+// CHECK-LABEL: Dumping case13
+// CHECK: VarDecl {{.*}} used SB 'SlicyBits' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'SlicyBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .Z {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI' 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue .W {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'TwoInts' lvalue ParmVar {{.*}} 'TI' 'TwoInts'
+SlicyBits case13(TwoInts TI) {
+  SlicyBits SB = {TI};
+  return SB;
+}
+
+// Case 14: Initialize struct of ints from struct with bitfields.
+// CHECK-LABEL: Dumping case14
+// CHECK: VarDecl {{.*}} used TI 'TwoInts' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoInts'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue bitfield .Z {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'SlicyBits' lvalue ParmVar {{.*}} 'SB' 'SlicyBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue bitfield .W {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'SlicyBits' lvalue ParmVar {{.*}} 'SB' 'SlicyBits'
+TwoInts case14(SlicyBits SB) {
+  TwoInts TI = {SB};
+  return TI;
+}
+
+// Case 15: Initialize struct of floats from struct with bitfields.
+// CHECK-LABEL: Dumping case15
+// CHECK: VarDecl {{.*}} used TI 'TwoFloats' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue bitfield .Z {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'SlicyBits' lvalue ParmVar {{.*}} 'SB' 'SlicyBits'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'int' lvalue bitfield .W {{.*}}
+// CHECK-NEXT: DeclRefExpr {{.*}} 'SlicyBits' lvalue ParmVar {{.*}} 'SB' 'SlicyBits'
+TwoFloats case15(SlicyBits SB) {
+  TwoFloats TI = {SB};
+  return TI;
+}
+
+// Case 16: Side-effecting initialization list arguments. The important thing
+// here is that case16 only has _one_ call to makeTwo.
+TwoFloats makeTwo(inout float X) {
+    TwoFloats TF = {X, X*1.5};
+    X *= 2;
+    return TF;
+}
+
+// CHECK-LABEL: Dumping case16
+// CHECK: VarDecl {{.*}} used FF 'FourFloats' nrvo cinit
+// CHECK-NEXT: InitListExpr {{.*}} 'FourFloats'
+// CHECK-NEXT: InitListExpr {{.*}} 'TwoFloats'
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
+// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <LValueToRValue>
+// CHECK-NEXT: MemberExpr {{.*}} 'float' xvalue .X {{.*}}
+// CHECK-NEXT: OpaqueValueExpr [[OVEArg:0x[0-9A-Fa-f]+]] {{.*}} 'TwoFloats' xvalue
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoFloats' xvalue
+// CHECK-NEXT: CallExpr {{.*}} 'TwoFloats'
+
+// I don't care about the call here, just skip ahead to the next argument, and
+// verify that we match the same OpaqueValueExpr.
+
+// CHECK: MemberExpr {{.*}} 'float' xvalue .Y {{.*}}
+// CHECK-NEXT: OpaqueValueExpr [[OVEArg]] {{.*}} 'TwoFloats' xvalue
+// CHECK-NEXT: MaterializeTemporaryExpr {{.*}} 'TwoFloats' xvalue
+// CHECK-NEXT: CallExpr {{.*}} 'TwoFloats'
+FourFloats case16() {
+    float X = 0;
+    FourFloats FF = {0, makeTwo(X), 3};
+    return FF;
+}

>From 60434e36024e96869d0006270aa7cf174da986f2 Mon Sep 17 00:00:00 2001
From: Chris B <cbieneman at microsoft.com>
Date: Fri, 14 Feb 2025 15:07:36 -0600
Subject: [PATCH 14/16] Update clang/lib/Sema/SemaHLSL.cpp

Co-authored-by: Justin Bogner <mail at justinbogner.com>
---
 clang/lib/Sema/SemaHLSL.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 593e00bc9cdac..bea0948b66586 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -2595,7 +2595,7 @@ static void BuildFlattenedTypeList(QualType BaseTy,
       if (RD->isStandardLayout())
         RD = RD->getStandardLayoutBaseWithFields();
 
-      // For types that we shouldn't decompose (unios and non-aggregates), just
+      // For types that we shouldn't decompose (unions and non-aggregates), just
       // add the type itself to the list.
       if (RD->isUnion() || !RD->isAggregate()) {
         List.push_back(T);

>From 22338cb5c5ac8bbd2f14397a3bc1e62db61fe5cc Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Fri, 14 Feb 2025 15:17:07 -0600
Subject: [PATCH 15/16] Updates based on PR review feedback

---
 clang/lib/AST/DeclCXX.cpp       | 6 +++++-
 clang/lib/CodeGen/CGExprAgg.cpp | 4 +++-
 clang/lib/Sema/SemaHLSL.cpp     | 8 ++++----
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c601b6c6dbd6a..1aa48f0026335 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1464,7 +1464,11 @@ void CXXRecordDecl::addedMember(Decl *D) {
   }
 
   // HLSL: All user-defined data types are aggregates and use aggregate
-  // initialization. This _needs_ to change in the future. There are two
+  // initialization, meanwhile most, but not all built-in types behave like
+  // aggregates. Resource types, and some other HLSL types that wrap handles
+  // don't behave like aggregates. We can identify these as different because we
+  // implicitly define "special" member functions, which aren't spellable in
+  // HLSL. This all _needs_ to change in the future. There are two
   // relevant HLSL feature proposals that will depend on this changing:
   // * 0005-strict-initializer-lists.md
   // * https://github.com/microsoft/hlsl-specs/pull/325
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 9935a4bd8993d..625ca363d9019 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1782,7 +1782,9 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
   // emit these we need to emit the opaque values before we emit the argument
   // expressions themselves. This is a little hacky, but it prevents us needing
   // to do a bigger AST-level change for a language feature that we need
-  // deprecate in the near future.
+  // deprecate in the near future. See related HLSL language proposals:
+  // * 0005-strict-initializer-lists.md
+  // * https://github.com/microsoft/hlsl-specs/pull/325
   if (CGF.getLangOpts().HLSL && isa<InitListExpr>(ExprToVisit))
     CGF.CGM.getHLSLRuntime().emitInitListOpaqueValues(
         CGF, cast<InitListExpr>(ExprToVisit));
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index bea0948b66586..be45761552290 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3096,8 +3096,8 @@ static bool BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
   if (Ty->isScalarType() || (Ty->isRecordType() && !Ty->isAggregateType()))
     return CastInitializer(S, Ctx, E, List, DestTypes);
 
-  if (auto *ATy = Ty->getAs<VectorType>()) {
-    uint64_t Size = ATy->getNumElements();
+  if (auto *VecTy = Ty->getAs<VectorType>()) {
+    uint64_t Size = VecTy->getNumElements();
 
     QualType SizeTy = Ctx.getSizeType();
     uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
@@ -3115,8 +3115,8 @@ static bool BuildInitializerList(Sema &S, ASTContext &Ctx, Expr *E,
     return true;
   }
 
-  if (auto *VTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
-    uint64_t Size = VTy->getZExtSize();
+  if (auto *ArrTy = dyn_cast<ConstantArrayType>(Ty.getTypePtr())) {
+    uint64_t Size = ArrTy->getZExtSize();
     QualType SizeTy = Ctx.getSizeType();
     uint64_t SizeTySize = Ctx.getTypeSize(SizeTy);
     for (uint64_t I = 0; I < Size; ++I) {

>From 70bb0635f8df383b42f99f783ec3038704d130a1 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Sat, 15 Feb 2025 12:47:27 -0600
Subject: [PATCH 16/16] Update tests based on changes that have merged to main
 ../clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl

---
 .../SemaHLSL/Language/ElementwiseCast-errors.hlsl   |  4 +++-
 clang/test/SemaHLSL/Language/InitLists.hlsl         | 13 +++++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl b/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
index b7085bc69547b..9417249383469 100644
--- a/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
+++ b/clang/test/SemaHLSL/Language/ElementwiseCast-errors.hlsl
@@ -43,7 +43,9 @@ export void cantCast4() {
   int2 A = {1,2};
   R r = R(A);
   // expected-error at -1 {{no matching conversion for functional-style cast from 'int2' (aka 'vector<int, 2>') to 'R'}}
-  R r2 = {1, 2};
+  R r2;
+  r2.A = 1;
+  r2.F = 2.0;
   int2 B = (int2)r2;
   // expected-error at -1 {{cannot convert 'R' to 'int2' (aka 'vector<int, 2>') without a conversion operator}}
 }
diff --git a/clang/test/SemaHLSL/Language/InitLists.hlsl b/clang/test/SemaHLSL/Language/InitLists.hlsl
index 80f1dbe7bf12b..3607dfd8aedbc 100644
--- a/clang/test/SemaHLSL/Language/InitLists.hlsl
+++ b/clang/test/SemaHLSL/Language/InitLists.hlsl
@@ -98,11 +98,24 @@ void Errs() {
   int2 Something = {1.xxx}; // expected-error{{too many initializers in list for type 'int2' (aka 'vector<int, 2>') (expected 2 but found 3)}}
 }
 
+struct R {
+  int A;
+  union { // #anon
+    float F;
+    int4 G;
+  };
+};
+
+// expected-note@#anon{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to}}
+// expected-note@#anon{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to}}
+
 void Err2(RWBuffer<float4> B) {
   ContainsResource RS1 = {1, B};
   ContainsResource RS2 = (1.xx); // expected-error{{no viable conversion from 'vector<int, 2>' (vector of 2 'int' values) to 'ContainsResource'}}
   ContainsResource RS3 = {B, 1}; // expected-error{{no viable conversion from 'RWBuffer<float4>' (aka 'RWBuffer<vector<float, 4>>') to 'int'}}
   ContainsResourceInverted IR = {RS1}; // expected-error{{no viable conversion from 'int' to 'hlsl::RWBuffer<vector<float, 4>>'}}
+
+  R r = {1,2}; // expected-error{{no viable conversion from 'int' to 'R::(anonymous union at}}
 }
 
 // expected-note@#ContainsResource{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'vector<int, 2>' (vector of 2 'int' values) to 'const ContainsResource &' for 1st argument}}



More information about the cfe-commits mailing list