Author: Andres-Salamanca
Date: 2025-07-31T10:12:56-05:00
New Revision: 4005edd5c446f04a37856d69b47f1693364c12f0

URL: 
https://github.com/llvm/llvm-project/commit/4005edd5c446f04a37856d69b47f1693364c12f0
DIFF: 
https://github.com/llvm/llvm-project/commit/4005edd5c446f04a37856d69b47f1693364c12f0.diff

LOG: [CIR] Add ComputeVolatileBitfields Implementation (#151252)

This PR adds the implementation of the `ComputeVolatileBitfields`
function for the AAPCS ABI, following the rules described in [AAPCS64
ยง8.1.8.5 Volatile
Bit-fields](https://github.com/ARM-software/abi-aa/blob/f52e1ad3f81254497a83578dc102f6aac89e52d0/aapcs64/aapcs64.rst#8185volatile-bit-fields----preserving-number-and-width-of-container-accesses).
When accessing a volatile bit-field either reading or writing the
compiler must perform a load or store using the access size that matches
the width of the declared type (i.e., the type of the container), rather
than the packed bit-field size.
For example, if a field is declared as `int`, it must read or write 32
bits, even if the bit-field is only 3 bits wide.
The `ComputeVolatileBitfields` function calculates the correct values
and offsets necessary for proper lowering of volatile bitfields.
Support for emitting calls to `get_bitfield` and `set_bitfield` with the
correct access size for volatile bitfields will be implemented in a
future PR.

Added: 
    clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c

Modified: 
    clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp 
b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index e4ec380043689..0c8ff4bd807ad 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -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 isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }
+
   CharUnits bitsToCharUnits(uint64_t bitOffset) {
     return astContext.toCharUnitsFromBits(bitOffset);
   }
@@ -771,7 +774,104 @@ 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 
diff erent 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 =
+        isBigEndian() ? 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 (isBigEndian())
+      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) {

diff  --git a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c 
b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
new file mode 100644
index 0000000000000..3643cf257933e
--- /dev/null
+++ b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
@@ -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>
+
+// 
diff erent 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;
+
+// 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;
+
+// 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;


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to