mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:50:13 +01:00
For review convenience, the Clang patch is available as an LLVM Draft PR here: https://github.com/llvm/llvm-project/pull/202807
146 lines
6.0 KiB
Diff
146 lines
6.0 KiB
Diff
diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h
|
|
index 5173fd05d75d..a144e904b022 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 @@ public:
|
|
/// 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 dd6b3c904d03..82f5bc336591 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?");
|
|
@@ -377,6 +383,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 be3be147460f..8ad1ead91532 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);
|
|
}
|
|
}
|
|
}
|