Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[ForceFunctionAttrs] Fix handling of alwaysinline and noinline attributes.#180026

Merged
justinfargnoli merged 4 commits intollvm:mainfrom
justinfargnoli:dev/jf/upstream-force-func-attrs
Feb 9, 2026
Merged

[ForceFunctionAttrs] Fix handling of alwaysinline and noinline attributes.#180026
justinfargnoli merged 4 commits intollvm:mainfrom
justinfargnoli:dev/jf/upstream-force-func-attrs

Conversation

@justinfargnoli
Copy link
Copy Markdown
Contributor

@justinfargnoli justinfargnoli self-assigned this Feb 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the handling of alwaysinline and noinline attributes in the ForceFunctionAttrs pass to prevent the creation of invalid IR. The fix ensures that these mutually exclusive attributes are not applied together, which would violate LLVM's attribute constraints.

Changes:

  • Added conflict detection logic to prevent applying alwaysinline to functions with noinline and vice versa
  • Added comprehensive test coverage for the new conflict detection behavior
  • Updated existing tests to include verification passes

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp Implements hasConflictingFnAttr helper and integrates conflict checks into attribute forcing logic
llvm/test/Transforms/ForcedFunctionAttrs/forced.ll Adds new test cases for conflicting attributes and updates existing test commands to include verification

@justinfargnoli
Copy link
Copy Markdown
Contributor Author

Once this PR is merged, I'll revert 58de8f2 and include a note in the reverted commit message to use this functionality instead.

@justinfargnoli justinfargnoli changed the title [ForceFunctionAttrs] Fix handling of alwaysinline and noinline attributes. [ForceFunctionAttrs] Fix handling of alwaysinline and noinline attributes. Feb 5, 2026
@justinfargnoli justinfargnoli marked this pull request as ready for review February 5, 2026 21:28
@justinfargnoli justinfargnoli requested a review from arsenm February 5, 2026 21:29
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Feb 5, 2026

@llvm/pr-subscribers-llvm-transforms

Author: Justin Fargnoli (justinfargnoli)

Changes

Address #152365 (comment)


Full diff: https://github.com/llvm/llvm-project/pull/180026.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp (+12-2)
  • (modified) llvm/test/Transforms/ForcedFunctionAttrs/forced.ll (+36-9)
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 }
 

@justinfargnoli justinfargnoli enabled auto-merge (squash) February 9, 2026 17:35
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 9, 2026

🐧 Linux x64 Test Results

  • 169427 tests passed
  • 3051 tests skipped
  • 2 tests failed

Failed Tests

(click on a test name to see its output)

lldb-api

lldb-api.functionalities/tsan/cpp_global_location/TestTsanCPPGlobalLocation.py
Script:
--
/usr/bin/python3 /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --env LLVM_INCLUDE_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include --env LLVM_TOOLS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --libcxx-include-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/c++/v1 --libcxx-include-target-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/x86_64-unknown-linux-gnu/c++/v1 --libcxx-library-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib/x86_64-unknown-linux-gnu --arch x86_64 --build-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex --lldb-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/lldb --compiler /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/clang --dsymutil /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --lldb-obj-root /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/lldb --lldb-libs-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --cmake-build-type Release /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/functionalities/tsan/cpp_global_location -p TestTsanCPPGlobalLocation.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 23.0.0git (https://github.com/llvm/llvm-project revision ae58587c1b1e8957c262cbb25c8fffd26ad646a5)
  clang revision ae58587c1b1e8957c262cbb25c8fffd26ad646a5
  llvm revision ae58587c1b1e8957c262cbb25c8fffd26ad646a5
ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
Skipping the following test categories: msvcstl, dsym, pdb, gmodules, debugserver, objc

--
Command Output (stderr):
--
UNSUPPORTED: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_dsym (TestTsanCPPGlobalLocation.TsanCPPGlobalLocationTestCase.test_dsym) (test case does not fall in any category of interest for this run) 
XPASS: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_dwarf (TestTsanCPPGlobalLocation.TsanCPPGlobalLocationTestCase.test_dwarf)
XPASS: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_dwo (TestTsanCPPGlobalLocation.TsanCPPGlobalLocationTestCase.test_dwo)
======================================================================
UNEXPECTED SUCCESS: test_dwarf (TestTsanCPPGlobalLocation.TsanCPPGlobalLocationTestCase.test_dwarf)
UNEXPECTED SUCCESS: test_dwo (TestTsanCPPGlobalLocation.TsanCPPGlobalLocationTestCase.test_dwo)
----------------------------------------------------------------------
Ran 3 tests in 3.401s

FAILED (skipped=1, unexpected successes=2)

--

lldb-api.functionalities/tsan/global_location/TestTsanGlobalLocation.py
Script:
--
/usr/bin/python3 /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --env LLVM_INCLUDE_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/include --env LLVM_TOOLS_DIR=/home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --libcxx-include-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/c++/v1 --libcxx-include-target-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/include/x86_64-unknown-linux-gnu/c++/v1 --libcxx-library-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib/x86_64-unknown-linux-gnu --arch x86_64 --build-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex --lldb-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/lldb --compiler /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/clang --dsymutil /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./bin --lldb-obj-root /home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/lldb --lldb-libs-dir /home/gha/actions-runner/_work/llvm-project/llvm-project/build/./lib --cmake-build-type Release /home/gha/actions-runner/_work/llvm-project/llvm-project/lldb/test/API/functionalities/tsan/global_location -p TestTsanGlobalLocation.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 23.0.0git (https://github.com/llvm/llvm-project revision ae58587c1b1e8957c262cbb25c8fffd26ad646a5)
  clang revision ae58587c1b1e8957c262cbb25c8fffd26ad646a5
  llvm revision ae58587c1b1e8957c262cbb25c8fffd26ad646a5
ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
ThreadSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
Skipping the following test categories: msvcstl, dsym, pdb, gmodules, debugserver, objc

--
Command Output (stderr):
--
UNSUPPORTED: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_dsym (TestTsanGlobalLocation.TsanGlobalLocationTestCase.test_dsym) (test case does not fall in any category of interest for this run) 
XPASS: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_dwarf (TestTsanGlobalLocation.TsanGlobalLocationTestCase.test_dwarf)
XPASS: LLDB (/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang-x86_64) :: test_dwo (TestTsanGlobalLocation.TsanGlobalLocationTestCase.test_dwo)
======================================================================
UNEXPECTED SUCCESS: test_dwarf (TestTsanGlobalLocation.TsanGlobalLocationTestCase.test_dwarf)
UNEXPECTED SUCCESS: test_dwo (TestTsanGlobalLocation.TsanGlobalLocationTestCase.test_dwo)
----------------------------------------------------------------------
Ran 3 tests in 3.144s

FAILED (skipped=1, unexpected successes=2)

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@justinfargnoli
Copy link
Copy Markdown
Contributor Author

justinfargnoli commented Feb 9, 2026

Merging despite CI failures

Edit:

  • Code formatter failing due to GitHub rate limiting
    • github.GithubException.GithubException: 429 {"message": "This endpoint is temporarily being throttled. Please try again later. For more on scraping GitHub and how it may affect your rights, please review our Terms of Service (https://docs.github.com/en/site-policy/github-terms/github-terms-of-service)", "documentation_url": "https://docs.github.com/rest/using-the-rest-api/rate-limits-for-the-rest-api", "status": "429"}

@boomanaiden154
Copy link
Copy Markdown
Contributor

Yeah, the CI failures are unrelated. They were fixed in 74c8891.

@justinfargnoli justinfargnoli enabled auto-merge (squash) February 9, 2026 19:25
@justinfargnoli justinfargnoli enabled auto-merge (squash) February 9, 2026 19:26
@justinfargnoli justinfargnoli merged commit 754fc78 into llvm:main Feb 9, 2026
6 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants