llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-codegen Author: Erich Keane (erichkeane) <details> <summary>Changes</summary> We have plenty of stuff that needs to be shared between Classic-Codegen and CIR, that we've been copy/pasting too often. This patch proposes/produces a shared directory of CodeGenUtils that will be for things that don't really belong elsewhere. This functionality (calculating padding for __builtin_clear_padding) is both too complex to copy/paste, and doesn't really have reason to live anywhere except CodeGen/CIR-CodeGen. The type has been split out as faithfully as possible, with only minor changes to make it LLVM-agnostic. The part of it that is required to generate the LLVM-IR is left in CGBuiltin.cpp, but takes the list of padding-intervals as an input, which will be useful for CIR's representation. --- Patch is 26.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/215823.diff 2 Files Affected: - (added) clang/include/clang/CodeGenUtils/CodeGenUtils.h (+283) - (modified) clang/lib/CodeGen/CGBuiltin.cpp (+69-326) ``````````diff diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h new file mode 100644 index 0000000000000..2da4ddc5aea36 --- /dev/null +++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h @@ -0,0 +1,283 @@ +//===--- CodeGenUtils.h - Shared Classic CodeGen/CIR CodeGen Utils--C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/APFloat.h" + +#include <algorithm> +#include <utility> + +namespace clang::CodeGenUtils { +// A type that helps represent a padding interval. +struct BitInterval { + // [First, Last) + uint64_t First; + uint64_t Last; +}; + +// PaddingCalculator is a utility class that calculates the padding bits in a +// c/c++ type. It traverses the type recursively, collecting occupied +// bit intervals, and then computes the padding intervals. +// If a byte only contains some padding bits, it gets intervals for only those +// bits. This is the case for bit-fields. +struct PaddingCalculator { + PaddingCalculator(const ASTContext &Ctx, const TargetInfo &TI, + unsigned PointerSizeInBits) + : Ctx(Ctx), TI(TI), PointerSizeInBits(PointerSizeInBits) {} + + void run(QualType Ty) { + OccuppiedIntervals.clear(); + Stack.clear(); + + TySizeInBits = Ctx.getTypeSize(Ty); + + Stack.push_back(Data{0, Ty, true}); + while (!Stack.empty()) { + Data Current = Stack.back(); + Stack.pop_back(); + Visit(Current); + } + MergeOccuppiedIntervals(); + } + + llvm::SmallVector<BitInterval> GetPaddingIntervals() { + llvm::SmallVector<BitInterval> Results; + if (OccuppiedIntervals.size() == 1 && + OccuppiedIntervals.front().First == 0 && + OccuppiedIntervals.front().Last == TySizeInBits) { + return Results; + } + Results.reserve(OccuppiedIntervals.size() + 1); + uint64_t CurrentPos = 0; + for (const BitInterval &OccupiedInterval : OccuppiedIntervals) { + if (OccupiedInterval.First > CurrentPos) { + Results.push_back(BitInterval{CurrentPos, OccupiedInterval.First}); + } + CurrentPos = OccupiedInterval.Last; + } + if (TySizeInBits > CurrentPos) { + Results.push_back(BitInterval{CurrentPos, TySizeInBits}); + } + return Results; + } + +private: + struct Data { + uint64_t StartBitOffset; + QualType Ty; + bool VisitVirtualBase; + }; + + // Return the number of non padding bits of a scalar type. + // + // The property that we specifically care about here is whether the scalar + // type has padding bits, i.e. are there bits in the type which are not + // specified by the ABI. + // + // We currently don't care about this anywhere else in clang: layout cares + // about the ABI size, calling convention code cares about specific types, + // but nothing cares about padding specifically. And it's not something we can + // easily query from LLVM due to the type system mismatches. + // DL.getTypeSizeInBits(convertTypeForLoadStore(T)) is probably close, but the + // DataLayout methods aren't really designed for this usage. + // + // Therefore, it is better to explicitly list all the scalar types + // containing padding bits that we know of, namely, _BitInt(N) and x87 long + // double. + uint64_t getScalarOccupiedSizeInBits(QualType Ty) const { + if (const auto *BIT = Ty->getAs<BitIntType>()) + return BIT->getNumBits(); + + if (const auto *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::LongDouble && + &TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) + return llvm::APFloat::getSizeInBits(TI.getLongDoubleFormat()); + } + + return Ctx.getTypeSize(Ty); + } + + void Visit(const Data &D) { + if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) { + VisitArray(AT, D.StartBitOffset); + return; + } + + if (auto *Record = D.Ty->getAsRecordDecl()) { + VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase); + return; + } + + if (D.Ty->isAtomicType()) { + auto Unwrapped = D; + Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType(); + Stack.push_back(Unwrapped); + return; + } + + if (const auto *Complex = D.Ty->getAs<ComplexType>()) { + VisitComplex(Complex, D.StartBitOffset); + return; + } + + if (const auto *VT = D.Ty->getAs<clang::VectorType>()) { + VisitVector(VT, D.StartBitOffset); + return; + } + + uint64_t SizeBit = getScalarOccupiedSizeInBits(D.Ty); + OccuppiedIntervals.push_back( + BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit}); + } + + void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) { + for (uint64_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue(); + ++ArrIndex) { + + QualType ElementQualType = AT->getElementType(); + auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType); + auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType); + auto Offset = ElementSize.alignTo(ElementAlign); + + Stack.push_back(Data{StartBitOffset + ArrIndex * Offset.getQuantity() * + Ctx.getCharWidth(), + ElementQualType, /*VisitVirtualBase*/ true}); + } + } + + void VisitStruct(const RecordDecl *R, uint64_t StartBitOffset, + bool VisitVirtualBase) { + const ASTRecordLayout &ASTLayout = Ctx.getASTRecordLayout(R); + auto *CXXRecord = dyn_cast<CXXRecordDecl>(R); + + if (CXXRecord) { + if (ASTLayout.hasOwnVFPtr()) { + OccuppiedIntervals.push_back( + BitInterval{StartBitOffset, StartBitOffset + PointerSizeInBits}); + } + + if (ASTLayout.hasOwnVBPtr()) { + auto Offset = ASTLayout.getVBPtrOffset().getQuantity(); + auto StartVBPtr = StartBitOffset + Offset * Ctx.getCharWidth(); + OccuppiedIntervals.push_back( + BitInterval{StartVBPtr, StartVBPtr + PointerSizeInBits}); + } + + const auto VisitBase = [&ASTLayout, StartBitOffset, this]( + const CXXBaseSpecifier &Base, auto GetOffset) { + auto *BaseRecord = Base.getType()->getAsCXXRecordDecl(); + if (!BaseRecord) { + return; + } + auto BaseOffset = + std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity(); + + Stack.push_back(Data{StartBitOffset + BaseOffset * Ctx.getCharWidth(), + Base.getType(), /*VisitVirtualBase*/ false}); + }; + + for (auto Base : CXXRecord->bases()) { + if (!Base.isVirtual()) { + VisitBase(Base, &ASTRecordLayout::getBaseClassOffset); + } + } + + if (VisitVirtualBase) { + for (auto VBase : CXXRecord->vbases()) { + VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset); + } + } + } + + for (auto *Field : R->fields()) { + // Treat unnamed bitfields as padding. + if (Field->isUnnamedBitField()) + continue; + + auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex()); + if (Field->isBitField()) { + OccuppiedIntervals.push_back(BitInterval{ + StartBitOffset + FieldOffset, + StartBitOffset + FieldOffset + Field->getBitWidthValue()}); + } else { + Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(), + /*VisitVirtualBase*/ true}); + } + } + } + + void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) { + QualType ElementQualType = CT->getElementType(); + auto ElementSize = Ctx.getTypeSizeInChars(ElementQualType); + auto ElementAlign = Ctx.getTypeAlignInChars(ElementQualType); + auto ImgOffset = ElementSize.alignTo(ElementAlign); + + Stack.push_back( + Data{StartBitOffset, ElementQualType, /*VisitVirtualBase*/ true}); + Stack.push_back( + Data{StartBitOffset + ImgOffset.getQuantity() * Ctx.getCharWidth(), + ElementQualType, /*VisitVirtualBase*/ true}); + } + + void VisitVector(const clang::VectorType *VT, uint64_t StartBitOffset) { + uint64_t SizeBit = [&]() -> uint64_t { + if (VT->isPackedVectorBoolType(Ctx)) + return VT->getNumElements(); + return getScalarOccupiedSizeInBits(VT->getElementType()) * + VT->getNumElements(); + }(); + OccuppiedIntervals.push_back( + BitInterval{StartBitOffset, StartBitOffset + SizeBit}); + } + + void MergeOccuppiedIntervals() { + std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(), + [](const BitInterval &lhs, const BitInterval &rhs) { + return std::tie(lhs.First, lhs.Last) < + std::tie(rhs.First, rhs.Last); + }); + + llvm::SmallVector<BitInterval> Merged; + Merged.reserve(OccuppiedIntervals.size()); + + for (const BitInterval &NextInterval : OccuppiedIntervals) { + if (Merged.empty()) { + Merged.push_back(NextInterval); + continue; + } + auto &LastInterval = Merged.back(); + + if (NextInterval.First > LastInterval.Last) { + Merged.push_back(NextInterval); + } else { + LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last); + } + } + + OccuppiedIntervals = Merged; + } + + const ASTContext &Ctx; + const TargetInfo &TI; + unsigned PointerSizeInBits; + uint64_t TySizeInBits = 0; + llvm::SmallVector<Data> Stack; + llvm::SmallVector<BitInterval> OccuppiedIntervals; +}; + +// Calculate and gets the 'padding intervals' inside of a type. +llvm::SmallVector<BitInterval> +CalculatePaddingIntervals(const ASTContext &Ctx, const TargetInfo &TI, + QualType Ty, unsigned PointerSizeInBits) { + PaddingCalculator pc{Ctx, TI, PointerSizeInBits}; + pc.run(Ty); + return pc.GetPaddingIntervals(); +} +} // namespace clang::CodeGenUtils diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 3521fc10f1387..9fa54b8f18b13 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -28,6 +28,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/TargetInfo.h" +#include "clang/CodeGenUtils/CodeGenUtils.h" #include "llvm/ADT/APFloat.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" @@ -2598,277 +2599,40 @@ RValue CodeGenFunction::emitStdcFirstBit(const CallExpr *E, Intrinsic::ID IntID, return RValue::get(Result); } -namespace { - -// PaddingClearer is a utility class that clears padding bits in a -// c/c++ type. It traverses the type recursively, collecting occupied -// bit intervals, and then computes the padding intervals. -// In the end, it clears the padding bits by writing zeros -// to the padding intervals bytes-by-bytes. If a byte only contains -// some padding bits, it writes zeros to only those bits. This is -// the case for bit-fields. -struct PaddingClearer { - PaddingClearer(CodeGenFunction &F) - : CGF(F), CharWidth(CGF.getContext().getCharWidth()) {} - - void run(Address Src, QualType Ty) { - OccuppiedIntervals.clear(); - Stack.clear(); - - Stack.push_back(Data{0, Ty, true}); - while (!Stack.empty()) { - auto Current = Stack.back(); - Stack.pop_back(); - Visit(Current); - } - - MergeOccuppiedIntervals(); - auto PaddingIntervals = - GetPaddingIntervals(CGF.getContext().getTypeSize(Ty)); - for (const auto &Interval : PaddingIntervals) { - ClearPadding(Src, Interval); - } - } - -private: - struct BitInterval { - // [First, Last) - uint64_t First; - uint64_t Last; - }; - - struct Data { - uint64_t StartBitOffset; - QualType Ty; - bool VisitVirtualBase; - }; - - // Return the number of non padding bits of a scalar type. - // - // The property that we specifically care about here is whether the scalar - // type has padding bits, i.e. are there bits in the type which are not - // specified by the ABI. - // - // We currently don't care about this anywhere else in clang: layout cares - // about the ABI size, calling convention code cares about specific types, but - // nothing cares about padding specifically. And it's not something we can - // easily query from LLVM due to the type system mismatches. - // DL.getTypeSizeInBits(convertTypeForLoadStore(T)) is probably close, but the - // DataLayout methods aren't really designed for this usage. - // - // Therefore, it is better to explicitly list all the scalar types containing - // padding bits that we know of, namely, _BitInt(N) and x87 long double. - uint64_t getScalarOccupiedSizeInBits(QualType Ty) const { - if (const auto *BIT = Ty->getAs<BitIntType>()) - return BIT->getNumBits(); - - if (const auto *BT = Ty->getAs<BuiltinType>()) { - if (BT->getKind() == BuiltinType::LongDouble && - &CGF.getTarget().getLongDoubleFormat() == - &APFloat::x87DoubleExtended()) - return APFloat::getSizeInBits(CGF.getTarget().getLongDoubleFormat()); - } - - return CGF.getContext().getTypeSize(Ty); - } - - void Visit(const Data &D) { - if (auto *AT = dyn_cast<ConstantArrayType>(D.Ty)) { - VisitArray(AT, D.StartBitOffset); - return; - } - - if (auto *Record = D.Ty->getAsRecordDecl()) { - VisitStruct(Record, D.StartBitOffset, D.VisitVirtualBase); - return; - } - - if (D.Ty->isAtomicType()) { - auto Unwrapped = D; - Unwrapped.Ty = D.Ty.getAtomicUnqualifiedType(); - Stack.push_back(Unwrapped); - return; - } - - if (const auto *Complex = D.Ty->getAs<ComplexType>()) { - VisitComplex(Complex, D.StartBitOffset); - return; - } - - if (const auto *VT = D.Ty->getAs<clang::VectorType>()) { - VisitVector(VT, D.StartBitOffset); - return; - } - - uint64_t SizeBit = getScalarOccupiedSizeInBits(D.Ty); - OccuppiedIntervals.push_back( - BitInterval{D.StartBitOffset, D.StartBitOffset + SizeBit}); - } - - void VisitArray(const ConstantArrayType *AT, uint64_t StartBitOffset) { - for (uint64_t ArrIndex = 0; ArrIndex < AT->getSize().getLimitedValue(); - ++ArrIndex) { - - QualType ElementQualType = AT->getElementType(); - auto ElementSize = CGF.getContext().getTypeSizeInChars(ElementQualType); - auto ElementAlign = CGF.getContext().getTypeAlignInChars(ElementQualType); - auto Offset = ElementSize.alignTo(ElementAlign); - - Stack.push_back( - Data{StartBitOffset + ArrIndex * Offset.getQuantity() * CharWidth, - ElementQualType, /*VisitVirtualBase*/ true}); - } - } - - void VisitStruct(const RecordDecl *R, uint64_t StartBitOffset, - bool VisitVirtualBase) { - const auto &DL = CGF.CGM.getModule().getDataLayout(); - const ASTRecordLayout &ASTLayout = CGF.getContext().getASTRecordLayout(R); - - auto *CXXRecord = dyn_cast<CXXRecordDecl>(R); - - if (CXXRecord) { - if (ASTLayout.hasOwnVFPtr()) { - OccuppiedIntervals.push_back(BitInterval{ - StartBitOffset, StartBitOffset + DL.getPointerSizeInBits()}); - } - - if (ASTLayout.hasOwnVBPtr()) { - auto Offset = ASTLayout.getVBPtrOffset().getQuantity(); - auto StartVBPtr = StartBitOffset + Offset * CharWidth; - OccuppiedIntervals.push_back( - BitInterval{StartVBPtr, StartVBPtr + DL.getPointerSizeInBits()}); - } - - const auto VisitBase = [&ASTLayout, StartBitOffset, this]( - const CXXBaseSpecifier &Base, auto GetOffset) { - auto *BaseRecord = Base.getType()->getAsCXXRecordDecl(); - if (!BaseRecord) { - return; - } - auto BaseOffset = - std::invoke(GetOffset, ASTLayout, BaseRecord).getQuantity(); - - Stack.push_back(Data{StartBitOffset + BaseOffset * CharWidth, - Base.getType(), /*VisitVirtualBase*/ false}); - }; - - for (auto Base : CXXRecord->bases()) { - if (!Base.isVirtual()) { - VisitBase(Base, &ASTRecordLayout::getBaseClassOffset); - } - } - - if (VisitVirtualBase) { - for (auto VBase : CXXRecord->vbases()) { - VisitBase(VBase, &ASTRecordLayout::getVBaseClassOffset); - } - } - } - - for (auto *Field : R->fields()) { - // Treat unnamed bitfields as padding. - if (Field->isUnnamedBitField()) - continue; - - auto FieldOffset = ASTLayout.getFieldOffset(Field->getFieldIndex()); - if (Field->isBitField()) { - OccuppiedIntervals.push_back(BitInterval{ - StartBitOffset + FieldOffset, - StartBitOffset + FieldOffset + Field->getBitWidthValue()}); - } else { - Stack.push_back(Data{StartBitOffset + FieldOffset, Field->getType(), - /*VisitVirtualBase*/ true}); - } - } - } - - void VisitComplex(const ComplexType *CT, uint64_t StartBitOffset) { - QualType ElementQualType = CT->getElementType(); - auto ElementSize = CGF.getContext().getTypeSizeInChars(ElementQualType); - auto ElementAlign = CGF.getContext().getTypeAlignInChars(ElementQualType); - auto ImgOffset = ElementSize.alignTo(ElementAlign); - - Stack.push_back( - Data{StartBitOffset, ElementQualType, /*VisitVirtualBase*/ true}); - Stack.push_back(Data{StartBitOffset + ImgOffset.getQuantity() * CharWidth, - ElementQualType, /*VisitVirtualBase*/ true}); - } - - void VisitVector(const clang::VectorType *VT, uint64_t StartBitOffset) { - ASTContext &Ctx = CGF.getContext(); - uint64_t SizeBit = [&]() -> uint64_t { - if (VT->isPackedVectorBoolType(Ctx)) - return VT->getNumElements(); - return getScalarOccupiedSizeInBits(VT->getElementType()) * - VT->getNumElements(); - }(); - OccuppiedIntervals.push_back( - BitInterval{StartBitOffset, StartBitOffset + SizeBit}); - } - - void MergeOccuppiedIntervals() { - std::sort(OccuppiedIntervals.begin(), OccuppiedIntervals.end(), - [](const BitInterval &lhs, const BitInterval &rhs) { - return std::tie(lhs.First, lhs.Last) < - std::tie(rhs.First, rhs.Last); - }); - - llvm::SmallVector<BitInterval> Merged; - Merged.reserve(OccuppiedIntervals.size()); - - for (const BitInterval &NextInterval : OccuppiedIntervals) { - if (Merged.empty()) { - Merged.push_back(NextInterval); - continue; - } - auto &LastInterval = Merged.back(); - - if (NextInterval.First > LastInterval.Last) { - Merged.push_back(NextInterval); - } else { - LastInterval.Last = std::max(LastInterval.Last, NextInterval.Last); - } - } - - OccuppiedIntervals = Merged; - } - - llvm::SmallVector<BitInterval> - GetPaddingIntervals(uint64_t SizeInBits) const { - llvm::SmallVector<BitInterval> Results; - if (OccuppiedIntervals.size() == 1 && - OccuppiedIntervals.front().First == 0 && - OccuppiedIntervals.front().Last == SizeInBits) { - return Results; - } - Results.reserve(OccuppiedIntervals.size() + 1); - uint64_t CurrentPos = 0; - for (const BitInterval &OccupiedInterval : OccuppiedIntervals) { - if (OccupiedInterval.First > CurrentPos) { - Results.push_back(BitInterval{CurrentPos, OccupiedInterval.First}); - } - CurrentPos = OccupiedInterval.Last; - } - if (SizeInBits > CurrentPos) { - Results.push_back(BitInterval{CurrentPos, SizeInBits}); - } - return Results; - } - - void ClearPadding(Address Src, const BitInterval &PaddingInterval) { - auto *I8Ptr = - CGF.Builder.CreateBitCast(Src.getBasePointer(), CGF.Int8PtrTy); - auto *Zero = ConstantInt::get(CGF.Int8Ty, 0); - - // Calculate byte indices and bit positions - auto StartByte = PaddingInterval.First / CharWidth; - auto StartBit = PaddingInterval.First % CharWidth; - auto EndByte = PaddingInterval.Last / CharWidth; - auto EndBit = PaddingInterval.Las... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/215823 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
