https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/223424
>From e234ef8e26fe01ca504e57fdba1901016d75e497 Mon Sep 17 00:00:00 2001 From: Henrich Lauko <[email protected]> Date: Tue, 29 Sep 2026 09:56:08 +0000 Subject: [PATCH] [CIR][CodeGen][NFC] Share isEmptyFieldForLayout and isEmptyRecordForLayout Deduplicates `isEmptyFieldForLayout` and `isEmptyRecordForLayout` between CIR and classic CodeGen into a new `RecordLayoutUtils.h`. The 25 callers now name them as `CodeGenUtils::isEmptyFieldForLayout` and `CodeGenUtils::isEmptyRecordForLayout`, like the other shared helpers. Assisted-by: Claude Code (Claude Fable 5.1). --- .../clang/CodeGenUtils/RecordLayoutUtils.h | 34 ++++++++++++++ clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 3 +- clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp | 6 ++- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 3 +- .../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 7 +-- clang/lib/CIR/CodeGen/TargetInfo.cpp | 34 -------------- clang/lib/CIR/CodeGen/TargetInfo.h | 9 ---- clang/lib/CodeGen/ABIInfoImpl.cpp | 33 -------------- clang/lib/CodeGen/ABIInfoImpl.h | 9 ---- clang/lib/CodeGen/CGClass.cpp | 5 ++- clang/lib/CodeGen/CGExpr.cpp | 3 +- clang/lib/CodeGen/CGExprConstant.cpp | 11 ++--- clang/lib/CodeGen/CGOpenMPRuntime.cpp | 7 +-- clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 13 +++--- clang/lib/CodeGen/CodeGenTBAA.cpp | 3 +- clang/lib/CodeGenUtils/CMakeLists.txt | 1 + clang/lib/CodeGenUtils/RecordLayoutUtils.cpp | 45 +++++++++++++++++++ 17 files changed, 116 insertions(+), 110 deletions(-) create mode 100644 clang/include/clang/CodeGenUtils/RecordLayoutUtils.h create mode 100644 clang/lib/CodeGenUtils/RecordLayoutUtils.cpp diff --git a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h new file mode 100644 index 0000000000000..77f14fee5a3b4 --- /dev/null +++ b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h @@ -0,0 +1,34 @@ +//===--- RecordLayoutUtils.h - Shared record layout queries -----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file holds the AST queries about record layout that both classic +// CodeGen and CIR CodeGen need while lowering a record to its target type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H +#define LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H + +#include "clang/AST/ASTContext.h" + +namespace clang::CodeGenUtils { + +/// Return true iff the field is "empty", that is, either a zero-width +/// bit-field or an \ref isEmptyRecordForLayout. +bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD); + +/// Return true iff a structure contains only empty base classes (per \ref +/// isEmptyRecordForLayout) and fields (per \ref isEmptyFieldForLayout). Note, +/// C++ record fields are considered empty if the [[no_unique_address]] +/// attribute would have made them empty, so this is not the same as \ref +/// isEmptyRecord. +bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T); + +} // namespace clang::CodeGenUtils + +#endif // LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index 1f738f9737d31..51533f9dc0f9c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -32,6 +32,7 @@ #include "clang/CIR/MissingFeatures.h" #include "clang/CodeGenUtils/CodeGenUtils.h" #include "clang/CodeGenUtils/ExprUtils.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include <optional> using namespace clang; @@ -77,7 +78,7 @@ Address CIRGenFunction::emitAddrOfFieldStorage(Address base, bool addressedByFieldIndex = field->isPotentiallyOverlapping() ? layout.hasCIRField(field) - : !isEmptyFieldForLayout(getContext(), field); + : !CodeGenUtils::isEmptyFieldForLayout(getContext(), field); if (!addressedByFieldIndex) return emitAddrOfZeroSizeField(*this, base, field); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp index afc6b8058066d..100d11916dcee 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp @@ -29,6 +29,7 @@ #include "clang/CIR/Dialect/IR/CIRAttrs.h" #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/MissingFeatures.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" @@ -1210,7 +1211,8 @@ static mlir::TypedAttr emitNullConstant(CIRGenModule &cgm, const RecordDecl *rd, const auto *baseDecl = base.getType()->castAsCXXRecordDecl(); // Ignore empty bases. - if (isEmptyRecordForLayout(cgm.getASTContext(), base.getType()) || + if (CodeGenUtils::isEmptyRecordForLayout(cgm.getASTContext(), + base.getType()) || cgm.getASTContext() .getASTRecordLayout(baseDecl) .getNonVirtualSize() @@ -1228,7 +1230,7 @@ static mlir::TypedAttr emitNullConstant(CIRGenModule &cgm, const RecordDecl *rd, // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) if (!field->isBitField() && - !isEmptyFieldForLayout(cgm.getASTContext(), field)) { + !CodeGenUtils::isEmptyFieldForLayout(cgm.getASTContext(), field)) { unsigned fieldIndex = layout.getCIRFieldNo(field); elements[fieldIndex] = cgm.emitNullConstantAttr(field->getType()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 5063b6a4cc779..92c8af433aace 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -38,6 +38,7 @@ #include "clang/CIR/MissingFeatures.h" #include "clang/CodeGenUtils/CodeGenUtils.h" #include "clang/CodeGenUtils/ModuleUtils.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -2493,7 +2494,7 @@ bool CIRGenModule::findFieldMemberPath(const CXXRecordDecl *currentClass, bool CIRGenModule::isEmptyFieldForMemberPointer(const FieldDecl *field) { if (!field->isPotentiallyOverlapping() || - !isEmptyFieldForLayout(astContext, field)) + !CodeGenUtils::isEmptyFieldForLayout(astContext, field)) return false; // Unions always have a field even if they are empty. diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp index c2075a245f05c..8617ba5561e41 100644 --- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp @@ -23,6 +23,7 @@ #include "clang/CIR/Dialect/IR/CIRDataLayout.h" #include "clang/CIR/MissingFeatures.h" #include "clang/CodeGenUtils/CodeGenUtils.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/Support/Casting.h" #include <memory> @@ -632,7 +633,7 @@ CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field, // non-reusable tail padding. CharUnits limitOffset; for (auto probe = field; probe != fieldEnd; ++probe) - if (!isEmptyFieldForLayout(astContext, *probe)) { + if (!CodeGenUtils::isEmptyFieldForLayout(astContext, *probe)) { // A member with storage sets the limit. assert((getFieldBitOffset(*probe) % charBits) == 0 && "Next storage is not byte-aligned"); @@ -730,7 +731,7 @@ void CIRRecordLowering::accumulateFields(bool nonVirtualBaseType) { field = accumulateBitFields(field, fieldEnd); assert((field == fieldEnd || !field->isBitField()) && "Failed to accumulate all the bitfields"); - } else if (isEmptyFieldForLayout(astContext, *field) && + } else if (CodeGenUtils::isEmptyFieldForLayout(astContext, *field) && field->isPotentiallyOverlapping()) { // We lay out normal empty fields, as they are required for GEPs/getting // function pointers. However 'no-unique-address' lends some additional @@ -1287,7 +1288,7 @@ void CIRRecordLowering::accumulateBases() { void CIRRecordLowering::accumulateVBases() { for (const auto &base : cxxRecordDecl->vbases()) { const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl(); - if (isEmptyRecordForLayout(astContext, base.getType())) + if (CodeGenUtils::isEmptyRecordForLayout(astContext, base.getType())) continue; CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl); // If the vbase is a primary virtual base of some base, then it doesn't diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index cede4941b4473..57bc5f167e460 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -11,40 +11,6 @@ using namespace clang; using namespace clang::CIRGen; -bool clang::CIRGen::isEmptyRecordForLayout(const ASTContext &context, - QualType t) { - const auto *rd = t->getAsRecordDecl(); - if (!rd) - return false; - - // If this is a C++ record, check the bases first. - if (const CXXRecordDecl *cxxrd = dyn_cast<CXXRecordDecl>(rd)) { - if (cxxrd->isDynamicClass()) - return false; - - for (const auto &i : cxxrd->bases()) - if (!isEmptyRecordForLayout(context, i.getType())) - return false; - } - - for (const auto *i : rd->fields()) - if (!isEmptyFieldForLayout(context, i)) - return false; - - return true; -} - -bool clang::CIRGen::isEmptyFieldForLayout(const ASTContext &context, - const FieldDecl *fd) { - if (fd->isZeroLengthBitField()) - return true; - - if (fd->isUnnamedBitField()) - return false; - - return isEmptyRecordForLayout(context, fd->getType()); -} - bool clang::CIRGen::isEmptyRecordForABI(const ASTContext &context, QualType t) { const auto *rd = t->getAsRecordDecl(); if (!rd) diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index 5f380026e025d..69910491cceca 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -27,15 +27,6 @@ namespace clang::CIRGen { -/// isEmptyFieldForLayout - Return true if the field is "empty", that is, -/// either a zero-width bit-field or an isEmptyRecordForLayout. -bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd); - -/// isEmptyRecordForLayout - Return true if a structure contains only empty -/// base classes (per isEmptyRecordForLayout) and fields (per -/// isEmptyFieldForLayout). Note, C++ record fields are considered empty -/// if the [[no_unique_address]] attribute would have made them empty. -bool isEmptyRecordForLayout(const ASTContext &context, QualType t); /// isEmptyFieldForABI - Return true if the field is "empty", that is, it is a /// zero-width bit-field or an (array of) empty record(s). An unnamed diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index 887a645a4783a..23b6b7e8200da 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -302,39 +302,6 @@ bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, return true; } -bool CodeGen::isEmptyFieldForLayout(const ASTContext &Context, - const FieldDecl *FD) { - if (FD->isZeroLengthBitField()) - return true; - - if (FD->isUnnamedBitField()) - return false; - - return isEmptyRecordForLayout(Context, FD->getType()); -} - -bool CodeGen::isEmptyRecordForLayout(const ASTContext &Context, QualType T) { - const auto *RD = T->getAsRecordDecl(); - if (!RD) - return false; - - // If this is a C++ record, check the bases first. - if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { - if (CXXRD->isDynamicClass()) - return false; - - for (const auto &I : CXXRD->bases()) - if (!isEmptyRecordForLayout(Context, I.getType())) - return false; - } - - for (const auto *I : RD->fields()) - if (!isEmptyFieldForLayout(Context, I)) - return false; - - return true; -} - const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { const auto *RD = T->getAsRecordDecl(); if (!RD) diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h index d9d79c6a55ddb..180a76f4a820e 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.h +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -120,15 +120,6 @@ bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays, bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr = false); -/// isEmptyFieldForLayout - Return true iff the field is "empty", that is, -/// either a zero-width bit-field or an \ref isEmptyRecordForLayout. -bool isEmptyFieldForLayout(const ASTContext &Context, const FieldDecl *FD); - -/// isEmptyRecordForLayout - Return true iff a structure contains only empty -/// base classes (per \ref isEmptyRecordForLayout) and fields (per -/// \ref isEmptyFieldForLayout). Note, C++ record fields are considered empty -/// if the [[no_unique_address]] attribute would have made them empty. -bool isEmptyRecordForLayout(const ASTContext &Context, QualType T); /// isSingleElementStruct - Determine if a structure is a "single /// element struct", i.e. it has exactly one non-empty field or diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 63f5d9ae13dbf..7e832f8155aa7 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -27,6 +27,7 @@ #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGenUtils/ClassUtils.h" #include "clang/CodeGenUtils/CodeGenUtils.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/SaveAndRestore.h" @@ -882,7 +883,7 @@ class FieldMemcpyizer { } void addMemcpyableField(FieldDecl *F) { - if (isEmptyFieldForLayout(CGF.getContext(), F)) + if (CodeGenUtils::isEmptyFieldForLayout(CGF.getContext(), F)) return; if (!FirstField) addInitialField(F); @@ -1863,7 +1864,7 @@ class SanitizeDtorCleanupBuilder { const CXXDestructorDecl *DD) : Context(Context), EHStack(EHStack), DD(DD), StartIndex(std::nullopt) {} void PushCleanupForField(const FieldDecl *Field) { - if (isEmptyFieldForLayout(Context, Field)) + if (CodeGenUtils::isEmptyFieldForLayout(Context, Field)) return; unsigned FieldIndex = Field->getFieldIndex(); if (CodeGenUtils::fieldHasTrivialDestructorBody(Context, Field)) { diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 76bd781a709b6..8323a170a1dbb 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -41,6 +41,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/CodeGenUtils/CodeGenUtils.h" #include "clang/CodeGenUtils/ExprUtils.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringExtras.h" @@ -5909,7 +5910,7 @@ static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base, static Address emitRawAddrOfFieldStorage(CodeGenFunction &CGF, Address base, const FieldDecl *field, bool IsInBounds) { - if (isEmptyFieldForLayout(CGF.getContext(), field)) + if (CodeGenUtils::isEmptyFieldForLayout(CGF.getContext(), field)) return emitAddrOfZeroSizeField(CGF, base, field, IsInBounds); const RecordDecl *rec = field->getParent(); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index cc4793d328166..e2ec07bbae711 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -26,6 +26,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" #include "llvm/Analysis/ConstantFolding.h" @@ -762,7 +763,7 @@ bool ConstStructBuilder::Build(const InitListExpr *ILE, bool AllowOverwrite) { // Zero-sized fields are not emitted, but their initializers may still // prevent emission of this struct as a constant. - if (isEmptyFieldForLayout(CGM.getContext(), Field)) { + if (CodeGenUtils::isEmptyFieldForLayout(CGM.getContext(), Field)) { if (Init && Init->HasSideEffects(CGM.getContext())) return false; continue; @@ -925,7 +926,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, // Don't emit anonymous bitfields or zero-sized fields. if (Field->isUnnamedBitField() || - isEmptyFieldForLayout(CGM.getContext(), *Field)) + CodeGenUtils::isEmptyFieldForLayout(CGM.getContext(), *Field)) continue; // Emit the value of the initializer. @@ -2842,7 +2843,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, const auto *base = I.getType()->castAsCXXRecordDecl(); // Ignore empty bases. - if (isEmptyRecordForLayout(CGM.getContext(), I.getType()) || + if (CodeGenUtils::isEmptyRecordForLayout(CGM.getContext(), I.getType()) || CGM.getContext() .getASTRecordLayout(base) .getNonVirtualSize() @@ -2860,7 +2861,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) if (!Field->isBitField() && - !isEmptyFieldForLayout(CGM.getContext(), Field)) { + !CodeGenUtils::isEmptyFieldForLayout(CGM.getContext(), Field)) { unsigned fieldIndex = layout.getLLVMFieldNo(Field); elements[fieldIndex] = CGM.EmitNullConstant(Field->getType()); } @@ -2880,7 +2881,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, for (const auto &I : CXXR->vbases()) { const auto *base = I.getType()->castAsCXXRecordDecl(); // Ignore empty bases. - if (isEmptyRecordForLayout(CGM.getContext(), I.getType())) + if (CodeGenUtils::isEmptyRecordForLayout(CGM.getContext(), I.getType())) continue; unsigned fieldIndex = layout.getVirtualBaseIndex(base); diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 58bfd48a49d39..9893ecc4ec7cc 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -28,6 +28,7 @@ #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/SourceManager.h" #include "clang/CodeGen/ConstantInitBuilder.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" @@ -8937,7 +8938,7 @@ class MappableExprsHandler { QualType BaseTy = I.getType(); const auto *Base = BaseTy->getAsCXXRecordDecl(); // Ignore empty bases. - if (isEmptyRecordForLayout(CGF.getContext(), BaseTy) || + if (CodeGenUtils::isEmptyRecordForLayout(CGF.getContext(), BaseTy) || CGF.getContext() .getASTRecordLayout(Base) .getNonVirtualSize() @@ -8951,7 +8952,7 @@ class MappableExprsHandler { for (const auto &I : RD->vbases()) { QualType BaseTy = I.getType(); // Ignore empty bases. - if (isEmptyRecordForLayout(CGF.getContext(), BaseTy)) + if (CodeGenUtils::isEmptyRecordForLayout(CGF.getContext(), BaseTy)) continue; const auto *Base = BaseTy->getAsCXXRecordDecl(); @@ -8966,7 +8967,7 @@ class MappableExprsHandler { // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) if (!Field->isBitField() && - !isEmptyFieldForLayout(CGF.getContext(), Field)) { + !CodeGenUtils::isEmptyFieldForLayout(CGF.getContext(), Field)) { unsigned FieldIndex = RL.getLLVMFieldNo(Field); RecordLayout[FieldIndex] = Field; } diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index d98d7c0c96dc3..14c4b969e141c 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -22,6 +22,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/CodeGenUtils/CodeGenUtils.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Type.h" @@ -381,7 +382,7 @@ void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) { Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd); assert((Field == FieldEnd || !Field->isBitField()) && "Failed to accumulate all the bitfields"); - } else if (isEmptyFieldForLayout(Context, *Field)) { + } else if (CodeGenUtils::isEmptyFieldForLayout(Context, *Field)) { // Empty fields have no storage. ++Field; } else { @@ -630,7 +631,7 @@ CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, // non-reusable tail padding. CharUnits LimitOffset; for (auto Probe = Field; Probe != FieldEnd; ++Probe) - if (!isEmptyFieldForLayout(Context, *Probe)) { + if (!CodeGenUtils::isEmptyFieldForLayout(Context, *Probe)) { // A member with storage sets the limit. assert((getFieldBitOffset(*Probe) % CharBits) == 0 && "Next storage is not byte-aligned"); @@ -728,7 +729,7 @@ void CGRecordLowering::accumulateBases() { // Bases can be zero-sized even if not technically empty if they // contain only a trailing array member. const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (!isEmptyRecordForLayout(Context, Base.getType()) && + if (!CodeGenUtils::isEmptyRecordForLayout(Context, Base.getType()) && !Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl), MemberInfo::Base, getStorageType(BaseDecl), BaseDecl)); @@ -877,7 +878,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { if (!isNonVirtualBaseType && isOverlappingVBaseABI()) for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (isEmptyRecordForLayout(Context, Base.getType())) + if (CodeGenUtils::isEmptyRecordForLayout(Context, Base.getType())) continue; // If the vbase is a primary virtual base of some base, then it doesn't // get its own storage location but instead lives inside of that base. @@ -893,7 +894,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { void CGRecordLowering::accumulateVBases() { for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); - if (isEmptyRecordForLayout(Context, Base.getType())) + if (CodeGenUtils::isEmptyRecordForLayout(Context, Base.getType())) continue; CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl); // If the vbase is a primary virtual base of some base, then it doesn't @@ -1154,7 +1155,7 @@ CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, llvm::StructType *Ty) { const FieldDecl *FD = *it; // Ignore zero-sized fields. - if (isEmptyFieldForLayout(getContext(), FD)) + if (CodeGenUtils::isEmptyFieldForLayout(getContext(), FD)) continue; // For non-bit-fields, just check that the LLVM struct offset matches the diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 1854df7c7c0f1..d33188db9da15 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -25,6 +25,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/TargetInfo.h" +#include "clang/CodeGenUtils/RecordLayoutUtils.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" @@ -455,7 +456,7 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { - if (isEmptyFieldForLayout(Context, *i)) + if (CodeGenUtils::isEmptyFieldForLayout(Context, *i)) continue; uint64_t Offset = diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt index 83b11a5ed2cdf..2052ca13f6e5d 100644 --- a/clang/lib/CodeGenUtils/CMakeLists.txt +++ b/clang/lib/CodeGenUtils/CMakeLists.txt @@ -15,6 +15,7 @@ add_clang_library(clangCodeGenUtils FunctionUtils.cpp ItaniumCXXABIUtils.cpp ModuleUtils.cpp + RecordLayoutUtils.cpp StmtUtils.cpp LINK_LIBS diff --git a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp new file mode 100644 index 0000000000000..3b8d433dc8759 --- /dev/null +++ b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp @@ -0,0 +1,45 @@ +//===--- RecordLayoutUtils.cpp - Shared record layout queries -------------===// +// +// 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/CodeGenUtils/RecordLayoutUtils.h" + +namespace clang::CodeGenUtils { + +bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD) { + if (FD->isZeroLengthBitField()) + return true; + + if (FD->isUnnamedBitField()) + return false; + + return isEmptyRecordForLayout(Ctx, FD->getType()); +} + +bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T) { + const auto *RD = T->getAsRecordDecl(); + if (!RD) + return false; + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + if (CXXRD->isDynamicClass()) + return false; + + for (const auto &I : CXXRD->bases()) + if (!isEmptyRecordForLayout(Ctx, I.getType())) + return false; + } + + for (const auto *I : RD->fields()) + if (!isEmptyFieldForLayout(Ctx, I)) + return false; + + return true; +} + +} // namespace clang::CodeGenUtils _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
