diff --git a/clang/lib/CIR/CodeGen/CIRDataLayout.h b/clang/lib/CIR/CodeGen/CIRDataLayout.h index bf9a49202cfb..ef9f737a5620 100644 --- a/clang/lib/CIR/CodeGen/CIRDataLayout.h +++ b/clang/lib/CIR/CodeGen/CIRDataLayout.h @@ -30,9 +30,18 @@ class CIRDataLayout { // `useABI` is `true` if not using prefered alignment. unsigned getAlignment(mlir::Type ty, bool useABI) const { + if (llvm::isa(ty)) { + auto sTy = ty.cast(); + if (sTy.getPacked() && useABI) + return 1; + } else if (llvm::isa(ty)) { + return getAlignment(ty.cast().getEltType(), useABI); + } + return useABI ? layout.getTypeABIAlignment(ty) : layout.getTypePreferredAlignment(ty); } + unsigned getABITypeAlign(mlir::Type ty) const { return getAlignment(ty, true); } @@ -60,7 +69,7 @@ class CIRDataLayout { /// returns 12 or 16 for x86_fp80, depending on alignment. unsigned getTypeAllocSize(mlir::Type Ty) const { // Round up to the next alignment boundary. - return llvm::alignTo(getTypeStoreSize(Ty), layout.getTypeABIAlignment(Ty)); + return llvm::alignTo(getTypeStoreSize(Ty), getABITypeAlign(Ty)); } unsigned getPointerTypeSizeInBits(mlir::Type Ty) const { diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index f196ea53b7de..4e346f19ecd4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -175,7 +175,6 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy { llvm::SmallVector members; auto structTy = type.dyn_cast(); assert(structTy && "expected cir.struct"); - assert(!packed && "unpacked struct is NYI"); // Collect members and check if they are all zero. bool isZero = true; @@ -200,7 +199,6 @@ class CIRGenBuilderTy : public CIRBaseBuilderTy { mlir::cir::ConstStructAttr getAnonConstStruct(mlir::ArrayAttr arrayAttr, bool packed = false, mlir::Type ty = {}) { - assert(!packed && "NYI"); llvm::SmallVector members; for (auto &f : arrayAttr) { auto ta = f.dyn_cast(); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp index a214ba50a8fa..1ccd34a5d4bd 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConst.cpp @@ -378,6 +378,9 @@ mlir::Attribute ConstantAggregateBuilder::buildFrom( ArrayRef UnpackedElems = Elems; llvm::SmallVector UnpackedElemStorage; if (DesiredSize < AlignedSize || DesiredSize.alignTo(Align) != DesiredSize) { + NaturalLayout = false; + Packed = true; + } else if (DesiredSize > AlignedSize) { llvm_unreachable("NYI"); } diff --git a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp index e331fd79ec43..35a51cc71892 100644 --- a/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp @@ -67,6 +67,9 @@ struct CIRRecordLowering final { void lower(bool nonVirtualBaseType); void lowerUnion(); + /// Determines if we need a packed llvm struct. + void determinePacked(bool NVBaseType); + void computeVolatileBitfields(); void accumulateBases(); void accumulateVPtrs(); @@ -294,6 +297,11 @@ void CIRRecordLowering::lower(bool nonVirtualBaseType) { // TODO: implemented packed structs // TODO: implement padding // TODO: support zeroInit + + members.push_back(StorageInfo(Size, getUIntNType(8))); + determinePacked(nonVirtualBaseType); + members.pop_back(); + fillOutputFields(); computeVolatileBitfields(); } @@ -613,6 +621,41 @@ void CIRRecordLowering::accumulateFields() { } } +void CIRRecordLowering::determinePacked(bool NVBaseType) { + if (isPacked) + return; + CharUnits Alignment = CharUnits::One(); + CharUnits NVAlignment = CharUnits::One(); + CharUnits NVSize = !NVBaseType && cxxRecordDecl + ? astRecordLayout.getNonVirtualSize() + : CharUnits::Zero(); + for (std::vector::const_iterator Member = members.begin(), + MemberEnd = members.end(); + Member != MemberEnd; ++Member) { + if (!Member->data) + continue; + // If any member falls at an offset that it not a multiple of its alignment, + // then the entire record must be packed. + if (Member->offset % getAlignment(Member->data)) + isPacked = true; + if (Member->offset < NVSize) + NVAlignment = std::max(NVAlignment, getAlignment(Member->data)); + Alignment = std::max(Alignment, getAlignment(Member->data)); + } + // If the size of the record (the capstone's offset) is not a multiple of the + // record's alignment, it must be packed. + if (members.back().offset % Alignment) + isPacked = true; + // If the non-virtual sub-object is not a multiple of the non-virtual + // sub-object's alignment, it must be packed. We cannot have a packed + // non-virtual sub-object and an unpacked complete object or vise versa. + if (NVSize % NVAlignment) + isPacked = true; + // Update the alignment of the sentinel. + if (!isPacked) + members.back().data = getUIntNType(astContext.toBits(Alignment)); +} + std::unique_ptr CIRGenTypes::computeRecordLayout(const RecordDecl *D, mlir::cir::StructType *Ty) { @@ -645,9 +688,8 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *D, // Fill in the struct *after* computing the base type. Filling in the body // signifies that the type is no longer opaque and record layout is complete, // but we may need to recursively layout D while laying D out as a base type. - *Ty = - Builder.getCompleteStructTy(builder.fieldTypes, getRecordTypeName(D, ""), - /*packed=*/false, D); + *Ty = Builder.getCompleteStructTy( + builder.fieldTypes, getRecordTypeName(D, ""), builder.isPacked, D); auto RL = std::make_unique( Ty ? *Ty : mlir::cir::StructType{}, diff --git a/clang/test/CIR/CodeGen/packed-structs.c b/clang/test/CIR/CodeGen/packed-structs.c new file mode 100644 index 000000000000..aefe8a60e28b --- /dev/null +++ b/clang/test/CIR/CodeGen/packed-structs.c @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s + +#pragma pack(1) + +typedef struct { + int a0; + char a1; +} A; + +typedef struct { + int b0; + char b1; + A a[6]; +} B; + +typedef struct { + int c0; + char c1; +} __attribute__((aligned(2))) C; + + +// CHECK: !ty_22A22 = !cir.struct, !cir.int}> +// CHECK: !ty_22C22 = !cir.struct, !cir.int}> +// CHECK: !ty_22B22 = !cir.struct, !cir.int, !cir.array, !cir.int}> x 6>}> + +// CHECK: cir.func {{.*@foo()}} +// CHECK: %0 = cir.alloca !ty_22A22, cir.ptr , ["a"] {alignment = 1 : i64} +// CHECK: %1 = cir.alloca !ty_22B22, cir.ptr , ["b"] {alignment = 1 : i64} +// CHECK: %2 = cir.alloca !ty_22C22, cir.ptr , ["c"] {alignment = 2 : i64} +void foo() { + A a; + B b; + C c; +} + +