forked from OSchip/llvm-project
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 llvm-svn: 247723
This commit is contained in:
parent
68615ce606
commit
338c9d0ade
|
@ -862,6 +862,8 @@ def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>,
|
|||
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<["-"], "fstrict-aliasing">, Group<f_Group>,
|
|||
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>;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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(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<CXXTryStmt>(Body)->getTryBlock());
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: }
|
Loading…
Reference in New Issue