Skip to content

Commit 9c760ca

Browse files
committed
[Clang][CodeGen] typeid needs special care when type_info is not in the default AS
After https://reviews.llvm.org/D153092, for targets that use a non-default AS for globals, an "interesting" situation arises around typeid and its paired type, type_info: - on the AST level, the type_info interface is defined with default / generic addresses, be it for function arguments, or for this; - in IR, type_info values are globals, and thus pointers to type_info values are pointers to global This leads to a mismatch between the function signature / formal type of the argument, and its actual type. Currently we try to handle such mismatches via `bitcast`, but that is wrong in this case, since an `ascast` is required. This patch ensures that iff the pointer to `type_info` points to a non-default AS, an ascast is inserted so as to match the `typeid` interface / return value type. Reviewed by: yaxunl Differential Revision: https://reviews.llvm.org/D157452
1 parent dd3aa26 commit 9c760ca

File tree

6 files changed

+150
-4
lines changed

6 files changed

+150
-4
lines changed

clang/lib/CodeGen/CGExprCXX.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,11 +2195,19 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
21952195

21962196
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
21972197
llvm::Type *PtrTy = llvm::PointerType::getUnqual(getLLVMContext());
2198+
LangAS GlobAS = CGM.GetGlobalVarAddressSpace(nullptr);
2199+
2200+
auto MaybeASCast = [=](auto &&TypeInfo) {
2201+
if (GlobAS == LangAS::Default)
2202+
return TypeInfo;
2203+
return getTargetHooks().performAddrSpaceCast(CGM,TypeInfo, GlobAS,
2204+
LangAS::Default, PtrTy);
2205+
};
21982206

21992207
if (E->isTypeOperand()) {
22002208
llvm::Constant *TypeInfo =
22012209
CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand(getContext()));
2202-
return TypeInfo;
2210+
return MaybeASCast(TypeInfo);
22032211
}
22042212

22052213
// C++ [expr.typeid]p2:
@@ -2212,7 +2220,7 @@ llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
22122220
return EmitTypeidFromVTable(*this, E->getExprOperand(), PtrTy);
22132221

22142222
QualType OperandTy = E->getExprOperand()->getType();
2215-
return CGM.GetAddrOfRTTIDescriptor(OperandTy);
2223+
return MaybeASCast(CGM.GetAddrOfRTTIDescriptor(OperandTy));
22162224
}
22172225

22182226
static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,8 +1444,8 @@ llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
14441444
llvm::Type *StdTypeInfoPtrTy) {
14451445
auto *ClassDecl =
14461446
cast<CXXRecordDecl>(SrcRecordTy->castAs<RecordType>()->getDecl());
1447-
llvm::Value *Value = CGF.GetVTablePtr(
1448-
ThisPtr, llvm::PointerType::getUnqual(CGF.getLLVMContext()), ClassDecl);
1447+
llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, CGM.GlobalsInt8PtrTy,
1448+
ClassDecl);
14491449

14501450
if (CGM.getItaniumVTableContext().isRelativeLayout()) {
14511451
// Load the type info.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -I%S %s -triple amdgcn-amd-amdhsa -emit-llvm -std=c++11 -o - | FileCheck %s
2+
#include <typeinfo>
3+
4+
namespace Test1 {
5+
6+
struct Item {
7+
const std::type_info &ti;
8+
const char *name;
9+
void *(*make)();
10+
};
11+
12+
template<typename T> void *make_impl() { return new T; }
13+
template<typename T> constexpr Item item(const char *name) {
14+
return { typeid(T), name, make_impl<T> };
15+
}
16+
17+
struct A { virtual ~A(); };
18+
struct B : virtual A {};
19+
struct C { int n; };
20+
21+
// CHECK: @_ZN5Test15itemsE ={{.*}} constant [4 x {{.*}}] [{{.*}} ptr addrspacecast (ptr addrspace(1) @_ZTIN5Test11AE to ptr), {{.*}} @_ZN5Test19make_implINS_1AEEEPvv {{.*}} ptr addrspacecast (ptr addrspace(1) @_ZTIN5Test11BE to ptr), {{.*}} @_ZN5Test19make_implINS_1BEEEPvv {{.*}} ptr addrspacecast (ptr addrspace(1) @_ZTIN5Test11CE to ptr), {{.*}} @_ZN5Test19make_implINS_1CEEEPvv {{.*}} ptr addrspacecast (ptr addrspace(1) @_ZTIi to ptr), {{.*}} @_ZN5Test19make_implIiEEPvv }]
22+
extern constexpr Item items[] = {
23+
item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int")
24+
};
25+
26+
// CHECK: @_ZN5Test11xE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTIN5Test11AE to ptr), align 8
27+
constexpr auto &x = items[0].ti;
28+
29+
// CHECK: @_ZN5Test11yE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTIN5Test11BE to ptr), align 8
30+
constexpr auto &y = typeid(B{});
31+
32+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %clang_cc1 -I%S %s -triple amdgcn-amd-amdhsa -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s
2+
#include <typeinfo>
3+
4+
namespace Test1 {
5+
6+
// PR7400
7+
struct A { virtual void f(); };
8+
9+
// CHECK: @_ZN5Test16int_tiE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTIi to ptr), align 8
10+
const std::type_info &int_ti = typeid(int);
11+
12+
// CHECK: @_ZN5Test14A_tiE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTIN5Test11AE to ptr), align 8
13+
const std::type_info &A_ti = typeid(const volatile A &);
14+
15+
volatile char c;
16+
17+
// CHECK: @_ZN5Test14c_tiE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTIc to ptr), align 8
18+
const std::type_info &c_ti = typeid(c);
19+
20+
extern const double &d;
21+
22+
// CHECK: @_ZN5Test14d_tiE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTId to ptr), align 8
23+
const std::type_info &d_ti = typeid(d);
24+
25+
extern A &a;
26+
27+
// CHECK: @_ZN5Test14a_tiE ={{.*}} global
28+
const std::type_info &a_ti = typeid(a);
29+
30+
// CHECK: @_ZN5Test18A10_c_tiE ={{.*}} constant ptr addrspacecast (ptr addrspace(1) @_ZTIA10_c to ptr), align 8
31+
const std::type_info &A10_c_ti = typeid(char const[10]);
32+
33+
// CHECK-LABEL: define{{.*}} ptr @_ZN5Test11fEv
34+
// CHECK-SAME: personality ptr @__gxx_personality_v0
35+
const char *f() {
36+
try {
37+
// CHECK: br i1
38+
// CHECK: invoke void @__cxa_bad_typeid() [[NR:#[0-9]+]]
39+
return typeid(*static_cast<A *>(0)).name();
40+
} catch (...) {
41+
// CHECK: landingpad { ptr, i32 }
42+
// CHECK-NEXT: catch ptr null
43+
}
44+
45+
return 0;
46+
}
47+
48+
}
49+
50+
// CHECK: attributes [[NR]] = { noreturn }

clang/test/CodeGenCXX/typeinfo

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ namespace std {
1010
bool operator!=(const type_info& __arg) const {
1111
return !operator==(__arg);
1212
}
13+
14+
bool before(const type_info& __arg) const {
15+
return __name < __arg.__name;
16+
}
17+
18+
unsigned long hash_code() const {
19+
return reinterpret_cast<unsigned long long>(__name);
20+
}
1321
protected:
1422
const char *__name;
1523
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %clang_cc1 -I%S %s -triple amdgcn-amd-amdhsa -emit-llvm -o - | FileCheck %s -check-prefix=AS
2+
// RUN: %clang_cc1 -I%S %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s -check-prefix=NO-AS
3+
#include <typeinfo>
4+
5+
class A {
6+
virtual void f() = 0;
7+
};
8+
9+
class B : A {
10+
void f() override;
11+
};
12+
13+
// AS: @_ZTISt9type_info = external addrspace(1) constant ptr addrspace(1)
14+
// NO-AS: @_ZTISt9type_info = external constant ptr
15+
// AS: @_ZTIi = external addrspace(1) constant ptr addrspace(1)
16+
// NO-AS: @_ZTIi = external constant ptr
17+
// AS: @_ZTVN10__cxxabiv117__class_type_infoE = external addrspace(1) global ptr addrspace(1)
18+
// NO-AS: @_ZTVN10__cxxabiv117__class_type_infoE = external global ptr
19+
// AS: @_ZTS1A = linkonce_odr addrspace(1) constant [3 x i8] c"1A\00", comdat, align 1
20+
// NO-AS: @_ZTS1A = linkonce_odr constant [3 x i8] c"1A\00", comdat, align 1
21+
// 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
22+
// 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
23+
// AS: @_ZTIf = external addrspace(1) constant ptr addrspace(1)
24+
// NO-AS: @_ZTIf = external constant ptr
25+
26+
unsigned long Fn(B& b) {
27+
// AS: %call = call noundef zeroext i1 @_ZNKSt9type_infoeqERKS_(ptr {{.*}} addrspacecast (ptr addrspace(1) @_ZTISt9type_info to ptr), ptr {{.*}} %2)
28+
// NO-AS: %call = call noundef zeroext i1 @_ZNKSt9type_infoeqERKS_(ptr {{.*}} @_ZTISt9type_info, ptr {{.*}} %2)
29+
if (typeid(std::type_info) == typeid(b))
30+
return 42;
31+
// AS: %call2 = call noundef zeroext i1 @_ZNKSt9type_infoneERKS_(ptr {{.*}} addrspacecast (ptr addrspace(1) @_ZTIi to ptr), ptr {{.*}} %5)
32+
// NO-AS: %call2 = call noundef zeroext i1 @_ZNKSt9type_infoneERKS_(ptr {{.*}} @_ZTIi, ptr {{.*}} %5)
33+
if (typeid(int) != typeid(b))
34+
return 1712;
35+
// AS: %call5 = call noundef ptr @_ZNKSt9type_info4nameEv(ptr {{.*}} addrspacecast (ptr addrspace(1) @_ZTI1A to ptr))
36+
// NO-AS: %call5 = call noundef ptr @_ZNKSt9type_info4nameEv(ptr {{.*}} @_ZTI1A)
37+
// AS: %call7 = call noundef ptr @_ZNKSt9type_info4nameEv(ptr {{.*}} %8)
38+
// NO-AS: %call7 = call noundef ptr @_ZNKSt9type_info4nameEv(ptr {{.*}} %8)
39+
if (typeid(A).name() == typeid(b).name())
40+
return 0;
41+
// AS: %call11 = call noundef zeroext i1 @_ZNKSt9type_info6beforeERKS_(ptr {{.*}} %11, ptr {{.*}} addrspacecast (ptr addrspace(1) @_ZTIf to ptr))
42+
// NO-AS: %call11 = call noundef zeroext i1 @_ZNKSt9type_info6beforeERKS_(ptr {{.*}} %11, ptr {{.*}} @_ZTIf)
43+
if (typeid(b).before(typeid(float)))
44+
return 1;
45+
// AS: %call15 = call noundef i64 @_ZNKSt9type_info9hash_codeEv(ptr {{.*}} %14)
46+
// NO-AS: %call15 = call noundef i64 @_ZNKSt9type_info9hash_codeEv(ptr {{.*}} %14)
47+
return typeid(b).hash_code();
48+
}

0 commit comments

Comments
 (0)