================ @@ -442,79 +455,235 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, return; } - // Check if OffsetInRecord (the size in bits of the current run) is better - // as a single field run. When OffsetInRecord has legal integer width, and - // its bitfield offset is naturally aligned, it is better to make the - // bitfield a separate storage component so as it can be accessed directly - // with lower cost. - auto IsBetterAsSingleFieldRun = [&](uint64_t OffsetInRecord, - uint64_t StartBitOffset) { - if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses) - return false; - if (OffsetInRecord < 8 || !llvm::isPowerOf2_64(OffsetInRecord) || - !DataLayout.fitsInLegalInteger(OffsetInRecord)) - return false; - // Make sure StartBitOffset is naturally aligned if it is treated as an - // IType integer. - if (StartBitOffset % - Context.toBits(getAlignment(getIntNType(OffsetInRecord))) != - 0) - return false; - return true; + // The SysV ABI can overlap bitfield storage units with both other bitfield + // storage units /and/ other non-bitfield data members. Such overlap, in the + // absence of packing, is always complete -- one storage unit is entirely + // within another. However, llvm cannot represent that -- it's structures are + // entirely flat. We place bitfields in 'access units', which are similar to + // the SysV storage units, but a clang-specific concept. + + // It can be advantageous to concatenate two adjacent access units, if the + // concenation can be read or written in a single instruction. + + // We do two passes. + + // a) allocate bitfields into the smallest access units they can + // fit. This results in a set of integral-typed access units. + + // b) concatentate mergeable access units. This applies the + // above-mentioned optimization, and in general, requires lookahead + // to know the next access unit -- not merely the next bitfield. + + class AccessUnit { + // Which bitfields are in the access + RecordDecl::field_iterator First; + RecordDecl::field_iterator Last; + + CharUnits Start; // Starting offset within the record + CharUnits End; // Finish offset (exclusive) within the record + + bool ContainsVolatile = false; + + public: + AccessUnit(RecordDecl::field_iterator F, RecordDecl::field_iterator L, + CharUnits S, CharUnits E, bool HasVolatile = false) + : First(F), Last(L), Start(S), End(E), ContainsVolatile(HasVolatile) {} + AccessUnit(RecordDecl::field_iterator F, CharUnits Place) + : AccessUnit(F, F, Place, Place) {} + + public: + auto begin() const { return First; } + auto end() const { return Last; } + + public: + void MergeFrom(AccessUnit const &Earlier) { + First = Earlier.First; + Start = Earlier.Start; + } + + public: + // Accessors + CharUnits getSize() const { return getSize(*this); } + CharUnits getStart() const { return Start; } + CharUnits getSize(const AccessUnit &NotEarlier) const { + return NotEarlier.End - Start; + } + + // Setter + void setEnd(CharUnits E) { End = E; } + + // Predicates + bool isBarrier() const { return getSize().isZero(); } + bool hasVolatile() const { return ContainsVolatile; } + + bool StartsBefore(CharUnits Offset, bool NonStrict = false) const { + if (NonStrict) + // Not strictly <, permit == + ++Offset; + return Start < Offset; + } + bool ExtendsBeyond(CharUnits Offset) const { return End > Offset; } + bool EndsAt(CharUnits Offset) const { return End == Offset; } }; ---------------- rjmccall wrote:
This is definitely big enough that I would say to pull it out of the function body. https://github.com/llvm/llvm-project/pull/65742 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits