r247723 - Emiting llvm.invariant.group.barrier when dynamic type changes
Piotr Padlewski via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 15 14:46:47 PDT 2015
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: }
More information about the cfe-commits
mailing list