Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -1837,6 +1837,9 @@ This attribute indicates that the inliner should never inline this function in any situation. This attribute may not be used together with the ``alwaysinline`` attribute. +``nooutline`` + This attribute indicates that no outliner pass should ever outline from + this function in any situation. ``nomerge`` This attribute indicates that calls to this function should never be merged during optimization. For example, it will prevent tail merging otherwise Index: llvm/lib/CodeGen/MachineOutliner.cpp =================================================================== --- llvm/lib/CodeGen/MachineOutliner.cpp +++ llvm/lib/CodeGen/MachineOutliner.cpp @@ -884,6 +884,14 @@ if (F.empty()) continue; + if (F.hasFnAttribute("nooutline")) { + LLVM_DEBUG({ + dbgs() << "... Skipping function with nooutline attribute: " + << F.getName() << "\n"; + }); + continue; + } + // There's something in F. Check if it has a MachineFunction associated with // it. MachineFunction *MF = MMI.getMachineFunction(F); Index: llvm/lib/Transforms/IPO/IROutliner.cpp =================================================================== --- llvm/lib/Transforms/IPO/IROutliner.cpp +++ llvm/lib/Transforms/IPO/IROutliner.cpp @@ -2423,6 +2423,7 @@ PreviouslyOutlined = false; unsigned StartIdx = IRSC.getStartIdx(); unsigned EndIdx = IRSC.getEndIdx(); + const Function &FnForCurrCand = *IRSC.getFunction(); for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++) if (Outlined.contains(Idx)) { @@ -2442,9 +2443,17 @@ if (BBHasAddressTaken) continue; - if (IRSC.getFunction()->hasOptNone()) + if (FnForCurrCand.hasOptNone()) continue; + if (FnForCurrCand.hasFnAttribute("nooutline")) { + LLVM_DEBUG({ + dbgs() << "... Skipping function with nooutline attribute: " + << FnForCurrCand.getName() << "\n"; + }); + continue; + } + if (IRSC.front()->Inst->getFunction()->hasLinkOnceODRLinkage() && !OutlineFromLinkODRs) continue; Index: llvm/test/CodeGen/AArch64/machine-outliner-nooutline-attribute.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/machine-outliner-nooutline-attribute.mir @@ -0,0 +1,42 @@ +# RUN: llc -mtriple=aarch64 -debug-only=machine-outliner -run-pass=machine-outliner -verify-machineinstrs %s -o - 2>&1 | FileCheck %s +# REQUIRES: asserts + +# CHECK: ... Skipping function with nooutline attribute: no_outline +# CHECK-NOT: ... Skipping function with nooutline attribute: baz +# CHECK-NOT: OUTLINED + +--- | + define void @no_outline() #0 { unreachable } + define void @baz() { unreachable } + attributes #0 = { noredzone "nooutline" } +... +--- + +name: no_outline +tracksRegLiveness: true +body: | + bb.0: + liveins: $w0, $lr, $w8 + $sp = frame-setup SUBXri $sp, 32, 0 + $fp = frame-setup ADDXri $sp, 16, 0 + bb.1: + BL @baz, implicit-def dead $lr, implicit $sp + $w17 = ORRWri $wzr, 1 + $w17 = ORRWri $wzr, 1 + $w0 = ORRWri $wzr, 4 + BL @baz, implicit-def dead $lr, implicit $sp + $w17 = ORRWri $wzr, 1 + $w17 = ORRWri $wzr, 1 + $w0 = ORRWri $wzr, 3 + BL @baz, implicit-def dead $lr, implicit $sp + $w17 = ORRWri $wzr, 1 + $w17 = ORRWri $wzr, 1 + $w0 = ORRWri $wzr, 2 + BL @baz, implicit-def dead $lr, implicit $sp + $w17 = ORRWri $wzr, 1 + $w17 = ORRWri $wzr, 1 + $w0 = ORRWri $wzr, 1 + bb.2: + $fp, $lr = LDPXi $sp, 2 + RET undef $lr + Index: llvm/test/Transforms/IROutliner/nooutline-attribute.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/IROutliner/nooutline-attribute.ll @@ -0,0 +1,30 @@ +; RUN: opt -S -verify -debug-only=iroutliner -iroutliner -ir-outlining-no-cost %s -o - 2>&1 | FileCheck %s +; REQUIRES: asserts + +; CHECK-NOT: ... Skipping function with nooutline attribute: outlinable +; CHECK-NOT: @outlined_ir_func +; CHECK: ... Skipping function with nooutline attribute: nooutline1 +; CHECK: ... Skipping function with nooutline attribute: nooutline2 + +define void @outlinable() { ret void } + +define i8 @nooutline1(i8* noalias %s, i8* noalias %d, i64 %len) "nooutline" { + %a = load i8, i8* %s + %b = load i8, i8* %d + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %d, i8* %s, i64 %len, i1 false) + %c = add i8 %a, %b + %ret = load i8, i8* %s + ret i8 %ret +} + +define i8 @nooutline2(i8* noalias %s, i8* noalias %d, i64 %len) "nooutline" { + %a = load i8, i8* %s + %b = load i8, i8* %d + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %d, i8* %s, i64 %len, i1 false) + %c = add i8 %a, %b + %ret = load i8, i8* %s + ret i8 %ret +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i1) +