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:
Piotr Padlewski 2015-09-15 21:46:47 +00:00
parent 68615ce606
commit 338c9d0ade
7 changed files with 243 additions and 3 deletions

View File

@ -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>;

View File

@ -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.

View File

@ -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());

View File

@ -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()) {

View File

@ -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");

View File

@ -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);

View File

@ -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: }