[llvm] 754fc78 - [ForceFunctionAttrs] Fix handling of `alwaysinline` and `noinline` attributes. (#180026)

via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 9 11:49:42 PST 2026


Author: Justin Fargnoli
Date: 2026-02-09T11:49:36-08:00
New Revision: 754fc78d713285855e2a45225ec2b8b4f51e7ff9

URL: https://github.com/llvm/llvm-project/commit/754fc78d713285855e2a45225ec2b8b4f51e7ff9
DIFF: https://github.com/llvm/llvm-project/commit/754fc78d713285855e2a45225ec2b8b4f51e7ff9.diff

LOG: [ForceFunctionAttrs] Fix handling of `alwaysinline` and `noinline` attributes. (#180026)

Address
https://github.com/llvm/llvm-project/pull/152365#issuecomment-3198921342

Added: 
    

Modified: 
    llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
    llvm/test/Transforms/ForcedFunctionAttrs/forced.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
index 7ea7937d8b827..7a9eee56d8bb4 100644
--- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp
@@ -44,6 +44,14 @@ static cl::opt<std::string> CSVFilePath(
         "Path to CSV file containing lines of function names and attributes to "
         "add to them in the form of `f1,attr1` or `f2,attr2=str`."));
 
+static bool hasConflictingFnAttr(Attribute::AttrKind Kind, Function &F) {
+  if (Kind == Attribute::AlwaysInline)
+    return F.hasFnAttribute(Attribute::NoInline);
+  if (Kind == Attribute::NoInline)
+    return F.hasFnAttribute(Attribute::AlwaysInline);
+  return false;
+}
+
 /// If F has any forced attributes given on the command line, add them.
 /// If F has any forced remove attributes given on the command line, remove
 /// them. When both force and force-remove are given to a function, the latter
@@ -69,7 +77,8 @@ static void forceAttributes(Function &F) {
 
   for (const auto &S : ForceAttributes) {
     auto Kind = ParseFunctionAndAttr(S);
-    if (Kind == Attribute::None || F.hasFnAttribute(Kind))
+    if (Kind == Attribute::None || F.hasFnAttribute(Kind) ||
+        hasConflictingFnAttr(Kind, F))
       continue;
     F.addFnAttr(Kind);
   }
@@ -115,7 +124,8 @@ PreservedAnalyses ForceFunctionAttrsPass::run(Module &M,
         } else {
           auto AttrKind = Attribute::getAttrKindFromName(SplitPair.second);
           if (AttrKind != Attribute::None &&
-              Attribute::canUseAsFnAttr(AttrKind)) {
+              Attribute::canUseAsFnAttr(AttrKind) &&
+              !hasConflictingFnAttr(AttrKind, *Func)) {
             // TODO: There could be string attributes without a value, we should
             // support those, too.
             Func->addFnAttr(AttrKind);

diff  --git a/llvm/test/Transforms/ForcedFunctionAttrs/forced.ll b/llvm/test/Transforms/ForcedFunctionAttrs/forced.ll
index 496f698878a73..ae68f06654589 100644
--- a/llvm/test/Transforms/ForcedFunctionAttrs/forced.ll
+++ b/llvm/test/Transforms/ForcedFunctionAttrs/forced.ll
@@ -1,11 +1,13 @@
-; RUN: opt < %s -S -passes=forceattrs | FileCheck %s --check-prefix=CHECK-CONTROL
-; RUN: opt < %s -S -passes=forceattrs -force-attribute foo:noinline | FileCheck %s --check-prefix=CHECK-FOO
-; RUN: opt < %s -S -passes=forceattrs -force-remove-attribute goo:cold | FileCheck %s --check-prefix=REMOVE-COLD
-; RUN: opt < %s -S -passes=forceattrs -force-remove-attribute goo:noinline | FileCheck %s --check-prefix=REMOVE-NOINLINE
-; RUN: opt < %s -S -passes=forceattrs -force-attribute goo:cold -force-remove-attribute goo:noinline | FileCheck %s --check-prefix=ADD-COLD-REMOVE-NOINLINE
-; RUN: opt < %s -S -passes=forceattrs -force-attribute goo:noinline -force-remove-attribute goo:noinline | FileCheck %s --check-prefix=ADD-NOINLINE-REMOVE-NOINLINE
-; RUN: opt < %s -S -passes=forceattrs -force-attribute optsize | FileCheck %s --check-prefix=CHECK-ADD-ALL
-; RUN: opt < %s -S -passes=forceattrs -force-remove-attribute noinline | FileCheck %s --check-prefix=CHECK-REMOVE-ALL
+; RUN: opt < %s -S -passes=verify,forceattrs,verify | FileCheck %s --check-prefix=CHECK-CONTROL
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-attribute foo:noinline | FileCheck %s --check-prefix=CHECK-FOO
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-remove-attribute goo:cold | FileCheck %s --check-prefix=REMOVE-COLD
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-remove-attribute goo:noinline | FileCheck %s --check-prefix=REMOVE-NOINLINE
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-attribute goo:cold -force-remove-attribute goo:noinline | FileCheck %s --check-prefix=ADD-COLD-REMOVE-NOINLINE
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-attribute goo:noinline -force-remove-attribute goo:noinline | FileCheck %s --check-prefix=ADD-NOINLINE-REMOVE-NOINLINE
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-attribute optsize | FileCheck %s --check-prefix=CHECK-ADD-ALL
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-remove-attribute noinline | FileCheck %s --check-prefix=CHECK-REMOVE-ALL
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-attribute alwaysinline | FileCheck %s --check-prefix=CHECK-ALWAYSINLINE-ALL
+; RUN: opt < %s -S -passes=verify,forceattrs,verify -force-attribute noinline | FileCheck %s --check-prefix=CHECK-NOINLINE-ALL
 
 ; CHECK-CONTROL: define void @foo() {
 ; CHECK-FOO: define void @foo() #0 {
@@ -29,7 +31,13 @@ define void @foo() {
 define void @goo() #0 {
   ret void
 }
+
+define void @hoo() #1 {
+  ret void
+}
+
 attributes #0 = { noinline }
+attributes #1 = { alwaysinline }
 
 ; CHECK-FOO: attributes #0 = { noinline }
 ; REMOVE-COLD: attributes #0 = { noinline }
@@ -39,13 +47,32 @@ attributes #0 = { noinline }
 ; should be added to all functions in the module.
 ; CHECK-ADD-ALL: define void @foo() #0 {
 ; CHECK-ADD-ALL: define void @goo() #1 {
+; CHECK-ADD-ALL: define void @hoo() #2 {
 ; CHECK-ADD-ALL: attributes #0 = { optsize }
 ; CHECK-ADD-ALL: attributes #1 = { noinline optsize }
+; CHECK-ADD-ALL: attributes #2 = { alwaysinline optsize }
 
 ; When passing an attribute to be removed without specifying a function,
 ; the attribute should be removed from all functions in the module that
 ; have it.
 ; CHECK-REMOVE-ALL: define void @foo() {
 ; CHECK-REMOVE-ALL: define void @goo() {
-; CHECK-REMOVE-ALL-NOT: attributes #0
+; CHECK-REMOVE-ALL: define void @hoo() #0 {
+; CHECK-REMOVE-ALL: attributes #0 = { alwaysinline }
+
+; When forcing alwaysinline on all functions, it should not be added to
+; functions that already have noinline (would produce invalid IR).
+; CHECK-ALWAYSINLINE-ALL: define void @foo() #0 {
+; CHECK-ALWAYSINLINE-ALL: define void @goo() #1 {
+; CHECK-ALWAYSINLINE-ALL: define void @hoo() #0 {
+; CHECK-ALWAYSINLINE-ALL-DAG: attributes #0 = { alwaysinline }
+; CHECK-ALWAYSINLINE-ALL-DAG: attributes #1 = { noinline }
+
+; When forcing noinline on all functions, it should not be added to
+; functions that already have alwaysinline (would produce invalid IR).
+; CHECK-NOINLINE-ALL: define void @foo() #0 {
+; CHECK-NOINLINE-ALL: define void @goo() #0 {
+; CHECK-NOINLINE-ALL: define void @hoo() #1 {
+; CHECK-NOINLINE-ALL-DAG: attributes #0 = { noinline }
+; CHECK-NOINLINE-ALL-DAG: attributes #1 = { alwaysinline }
 


        


More information about the llvm-commits mailing list