[ForceFunctionAttrs] Fix handling of alwaysinline and noinline attributes.#180026
Conversation
There was a problem hiding this comment.
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
alwaysinlineto functions withnoinlineand 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 |
|
Once this PR is merged, I'll revert 58de8f2 and include a note in the reverted commit message to use this functionality instead. |
alwaysinline and noinline attributes.
|
@llvm/pr-subscribers-llvm-transforms Author: Justin Fargnoli (justinfargnoli) ChangesAddress #152365 (comment) Full diff: https://github.com/llvm/llvm-project/pull/180026.diff 2 Files Affected:
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 }
|
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) lldb-apilldb-api.functionalities/tsan/cpp_global_location/TestTsanCPPGlobalLocation.pylldb-api.functionalities/tsan/global_location/TestTsanGlobalLocation.pyIf 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 |
|
Merging despite CI failures
Edit:
|
|
Yeah, the CI failures are unrelated. They were fixed in 74c8891. |
Address #152365 (comment)