Skip to content

Commit 8e8b4a2

Browse files
[CIR] Add ComputeVolatileBitfields Implementation
1 parent 6422035 commit 8e8b4a2

File tree

2 files changed

+173
-1
lines changed

2 files changed

+173
-1
lines changed

clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ struct CIRRecordLowering final {
9191
return astContext.getTargetInfo().getABI().starts_with("aapcs");
9292
}
9393

94+
/// Helper function to check if the target machine is BigEndian.
95+
bool isBE() const { return astContext.getTargetInfo().isBigEndian(); }
96+
9497
CharUnits bitsToCharUnits(uint64_t bitOffset) {
9598
return astContext.toCharUnitsFromBits(bitOffset);
9699
}
@@ -773,7 +776,103 @@ void CIRRecordLowering::computeVolatileBitfields() {
773776
!cirGenTypes.getCGModule().getCodeGenOpts().AAPCSBitfieldWidth)
774777
return;
775778

776-
assert(!cir::MissingFeatures::armComputeVolatileBitfields());
779+
for (auto &[field, info] : bitFields) {
780+
mlir::Type resLTy = cirGenTypes.convertTypeForMem(field->getType());
781+
782+
if (astContext.toBits(astRecordLayout.getAlignment()) <
783+
getSizeInBits(resLTy).getQuantity())
784+
continue;
785+
786+
// CIRRecordLowering::setBitFieldInfo() pre-adjusts the bit-field offsets
787+
// for big-endian targets, but it assumes a container of width
788+
// info.storageSize. Since AAPCS uses a different container size (width
789+
// of the type), we first undo that calculation here and redo it once
790+
// the bit-field offset within the new container is calculated.
791+
const unsigned oldOffset =
792+
isBE() ? info.storageSize - (info.offset + info.size) : info.offset;
793+
// Offset to the bit-field from the beginning of the struct.
794+
const unsigned absoluteOffset =
795+
astContext.toBits(info.storageOffset) + oldOffset;
796+
797+
// Container size is the width of the bit-field type.
798+
const unsigned storageSize = getSizeInBits(resLTy).getQuantity();
799+
// Nothing to do if the access uses the desired
800+
// container width and is naturally aligned.
801+
if (info.storageSize == storageSize && (oldOffset % storageSize == 0))
802+
continue;
803+
804+
// Offset within the container.
805+
unsigned offset = absoluteOffset & (storageSize - 1);
806+
// Bail out if an aligned load of the container cannot cover the entire
807+
// bit-field. This can happen for example, if the bit-field is part of a
808+
// packed struct. AAPCS does not define access rules for such cases, we let
809+
// clang to follow its own rules.
810+
if (offset + info.size > storageSize)
811+
continue;
812+
813+
// Re-adjust offsets for big-endian targets.
814+
if (isBE())
815+
offset = storageSize - (offset + info.size);
816+
817+
const CharUnits storageOffset =
818+
astContext.toCharUnitsFromBits(absoluteOffset & ~(storageSize - 1));
819+
const CharUnits end = storageOffset +
820+
astContext.toCharUnitsFromBits(storageSize) -
821+
CharUnits::One();
822+
823+
const ASTRecordLayout &layout =
824+
astContext.getASTRecordLayout(field->getParent());
825+
// If we access outside memory outside the record, than bail out.
826+
const CharUnits recordSize = layout.getSize();
827+
if (end >= recordSize)
828+
continue;
829+
830+
// Bail out if performing this load would access non-bit-fields members.
831+
bool conflict = false;
832+
for (const auto *f : recordDecl->fields()) {
833+
// Allow sized bit-fields overlaps.
834+
if (f->isBitField() && !f->isZeroLengthBitField())
835+
continue;
836+
837+
const CharUnits fOffset = astContext.toCharUnitsFromBits(
838+
layout.getFieldOffset(f->getFieldIndex()));
839+
840+
// As C11 defines, a zero sized bit-field defines a barrier, so
841+
// fields after and before it should be race condition free.
842+
// The AAPCS acknowledges it and imposes no restritions when the
843+
// natural container overlaps a zero-length bit-field.
844+
if (f->isZeroLengthBitField()) {
845+
if (end > fOffset && storageOffset < fOffset) {
846+
conflict = true;
847+
break;
848+
}
849+
}
850+
851+
const CharUnits fEnd =
852+
fOffset +
853+
astContext.toCharUnitsFromBits(astContext.toBits(
854+
getSizeInBits(cirGenTypes.convertTypeForMem(f->getType())))) -
855+
CharUnits::One();
856+
// If no overlap, continue.
857+
if (end < fOffset || fEnd < storageOffset)
858+
continue;
859+
860+
// The desired load overlaps a non-bit-field member, bail out.
861+
conflict = true;
862+
break;
863+
}
864+
865+
if (conflict)
866+
continue;
867+
// Write the new bit-field access parameters.
868+
// As the storage offset now is defined as the number of elements from the
869+
// start of the structure, we should divide the Offset by the element size.
870+
info.volatileStorageOffset =
871+
storageOffset /
872+
astContext.toCharUnitsFromBits(storageSize).getQuantity();
873+
info.volatileStorageSize = storageSize;
874+
info.volatileOffset = offset;
875+
}
777876
}
778877

779878
void CIRRecordLowering::accumulateBases(const CXXRecordDecl *cxxRecordDecl) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -fclangir -emit-cir -fdump-record-layouts %s -o %t.cir 1> %t.cirlayout
2+
// RUN: FileCheck --input-file=%t.cirlayout %s --check-prefix=CIR-LAYOUT
3+
4+
// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -emit-llvm -fdump-record-layouts %s -o %t.ll 1> %t.ogcglayout
5+
// RUN: FileCheck --input-file=%t.ogcglayout %s --check-prefix=OGCG-LAYOUT
6+
7+
typedef struct {
8+
unsigned int a : 9;
9+
volatile unsigned int b : 1;
10+
unsigned int c : 1;
11+
} st1;
12+
13+
// CIR-LAYOUT: BitFields:[
14+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:9 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:0 volatileStorageSize:32 volatileStorageOffset:0>
15+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:9 size:1 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:9 volatileStorageSize:32 volatileStorageOffset:0>
16+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:c offset:10 size:1 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:10 volatileStorageSize:32 volatileStorageOffset:0>
17+
18+
// OGCG-LAYOUT: BitFields:[
19+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:9 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:32 VolatileStorageOffset:0>
20+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:9 Size:1 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:9 VolatileStorageSize:32 VolatileStorageOffset:0>
21+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:10 Size:1 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:10 VolatileStorageSize:32 VolatileStorageOffset:0>
22+
23+
// different base types
24+
typedef struct{
25+
volatile short a : 3;
26+
volatile int b: 13;
27+
volatile long c : 5;
28+
} st2;
29+
30+
// CIR-LAYOUT: BitFields:[
31+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:3 isSigned:1 storageSize:32 storageOffset:0 volatileOffset:0 volatileStorageSize:16 volatileStorageOffset:0>
32+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:3 size:13 isSigned:1 storageSize:32 storageOffset:0 volatileOffset:3 volatileStorageSize:32 volatileStorageOffset:0>
33+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:c offset:16 size:5 isSigned:1 storageSize:32 storageOffset:0 volatileOffset:16 volatileStorageSize:64 volatileStorageOffset:0>
34+
35+
// OGCG-LAYOUT: BitFields:[
36+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:3 IsSigned:1 StorageSize:32 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:16 VolatileStorageOffset:0>
37+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:3 Size:13 IsSigned:1 StorageSize:32 StorageOffset:0 VolatileOffset:3 VolatileStorageSize:32 VolatileStorageOffset:0>
38+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:16 Size:5 IsSigned:1 StorageSize:32 StorageOffset:0 VolatileOffset:16 VolatileStorageSize:64 VolatileStorageOffset:0>
39+
40+
typedef struct{
41+
volatile unsigned int a : 3;
42+
unsigned int : 0; // zero-length bit-field force next field to aligned int boundary
43+
volatile unsigned int b : 5;
44+
}st3;
45+
46+
// CIR-LAYOUT: BitFields:[
47+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:3 isSigned:0 storageSize:8 storageOffset:0 volatileOffset:0 volatileStorageSize:32 volatileStorageOffset:0>
48+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:0 size:5 isSigned:0 storageSize:8 storageOffset:4 volatileOffset:0 volatileStorageSize:0 volatileStorageOffset:0>
49+
50+
// OGCG-LAYOUT: BitFields:[
51+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:32 VolatileStorageOffset:0>
52+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:5 IsSigned:0 StorageSize:8 StorageOffset:4 VolatileOffset:0 VolatileStorageSize:0 VolatileStorageOffset:0>
53+
54+
typedef struct{
55+
volatile unsigned int a : 3;
56+
unsigned int z: 2;
57+
volatile unsigned int b : 5;
58+
}st4;
59+
60+
// CIR-LAYOUT: BitFields:[
61+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:a offset:0 size:3 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:0 volatileStorageSize:32 volatileStorageOffset:0>
62+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:z offset:3 size:2 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:3 volatileStorageSize:32 volatileStorageOffset:0>
63+
// CIR-LAYOUT-NEXT: <CIRBitFieldInfo name:b offset:5 size:5 isSigned:0 storageSize:16 storageOffset:0 volatileOffset:5 volatileStorageSize:32 volatileStorageOffset:0>
64+
65+
// OGCG-LAYOUT: BitFields:[
66+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:0 VolatileStorageSize:32 VolatileStorageOffset:0>
67+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:3 Size:2 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:3 VolatileStorageSize:32 VolatileStorageOffset:0>
68+
// OGCG-LAYOUT-NEXT: <CGBitFieldInfo Offset:5 Size:5 IsSigned:0 StorageSize:16 StorageOffset:0 VolatileOffset:5 VolatileStorageSize:32 VolatileStorageOffset:0>
69+
70+
st1 s1;
71+
st2 s2;
72+
st3 s3;
73+
st4 s4;

0 commit comments

Comments
 (0)