Author: prazek Date: Tue Sep 15 16:46:47 2015 New Revision: 247723 URL: http://llvm.org/viewvc/llvm-project?rev=247723&view=rev Log: Emiting llvm.invariant.group.barrier when dynamic type changes
For more goto: http://lists.llvm.org/pipermail/cfe-dev/2015-July/044227.html http://reviews.llvm.org/D12312 Added: cfe/trunk/test/CodeGenCXX/strict-vtable-pointers.cpp Modified: cfe/trunk/include/clang/Driver/Options.td cfe/trunk/include/clang/Frontend/CodeGenOptions.def cfe/trunk/lib/CodeGen/CGClass.cpp cfe/trunk/lib/CodeGen/CGExprCXX.cpp cfe/trunk/lib/Driver/Tools.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp Modified: cfe/trunk/include/clang/Driver/Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=247723&r1=247722&r2=247723&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/Options.td (original) +++ cfe/trunk/include/clang/Driver/Options.td Tue Sep 15 16:46:47 2015 @@ -862,6 +862,8 @@ def fno_strict_aliasing : Flag<["-"], "f def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>; def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group<f_Group>; def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>; +def fno_strict_vtable_pointers: Flag<["-"], "fno-strict-vtable-pointers">, + Group<f_Group>; def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>; def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">; @@ -990,6 +992,10 @@ def fstrict_aliasing : Flag<["-"], "fstr def fstrict_enums : Flag<["-"], "fstrict-enums">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Enable optimizations based on the strict definition of an enum's " "value range">; +def fstrict_vtable_pointers: Flag<["-"], "fstrict-vtable-pointers">, + Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Enable optimizations based on the strict rules for overwriting " + "polymorphic C++ objects">; def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>; def fsyntax_only : Flag<["-"], "fsyntax-only">, Flags<[DriverOption,CoreOption,CC1Option]>, Group<Action_Group>; Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=247723&r1=247722&r2=247723&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original) +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Tue Sep 15 16:46:47 2015 @@ -132,6 +132,7 @@ CODEGENOPT(SanitizeCoverage8bitCounters, CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. CODEGENOPT(StrictEnums , 1, 0) ///< Optimize based on strict enum definition. +CODEGENOPT(StrictVTablePointers, 1, 0) ///< Optimize based on the strict vtable pointers CODEGENOPT(TimePasses , 1, 0) ///< Set when -ftime-report is enabled. CODEGENOPT(UnitAtATime , 1, 1) ///< Unused. For mirroring GCC optimization ///< selection. Modified: cfe/trunk/lib/CodeGen/CGClass.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=247723&r1=247722&r2=247723&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGClass.cpp (original) +++ cfe/trunk/lib/CodeGen/CGClass.cpp Tue Sep 15 16:46:47 2015 @@ -1344,6 +1344,13 @@ namespace { } +static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) { + const Type *BaseType = BaseInit->getBaseClass(); + const auto *BaseClassDecl = + cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + return BaseClassDecl->isDynamicClass(); +} + /// EmitCtorPrologue - This routine generates necessary code to initialize /// base classes and non-static data members belonging to this constructor. void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, @@ -1367,9 +1374,13 @@ void CodeGenFunction::EmitCtorPrologue(c assert(BaseCtorContinueBB); } + bool BaseVPtrsInitialized = false; // Virtual base initializers first. for (; B != E && (*B)->isBaseInitializer() && (*B)->isBaseVirtual(); B++) { + CXXCtorInitializer *BaseInit = *B; EmitBaseInitializer(*this, ClassDecl, *B, CtorType); + BaseVPtrsInitialized |= BaseInitializerUsesThis(getContext(), + BaseInit->getInit()); } if (BaseCtorContinueBB) { @@ -1382,8 +1393,15 @@ void CodeGenFunction::EmitCtorPrologue(c for (; B != E && (*B)->isBaseInitializer(); B++) { assert(!(*B)->isBaseVirtual()); EmitBaseInitializer(*this, ClassDecl, *B, CtorType); + BaseVPtrsInitialized |= isInitializerOfDynamicClass(*B); } + // Pointer to this requires to be passed through invariant.group.barrier + // only if we've initialized any base vptrs. + if (CGM.getCodeGenOpts().StrictVTablePointers && + CGM.getCodeGenOpts().OptimizationLevel > 0 && BaseVPtrsInitialized) + CXXThisValue = Builder.CreateInvariantGroupBarrier(LoadCXXThis()); + InitializeVTablePointers(ClassDecl); // And finally, initialize class members. @@ -1468,11 +1486,14 @@ FieldHasTrivialDestructorBody(ASTContext /// any vtable pointers before calling this destructor. static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor) { + const CXXRecordDecl *ClassDecl = Dtor->getParent(); + if (!ClassDecl->isDynamicClass()) + return true; + if (!Dtor->hasTrivialBody()) return false; // Check the fields. - const CXXRecordDecl *ClassDecl = Dtor->getParent(); for (const auto *Field : ClassDecl->fields()) if (!FieldHasTrivialDestructorBody(CGF.getContext(), Field)) return false; @@ -1543,8 +1564,14 @@ void CodeGenFunction::EmitDestructorBody EnterDtorCleanups(Dtor, Dtor_Base); // Initialize the vtable pointers before entering the body. - if (!CanSkipVTablePointerInitialization(*this, Dtor)) - InitializeVTablePointers(Dtor->getParent()); + if (!CanSkipVTablePointerInitialization(*this, Dtor)) { + // Insert the llvm.invariant.group.barrier intrinsic before initializing + // the vptrs to cancel any previous assumptions we might have made. + if (CGM.getCodeGenOpts().StrictVTablePointers && + CGM.getCodeGenOpts().OptimizationLevel > 0) + CXXThisValue = Builder.CreateInvariantGroupBarrier(LoadCXXThis()); + InitializeVTablePointers(Dtor->getParent()); + } if (isTryBody) EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock()); Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=247723&r1=247722&r2=247723&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Sep 15 16:46:47 2015 @@ -1381,6 +1381,14 @@ llvm::Value *CodeGenFunction::EmitCXXNew llvm::Type *elementTy = ConvertTypeForMem(allocType); Address result = Builder.CreateElementBitCast(allocation, elementTy); + // Passing pointer through invariant.group.barrier to avoid propagation of + // vptrs information which may be included in previous type. + if (CGM.getCodeGenOpts().StrictVTablePointers && + CGM.getCodeGenOpts().OptimizationLevel > 0 && + allocator->isReservedGlobalPlacementOperator()) + result = Address(Builder.CreateInvariantGroupBarrier(result.getPointer()), + result.getAlignment()); + EmitNewInitializer(*this, E, allocType, elementTy, result, numElements, allocSizeWithoutCookie); if (E->isArray()) { Modified: cfe/trunk/lib/Driver/Tools.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=247723&r1=247722&r2=247723&view=diff ============================================================================== --- cfe/trunk/lib/Driver/Tools.cpp (original) +++ cfe/trunk/lib/Driver/Tools.cpp Tue Sep 15 16:46:47 2015 @@ -3443,6 +3443,10 @@ void Clang::ConstructJob(Compilation &C, if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, false)) CmdArgs.push_back("-fstrict-enums"); + if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, + options::OPT_fno_strict_vtable_pointers, + false)) + CmdArgs.push_back("-fstrict-vtable-pointers"); if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=247723&r1=247722&r2=247723&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Tue Sep 15 16:46:47 2015 @@ -494,6 +494,7 @@ static bool ParseCodeGenArgs(CodeGenOpti Opts.NoDwarfDirectoryAsm = Args.hasArg(OPT_fno_dwarf_directory_asm); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.StrictEnums = Args.hasArg(OPT_fstrict_enums); + Opts.StrictVTablePointers = Args.hasArg(OPT_fstrict_vtable_pointers); Opts.UnsafeFPMath = Args.hasArg(OPT_menable_unsafe_fp_math) || Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); Added: cfe/trunk/test/CodeGenCXX/strict-vtable-pointers.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/strict-vtable-pointers.cpp?rev=247723&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/strict-vtable-pointers.cpp (added) +++ cfe/trunk/test/CodeGenCXX/strict-vtable-pointers.cpp Tue Sep 15 16:46:47 2015 @@ -0,0 +1,193 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fstrict-vtable-pointers -disable-llvm-optzns -O2 -emit-llvm -o %t.ll +// RUN: FileCheck --check-prefix=CHECK-CTORS %s < %t.ll +// RUN: FileCheck --check-prefix=CHECK-NEW %s < %t.ll +// RUN: FileCheck --check-prefix=CHECK-DTORS %s < %t.ll + +typedef __typeof__(sizeof(0)) size_t; +void *operator new(size_t, void*) throw(); + +struct NotTrivialDtor { + ~NotTrivialDtor(); +}; + +struct DynamicBase1 { + NotTrivialDtor obj; + virtual void foo(); +}; + +struct DynamicDerived : DynamicBase1 { + void foo(); +}; + +struct DynamicBase2 { + virtual void bar(); + ~DynamicBase2() { + bar(); + } +}; + +struct DynamicDerivedMultiple : DynamicBase1, DynamicBase2 { + virtual void foo(); + virtual void bar(); +}; + +struct StaticBase { + NotTrivialDtor obj; + void bar(); +}; + +struct DynamicFromStatic : StaticBase { + virtual void bar(); +}; + +struct DynamicFromVirtualStatic1 : virtual StaticBase { +}; + +struct DynamicFromVirtualStatic2 : virtual StaticBase { +}; + +struct DynamicFrom2Virtuals : + DynamicFromVirtualStatic1, + DynamicFromVirtualStatic2 { +}; + +// CHECK-NEW-LABEL: define void @_Z12LocalObjectsv() +// CHECK-NEW-NOT: @llvm.invariant.group.barrier( +// CHECK-NEW-LABEL: } +void LocalObjects() { + DynamicBase1 DB; + DB.foo(); + DynamicDerived DD; + DD.foo(); + + DynamicBase2 DB2; + DB2.bar(); + + StaticBase SB; + SB.bar(); + + DynamicDerivedMultiple DDM; + DDM.foo(); + DDM.bar(); + + DynamicFromStatic DFS; + DFS.bar(); + DynamicFromVirtualStatic1 DFVS1; + DFVS1.bar(); + DynamicFrom2Virtuals DF2V; + DF2V.bar(); +} + +struct DynamicFromVirtualStatic1; +// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN25DynamicFromVirtualStatic1C1Ev +// CHECK-CTORS-NOT: @llvm.invariant.group.barrier( +// CHECK-CTORS-LABEL: } + +struct DynamicFrom2Virtuals; +// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN20DynamicFrom2VirtualsC1Ev +// CHECK-CTORS: call i8* @llvm.invariant.group.barrier( +// CHECK-CTORS-LABEL: } + + +// CHECK-NEW-LABEL: define void @_Z9Pointers1v() +// CHECK-NEW-NOT: @llvm.invariant.group.barrier( +// CHECK-NEW-LABEL: call void @_ZN12DynamicBase1C1Ev( + +// CHECK-NEW: %[[THIS3:.*]] = call i8* @llvm.invariant.group.barrier(i8* %[[THIS2:.*]]) +// CHECK-NEW: %[[THIS4:.*]] = bitcast i8* %[[THIS3]] to %[[DynamicDerived:.*]]* +// CHECK-NEW: call void @_ZN14DynamicDerivedC1Ev(%[[DynamicDerived:.*]]* %[[THIS4]]) +// CHECK-NEW-LABEL: } +void Pointers1() { + DynamicBase1 *DB = new DynamicBase1; + DB->foo(); + + DynamicDerived *DD = new (DB) DynamicDerived; + DD->foo(); + DD->~DynamicDerived(); +} + +// CHECK-NEW-LABEL: define void @_Z14HackingObjectsv() +// CHECK-NEW: call void @_ZN12DynamicBase1C1Ev +// CHECK-NEW: call i8* @llvm.invariant.group.barrier( +// CHECK-NEW: call void @_ZN14DynamicDerivedC1Ev( +// CHECK-NEW: call i8* @llvm.invariant.group.barrier( +// CHECK-NEW: call void @_ZN12DynamicBase1C1Ev( +// CHECK-NEW-LABEL: } +void HackingObjects() { + DynamicBase1 DB; + DB.foo(); + + DynamicDerived *DB2 = new (&DB) DynamicDerived; + // Using DB now is prohibited. + DB2->foo(); + DB2->~DynamicDerived(); + + // We have to get back to the previous type to avoid calling wrong destructor + new (&DB) DynamicBase1; + DB.foo(); +} + +/*** Testing Constructors ***/ +struct DynamicBase1; +// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase1C2Ev( +// CHECK-CTORS-NOT: call i8* @llvm.invariant.group.barrier( +// CHECK-CTORS-LABEL: } + + +struct DynamicDerived; +// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN14DynamicDerivedC2Ev( +// CHECK-CTORS: call void @_ZN12DynamicBase1C2Ev( +// CHECK-CTORS: %[[THIS1:.*]] = bitcast %[[DynamicDerived:.*]]* %[[THIS0:.*]] to i8* +// CHECK-CTORS: %[[THIS2:.*]] = call i8* @llvm.invariant.group.barrier(i8* %[[THIS1:.*]]) +// CHECK-CTORS: %[[THIS3:.*]] = bitcast i8* %[[THIS2:.*]] to %[[DynamicDerived]]* +// CHECK-CTORS: %[[THIS4:.*]] = bitcast %struct.DynamicDerived* %[[THIS3:.*]] to i32 (...)*** +// CHECK-CTORS: store {{.*}} %[[THIS4:.*]] +// CHECK-CTORS-LABEL: } + +struct DynamicDerivedMultiple; +// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN22DynamicDerivedMultipleC2Ev +// CHECK-CTORS: call void @_ZN12DynamicBase1C2Ev( +// CHECK-CTORS-NOT: @llvm.invariant.group.barrier +// CHECK-CTORS-LABEL: call void @_ZN12DynamicBase2C2Ev( +// CHECK-CTORS: %[[THIS1:.*]] = bitcast %[[CLASS:.*]]* %[[THIS0:.*]] to i8* +// CHECK-CTORS: %[[THIS2:.*]] = call i8* @llvm.invariant.group.barrier(i8* %[[THIS1:.*]]) +// CHECK-CTORS: %[[THIS3:.*]] = bitcast i8* %[[THIS2:.*]] to %[[CLASS]]* +// CHECK-CTORS-NOT: invariant.group.barrier +// CHECK-CTORS: store {{.*}} @_ZTV22DynamicDerivedMultiple, i64 0, i64 2) +// CHECK-CTORS: store {{.*}} @_ZTV22DynamicDerivedMultiple, i64 0, i64 6) +// CHECK-CTORS-LABEL: } + +struct DynamicFromStatic; +// CHECK-CTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticC2Ev( +// CHECK-CTORS-NOT: @llvm.invariant.group.barrier( +// CHECK-CTORS-LABEL: } + + +/** DTORS **/ +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN10StaticBaseD2Ev( +// CHECK-DTORS-NOT: call i8* @llvm.invariant.group.barrier( +// CHECK-DTORS-LABEL: } + + +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN25DynamicFromVirtualStatic2D2Ev( +// CHECK-DTORS-NOT: invariant.barrier +// CHECK-DTORS-LABEL: } + +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN17DynamicFromStaticD2Ev +// CHECK-DTORS-NOT: call i8* @llvm.invariant.group.barrier( +// CHECK-DTORS-LABEL: } + + +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN22DynamicDerivedMultipleD2Ev( + +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase2D2Ev( +// CHECK-DTORS: call i8* @llvm.invariant.group.barrier( +// CHECK-DTORS-LABEL: } + +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN12DynamicBase1D2Ev +// CHECK-DTORS: call i8* @llvm.invariant.group.barrier( +// CHECK-DTORS-LABEL: } + +// CHECK-DTORS-LABEL: define linkonce_odr void @_ZN14DynamicDerivedD2Ev +// CHECK-DTORS-NOT: call i8* @llvm.invariant.group.barrier( +// CHECK-DTORS-LABEL: } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits