Commit 4516dc1c authored by Akira Hatanaka's avatar Akira Hatanaka
Browse files

Don't add optnone or noinline if the function is already marked as

always_inline.

The assertion in SetLLVMFunctionAttributesForDefinition used to fail
when there was attribute OptimizeNone on the AST function and attribute
always_inline on the IR function. This happens because base destructors
are annotated with always_inline when the code is compiled with
-fapple-kext (see r124757).

rdar://problem/57169694
parent a578adc1
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -1515,16 +1515,15 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
      !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0;
  // We can't add optnone in the following cases, it won't pass the verifier.
  ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>();
  ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline);
  ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>();

  if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) {
  // Add optnone, but do so only if the function isn't always_inline.
  if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) &&
      !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
    B.addAttribute(llvm::Attribute::OptimizeNone);

    // OptimizeNone implies noinline; we should not be inlining such functions.
    B.addAttribute(llvm::Attribute::NoInline);
    assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) &&
           "OptimizeNone and AlwaysInline on same function!");

    // We still need to handle naked functions even though optnone subsumes
    // much of their semantics.
@@ -1540,7 +1539,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
    B.addAttribute(llvm::Attribute::NoInline);
  } else if (D->hasAttr<NoDuplicateAttr>()) {
    B.addAttribute(llvm::Attribute::NoDuplicate);
  } else if (D->hasAttr<NoInlineAttr>()) {
  } else if (D->hasAttr<NoInlineAttr>() && !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) {
    // Add noinline if the function isn't always_inline.
    B.addAttribute(llvm::Attribute::NoInline);
  } else if (D->hasAttr<AlwaysInlineAttr>() &&
             !F->hasFnAttribute(llvm::Attribute::NoInline)) {
+22 −0
Original line number Diff line number Diff line
@@ -4,6 +4,25 @@
// CHECK: @llvm.global_ctors = appending global {{.*}} { i32 65535, void ()* [[CTOR0:@.*]], i8* null }
// CHECK: @llvm.global_dtors = appending global {{.*}} { i32 65535, void ()* [[DTOR0:@.*]], i8* null }

// Check that the base destructor is marked as always_inline when generating
// code for kext.

namespace testBaseDestructor {
#pragma clang optimize off
struct D {
  virtual ~D();
};

D::~D() {}
#pragma clang optimize on
}

// CHECK: define void @_ZN18testBaseDestructor1DD2Ev({{.*}}) unnamed_addr #[[ATTR0:.*]] align 2 {

// CHECK: define void @_ZN18testBaseDestructor1DD1Ev({{.*}}) unnamed_addr #[[ATTR1:.*]] align 2 {

// CHECK: define void @_ZN18testBaseDestructor1DD0Ev({{.*}}) unnamed_addr #[[ATTR1]] align 2 {

// rdar://11241230
namespace test0 {
  struct A { A(); ~A(); };
@@ -20,3 +39,6 @@ namespace test0 {
// CHECK:    define internal void [[DTOR0]]()
// CHECK:      call void @_ZN5test01AD1Ev([[A]]* @_ZN5test01aE)
// CHECK-NEXT: ret void

// CHECK: attributes #[[ATTR0]] = { alwaysinline nounwind {{.*}} }
// CHECK: attributes #[[ATTR1]] = { noinline nounwind {{.*}} }