Unverified Commit 48d77659 authored by Grigory Pastukhov's avatar Grigory Pastukhov Committed by GitHub
Browse files

Revert "[Clang] Emit LLVM flatten attribute instead of per-callsite...

Revert "[Clang] Emit LLVM flatten attribute instead of per-callsite alwaysinline (#188615)"  (#195314)

Reverts #188615 due to #195236 — Linux kernel build with LTO hangs.
parent fe8ff670
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -311,16 +311,6 @@ Attribute Changes in Clang
  foreign language personality with a given function. Note that this does not
  perform any ABI validation for the personality routine.

- The ``__attribute__((flatten))`` attribute behavior has changed to match
  GCC. Previously, Clang only inlined direct callees of the attributed
  function. Now, all calls are inlined transitively, including calls
  introduced by inlining. Calls that cannot be inlined are left as-is:
  this includes callees marked ``noinline``, callees with incompatible ABI
  attributes (e.g. SME), callees without a visible definition, and
  recursive calls where a function already appears in the inlining chain.
  Flatten also works across ThinLTO module boundaries when callee
  definitions are available.

- The :doc:`ThreadSafetyAnalysis` attributes ``guarded_by`` and
  ``pt_guarded_by`` now accept multiple capability arguments with refined
  access semantics: *writing* requires all listed capabilities to be held
+11 −0
Original line number Diff line number Diff line
@@ -5992,6 +5992,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
  // Apply some call-site-specific attributes.
  // TODO: work this into building the attribute set.

  // Apply always_inline to all calls within flatten functions.
  // FIXME: should this really take priority over __try, below?
  if (CurCodeDecl && CurCodeDecl->hasAttr<FlattenAttr>() &&
      !InNoInlineAttributedStmt &&
      !(TargetDecl && TargetDecl->hasAttr<NoInlineAttr>()) &&
      !CGM.getTargetCodeGenInfo().wouldInliningViolateFunctionCallABI(
          CallerDecl, CalleeDecl)) {
    Attrs =
        Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::AlwaysInline);
  }

  // Disable inlining inside SEH __try blocks.
  if (isSEHTryScope()) {
    Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline);
+0 −3
Original line number Diff line number Diff line
@@ -2975,9 +2975,6 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
  if (CodeGenOpts.DisableOutlining || D->hasAttr<NoOutlineAttr>())
    B.addAttribute(llvm::Attribute::NoOutline);

  if (D->hasAttr<FlattenAttr>())
    B.addAttribute(llvm::Attribute::Flatten);

  F->addFnAttrs(B);

  llvm::MaybeAlign ExplicitAlignment;
+34 −81
Original line number Diff line number Diff line
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_FLATTEN -o - | FileCheck %s --check-prefix=CHECK-FLATTEN
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck %s --check-prefix=CHECK-ALWAYS-INLINE
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_FLATTEN -o - | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -target-feature +sme -target-feature +sme2 %s -DUSE_ALWAYS_INLINE_STMT -o - | FileCheck %s

// REQUIRES: aarch64-registered-target

@@ -31,26 +31,14 @@ void caller(void) {
    STMT_ATTR fn_streaming_new_za();
    STMT_ATTR fn_streaming_new_zt0();
}
// For flatten: fn() and fn_streaming_compatible() are inlined, streaming functions
// are blocked by TTI (non-streaming caller), new_za/new_zt0 are always blocked.
// CHECK-FLATTEN-LABEL: void @caller()
//  CHECK-FLATTEN-NEXT: entry:
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming
//  CHECK-FLATTEN-NEXT:   call void @fn_locally_streaming
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_za
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_zt0

// For always_inline: Clang's wouldInliningViolateFunctionCallABI controls.
// CHECK-ALWAYS-INLINE-LABEL: void @caller()
//  CHECK-ALWAYS-INLINE-NEXT: entry:
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_locally_streaming
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_za
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_zt0
// CHECK-LABEL: void @caller()
//  CHECK-NEXT: entry:
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @fn_streaming
//  CHECK-NEXT:   call void @fn_locally_streaming
//  CHECK-NEXT:   call void @fn_streaming_new_za
//  CHECK-NEXT:   call void @fn_streaming_new_zt0

FN_ATTR void caller_streaming_compatible(void) __arm_streaming_compatible {
    STMT_ATTR fn();
@@ -60,26 +48,14 @@ FN_ATTR void caller_streaming_compatible(void) __arm_streaming_compatible {
    STMT_ATTR fn_streaming_new_za();
    STMT_ATTR fn_streaming_new_zt0();
}
// For flatten: TTI allows inlining fn(), fn_streaming_compatible(), fn_streaming(),
// fn_locally_streaming() because they don't have incompatible ops. Only new_za/new_zt0 blocked.
// CHECK-FLATTEN-LABEL: void @caller_streaming_compatible()
//  CHECK-FLATTEN-NEXT: entry:
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_za
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_zt0

// For always_inline: Clang blocks fn() (streaming-compatible caller, non-streaming callee).
// CHECK-ALWAYS-INLINE-LABEL: void @caller_streaming_compatible()
//  CHECK-ALWAYS-INLINE-NEXT: entry:
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_locally_streaming
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_za
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_zt0
// CHECK-LABEL: void @caller_streaming_compatible()
//  CHECK-NEXT: entry:
//  CHECK-NEXT:   call void @fn
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @fn_streaming
//  CHECK-NEXT:   call void @fn_locally_streaming
//  CHECK-NEXT:   call void @fn_streaming_new_za
//  CHECK-NEXT:   call void @fn_streaming_new_zt0

FN_ATTR void caller_streaming(void) __arm_streaming {
    STMT_ATTR fn();
@@ -89,26 +65,14 @@ FN_ATTR void caller_streaming(void) __arm_streaming {
    STMT_ATTR fn_streaming_new_za();
    STMT_ATTR fn_streaming_new_zt0();
}
// For flatten: TTI allows all except new_za/new_zt0. fn() is inlined because
// streaming caller can execute non-streaming callee's code (no incompatible ops).
// CHECK-FLATTEN-LABEL: void @caller_streaming()
//  CHECK-FLATTEN-NEXT: entry:
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_za
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_zt0

// For always_inline: Clang blocks fn() (streaming caller, non-streaming callee).
// CHECK-ALWAYS-INLINE-LABEL: void @caller_streaming()
//  CHECK-ALWAYS-INLINE-NEXT: entry:
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_za
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_zt0
// CHECK-LABEL: void @caller_streaming()
//  CHECK-NEXT: entry:
//  CHECK-NEXT:   call void @fn
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @fn_streaming_new_za
//  CHECK-NEXT:   call void @fn_streaming_new_zt0

FN_ATTR __arm_locally_streaming
void caller_locally_streaming(void) {
@@ -119,22 +83,11 @@ void caller_locally_streaming(void) {
    STMT_ATTR fn_streaming_new_za();
    STMT_ATTR fn_streaming_new_zt0();
}
// For flatten: Similar to caller_streaming - TTI allows all except new_za/new_zt0.
// CHECK-FLATTEN-LABEL: void @caller_locally_streaming()
//  CHECK-FLATTEN-NEXT: entry:
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @was_inlined
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_za
//  CHECK-FLATTEN-NEXT:   call void @fn_streaming_new_zt0

// For always_inline: Clang blocks fn().
// CHECK-ALWAYS-INLINE-LABEL: void @caller_locally_streaming()
//  CHECK-ALWAYS-INLINE-NEXT: entry:
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @was_inlined
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_za
//  CHECK-ALWAYS-INLINE-NEXT:   call void @fn_streaming_new_zt0
// CHECK-LABEL: void @caller_locally_streaming()
//  CHECK-NEXT: entry:
//  CHECK-NEXT:   call void @fn
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @was_inlined
//  CHECK-NEXT:   call void @fn_streaming_new_za
//  CHECK-NEXT:   call void @fn_streaming_new_zt0
+10 −18
Original line number Diff line number Diff line
// RUN: %clang_cc1 -triple=x86_64-linux-gnu %s -emit-llvm -o - | FileCheck %s

// External functions to provide side effects that prevent trivial elimination.
void external_f(void);
void external_h(void);
void f(void) {}

void f(void) { external_f(); }
__attribute__((noinline)) void ni(void) {}

void h(void) {
  external_h();
  f();
}

// CHECK-LABEL: define{{.*}} void @g()
// CHECK-SAME: [[FLATTEN_ATTR:#[0-9]+]]
__attribute__((flatten))
// CHECK: define{{.*}} void @g()
void g(void) {
  // Flatten recursively inlines: g -> h -> f, so neither call remains.
  // Only the leaf external() call should survive.
  // CHECK-NOT: call {{.*}} @h
  // CHECK-NOT: call {{.*}} @f
  // CHECK: call {{.*}} @external_h
  // CHECK: call {{.*}} @external_f
  h();
  f();
  // CHECK: call {{.*}} @ni
  ni();
}

// CHECK: attributes [[FLATTEN_ATTR]] = {{{.*}}flatten{{.*}}}
void h(void) {
  // CHECK: call {{.*}} @f
  f();
}