Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
101 changes: 100 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ struct CIRRecordLowering final {
return astContext.getTargetInfo().getABI().starts_with("aapcs");
}

/// Helper function to check if the target machine is BigEndian.
bool isBE() const { return astContext.getTargetInfo().isBigEndian(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool isBE() const { return astContext.getTargetInfo().isBigEndian(); }
bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


CharUnits bitsToCharUnits(uint64_t bitOffset) {
return astContext.toCharUnitsFromBits(bitOffset);
}
Expand Down Expand Up @@ -773,7 +776,103 @@ void CIRRecordLowering::computeVolatileBitfields() {
!cirGenTypes.getCGModule().getCodeGenOpts().AAPCSBitfieldWidth)
return;

assert(!cir::MissingFeatures::armComputeVolatileBitfields());
for (auto &[field, info] : bitFields) {
mlir::Type resLTy = cirGenTypes.convertTypeForMem(field->getType());

if (astContext.toBits(astRecordLayout.getAlignment()) <
getSizeInBits(resLTy).getQuantity())
continue;

// CIRRecordLowering::setBitFieldInfo() pre-adjusts the bit-field offsets
// for big-endian targets, but it assumes a container of width
// info.storageSize. Since AAPCS uses a different container size (width
// of the type), we first undo that calculation here and redo it once
// the bit-field offset within the new container is calculated.
const unsigned oldOffset =
isBE() ? info.storageSize - (info.offset + info.size) : info.offset;
// Offset to the bit-field from the beginning of the struct.
const unsigned absoluteOffset =
astContext.toBits(info.storageOffset) + oldOffset;

// Container size is the width of the bit-field type.
const unsigned storageSize = getSizeInBits(resLTy).getQuantity();
// Nothing to do if the access uses the desired
// container width and is naturally aligned.
if (info.storageSize == storageSize && (oldOffset % storageSize == 0))
continue;

// Offset within the container.
unsigned offset = absoluteOffset & (storageSize - 1);
// Bail out if an aligned load of the container cannot cover the entire
// bit-field. This can happen for example, if the bit-field is part of a
// packed struct. AAPCS does not define access rules for such cases, we let
// clang to follow its own rules.
if (offset + info.size > storageSize)
continue;

// Re-adjust offsets for big-endian targets.
if (isBE())
offset = storageSize - (offset + info.size);

const CharUnits storageOffset =
astContext.toCharUnitsFromBits(absoluteOffset & ~(storageSize - 1));
const CharUnits end = storageOffset +
astContext.toCharUnitsFromBits(storageSize) -
CharUnits::One();

const ASTRecordLayout &layout =
astContext.getASTRecordLayout(field->getParent());
// If we access outside memory outside the record, than bail out.
const CharUnits recordSize = layout.getSize();
if (end >= recordSize)
continue;

// Bail out if performing this load would access non-bit-fields members.
bool conflict = false;
for (const auto *f : recordDecl->fields()) {
// Allow sized bit-fields overlaps.
if (f->isBitField() && !f->isZeroLengthBitField())
continue;

const CharUnits fOffset = astContext.toCharUnitsFromBits(
layout.getFieldOffset(f->getFieldIndex()));

// As C11 defines, a zero sized bit-field defines a barrier, so
// fields after and before it should be race condition free.
// The AAPCS acknowledges it and imposes no restritions when the
// natural container overlaps a zero-length bit-field.
if (f->isZeroLengthBitField()) {
if (end > fOffset && storageOffset < fOffset) {
conflict = true;
break;
}
}

const CharUnits fEnd =
fOffset +
astContext.toCharUnitsFromBits(astContext.toBits(
getSizeInBits(cirGenTypes.convertTypeForMem(f->getType())))) -
CharUnits::One();
// If no overlap, continue.
if (end < fOffset || fEnd < storageOffset)
continue;

// The desired load overlaps a non-bit-field member, bail out.
conflict = true;
break;
}

if (conflict)
continue;
// Write the new bit-field access parameters.
// As the storage offset now is defined as the number of elements from the
// start of the structure, we should divide the Offset by the element size.
info.volatileStorageOffset =
storageOffset /
astContext.toCharUnitsFromBits(storageSize).getQuantity();
info.volatileStorageSize = storageSize;
info.volatileOffset = offset;
}
}

void CIRRecordLowering::accumulateBases(const CXXRecordDecl *cxxRecordDecl) {
Expand Down
73 changes: 73 additions & 0 deletions clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -fclangir -emit-cir -fdump-record-layouts %s -o %t.cir 1> %t.cirlayout
// RUN: FileCheck --input-file=%t.cirlayout %s --check-prefix=CIR-LAYOUT

// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -emit-llvm -fdump-record-layouts %s -o %t.ll 1> %t.ogcglayout
// RUN: FileCheck --input-file=%t.ogcglayout %s --check-prefix=OGCG-LAYOUT

typedef struct {
unsigned int a : 9;
volatile unsigned int b : 1;
unsigned int c : 1;
} st1;

// CIR-LAYOUT: BitFields:[
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:9 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:0 volatileStorageSize:32 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:9 size:1 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:9 volatileStorageSize:32 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:c offset:10 size:1 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:10 volatileStorageSize:32 volatileStorageOffset:0>

// OGCG-LAYOUT: BitFields:[
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:9 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:32 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:9 Size:1 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:9 VolatileStorageSize:32 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:10 Size:1 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:10 VolatileStorageSize:32 VolatileStorageOffset:0>

// different base types
typedef struct{
volatile short a : 3;
volatile int b: 13;
volatile long c : 5;
} st2;

// CIR-LAYOUT: BitFields:[
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:3 isSigned:1 storageSize:32 storageOffset:0 volatileOffset:0 volatileStorageSize:16 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:3 size:13 isSigned:1 storageSize:32 storageOffset:0 volatileOffset:3 volatileStorageSize:32 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:c offset:16 size:5 isSigned:1 storageSize:32 storageOffset:0 volatileOffset:16 volatileStorageSize:64 volatileStorageOffset:0>

// OGCG-LAYOUT: BitFields:[
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:3 IsSigned:1 StorageSize:32 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:16 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:3 Size:13 IsSigned:1 StorageSize:32 StorageOffset:0 VolatileOffset:3 VolatileStorageSize:32 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:16 Size:5 IsSigned:1 StorageSize:32 StorageOffset:0 VolatileOffset:16 VolatileStorageSize:64 VolatileStorageOffset:0>

typedef struct{
volatile unsigned int a : 3;
unsigned int : 0; // zero-length bit-field force next field to aligned int boundary
volatile unsigned int b : 5;
}st3;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}st3;
} st3;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// CIR-LAYOUT: BitFields:[
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:3 isSigned:0 storageSize:8 storageOffset:0 volatileOffset:0 volatileStorageSize:32 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:0 size:5 isSigned:0 storageSize:8 storageOffset:4 volatileOffset:0 volatileStorageSize:0 volatileStorageOffset:0>

// OGCG-LAYOUT: BitFields:[
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:32 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:5 IsSigned:0 StorageSize:8 StorageOffset:4 VolatileOffset:0 VolatileStorageSize:0 VolatileStorageOffset:0>

typedef struct{
volatile unsigned int a : 3;
unsigned int z: 2;
volatile unsigned int b : 5;
}st4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}st4;
} st4;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// CIR-LAYOUT: BitFields:[
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:3 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:0 volatileStorageSize:32 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:z offset:3 size:2 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:3 volatileStorageSize:32 volatileStorageOffset:0>
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:5 size:5 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:5 volatileStorageSize:32 volatileStorageOffset:0>

// OGCG-LAYOUT: BitFields:[
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:32 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:3 Size:2 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:3 VolatileStorageSize:32 VolatileStorageOffset:0>
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:5 Size:5 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:5 VolatileStorageSize:32 VolatileStorageOffset:0>

st1 s1;
st2 s2;
st3 s3;
st4 s4;