[clang] [NFCI] Extract out some functions into CodeGenUtils. (PR #221001)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Thu Sep 3 14:09:56 PDT 2026
https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/221001
>From fe6f4b59a4d872a34965a8fefb9925e8fb450702 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 3 Sep 2026 09:50:02 -0700
Subject: [PATCH 1/4] [NFCI] Extract out some functions into CodeGenUtils.
I need to use these for CIR (see #220946). Also, its been a long-time
coming that we had a way to share stuff between both CodeGens.
This patch does (hopefully) the infrastructure work to get this running
right.
I asked Claude to help me with the CMake files, and best I can tell it
looks right? But if someone knows better, please let me know. I suspect
we might need to add dependencies along the way as we add new things,
but this seems to work at the moment?
Otherwise, this just moves a handful of trivial utilities that seemed
like a good starting point, plus one I need for CIR right away.
---
.../include/clang/CodeGenUtils/CodeGenUtils.h | 33 +++++
clang/lib/CIR/CodeGen/CIRGenClass.cpp | 9 +-
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 15 +--
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 21 +---
.../CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp | 7 +-
clang/lib/CIR/CodeGen/CMakeLists.txt | 1 +
clang/lib/CMakeLists.txt | 1 +
clang/lib/CodeGen/CGClass.cpp | 94 +-------------
clang/lib/CodeGen/CGExpr.cpp | 15 +--
clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 9 +-
clang/lib/CodeGen/CMakeLists.txt | 1 +
clang/lib/CodeGen/CodeGenModule.cpp | 23 +---
clang/lib/CodeGenUtils/CMakeLists.txt | 11 ++
clang/lib/CodeGenUtils/CodeGenUtils.cpp | 115 ++++++++++++++++++
14 files changed, 189 insertions(+), 166 deletions(-)
create mode 100644 clang/include/clang/CodeGenUtils/CodeGenUtils.h
create mode 100644 clang/lib/CodeGenUtils/CMakeLists.txt
create mode 100644 clang/lib/CodeGenUtils/CodeGenUtils.cpp
diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
new file mode 100644
index 0000000000000..9a93281c3689d
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -0,0 +1,33 @@
+//===--- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang::CodeGenUtils {
+/// Check whether we need to initialize any vtable pointers before calling this
+/// destructor.
+bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
+ const CXXDestructorDecl *Dtor);
+bool FieldHasTrivialDestructorBody(ASTContext &Context,
+ const FieldDecl *Field);
+/// Determines whether the language options require us to model
+/// unwind exceptions. We treat -fexceptions as mandating this
+/// except under the fragile ObjC ABI with only ObjC exceptions
+/// enabled. This means, for example, that C with -fexceptions
+/// enables this.
+bool hasUnwindExceptions(const LangOptions &LangOpts);
+/// Helper method to check if the underlying ABI is AAPCS
+bool isAAPCS(const TargetInfo &TargetInfo);
+
+bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit);
+}
+
+#endif // LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
index 5427ca8bf30a6..b81f26839a579 100644
--- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Type.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
using namespace clang;
using namespace clang::CIRGen;
@@ -154,12 +155,6 @@ static void emitMemberInitializer(CIRGenFunction &cgf,
cgf.emitInitializerForField(field, lhs, memberInit->getInit());
}
-static bool isInitializerOfDynamicClass(const CXXCtorInitializer *baseInit) {
- const Type *baseType = baseInit->getBaseClass();
- const auto *baseClassDecl = baseType->castAsCXXRecordDecl();
- return baseClassDecl->isDynamicClass();
-}
-
namespace {
/// Call the destructor for a direct base class.
struct CallBaseDtor final : EHScopeStack::Cleanup {
@@ -344,7 +339,7 @@ void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd,
auto emitInitializer = [&](CXXCtorInitializer *baseInit) {
if (cgm.getCodeGenOpts().StrictVTablePointers &&
cgm.getCodeGenOpts().OptimizationLevel > 0 &&
- isInitializerOfDynamicClass(baseInit)) {
+ CodeGenUtils::isInitializerOfDynamicClass(baseInit)) {
// It's OK to continue after emitting the error here. The missing code
// just "launders" the 'this' pointer.
cgm.errorNYI(cd->getSourceRange(),
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index ac7d4693c6000..28b00321fa39b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -30,6 +30,7 @@
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include <optional>
using namespace clang;
@@ -507,12 +508,6 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
assert(!cir::MissingFeatures::opTBAA());
}
-// TODO: Replace this with a proper TargetInfo function call.
-/// Helper method to check if the underlying ABI is AAPCS
-static bool isAAPCS(const TargetInfo &targetInfo) {
- return targetInfo.getABI().starts_with("aapcs");
-}
-
mlir::Value CIRGenFunction::emitStoreThroughBitfieldLValue(RValue src,
LValue dst) {
@@ -520,9 +515,9 @@ mlir::Value CIRGenFunction::emitStoreThroughBitfieldLValue(RValue src,
mlir::Type resLTy = convertTypeForMem(dst.getType());
Address ptr = dst.getBitFieldAddress();
- bool useVoaltile = cgm.getCodeGenOpts().AAPCSBitfieldWidth &&
- dst.isVolatileQualified() &&
- info.volatileStorageSize != 0 && isAAPCS(cgm.getTarget());
+ bool useVoaltile =
+ cgm.getCodeGenOpts().AAPCSBitfieldWidth && dst.isVolatileQualified() &&
+ info.volatileStorageSize != 0 && CodeGenUtils::isAAPCS(cgm.getTarget());
assert(currSrcLoc && "must pass in source location");
@@ -539,7 +534,7 @@ RValue CIRGenFunction::emitLoadOfBitfieldLValue(LValue lv, SourceLocation loc) {
Address ptr = lv.getBitFieldAddress();
bool useVoaltile = lv.isVolatileQualified() && info.volatileOffset != 0 &&
- isAAPCS(cgm.getTarget());
+ CodeGenUtils::isAAPCS(cgm.getTarget());
mlir::Value field =
builder.createGetBitfield(getLoc(loc), resLTy, ptr, ptr.getElementType(),
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0cb2164f4c0ef..2abd167634614 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -36,6 +36,7 @@
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/Interfaces/CIROpInterfaces.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -3268,30 +3269,12 @@ void CIRGenModule::setFunctionAttributes(GlobalDecl globalDecl,
}
}
-/// Determines whether the language options require us to model
-/// unwind exceptions. We treat -fexceptions as mandating this
-/// except under the fragile ObjC ABI with only ObjC exceptions
-/// enabled. This means, for example, that C with -fexceptions
-/// enables this.
-static bool hasUnwindExceptions(const LangOptions &langOpts) {
- // If exceptions are completely disabled, obviously this is false.
- if (!langOpts.Exceptions)
- return false;
- // If C++ exceptions are enabled, this is true.
- if (langOpts.CXXExceptions)
- return true;
- // If ObjC exceptions are enabled, this depends on the ABI.
- if (langOpts.ObjCExceptions)
- return langOpts.ObjCRuntime.hasUnwindExceptions();
- return true;
-}
-
void CIRGenModule::setCIRFunctionAttributesForDefinition(
const clang::FunctionDecl *decl, cir::FuncOp f) {
assert(!cir::MissingFeatures::opFuncUnwindTablesAttr());
assert(!cir::MissingFeatures::stackProtector());
- if (!hasUnwindExceptions(langOpts))
+ if (!CodeGenUtils::hasUnwindExceptions(langOpts))
f->setAttr(cir::CIRDialect::getNoThrowAttrName(),
mlir::UnitAttr::get(&getMLIRContext()));
diff --git a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
index c00e514c48cd0..fe31b92af6166 100644
--- a/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp
@@ -22,6 +22,7 @@
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
#include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "llvm/Support/Casting.h"
#include <memory>
@@ -112,10 +113,6 @@ struct CIRRecordLowering final {
mlir::Type getVFPtrType();
- bool isAAPCS() const {
- return astContext.getTargetInfo().getABI().starts_with("aapcs");
- }
-
/// Helper function to check if the target machine is BigEndian.
bool isBigEndian() const { return astContext.getTargetInfo().isBigEndian(); }
@@ -1091,7 +1088,7 @@ bool CIRRecordLowering::hasOwnStorage(const CXXRecordDecl *decl,
/// Enforcing the width restriction can be disabled using
/// -fno-aapcs-bitfield-width.
void CIRRecordLowering::computeVolatileBitfields() {
- if (!isAAPCS() ||
+ if (!CodeGenUtils::isAAPCS(astContext.getTargetInfo()) ||
!cirGenTypes.getCGModule().getCodeGenOpts().AAPCSBitfieldWidth)
return;
diff --git a/clang/lib/CIR/CodeGen/CMakeLists.txt b/clang/lib/CIR/CodeGen/CMakeLists.txt
index 3ea96a8ea05e9..0fd5cdfb02540 100644
--- a/clang/lib/CIR/CodeGen/CMakeLists.txt
+++ b/clang/lib/CIR/CodeGen/CMakeLists.txt
@@ -69,6 +69,7 @@ add_clang_library(clangCIR
LINK_LIBS
clangAST
clangBasic
+ clangCodeGenUtils
clangLex
${dialect_libs}
CIRRegisterAllDialects
diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt
index dee31cb3f166e..22d260e55b271 100644
--- a/clang/lib/CMakeLists.txt
+++ b/clang/lib/CMakeLists.txt
@@ -7,6 +7,7 @@ add_subdirectory(AST)
add_subdirectory(ASTMatchers)
add_subdirectory(CrossTU)
add_subdirectory(Sema)
+add_subdirectory(CodeGenUtils)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
add_subdirectory(Edit)
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index b1c4b0db65c2b..8db5e0393b73d 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -26,6 +26,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/CodeGenOptions.h"
#include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -1228,11 +1229,6 @@ class AssignmentMemcpyizer : public FieldMemcpyizer {
} // end anonymous namespace
-static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) {
- const Type *BaseType = BaseInit->getBaseClass();
- return BaseType->castAsCXXRecordDecl()->isDynamicClass();
-}
-
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
@@ -1291,7 +1287,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
SaveAndRestore ThisRAII(CXXThisValue);
if (CGM.getCodeGenOpts().StrictVTablePointers &&
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- isInitializerOfDynamicClass(Initializer))
+ CodeGenUtils::isInitializerOfDynamicClass(Initializer))
CXXThisValue = Builder.CreateLaunderInvariantGroup(LoadCXXThis());
EmitBaseInitializer(*this, ClassDecl, Initializer);
}
@@ -1309,7 +1305,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
SaveAndRestore ThisRAII(CXXThisValue);
if (CGM.getCodeGenOpts().StrictVTablePointers &&
CGM.getCodeGenOpts().OptimizationLevel > 0 &&
- isInitializerOfDynamicClass(Initializer))
+ CodeGenUtils::isInitializerOfDynamicClass(Initializer))
CXXThisValue = Builder.CreateLaunderInvariantGroup(LoadCXXThis());
EmitBaseInitializer(*this, ClassDecl, Initializer);
}
@@ -1329,86 +1325,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CM.finish();
}
-static bool FieldHasTrivialDestructorBody(ASTContext &Context,
- const FieldDecl *Field);
-
-static bool
-HasTrivialDestructorBody(ASTContext &Context,
- const CXXRecordDecl *BaseClassDecl,
- const CXXRecordDecl *MostDerivedClassDecl) {
- // If the destructor is trivial we don't have to check anything else.
- if (BaseClassDecl->hasTrivialDestructor())
- return true;
-
- if (!BaseClassDecl->getDestructor()->hasTrivialBody())
- return false;
-
- // Check fields.
- for (const auto *Field : BaseClassDecl->fields())
- if (!FieldHasTrivialDestructorBody(Context, Field))
- return false;
-
- // Check non-virtual bases.
- for (const auto &I : BaseClassDecl->bases()) {
- if (I.isVirtual())
- continue;
-
- const auto *NonVirtualBase = I.getType()->castAsCXXRecordDecl();
- if (!HasTrivialDestructorBody(Context, NonVirtualBase,
- MostDerivedClassDecl))
- return false;
- }
-
- if (BaseClassDecl == MostDerivedClassDecl) {
- // Check virtual bases.
- for (const auto &I : BaseClassDecl->vbases()) {
- const auto *VirtualBase = I.getType()->castAsCXXRecordDecl();
- if (!HasTrivialDestructorBody(Context, VirtualBase, MostDerivedClassDecl))
- return false;
- }
- }
-
- return true;
-}
-
-static bool FieldHasTrivialDestructorBody(ASTContext &Context,
- const FieldDecl *Field) {
- QualType FieldBaseElementType = Context.getBaseElementType(Field->getType());
-
- auto *FieldClassDecl = FieldBaseElementType->getAsCXXRecordDecl();
- if (!FieldClassDecl)
- return true;
-
- // The destructor for an implicit anonymous union member is never invoked.
- if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
- return true;
-
- return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
-}
-
-/// CanSkipVTablePointerInitialization - Check whether we need to initialize
-/// any vtable pointers before calling this destructor.
-static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF,
- const CXXDestructorDecl *Dtor) {
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- if (!ClassDecl->isDynamicClass())
- return true;
-
- // For a final class, the vtable pointer is known to already point to the
- // class's vtable.
- if (ClassDecl->isEffectivelyFinal())
- return true;
-
- if (!Dtor->hasTrivialBody())
- return false;
-
- // Check the fields.
- for (const auto *Field : ClassDecl->fields())
- if (!FieldHasTrivialDestructorBody(CGF.getContext(), Field))
- return false;
-
- return true;
-}
static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
CodeGenFunction &CGF,
@@ -1611,7 +1527,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
EnterDtorCleanups(Dtor, Dtor_Base);
// Initialize the vtable pointers before entering the body.
- if (!CanSkipVTablePointerInitialization(*this, Dtor)) {
+ if (!CodeGenUtils::CanSkipVTablePointerInitialization(getContext(), Dtor)) {
// Insert the llvm.launder.invariant.group intrinsic before initializing
// the vptrs to cancel any previous assumptions we might have made.
if (CGM.getCodeGenOpts().StrictVTablePointers &&
@@ -1981,7 +1897,7 @@ class SanitizeDtorCleanupBuilder {
if (isEmptyFieldForLayout(Context, Field))
return;
unsigned FieldIndex = Field->getFieldIndex();
- if (FieldHasTrivialDestructorBody(Context, Field)) {
+ if (CodeGenUtils::FieldHasTrivialDestructorBody(Context, Field)) {
if (!StartIndex)
StartIndex = FieldIndex;
} else if (StartIndex) {
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index cba81de9d10dd..6e78ed6b7cabb 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -39,6 +39,7 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
@@ -514,11 +515,6 @@ static RawAddress createReferenceTemporary(CodeGenFunction &CGF,
llvm_unreachable("unknown storage duration");
}
-/// Helper method to check if the underlying ABI is AAPCS
-static bool isAAPCS(const TargetInfo &TargetInfo) {
- return TargetInfo.getABI().starts_with("aapcs");
-}
-
LValue CodeGenFunction::
EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
const Expr *E = M->getSubExpr();
@@ -2665,7 +2661,8 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV,
Builder.CreateLoad(Ptr, LV.isVolatileQualified(), "bf.load");
bool UseVolatile = LV.isVolatileQualified() &&
- Info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget());
+ Info.VolatileStorageSize != 0 &&
+ CodeGenUtils::isAAPCS(CGM.getTarget());
const unsigned Offset = UseVolatile ? Info.VolatileOffset : Info.Offset;
const unsigned StorageSize =
UseVolatile ? Info.VolatileStorageSize : Info.StorageSize;
@@ -3067,7 +3064,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
const bool UseVolatile =
CGM.getCodeGenOpts().AAPCSBitfieldWidth && Dst.isVolatileQualified() &&
- Info.VolatileStorageSize != 0 && isAAPCS(CGM.getTarget());
+ Info.VolatileStorageSize != 0 && CodeGenUtils::isAAPCS(CGM.getTarget());
const unsigned StorageSize =
UseVolatile ? Info.VolatileStorageSize : Info.StorageSize;
const unsigned Offset = UseVolatile ? Info.VolatileOffset : Info.Offset;
@@ -3101,7 +3098,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst,
// with any non-bit-field member, its container must be read exactly once
// and written exactly once using the access width appropriate to the type
// of the container. The two accesses are not atomic.
- if (Dst.isVolatileQualified() && isAAPCS(CGM.getTarget()) &&
+ if (Dst.isVolatileQualified() && CodeGenUtils::isAAPCS(CGM.getTarget()) &&
CGM.getCodeGenOpts().ForceAAPCSBitfieldLoad)
Builder.CreateLoad(Ptr, true, "bf.load");
}
@@ -5801,7 +5798,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, const FieldDecl *field,
const CGRecordLayout &RL =
CGM.getTypes().getCGRecordLayout(field->getParent());
const CGBitFieldInfo &Info = RL.getBitFieldInfo(field);
- const bool UseVolatile = isAAPCS(CGM.getTarget()) &&
+ const bool UseVolatile = CodeGenUtils::isAAPCS(CGM.getTarget()) &&
CGM.getCodeGenOpts().AAPCSBitfieldWidth &&
Info.VolatileStorageSize != 0 &&
field->getType()
diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
index e9205c68c2812..d98d7c0c96dc3 100644
--- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/CodeGenOptions.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Type.h"
@@ -109,11 +110,6 @@ struct CGRecordLowering {
D->isMsStruct(Context);
}
- /// Helper function to check if we are targeting AAPCS.
- bool isAAPCS() const {
- return Context.getTargetInfo().getABI().starts_with("aapcs");
- }
-
/// Helper function to check if the target machine is BigEndian.
bool isBE() const { return Context.getTargetInfo().isBigEndian(); }
@@ -753,7 +749,8 @@ void CGRecordLowering::accumulateBases() {
/// Enforcing the width restriction can be disabled using
/// -fno-aapcs-bitfield-width.
void CGRecordLowering::computeVolatileBitfields() {
- if (!isAAPCS() || !Types.getCodeGenOpts().AAPCSBitfieldWidth)
+ if (!CodeGenUtils::isAAPCS(Context.getTargetInfo()) ||
+ !Types.getCodeGenOpts().AAPCSBitfieldWidth)
return;
for (auto &I : BitFields) {
diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt
index 853f038c4186b..d3986ddecfe12 100644
--- a/clang/lib/CodeGen/CMakeLists.txt
+++ b/clang/lib/CodeGen/CMakeLists.txt
@@ -178,6 +178,7 @@ add_clang_library(clangCodeGen
clangAST
clangAnalysis
clangBasic
+ clangCodeGenUtils
clangFrontend
clangLex
clangSerialization
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 17b5f0fe4133d..622423893bfa6 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -48,6 +48,7 @@
#include "clang/Basic/Version.h"
#include "clang/CodeGen/BackendUtil.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/ABI/IRTypeMapper.h"
#include "llvm/ABI/TargetInfo.h"
@@ -3073,26 +3074,6 @@ void CodeGenModule::GenKernelArgMetadata(llvm::Function *Fn,
llvm::MDNode::get(VMContext, argNames));
}
-/// Determines whether the language options require us to model
-/// unwind exceptions. We treat -fexceptions as mandating this
-/// except under the fragile ObjC ABI with only ObjC exceptions
-/// enabled. This means, for example, that C with -fexceptions
-/// enables this.
-static bool hasUnwindExceptions(const LangOptions &LangOpts) {
- // If exceptions are completely disabled, obviously this is false.
- if (!LangOpts.Exceptions) return false;
-
- // If C++ exceptions are enabled, this is true.
- if (LangOpts.CXXExceptions) return true;
-
- // If ObjC exceptions are enabled, this depends on the ABI.
- if (LangOpts.ObjCExceptions) {
- return LangOpts.ObjCRuntime.hasUnwindExceptions();
- }
-
- return true;
-}
-
static bool requiresMemberFunctionPointerTypeMetadata(CodeGenModule &CGM,
const CXXMethodDecl *MD) {
// Check that the type metadata can ever actually be used by a call.
@@ -3135,7 +3116,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
B.addAttribute("stack-probe-size",
std::to_string(CodeGenOpts.StackProbeSize));
- if (!hasUnwindExceptions(LangOpts))
+ if (!CodeGenUtils::hasUnwindExceptions(LangOpts))
B.addAttribute(llvm::Attribute::NoUnwind);
if (std::optional<llvm::Attribute::AttrKind> Attr =
diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt
new file mode 100644
index 0000000000000..b87c83b42dd9b
--- /dev/null
+++ b/clang/lib/CodeGenUtils/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ )
+
+add_clang_library(clangCodeGenUtils
+ CodeGenUtils.cpp
+
+ LINK_LIBS
+ clangAST
+ clangBasic
+ )
diff --git a/clang/lib/CodeGenUtils/CodeGenUtils.cpp b/clang/lib/CodeGenUtils/CodeGenUtils.cpp
new file mode 100644
index 0000000000000..e052410dfc3c5
--- /dev/null
+++ b/clang/lib/CodeGenUtils/CodeGenUtils.cpp
@@ -0,0 +1,115 @@
+//==--- CodeGenUtils.cpp - 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/CodeGenUtils/CodeGenUtils.h"
+#include "clang/Basic/TargetInfo.h"
+
+namespace clang::CodeGenUtils {
+static bool
+HasTrivialDestructorBody(ASTContext &Context,
+ const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *MostDerivedClassDecl) {
+ // If the destructor is trivial we don't have to check anything else.
+ if (BaseClassDecl->hasTrivialDestructor())
+ return true;
+
+ if (!BaseClassDecl->getDestructor()->hasTrivialBody())
+ return false;
+
+ // Check fields.
+ for (const auto *Field : BaseClassDecl->fields())
+ if (!FieldHasTrivialDestructorBody(Context, Field))
+ return false;
+
+ // Check non-virtual bases.
+ for (const auto &I : BaseClassDecl->bases()) {
+ if (I.isVirtual())
+ continue;
+
+ const auto *NonVirtualBase = I.getType()->castAsCXXRecordDecl();
+ if (!HasTrivialDestructorBody(Context, NonVirtualBase,
+ MostDerivedClassDecl))
+ return false;
+ }
+
+ if (BaseClassDecl == MostDerivedClassDecl) {
+ // Check virtual bases.
+ for (const auto &I : BaseClassDecl->vbases()) {
+ const auto *VirtualBase = I.getType()->castAsCXXRecordDecl();
+ if (!HasTrivialDestructorBody(Context, VirtualBase, MostDerivedClassDecl))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool FieldHasTrivialDestructorBody(ASTContext &Context,
+ const FieldDecl *Field) {
+ QualType FieldBaseElementType = Context.getBaseElementType(Field->getType());
+
+ auto *FieldClassDecl = FieldBaseElementType->getAsCXXRecordDecl();
+ if (!FieldClassDecl)
+ return true;
+
+ // The destructor for an implicit anonymous union member is never invoked.
+ if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
+ return true;
+
+ return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
+}
+
+/// Check whether we need to initialize any vtable pointers before calling this
+/// destructor.
+bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
+ const CXXDestructorDecl *Dtor) {
+ const CXXRecordDecl *ClassDecl = Dtor->getParent();
+ if (!ClassDecl->isDynamicClass())
+ return true;
+
+ // For a final class, the vtable pointer is known to already point to the
+ // class's vtable.
+ if (ClassDecl->isEffectivelyFinal())
+ return true;
+
+ if (!Dtor->hasTrivialBody())
+ return false;
+
+ // Check the fields.
+ for (const auto *Field : ClassDecl->fields())
+ if (!FieldHasTrivialDestructorBody(Ctx, Field))
+ return false;
+
+ return true;
+}
+bool hasUnwindExceptions(const LangOptions &LangOpts) {
+ // If exceptions are completely disabled, obviously this is false.
+ if (!LangOpts.Exceptions)
+ return false;
+
+ // If C++ exceptions are enabled, this is true.
+ if (LangOpts.CXXExceptions)
+ return true;
+
+ // If ObjC exceptions are enabled, this depends on the ABI.
+ if (LangOpts.ObjCExceptions) {
+ return LangOpts.ObjCRuntime.hasUnwindExceptions();
+ }
+
+ return true;
+}
+
+bool isAAPCS(const TargetInfo &TargetInfo) {
+ return TargetInfo.getABI().starts_with("aapcs");
+}
+bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) {
+ const Type *BaseType = BaseInit->getBaseClass();
+ return BaseType->castAsCXXRecordDecl()->isDynamicClass();
+}
+
+} // namespace clang::CodeGenUtils
>From 18d9d305ae14839706c2219338d883815f639238 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 3 Sep 2026 10:22:22 -0700
Subject: [PATCH 2/4] Clang-format
---
clang/include/clang/CodeGenUtils/CodeGenUtils.h | 5 ++---
clang/lib/CodeGen/CGClass.cpp | 1 -
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
index 9a93281c3689d..19ba6732d4b30 100644
--- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -16,8 +16,7 @@ namespace clang::CodeGenUtils {
/// destructor.
bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
const CXXDestructorDecl *Dtor);
-bool FieldHasTrivialDestructorBody(ASTContext &Context,
- const FieldDecl *Field);
+bool FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
/// Determines whether the language options require us to model
/// unwind exceptions. We treat -fexceptions as mandating this
/// except under the fragile ObjC ABI with only ObjC exceptions
@@ -28,6 +27,6 @@ bool hasUnwindExceptions(const LangOptions &LangOpts);
bool isAAPCS(const TargetInfo &TargetInfo);
bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit);
-}
+} // namespace clang::CodeGenUtils
#endif // LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 8db5e0393b73d..030c7328edcb3 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1325,7 +1325,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CM.finish();
}
-
static void EmitConditionalArrayDtorCall(const CXXDestructorDecl *DD,
CodeGenFunction &CGF,
llvm::Value *ShouldDeleteCondition) {
>From 105aa8af71bfe8ed0af4c1ed92e264a630c0d8c7 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 3 Sep 2026 11:15:12 -0700
Subject: [PATCH 3/4] Add newlines inside header file
---
clang/include/clang/CodeGenUtils/CodeGenUtils.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
index 19ba6732d4b30..9f8cde5835eaa 100644
--- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -16,13 +16,16 @@ namespace clang::CodeGenUtils {
/// destructor.
bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
const CXXDestructorDecl *Dtor);
+
bool FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
+
/// Determines whether the language options require us to model
/// unwind exceptions. We treat -fexceptions as mandating this
/// except under the fragile ObjC ABI with only ObjC exceptions
/// enabled. This means, for example, that C with -fexceptions
/// enables this.
bool hasUnwindExceptions(const LangOptions &LangOpts);
+
/// Helper method to check if the underlying ABI is AAPCS
bool isAAPCS(const TargetInfo &TargetInfo);
>From b751d719bd2494d9dec6d2bc97ecee086dd3d363 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 3 Sep 2026 14:07:42 -0700
Subject: [PATCH 4/4] Switch to camel case
---
clang/include/clang/CodeGenUtils/CodeGenUtils.h | 4 ++--
clang/lib/CodeGen/CGClass.cpp | 4 ++--
clang/lib/CodeGenUtils/CodeGenUtils.cpp | 16 ++++++++--------
3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
index 9f8cde5835eaa..faca3b151edc2 100644
--- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -14,10 +14,10 @@
namespace clang::CodeGenUtils {
/// Check whether we need to initialize any vtable pointers before calling this
/// destructor.
-bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
+bool canSkipVTablePointerInitialization(ASTContext &Ctx,
const CXXDestructorDecl *Dtor);
-bool FieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
+bool fieldHasTrivialDestructorBody(ASTContext &Context, const FieldDecl *Field);
/// Determines whether the language options require us to model
/// unwind exceptions. We treat -fexceptions as mandating this
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 030c7328edcb3..e51f3f9ac9cb4 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1526,7 +1526,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
EnterDtorCleanups(Dtor, Dtor_Base);
// Initialize the vtable pointers before entering the body.
- if (!CodeGenUtils::CanSkipVTablePointerInitialization(getContext(), Dtor)) {
+ if (!CodeGenUtils::canSkipVTablePointerInitialization(getContext(), Dtor)) {
// Insert the llvm.launder.invariant.group intrinsic before initializing
// the vptrs to cancel any previous assumptions we might have made.
if (CGM.getCodeGenOpts().StrictVTablePointers &&
@@ -1896,7 +1896,7 @@ class SanitizeDtorCleanupBuilder {
if (isEmptyFieldForLayout(Context, Field))
return;
unsigned FieldIndex = Field->getFieldIndex();
- if (CodeGenUtils::FieldHasTrivialDestructorBody(Context, Field)) {
+ if (CodeGenUtils::fieldHasTrivialDestructorBody(Context, Field)) {
if (!StartIndex)
StartIndex = FieldIndex;
} else if (StartIndex) {
diff --git a/clang/lib/CodeGenUtils/CodeGenUtils.cpp b/clang/lib/CodeGenUtils/CodeGenUtils.cpp
index e052410dfc3c5..482896e1944c1 100644
--- a/clang/lib/CodeGenUtils/CodeGenUtils.cpp
+++ b/clang/lib/CodeGenUtils/CodeGenUtils.cpp
@@ -11,7 +11,7 @@
namespace clang::CodeGenUtils {
static bool
-HasTrivialDestructorBody(ASTContext &Context,
+hasTrivialDestructorBody(ASTContext &Context,
const CXXRecordDecl *BaseClassDecl,
const CXXRecordDecl *MostDerivedClassDecl) {
// If the destructor is trivial we don't have to check anything else.
@@ -23,7 +23,7 @@ HasTrivialDestructorBody(ASTContext &Context,
// Check fields.
for (const auto *Field : BaseClassDecl->fields())
- if (!FieldHasTrivialDestructorBody(Context, Field))
+ if (!fieldHasTrivialDestructorBody(Context, Field))
return false;
// Check non-virtual bases.
@@ -32,7 +32,7 @@ HasTrivialDestructorBody(ASTContext &Context,
continue;
const auto *NonVirtualBase = I.getType()->castAsCXXRecordDecl();
- if (!HasTrivialDestructorBody(Context, NonVirtualBase,
+ if (!hasTrivialDestructorBody(Context, NonVirtualBase,
MostDerivedClassDecl))
return false;
}
@@ -41,7 +41,7 @@ HasTrivialDestructorBody(ASTContext &Context,
// Check virtual bases.
for (const auto &I : BaseClassDecl->vbases()) {
const auto *VirtualBase = I.getType()->castAsCXXRecordDecl();
- if (!HasTrivialDestructorBody(Context, VirtualBase, MostDerivedClassDecl))
+ if (!hasTrivialDestructorBody(Context, VirtualBase, MostDerivedClassDecl))
return false;
}
}
@@ -49,7 +49,7 @@ HasTrivialDestructorBody(ASTContext &Context,
return true;
}
-bool FieldHasTrivialDestructorBody(ASTContext &Context,
+bool fieldHasTrivialDestructorBody(ASTContext &Context,
const FieldDecl *Field) {
QualType FieldBaseElementType = Context.getBaseElementType(Field->getType());
@@ -61,12 +61,12 @@ bool FieldHasTrivialDestructorBody(ASTContext &Context,
if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion())
return true;
- return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
+ return hasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl);
}
/// Check whether we need to initialize any vtable pointers before calling this
/// destructor.
-bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
+bool canSkipVTablePointerInitialization(ASTContext &Ctx,
const CXXDestructorDecl *Dtor) {
const CXXRecordDecl *ClassDecl = Dtor->getParent();
if (!ClassDecl->isDynamicClass())
@@ -82,7 +82,7 @@ bool CanSkipVTablePointerInitialization(ASTContext &Ctx,
// Check the fields.
for (const auto *Field : ClassDecl->fields())
- if (!FieldHasTrivialDestructorBody(Ctx, Field))
+ if (fieldHasTrivialDestructorBody(Ctx, Field))
return false;
return true;
More information about the cfe-commits
mailing list