[llvm-branch-commits] [clang] [CIR][CodeGen][NFC] Share the bit-field and vbase layout ABI predicates (PR #227258)
Henrich Lauko via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Sep 29 04:23:04 PDT 2026
https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/227258
>From bc69802b05e1c0e95a045e0a63160e9147906040 Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Tue, 29 Sep 2026 09:56:12 +0000
Subject: [PATCH] [CIR][CodeGen][NFC] Share the bit-field and vbase layout ABI
predicates
Deduplicates `isDiscreteBitFieldABI` and `isOverlappingVBaseABI` between CIR and
classic CodeGen into `RecordLayoutUtils.h`, as free functions taking the
`ASTContext`.
---
.../clang/CodeGenUtils/RecordLayoutUtils.h | 12 +++++++
.../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 23 +++-----------
clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 31 +++++--------------
clang/lib/CodeGenUtils/RecordLayoutUtils.cpp | 9 ++++++
4 files changed, 32 insertions(+), 43 deletions(-)
diff --git a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
index 77f14fee5a3b4..2c1ee3c271a3d 100644
--- a/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
+++ b/clang/include/clang/CodeGenUtils/RecordLayoutUtils.h
@@ -18,6 +18,12 @@
namespace clang::CodeGenUtils {
+/// The Microsoft bitfield layout rule allocates discrete storage units of the
+/// field's formal type and only combines adjacent fields of the same formal
+/// type. We want to emit a layout with these discrete storage units instead
+/// of combining them into a continuous run.
+bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD);
+
/// 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);
@@ -29,6 +35,12 @@ bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD);
/// isEmptyRecord.
bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T);
+/// The Itanium base layout rule allows virtual bases to overlap other bases,
+/// which complicates layout in specific ways.
+///
+/// Note specifically that the ms_struct attribute doesn't change this.
+bool isOverlappingVBaseABI(const ASTContext &Ctx);
+
} // namespace clang::CodeGenUtils
#endif // LLVM_CLANG_CODEGENUTILS_RECORDLAYOUTUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index c2075a245f05c..733cb208fd93e 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>
@@ -133,27 +134,10 @@ struct CIRRecordLowering final {
/// Helper function to check if the target machine is BigEndian.
bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }
- // The Itanium base layout rule allows virtual bases to overlap
- // other bases, which complicates layout in specific ways.
- //
- // Note specifically that the ms_struct attribute doesn't change this.
- bool isOverlappingVBaseABI() {
- return !astContext.getTargetInfo().getCXXABI().isMicrosoft();
- }
// Recursively searches all of the bases to find out if a vbase is
// not the primary vbase of some base class.
bool hasOwnStorage(const CXXRecordDecl *decl, const CXXRecordDecl *query);
- /// The Microsoft bitfield layout rule allocates discrete storage
- /// units of the field's formal type and only combines adjacent
- /// fields of the same formal type. We want to emit a layout with
- /// these discrete storage units instead of combining them into a
- /// continuous run.
- bool isDiscreteBitFieldABI() {
- return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||
- recordDecl->isMsStruct(astContext);
- }
-
CharUnits bitsToCharUnits(uint64_t bitOffset) {
return astContext.toCharUnitsFromBits(bitOffset);
}
@@ -445,7 +429,7 @@ void CIRRecordLowering::fillOutputFields() {
RecordDecl::field_iterator
CIRRecordLowering::accumulateBitFields(RecordDecl::field_iterator field,
RecordDecl::field_iterator fieldEnd) {
- if (isDiscreteBitFieldABI()) {
+ if (CodeGenUtils::isDiscreteBitFieldABI(astContext, recordDecl)) {
// run stores the first element of the current run of bitfields. fieldEnd is
// used as a special value to note that we don't have a current run. A
// bitfield run is a contiguous collection of bitfields that can be stored
@@ -1292,7 +1276,8 @@ void CIRRecordLowering::accumulateVBases() {
CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl);
// 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.
- if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(baseDecl) &&
+ if (CodeGenUtils::isOverlappingVBaseABI(astContext) &&
+ astContext.isNearlyEmpty(baseDecl) &&
!hasOwnStorage(cxxRecordDecl, baseDecl)) {
members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase, nullptr,
cir::RecordMemberKind::Data, baseDecl));
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index d98d7c0c96dc3..7b21b40ff26ed 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"
@@ -100,27 +101,9 @@ struct CGRecordLowering {
return MemberInfo(Offset, MemberInfo::Field, Data);
}
- /// The Microsoft bitfield layout rule allocates discrete storage
- /// units of the field's formal type and only combines adjacent
- /// fields of the same formal type. We want to emit a layout with
- /// these discrete storage units instead of combining them into a
- /// continuous run.
- bool isDiscreteBitFieldABI() const {
- return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- D->isMsStruct(Context);
- }
-
/// Helper function to check if the target machine is BigEndian.
bool isBE() const { return Context.getTargetInfo().isBigEndian(); }
- /// The Itanium base layout rule allows virtual bases to overlap
- /// other bases, which complicates layout in specific ways.
- ///
- /// Note specifically that the ms_struct attribute doesn't change this.
- bool isOverlappingVBaseABI() const {
- return !Context.getTargetInfo().getCXXABI().isMicrosoft();
- }
-
/// Wraps llvm::Type::getIntNTy with some implicit arguments.
llvm::Type *getIntNType(uint64_t NumBits) const {
unsigned AlignedBits = llvm::alignTo(NumBits, Context.getCharWidth());
@@ -143,7 +126,8 @@ struct CGRecordLowering {
llvm::Type *getStorageType(const FieldDecl *FD) const {
llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
if (!FD->isBitField()) return Type;
- if (isDiscreteBitFieldABI()) return Type;
+ if (CodeGenUtils::isDiscreteBitFieldABI(Context, D))
+ return Type;
return getIntNType(std::min(FD->getBitWidthValue(),
(unsigned)Context.toBits(getSize(Type))));
}
@@ -406,7 +390,7 @@ RecordDecl::field_iterator
CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType,
RecordDecl::field_iterator Field,
RecordDecl::field_iterator FieldEnd) {
- if (isDiscreteBitFieldABI()) {
+ if (CodeGenUtils::isDiscreteBitFieldABI(Context, D)) {
// Run stores the first element of the current run of bitfields. FieldEnd is
// used as a special value to note that we don't have a current run. A
// bitfield run is a contiguous collection of bitfields that can be stored
@@ -874,7 +858,7 @@ CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const {
// smaller than the nvsize. Here we check to see if such a base is placed
// before the nvsize and set the scissor offset to that, instead of the
// nvsize.
- if (!isNonVirtualBaseType && isOverlappingVBaseABI())
+ if (!isNonVirtualBaseType && CodeGenUtils::isOverlappingVBaseABI(Context))
for (const auto &Base : RD->vbases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
if (isEmptyRecordForLayout(Context, Base.getType()))
@@ -898,9 +882,8 @@ void CGRecordLowering::accumulateVBases() {
CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl);
// 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.
- if (isOverlappingVBaseABI() &&
- Context.isNearlyEmpty(BaseDecl) &&
- !hasOwnStorage(RD, BaseDecl)) {
+ if (CodeGenUtils::isOverlappingVBaseABI(Context) &&
+ Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl)) {
Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr,
BaseDecl));
continue;
diff --git a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
index 3b8d433dc8759..b41fb61491377 100644
--- a/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
+++ b/clang/lib/CodeGenUtils/RecordLayoutUtils.cpp
@@ -7,9 +7,14 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGenUtils/RecordLayoutUtils.h"
+#include "clang/Basic/TargetInfo.h"
namespace clang::CodeGenUtils {
+bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD) {
+ return Ctx.getTargetInfo().getCXXABI().isMicrosoft() || RD->isMsStruct(Ctx);
+}
+
bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD) {
if (FD->isZeroLengthBitField())
return true;
@@ -42,4 +47,8 @@ bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T) {
return true;
}
+bool isOverlappingVBaseABI(const ASTContext &Ctx) {
+ return !Ctx.getTargetInfo().getCXXABI().isMicrosoft();
+}
+
} // namespace clang::CodeGenUtils
More information about the llvm-branch-commits
mailing list