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