Author: Iris Shi
Date: 2025-05-01T07:56:38+08:00
New Revision: 708053cd7ec576c67fd1c72cd6b836987fbee2ce

URL: 
https://github.com/llvm/llvm-project/commit/708053cd7ec576c67fd1c72cd6b836987fbee2ce
DIFF: 
https://github.com/llvm/llvm-project/commit/708053cd7ec576c67fd1c72cd6b836987fbee2ce.diff

LOG: [CIR] Upstream initial support for union type (#137501)

Closes #136059

Added: 
    

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIRTypes.td
    clang/lib/CIR/CodeGen/CIRGenExpr.cpp
    clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
    clang/lib/CIR/CodeGen/CIRGenRecordLayout.h
    clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
    clang/lib/CIR/Dialect/IR/CIRTypes.cpp
    clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
    clang/test/CIR/CodeGen/union.c

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td 
b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index de754a982edcd..6ca6fbeeb6165 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -531,6 +531,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 a50e1fd18c807..da5a0b97a395e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -317,20 +317,21 @@ 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);
-
+  unsigned fieldIndex;
   assert(!cir::MissingFeatures::lambdaFieldToName());
 
+  if (rec->isUnion())
+    fieldIndex = field->getFieldIndex();
+  else {
+    const CIRGenRecordLayout &layout =
+        cgm.getTypes().getCIRGenRecordLayout(field->getParent());
+    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()) {

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/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 83aba256cd48e..5bcd408b4072a 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;
@@ -130,12 +142,14 @@ 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)
   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;
   }
 
@@ -194,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());
     }
@@ -296,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) {
@@ -306,3 +321,68 @@ 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.
+  for (const FieldDecl *field : recordDecl->fields()) {
+    mlir::Type fieldType;
+    if (field->isBitField())
+      cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
+                                         "bitfields in lowerUnion");
+    else
+      fieldType = getStorageType(field);
+
+    // 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 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) {
+      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);
+  else
+    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 b35442964c169..ce85e48c4555e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -230,6 +230,25 @@ 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");
+  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));
+      });
+}
+
 
//===----------------------------------------------------------------------===//
 // Data Layout information for types
 
//===----------------------------------------------------------------------===//
@@ -237,10 +256,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 +266,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 +283,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 2c87255045df8..1afcee6857de1 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1436,7 +1436,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;
     }
 
@@ -1609,7 +1616,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..790fbb7effdda 100644
--- a/clang/test/CIR/CodeGen/union.c
+++ b/clang/test/CIR/CodeGen/union.c
@@ -5,25 +5,227 @@
 // 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 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>
+// 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:   %[[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:   %[[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: %[[N_VAL:.*]] = load i32, ptr %[[U]], align 4
+// OGCG-NEXT: ret i32 %[[N_VAL]]
+
+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(%[[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 %[[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 %[[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 %[[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