Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIRDataLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ class CIRDataLayout {
return llvm::alignTo(getTypeStoreSize(Ty), getABITypeAlign(Ty).value());
}

/// Returns the offset in bits between successive objects of the
/// specified type, including alignment padding; always a multiple of 8.
///
/// If Ty is a scalable vector type, the scalable property will be set and
/// the runtime size will be a positive integer multiple of the base size.
///
/// This is the amount that alloca reserves for this type. For example,
/// returns 96 or 128 for x86_fp80, depending on alignment.
llvm::TypeSize getTypeAllocSizeInBits(mlir::Type ty) const {
return 8 * getTypeAllocSize(ty);
}

llvm::TypeSize getPointerTypeSizeInBits(mlir::Type Ty) const {
assert(mlir::isa<cir::PointerType>(Ty) &&
"This should only be called with a pointer type");
Expand Down
40 changes: 38 additions & 2 deletions clang/lib/CIR/CodeGen/CIRRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -513,8 +513,44 @@ RecordDecl::field_iterator
CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field,
RecordDecl::field_iterator FieldEnd) {

if (isDiscreteBitFieldABI())
llvm_unreachable("NYI");
if (isDiscreteBitFieldABI()) {
// run stores the first element of the current run of bitfields. FieldEnd is
// used as a special value to note that we don't have a current run. A
// bitfield run is a contiguous collection of bitfields that can be stored
// in the same storage block. Zero-sized bitfields and bitfields that would
// cross an alignment boundary break a run and start a new one.
RecordDecl::field_iterator run = FieldEnd;
// tail is the offset of the first bit off the end of the current run. It's
// used to determine if the ASTRecordLayout is treating these two bitfields
// as contiguous. StartBitOffset is offset of the beginning of the Run.
uint64_t startBitOffset, tail = 0;
for (; Field != FieldEnd && Field->isBitField(); ++Field) {
// Zero-width bitfields end runs.
if (Field->isZeroLengthBitField()) {
run = FieldEnd;
continue;
}
uint64_t bitOffset = getFieldBitOffset(*Field);
mlir::Type type = cirGenTypes.convertTypeForMem(Field->getType());
// If we don't have a run yet, or don't live within the previous run's
// allocated storage then we allocate some storage and start a new run.
if (run == FieldEnd || bitOffset >= tail) {
run = Field;
startBitOffset = bitOffset;
tail = startBitOffset + dataLayout.getTypeAllocSizeInBits(type);
// Add the storage member to the record. This must be added to the
// record before the bitfield members so that it gets laid out before
// the bitfields it contains get laid out.
members.push_back(StorageInfo(bitsToCharUnits(startBitOffset), type));
}
// Bitfields get the offset of their storage but come afterward and remain
// there after a stable sort.
members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),
MemberInfo::InfoKind::Field, nullptr,
*Field));
}
return Field;
}

CharUnits RegSize =
bitsToCharUnits(astContext.getTargetInfo().getRegisterWidth());
Expand Down
66 changes: 66 additions & 0 deletions clang/test/CIR/CodeGen/mms-bitfields.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mms-bitfields -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG

struct s1 {
int f32 : 2;
long long f64 : 30;
} s1;

// CIR-DAG: !rec_s1 = !cir.record<struct "s1" {!s32i, !s64i} #cir.record.decl.ast>
// LLVM-DAG: %struct.s1 = type { i32, i64 }
// OGCG-DAG: %struct.s1 = type { i32, i64 }

struct s2 {
int a : 24;
char b;
int c : 30;
} Clip;

// CIR-DAG: !rec_s2 = !cir.record<struct "s2" {!s32i, !s8i, !s32i} #cir.record.decl.ast>
// LLVM-DAG: %struct.s2 = type { i32, i8, i32 }
// OGCG-DAG: %struct.s2 = type { i32, i8, i32 }

#pragma pack (push,1)

struct Inner {
unsigned int A : 1;
unsigned int B : 1;
unsigned int C : 1;
unsigned int D : 30;
} Inner;

#pragma pack (pop)

// CIR-DAG: !rec_Inner = !cir.record<struct "Inner" {!u32i, !u32i} #cir.record.decl.ast>
// LLVM-DAG: %struct.Inner = type { i32, i32 }
// OGCG-DAG: %struct.Inner = type { i32, i32 }

#pragma pack(push, 1)

union HEADER {
struct A {
int : 3; // Bits 2:0
int a : 9; // Bits 11:3
int : 12; // Bits 23:12
int b : 17; // Bits 40:24
int : 7; // Bits 47:41
int c : 4; // Bits 51:48
int : 4; // Bits 55:52
int d : 3; // Bits 58:56
int : 5; // Bits 63:59
} Bits;
} HEADER;

#pragma pack(pop)

// CIR-DAG: !rec_A = !cir.record<struct "A" {!s32i, !s32i, !s32i} #cir.record.decl.ast>
// CIR-DAG: !rec_HEADER = !cir.record<union "HEADER" {!rec_A} #cir.record.decl.ast>
// LLVM-DAG: %struct.A = type { i32, i32, i32 }
// LLVM-DAG: %union.HEADER = type { %struct.A }
// OGCG-DAG: %struct.A = type { i32, i32, i32 }
// OGCG-DAG: %union.HEADER = type { %struct.A }

Loading