From c9b231c8d11f400eb57d5a22348aaf4ecf4cb67d Mon Sep 17 00:00:00 2001 From: Mike Stump Date: Sun, 15 Nov 2009 08:09:41 +0000 Subject: [PATCH] Implement typeid for class types. llvm-svn: 88843 --- clang/lib/CodeGen/CGCXXExpr.cpp | 36 +++++++++++++++++++++++++++++ clang/lib/CodeGen/CGExpr.cpp | 8 +++++++ clang/lib/CodeGen/CodeGenFunction.h | 5 +++- clang/lib/CodeGen/Mangle.cpp | 2 ++ clang/test/CodeGenCXX/rtti.cpp | 26 +++++++++++++++++++++ 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGCXXExpr.cpp b/clang/lib/CodeGen/CGCXXExpr.cpp index abf8d16524d1..565685c6d06a 100644 --- a/clang/lib/CodeGen/CGCXXExpr.cpp +++ b/clang/lib/CodeGen/CGCXXExpr.cpp @@ -334,3 +334,39 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { EmitBlock(DeleteEnd); } + +llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { + QualType Ty = E->getType(); + const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); + if (E->isTypeOperand()) { + QualType Ty = E->getTypeOperand(); + if (const RecordType *RT = Ty->getAs()) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->isPolymorphic()) + return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy); + return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy); + } + // FIXME: return the rtti for the non-class static type. + ErrorUnsupported(E, "typeid expression"); + return 0; + } + Expr *subE = E->getExprOperand(); + if (const RecordType *RT = Ty->getAs()) { + const CXXRecordDecl *RD = cast(RT->getDecl()); + if (RD->isPolymorphic()) { + // FIXME: if subE is an lvalue do + LValue Obj = EmitLValue(subE); + llvm::Value *This = Obj.getAddress(); + // FIXME: need to do a 0 check here for *p on This + llvm::Value *V = Builder.CreateBitCast(This, LTy->getPointerTo()->getPointerTo()); + V = Builder.CreateLoad(V, "vtable"); + V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL); + V = Builder.CreateLoad(V); + return V; + } + return CGM.GenerateRtti(RD); + } + // FIXME: return rtti for the non-class static type. + ErrorUnsupported(E, "typeid expression"); + return 0; +} diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index c446c0368972..bd1c12ccb3f6 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -271,6 +271,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitNullInitializationLValue(cast(E)); case Expr::CXXDefaultArgExprClass: return EmitLValue(cast(E)->getExpr()); + case Expr::CXXTypeidExprClass: + return EmitCXXTypeidLValue(cast(E)); case Expr::ObjCMessageExprClass: return EmitObjCMessageExprLValue(cast(E)); @@ -1464,6 +1466,12 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); } +LValue +CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { + llvm::Value *Temp = EmitCXXTypeidExpr(E); + return LValue::MakeAddr(Temp, MakeQualifiers(E->getType())); +} + LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 5f8a1969f91e..743bf947f82c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -663,6 +663,8 @@ public: llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); void EmitCXXDeleteExpr(const CXXDeleteExpr *E); + llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E); + //===--------------------------------------------------------------------===// // Declaration Emission //===--------------------------------------------------------------------===// @@ -856,6 +858,7 @@ public: LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E); + LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E); LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E); LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E); @@ -1022,7 +1025,7 @@ public: bool IsInitializer = false); void EmitCXXThrowExpr(const CXXThrowExpr *E); - + //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/Mangle.cpp b/clang/lib/CodeGen/Mangle.cpp index e644ff3e4ea0..91e89fb711a2 100644 --- a/clang/lib/CodeGen/Mangle.cpp +++ b/clang/lib/CodeGen/Mangle.cpp @@ -1286,6 +1286,8 @@ static bool isCharSpecialization(QualType T, const char *Name) { bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { // ::= St # ::std:: + // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of + // __ZNKSt9type_infoeqERKS_ if (const NamespaceDecl *NS = dyn_cast(ND)) { if (isStdNamespace(NS)) { Out << "St"; diff --git a/clang/test/CodeGenCXX/rtti.cpp b/clang/test/CodeGenCXX/rtti.cpp index d5ac986b3833..f89396dd11be 100644 --- a/clang/test/CodeGenCXX/rtti.cpp +++ b/clang/test/CodeGenCXX/rtti.cpp @@ -1,6 +1,11 @@ // RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -O0 -S %s -o %t.s // RUN: FileCheck --input-file=%t.s %s +// RUN: clang-cc -triple x86_64-apple-darwin -std=c++0x -emit-llvm %s -o %t.ll +// RUN: FileCheck -check-prefix LL --input-file=%t.ll %s + +#include + class test1_B1 { virtual void foo() { } }; @@ -87,3 +92,24 @@ class test1_D : public test1_B7 { // CHECK-NEXT: .quad (__ZTVN10__cxxabiv120__si_class_type_infoE) + 16 // CHECK-NEXT: .quad __ZTS8test1_B2 // CHECK-NEXT: .quad __ZTI8test1_B1 + + +class NP { }; +void test2_1(); +void test2_2(test1_D *dp) { + test1_D &d = *dp; + if (typeid(d) == typeid(test1_D)) + test2_1(); + if (typeid(NP) == typeid(test1_D)) + test2_1(); +} + +// CHECK-LL:define void @_Z7test2_2P7test1_D(%class.test1_B7* %dp) nounwind { +// CHECK-LL: %tmp1 = load %class.test1_B7** %d +// CHECK-LL-NEXT: %0 = bitcast %class.test1_B7* %tmp1 to %"class.std::type_info"*** +// CHECK-LL-NEXT: %vtable = load %"class.std::type_info"*** %0 +// CHECK-LL-NEXT: %1 = getelementptr inbounds %"class.std::type_info"** %vtable, i64 -1 +// CHECK-LL-NEXT: %2 = load %"class.std::type_info"** %1 +// CHECK-LL-NEXT: %call = call zeroext i1 @_ZNK3std9type_infoeqERKS0_(%"class.std::type_info"* %2, %"class.std::type_info"* bitcast (%1* @_ZTI7test1_D to %"class.std::type_info"*)) + +// CHECK-LL: %call2 = call zeroext i1 @_ZNK3std9type_infoeqERKS0_(%"class.std::type_info"* bitcast (%0* @_ZTI2NP to %"class.std::type_info"*), %"class.std::type_info"* bitcast (%1* @_ZTI7test1_D to %"class.std::type_info"*))