From 0d08cb0e70378d1f10578f4e009eb29eb17ad2dd Mon Sep 17 00:00:00 2001 From: Sam Elliott Date: Tue, 10 Feb 2026 21:44:17 -0800 Subject: [PATCH] [outliners] Turn nooutline into an Enum Attribute (#163665) This change turns the `"nooutline"` attribute into an enum attribute called `nooutline`, and adds an auto-upgrader for bitcode to make the same change to existing IR. This IR attribute disables both the Machine Outliner (enabled at Oz for some targets), and the IR Outliner (disabled by default). --- llvm/docs/LangRef.rst | 2 +- llvm/docs/ReleaseNotes.md | 3 +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 + llvm/include/llvm/IR/Attributes.td | 3 +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 2 ++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 ++ llvm/lib/CodeGen/MachineOutliner.cpp | 2 +- llvm/lib/IR/AutoUpgrade.cpp | 7 +++++++ llvm/lib/Transforms/IPO/IROutliner.cpp | 2 +- llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 + llvm/test/Bitcode/upgrade-nooutline.ll | 10 ++++++++++ .../AArch64/machine-outliner-mapper-debug-output.mir | 2 +- llvm/test/Transforms/IROutliner/nooutline-attribute.ll | 4 ++-- llvm/utils/kate/llvm.xml | 1 + llvm/utils/vim/syntax/llvm.vim | 1 + llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml | 1 + 16 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 llvm/test/Bitcode/upgrade-nooutline.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 28edd439b690..00a4a00c5bf9 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2766,7 +2766,7 @@ For example: to signify an unbounded maximum. The syntax `vscale_range()` can be used to set both `min` and `max` to the same value. Functions that don't include this attribute make no assumptions about the value of `vscale`. -``"nooutline"`` +``nooutline`` This attribute indicates that outlining passes should not modify the function. ``nocreateundeforpoison`` diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 30e74acf973e..91726e795405 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -66,6 +66,9 @@ Changes to the LLVM IR * "denormal-fp-math" and "denormal-fp-math-f32" string attributes were migrated to first-class denormal_fpenv attribute. +* The `"nooutline"` attribute is now writen as `nooutline`. Existing IR and + bitcode will be automatically updated. + Changes to LLVM infrastructure ------------------------------ diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h index 811116a3e175..bcf596a0d79b 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -808,6 +808,7 @@ enum AttributeKindCodes { ATTR_KIND_SANITIZE_ALLOC_TOKEN = 104, ATTR_KIND_NO_CREATE_UNDEF_OR_POISON = 105, ATTR_KIND_DENORMAL_FPENV = 106, + ATTR_KIND_NOOUTLINE = 107, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index 7c5457459f24..941251003f5b 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -212,6 +212,9 @@ def NoImplicitFloat : EnumAttr<"noimplicitfloat", IntersectPreserve, [FnAttr]>; /// inline=never. def NoInline : EnumAttr<"noinline", IntersectPreserve, [FnAttr]>; +/// nooutline +def NoOutline : EnumAttr<"nooutline", IntersectPreserve, [FnAttr]>; + /// Function is called early and/or often, so lazy binding isn't worthwhile. def NonLazyBind : EnumAttr<"nonlazybind", IntersectPreserve, [FnAttr]>; diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 749df3f2fc61..32b936aa45ea 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2271,6 +2271,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::NoCreateUndefOrPoison; case bitc::ATTR_KIND_DENORMAL_FPENV: return Attribute::DenormalFPEnv; + case bitc::ATTR_KIND_NOOUTLINE: + return Attribute::NoOutline; } } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 2566b2a29230..6b332554bddd 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -956,6 +956,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_NO_CREATE_UNDEF_OR_POISON; case Attribute::DenormalFPEnv: return bitc::ATTR_KIND_DENORMAL_FPENV; + case Attribute::NoOutline: + return bitc::ATTR_KIND_NOOUTLINE; case Attribute::EndAttrKinds: llvm_unreachable("Can not encode end-attribute kinds marker."); case Attribute::None: diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp index 245f97a17ea8..7ef37a2ac7b2 100644 --- a/llvm/lib/CodeGen/MachineOutliner.cpp +++ b/llvm/lib/CodeGen/MachineOutliner.cpp @@ -1255,7 +1255,7 @@ void MachineOutliner::populateMapper(InstructionMapper &Mapper, Module &M) { for (Function &F : M) { LLVM_DEBUG(dbgs() << "MAPPING FUNCTION: " << F.getName() << "\n"); - if (F.hasFnAttribute("nooutline")) { + if (F.hasFnAttribute(Attribute::NoOutline)) { LLVM_DEBUG(dbgs() << "SKIP: Function has nooutline attribute\n"); continue; } diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 0efeeb999d3d..0463bacca350 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -6345,6 +6345,13 @@ void llvm::UpgradeFunctionAttributes(Function &F) { RemovingAttrs = true; } + if (Attribute A = F.getFnAttribute("nooutline"); + A.isValid() && A.isStringAttribute()) { + AttrsToRemove.addAttribute("nooutline"); + AttrsToAdd.addAttribute(Attribute::NoOutline); + AddingAttrs = RemovingAttrs = true; + } + if (!F.empty()) { // For some reason this is called twice, and the first time is before any // instructions are loaded into the body. diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp index 250957684dff..574e4639b543 100644 --- a/llvm/lib/Transforms/IPO/IROutliner.cpp +++ b/llvm/lib/Transforms/IPO/IROutliner.cpp @@ -2411,7 +2411,7 @@ void IROutliner::pruneIncompatibleRegions( if (FnForCurrCand.hasOptNone()) continue; - if (FnForCurrCand.hasFnAttribute("nooutline")) { + if (FnForCurrCand.hasFnAttribute(Attribute::NoOutline)) { LLVM_DEBUG({ dbgs() << "... Skipping function with nooutline attribute: " << FnForCurrCand.getName() << "\n"; diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index fe8758b94293..b298a8ae144d 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -949,6 +949,7 @@ Function *CodeExtractor::constructFunctionDeclaration( case Attribute::NoFree: case Attribute::NoImplicitFloat: case Attribute::NoInline: + case Attribute::NoOutline: case Attribute::NonLazyBind: case Attribute::NoRedZone: case Attribute::NoUnwind: diff --git a/llvm/test/Bitcode/upgrade-nooutline.ll b/llvm/test/Bitcode/upgrade-nooutline.ll new file mode 100644 index 000000000000..619d4705e64e --- /dev/null +++ b/llvm/test/Bitcode/upgrade-nooutline.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llvm-dis - | FileCheck %s --implicit-check-not='"nooutline"' + +; CHECK: define void @f() [[ATTR:#[0-9]+]] +; CHECK: attributes [[ATTR]] = { +; CHECK-SAME: nooutline +; CHECK-SAME: } + +define void @f() "nooutline" { + ret void +} diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-mapper-debug-output.mir b/llvm/test/CodeGen/AArch64/machine-outliner-mapper-debug-output.mir index 826157e68d75..056c5f18d492 100644 --- a/llvm/test/CodeGen/AArch64/machine-outliner-mapper-debug-output.mir +++ b/llvm/test/CodeGen/AArch64/machine-outliner-mapper-debug-output.mir @@ -17,7 +17,7 @@ --- | define void @block_too_small() noredzone { unreachable } - define void @no_outline() noredzone "nooutline" { unreachable } + define void @no_outline() noredzone nooutline { unreachable } define void @redzone() { unreachable } declare void @no_mf() define void @block_addr_fn() noredzone { diff --git a/llvm/test/Transforms/IROutliner/nooutline-attribute.ll b/llvm/test/Transforms/IROutliner/nooutline-attribute.ll index eaf3afa3b15a..a61a1614a311 100644 --- a/llvm/test/Transforms/IROutliner/nooutline-attribute.ll +++ b/llvm/test/Transforms/IROutliner/nooutline-attribute.ll @@ -8,7 +8,7 @@ define void @outlinable() { ret void } -define i8 @nooutline1(ptr noalias %s, ptr noalias %d, i64 %len) "nooutline" { +define i8 @nooutline1(ptr noalias %s, ptr noalias %d, i64 %len) nooutline { %a = load i8, ptr %s %b = load i8, ptr %d call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false) @@ -17,7 +17,7 @@ define i8 @nooutline1(ptr noalias %s, ptr noalias %d, i64 %len) "nooutline" { ret i8 %ret } -define i8 @nooutline2(ptr noalias %s, ptr noalias %d, i64 %len) "nooutline" { +define i8 @nooutline2(ptr noalias %s, ptr noalias %d, i64 %len) nooutline { %a = load i8, ptr %s %b = load i8, ptr %d call void @llvm.memcpy.p0.p0.i64(ptr %d, ptr %s, i64 %len, i1 false) diff --git a/llvm/utils/kate/llvm.xml b/llvm/utils/kate/llvm.xml index 0e7aec3880e6..c66547d9121c 100644 --- a/llvm/utils/kate/llvm.xml +++ b/llvm/utils/kate/llvm.xml @@ -105,6 +105,7 @@ noimplicitfloat noinline nomerge + nooutline noprofile noredzone noreturn diff --git a/llvm/utils/vim/syntax/llvm.vim b/llvm/utils/vim/syntax/llvm.vim index cbff478d4bf0..d8cf75fa816f 100644 --- a/llvm/utils/vim/syntax/llvm.vim +++ b/llvm/utils/vim/syntax/llvm.vim @@ -133,6 +133,7 @@ syn keyword llvmKeyword \ noimplicitfloat \ noinline \ nomerge + \ nooutline \ nonlazybind \ nonnull \ noprofile diff --git a/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml b/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml index 1faaf6b26f30..0559b8cac5d9 100644 --- a/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml +++ b/llvm/utils/vscode/llvm/syntaxes/ll.tmLanguage.yaml @@ -230,6 +230,7 @@ patterns: \\bnoimplicitfloat\\b|\ \\bnoinline\\b|\ \\bnomerge\\b|\ + \\bnooutline\\b|\ \\bnonlazybind\\b|\ \\bnonnull\\b|\ \\bnoprofile\\b|\