[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).
This commit is contained in:
Sam Elliott 2026-02-10 21:44:17 -08:00 committed by GitHub
parent b02b395a1e
commit 0d08cb0e70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 38 additions and 6 deletions

View File

@ -2766,7 +2766,7 @@ For example:
to signify an unbounded maximum. The syntax `vscale_range(<val>)` 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``

View File

@ -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
------------------------------

View File

@ -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 {

View File

@ -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]>;

View File

@ -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;
}
}

View File

@ -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:

View File

@ -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;
}

View File

@ -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.

View File

@ -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";

View File

@ -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:

View File

@ -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
}

View File

@ -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 {

View File

@ -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)

View File

@ -105,6 +105,7 @@
<item> noimplicitfloat </item>
<item> noinline </item>
<item> nomerge </item>
<item> nooutline </item>
<item> noprofile </item>
<item> noredzone </item>
<item> noreturn </item>

View File

@ -133,6 +133,7 @@ syn keyword llvmKeyword
\ noimplicitfloat
\ noinline
\ nomerge
\ nooutline
\ nonlazybind
\ nonnull
\ noprofile

View File

@ -230,6 +230,7 @@ patterns:
\\bnoimplicitfloat\\b|\
\\bnoinline\\b|\
\\bnomerge\\b|\
\\bnooutline\\b|\
\\bnonlazybind\\b|\
\\bnonnull\\b|\
\\bnoprofile\\b|\