https://github.com/el-ev updated 
https://github.com/llvm/llvm-project/pull/137501

>From b8011997fdc2548be80dd9305d758466a66cee4c Mon Sep 17 00:00:00 2001
From: Iris Shi <0...@owo.li>
Date: Sun, 27 Apr 2025 15:16:19 +0800
Subject: [PATCH 1/2] [CIR] Upstream initial support for union type

---
 .../include/clang/CIR/Dialect/IR/CIRTypes.td  |   1 +
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  25 ++--
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp |   2 +-
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp |  94 +++++++++++-
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         |  40 ++++--
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp |  15 +-
 clang/test/CIR/CodeGen/union.c                | 135 +++++++++++++++++-
 7 files changed, 276 insertions(+), 36 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 0a821e152d353..afb7da1fa011d 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -494,6 +494,7 @@ def CIR_RecordType : CIR_Type<"Record", "record",
     bool isComplete() const { return !isIncomplete(); };
     bool isIncomplete() const;
 
+    mlir::Type getLargestMember(const mlir::DataLayout &dataLayout) const;
     size_t getNumElements() const { return getMembers().size(); };
     std::string getKindAsStr() {
       switch (getKind()) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 0a518c0fd935d..9069d1a2cf6ac 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -317,20 +317,25 @@ LValue CIRGenFunction::emitLValueForField(LValue base, 
const FieldDecl *field) {
   }
 
   unsigned recordCVR = base.getVRQualifiers();
-  if (rec->isUnion()) {
-    cgm.errorNYI(field->getSourceRange(), "emitLValueForField: union");
-    return LValue();
-  }
 
-  assert(!cir::MissingFeatures::preservedAccessIndexRegion());
   llvm::StringRef fieldName = field->getName();
-  const CIRGenRecordLayout &layout =
-      cgm.getTypes().getCIRGenRecordLayout(field->getParent());
-  unsigned fieldIndex = layout.getCIRFieldNo(field);
 
-  assert(!cir::MissingFeatures::lambdaFieldToName());
+  if (rec->isUnion()) {
+    unsigned fieldIndex = field->getFieldIndex();
+    assert(!cir::MissingFeatures::lambdaFieldToName());
+    addr = emitAddrOfFieldStorage(addr, field, fieldName, fieldIndex);
+
+  } else {
+    assert(!cir::MissingFeatures::preservedAccessIndexRegion());
+
+    const CIRGenRecordLayout &layout =
+        cgm.getTypes().getCIRGenRecordLayout(field->getParent());
+    unsigned fieldIndex = layout.getCIRFieldNo(field);
 
-  addr = emitAddrOfFieldStorage(addr, field, fieldName, fieldIndex);
+    assert(!cir::MissingFeatures::lambdaFieldToName());
+
+    addr = emitAddrOfFieldStorage(addr, field, fieldName, fieldIndex);
+  }
 
   // If this is a reference field, load the reference right now.
   if (fieldType->isReferenceType()) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 368a6cb27c0fd..e006a77c6e7d6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -1,4 +1,4 @@
-//===--- CIRGenExprAgg.cpp - Emit CIR Code from Aggregate Expressions 
-----===//
+//===- CIRGenExprAggregrate.cpp - Emit CIR Code from Aggregate Expressions 
===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index 83aba256cd48e..7b9631daacfdd 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -56,7 +56,7 @@ struct CIRRecordLowering final {
   };
   // The constructor.
   CIRRecordLowering(CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,
-                    bool isPacked);
+                    bool packed);
 
   /// Constructs a MemberInfo instance from an offset and mlir::Type.
   MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data) {
@@ -64,6 +64,7 @@ struct CIRRecordLowering final {
   }
 
   void lower();
+  void lowerUnion();
 
   /// Determines if we need a packed llvm struct.
   void determinePacked();
@@ -83,6 +84,10 @@ struct CIRRecordLowering final {
     return CharUnits::fromQuantity(dataLayout.layout.getTypeABIAlignment(Ty));
   }
 
+  bool isZeroInitializable(const FieldDecl *fd) {
+    return cirGenTypes.isZeroInitializable(fd->getType());
+  }
+
   /// Wraps cir::IntType with some implicit arguments.
   mlir::Type getUIntNType(uint64_t numBits) {
     unsigned alignedBits = llvm::PowerOf2Ceil(numBits);
@@ -121,6 +126,13 @@ struct CIRRecordLowering final {
   /// Fills out the structures that are ultimately consumed.
   void fillOutputFields();
 
+  void appendPaddingBytes(CharUnits size) {
+    if (!size.isZero()) {
+      fieldTypes.push_back(getByteArrayType(size));
+      padded = true;
+    }
+  }
+
   CIRGenTypes &cirGenTypes;
   CIRGenBuilderTy &builder;
   const ASTContext &astContext;
@@ -136,6 +148,8 @@ struct CIRRecordLowering final {
   LLVM_PREFERRED_TYPE(bool)
   unsigned zeroInitializable : 1;
   LLVM_PREFERRED_TYPE(bool)
+  unsigned zeroInitializableAsBase : 1;
+  LLVM_PREFERRED_TYPE(bool)
   unsigned packed : 1;
   LLVM_PREFERRED_TYPE(bool)
   unsigned padded : 1;
@@ -147,19 +161,19 @@ struct CIRRecordLowering final {
 } // namespace
 
 CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes,
-                                     const RecordDecl *recordDecl,
-                                     bool isPacked)
+                                     const RecordDecl *recordDecl, bool packed)
     : cirGenTypes(cirGenTypes), builder(cirGenTypes.getBuilder()),
       astContext(cirGenTypes.getASTContext()), recordDecl(recordDecl),
       astRecordLayout(
           cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)),
       dataLayout(cirGenTypes.getCGModule().getModule()),
-      zeroInitializable(true), packed(isPacked), padded(false) {}
+      zeroInitializable(true), zeroInitializableAsBase(true), packed(packed),
+      padded(false) {}
 
 void CIRRecordLowering::lower() {
   if (recordDecl->isUnion()) {
-    cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
-                                       "lower: union");
+    lowerUnion();
+    assert(!cir::MissingFeatures::bitfields());
     return;
   }
 
@@ -306,3 +320,71 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, 
cir::RecordType *ty) {
   // TODO: implement verification
   return rl;
 }
+
+void CIRRecordLowering::lowerUnion() {
+  CharUnits layoutSize = astRecordLayout.getSize();
+  mlir::Type storageType = nullptr;
+  bool seenNamedMember = false;
+
+  // Iterate through the fields setting bitFieldInfo and the Fields array. Also
+  // locate the "most appropriate" storage type.  The heuristic for finding the
+  // storage type isn't necessary, the first (non-0-length-bitfield) field's
+  // type would work fine and be simpler but would be different than what we've
+  // been doing and cause lit tests to change.
+  for (const FieldDecl *field : recordDecl->fields()) {
+    mlir::Type fieldType;
+    if (field->isBitField())
+      cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
+                                         "bitfields in lowerUnion");
+    else
+      fieldType = getStorageType(field);
+
+    fields[field->getCanonicalDecl()] = 0;
+
+    // Compute zero-initializable status.
+    // This union might not be zero initialized: it may contain a pointer to
+    // data member which might have some exotic initialization sequence.
+    // If this is the case, then we aught not to try and come up with a 
"better"
+    // type, it might not be very easy to come up with a Constant which
+    // correctly initializes it.
+    if (!seenNamedMember) {
+      seenNamedMember = field->getIdentifier();
+      if (!seenNamedMember)
+        if (const RecordDecl *fieldRD = field->getType()->getAsRecordDecl())
+          seenNamedMember = fieldRD->findFirstNamedDataMember();
+      if (seenNamedMember && !isZeroInitializable(field)) {
+        zeroInitializable = zeroInitializableAsBase = false;
+        storageType = fieldType;
+      }
+    }
+
+    // Because our union isn't zero initializable, we won't be getting a better
+    // storage type.
+    if (!zeroInitializable)
+      continue;
+
+    // Conditionally update our storage type if we've got a new "better" one.
+    if (!storageType || getAlignment(fieldType) > getAlignment(storageType) ||
+        (getAlignment(fieldType) == getAlignment(storageType) &&
+         getSize(fieldType) > getSize(storageType)))
+      storageType = fieldType;
+
+    // NOTE(cir): Track all union member's types, not just the largest one. It
+    // allows for proper type-checking and retain more info for analisys.
+    fieldTypes.push_back(fieldType);
+  }
+
+  if (!storageType)
+    cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
+                                       "No-storage Union NYI");
+
+  if (layoutSize < getSize(storageType))
+    storageType = getByteArrayType(layoutSize);
+
+  // NOTE(cir): Defer padding calculations to the lowering process.
+  appendPaddingBytes(layoutSize - getSize(storageType));
+
+  // Set packed if we need it.
+  if (layoutSize % getAlignment(storageType))
+    packed = true;
+}
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index c6133b9a20e4f..f61fc750d7c0e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -230,6 +230,32 @@ void RecordType::complete(ArrayRef<Type> members, bool 
packed, bool padded) {
     llvm_unreachable("failed to complete record");
 }
 
+/// Return the largest member of in the type.
+///
+/// Recurses into union members never returning a union as the largest member.
+Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
+  assert(isUnion() && "Only call getLargestMember on unions");
+  Type largestMember;
+  unsigned largestMemberSize = 0;
+  unsigned numElements = getNumElements();
+  auto members = getMembers();
+  if (getPadded())
+    numElements -= 1; // The last element is padding.
+  for (unsigned i = 0; i < numElements; ++i) {
+    Type ty = members[i];
+    if (!largestMember ||
+        dataLayout.getTypeABIAlignment(ty) >
+            dataLayout.getTypeABIAlignment(largestMember) ||
+        (dataLayout.getTypeABIAlignment(ty) ==
+             dataLayout.getTypeABIAlignment(largestMember) &&
+         dataLayout.getTypeSize(ty) > largestMemberSize)) {
+      largestMember = ty;
+      largestMemberSize = dataLayout.getTypeSize(largestMember);
+    }
+  }
+  return largestMember;
+}
+
 
//===----------------------------------------------------------------------===//
 // Data Layout information for types
 
//===----------------------------------------------------------------------===//
@@ -237,10 +263,8 @@ void RecordType::complete(ArrayRef<Type> members, bool 
packed, bool padded) {
 llvm::TypeSize
 RecordType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
                               mlir::DataLayoutEntryListRef params) const {
-  if (isUnion()) {
-    // TODO(CIR): Implement union layout.
-    return llvm::TypeSize::getFixed(8);
-  }
+  if (isUnion())
+    return dataLayout.getTypeSize(getLargestMember(dataLayout));
 
   unsigned recordSize = computeStructSize(dataLayout);
   return llvm::TypeSize::getFixed(recordSize * 8);
@@ -249,10 +273,8 @@ RecordType::getTypeSizeInBits(const mlir::DataLayout 
&dataLayout,
 uint64_t
 RecordType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
                             ::mlir::DataLayoutEntryListRef params) const {
-  if (isUnion()) {
-    // TODO(CIR): Implement union layout.
-    return 8;
-  }
+  if (isUnion())
+    return dataLayout.getTypeABIAlignment(getLargestMember(dataLayout));
 
   // Packed structures always have an ABI alignment of 1.
   if (getPacked())
@@ -268,8 +290,6 @@ RecordType::computeStructSize(const mlir::DataLayout 
&dataLayout) const {
   unsigned recordSize = 0;
   uint64_t recordAlignment = 1;
 
-  // We can't use a range-based for loop here because we might be ignoring the
-  // last element.
   for (mlir::Type ty : getMembers()) {
     // This assumes that we're calculating size based on the ABI alignment, not
     // the preferred alignment for each type.
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp 
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 8bb27942d9646..0dba45a5aba35 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1431,7 +1431,14 @@ static void prepareTypeConverter(mlir::LLVMTypeConverter 
&converter,
       break;
     // Unions are lowered as only the largest member.
     case cir::RecordType::Union:
-      llvm_unreachable("Lowering of unions is NYI");
+      if (auto largestMember = type.getLargestMember(dataLayout))
+        llvmMembers.push_back(
+            convertTypeForMemory(converter, dataLayout, largestMember));
+      if (type.getPadded()) {
+        auto last = *type.getMembers().rbegin();
+        llvmMembers.push_back(
+            convertTypeForMemory(converter, dataLayout, last));
+      }
       break;
     }
 
@@ -1604,7 +1611,11 @@ mlir::LogicalResult 
CIRToLLVMGetMemberOpLowering::matchAndRewrite(
     return mlir::success();
   }
   case cir::RecordType::Union:
-    return op.emitError() << "NYI: union get_member lowering";
+    // Union members share the address space, so we just need a bitcast to
+    // conform to type-checking.
+    rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(op, llResTy,
+                                                       adaptor.getAddr());
+    return mlir::success();
   }
 }
 
diff --git a/clang/test/CIR/CodeGen/union.c b/clang/test/CIR/CodeGen/union.c
index c4db37f835add..71cb9c2b20ca1 100644
--- a/clang/test/CIR/CodeGen/union.c
+++ b/clang/test/CIR/CodeGen/union.c
@@ -5,25 +5,146 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
 // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
 
+union U1 {
+  int n;
+  char c;
+};
+
+// CIR:  !rec_U1 = !cir.record<union "U1" {!s32i, !s8i}>
+// LLVM: %union.U1 = type { i32 }
+// OGCG: %union.U1 = type { i32 }
+
+union U2 {
+  char b;
+  short s;
+  int i;
+  float f;
+  double d;
+};
+
+// CIR:  !rec_U2 = !cir.record<union "U2" {!s8i, !s16i, !s32i, !cir.float, 
!cir.double}>
+// LLVM: %union.U2 = type { double }
+// OGCG: %union.U2 = type { double }
+
 union IncompleteU *p;
 
-// CIR: cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteU>
+// CIR:  cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteU>
 // LLVM: @p = dso_local global ptr null
 // OGCG: @p = global ptr null, align 8
 
-void f(void) {
+void f1(void) {
   union IncompleteU *p;
 }
 
-// CIR: cir.func @f()
-// CIR-NEXT: cir.alloca !cir.ptr<!rec_IncompleteU>, 
!cir.ptr<!cir.ptr<!rec_IncompleteU>>, ["p"]
-// CIR-NEXT: cir.return
+// CIR:      cir.func @f1()
+// CIR-NEXT:   cir.alloca !cir.ptr<!rec_IncompleteU>, 
!cir.ptr<!cir.ptr<!rec_IncompleteU>>, ["p"]
+// CIR-NEXT:   cir.return
 
-// LLVM:      define void @f()
+// LLVM:      define void @f1()
 // LLVM-NEXT:   %[[P:.*]] = alloca ptr, i64 1, align 8
 // LLVM-NEXT:   ret void
 
-// OGCG:      define{{.*}} void @f()
+// OGCG:      define{{.*}} void @f1()
 // OGCG-NEXT: entry:
 // OGCG-NEXT:   %[[P:.*]] = alloca ptr, align 8
 // OGCG-NEXT:   ret void
+
+int f2(void) {
+  union U1 u;
+  u.n = 42;
+  return u.n;
+}
+
+// CIR:      cir.func @f2() -> !s32i
+// CIR-NEXT:   %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment 
= 4 : i64}
+// CIR-NEXT:   %1 = cir.alloca !rec_U1, !cir.ptr<!rec_U1>, ["u"] {alignment = 
4 : i64}
+// CIR-NEXT:   %2 = cir.const #cir.int<42> : !s32i
+// CIR-NEXT:   %3 = cir.get_member %1[0] {name = "n"} : !cir.ptr<!rec_U1> -> 
!cir.ptr<!s32i>
+// CIR-NEXT:   cir.store %2, %3 : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   %4 = cir.get_member %1[0] {name = "n"} : !cir.ptr<!rec_U1> -> 
!cir.ptr<!s32i>
+// CIR-NEXT:   %5 = cir.load %4 : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:   cir.store %5, %0 : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   %6 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:   cir.return %6 : !s32i
+
+// LLVM:      define i32 @f2()
+// LLVM-NEXT:   %1 = alloca i32, i64 1, align 4
+// LLVM-NEXT:   %2 = alloca %union.U1, i64 1, align 4
+// LLVM-NEXT:   store i32 42, ptr %2, align 4
+// LLVM-NEXT:   %3 = load i32, ptr %2, align 4
+// LLVM-NEXT:   store i32 %3, ptr %1, align 4
+// LLVM-NEXT:   %4 = load i32, ptr %1, align 4
+// LLVM-NEXT:   ret i32 %4
+
+//      OGCG: define dso_local i32 @f2()
+// OGCG-NEXT: entry:
+// OGCG-NEXT: %u = alloca %union.U1, align 4
+// OGCG-NEXT: store i32 42, ptr %u, align 4
+// OGCG-NEXT: %0 = load i32, ptr %u, align 4
+// OGCG-NEXT: ret i32 %0
+
+
+void shouldGenerateUnionAccess(union U2 u) {
+  u.b = 0;
+  u.b;
+  u.i = 1;
+  u.i;
+  u.f = 0.1F;
+  u.f;
+  u.d = 0.1;
+  u.d;
+}
+
+// CIR:      cir.func @shouldGenerateUnionAccess(%arg0: !rec_U2
+// CIR-NEXT:   %0 = cir.alloca !rec_U2, !cir.ptr<!rec_U2>, ["u", init] 
{alignment = 8 : i64}
+// CIR-NEXT:   cir.store %arg0, %0 : !rec_U2, !cir.ptr<!rec_U2>
+// CIR-NEXT:   %1 = cir.const #cir.int<0> : !s32i
+// CIR-NEXT:   %2 = cir.cast(integral, %1 : !s32i), !s8i
+// CIR-NEXT:   %3 = cir.get_member %0[0] {name = "b"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s8i>
+// CIR-NEXT:   cir.store %2, %3 : !s8i, !cir.ptr<!s8i>
+// CIR-NEXT:   %4 = cir.get_member %0[0] {name = "b"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s8i>
+// CIR-NEXT:   %5 = cir.load %4 : !cir.ptr<!s8i>, !s8i
+// CIR-NEXT:   %6 = cir.const #cir.int<1> : !s32i
+// CIR-NEXT:   %7 = cir.get_member %0[2] {name = "i"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s32i>
+// CIR-NEXT:   cir.store %6, %7 : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   %8 = cir.get_member %0[2] {name = "i"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s32i>
+// CIR-NEXT:   %9 = cir.load %8 : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:   %10 = cir.const #cir.fp<1.000000e-01> : !cir.float
+// CIR-NEXT:   %11 = cir.get_member %0[3] {name = "f"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.float>
+// CIR-NEXT:   cir.store %10, %11 : !cir.float, !cir.ptr<!cir.float>
+// CIR-NEXT:   %12 = cir.get_member %0[3] {name = "f"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.float>
+// CIR-NEXT:   %13 = cir.load %12 : !cir.ptr<!cir.float>, !cir.float
+// CIR-NEXT:   %14 = cir.const #cir.fp<1.000000e-01> : !cir.double
+// CIR-NEXT:   %15 = cir.get_member %0[4] {name = "d"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.double>
+// CIR-NEXT:   cir.store %14, %15 : !cir.double, !cir.ptr<!cir.double>
+// CIR-NEXT:   %16 = cir.get_member %0[4] {name = "d"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.double>
+// CIR-NEXT:   %17 = cir.load %16 : !cir.ptr<!cir.double>, !cir.double
+// CIR-NEXT:   cir.return
+
+// LLVM:      define void @shouldGenerateUnionAccess(%union.U2 %0) {
+// LLVM-NEXT:   %2 = alloca %union.U2, i64 1, align 8
+// LLVM-NEXT:   store %union.U2 %0, ptr %2, align 8
+// LLVM-NEXT:   store i8 0, ptr %2, align 1
+// LLVM-NEXT:   %3 = load i8, ptr %2, align 1
+// LLVM-NEXT:   store i32 1, ptr %2, align 4
+// LLVM-NEXT:   %4 = load i32, ptr %2, align 4
+// LLVM-NEXT:   store float 0x3FB99999A0000000, ptr %2, align 4
+// LLVM-NEXT:   %5 = load float, ptr %2, align 4
+// LLVM-NEXT:   store double 1.000000e-01, ptr %2, align 8
+// LLVM-NEXT:   %6 = load double, ptr %2, align 8
+// LLVM-NEXT:   ret void
+
+// OGCG:      define dso_local void @shouldGenerateUnionAccess(i64 %u.coerce) 
#0 {
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   %u = alloca %union.U2, align 8
+// OGCG-NEXT:   %coerce.dive = getelementptr inbounds nuw %union.U2, ptr %u, 
i32 0, i32 0
+// OGCG-NEXT:   store i64 %u.coerce, ptr %coerce.dive, align 8
+// OGCG-NEXT:   store i8 0, ptr %u, align 8
+// OGCG-NEXT:   %0 = load i8, ptr %u, align 8
+// OGCG-NEXT:   store i32 1, ptr %u, align 8
+// OGCG-NEXT:   %1 = load i32, ptr %u, align 8
+// OGCG-NEXT:   store float 0x3FB99999A0000000, ptr %u, align 8
+// OGCG-NEXT:   %2 = load float, ptr %u, align 8
+// OGCG-NEXT:   store double 1.000000e-01, ptr %u, align 8
+// OGCG-NEXT:   %3 = load double, ptr %u, align 8
+// OGCG-NEXT:   ret void
\ No newline at end of file

>From b596096bc5d0c5b09df62c225577f1a8fd05bdd1 Mon Sep 17 00:00:00 2001
From: Iris Shi <0...@owo.li>
Date: Wed, 30 Apr 2025 12:39:12 +0800
Subject: [PATCH 2/2] apply suggestions

---
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  22 +-
 clang/lib/CIR/CodeGen/CIRGenRecordLayout.h    |   6 +-
 .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp |  22 +-
 clang/lib/CIR/Dialect/IR/CIRTypes.cpp         |  31 +--
 clang/test/CIR/CodeGen/union.c                | 221 ++++++++++++------
 5 files changed, 185 insertions(+), 117 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 9069d1a2cf6ac..1a9d84afd2617 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -319,24 +319,20 @@ LValue CIRGenFunction::emitLValueForField(LValue base, 
const FieldDecl *field) {
   unsigned recordCVR = base.getVRQualifiers();
 
   llvm::StringRef fieldName = field->getName();
+  unsigned fieldIndex;
+  assert(!cir::MissingFeatures::lambdaFieldToName());
 
-  if (rec->isUnion()) {
-    unsigned fieldIndex = field->getFieldIndex();
-    assert(!cir::MissingFeatures::lambdaFieldToName());
-    addr = emitAddrOfFieldStorage(addr, field, fieldName, fieldIndex);
-
-  } else {
-    assert(!cir::MissingFeatures::preservedAccessIndexRegion());
-
+  if (rec->isUnion())
+    fieldIndex = field->getFieldIndex();
+  else {
     const CIRGenRecordLayout &layout =
         cgm.getTypes().getCIRGenRecordLayout(field->getParent());
-    unsigned fieldIndex = layout.getCIRFieldNo(field);
-
-    assert(!cir::MissingFeatures::lambdaFieldToName());
-
-    addr = emitAddrOfFieldStorage(addr, field, fieldName, fieldIndex);
+    fieldIndex = layout.getCIRFieldNo(field);
   }
 
+  addr = emitAddrOfFieldStorage(addr, field, fieldName, fieldIndex);
+  assert(!cir::MissingFeatures::preservedAccessIndexRegion());
+
   // If this is a reference field, load the reference right now.
   if (fieldType->isReferenceType()) {
     cgm.errorNYI(field->getSourceRange(), "emitLValueForField: reference 
type");
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
index 39a9d16ffd766..11768b042e87e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
@@ -31,7 +31,7 @@ class CIRGenRecordLayout {
 
   /// Map from (non-bit-field) record field to the corresponding cir record 
type
   /// field no. This info is populated by the record builder.
-  llvm::DenseMap<const clang::FieldDecl *, unsigned> fieldInfo;
+  llvm::DenseMap<const clang::FieldDecl *, unsigned> fieldIdxMap;
 
 public:
   CIRGenRecordLayout(cir::RecordType completeObjectType)
@@ -44,8 +44,8 @@ class CIRGenRecordLayout {
   /// Return cir::RecordType element number that corresponds to the field FD.
   unsigned getCIRFieldNo(const clang::FieldDecl *fd) const {
     fd = fd->getCanonicalDecl();
-    assert(fieldInfo.count(fd) && "Invalid field for record!");
-    return fieldInfo.lookup(fd);
+    assert(fieldIdxMap.count(fd) && "Invalid field for record!");
+    return fieldIdxMap.lookup(fd);
   }
 };
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index 7b9631daacfdd..5bcd408b4072a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -142,7 +142,7 @@ struct CIRRecordLowering final {
   std::vector<MemberInfo> members;
   // Output fields, consumed by CIRGenTypes::computeRecordLayout
   llvm::SmallVector<mlir::Type, 16> fieldTypes;
-  llvm::DenseMap<const FieldDecl *, unsigned> fields;
+  llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;
   cir::CIRDataLayout dataLayout;
 
   LLVM_PREFERRED_TYPE(bool)
@@ -208,7 +208,8 @@ void CIRRecordLowering::fillOutputFields() {
       fieldTypes.push_back(member.data);
     if (member.kind == MemberInfo::InfoKind::Field) {
       if (member.fieldDecl)
-        fields[member.fieldDecl->getCanonicalDecl()] = fieldTypes.size() - 1;
+        fieldIdxMap[member.fieldDecl->getCanonicalDecl()] =
+            fieldTypes.size() - 1;
       // A field without storage must be a bitfield.
       assert(!cir::MissingFeatures::bitfields());
     }
@@ -310,7 +311,7 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, 
cir::RecordType *ty) {
   assert(!cir::MissingFeatures::bitfields());
 
   // Add all the field numbers.
-  rl->fieldInfo.swap(lowering.fields);
+  rl->fieldIdxMap.swap(lowering.fieldIdxMap);
 
   // Dump the layout, if requested.
   if (getASTContext().getLangOpts().DumpRecordLayouts) {
@@ -327,10 +328,7 @@ void CIRRecordLowering::lowerUnion() {
   bool seenNamedMember = false;
 
   // Iterate through the fields setting bitFieldInfo and the Fields array. Also
-  // locate the "most appropriate" storage type.  The heuristic for finding the
-  // storage type isn't necessary, the first (non-0-length-bitfield) field's
-  // type would work fine and be simpler but would be different than what we've
-  // been doing and cause lit tests to change.
+  // locate the "most appropriate" storage type.
   for (const FieldDecl *field : recordDecl->fields()) {
     mlir::Type fieldType;
     if (field->isBitField())
@@ -339,12 +337,13 @@ void CIRRecordLowering::lowerUnion() {
     else
       fieldType = getStorageType(field);
 
-    fields[field->getCanonicalDecl()] = 0;
+    // This maps a field to its index. For unions, the index is always 0.
+    fieldIdxMap[field->getCanonicalDecl()] = 0;
 
     // Compute zero-initializable status.
     // This union might not be zero initialized: it may contain a pointer to
     // data member which might have some exotic initialization sequence.
-    // If this is the case, then we aught not to try and come up with a 
"better"
+    // If this is the case, then we ought not to try and come up with a 
"better"
     // type, it might not be very easy to come up with a Constant which
     // correctly initializes it.
     if (!seenNamedMember) {
@@ -380,9 +379,8 @@ void CIRRecordLowering::lowerUnion() {
 
   if (layoutSize < getSize(storageType))
     storageType = getByteArrayType(layoutSize);
-
-  // NOTE(cir): Defer padding calculations to the lowering process.
-  appendPaddingBytes(layoutSize - getSize(storageType));
+  else
+    appendPaddingBytes(layoutSize - getSize(storageType));
 
   // Set packed if we need it.
   if (layoutSize % getAlignment(storageType))
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp 
b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index f61fc750d7c0e..d0c80911c3863 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -235,25 +235,18 @@ void RecordType::complete(ArrayRef<Type> members, bool 
packed, bool padded) {
 /// Recurses into union members never returning a union as the largest member.
 Type RecordType::getLargestMember(const ::mlir::DataLayout &dataLayout) const {
   assert(isUnion() && "Only call getLargestMember on unions");
-  Type largestMember;
-  unsigned largestMemberSize = 0;
-  unsigned numElements = getNumElements();
-  auto members = getMembers();
-  if (getPadded())
-    numElements -= 1; // The last element is padding.
-  for (unsigned i = 0; i < numElements; ++i) {
-    Type ty = members[i];
-    if (!largestMember ||
-        dataLayout.getTypeABIAlignment(ty) >
-            dataLayout.getTypeABIAlignment(largestMember) ||
-        (dataLayout.getTypeABIAlignment(ty) ==
-             dataLayout.getTypeABIAlignment(largestMember) &&
-         dataLayout.getTypeSize(ty) > largestMemberSize)) {
-      largestMember = ty;
-      largestMemberSize = dataLayout.getTypeSize(largestMember);
-    }
-  }
-  return largestMember;
+  llvm::ArrayRef<Type> members = getMembers();
+  // If the union is padded, we need to ignore the last member,
+  // which is the padding.
+  return *std::max_element(
+      members.begin(), getPadded() ? members.end() - 1 : members.end(),
+      [&](Type lhs, Type rhs) {
+        return dataLayout.getTypeABIAlignment(lhs) <
+                   dataLayout.getTypeABIAlignment(rhs) ||
+               (dataLayout.getTypeABIAlignment(lhs) ==
+                    dataLayout.getTypeABIAlignment(rhs) &&
+                dataLayout.getTypeSize(lhs) < dataLayout.getTypeSize(rhs));
+      });
 }
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/CodeGen/union.c b/clang/test/CIR/CodeGen/union.c
index 71cb9c2b20ca1..790fbb7effdda 100644
--- a/clang/test/CIR/CodeGen/union.c
+++ b/clang/test/CIR/CodeGen/union.c
@@ -26,6 +26,24 @@ union U2 {
 // LLVM: %union.U2 = type { double }
 // OGCG: %union.U2 = type { double }
 
+union U3 {
+  char c[5];
+  int i;
+} __attribute__((packed));
+
+// CIR:  !rec_U3 = !cir.record<union "U3" packed padded {!cir.array<!s8i x 5>, 
!s32i, !u8i}>
+// LLVM: %union.U3 = type <{ i32, i8 }>
+// OGCG: %union.U3 = type <{ i32, i8 }>
+
+union U4 {
+  char c[5];
+  int i;
+};
+
+// CIR:  !rec_U4 = !cir.record<union "U4" padded {!cir.array<!s8i x 5>, !s32i, 
!cir.array<!u8i x 4>}>
+// LLVM: %union.U4 = type { i32, [4 x i8] }
+// OGCG: %union.U4 = type { i32, [4 x i8] }
+
 union IncompleteU *p;
 
 // CIR:  cir.global external @p = #cir.ptr<null> : !cir.ptr<!rec_IncompleteU>
@@ -56,33 +74,32 @@ int f2(void) {
 }
 
 // CIR:      cir.func @f2() -> !s32i
-// CIR-NEXT:   %0 = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"] {alignment 
= 4 : i64}
-// CIR-NEXT:   %1 = cir.alloca !rec_U1, !cir.ptr<!rec_U1>, ["u"] {alignment = 
4 : i64}
-// CIR-NEXT:   %2 = cir.const #cir.int<42> : !s32i
-// CIR-NEXT:   %3 = cir.get_member %1[0] {name = "n"} : !cir.ptr<!rec_U1> -> 
!cir.ptr<!s32i>
-// CIR-NEXT:   cir.store %2, %3 : !s32i, !cir.ptr<!s32i>
-// CIR-NEXT:   %4 = cir.get_member %1[0] {name = "n"} : !cir.ptr<!rec_U1> -> 
!cir.ptr<!s32i>
-// CIR-NEXT:   %5 = cir.load %4 : !cir.ptr<!s32i>, !s32i
-// CIR-NEXT:   cir.store %5, %0 : !s32i, !cir.ptr<!s32i>
-// CIR-NEXT:   %6 = cir.load %0 : !cir.ptr<!s32i>, !s32i
-// CIR-NEXT:   cir.return %6 : !s32i
+// CIR-NEXT:   %[[RETVAL_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, 
["__retval"] {alignment = 4 : i64}
+// CIR-NEXT:   %[[U:.*]] = cir.alloca !rec_U1, !cir.ptr<!rec_U1>, ["u"] 
{alignment = 4 : i64}
+// CIR-NEXT:   %[[I:.*]] = cir.const #cir.int<42> : !s32i
+// CIR-NEXT:   %[[N:.*]] = cir.get_member %[[U]][0] {name = "n"} : 
!cir.ptr<!rec_U1> -> !cir.ptr<!s32i>
+// CIR-NEXT:   cir.store %[[I]], %[[N]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   %[[N2:.*]] = cir.get_member %[[U]][0] {name = "n"} : 
!cir.ptr<!rec_U1> -> !cir.ptr<!s32i>
+// CIR-NEXT:   %[[VAL:.*]] = cir.load %[[N2]] : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:   cir.store %[[VAL]], %[[RETVAL_ADDR]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   %[[RET:.*]] = cir.load %[[RETVAL_ADDR]] : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:   cir.return %[[RET]] : !s32i
 
 // LLVM:      define i32 @f2()
-// LLVM-NEXT:   %1 = alloca i32, i64 1, align 4
-// LLVM-NEXT:   %2 = alloca %union.U1, i64 1, align 4
-// LLVM-NEXT:   store i32 42, ptr %2, align 4
-// LLVM-NEXT:   %3 = load i32, ptr %2, align 4
-// LLVM-NEXT:   store i32 %3, ptr %1, align 4
-// LLVM-NEXT:   %4 = load i32, ptr %1, align 4
-// LLVM-NEXT:   ret i32 %4
+// LLVM-NEXT:   %[[RETVAL:.*]] = alloca i32, i64 1, align 4
+// LLVM-NEXT:   %[[U:.*]] = alloca %union.U1, i64 1, align 4
+// LLVM-NEXT:   store i32 42, ptr %[[U]], align 4
+// LLVM-NEXT:   %[[N_VAL:.*]] = load i32, ptr %[[U]], align 4
+// LLVM-NEXT:   store i32 %[[N_VAL]], ptr %[[RETVAL]], align 4
+// LLVM-NEXT:   %[[RET:.*]] = load i32, ptr %[[RETVAL]], align 4
+// LLVM-NEXT:   ret i32 %[[RET]]
 
 //      OGCG: define dso_local i32 @f2()
 // OGCG-NEXT: entry:
-// OGCG-NEXT: %u = alloca %union.U1, align 4
-// OGCG-NEXT: store i32 42, ptr %u, align 4
-// OGCG-NEXT: %0 = load i32, ptr %u, align 4
-// OGCG-NEXT: ret i32 %0
-
+// OGCG-NEXT: %[[U:.*]] = alloca %union.U1, align 4
+// OGCG-NEXT: store i32 42, ptr %[[U]], align 4
+// OGCG-NEXT: %[[N_VAL:.*]] = load i32, ptr %[[U]], align 4
+// OGCG-NEXT: ret i32 %[[N_VAL]]
 
 void shouldGenerateUnionAccess(union U2 u) {
   u.b = 0;
@@ -95,56 +112,120 @@ void shouldGenerateUnionAccess(union U2 u) {
   u.d;
 }
 
-// CIR:      cir.func @shouldGenerateUnionAccess(%arg0: !rec_U2
-// CIR-NEXT:   %0 = cir.alloca !rec_U2, !cir.ptr<!rec_U2>, ["u", init] 
{alignment = 8 : i64}
-// CIR-NEXT:   cir.store %arg0, %0 : !rec_U2, !cir.ptr<!rec_U2>
-// CIR-NEXT:   %1 = cir.const #cir.int<0> : !s32i
-// CIR-NEXT:   %2 = cir.cast(integral, %1 : !s32i), !s8i
-// CIR-NEXT:   %3 = cir.get_member %0[0] {name = "b"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s8i>
-// CIR-NEXT:   cir.store %2, %3 : !s8i, !cir.ptr<!s8i>
-// CIR-NEXT:   %4 = cir.get_member %0[0] {name = "b"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s8i>
-// CIR-NEXT:   %5 = cir.load %4 : !cir.ptr<!s8i>, !s8i
-// CIR-NEXT:   %6 = cir.const #cir.int<1> : !s32i
-// CIR-NEXT:   %7 = cir.get_member %0[2] {name = "i"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s32i>
-// CIR-NEXT:   cir.store %6, %7 : !s32i, !cir.ptr<!s32i>
-// CIR-NEXT:   %8 = cir.get_member %0[2] {name = "i"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!s32i>
-// CIR-NEXT:   %9 = cir.load %8 : !cir.ptr<!s32i>, !s32i
-// CIR-NEXT:   %10 = cir.const #cir.fp<1.000000e-01> : !cir.float
-// CIR-NEXT:   %11 = cir.get_member %0[3] {name = "f"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.float>
-// CIR-NEXT:   cir.store %10, %11 : !cir.float, !cir.ptr<!cir.float>
-// CIR-NEXT:   %12 = cir.get_member %0[3] {name = "f"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.float>
-// CIR-NEXT:   %13 = cir.load %12 : !cir.ptr<!cir.float>, !cir.float
-// CIR-NEXT:   %14 = cir.const #cir.fp<1.000000e-01> : !cir.double
-// CIR-NEXT:   %15 = cir.get_member %0[4] {name = "d"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.double>
-// CIR-NEXT:   cir.store %14, %15 : !cir.double, !cir.ptr<!cir.double>
-// CIR-NEXT:   %16 = cir.get_member %0[4] {name = "d"} : !cir.ptr<!rec_U2> -> 
!cir.ptr<!cir.double>
-// CIR-NEXT:   %17 = cir.load %16 : !cir.ptr<!cir.double>, !cir.double
+// CIR:      cir.func @shouldGenerateUnionAccess(%[[ARG:.*]]: !rec_U2
+// CIR-NEXT:   %[[U:.*]] = cir.alloca !rec_U2, !cir.ptr<!rec_U2>, ["u", init] 
{alignment = 8 : i64}
+// CIR-NEXT:   cir.store %[[ARG]], %[[U]] : !rec_U2, !cir.ptr<!rec_U2>
+// CIR-NEXT:   %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR-NEXT:   %[[ZERO_CHAR:.*]] = cir.cast(integral, %[[ZERO]] : !s32i), !s8i
+// CIR-NEXT:   %[[B_PTR:.*]] = cir.get_member %[[U]][0] {name = "b"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!s8i>
+// CIR-NEXT:   cir.store %[[ZERO_CHAR]], %[[B_PTR]] : !s8i, !cir.ptr<!s8i>
+// CIR-NEXT:   %[[B_PTR2:.*]] = cir.get_member %[[U]][0] {name = "b"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!s8i>
+// CIR-NEXT:   %[[B_VAL:.*]] = cir.load %[[B_PTR2]] : !cir.ptr<!s8i>, !s8i
+// CIR-NEXT:   %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
+// CIR-NEXT:   %[[I_PTR:.*]] = cir.get_member %[[U]][2] {name = "i"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!s32i>
+// CIR-NEXT:   cir.store %[[ONE]], %[[I_PTR]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   %[[I_PTR2:.*]] = cir.get_member %[[U]][2] {name = "i"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!s32i>
+// CIR-NEXT:   %[[I_VAL:.*]] = cir.load %[[I_PTR2]] : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:   %[[FLOAT_VAL:.*]] = cir.const #cir.fp<1.000000e-01> : !cir.float
+// CIR-NEXT:   %[[F_PTR:.*]] = cir.get_member %[[U]][3] {name = "f"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!cir.float>
+// CIR-NEXT:   cir.store %[[FLOAT_VAL]], %[[F_PTR]] : !cir.float, 
!cir.ptr<!cir.float>
+// CIR-NEXT:   %[[F_PTR2:.*]] = cir.get_member %[[U]][3] {name = "f"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!cir.float>
+// CIR-NEXT:   %[[F_VAL:.*]] = cir.load %[[F_PTR2]] : !cir.ptr<!cir.float>, 
!cir.float
+// CIR-NEXT:   %[[DOUBLE_VAL:.*]] = cir.const #cir.fp<1.000000e-01> : 
!cir.double
+// CIR-NEXT:   %[[D_PTR:.*]] = cir.get_member %[[U]][4] {name = "d"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!cir.double>
+// CIR-NEXT:   cir.store %[[DOUBLE_VAL]], %[[D_PTR]] : !cir.double, 
!cir.ptr<!cir.double>
+// CIR-NEXT:   %[[D_PTR2:.*]] = cir.get_member %[[U]][4] {name = "d"} : 
!cir.ptr<!rec_U2> -> !cir.ptr<!cir.double>
+// CIR-NEXT:   %[[D_VAL:.*]] = cir.load %[[D_PTR2]] : !cir.ptr<!cir.double>, 
!cir.double
 // CIR-NEXT:   cir.return
 
-// LLVM:      define void @shouldGenerateUnionAccess(%union.U2 %0) {
-// LLVM-NEXT:   %2 = alloca %union.U2, i64 1, align 8
-// LLVM-NEXT:   store %union.U2 %0, ptr %2, align 8
-// LLVM-NEXT:   store i8 0, ptr %2, align 1
-// LLVM-NEXT:   %3 = load i8, ptr %2, align 1
-// LLVM-NEXT:   store i32 1, ptr %2, align 4
-// LLVM-NEXT:   %4 = load i32, ptr %2, align 4
-// LLVM-NEXT:   store float 0x3FB99999A0000000, ptr %2, align 4
-// LLVM-NEXT:   %5 = load float, ptr %2, align 4
-// LLVM-NEXT:   store double 1.000000e-01, ptr %2, align 8
-// LLVM-NEXT:   %6 = load double, ptr %2, align 8
+// LLVM:      define void @shouldGenerateUnionAccess(%union.U2 %[[ARG:.*]])
+// LLVM-NEXT:   %[[U:.*]] = alloca %union.U2, i64 1, align 8
+// LLVM-NEXT:   store %union.U2 %[[ARG]], ptr %[[U]], align 8
+// LLVM-NEXT:   store i8 0, ptr %[[U]], align 1
+// LLVM-NEXT:   %[[B_VAL:.*]] = load i8, ptr %[[U]], align 1
+// LLVM-NEXT:   store i32 1, ptr %[[U]], align 4
+// LLVM-NEXT:   %[[I_VAL:.*]] = load i32, ptr %[[U]], align 4
+// LLVM-NEXT:   store float 0x3FB99999A0000000, ptr %[[U]], align 4
+// LLVM-NEXT:   %[[F_VAL:.*]] = load float, ptr %[[U]], align 4
+// LLVM-NEXT:   store double 1.000000e-01, ptr %[[U]], align 8
+// LLVM-NEXT:   %[[D_VAL:.*]] = load double, ptr %[[U]], align 8
 // LLVM-NEXT:   ret void
 
-// OGCG:      define dso_local void @shouldGenerateUnionAccess(i64 %u.coerce) 
#0 {
+// OGCG:      define dso_local void @shouldGenerateUnionAccess(i64 %[[ARG:.*]])
 // OGCG-NEXT: entry:
-// OGCG-NEXT:   %u = alloca %union.U2, align 8
-// OGCG-NEXT:   %coerce.dive = getelementptr inbounds nuw %union.U2, ptr %u, 
i32 0, i32 0
-// OGCG-NEXT:   store i64 %u.coerce, ptr %coerce.dive, align 8
-// OGCG-NEXT:   store i8 0, ptr %u, align 8
-// OGCG-NEXT:   %0 = load i8, ptr %u, align 8
-// OGCG-NEXT:   store i32 1, ptr %u, align 8
-// OGCG-NEXT:   %1 = load i32, ptr %u, align 8
-// OGCG-NEXT:   store float 0x3FB99999A0000000, ptr %u, align 8
-// OGCG-NEXT:   %2 = load float, ptr %u, align 8
-// OGCG-NEXT:   store double 1.000000e-01, ptr %u, align 8
-// OGCG-NEXT:   %3 = load double, ptr %u, align 8
-// OGCG-NEXT:   ret void
\ No newline at end of file
+// OGCG-NEXT:   %[[U:.*]] = alloca %union.U2, align 8
+// OGCG-NEXT:   %[[COERCE_DIVE:.*]] = getelementptr inbounds nuw %union.U2, 
ptr %[[U]], i32 0, i32 0
+// OGCG-NEXT:   store i64 %[[ARG]], ptr %[[COERCE_DIVE]], align 8
+// OGCG-NEXT:   store i8 0, ptr %[[U]], align 8
+// OGCG-NEXT:   %[[B_VAL:.*]] = load i8, ptr %[[U]], align 8
+// OGCG-NEXT:   store i32 1, ptr %[[U]], align 8
+// OGCG-NEXT:   %[[I_VAL:.*]] = load i32, ptr %[[U]], align 8
+// OGCG-NEXT:   store float 0x3FB99999A0000000, ptr %[[U]], align 8
+// OGCG-NEXT:   %[[F_VAL:.*]] = load float, ptr %[[U]], align 8
+// OGCG-NEXT:   store double 1.000000e-01, ptr %[[U]], align 8
+// OGCG-NEXT:   %[[D_VAL:.*]] = load double, ptr %[[U]], align 8
+// OGCG-NEXT:   ret void
+
+void f3(union U3 u) {
+  u.c[2] = 0;
+}
+
+// CIR:      cir.func @f3(%[[ARG:.*]]: !rec_U3
+// CIR-NEXT:   %[[U:.*]] = cir.alloca !rec_U3, !cir.ptr<!rec_U3>, ["u", init] 
{alignment = 1 : i64}
+// CIR-NEXT:   cir.store %[[ARG]], %[[U]] : !rec_U3, !cir.ptr<!rec_U3>
+// CIR-NEXT:   %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR-NEXT:   %[[ZERO_CHAR:.*]] = cir.cast(integral, %[[ZERO]] : !s32i), !s8i
+// CIR-NEXT:   %[[IDX:.*]] = cir.const #cir.int<2> : !s32i
+// CIR-NEXT:   %[[C_PTR:.*]] = cir.get_member %[[U]][0] {name = "c"} : 
!cir.ptr<!rec_U3> -> !cir.ptr<!cir.array<!s8i x 5>>
+// CIR-NEXT:   %[[C_DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[C_PTR]] : 
!cir.ptr<!cir.array<!s8i x 5>>), !cir.ptr<!s8i>
+// CIR-NEXT:   %[[ELEM_PTR:.*]] = cir.ptr_stride(%[[C_DECAY]] : 
!cir.ptr<!s8i>, %[[IDX]] : !s32i), !cir.ptr<!s8i>
+// CIR-NEXT:   cir.store %[[ZERO_CHAR]], %[[ELEM_PTR]] : !s8i, !cir.ptr<!s8i>
+// CIR-NEXT:   cir.return
+
+// LLVM:      define void @f3(%union.U3 %[[ARG:.*]])
+// LLVM-NEXT:   %[[U:.*]] = alloca %union.U3, i64 1, align 1
+// LLVM-NEXT:   store %union.U3 %[[ARG]], ptr %[[U]], align 1
+// LLVM-NEXT:   %[[C_PTR:.*]] = getelementptr i8, ptr %[[U]], i32 0
+// LLVM-NEXT:   %[[ELEM_PTR:.*]] = getelementptr i8, ptr %[[C_PTR]], i64 2
+// LLVM-NEXT:   store i8 0, ptr %[[ELEM_PTR]], align 1
+// LLVM-NEXT:   ret void
+
+// OGCG:      define dso_local void @f3(i40 %[[ARG:.*]])
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   %[[U:.*]] = alloca %union.U3, align 1
+// OGCG-NEXT:   store i40 %[[ARG]], ptr %[[U]], align 1
+// OGCG-NEXT:   %[[ARRAYIDX:.*]] = getelementptr inbounds [5 x i8], ptr 
%[[U]], i64 0, i64 2
+// OGCG-NEXT:   store i8 0, ptr %[[ARRAYIDX]], align 1
+// OGCG-NEXT:   ret void
+
+void f5(union U4 u) {
+  u.c[4] = 65;
+}
+
+// CIR:      cir.func @f5(%[[ARG:.*]]: !rec_U4
+// CIR-NEXT:   %[[U:.*]] = cir.alloca !rec_U4, !cir.ptr<!rec_U4>, ["u", init] 
{alignment = 4 : i64}
+// CIR-NEXT:   cir.store %[[ARG]], %[[U]] : !rec_U4, !cir.ptr<!rec_U4>
+// CIR-NEXT:   %[[CHAR_VAL:.*]] = cir.const #cir.int<65> : !s32i
+// CIR-NEXT:   %[[CHAR_CAST:.*]] = cir.cast(integral, %[[CHAR_VAL]] : !s32i), 
!s8i
+// CIR-NEXT:   %[[IDX:.*]] = cir.const #cir.int<4> : !s32i
+// CIR-NEXT:   %[[C_PTR:.*]] = cir.get_member %[[U]][0] {name = "c"} : 
!cir.ptr<!rec_U4> -> !cir.ptr<!cir.array<!s8i x 5>>
+// CIR-NEXT:   %[[C_DECAY:.*]] = cir.cast(array_to_ptrdecay, %[[C_PTR]] : 
!cir.ptr<!cir.array<!s8i x 5>>), !cir.ptr<!s8i>
+// CIR-NEXT:   %[[ELEM_PTR:.*]] = cir.ptr_stride(%[[C_DECAY]] : 
!cir.ptr<!s8i>, %[[IDX]] : !s32i), !cir.ptr<!s8i>
+// CIR-NEXT:   cir.store %[[CHAR_CAST]], %[[ELEM_PTR]] : !s8i, !cir.ptr<!s8i>
+// CIR-NEXT:   cir.return
+
+// LLVM:      define void @f5(%union.U4 %[[ARG:.*]])
+// LLVM-NEXT:   %[[U:.*]] = alloca %union.U4, i64 1, align 4
+// LLVM-NEXT:   store %union.U4 %[[ARG]], ptr %[[U]], align 4
+// LLVM-NEXT:   %[[C_PTR:.*]] = getelementptr i8, ptr %[[U]], i32 0
+// LLVM-NEXT:   %[[ELEM_PTR:.*]] = getelementptr i8, ptr %[[C_PTR]], i64 4
+// LLVM-NEXT:   store i8 65, ptr %[[ELEM_PTR]], align 1
+// LLVM-NEXT:   ret void
+
+// OGCG:      define dso_local void @f5(i64 %[[ARG:.*]])
+// OGCG-NEXT: entry:
+// OGCG-NEXT:   %[[U:.*]] = alloca %union.U4, align 4
+// OGCG-NEXT:   store i64 %[[ARG]], ptr %[[U]], align 4
+// OGCG-NEXT:   %[[ARRAYIDX:.*]] = getelementptr inbounds [5 x i8], ptr 
%[[U]], i64 0, i64 4
+// OGCG-NEXT:   store i8 65, ptr %[[ARRAYIDX]], align 4
+// OGCG-NEXT:   ret void

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to