From: Anders Carlsson Date: Sun, 31 Jan 2010 02:39:02 +0000 (+0000) Subject: When performing a derived-to-base cast that we know will not change the offset, we... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=905a100f3d03039f6f3e3aecf2996a05cef4a267;p=clang When performing a derived-to-base cast that we know will not change the offset, we don't need to null check the input pointer. Fixes PR5965. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94942 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index eaebf140fc..1b337ebc1d 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -67,51 +67,6 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *Class, return llvm::ConstantInt::get(PtrDiffTy, Offset); } -static llvm::Value *GetBaseClassOffset(CodeGenFunction &CGF, - llvm::Value *BaseValue, - const CXXRecordDecl *ClassDecl, - const CXXRecordDecl *BaseClassDecl) { - CXXBasePaths Paths(/*FindAmbiguities=*/false, - /*RecordPaths=*/true, /*DetectVirtual=*/false); - if (!const_cast(ClassDecl)-> - isDerivedFrom(const_cast(BaseClassDecl), Paths)) { - assert(false && "Class must be derived from the passed in base class!"); - return 0; - } - - unsigned Start = 0; - llvm::Value *VirtualOffset = 0; - - const CXXBasePath &Path = Paths.front(); - const CXXRecordDecl *VBase = 0; - for (unsigned i = 0, e = Path.size(); i != e; ++i) { - const CXXBasePathElement& Element = Path[i]; - if (Element.Base->isVirtual()) { - Start = i+1; - QualType VBaseType = Element.Base->getType(); - VBase = cast(VBaseType->getAs()->getDecl()); - } - } - if (VBase) - VirtualOffset = - CGF.GetVirtualBaseClassOffset(BaseValue, ClassDecl, VBase); - - uint64_t Offset = - ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start); - - if (!Offset) - return VirtualOffset; - - const llvm::Type *PtrDiffTy = - CGF.ConvertType(CGF.getContext().getPointerDiffType()); - llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - - if (VirtualOffset) - return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset); - - return NonVirtualOffset; -} - // FIXME: This probably belongs in CGVtable, but it relies on // the static function ComputeNonVirtualBaseClassOffset, so we should make that // a CodeGenModule member function as well. @@ -162,7 +117,37 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, // Just cast back. return Builder.CreateBitCast(Value, BasePtrTy); } + + CXXBasePaths Paths(/*FindAmbiguities=*/false, + /*RecordPaths=*/true, /*DetectVirtual=*/false); + if (!const_cast(Class)-> + isDerivedFrom(const_cast(BaseClass), Paths)) { + assert(false && "Class must be derived from the passed in base class!"); + return 0; + } + + unsigned Start = 0; + llvm::Value *VirtualOffset = 0; + + const CXXBasePath &Path = Paths.front(); + const CXXRecordDecl *VBase = 0; + for (unsigned i = 0, e = Path.size(); i != e; ++i) { + const CXXBasePathElement& Element = Path[i]; + if (Element.Base->isVirtual()) { + Start = i+1; + QualType VBaseType = Element.Base->getType(); + VBase = cast(VBaseType->getAs()->getDecl()); + } + } + + uint64_t Offset = + ComputeNonVirtualBaseClassOffset(getContext(), Paths, Start); + if (!Offset && !VBase) { + // Just cast back. + return Builder.CreateBitCast(Value, BasePtrTy); + } + llvm::BasicBlock *CastNull = 0; llvm::BasicBlock *CastNotNull = 0; llvm::BasicBlock *CastEnd = 0; @@ -179,15 +164,27 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, EmitBlock(CastNotNull); } - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); + if (VBase) + VirtualOffset = GetVirtualBaseClassOffset(Value, Class, VBase); - llvm::Value *Offset = GetBaseClassOffset(*this, Value, Class, BaseClass); + const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + llvm::Value *NonVirtualOffset = 0; + if (Offset) + NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset); - if (Offset) { - // Apply the offset. - Value = Builder.CreateBitCast(Value, Int8PtrTy); - Value = Builder.CreateGEP(Value, Offset, "add.ptr"); - } + llvm::Value *BaseOffset; + if (VBase) { + if (NonVirtualOffset) + BaseOffset = Builder.CreateAdd(VirtualOffset, NonVirtualOffset); + else + BaseOffset = VirtualOffset; + } else + BaseOffset = NonVirtualOffset; + + // Apply the base offset. + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + Value = Builder.CreateBitCast(Value, Int8PtrTy); + Value = Builder.CreateGEP(Value, BaseOffset, "add.ptr"); // Cast back. Value = Builder.CreateBitCast(Value, BasePtrTy); diff --git a/test/CodeGenCXX/derived-to-base.cpp b/test/CodeGenCXX/derived-to-base.cpp index 79aeea70e3..e44fdc5ed2 100644 --- a/test/CodeGenCXX/derived-to-base.cpp +++ b/test/CodeGenCXX/derived-to-base.cpp @@ -21,3 +21,16 @@ B *f(A *a) { // CHECK: ret %struct.B* return static_cast(a); } + +// PR5965 +namespace PR5965 { + +// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) nounwind +A *f(B* b) { + // CHECK-NOT: br label + // CHECK: ret %struct.A* + return b; +} + +} + diff --git a/test/CodeGenCXX/dyncast.cpp b/test/CodeGenCXX/dyncast.cpp index 054b972bb1..c05f3f0244 100644 --- a/test/CodeGenCXX/dyncast.cpp +++ b/test/CodeGenCXX/dyncast.cpp @@ -69,14 +69,7 @@ void test1() { // CHECK-LL-NEXT: [[ep:%.*]] = alloca %class.test1_E*, align 8 // CHECK-LL-NEXT: [[vp:%.*]] = alloca i8*, align 8 // CHECK-LL-NEXT: [[cvp:%.*]] = alloca i8*, align 8 -// CHECK-LL-NEXT: br i1 false, label %[[castnull:.*]], label %[[castnotnull:.*]] -// CHECK-LL: [[castnotnull]] -// CHECK-LL-NEXT: br label %[[castend:.*]] -// CHECK-LL: [[castnull]] -// CHECK-LL-NEXT: br label %[[castend]] -// CHECK-LL: [[castend]] -// CHECK-LL-NEXT: [[v0:%.*]] = phi %class.test1_A* [ bitcast (%class.test1_D* @test1_d to %class.test1_A*), %[[castnotnull]] ], [ null, %[[castnull]] ] -// CHECK-LL-NEXT: store %class.test1_A* [[v0]], %class.test1_A** [[bp]] +// CHECK-LL-NEXT: store %class.test1_A* bitcast (%class.test1_D* @test1_d to %class.test1_A*), %class.test1_A** [[bp]] // CHECK-LL-NEXT: br i1 false, label %[[castnull2:.*]], label %[[castnotnull1:.*]] // CHECK-LL: [[castnotnull1]] // CHECK-LL-NEXT: [[vtable:%.*]] = load i8** bitcast (%class.test1_D* @test1_d to i8**) @@ -333,23 +326,10 @@ void test1() { // CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str1, i32 0, i32 0), i32 12) // CHECK-LL-NEXT: br label %[[ifend113]] // CHECK-LL: [[ifend113]] -// CHECK-LL-NEXT: br i1 false, label %[[castnull116:.*]], label %[[castnotnull115:.*]] -// CHECK-LL: [[castnotnull115]] -// CHECK-LL-NEXT: br label %[[castend117:.*]] -// CHECK-LL: [[castnull116]] -// CHECK-LL-NEXT: br label %[[castend117]] -// CHECK-LL: [[castend117]] -// CHECK-LL-NEXT: [[v62:%.*]] = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %[[castnotnull115]] ], [ null, %[[castnull116]] ] -// CHECK-LL-NEXT: store %class.test1_E* [[v62]], %class.test1_E** [[ep]] +// CHECK-LL-NEXT: store %class.test1_E* bitcast (%class.test1_F* @test1_f to %class.test1_E*), %class.test1_E** [[ep]] // CHECK-LL-NEXT: [[tmp118:%.*]] = load %class.test1_E** [[ep]] -// CHECK-LL-NEXT: br i1 false, label %[[castnull120:.*]], label %[[castnotnull119:.*]] -// CHECK-LL: [[castnotnull119]] -// CHECK-LL-NEXT: br label %[[castend121:.*]] -// CHECK-LL: [[castnull120]] -// CHECK-LL-NEXT: br label %[[castend121]] -// CHECK-LL: [[castend121]] -// CHECK-LL-NEXT: [[v63:%.*]] = phi %class.test1_E* [ bitcast (%class.test1_F* @test1_f to %class.test1_E*), %[[castnotnull119]] ], [ null, %[[castnull120]] ] -// CHECK-LL-NEXT: [[cmp122:%.*]] = icmp eq %class.test1_E* [[tmp118]], [[v63]] +// CHECK-LL-NEXT: [[cmp122:%.*]] = icmp eq %class.test1_E* [[tmp118]], bitcast (%class.test1_F* @test1_f to %class.test1_E*) ; [#uses=1] + // CHECK-LL-NEXT: br i1 [[cmp122]], label %[[ifthen123:.*]], label %[[ifelse125:.*]] // CHECK-LL: [[ifthen123]] // CHECK-LL-NEXT: call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0), i32 13)