Author: pcc Date: Mon Feb 5 15:09:13 2018 New Revision: 324286 URL: http://llvm.org/viewvc/llvm-project?rev=324286&view=rev Log: IRGen: Move vtable load after argument evaluation.
This change reduces the live range of the loaded function pointer, resulting in a slight code size decrease (~10KB in clang), and also improves the security of CFI for virtual calls by making it less likely that the function pointer will be spilled, and ensuring that it is not spilled across a function call boundary. Fixes PR35353. Differential Revision: https://reviews.llvm.org/D42725 Added: cfe/trunk/test/CodeGenCXX/cfi-vcall-check-after-args.cpp Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h cfe/trunk/lib/CodeGen/CGCall.cpp cfe/trunk/lib/CodeGen/CGCall.h cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp cfe/trunk/test/CodeGenCXX/cxx2a-destroying-delete.cpp cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original) +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Mon Feb 5 15:09:13 2018 @@ -413,11 +413,10 @@ public: CharUnits VPtrOffset) = 0; /// Build a virtual function pointer in the ABI-specific way. - virtual CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, - GlobalDecl GD, - Address This, - llvm::Type *Ty, - SourceLocation Loc) = 0; + virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, + GlobalDecl GD, Address This, + llvm::Type *Ty, + SourceLocation Loc) = 0; /// Emit the ABI-specific virtual destructor call. virtual llvm::Value * Modified: cfe/trunk/lib/CodeGen/CGCall.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.cpp (original) +++ cfe/trunk/lib/CodeGen/CGCall.cpp Mon Feb 5 15:09:13 2018 @@ -3728,7 +3728,7 @@ RValue CodeGenFunction::EmitCall(const C SourceLocation Loc) { // FIXME: We no longer need the types from CallArgs; lift up and simplify. - assert(Callee.isOrdinary()); + assert(Callee.isOrdinary() || Callee.isVirtual()); // Handle struct-return functions by passing a pointer to the // location that we would like to return into. @@ -4052,7 +4052,14 @@ RValue CodeGenFunction::EmitCall(const C } } - llvm::Value *CalleePtr = Callee.getFunctionPointer(); + llvm::Value *CalleePtr; + if (Callee.isVirtual()) { + const CallExpr *CE = Callee.getVirtualCallExpr(); + CalleePtr = CGM.getCXXABI().getVirtualFunctionPointer( + *this, Callee.getVirtualMethodDecl(), Callee.getThisAddress(), + Callee.getFunctionType(), CE ? CE->getLocStart() : SourceLocation()); + } else + CalleePtr = Callee.getFunctionPointer(); // If we're using inalloca, set up that argument. if (ArgMemory.isValid()) { Modified: cfe/trunk/lib/CodeGen/CGCall.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.h?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGCall.h (original) +++ cfe/trunk/lib/CodeGen/CGCall.h Mon Feb 5 15:09:13 2018 @@ -18,6 +18,7 @@ #include "CGValue.h" #include "EHScopeStack.h" #include "clang/AST/CanonicalType.h" +#include "clang/AST/GlobalDecl.h" #include "clang/AST/Type.h" #include "llvm/IR/Value.h" @@ -68,8 +69,9 @@ public: Invalid, Builtin, PseudoDestructor, + Virtual, - Last = PseudoDestructor + Last = Virtual }; struct BuiltinInfoStorage { @@ -79,12 +81,19 @@ public: struct PseudoDestructorInfoStorage { const CXXPseudoDestructorExpr *Expr; }; + struct VirtualInfoStorage { + const CallExpr *CE; + GlobalDecl MD; + Address Addr; + llvm::FunctionType *FTy; + }; SpecialKind KindOrFunctionPointer; union { CGCalleeInfo AbstractInfo; BuiltinInfoStorage BuiltinInfo; PseudoDestructorInfoStorage PseudoDestructorInfo; + VirtualInfoStorage VirtualInfo; }; explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {} @@ -127,6 +136,16 @@ public: return CGCallee(abstractInfo, functionPtr); } + static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr, + llvm::FunctionType *FTy) { + CGCallee result(SpecialKind::Virtual); + result.VirtualInfo.CE = CE; + result.VirtualInfo.MD = MD; + result.VirtualInfo.Addr = Addr; + result.VirtualInfo.FTy = FTy; + return result; + } + bool isBuiltin() const { return KindOrFunctionPointer == SpecialKind::Builtin; } @@ -150,7 +169,9 @@ public: bool isOrdinary() const { return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last); } - const CGCalleeInfo &getAbstractInfo() const { + CGCalleeInfo getAbstractInfo() const { + if (isVirtual()) + return VirtualInfo.MD.getDecl(); assert(isOrdinary()); return AbstractInfo; } @@ -158,14 +179,33 @@ public: assert(isOrdinary()); return reinterpret_cast<llvm::Value*>(uintptr_t(KindOrFunctionPointer)); } - llvm::FunctionType *getFunctionType() const { - return cast<llvm::FunctionType>( - getFunctionPointer()->getType()->getPointerElementType()); - } void setFunctionPointer(llvm::Value *functionPtr) { assert(isOrdinary()); KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr)); } + + bool isVirtual() const { + return KindOrFunctionPointer == SpecialKind::Virtual; + } + const CallExpr *getVirtualCallExpr() const { + assert(isVirtual()); + return VirtualInfo.CE; + } + GlobalDecl getVirtualMethodDecl() const { + assert(isVirtual()); + return VirtualInfo.MD; + } + Address getThisAddress() const { + assert(isVirtual()); + return VirtualInfo.Addr; + } + + llvm::FunctionType *getFunctionType() const { + if (isVirtual()) + return VirtualInfo.FTy; + return cast<llvm::FunctionType>( + getFunctionPointer()->getType()->getPointerElementType()); + } }; struct CallArg { Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Mon Feb 5 15:09:13 2018 @@ -371,9 +371,7 @@ RValue CodeGenFunction::EmitCXXMemberOrO CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty), Ctor); } else if (UseVirtualCall) { - Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, - This.getAddress(), Ty, - CE->getLocStart()); + Callee = CGCallee::forVirtual(CE, MD, This.getAddress(), Ty); } else { if (SanOpts.has(SanitizerKind::CFINVCall) && MD->getParent()->isDynamicClass()) { Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Mon Feb 5 15:09:13 2018 @@ -280,9 +280,9 @@ public: llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; - CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, - Address This, llvm::Type *Ty, - SourceLocation Loc) override; + llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, + Address This, llvm::Type *Ty, + SourceLocation Loc) override; llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, @@ -1651,47 +1651,42 @@ llvm::GlobalVariable *ItaniumCXXABI::get return VTable; } -CGCallee ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, - GlobalDecl GD, - Address This, - llvm::Type *Ty, - SourceLocation Loc) { +llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, + GlobalDecl GD, + Address This, + llvm::Type *Ty, + SourceLocation Loc) { GD = GD.getCanonicalDecl(); Ty = Ty->getPointerTo()->getPointerTo(); auto *MethodDecl = cast<CXXMethodDecl>(GD.getDecl()); llvm::Value *VTable = CGF.GetVTablePtr(This, Ty, MethodDecl->getParent()); uint64_t VTableIndex = CGM.getItaniumVTableContext().getMethodVTableIndex(GD); - llvm::Value *VFunc; - if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) { - VFunc = CGF.EmitVTableTypeCheckedLoad( + if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) + return CGF.EmitVTableTypeCheckedLoad( MethodDecl->getParent(), VTable, VTableIndex * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8); - } else { - CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc); - llvm::Value *VFuncPtr = - CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); - auto *VFuncLoad = - CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); - - // Add !invariant.load md to virtual function load to indicate that - // function didn't change inside vtable. - // It's safe to add it without -fstrict-vtable-pointers, but it would not - // help in devirtualization because it will only matter if we will have 2 - // the same virtual function loads from the same vtable load, which won't - // happen without enabled devirtualization with -fstrict-vtable-pointers. - if (CGM.getCodeGenOpts().OptimizationLevel > 0 && - CGM.getCodeGenOpts().StrictVTablePointers) - VFuncLoad->setMetadata( - llvm::LLVMContext::MD_invariant_load, - llvm::MDNode::get(CGM.getLLVMContext(), - llvm::ArrayRef<llvm::Metadata *>())); - VFunc = VFuncLoad; - } + CGF.EmitTypeMetadataCodeForVCall(MethodDecl->getParent(), VTable, Loc); - CGCallee Callee(MethodDecl, VFunc); - return Callee; + llvm::Value *VFuncPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); + auto *VFuncLoad = + CGF.Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); + + // Add !invariant.load md to virtual function load to indicate that + // function didn't change inside vtable. + // It's safe to add it without -fstrict-vtable-pointers, but it would not + // help in devirtualization because it will only matter if we will have 2 + // the same virtual function loads from the same vtable load, which won't + // happen without enabled devirtualization with -fstrict-vtable-pointers. + if (CGM.getCodeGenOpts().OptimizationLevel > 0 && + CGM.getCodeGenOpts().StrictVTablePointers) + VFuncLoad->setMetadata( + llvm::LLVMContext::MD_invariant_load, + llvm::MDNode::get(CGM.getLLVMContext(), + llvm::ArrayRef<llvm::Metadata *>())); + return VFuncLoad; } llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( @@ -1702,10 +1697,10 @@ llvm::Value *ItaniumCXXABI::EmitVirtualD const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration( Dtor, getFromDtorType(DtorType)); - llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); + auto *Ty = + cast<llvm::FunctionType>(CGF.CGM.getTypes().GetFunctionType(*FInfo)); CGCallee Callee = - getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty, - CE ? CE->getLocStart() : SourceLocation()); + CGCallee::forVirtual(CE, GlobalDecl(Dtor, DtorType), This, Ty); CGF.EmitCXXMemberOrOperatorCall(Dtor, Callee, ReturnValueSlot(), This.getPointer(), /*ImplicitParam=*/nullptr, Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Mon Feb 5 15:09:13 2018 @@ -285,9 +285,9 @@ public: llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; - CGCallee getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, - Address This, llvm::Type *Ty, - SourceLocation Loc) override; + llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, + Address This, llvm::Type *Ty, + SourceLocation Loc) override; llvm::Value *EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, @@ -1827,11 +1827,11 @@ llvm::GlobalVariable *MicrosoftCXXABI::g return VTable; } -CGCallee MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, - GlobalDecl GD, - Address This, - llvm::Type *Ty, - SourceLocation Loc) { +llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, + GlobalDecl GD, + Address This, + llvm::Type *Ty, + SourceLocation Loc) { GD = GD.getCanonicalDecl(); CGBuilderTy &Builder = CGF.Builder; @@ -1858,22 +1858,17 @@ CGCallee MicrosoftCXXABI::getVirtualFunc ->ObjectWithVPtr; }; - llvm::Value *VFunc; - if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) { - VFunc = CGF.EmitVTableTypeCheckedLoad( + if (CGF.ShouldEmitVTableTypeCheckedLoad(MethodDecl->getParent())) + return CGF.EmitVTableTypeCheckedLoad( getObjectWithVPtr(), VTable, ML.Index * CGM.getContext().getTargetInfo().getPointerWidth(0) / 8); - } else { - if (CGM.getCodeGenOpts().PrepareForLTO) - CGF.EmitTypeMetadataCodeForVCall(getObjectWithVPtr(), VTable, Loc); - llvm::Value *VFuncPtr = - Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn"); - VFunc = Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); - } + if (CGM.getCodeGenOpts().PrepareForLTO) + CGF.EmitTypeMetadataCodeForVCall(getObjectWithVPtr(), VTable, Loc); - CGCallee Callee(MethodDecl, VFunc); - return Callee; + llvm::Value *VFuncPtr = + Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn"); + return Builder.CreateAlignedLoad(VFuncPtr, CGF.getPointerAlign()); } llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( @@ -1887,9 +1882,9 @@ llvm::Value *MicrosoftCXXABI::EmitVirtua GlobalDecl GD(Dtor, Dtor_Deleting); const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXStructorDeclaration( Dtor, StructorType::Deleting); - llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); - CGCallee Callee = getVirtualFunctionPointer( - CGF, GD, This, Ty, CE ? CE->getLocStart() : SourceLocation()); + auto *Ty = + cast<llvm::FunctionType>(CGF.CGM.getTypes().GetFunctionType(*FInfo)); + CGCallee Callee = CGCallee::forVirtual(CE, GD, This, Ty); ASTContext &Context = getContext(); llvm::Value *ImplicitParam = llvm::ConstantInt::get( Added: cfe/trunk/test/CodeGenCXX/cfi-vcall-check-after-args.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cfi-vcall-check-after-args.cpp?rev=324286&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/cfi-vcall-check-after-args.cpp (added) +++ cfe/trunk/test/CodeGenCXX/cfi-vcall-check-after-args.cpp Mon Feb 5 15:09:13 2018 @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -flto -flto-unit -triple x86_64-unknown-linux -fvisibility hidden -fsanitize=cfi-vcall -fsanitize-trap=cfi-vcall -emit-llvm -o - %s | FileCheck %s + +struct A { + virtual void f(int); +}; + +int g(); +void f(A *a) { + // CHECK: call i32 @_Z1gv() + // CHECK: call i1 @llvm.type.test + a->f(g()); +} Modified: cfe/trunk/test/CodeGenCXX/cxx2a-destroying-delete.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx2a-destroying-delete.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/cxx2a-destroying-delete.cpp (original) +++ cfe/trunk/test/CodeGenCXX/cxx2a-destroying-delete.cpp Mon Feb 5 15:09:13 2018 @@ -78,15 +78,15 @@ void delete_D(D *d) { delete d; } // CHECK: br i1 // // CHECK-NOT: call -// CHECK: %[[VTABLE:.*]] = load -// CHECK: %[[DTOR:.*]] = load -// // For MS, we don't add a new vtable slot to the primary vtable for the virtual // destructor. Instead we cast to the VDel base class. // CHECK-MSABI: bitcast {{.*}} %[[d]] // CHECK-MSABI-NEXT: getelementptr {{.*}}, i64 8 // CHECK-MSABI-NEXT: %[[d:.*]] = bitcast i8* // +// CHECK: %[[VTABLE:.*]] = load +// CHECK: %[[DTOR:.*]] = load +// // CHECK: call {{void|i8\*}} %[[DTOR]](%{{.*}}* %[[d]] // CHECK-MSABI-SAME: , i32 1) // CHECK-NOT: call Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp (original) +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp Mon Feb 5 15:09:13 2018 @@ -114,16 +114,15 @@ void call_right_override(ChildOverride * // the caller site. // // CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* +// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8, i8* %[[CHILD_i8]], i32 4 // +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* // CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8, i8* %[[CHILD_i8]], i32 4 // CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to void (i8*)*** // CHECK: %[[VFTABLE:.*]] = load void (i8*)**, void (i8*)*** %[[VFPTR]] // CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)*, void (i8*)** %[[VFTABLE]], i64 0 // CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)*, void (i8*)** %[[VFUN]] // -// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* -// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8, i8* %[[CHILD_i8]], i32 4 -// // CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[RIGHT]]) // CHECK: ret } Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp (original) +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp Mon Feb 5 15:09:13 2018 @@ -163,11 +163,7 @@ void call_vbase_bar(B *obj) { // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, i32* %[[VBTABLE]], i32 1 // CHECK: %[[VBOFFSET32:.*]] = load i32, i32* %[[VBENTRY]] // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] -// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] -// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)*** -// CHECK: %[[VFTABLE:.*]] = load void (i8*)**, void (i8*)*** %[[VFPTR]] -// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)*, void (i8*)** %[[VFTABLE]], i64 2 -// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)*, void (i8*)** %[[VFUN]] +// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] // // CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 0 @@ -176,7 +172,11 @@ void call_vbase_bar(B *obj) { // CHECK: %[[VBENTRY:.*]] = getelementptr inbounds i32, i32* %[[VBTABLE]], i32 1 // CHECK: %[[VBOFFSET32:.*]] = load i32, i32* %[[VBENTRY]] // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] -// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)*** +// CHECK: %[[VFTABLE:.*]] = load void (i8*)**, void (i8*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)*, void (i8*)** %[[VFTABLE]], i64 2 +// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)*, void (i8*)** %[[VFUN]] // // CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[VBASE]]) // @@ -196,10 +196,7 @@ void delete_B(B *obj) { // CHECK: %[[VBOFFSET32:.*]] = load i32, i32* %[[VBENTRY]] // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] -// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to i8* (%struct.B*, i32)*** -// CHECK: %[[VFTABLE:.*]] = load i8* (%struct.B*, i32)**, i8* (%struct.B*, i32)*** %[[VFPTR]] -// CHECK: %[[VFUN:.*]] = getelementptr inbounds i8* (%struct.B*, i32)*, i8* (%struct.B*, i32)** %[[VFTABLE]], i64 0 -// CHECK: %[[VFUN_VALUE:.*]] = load i8* (%struct.B*, i32)*, i8* (%struct.B*, i32)** %[[VFUN]] +// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.B* // // CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* // CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 0 @@ -209,7 +206,10 @@ void delete_B(B *obj) { // CHECK: %[[VBOFFSET32:.*]] = load i32, i32* %[[VBENTRY]] // CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] // CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] -// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.B* +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to i8* (%struct.B*, i32)*** +// CHECK: %[[VFTABLE:.*]] = load i8* (%struct.B*, i32)**, i8* (%struct.B*, i32)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds i8* (%struct.B*, i32)*, i8* (%struct.B*, i32)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load i8* (%struct.B*, i32)*, i8* (%struct.B*, i32)** %[[VFUN]] // // CHECK: call x86_thiscallcc i8* %[[VFUN_VALUE]](%struct.B* %[[VBASE]], i32 1) // CHECK: ret void @@ -457,16 +457,16 @@ void destroy(E *obj) { // CHECK-LABEL: define void @"\01?destroy@test4@@YAXPAUE@1@@Z"(%"struct.test4::E"* %obj) // CHECK-NOT: getelementptr + // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ]] to i8* + // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 4 + // FIXME: in fact, the call should take i8* and the bitcast is redundant. + // CHECK: %[[B_as_E:.*]] = bitcast i8* %[[B_i8]] to %"struct.test4::E"* // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ:.*]] to i8* // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 4 // CHECK: %[[VPTR:.*]] = bitcast i8* %[[B_i8]] to i8* (%"struct.test4::E"*, i32)*** // CHECK: %[[VFTABLE:.*]] = load i8* (%"struct.test4::E"*, i32)**, i8* (%"struct.test4::E"*, i32)*** %[[VPTR]] // CHECK: %[[VFTENTRY:.*]] = getelementptr inbounds i8* (%"struct.test4::E"*, i32)*, i8* (%"struct.test4::E"*, i32)** %[[VFTABLE]], i64 0 // CHECK: %[[VFUN:.*]] = load i8* (%"struct.test4::E"*, i32)*, i8* (%"struct.test4::E"*, i32)** %[[VFTENTRY]] - // CHECK: %[[OBJ_i8:.*]] = bitcast %"struct.test4::E"* %[[OBJ]] to i8* - // CHECK: %[[B_i8:.*]] = getelementptr inbounds i8, i8* %[[OBJ_i8]], i32 4 - // FIXME: in fact, the call should take i8* and the bitcast is redundant. - // CHECK: %[[B_as_E:.*]] = bitcast i8* %[[B_i8]] to %"struct.test4::E"* // CHECK: call x86_thiscallcc i8* %[[VFUN]](%"struct.test4::E"* %[[B_as_E]], i32 1) delete obj; } Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp?rev=324286&r1=324285&r2=324286&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp (original) +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-vtables-multiple-nonvirtual-inheritance-this-adjustment.cpp Mon Feb 5 15:09:13 2018 @@ -156,23 +156,17 @@ struct C : public A, public B { // BITCODE-LABEL: define {{.*}}\01?ffun@test4@@YAXAAUC@1@@Z void ffun(C &c) { - // BITCODE: load - // BITCODE: bitcast - // BITCODE: bitcast // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8* // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, i8* [[THIS1]], i32 4 - // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]]) + // BITCODE: call x86_thiscallcc {{.*}}(i8* [[THIS2]]) c.bar(); } // BITCODE-LABEL: define {{.*}}\01?fop@test4@@YAXAAUC@1@@Z void fop(C &c) { - // BITCODE: load - // BITCODE: bitcast - // BITCODE: bitcast // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8* // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, i8* [[THIS1]], i32 4 - // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]]) + // BITCODE: call x86_thiscallcc {{.*}}(i8* [[THIS2]]) -c; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits