https://github.com/dwblaikie updated https://github.com/llvm/llvm-project/pull/202807
>From 196ec3726f4f462910c5b5616aa68f7e6e5abbcb Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Wed, 20 May 2026 22:07:29 +0000 Subject: [PATCH 1/7] WIP --- clang/include/clang/CodeGen/ModuleBuilder.h | 3 ++ clang/lib/CodeGen/ModuleBuilder.cpp | 11 +++++ .../unittests/CodeGen/CodeGenExternalTest.cpp | 47 +++++++++++++++---- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 5173fd05d75d6..a144e904b0228 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -32,6 +32,7 @@ namespace llvm { inline constexpr llvm::StringRef ClangTrapPrefix = "__clang_trap_msg"; namespace clang { + class BaseSubobject; class CodeGenOptions; class CoverageSourceInfo; class Decl; @@ -105,6 +106,8 @@ class CodeGenerator : public ASTConsumer { /// definition has been registered with this code generator. llvm::Constant *GetAddrOfGlobal(GlobalDecl decl, bool isForDefinition); + llvm::Constant *GetAddrOfVTable(BaseSubobject base, CXXRecordDecl *decl); + /// Create a new \c llvm::Module after calling HandleTranslationUnit. This /// enable codegen in interactive processing environments. llvm::Module* StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C); diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 1888de4521abd..f91d9222e9232 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/CodeGen/ModuleBuilder.h" +#include "CGCXXABI.h" #include "CGDebugInfo.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" @@ -131,6 +132,11 @@ namespace { return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition)); } + llvm::Constant *GetAddrOfVTable(BaseSubobject subobject, + CXXRecordDecl *decl) { + return Builder->getCXXABI().getVTableAddressPoint(subobject, decl); + } + llvm::Module *StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C) { assert(!M && "Replacing existing Module?"); @@ -378,6 +384,11 @@ llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global, ->GetAddrOfGlobal(global, isForDefinition); } +llvm::Constant *CodeGenerator::GetAddrOfVTable(BaseSubobject base, + CXXRecordDecl *decl) { + return static_cast<CodeGeneratorImpl *>(this)->GetAddrOfVTable(base, decl); +} + llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName, llvm::LLVMContext &C) { return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C); diff --git a/clang/unittests/CodeGen/CodeGenExternalTest.cpp b/clang/unittests/CodeGen/CodeGenExternalTest.cpp index be3be147460f3..8ad1ead915328 100644 --- a/clang/unittests/CodeGen/CodeGenExternalTest.cpp +++ b/clang/unittests/CodeGen/CodeGenExternalTest.cpp @@ -10,6 +10,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/BaseSubobject.h" #include "clang/AST/GlobalDecl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/TargetInfo.h" @@ -21,6 +22,7 @@ #include "clang/Sema/Sema.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Operator.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/TargetParser/Host.h" @@ -163,7 +165,12 @@ bool MyASTConsumer::shouldSkipFunctionBody(Decl *D) { const char TestProgram[] = "struct mytest_struct { char x; short y; char p; long z; };\n" - "int mytest_fn(int x) { return x; }\n"; + "int mytest_fn(int x) { return x; }\n" + "struct mytest_dynamic_struct {\n" + " mytest_dynamic_struct();\n" + " virtual void f1();\n" + "};\n" + "mytest_dynamic_struct::mytest_dynamic_struct() { }\n"; // This function has the real test code here static void test_codegen_fns(MyASTConsumer *my) { @@ -176,17 +183,19 @@ static void test_codegen_fns(MyASTConsumer *my) { for (auto decl : my->toplevel_decls ) { if (FunctionDecl *fd = dyn_cast<FunctionDecl>(decl)) { - if (fd->getName() == "mytest_fn") { - Constant *c = my->Builder->GetAddrOfGlobal(GlobalDecl(fd), false); - // Verify that we got a function. - ASSERT_TRUE(c != NULL); - if (DebugThisTest) { - c->print(dbgs(), true); - dbgs() << "\n"; + if (fd->getDeclName().isIdentifier()) { + if (fd->getName() == "mytest_fn") { + Constant *c = my->Builder->GetAddrOfGlobal(GlobalDecl(fd), false); + // Verify that we got a function. + ASSERT_TRUE(c != NULL); + if (DebugThisTest) { + c->print(dbgs(), true); + dbgs() << "\n"; + } + mytest_fn_ok = true; } - mytest_fn_ok = true; } - } else if(clang::RecordDecl *rd = dyn_cast<RecordDecl>(decl)) { + } else if(CXXRecordDecl *rd = dyn_cast<CXXRecordDecl>(decl)) { if (rd->getName() == "mytest_struct") { RecordDecl *def = rd->getDefinition(); ASSERT_TRUE(def != NULL); @@ -247,6 +256,24 @@ static void test_codegen_fns(MyASTConsumer *my) { ASSERT_GE(zTy->getPrimitiveSizeInBits(), 32u); // long is at least 32b mytest_struct_ok = true; + } else if (rd->getName() == "mytest_dynamic_struct") { + Constant *c = my->Builder->GetAddrOfVTable( + BaseSubobject(rd, CharUnits::fromQuantity(0)), rd); + ASSERT_NE(c, nullptr); + Value *vtableGlobal = c->getOperand(0); + ASSERT_NE(vtableGlobal, nullptr); + ASSERT_EQ(vtableGlobal->getName(), "_ZTV21mytest_dynamic_struct"); + const DataLayout &dataLayout = + my->Builder->GetModule()->getDataLayout(); + unsigned pointerSizeInBits = + dataLayout.getPointerTypeSizeInBits(c->getType()); + APInt offset(pointerSizeInBits, 0); + GEPOperator* gepOperator = dyn_cast<GEPOperator>(c); + ASSERT_NE(gepOperator, nullptr); + gepOperator->accumulateConstantOffset(dataLayout, offset); + // Itanium ABI has a couple of pointersi (offset to top, type info) + // before the array of function pointers. + ASSERT_EQ(offset, (pointerSizeInBits / 8) * 2); } } } >From 239c21617ff9eb4fa8f8b94c3d4e31d1063a45a1 Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Wed, 10 Jun 2026 18:38:06 +0000 Subject: [PATCH 2/7] Formatting --- clang/include/clang/CodeGen/ModuleBuilder.h | 20 +++++++++---------- .../unittests/CodeGen/CodeGenExternalTest.cpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index a144e904b0228..21dee80d60d65 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -32,16 +32,16 @@ namespace llvm { inline constexpr llvm::StringRef ClangTrapPrefix = "__clang_trap_msg"; namespace clang { - class BaseSubobject; - class CodeGenOptions; - class CoverageSourceInfo; - class Decl; - class DiagnosticsEngine; - class GlobalDecl; - class HeaderSearchOptions; - class LangOptions; - class PreprocessorOptions; - class CompilerInstance; +class BaseSubobject; +class CodeGenOptions; +class CoverageSourceInfo; +class Decl; +class DiagnosticsEngine; +class GlobalDecl; +class HeaderSearchOptions; +class LangOptions; +class PreprocessorOptions; +class CompilerInstance; namespace CodeGen { class CodeGenModule; diff --git a/clang/unittests/CodeGen/CodeGenExternalTest.cpp b/clang/unittests/CodeGen/CodeGenExternalTest.cpp index 8ad1ead915328..dcb04f1f3237a 100644 --- a/clang/unittests/CodeGen/CodeGenExternalTest.cpp +++ b/clang/unittests/CodeGen/CodeGenExternalTest.cpp @@ -195,7 +195,7 @@ static void test_codegen_fns(MyASTConsumer *my) { mytest_fn_ok = true; } } - } else if(CXXRecordDecl *rd = dyn_cast<CXXRecordDecl>(decl)) { + } else if (CXXRecordDecl *rd = dyn_cast<CXXRecordDecl>(decl)) { if (rd->getName() == "mytest_struct") { RecordDecl *def = rd->getDefinition(); ASSERT_TRUE(def != NULL); @@ -268,7 +268,7 @@ static void test_codegen_fns(MyASTConsumer *my) { unsigned pointerSizeInBits = dataLayout.getPointerTypeSizeInBits(c->getType()); APInt offset(pointerSizeInBits, 0); - GEPOperator* gepOperator = dyn_cast<GEPOperator>(c); + GEPOperator *gepOperator = dyn_cast<GEPOperator>(c); ASSERT_NE(gepOperator, nullptr); gepOperator->accumulateConstantOffset(dataLayout, offset); // Itanium ABI has a couple of pointersi (offset to top, type info) >From f25541c777950df723f445a7d146cd6197044c61 Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Wed, 10 Jun 2026 20:49:43 +0000 Subject: [PATCH 3/7] Typo --- clang/unittests/CodeGen/CodeGenExternalTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/unittests/CodeGen/CodeGenExternalTest.cpp b/clang/unittests/CodeGen/CodeGenExternalTest.cpp index dcb04f1f3237a..8824451ccc2f4 100644 --- a/clang/unittests/CodeGen/CodeGenExternalTest.cpp +++ b/clang/unittests/CodeGen/CodeGenExternalTest.cpp @@ -271,7 +271,7 @@ static void test_codegen_fns(MyASTConsumer *my) { GEPOperator *gepOperator = dyn_cast<GEPOperator>(c); ASSERT_NE(gepOperator, nullptr); gepOperator->accumulateConstantOffset(dataLayout, offset); - // Itanium ABI has a couple of pointersi (offset to top, type info) + // Itanium ABI has a couple of pointers (offset to top, type info) // before the array of function pointers. ASSERT_EQ(offset, (pointerSizeInBits / 8) * 2); } >From 2ee97ea8153e6f6227f473ba7b043af7d03da685 Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Tue, 16 Jun 2026 22:04:17 +0000 Subject: [PATCH 4/7] make decl parameter const CXXRecordDecl* --- clang/include/clang/CodeGen/ModuleBuilder.h | 2 +- clang/lib/CodeGen/ModuleBuilder.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 21dee80d60d65..16bc7f2928303 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -106,7 +106,7 @@ class CodeGenerator : public ASTConsumer { /// definition has been registered with this code generator. llvm::Constant *GetAddrOfGlobal(GlobalDecl decl, bool isForDefinition); - llvm::Constant *GetAddrOfVTable(BaseSubobject base, CXXRecordDecl *decl); + llvm::Constant *GetAddrOfVTable(BaseSubobject base, const CXXRecordDecl *decl); /// Create a new \c llvm::Module after calling HandleTranslationUnit. This /// enable codegen in interactive processing environments. diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index f91d9222e9232..124783e36c6dc 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -133,7 +133,7 @@ namespace { } llvm::Constant *GetAddrOfVTable(BaseSubobject subobject, - CXXRecordDecl *decl) { + const CXXRecordDecl *decl) { return Builder->getCXXABI().getVTableAddressPoint(subobject, decl); } >From 7fb3d794c46f883341003d11de81e29dc0870817 Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Tue, 16 Jun 2026 22:07:19 +0000 Subject: [PATCH 5/7] Add comment --- clang/include/clang/CodeGen/ModuleBuilder.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 16bc7f2928303..0815c9b9c734b 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -106,6 +106,10 @@ class CodeGenerator : public ASTConsumer { /// definition has been registered with this code generator. llvm::Constant *GetAddrOfGlobal(GlobalDecl decl, bool isForDefinition); + /// Return the LLVM address of the vtable for the given base subobject. + /// + /// \param base The base subobject that owns the vptr to be initialized. + /// \param decl The derived type being initialized, that contains `base`. llvm::Constant *GetAddrOfVTable(BaseSubobject base, const CXXRecordDecl *decl); /// Create a new \c llvm::Module after calling HandleTranslationUnit. This >From 1626ffa256c92b62e7aaab10925701740bb7dec2 Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Tue, 16 Jun 2026 22:07:59 +0000 Subject: [PATCH 6/7] More const --- clang/lib/CodeGen/ModuleBuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 124783e36c6dc..0b00362487d2a 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -385,7 +385,7 @@ llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global, } llvm::Constant *CodeGenerator::GetAddrOfVTable(BaseSubobject base, - CXXRecordDecl *decl) { + const CXXRecordDecl *decl) { return static_cast<CodeGeneratorImpl *>(this)->GetAddrOfVTable(base, decl); } >From 446f407459eda2d4061a303241000b9ca012e89e Mon Sep 17 00:00:00 2001 From: David Blaikie <[email protected]> Date: Wed, 17 Jun 2026 16:16:02 +0000 Subject: [PATCH 7/7] Format --- clang/include/clang/CodeGen/ModuleBuilder.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index 0815c9b9c734b..cd93ef7cc654a 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -110,7 +110,8 @@ class CodeGenerator : public ASTConsumer { /// /// \param base The base subobject that owns the vptr to be initialized. /// \param decl The derived type being initialized, that contains `base`. - llvm::Constant *GetAddrOfVTable(BaseSubobject base, const CXXRecordDecl *decl); + llvm::Constant *GetAddrOfVTable(BaseSubobject base, + const CXXRecordDecl *decl); /// Create a new \c llvm::Module after calling HandleTranslationUnit. This /// enable codegen in interactive processing environments. _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
