@@ -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
779878void CIRRecordLowering::accumulateBases (const CXXRecordDecl *cxxRecordDecl) {
0 commit comments