[clang] [Clang][CodeGen] Start migrating away from assuming the Default AS is 0 (PR #88182)
Alex Voicu via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 23 16:59:54 PDT 2024
https://github.com/AlexVlx updated https://github.com/llvm/llvm-project/pull/88182
>From 426e74cabb003eb5dc83adf347a5800d49bc87b7 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Mon, 18 Mar 2024 11:49:12 +0000
Subject: [PATCH 1/8] Start migrating away from the embedded assumption that
the default AS **must** be 0.
---
clang/lib/CodeGen/CGExprCXX.cpp | 2 +-
clang/lib/CodeGen/CodeGenModule.cpp | 10 ++++++----
clang/lib/CodeGen/CodeGenTypeCache.h | 2 +-
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 2adbef6d55122c..b9c920a81d79c9 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -2222,7 +2222,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
}
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
- llvm::Type *PtrTy = llvm::PointerType::getUnqual(getLLVMContext());
+ llvm::Type *PtrTy = Int8PtrTy;
LangAS GlobAS = CGM.GetGlobalVarAddressSpace(nullptr);
auto MaybeASCast = [=](auto &&TypeInfo) {
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 8ceecff28cbc63..7dd14d32aa2d03 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -364,7 +364,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
IntPtrTy = llvm::IntegerType::get(LLVMContext,
C.getTargetInfo().getMaxPointerWidth());
- Int8PtrTy = llvm::PointerType::get(LLVMContext, 0);
+ Int8PtrTy = llvm::PointerType::get(
+ LLVMContext, C.getTargetInfo().getTargetAddressSpace(LangAS::Default));
const llvm::DataLayout &DL = M.getDataLayout();
AllocaInt8PtrTy =
llvm::PointerType::get(LLVMContext, DL.getAllocaAddrSpace());
@@ -4512,9 +4513,10 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
IsIncompleteFunction = true;
}
- llvm::Function *F =
- llvm::Function::Create(FTy, llvm::Function::ExternalLinkage,
- Entry ? StringRef() : MangledName, &getModule());
+ llvm::Function *F = llvm::Function::Create(
+ FTy, llvm::Function::ExternalLinkage,
+ getDataLayout().getProgramAddressSpace(),
+ Entry ? StringRef() : MangledName, &getModule());
// Store the declaration associated with this function so it is potentially
// updated by further declarations or definitions and emitted at the end.
diff --git a/clang/lib/CodeGen/CodeGenTypeCache.h b/clang/lib/CodeGen/CodeGenTypeCache.h
index 083d69214fb3c2..e273ebe3b060f2 100644
--- a/clang/lib/CodeGen/CodeGenTypeCache.h
+++ b/clang/lib/CodeGen/CodeGenTypeCache.h
@@ -51,7 +51,7 @@ struct CodeGenTypeCache {
llvm::IntegerType *PtrDiffTy;
};
- /// void*, void** in address space 0
+ /// void*, void** in the target's default address space (often 0)
union {
llvm::PointerType *UnqualPtrTy;
llvm::PointerType *VoidPtrTy;
>From 74ae6f52a5f84f8fc92135df3ff93a4a89b914ed Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Mon, 25 Mar 2024 10:55:22 +0200
Subject: [PATCH 2/8] Make querying the Global AS more robust, add 1 new test
(WiP).
---
clang/lib/CodeGen/CodeGenModule.cpp | 10 ++++---
clang/lib/CodeGen/ItaniumCXXABI.cpp | 4 ++-
...x11-with-nonzero-default-address-space.cpp | 29 +++++++++++++++++++
3 files changed, 38 insertions(+), 5 deletions(-)
create mode 100644 clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 63d54f9b1c0b60..39ccd40bf1adbb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -371,8 +371,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
const llvm::DataLayout &DL = M.getDataLayout();
AllocaInt8PtrTy =
llvm::PointerType::get(LLVMContext, DL.getAllocaAddrSpace());
- GlobalsInt8PtrTy =
- llvm::PointerType::get(LLVMContext, DL.getDefaultGlobalsAddressSpace());
+ GlobalsInt8PtrTy = llvm::PointerType::get(
+ LLVMContext, C.getTargetAddressSpace(GetGlobalVarAddressSpace(nullptr)));
ConstGlobalsPtrTy = llvm::PointerType::get(
LLVMContext, C.getTargetAddressSpace(GetGlobalConstantAddressSpace()));
ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();
@@ -5018,7 +5018,9 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
// Create a new variable.
GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true,
- Linkage, nullptr, Name);
+ Linkage, nullptr, Name, nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ GlobalsInt8PtrTy->getAddressSpace());
if (OldGV) {
// Replace occurrences of the old variable if needed.
@@ -5133,7 +5135,7 @@ LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) {
return LangAS::cuda_device;
}
- if (LangOpts.OpenMP) {
+ if (LangOpts.OpenMP && OpenMPRuntime) {
LangAS AS;
if (OpenMPRuntime->hasAllocateAttributeForGlobalVar(D, AS))
return AS;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index bdd53a192f828a..907798cf60b91f 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3938,7 +3938,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
llvm::GlobalVariable *OldGV = M.getNamedGlobal(Name);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(M, Init->getType(),
- /*isConstant=*/true, Linkage, Init, Name);
+ /*isConstant=*/true, Linkage, Init, Name,
+ nullptr, llvm::GlobalValue::NotThreadLocal,
+ CGM.GlobalsInt8PtrTy->getAddressSpace());
// Export the typeinfo in the same circumstances as the vtable is exported.
auto GVDLLStorageClass = DLLStorageClass;
diff --git a/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..c7a9808ba4eb0f
--- /dev/null
+++ b/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -I%S %s -triple spirv64-unknown-unknown -fsycl -fsycl-is-device -emit-llvm -std=c++11 -o - | FileCheck %s
+#include "typeinfo"
+
+namespace Test1 {
+
+struct Item {
+ const std::type_info &ti;
+ const char *name;
+ void *(*make)();
+};
+
+template<typename T> void *make_impl() { return new T; }
+template<typename T> constexpr Item item(const char *name) {
+ return { typeid(T), name, make_impl<T> };
+}
+
+struct A { virtual ~A(); };
+struct B : virtual A {};
+struct C { int n; };
+
+extern constexpr Item items[] = {
+ item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int")
+};
+
+constexpr auto &x = items[0].ti;
+
+constexpr auto &y = typeid(B{});
+
+}
>From ef0bd832d7fce2bd70cbdcec8de5c41003c93246 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 9 Apr 2024 18:23:41 +0100
Subject: [PATCH 3/8] Fix a few additional places where we emit globals in AS 0
implicitly; add (more) tests.
---
clang/lib/CodeGen/CodeGenModule.cpp | 4 +-
clang/lib/CodeGen/ItaniumCXXABI.cpp | 18 +-
...mic-cast-nonzero-default-address-space.cpp | 24 ++
...-objects-nonzero-default-address-space.cpp | 32 ++
...einfo-in-nonzero-default-address-space.cpp | 17 ++
...tch-with-nonzero-default-address-space.cpp | 25 ++
...x11-with-nonzero-default-address-space.cpp | 5 +-
...eid-with-nonzero-default-address-space.cpp | 50 +++
...nfo-with-nonzero-default-address-space.cpp | 48 +++
...le-align-nonzero-default-address-space.cpp | 13 +
...ume-load-nonzero-default-address-space.cpp | 288 ++++++++++++++++++
...onsteval-nonzero-default-address-space.cpp | 44 +++
...onstexpr-nonzero-default-address-space.cpp | 27 ++
...function-nonzero-default-address-space.cpp | 33 ++
...-extreme-nonzero-default-address-space.cpp | 210 +++++++++++++
...-linkage-nonzero-default-address-space.cpp | 217 +++++++++++++
...lization-nonzero-default-address-space.cpp | 60 ++++
...out-with-nonzero-default-address-space.cpp | 89 ++++++
.../vtt-nonzero-default-address-space.cpp | 27 ++
19 files changed, 1226 insertions(+), 5 deletions(-)
create mode 100644 clang/test/CodeGenCXX/dynamic-cast-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/template-param-objects-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/throw-expression-typeinfo-in-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/try-catch-with-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/typeid-with-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/typeinfo-with-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-align-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-assume-load-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-consteval-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-constexpr-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-key-function-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-layout-extreme-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-linkage-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-pointer-initialization-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtt-layout-with-nonzero-default-address-space.cpp
create mode 100644 clang/test/CodeGenCXX/vtt-nonzero-default-address-space.cpp
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 4a3e4b45ca8383..01763308e6c17c 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3583,7 +3583,9 @@ ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject(
? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage;
auto *GV = new llvm::GlobalVariable(getModule(), Init->getType(),
- /*isConstant=*/true, Linkage, Init, Name);
+ /*isConstant=*/true, Linkage, Init, Name,
+ nullptr, llvm::GlobalValue::NotThreadLocal,
+ GlobalsInt8PtrTy->getAddressSpace());
setGVProperties(GV, TPO);
if (supportsCOMDAT())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 7589b85c9930b1..942ab4c3a43d05 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3279,7 +3279,9 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
GV = new llvm::GlobalVariable(
CGM.getModule(), CGM.GlobalsInt8PtrTy,
- /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr, Name);
+ /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr, Name,
+ nullptr, llvm::GlobalValue::NotThreadLocal,
+ CGM.GlobalsInt8PtrTy->getAddressSpace());
const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
CGM.setGVProperties(GV, RD);
// Import the typeinfo symbol when all non-inline virtual methods are
@@ -3673,8 +3675,18 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
if (CGM.getItaniumVTableContext().isRelativeLayout())
VTable = CGM.getModule().getNamedAlias(VTableName);
if (!VTable) {
- llvm::Type *Ty = llvm::ArrayType::get(CGM.GlobalsInt8PtrTy, 0);
- VTable = CGM.getModule().getOrInsertGlobal(VTableName, Ty);
+ VTable = CGM.GetGlobalValue(VTableName);
+ if (!VTable) {
+ llvm::Type *Ty = llvm::ArrayType::get(CGM.GlobalsInt8PtrTy, 0);
+ // FIXME: External StdLib VTables should be constant as well, but changing
+ // it *might* constitute a very subtle ABI break.
+ VTable = new llvm::GlobalVariable(CGM.getModule(), Ty,
+ /*isConstant=*/false,
+ llvm::GlobalVariable::ExternalLinkage,
+ nullptr, VTableName, nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ CGM.GlobalsInt8PtrTy->getAddressSpace());
+ }
}
CGM.setDSOLocal(cast<llvm::GlobalValue>(VTable->stripPointerCasts()));
diff --git a/clang/test/CodeGenCXX/dynamic-cast-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/dynamic-cast-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..9a9fbdbd14582d
--- /dev/null
+++ b/clang/test/CodeGenCXX/dynamic-cast-nonzero-default-address-space.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -I%S %s -triple spirv64-unknown-unknown -fsycl-is-device -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s
+struct A { virtual void f(); };
+struct B : A { };
+
+// CHECK: {{define.*@_Z1fP1A}}
+// CHECK-SAME: personality ptr @__gxx_personality_v0
+B fail;
+const B& f(A *a) {
+ try {
+ // CHECK: call {{.*}} ptr addrspace(4) @__dynamic_cast
+ // CHECK: br i1
+ // CHECK: invoke {{.*}} void @__cxa_bad_cast() [[NR:#[0-9]+]]
+ dynamic_cast<const B&>(*a);
+ } catch (...) {
+ // CHECK: landingpad { ptr addrspace(4), i32 }
+ // CHECK-NEXT: catch ptr addrspace(4) null
+ }
+ return fail;
+}
+
+// CHECK: declare {{.*}} ptr addrspace(4) @__dynamic_cast(ptr addrspace(4), ptr addrspace(1), ptr addrspace(1), i64) [[NUW_RO:#[0-9]+]]
+
+// CHECK: attributes [[NUW_RO]] = { nounwind willreturn memory(read) }
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/clang/test/CodeGenCXX/template-param-objects-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/template-param-objects-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..9fc95acaebc7bf
--- /dev/null
+++ b/clang/test/CodeGenCXX/template-param-objects-nonzero-default-address-space.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple spirv64-unknown-unknown -fsycl-is-device -std=c++20 %s -emit-llvm -o - | FileCheck %s
+
+struct S { char buf[32]; };
+template<S s> constexpr const char *begin() { return s.buf; }
+template<S s> constexpr const char *end() { return s.buf + __builtin_strlen(s.buf); }
+template<S s> constexpr const void *retval() { return &s; }
+extern const void *callee(const S*);
+template<S s> constexpr const void* observable_addr() { return callee(&s); }
+
+// CHECK: [[HELLO:@_ZTAXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEE]]
+// CHECK-SAME: = linkonce_odr addrspace(1) constant { <{ [11 x i8], [21 x i8] }> } { <{ [11 x i8], [21 x i8] }> <{ [11 x i8] c"hello world", [21 x i8] zeroinitializer }> }, comdat
+
+// CHECK: @p
+// CHECK-SAME: addrspace(1) global ptr addrspace(4) addrspacecast (ptr addrspace(1) [[HELLO]] to ptr addrspace(4))
+const char *p = begin<S{"hello world"}>();
+
+// CHECK: @q
+// CHECK-SAME: addrspace(1) global ptr addrspace(4) addrspacecast (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) [[HELLO]], i64 11) to ptr addrspace(4))
+const char *q = end<S{"hello world"}>();
+
+const void *(*r)() = &retval<S{"hello world"}>;
+
+// CHECK: @s
+// CHECK-SAME: addrspace(1) global ptr addrspace(4) null
+const void *s = observable_addr<S{"hello world"}>();
+
+// CHECK: define linkonce_odr {{.*}} noundef ptr addrspace(4) @_Z6retvalIXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEEEPKvv()
+// CHECK: ret ptr addrspace(4) addrspacecast (ptr addrspace(1) [[HELLO]] to ptr addrspace(4))
+
+// CHECK: define linkonce_odr {{.*}} noundef ptr addrspace(4) @_Z15observable_addrIXtl1StlA32_cLc104ELc101ELc108ELc108ELc111ELc32ELc119ELc111ELc114ELc108ELc100EEEEEPKvv()
+// CHECK: %call = call {{.*}} noundef ptr addrspace(4) @_Z6calleePK1S(ptr addrspace(4) noundef addrspacecast (ptr addrspace(1) [[HELLO]] to ptr addrspace(4)))
+// CHECK: declare {{.*}} noundef ptr addrspace(4) @_Z6calleePK1S(ptr addrspace(4) noundef)
diff --git a/clang/test/CodeGenCXX/throw-expression-typeinfo-in-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/throw-expression-typeinfo-in-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..b7fcde23efe6dd
--- /dev/null
+++ b/clang/test/CodeGenCXX/throw-expression-typeinfo-in-nonzero-default-address-space.cpp
@@ -0,0 +1,17 @@
+// RUN: %clang_cc1 %s -triple spirv64-unknown-unknown -fsycl-is-device -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - | FileCheck %s
+
+struct X {
+ ~X();
+};
+
+struct Error {
+ Error(const X&) noexcept;
+};
+
+void f() {
+ try {
+ throw Error(X());
+ } catch (...) { }
+}
+
+// CHECK: declare{{.*}} void @__cxa_throw(ptr addrspace(4), ptr addrspace(1), ptr addrspace(4))
diff --git a/clang/test/CodeGenCXX/try-catch-with-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/try-catch-with-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..62143ef580835b
--- /dev/null
+++ b/clang/test/CodeGenCXX/try-catch-with-nonzero-default-address-space.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+
+struct X { };
+
+const X g();
+
+void f() {
+ try {
+ throw g();
+ // CHECK: ptr addrspace(1) @_ZTI1X
+ } catch (const X x) {
+ // CHECK: catch ptr addrspace(1) @_ZTI1X
+ // CHECK: call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(1) @_ZTI1X to ptr))
+ }
+}
+
+void h() {
+ try {
+ throw "ABC";
+ // CHECK: ptr addrspace(1) @_ZTIPKc
+ } catch (char const(&)[4]) {
+ // CHECK: catch ptr addrspace(1) @_ZTIA4_c
+ // CHECK: call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(1) @_ZTIA4_c to ptr))
+ }
+}
diff --git a/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp
index c7a9808ba4eb0f..cc6bc7f53b70af 100644
--- a/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp
+++ b/clang/test/CodeGenCXX/typeid-cxx11-with-nonzero-default-address-space.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -I%S %s -triple spirv64-unknown-unknown -fsycl -fsycl-is-device -emit-llvm -std=c++11 -o - | FileCheck %s
+// RUN: %clang_cc1 -I%S %s -triple spirv64-unknown-unknown -fsycl-is-device -emit-llvm -std=c++11 -o - | FileCheck %s
#include "typeinfo"
namespace Test1 {
@@ -18,12 +18,15 @@ struct A { virtual ~A(); };
struct B : virtual A {};
struct C { int n; };
+// CHECK: @_ZN5Test15itemsE ={{.*}} addrspace(1) constant [4 x {{.*}}] [{{.*}} ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIN5Test11AE to ptr addrspace(4)), {{.*}} @_ZN5Test19make_implINS_1AEEEPvv {{.*}} ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIN5Test11BE to ptr addrspace(4)), {{.*}} @_ZN5Test19make_implINS_1BEEEPvv {{.*}} ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIN5Test11CE to ptr addrspace(4)), {{.*}} @_ZN5Test19make_implINS_1CEEEPvv {{.*}} ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIi to ptr addrspace(4)), {{.*}} @_ZN5Test19make_implIiEEPvv }]
extern constexpr Item items[] = {
item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int")
};
+// CHECK: @_ZN5Test11xE ={{.*}} addrspace(1) constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIN5Test11AE to ptr addrspace(4)), align 8
constexpr auto &x = items[0].ti;
+// CHECK: @_ZN5Test11yE ={{.*}} addrspace(1) constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIN5Test11BE to ptr addrspace(4)), align 8
constexpr auto &y = typeid(B{});
}
diff --git a/clang/test/CodeGenCXX/typeid-with-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/typeid-with-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..3a5a5515c46b4e
--- /dev/null
+++ b/clang/test/CodeGenCXX/typeid-with-nonzero-default-address-space.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -I%S %s -triple spirv64-unknown-unknown -fsycl-is-device -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s
+#include <typeinfo>
+
+namespace Test1 {
+
+// PR7400
+struct A { virtual void f(); };
+
+// CHECK: @_ZN5Test16int_tiE ={{.*}} constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIi to ptr addrspace(4)), align 8
+const std::type_info &int_ti = typeid(int);
+
+// CHECK: @_ZN5Test14A_tiE ={{.*}} constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIN5Test11AE to ptr addrspace(4)), align 8
+const std::type_info &A_ti = typeid(const volatile A &);
+
+volatile char c;
+
+// CHECK: @_ZN5Test14c_tiE ={{.*}} constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIc to ptr addrspace(4)), align 8
+const std::type_info &c_ti = typeid(c);
+
+extern const double &d;
+
+// CHECK: @_ZN5Test14d_tiE ={{.*}} constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTId to ptr addrspace(4)), align 8
+const std::type_info &d_ti = typeid(d);
+
+extern A &a;
+
+// CHECK: @_ZN5Test14a_tiE ={{.*}} global
+const std::type_info &a_ti = typeid(a);
+
+// CHECK: @_ZN5Test18A10_c_tiE ={{.*}} constant ptr addrspace(4) addrspacecast (ptr addrspace(1) @_ZTIA10_c to ptr addrspace(4)), align 8
+const std::type_info &A10_c_ti = typeid(char const[10]);
+
+// CHECK-LABEL: define{{.*}} ptr addrspace(4) @_ZN5Test11fEv
+// CHECK-SAME: personality ptr @__gxx_personality_v0
+const char *f() {
+ try {
+ // CHECK: br i1
+ // CHECK: invoke{{.*}} void @__cxa_bad_typeid() [[NR:#[0-9]+]]
+ return typeid(*static_cast<A *>(0)).name();
+ } catch (...) {
+ // CHECK: landingpad { ptr addrspace(4), i32 }
+ // CHECK-NEXT: catch ptr addrspace(4) null
+ }
+
+ return 0;
+}
+
+}
+
+// CHECK: attributes [[NR]] = { noreturn }
diff --git a/clang/test/CodeGenCXX/typeinfo-with-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/typeinfo-with-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..7eab1ba86b9dfe
--- /dev/null
+++ b/clang/test/CodeGenCXX/typeinfo-with-nonzero-default-address-space.cpp
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -I%S %s -triple spirv64-unknown-unknown -fsycl-is-device -emit-llvm -o - | FileCheck %s -check-prefix=AS
+// RUN: %clang_cc1 -I%S %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s -check-prefix=NO-AS
+#include <typeinfo>
+
+class A {
+ virtual void f() = 0;
+};
+
+class B : A {
+ void f() override;
+};
+
+// AS: @_ZTISt9type_info = external addrspace(1) constant ptr addrspace(1)
+// NO-AS: @_ZTISt9type_info = external constant ptr
+// AS: @_ZTIi = external addrspace(1) constant ptr addrspace(1)
+// NO-AS: @_ZTIi = external constant ptr
+// AS: @_ZTVN10__cxxabiv117__class_type_infoE = external addrspace(1) global [0 x ptr addrspace(1)]
+// NO-AS: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
+// AS: @_ZTS1A = linkonce_odr addrspace(1) constant [3 x i8] c"1A\00", comdat, align 1
+// NO-AS: @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", comdat, align 1
+// AS: @_ZTI1A = linkonce_odr addrspace(1) constant { ptr addrspace(1), ptr addrspace(1) } { ptr addrspace(1) getelementptr inbounds (ptr addrspace(1), ptr addrspace(1) @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr addrspace(1) @_ZTS1A }, comdat, align 8
+// NO-AS: @_ZTI1A = linkonce_odr constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS1A }, comdat, align 8
+// AS: @_ZTIf = external addrspace(1) constant ptr addrspace(1)
+// NO-AS: @_ZTIf = external constant ptr
+
+unsigned long Fn(B& b) {
+// AS: %call = call{{.*}} noundef zeroext i1 @_ZNKSt9type_infoeqERKS_(ptr addrspace(4) {{.*}} addrspacecast (ptr addrspace(1) @_ZTISt9type_info to ptr addrspace(4)), ptr addrspace(4) {{.*}} %2)
+// NO-AS: %call = call noundef zeroext i1 @_ZNKSt9type_infoeqERKS_(ptr {{.*}} @_ZTISt9type_info, ptr {{.*}} %2)
+ if (typeid(std::type_info) == typeid(b))
+ return 42;
+// AS: %call2 = call{{.*}} noundef zeroext i1 @_ZNKSt9type_infoneERKS_(ptr addrspace(4) {{.*}} addrspacecast (ptr addrspace(1) @_ZTIi to ptr addrspace(4)), ptr addrspace(4) {{.*}} %5)
+// NO-AS: %call2 = call noundef zeroext i1 @_ZNKSt9type_infoneERKS_(ptr {{.*}} @_ZTIi, ptr {{.*}} %5)
+ if (typeid(int) != typeid(b))
+ return 1712;
+// AS: %call5 = call{{.*}} noundef ptr addrspace(4) @_ZNKSt9type_info4nameEv(ptr addrspace(4) {{.*}} addrspacecast (ptr addrspace(1) @_ZTI1A to ptr addrspace(4)))
+// NO-AS: %call5 = call noundef ptr @_ZNKSt9type_info4nameEv(ptr {{.*}} @_ZTI1A)
+// AS: %call7 = call{{.*}} noundef ptr addrspace(4) @_ZNKSt9type_info4nameEv(ptr addrspace(4) {{.*}} %8)
+// NO-AS: %call7 = call noundef ptr @_ZNKSt9type_info4nameEv(ptr {{.*}} %8)
+ if (typeid(A).name() == typeid(b).name())
+ return 0;
+// AS: %call11 = call{{.*}} noundef zeroext i1 @_ZNKSt9type_info6beforeERKS_(ptr addrspace(4) {{.*}} %11, ptr addrspace(4) {{.*}} addrspacecast (ptr addrspace(1) @_ZTIf to ptr addrspace(4)))
+// NO-AS: %call11 = call noundef zeroext i1 @_ZNKSt9type_info6beforeERKS_(ptr {{.*}} %11, ptr {{.*}} @_ZTIf)
+ if (typeid(b).before(typeid(float)))
+ return 1;
+// AS: %call15 = call{{.*}} noundef i64 @_ZNKSt9type_info9hash_codeEv(ptr addrspace(4) {{.*}} %14)
+// NO-AS: %call15 = call noundef i64 @_ZNKSt9type_info9hash_codeEv(ptr {{.*}} %14)
+ return typeid(b).hash_code();
+}
diff --git a/clang/test/CodeGenCXX/vtable-align-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-align-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..2a1a7293982f18
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-align-nonzero-default-address-space.cpp
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -std=c++11 -emit-llvm -o - | FileCheck %s
+
+struct A {
+ virtual void f();
+ virtual void g();
+ virtual void h();
+};
+
+void A::f() {}
+
+// CHECK: @_ZTV1A ={{.*}} unnamed_addr addrspace(1) constant { [5 x ptr addrspace(1)] } { [5 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @_ZTI1A, ptr addrspace(1) addrspacecast (ptr @_ZN1A1fEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1A1gEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1A1hEv to ptr addrspace(1))]
+// CHECK: @_ZTS1A ={{.*}} constant [3 x i8] c"1A\00", align 1
+// CHECK: @_ZTI1A ={{.*}} addrspace(1) constant { ptr addrspace(1), ptr addrspace(1) } { ptr addrspace(1) getelementptr inbounds (ptr addrspace(1), ptr addrspace(1) @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr addrspace(1) @_ZTS1A }, align 8
diff --git a/clang/test/CodeGenCXX/vtable-assume-load-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-assume-load-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..63e7bb8b570a65
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-assume-load-nonzero-default-address-space.cpp
@@ -0,0 +1,288 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -std=c++11 -emit-llvm -o %t.ll -O1 -disable-llvm-passes -fms-extensions -fstrict-vtable-pointers
+// FIXME: Assume load should not require -fstrict-vtable-pointers
+
+// RUN: FileCheck --check-prefix=CHECK1 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK2 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK3 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK4 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK5 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK6 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK7 --input-file=%t.ll %s
+// RUN: FileCheck --check-prefix=CHECK8 --input-file=%t.ll %s
+namespace test1 {
+
+struct A {
+ A();
+ virtual void foo();
+};
+
+struct B : A {
+ virtual void foo();
+};
+
+void g(A *a) { a->foo(); }
+
+// CHECK1-LABEL: define{{.*}} void @_ZN5test14fooAEv()
+// CHECK1: call{{.*}} void @_ZN5test11AC1Ev(ptr addrspace(4)
+// CHECK1: %[[VTABLE:.*]] = load ptr addrspace(1), ptr addrspace(4) %{{.*}}
+// CHECK1: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test11AE, i32 0, i32 0, i32 2)
+// CHECK1: call void @llvm.assume(i1 %[[CMP]])
+// CHECK1-LABEL: {{^}}}
+
+void fooA() {
+ A a;
+ g(&a);
+}
+
+// CHECK1-LABEL: define{{.*}} void @_ZN5test14fooBEv()
+// CHECK1: call{{.*}} void @_ZN5test11BC1Ev(ptr addrspace(4) {{[^,]*}} %{{.*}})
+// CHECK1: %[[VTABLE:.*]] = load ptr addrspace(1), ptr addrspace(4) %{{.*}}
+// CHECK1: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test11BE, i32 0, i32 0, i32 2)
+// CHECK1: call void @llvm.assume(i1 %[[CMP]])
+// CHECK1-LABEL: {{^}}}
+
+void fooB() {
+ B b;
+ g(&b);
+}
+// there should not be any assumes in the ctor that calls base ctor
+// CHECK1-LABEL: define linkonce_odr{{.*}} void @_ZN5test11BC2Ev(ptr addrspace(4)
+// CHECK1-NOT: @llvm.assume(
+// CHECK1-LABEL: {{^}}}
+}
+namespace test2 {
+struct A {
+ A();
+ virtual void foo();
+};
+
+struct B {
+ B();
+ virtual void bar();
+};
+
+struct C : A, B {
+ C();
+ virtual void foo();
+};
+void g(A *a) { a->foo(); }
+void h(B *b) { b->bar(); }
+
+// CHECK2-LABEL: define{{.*}} void @_ZN5test24testEv()
+// CHECK2: call{{.*}} void @_ZN5test21CC1Ev(ptr
+// CHECK2: %[[VTABLE:.*]] = load ptr addrspace(1), ptr addrspace(4) {{.*}}
+// CHECK2: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test21CE, i32 0, i32 0, i32 2)
+// CHECK2: call void @llvm.assume(i1 %[[CMP]])
+
+// CHECK2: %[[ADD_PTR:.*]] = getelementptr inbounds i8, ptr addrspace(4) %{{.*}}, i64 8
+// CHECK2: %[[VTABLE2:.*]] = load ptr addrspace(1), ptr addrspace(4) %[[ADD_PTR]]
+// CHECK2: %[[CMP2:.*]] = icmp eq ptr addrspace(1) %[[VTABLE2]], getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test21CE, i32 0, i32 1, i32 2)
+// CHECK2: call void @llvm.assume(i1 %[[CMP2]])
+
+// CHECK2: call{{.*}} void @_ZN5test21gEPNS_1AE(ptr addrspace(4)
+// CHECK2-LABEL: {{^}}}
+
+void test() {
+ C c;
+ g(&c);
+ h(&c);
+}
+}
+
+namespace test3 {
+struct A {
+ A();
+};
+
+struct B : A {
+ B();
+ virtual void foo();
+};
+
+struct C : virtual A, B {
+ C();
+ virtual void foo();
+};
+void g(B *a) { a->foo(); }
+
+// CHECK3-LABEL: define{{.*}} void @_ZN5test34testEv()
+// CHECK3: call{{.*}} void @_ZN5test31CC1Ev(ptr addrspace(4)
+// CHECK3: %[[CMP:.*]] = icmp eq ptr addrspace(1) %{{.*}}, getelementptr inbounds inrange(-24, 8) ({ [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test31CE, i32 0, i32 0, i32 3)
+// CHECK3: call void @llvm.assume(i1 %[[CMP]])
+// CHECK3-LABLEL: }
+void test() {
+ C c;
+ g(&c);
+}
+} // test3
+
+namespace test4 {
+struct A {
+ A();
+ virtual void foo();
+};
+
+struct B : virtual A {
+ B();
+ virtual void foo();
+};
+struct C : B {
+ C();
+ virtual void foo();
+};
+
+void g(C *c) { c->foo(); }
+
+// CHECK4-LABEL: define{{.*}} void @_ZN5test44testEv()
+// CHECK4: call{{.*}} void @_ZN5test41CC1Ev(ptr addrspace(4)
+// CHECK4: %[[VTABLE:.*]] = load ptr addrspace(1), ptr addrspace(4) %{{.*}}
+// CHECK4: %[[CMP:.*]] = icmp eq ptr addrspace(1) %[[VTABLE]], getelementptr inbounds inrange(-32, 8) ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test41CE, i32 0, i32 0, i32 4)
+// CHECK4: call void @llvm.assume(i1 %[[CMP]]
+
+// CHECK4: %[[VTABLE2:.*]] = load ptr addrspace(1), ptr addrspace(4) %{{.*}}
+// CHECK4: %[[CMP2:.*]] = icmp eq ptr addrspace(1) %[[VTABLE2]], getelementptr inbounds inrange(-32, 8) ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5test41CE, i32 0, i32 0, i32 4)
+// CHECK4: call void @llvm.assume(i1 %[[CMP2]])
+// CHECK4-LABEL: {{^}}}
+
+void test() {
+ C c;
+ g(&c);
+}
+} // test4
+
+namespace test6 {
+struct A {
+ A();
+ virtual void foo();
+ virtual ~A() {}
+};
+struct B : A {
+ B();
+};
+// FIXME: Because A's vtable is external, and no virtual functions are hidden,
+// it's safe to generate assumption loads.
+// CHECK5-LABEL: define{{.*}} void @_ZN5test61gEv()
+// CHECK5: call{{.*}} void @_ZN5test61AC1Ev(ptr addrspace(4)
+// CHECK5-NOT: call void @llvm.assume(
+
+// We can't emit assumption loads for B, because if we would refer to vtable
+// it would refer to functions that will not be able to find (like implicit
+// inline destructor).
+
+// CHECK5-LABEL: call{{.*}} void @_ZN5test61BC1Ev(ptr addrspace(4)
+// CHECK5-NOT: call void @llvm.assume(
+// CHECK5-LABEL: {{^}}}
+void g() {
+ A *a = new A;
+ B *b = new B;
+}
+}
+
+namespace test7 {
+// Because A's key function is defined here, vtable is generated in this TU
+// CHECK6: @_ZTVN5test71AE ={{.*}} unnamed_addr addrspace(1) constant
+struct A {
+ A();
+ virtual void foo();
+ virtual void bar();
+};
+void A::foo() {}
+
+// CHECK6-LABEL: define{{.*}} void @_ZN5test71gEv()
+// CHECK6: call{{.*}} void @_ZN5test71AC1Ev(ptr addrspace(4)
+// CHECK6: call void @llvm.assume(
+// CHECK6-LABEL: {{^}}}
+void g() {
+ A *a = new A();
+ a->bar();
+}
+}
+
+namespace test8 {
+
+struct A {
+ virtual void foo();
+ virtual void bar();
+};
+
+// CHECK7-DAG: @_ZTVN5test81BE = available_externally unnamed_addr addrspace(1) constant
+struct B : A {
+ B();
+ void foo();
+ void bar();
+};
+
+// CHECK7-DAG: @_ZTVN5test81CE = linkonce_odr unnamed_addr addrspace(1) constant
+struct C : A {
+ C();
+ void bar();
+ void foo() {}
+};
+inline void C::bar() {}
+
+struct D : A {
+ D();
+ void foo();
+ void inline bar();
+};
+void D::bar() {}
+
+// CHECK7-DAG: @_ZTVN5test81EE = linkonce_odr unnamed_addr addrspace(1) constant
+struct E : A {
+ E();
+};
+
+// CHECK7-LABEL: define{{.*}} void @_ZN5test81bEv()
+// CHECK7: call void @llvm.assume(
+// CHECK7-LABEL: {{^}}}
+void b() {
+ B b;
+ b.bar();
+}
+
+// FIXME: C has inline virtual functions which prohibits as from generating
+// assumption loads, but because vtable is generated in this TU (key function
+// defined here) it would be correct to refer to it.
+// CHECK7-LABEL: define{{.*}} void @_ZN5test81cEv()
+// CHECK7-NOT: call void @llvm.assume(
+// CHECK7-LABEL: {{^}}}
+void c() {
+ C c;
+ c.bar();
+}
+
+// FIXME: We could generate assumption loads here.
+// CHECK7-LABEL: define{{.*}} void @_ZN5test81dEv()
+// CHECK7-NOT: call void @llvm.assume(
+// CHECK7-LABEL: {{^}}}
+void d() {
+ D d;
+ d.bar();
+}
+
+// CHECK7-LABEL: define{{.*}} void @_ZN5test81eEv()
+// CHECK7: call void @llvm.assume(
+// CHECK7-LABEL: {{^}}}
+void e() {
+ E e;
+ e.bar();
+}
+}
+
+namespace test9 {
+
+struct S {
+ S();
+ __attribute__((visibility("hidden"))) virtual void doStuff();
+};
+
+// CHECK8-LABEL: define{{.*}} void @_ZN5test94testEv()
+// CHECK8-NOT: @llvm.assume(
+// CHECK8: }
+void test() {
+ S *s = new S();
+ s->doStuff();
+ delete s;
+}
+}
+
diff --git a/clang/test/CodeGenCXX/vtable-consteval-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-consteval-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..4e3850264d42fc
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-consteval-nonzero-default-address-space.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++20 -triple=spirv64-unknown-unknown -fsycl-is-device %s -emit-llvm -o - | FileCheck %s --check-prefix=ITANIUM --implicit-check-not=DoNotEmit
+
+// FIXME: The MSVC ABI rule in use here was discussed with MS folks prior to
+// them implementing virtual consteval functions, but we do not know for sure
+// if this is the ABI rule they will use.
+
+// ITANIUM-DAG: @_ZTV1A = {{.*}} addrspace(1) constant { [2 x ptr addrspace(1)] } {{.*}} null, {{.*}} @_ZTI1A
+struct A {
+ virtual consteval void DoNotEmit_f() {}
+};
+// ITANIUM-DAG: @a = addrspace(1) global { {{.*}} ptr addrspace(1) @_ZTV1A,
+A a;
+
+// ITANIUM-DAG: @_ZTV1B = {{.*}} addrspace(1) constant { [4 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1B, ptr addrspace(1) addrspacecast (ptr @_ZN1B1fEv to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1B1hEv to ptr addrspace(1))
+struct B {
+ virtual void f() {}
+ virtual consteval void DoNotEmit_g() {}
+ virtual void h() {}
+};
+// ITANIUM-DAG: @b = addrspace(1) global { {{.*}} @_ZTV1B,
+B b;
+
+// ITANIUM-DAG: @_ZTV1C = {{.*}} addrspace(1) constant { [4 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1C, ptr addrspace(1) addrspacecast (ptr @_ZN1CD1Ev to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1CD0Ev to ptr addrspace(1))
+struct C {
+ virtual ~C() = default;
+ virtual consteval C &operator=(const C&) = default;
+};
+// ITANIUM-DAG: @c = addrspace(1) global { {{.*}} @_ZTV1C,
+C c;
+
+// ITANIUM-DAG: @_ZTV1D = {{.*}} addrspace(1) constant { [4 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1D, ptr addrspace(1) addrspacecast (ptr @_ZN1DD1Ev to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN1DD0Ev to ptr addrspace(1))
+struct D : C {};
+// ITANIUM-DAG: @d = addrspace(1) global { ptr addrspace(1) } { {{.*}} @_ZTV1D,
+D d;
+
+// ITANIUM-DAG: @_ZTV1E = {{.*}} addrspace(1) constant { [3 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1E, ptr addrspace(1) addrspacecast (ptr @_ZN1E1fEv to ptr addrspace(1))
+struct E { virtual void f() {} };
+// ITANIUM-DAG: @e = addrspace(1) global { {{.*}} @_ZTV1E,
+E e;
+
+// ITANIUM-DAG: @_ZTV1F = {{.*}} addrspace(1) constant { [3 x ptr addrspace(1)] } {{.*}} addrspace(1) null, ptr addrspace(1) @_ZTI1F, ptr addrspace(1) addrspacecast (ptr @_ZN1E1fEv to ptr addrspace(1))
+struct F : E { virtual consteval void DoNotEmit_g(); };
+// ITANIUM-DAG: @f = addrspace(1) global { ptr addrspace(1) } { {{.*}} @_ZTV1F,
+F f;
diff --git a/clang/test/CodeGenCXX/vtable-constexpr-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-constexpr-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..ea53d7208fc39f
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-constexpr-nonzero-default-address-space.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -std=c++20 -triple=spirv64-unknown-unknown -fsycl-is-device %s -emit-llvm -o - | FileCheck %s --implicit-check-not=DoNotEmit
+
+// constexpr virtual functions can be called at runtime and go in the vtable as
+// normal. But they are implicitly inline so are never the key function.
+
+struct DoNotEmit {
+ virtual constexpr void f();
+};
+constexpr void DoNotEmit::f() {}
+
+// CHECK-DAG: @_ZTV1B = {{.*}} addrspace(1) constant { [3 x ptr addrspace(1)] } { {{.*}} null, {{.*}} @_ZTI1B, {{.*}} @_ZN1B1fEv
+struct B {
+ // CHECK-DAG: define {{.*}} @_ZN1B1fEv
+ virtual constexpr void f() {}
+};
+B b;
+
+struct CBase {
+ virtual constexpr void f(); // not key function
+};
+
+// CHECK-DAG: @_ZTV1C = {{.*}} addrspace(1) constant {{.*}} null, {{.*}} @_ZTI1C, {{.*}} @_ZN1C1fEv
+struct C : CBase {
+ void f(); // key function
+};
+// CHECK-DAG: define {{.*}} @_ZN1C1fEv
+void C::f() {}
diff --git a/clang/test/CodeGenCXX/vtable-key-function-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-key-function-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..3805afe61b8a21
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-key-function-nonzero-default-address-space.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -emit-llvm -o - | FileCheck %s
+// PR5697
+namespace PR5697 {
+struct A {
+ virtual void f() { }
+ A();
+ A(int);
+};
+
+// A does not have a key function, so the first constructor we emit should
+// cause the vtable to be defined (without assertions.)
+// CHECK: @_ZTVN6PR56971AE = linkonce_odr unnamed_addr addrspace(1) constant
+A::A() { }
+A::A(int) { }
+}
+
+// Make sure that we don't assert when building the vtable for a class
+// template specialization or explicit instantiation with a key
+// function.
+template<typename T>
+struct Base {
+ virtual ~Base();
+};
+
+template<typename T>
+struct Derived : public Base<T> { };
+
+template<>
+struct Derived<char> : public Base<char> {
+ virtual void anchor();
+};
+
+void Derived<char>::anchor() { }
diff --git a/clang/test/CodeGenCXX/vtable-layout-extreme-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-layout-extreme-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..d639bfcf4d82ac
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-layout-extreme-nonzero-default-address-space.cpp
@@ -0,0 +1,210 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -std=c++11 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s
+
+// A collection of big class hierarchies and their vtables.
+
+namespace Test1 {
+
+class C0
+{
+};
+class C1
+ : virtual public C0
+{
+ int k0;
+};
+class C2
+ : public C0
+ , virtual public C1
+{
+ int k0;
+};
+class C3
+ : virtual public C0
+ , virtual public C1
+ , public C2
+{
+ int k0;
+ int k1;
+ int k2;
+ int k3;
+};
+class C4
+ : public C2
+ , virtual public C3
+ , public C0
+{
+ int k0;
+};
+class C5
+ : public C0
+ , virtual public C4
+ , public C2
+ , public C1
+ , virtual public C3
+{
+ int k0;
+};
+class C6
+ : virtual public C3
+ , public C0
+ , public C5
+ , public C4
+ , public C1
+{
+ int k0;
+};
+class C7
+ : virtual public C5
+ , virtual public C6
+ , virtual public C3
+ , public C4
+ , virtual public C2
+{
+ int k0;
+ int k1;
+};
+class C8
+ : public C7
+ , public C5
+ , public C3
+ , virtual public C4
+ , public C1
+ , public C2
+{
+ int k0;
+ int k1;
+};
+
+// CHECK: Vtable for 'Test1::C9' (87 entries).
+// CHECK-NEXT: 0 | vbase_offset (344)
+// CHECK-NEXT: 1 | vbase_offset (312)
+// CHECK-NEXT: 2 | vbase_offset (184)
+// CHECK-NEXT: 3 | vbase_offset (168)
+// CHECK-NEXT: 4 | vbase_offset (120)
+// CHECK-NEXT: 5 | vbase_offset (48)
+// CHECK-NEXT: 6 | vbase_offset (148)
+// CHECK-NEXT: 7 | vbase_offset (152)
+// CHECK-NEXT: 8 | offset_to_top (0)
+// CHECK-NEXT: 9 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 0) vtable address --
+// CHECK-NEXT: -- (Test1::C9, 0) vtable address --
+// CHECK-NEXT: 10 | void Test1::C9::f()
+// CHECK-NEXT: 11 | vbase_offset (104)
+// CHECK-NEXT: 12 | vbase_offset (132)
+// CHECK-NEXT: 13 | vbase_offset (136)
+// CHECK-NEXT: 14 | offset_to_top (-16)
+// CHECK-NEXT: 15 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 16) vtable address --
+// CHECK-NEXT: -- (Test1::C4, 16) vtable address --
+// CHECK-NEXT: 16 | vbase_offset (72)
+// CHECK-NEXT: 17 | vbase_offset (120)
+// CHECK-NEXT: 18 | vbase_offset (100)
+// CHECK-NEXT: 19 | vbase_offset (104)
+// CHECK-NEXT: 20 | offset_to_top (-48)
+// CHECK-NEXT: 21 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 48) vtable address --
+// CHECK-NEXT: -- (Test1::C5, 48) vtable address --
+// CHECK-NEXT: -- (Test1::C6, 48) vtable address --
+// CHECK-NEXT: 22 | vbase_offset (84)
+// CHECK-NEXT: 23 | offset_to_top (-64)
+// CHECK-NEXT: 24 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C1, 64) vtable address --
+// CHECK-NEXT: 25 | vbase_offset (32)
+// CHECK-NEXT: 26 | vbase_offset (60)
+// CHECK-NEXT: 27 | vbase_offset (64)
+// CHECK-NEXT: 28 | offset_to_top (-88)
+// CHECK-NEXT: 29 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 88) vtable address --
+// CHECK-NEXT: -- (Test1::C4, 88) vtable address --
+// CHECK-NEXT: 30 | vbase_offset (44)
+// CHECK-NEXT: 31 | offset_to_top (-104)
+// CHECK-NEXT: 32 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C1, 104) vtable address --
+// CHECK-NEXT: 33 | vbase_offset (28)
+// CHECK-NEXT: 34 | vbase_offset (32)
+// CHECK-NEXT: 35 | offset_to_top (-120)
+// CHECK-NEXT: 36 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 120) vtable address --
+// CHECK-NEXT: -- (Test1::C3, 120) vtable address --
+// CHECK-NEXT: 37 | vbase_offset (-4)
+// CHECK-NEXT: 38 | offset_to_top (-152)
+// CHECK-NEXT: 39 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C1, 152) vtable address --
+// CHECK-NEXT: 40 | vbase_offset (-48)
+// CHECK-NEXT: 41 | vbase_offset (-20)
+// CHECK-NEXT: 42 | vbase_offset (-16)
+// CHECK-NEXT: 43 | offset_to_top (-168)
+// CHECK-NEXT: 44 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 168) vtable address --
+// CHECK-NEXT: -- (Test1::C4, 168) vtable address --
+// CHECK-NEXT: 45 | vbase_offset (160)
+// CHECK-NEXT: 46 | vbase_offset (-136)
+// CHECK-NEXT: 47 | vbase_offset (-16)
+// CHECK-NEXT: 48 | vbase_offset (128)
+// CHECK-NEXT: 49 | vbase_offset (-64)
+// CHECK-NEXT: 50 | vbase_offset (-36)
+// CHECK-NEXT: 51 | vbase_offset (-32)
+// CHECK-NEXT: 52 | offset_to_top (-184)
+// CHECK-NEXT: 53 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 184) vtable address --
+// CHECK-NEXT: -- (Test1::C4, 184) vtable address --
+// CHECK-NEXT: -- (Test1::C7, 184) vtable address --
+// CHECK-NEXT: -- (Test1::C8, 184) vtable address --
+// CHECK-NEXT: 54 | vbase_offset (-88)
+// CHECK-NEXT: 55 | vbase_offset (-40)
+// CHECK-NEXT: 56 | vbase_offset (-60)
+// CHECK-NEXT: 57 | vbase_offset (-56)
+// CHECK-NEXT: 58 | offset_to_top (-208)
+// CHECK-NEXT: 59 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 208) vtable address --
+// CHECK-NEXT: -- (Test1::C5, 208) vtable address --
+// CHECK-NEXT: 60 | vbase_offset (-76)
+// CHECK-NEXT: 61 | offset_to_top (-224)
+// CHECK-NEXT: 62 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C1, 224) vtable address --
+// CHECK-NEXT: 63 | vbase_offset (-92)
+// CHECK-NEXT: 64 | vbase_offset (-88)
+// CHECK-NEXT: 65 | offset_to_top (-240)
+// CHECK-NEXT: 66 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 240) vtable address --
+// CHECK-NEXT: -- (Test1::C3, 240) vtable address --
+// CHECK-NEXT: 67 | vbase_offset (-124)
+// CHECK-NEXT: 68 | offset_to_top (-272)
+// CHECK-NEXT: 69 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C1, 272) vtable address --
+// CHECK-NEXT: 70 | vbase_offset (-140)
+// CHECK-NEXT: 71 | vbase_offset (-136)
+// CHECK-NEXT: 72 | offset_to_top (-288)
+// CHECK-NEXT: 73 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 288) vtable address --
+// CHECK-NEXT: 74 | vbase_offset (-192)
+// CHECK-NEXT: 75 | vbase_offset (-144)
+// CHECK-NEXT: 76 | vbase_offset (-164)
+// CHECK-NEXT: 77 | vbase_offset (-160)
+// CHECK-NEXT: 78 | offset_to_top (-312)
+// CHECK-NEXT: 79 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C2, 312) vtable address --
+// CHECK-NEXT: -- (Test1::C5, 312) vtable address --
+// CHECK-NEXT: 80 | vbase_offset (-180)
+// CHECK-NEXT: 81 | offset_to_top (-328)
+// CHECK-NEXT: 82 | Test1::C9 RTTI
+// CHECK-NEXT: -- (Test1::C1, 328) vtable address --
+// CHECK-NEXT: 83 | vbase_offset (-196)
+// CHECK-NEXT: 84 | vbase_offset (-192)
+// CHECK-NEXT: 85 | offset_to_top (-344)
+// CHECK-NEXT: 86 | Test1::C9 RTTI
+class C9
+ : virtual public C6
+ , public C2
+ , public C4
+ , virtual public C8
+{
+ int k0;
+ int k1;
+ int k2;
+ int k3;
+ virtual void f();
+};
+void C9::f() { }
+
+}
diff --git a/clang/test/CodeGenCXX/vtable-linkage-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-linkage-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..38f6b6a352bb84
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-linkage-nonzero-default-address-space.cpp
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -emit-llvm -o %t
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -emit-llvm -std=c++03 -o %t.03
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -emit-llvm -std=c++11 -o %t.11
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -disable-llvm-passes -O3 -emit-llvm -o %t.opt
+// RUN: FileCheck %s < %t
+// RUN: FileCheck %s < %t.03
+// RUN: FileCheck %s < %t.11
+// RUN: FileCheck --check-prefix=CHECK-OPT %s < %t.opt
+
+namespace {
+ struct A {
+ virtual void f() { }
+ };
+}
+
+void f() { A b; }
+
+struct B {
+ B();
+ virtual void f();
+};
+
+B::B() { }
+
+struct C : virtual B {
+ C();
+ virtual void f() { }
+};
+
+C::C() { }
+
+struct D {
+ virtual void f();
+};
+
+void D::f() { }
+
+static struct : D { } e;
+
+// Force 'e' to be constructed and therefore have a vtable defined.
+void use_e() {
+ e.f();
+}
+
+// The destructor is the key function.
+template<typename T>
+struct E {
+ virtual ~E();
+};
+
+template<typename T> E<T>::~E() { }
+
+// Anchor is the key function
+template<>
+struct E<char> {
+ virtual void anchor();
+};
+
+void E<char>::anchor() { }
+
+template struct E<short>;
+extern template struct E<int>;
+
+void use_E() {
+ E<int> ei;
+ (void)ei;
+ E<long> el;
+ (void)el;
+}
+
+// No key function
+template<typename T>
+struct F {
+ virtual void foo() { }
+};
+
+// No key function
+template<>
+struct F<char> {
+ virtual void foo() { }
+};
+
+template struct F<short>;
+extern template struct F<int>;
+
+void use_F() {
+ F<char> fc;
+ fc.foo();
+ F<int> fi;
+ fi.foo();
+ F<long> fl;
+ (void)fl;
+}
+
+// B has a key function that is not defined in this translation unit so its vtable
+// has external linkage.
+// CHECK-DAG: @_ZTV1B = external unnamed_addr addrspace(1) constant
+
+// C has no key function, so its vtable should have weak_odr linkage
+// and hidden visibility
+// CHECK-DAG: @_ZTV1C = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+// CHECK-DAG: @_ZTS1C = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}}
+// CHECK-DAG: @_ZTI1C = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+// CHECK-DAG: @_ZTT1C = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+
+// D has a key function that is defined in this translation unit so its vtable is
+// defined in the translation unit.
+// CHECK-DAG: @_ZTV1D ={{.*}} unnamed_addr addrspace(1) constant
+// CHECK-DAG: @_ZTS1D ={{.*}} addrspace(1) constant
+// CHECK-DAG: @_ZTI1D ={{.*}} addrspace(1) constant
+
+// E<char> is an explicit specialization with a key function defined
+// in this translation unit, so its vtable should have external
+// linkage.
+// CHECK-DAG: @_ZTV1EIcE ={{.*}} unnamed_addr addrspace(1) constant
+// CHECK-DAG: @_ZTS1EIcE ={{.*}} addrspace(1) constant
+// CHECK-DAG: @_ZTI1EIcE ={{.*}} addrspace(1) constant
+
+// E<short> is an explicit template instantiation with a key function
+// defined in this translation unit, so its vtable should have
+// weak_odr linkage.
+// CHECK-DAG: @_ZTV1EIsE = weak_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+// CHECK-DAG: @_ZTS1EIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}}
+// CHECK-DAG: @_ZTI1EIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+
+// F<short> is an explicit template instantiation without a key
+// function, so its vtable should have weak_odr linkage
+// CHECK-DAG: @_ZTV1FIsE = weak_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+// CHECK-DAG: @_ZTS1FIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}}
+// CHECK-DAG: @_ZTI1FIsE = weak_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+
+// E<long> is an implicit template instantiation with a key function
+// defined in this translation unit, so its vtable should have
+// linkonce_odr linkage.
+// CHECK-DAG: @_ZTV1EIlE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+// CHECK-DAG: @_ZTS1EIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}}
+// CHECK-DAG: @_ZTI1EIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+
+// F<long> is an implicit template instantiation with no key function,
+// so its vtable should have linkonce_odr linkage.
+// CHECK-DAG: @_ZTV1FIlE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+// CHECK-DAG: @_ZTS1FIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}}
+// CHECK-DAG: @_ZTI1FIlE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+
+// F<int> is an explicit template instantiation declaration without a
+// key function, so its vtable should have external linkage.
+// CHECK-DAG: @_ZTV1FIiE = external unnamed_addr addrspace(1) constant
+// CHECK-OPT-DAG: @_ZTV1FIiE = available_externally unnamed_addr addrspace(1) constant
+
+// E<int> is an explicit template instantiation declaration. It has a
+// key function is not instantiated, so we know that vtable definition
+// will be generated in TU where key function will be defined
+// so we can mark it as external (without optimizations) and
+// available_externally (with optimizations) because all of the inline
+// virtual functions have been emitted.
+// CHECK-DAG: @_ZTV1EIiE = external unnamed_addr addrspace(1) constant
+// CHECK-OPT-DAG: @_ZTV1EIiE = available_externally unnamed_addr addrspace(1) constant
+
+// The anonymous struct for e has no linkage, so the vtable should have
+// internal linkage.
+// CHECK-DAG: @"_ZTV3$_0" = internal unnamed_addr addrspace(1) constant
+// CHECK-DAG: @"_ZTS3$_0" = internal addrspace(1) constant
+// CHECK-DAG: @"_ZTI3$_0" = internal addrspace(1) constant
+
+// The A vtable should have internal linkage since it is inside an anonymous
+// namespace.
+// CHECK-DAG: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr addrspace(1) constant
+// CHECK-DAG: @_ZTSN12_GLOBAL__N_11AE = internal addrspace(1) constant
+// CHECK-DAG: @_ZTIN12_GLOBAL__N_11AE = internal addrspace(1) constant
+
+// F<char> is an explicit specialization without a key function, so
+// its vtable should have linkonce_odr linkage.
+// CHECK-DAG: @_ZTV1FIcE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+// CHECK-DAG: @_ZTS1FIcE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 1{{$}}
+// CHECK-DAG: @_ZTI1FIcE = linkonce_odr addrspace(1) constant {{.*}}, comdat, align 8{{$}}
+
+// CHECK-DAG: @_ZTV1GIiE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+template <typename T>
+class G {
+public:
+ G() {}
+ virtual void f0();
+ virtual void f1();
+};
+template <>
+void G<int>::f1() {}
+template <typename T>
+void G<T>::f0() {}
+void G_f0() { new G<int>(); }
+
+// H<int> has a key function without a body but it's a template instantiation
+// so its VTable must be emitted.
+// CHECK-DAG: @_ZTV1HIiE = linkonce_odr unnamed_addr addrspace(1) constant {{.*}}, comdat,
+template <typename T>
+class H {
+public:
+ virtual ~H();
+};
+
+void use_H() {
+ H<int> h;
+}
+
+// I<int> has an explicit instantiation declaration and needs a VTT and
+// construction vtables.
+
+// CHECK-DAG: @_ZTV1IIiE = external unnamed_addr addrspace(1) constant
+// CHECK-DAG: @_ZTT1IIiE = external unnamed_addr addrspace(1) constant
+// CHECK-NOT: @_ZTC1IIiE
+//
+// CHECK-OPT-DAG: @_ZTV1IIiE = available_externally unnamed_addr addrspace(1) constant
+// CHECK-OPT-DAG: @_ZTT1IIiE = available_externally unnamed_addr addrspace(1) constant
+struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {};
+template<typename T>
+struct I : VBase2 {};
+extern template struct I<int>;
+I<int> i;
diff --git a/clang/test/CodeGenCXX/vtable-pointer-initialization-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtable-pointer-initialization-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..efb4afb38f5e8c
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-pointer-initialization-nonzero-default-address-space.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -std=c++11 -emit-llvm -o - | FileCheck %s
+
+struct Field {
+ Field();
+ ~Field();
+};
+
+struct Base {
+ Base();
+ ~Base();
+};
+
+struct A : Base {
+ A();
+ ~A();
+
+ virtual void f();
+
+ Field field;
+};
+
+// CHECK-LABEL: define{{.*}} void @_ZN1AC2Ev(ptr addrspace(4) {{[^,]*}} %this) unnamed_addr
+// CHECK: call{{.*}} void @_ZN4BaseC2Ev(
+// CHECK: store ptr addrspace(1) getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1A, i32 0, i32 0, i32 2)
+// CHECK: call{{.*}} void @_ZN5FieldC1Ev(
+// CHECK: ret void
+A::A() { }
+
+// CHECK-LABEL: define{{.*}} void @_ZN1AD2Ev(ptr addrspace(4) {{[^,]*}} %this) unnamed_addr
+// CHECK: store ptr addrspace(1) getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1A, i32 0, i32 0, i32 2)
+// CHECK: call{{.*}} void @_ZN5FieldD1Ev(
+// CHECK: call{{.*}} void @_ZN4BaseD2Ev(
+// CHECK: ret void
+A::~A() { }
+
+struct B : Base {
+ virtual void f();
+
+ Field field;
+};
+
+void f() { B b; }
+
+// CHECK-LABEL: define linkonce_odr{{.*}} void @_ZN1BC1Ev(ptr addrspace(4) {{[^,]*}} %this) unnamed_addr
+// CHECK: call{{.*}} void @_ZN1BC2Ev(
+
+// CHECK-LABEL: define linkonce_odr{{.*}} void @_ZN1BD1Ev(ptr addrspace(4) {{[^,]*}} %this) unnamed_addr
+// CHECK: call{{.*}} void @_ZN1BD2Ev(
+
+// CHECK-LABEL: define linkonce_odr{{.*}} void @_ZN1BC2Ev(ptr addrspace(4) {{[^,]*}} %this) unnamed_addr
+// CHECK: call{{.*}} void @_ZN4BaseC2Ev(
+// CHECK: store ptr addrspace(1) getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1B, i32 0, i32 0, i32 2)
+// CHECK: call{{.*}} void @_ZN5FieldC1Ev
+// CHECK: ret void
+
+// CHECK-LABEL: define linkonce_odr{{.*}} void @_ZN1BD2Ev(ptr addrspace(4) {{[^,]*}} %this) unnamed_addr
+// CHECK: store ptr addrspace(1) getelementptr inbounds inrange(-16, 8) ({ [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTV1B, i32 0, i32 0, i32 2)
+// CHECK: call{{.*}} void @_ZN5FieldD1Ev(
+// CHECK: call{{.*}} void @_ZN4BaseD2Ev(
+// CHECK: ret void
diff --git a/clang/test/CodeGenCXX/vtt-layout-with-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtt-layout-with-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..52c6249af9f51c
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtt-layout-with-nonzero-default-address-space.cpp
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -std=c++11 -emit-llvm -o - | FileCheck %s
+
+// Test1::B should just have a single entry in its VTT, which points to the vtable.
+namespace Test1 {
+struct A { };
+
+struct B : virtual A {
+ virtual void f();
+};
+
+void B::f() { }
+}
+
+// Check that we don't add a secondary virtual pointer for Test2::A, since Test2::A doesn't have any virtual member functions or bases.
+namespace Test2 {
+ struct A { };
+
+ struct B : A { virtual void f(); };
+ struct C : virtual B { };
+
+ C c;
+}
+
+// This is the sample from the C++ Itanium ABI, p2.6.2.
+namespace Test3 {
+ class A1 { int i; };
+ class A2 { int i; virtual void f(); };
+ class V1 : public A1, public A2 { int i; };
+ class B1 { int i; };
+ class B2 { int i; };
+ class V2 : public B1, public B2, public virtual V1 { int i; };
+ class V3 {virtual void g(); };
+ class C1 : public virtual V1 { int i; };
+ class C2 : public virtual V3, virtual V2 { int i; };
+ class X1 { int i; };
+ class C3 : public X1 { int i; };
+ class D : public C1, public C2, public C3 { int i; };
+
+ D d;
+}
+
+// This is the sample from the C++ Itanium ABI, p2.6.2, with the change suggested
+// (making A2 a virtual base of V1)
+namespace Test4 {
+ class A1 { int i; };
+ class A2 { int i; virtual void f(); };
+ class V1 : public A1, public virtual A2 { int i; };
+ class B1 { int i; };
+ class B2 { int i; };
+ class V2 : public B1, public B2, public virtual V1 { int i; };
+ class V3 {virtual void g(); };
+ class C1 : public virtual V1 { int i; };
+ class C2 : public virtual V3, virtual V2 { int i; };
+ class X1 { int i; };
+ class C3 : public X1 { int i; };
+ class D : public C1, public C2, public C3 { int i; };
+
+ D d;
+}
+
+namespace Test5 {
+ struct A {
+ virtual void f() = 0;
+ virtual void anchor();
+ };
+
+ void A::anchor() {
+ }
+}
+
+namespace Test6 {
+ struct A {
+ virtual void f() = delete;
+ virtual void anchor();
+ };
+
+ void A::anchor() {
+ }
+}
+
+// CHECK: @_ZTTN5Test11BE ={{.*}} unnamed_addr addrspace(1) constant [1 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test11BE, i32 0, i32 0, i32 3)]
+// CHECK: @_ZTVN5Test51AE ={{.*}} unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } { [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @_ZTIN5Test51AE, ptr addrspace(1) addrspacecast (ptr @__cxa_pure_virtual to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN5Test51A6anchorEv to ptr addrspace(1))] }
+// CHECK: @_ZTVN5Test61AE ={{.*}} unnamed_addr addrspace(1) constant { [4 x ptr addrspace(1)] } { [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) @_ZTIN5Test61AE, ptr addrspace(1) addrspacecast (ptr @__cxa_deleted_virtual to ptr addrspace(1)), ptr addrspace(1) addrspacecast (ptr @_ZN5Test61A6anchorEv to ptr addrspace(1))] }
+// CHECK: @_ZTTN5Test21CE = linkonce_odr unnamed_addr addrspace(1) constant [2 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds inrange(-32, 8) ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test21CE, i32 0, i32 0, i32 4), ptr addrspace(1) getelementptr inbounds inrange(-32, 8) ({ [5 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test21CE, i32 0, i32 0, i32 4)]
+// CHECK: @_ZTTN5Test31DE = linkonce_odr unnamed_addr addrspace(1) constant [13 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds inrange(-40, 0) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, i32 0, i32 5), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE0_NS_2C1E, i32 0, i32 0, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE0_NS_2C1E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 0, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 0, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE16_NS_2C2E, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, i32 1, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, i32 1, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test31DE, i32 0, i32 3, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE64_NS_2V2E, i32 0, i32 0, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test31DE64_NS_2V2E, i32 0, i32 1, i32 3)]
+// CHECK: @_ZTVN5Test41DE = linkonce_odr unnamed_addr addrspace(1) constant { [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] } { [6 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 72 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 16 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 56 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 40 to ptr addrspace(1)), ptr addrspace(1) null, ptr addrspace(1) @_ZTIN5Test41DE], [8 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 40 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 24 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 56 to ptr addrspace(1)), ptr addrspace(1) null, ptr addrspace(1) null, ptr addrspace(1) inttoptr (i64 -16 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE, ptr addrspace(1) addrspacecast (ptr @_ZN5Test42V31gEv to ptr addrspace(1))], [3 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 16 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 -40 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE], [4 x ptr addrspace(1)] [ptr addrspace(1) null, ptr addrspace(1) inttoptr (i64 -56 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE, ptr addrspace(1) addrspacecast (ptr @_ZN5Test42A21fEv to ptr addrspace(1))], [4 x ptr addrspace(1)] [ptr addrspace(1) inttoptr (i64 -16 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 -32 to ptr addrspace(1)), ptr addrspace(1) inttoptr (i64 -72 to ptr addrspace(1)), ptr addrspace(1) @_ZTIN5Test41DE] }
+// CHECK: @_ZTTN5Test41DE = linkonce_odr unnamed_addr addrspace(1) constant [19 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds inrange(-48, 0) ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, i32 0, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-32, 0) ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE0_NS_2C1E, i32 0, i32 0, i32 4), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE0_NS_2C1E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE0_NS_2C1E, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-56, 8) ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 0, i32 7), ptr addrspace(1) getelementptr inbounds inrange(-56, 8) ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 0, i32 7), ptr addrspace(1) getelementptr inbounds inrange(-32, 0) ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 1, i32 4), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [8 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE16_NS_2C2E, i32 0, i32 3, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, i32 3, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-56, 8) ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, i32 1, i32 7), ptr addrspace(1) getelementptr inbounds inrange(-56, 8) ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, i32 1, i32 7), ptr addrspace(1) getelementptr inbounds inrange(-32, 0) ({ [6 x ptr addrspace(1)], [8 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN5Test41DE, i32 0, i32 4, i32 4), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE40_NS_2V1E, i32 0, i32 0, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE40_NS_2V1E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-32, 0) ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE72_NS_2V2E, i32 0, i32 0, i32 4), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE72_NS_2V2E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [4 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN5Test41DE72_NS_2V2E, i32 0, i32 2, i32 3)]
+// CHECK: declare{{.*}} void @__cxa_pure_virtual() unnamed_addr
+// CHECK: declare{{.*}} void @__cxa_deleted_virtual() unnamed_addr
diff --git a/clang/test/CodeGenCXX/vtt-nonzero-default-address-space.cpp b/clang/test/CodeGenCXX/vtt-nonzero-default-address-space.cpp
new file mode 100644
index 00000000000000..c7f388959201fc
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtt-nonzero-default-address-space.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 %s -triple=spirv64-unknown-unknown -fsycl-is-device -std=c++11 -emit-llvm -o - | FileCheck %s
+
+// This is the sample from the C++ Itanium ABI, p2.6.2.
+namespace Test {
+ class A1 { int i; };
+ class A2 { int i; virtual void f(); };
+ class V1 : public A1, public A2 { int i; };
+ class B1 { int i; };
+ class B2 { int i; };
+ class V2 : public B1, public B2, public virtual V1 { int i; };
+ class V3 { virtual void g(); };
+ class C1 : public virtual V1 { int i; };
+ class C2 : public virtual V3, virtual V2 { int i; };
+ class X1 { int i; };
+ class C3 : public X1 { int i; };
+ class D : public C1, public C2, public C3 { int i; };
+
+ D d;
+}
+
+// CHECK: linkonce_odr unnamed_addr addrspace(1) constant [13 x ptr addrspace(1)] [ptr addrspace(1) getelementptr inbounds inrange(-40, 0) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, i32 0, i32 5), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE0_NS_2C1E, i32 0, i32 0, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE0_NS_2C1E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, i32 0, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, i32 0, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, i32 1, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [7 x ptr addrspace(1)], [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE16_NS_2C2E, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, i32 2, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, i32 1, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-48, 8) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, i32 1, i32 6), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [5 x ptr addrspace(1)], [7 x ptr addrspace(1)], [4 x ptr addrspace(1)], [3 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTVN4Test1DE, i32 0, i32 3, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 0) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE64_NS_2V2E, i32 0, i32 0, i32 3), ptr addrspace(1) getelementptr inbounds inrange(-24, 8) ({ [3 x ptr addrspace(1)], [4 x ptr addrspace(1)] }, ptr addrspace(1) @_ZTCN4Test1DE64_NS_2V2E, i32 0, i32 1, i32 3)], comdat, align 8
+// CHECK: call {{.*}} void @_ZN4Test2V2C2Ev(ptr addrspace(4) noundef align 8 dereferenceable_or_null(20) %2, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr addrspace(1)], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 11))
+// CHECK: call {{.*}} void @_ZN4Test2C1C2Ev(ptr addrspace(4) noundef align 8 dereferenceable_or_null(12) %this1, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr addrspace(1)], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 1))
+// CHECK: call {{.*}} void @_ZN4Test2C2C2Ev(ptr addrspace(4) noundef align 8 dereferenceable_or_null(12) %3, ptr addrspace(1) noundef getelementptr inbounds ([13 x ptr addrspace(1)], ptr addrspace(1) @_ZTTN4Test1DE, i64 0, i64 3))
+// CHECK: define linkonce_odr {{.*}} void @_ZN4Test2V2C2Ev(ptr addrspace(4) noundef align 8 dereferenceable_or_null(20) %this, ptr addrspace(1) noundef %vtt)
+// CHECK: define linkonce_odr {{.*}} void @_ZN4Test2C1C2Ev(ptr addrspace(4) noundef align 8 dereferenceable_or_null(12) %this, ptr addrspace(1) noundef %vtt)
+// CHECK: define linkonce_odr {{.*}} void @_ZN4Test2C2C2Ev(ptr addrspace(4) noundef align 8 dereferenceable_or_null(12) %this, ptr addrspace(1) noundef %vtt)
>From 453e96aafd02bd19f44c0383acb74b930d2767c9 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 9 Apr 2024 19:25:02 +0100
Subject: [PATCH 4/8] Simplify generic pointer type retrieval.
---
clang/lib/CodeGen/CodeGenModule.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 01763308e6c17c..158dca114679ce 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -366,8 +366,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
IntTy = llvm::IntegerType::get(LLVMContext, C.getTargetInfo().getIntWidth());
IntPtrTy = llvm::IntegerType::get(LLVMContext,
C.getTargetInfo().getMaxPointerWidth());
- Int8PtrTy = llvm::PointerType::get(
- LLVMContext, C.getTargetInfo().getTargetAddressSpace(LangAS::Default));
+ Int8PtrTy = llvm::PointerType::get(LLVMContext,
+ C.getTargetAddressSpace(LangAS::Default));
const llvm::DataLayout &DL = M.getDataLayout();
AllocaInt8PtrTy =
llvm::PointerType::get(LLVMContext, DL.getAllocaAddrSpace());
>From 6c096210bebe999392b2c3432ad8c8bc5b6288e9 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 9 Apr 2024 20:50:39 +0100
Subject: [PATCH 5/8] Fix formatting.
---
clang/lib/CodeGen/CodeGenModule.cpp | 24 ++++++++++++------------
clang/lib/CodeGen/ItaniumCXXABI.cpp | 11 +++++------
2 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 158dca114679ce..faa1058f8ec23a 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3582,10 +3582,11 @@ ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject(
isExternallyVisible(TPO->getLinkageAndVisibility().getLinkage())
? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage;
- auto *GV = new llvm::GlobalVariable(getModule(), Init->getType(),
- /*isConstant=*/true, Linkage, Init, Name,
- nullptr, llvm::GlobalValue::NotThreadLocal,
- GlobalsInt8PtrTy->getAddressSpace());
+ auto *GV = new llvm::GlobalVariable(
+ getModule(), Init->getType(),
+ /*isConstant=*/true, Linkage, Init, Name, nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ GlobalsInt8PtrTy->getAddressSpace());
setGVProperties(GV, TPO);
if (supportsCOMDAT())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
@@ -4552,10 +4553,10 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
IsIncompleteFunction = true;
}
- llvm::Function *F = llvm::Function::Create(
- FTy, llvm::Function::ExternalLinkage,
- getDataLayout().getProgramAddressSpace(),
- Entry ? StringRef() : MangledName, &getModule());
+ llvm::Function *F =
+ llvm::Function::Create(FTy, llvm::Function::ExternalLinkage,
+ getDataLayout().getProgramAddressSpace(),
+ Entry ? StringRef() : MangledName, &getModule());
// Store the declaration associated with this function so it is potentially
// updated by further declarations or definitions and emitted at the end.
@@ -5025,10 +5026,9 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
}
// Create a new variable.
- GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true,
- Linkage, nullptr, Name, nullptr,
- llvm::GlobalValue::NotThreadLocal,
- GlobalsInt8PtrTy->getAddressSpace());
+ GV = new llvm::GlobalVariable(
+ getModule(), Ty, /*isConstant=*/true, Linkage, nullptr, Name, nullptr,
+ llvm::GlobalValue::NotThreadLocal, GlobalsInt8PtrTy->getAddressSpace());
if (OldGV) {
// Replace occurrences of the old variable if needed.
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 942ab4c3a43d05..823244a4115316 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3680,12 +3680,11 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
llvm::Type *Ty = llvm::ArrayType::get(CGM.GlobalsInt8PtrTy, 0);
// FIXME: External StdLib VTables should be constant as well, but changing
// it *might* constitute a very subtle ABI break.
- VTable = new llvm::GlobalVariable(CGM.getModule(), Ty,
- /*isConstant=*/false,
- llvm::GlobalVariable::ExternalLinkage,
- nullptr, VTableName, nullptr,
- llvm::GlobalValue::NotThreadLocal,
- CGM.GlobalsInt8PtrTy->getAddressSpace());
+ VTable = new llvm::GlobalVariable(
+ CGM.getModule(), Ty,
+ /*isConstant=*/false, llvm::GlobalVariable::ExternalLinkage, nullptr,
+ VTableName, nullptr, llvm::GlobalValue::NotThreadLocal,
+ CGM.GlobalsInt8PtrTy->getAddressSpace());
}
}
>From 2549f5ac5a29933c76ea5eb868f1d3f0612280a0 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 9 Apr 2024 21:03:35 +0100
Subject: [PATCH 6/8] (Actually) Fix formatting.
---
clang/lib/CodeGen/CodeGenModule.cpp | 7 +++----
clang/lib/CodeGen/ItaniumCXXABI.cpp | 8 ++++----
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index faa1058f8ec23a..8ed88b34b4a00b 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -3585,8 +3585,7 @@ ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject(
auto *GV = new llvm::GlobalVariable(
getModule(), Init->getType(),
/*isConstant=*/true, Linkage, Init, Name, nullptr,
- llvm::GlobalValue::NotThreadLocal,
- GlobalsInt8PtrTy->getAddressSpace());
+ llvm::GlobalValue::NotThreadLocal, GlobalsInt8PtrTy->getAddressSpace());
setGVProperties(GV, TPO);
if (supportsCOMDAT())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
@@ -5027,8 +5026,8 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
// Create a new variable.
GV = new llvm::GlobalVariable(
- getModule(), Ty, /*isConstant=*/true, Linkage, nullptr, Name, nullptr,
- llvm::GlobalValue::NotThreadLocal, GlobalsInt8PtrTy->getAddressSpace());
+ getModule(), Ty, /*isConstant=*/true, Linkage, nullptr, Name, nullptr,
+ llvm::GlobalValue::NotThreadLocal, GlobalsInt8PtrTy->getAddressSpace());
if (OldGV) {
// Replace occurrences of the old variable if needed.
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 823244a4115316..5e42e94bf31756 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3681,10 +3681,10 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
// FIXME: External StdLib VTables should be constant as well, but changing
// it *might* constitute a very subtle ABI break.
VTable = new llvm::GlobalVariable(
- CGM.getModule(), Ty,
- /*isConstant=*/false, llvm::GlobalVariable::ExternalLinkage, nullptr,
- VTableName, nullptr, llvm::GlobalValue::NotThreadLocal,
- CGM.GlobalsInt8PtrTy->getAddressSpace());
+ CGM.getModule(), Ty,
+ /*isConstant=*/false, llvm::GlobalVariable::ExternalLinkage, nullptr,
+ VTableName, nullptr, llvm::GlobalValue::NotThreadLocal,
+ CGM.GlobalsInt8PtrTy->getAddressSpace());
}
}
>From 0b3dac3be59d0c9a65e04e5a6ba53a706d8f8695 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Wed, 10 Apr 2024 00:25:13 +0100
Subject: [PATCH 7/8] Delete unnecessary leftover diff.
---
clang/lib/CodeGen/CodeGenModule.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 8ed88b34b4a00b..3c5acfffabfeac 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4554,7 +4554,6 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
llvm::Function *F =
llvm::Function::Create(FTy, llvm::Function::ExternalLinkage,
- getDataLayout().getProgramAddressSpace(),
Entry ? StringRef() : MangledName, &getModule());
// Store the declaration associated with this function so it is potentially
>From c18febe32478aaf4d5602ab6f0a41554ae8a6ab2 Mon Sep 17 00:00:00 2001
From: Alex Voicu <alexandru.voicu at amd.com>
Date: Tue, 16 Apr 2024 14:21:49 +0100
Subject: [PATCH 8/8] Roll-back Global generation to use defaults now that
#88455 went in.
---
clang/lib/CodeGen/CodeGenModule.cpp | 17 +++++++----------
clang/lib/CodeGen/ItaniumCXXABI.cpp | 21 ++++-----------------
2 files changed, 11 insertions(+), 27 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 070ad5d374168e..0307099344c0d4 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -371,8 +371,8 @@ CodeGenModule::CodeGenModule(ASTContext &C,
const llvm::DataLayout &DL = M.getDataLayout();
AllocaInt8PtrTy =
llvm::PointerType::get(LLVMContext, DL.getAllocaAddrSpace());
- GlobalsInt8PtrTy = llvm::PointerType::get(
- LLVMContext, C.getTargetAddressSpace(GetGlobalVarAddressSpace(nullptr)));
+ GlobalsInt8PtrTy =
+ llvm::PointerType::get(LLVMContext, DL.getDefaultGlobalsAddressSpace());
ConstGlobalsPtrTy = llvm::PointerType::get(
LLVMContext, C.getTargetAddressSpace(GetGlobalConstantAddressSpace()));
ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace();
@@ -3590,10 +3590,8 @@ ConstantAddress CodeGenModule::GetAddrOfTemplateParamObject(
isExternallyVisible(TPO->getLinkageAndVisibility().getLinkage())
? llvm::GlobalValue::LinkOnceODRLinkage
: llvm::GlobalValue::InternalLinkage;
- auto *GV = new llvm::GlobalVariable(
- getModule(), Init->getType(),
- /*isConstant=*/true, Linkage, Init, Name, nullptr,
- llvm::GlobalValue::NotThreadLocal, GlobalsInt8PtrTy->getAddressSpace());
+ auto *GV = new llvm::GlobalVariable(getModule(), Init->getType(),
+ /*isConstant=*/true, Linkage, Init, Name);
setGVProperties(GV, TPO);
if (supportsCOMDAT())
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
@@ -5044,9 +5042,8 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable(
}
// Create a new variable.
- GV = new llvm::GlobalVariable(
- getModule(), Ty, /*isConstant=*/true, Linkage, nullptr, Name, nullptr,
- llvm::GlobalValue::NotThreadLocal, GlobalsInt8PtrTy->getAddressSpace());
+ GV = new llvm::GlobalVariable(getModule(), Ty, /*isConstant=*/true,
+ Linkage, nullptr, Name);
if (OldGV) {
// Replace occurrences of the old variable if needed.
@@ -5161,7 +5158,7 @@ LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) {
return LangAS::cuda_device;
}
- if (LangOpts.OpenMP && OpenMPRuntime) {
+ if (LangOpts.OpenMP) {
LangAS AS;
if (OpenMPRuntime->hasAllocateAttributeForGlobalVar(D, AS))
return AS;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 5e42e94bf31756..18acf7784f714b 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -3279,9 +3279,7 @@ ItaniumRTTIBuilder::GetAddrOfExternalRTTIDescriptor(QualType Ty) {
GV = new llvm::GlobalVariable(
CGM.getModule(), CGM.GlobalsInt8PtrTy,
- /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr, Name,
- nullptr, llvm::GlobalValue::NotThreadLocal,
- CGM.GlobalsInt8PtrTy->getAddressSpace());
+ /*isConstant=*/true, llvm::GlobalValue::ExternalLinkage, nullptr, Name);
const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
CGM.setGVProperties(GV, RD);
// Import the typeinfo symbol when all non-inline virtual methods are
@@ -3675,17 +3673,8 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
if (CGM.getItaniumVTableContext().isRelativeLayout())
VTable = CGM.getModule().getNamedAlias(VTableName);
if (!VTable) {
- VTable = CGM.GetGlobalValue(VTableName);
- if (!VTable) {
- llvm::Type *Ty = llvm::ArrayType::get(CGM.GlobalsInt8PtrTy, 0);
- // FIXME: External StdLib VTables should be constant as well, but changing
- // it *might* constitute a very subtle ABI break.
- VTable = new llvm::GlobalVariable(
- CGM.getModule(), Ty,
- /*isConstant=*/false, llvm::GlobalVariable::ExternalLinkage, nullptr,
- VTableName, nullptr, llvm::GlobalValue::NotThreadLocal,
- CGM.GlobalsInt8PtrTy->getAddressSpace());
- }
+ llvm::Type *Ty = llvm::ArrayType::get(CGM.GlobalsInt8PtrTy, 0);
+ VTable = CGM.getModule().getOrInsertGlobal(VTableName, Ty);
}
CGM.setDSOLocal(cast<llvm::GlobalValue>(VTable->stripPointerCasts()));
@@ -3945,9 +3934,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
llvm::GlobalVariable *OldGV = M.getNamedGlobal(Name);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(M, Init->getType(),
- /*isConstant=*/true, Linkage, Init, Name,
- nullptr, llvm::GlobalValue::NotThreadLocal,
- CGM.GlobalsInt8PtrTy->getAddressSpace());
+ /*isConstant=*/true, Linkage, Init, Name);
// Export the typeinfo in the same circumstances as the vtable is exported.
auto GVDLLStorageClass = DLLStorageClass;
More information about the cfe-commits
mailing list