From: Piotr Padlewski Date: Tue, 15 Sep 2015 21:46:47 +0000 (+0000) Subject: Emiting llvm.invariant.group.barrier when dynamic type changes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ac87852f578b4fc948e6d38bacdf439b1b5658b5;p=clang 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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247723 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index af46a8eeda..8c15cef8ef 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -862,6 +862,8 @@ def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group, def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group; def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group; def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group; +def fno_strict_vtable_pointers: Flag<["-"], "fno-strict-vtable-pointers">, + Group; def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group; def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group, Flags<[CC1Option]>, HelpText<"Do not emit code to make initialization of local statics thread safe">; @@ -990,6 +992,10 @@ def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group, def fstrict_enums : Flag<["-"], "fstrict-enums">, 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, Flags<[CC1Option]>, + HelpText<"Enable optimizations based on the strict rules for overwriting " + "polymorphic C++ objects">; def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group; def fsyntax_only : Flag<["-"], "fsyntax-only">, Flags<[DriverOption,CoreOption,CC1Option]>, Group; diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def index 5870621c15..7c00756090 100644 --- a/include/clang/Frontend/CodeGenOptions.def +++ b/include/clang/Frontend/CodeGenOptions.def @@ -132,6 +132,7 @@ CODEGENOPT(SanitizeCoverage8bitCounters, 1, 0) ///< Use 8-bit frequency counters 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. diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 6c9f404eab..4c46d56590 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1344,6 +1344,13 @@ namespace { } +static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) { + const Type *BaseType = BaseInit->getBaseClass(); + const auto *BaseClassDecl = + cast(BaseType->getAs()->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(const CXXConstructorDecl *CD, 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(const CXXConstructorDecl *CD, 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 &Context, /// 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(FunctionArgList &Args) { 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(Body)->getTryBlock()); diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 8b060ce287..1952282a07 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -1381,6 +1381,14 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { 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()) { diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index db29be1367..755ea1b9b3 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -3443,6 +3443,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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"); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 7caa709596..81a12caece 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -494,6 +494,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, 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); diff --git a/test/CodeGenCXX/strict-vtable-pointers.cpp b/test/CodeGenCXX/strict-vtable-pointers.cpp new file mode 100644 index 0000000000..e84afa0333 --- /dev/null +++ b/test/CodeGenCXX/strict-vtable-pointers.cpp @@ -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: }