Skip to content

Commit

Permalink
[MachineOutliner] Don't outline functions starting with PATCHABLE_FUN…
Browse files Browse the repository at this point in the history
…CTION_ENTER/FENTRL_CALL

MachineOutliner may outline a "patchable-function-entry" function whose body has
a TargetOpcode::PATCHABLE_FUNCTION_ENTER MachineInstr. This is incorrect because
the special code sequence must stay unchanged to be used at run-time.
Avoid outlining PATCHABLE_FUNCTION_ENTER. While here, avoid outlining FENTRY_CALL too
(which doesn't reproduce currently) to allow phase ordering flexibility.

Fixes #52635

Reviewed By: paquette

Differential Revision: https://reviews.llvm.org/D115614
  • Loading branch information
MaskRay committed Dec 13, 2021
1 parent f212032 commit a6a07a5
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 4 deletions.
4 changes: 1 addition & 3 deletions llvm/include/llvm/CodeGen/TargetInstrInfo.h
Expand Up @@ -1927,9 +1927,7 @@ class TargetInstrInfo : public MCInstrInfo {
/// Optional target hook that returns true if \p MBB is safe to outline from,
/// and returns any target-specific information in \p Flags.
virtual bool isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
unsigned &Flags) const {
return true;
}
unsigned &Flags) const;

/// Insert a custom frame for outlined functions.
virtual void buildOutlinedFrame(MachineBasicBlock &MBB, MachineFunction &MF,
Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/CodeGen/TargetInstrInfo.cpp
Expand Up @@ -1418,3 +1418,16 @@ void TargetInstrInfo::mergeOutliningCandidateAttributes(
}))
F.addFnAttr(Attribute::NoUnwind);
}

bool TargetInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
unsigned &Flags) const {
// Some instrumentations create special TargetOpcode at the start which
// expands to special code sequences which must be present.
auto First = MBB.getFirstNonDebugInstr();
if (First != MBB.end() &&
(First->getOpcode() == TargetOpcode::FENTRY_CALL ||
First->getOpcode() == TargetOpcode::PATCHABLE_FUNCTION_ENTER))
return false;

return true;
}
2 changes: 2 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
Expand Up @@ -7055,6 +7055,8 @@ bool AArch64InstrInfo::isFunctionSafeToOutlineFrom(

bool AArch64InstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
unsigned &Flags) const {
if (!TargetInstrInfo::isMBBSafeToOutlineFrom(MBB, Flags))
return false;
// Check if LR is available through all of the MBB. If it's not, then set
// a flag.
assert(MBB.getParent()->getRegInfo().tracksLiveness() &&
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
Expand Up @@ -1254,7 +1254,7 @@ bool RISCVInstrInfo::isFunctionSafeToOutlineFrom(
bool RISCVInstrInfo::isMBBSafeToOutlineFrom(MachineBasicBlock &MBB,
unsigned &Flags) const {
// More accurate safety checking is done in getOutliningCandidateInfo.
return true;
return TargetInstrInfo::isMBBSafeToOutlineFrom(MBB, Flags);
}

// Enum values indicating how an outlined call should be constructed.
Expand Down
114 changes: 114 additions & 0 deletions llvm/test/CodeGen/AArch64/machine-outliner-patchable.ll
@@ -0,0 +1,114 @@
; RUN: llc < %s -verify-machineinstrs -enable-machine-outliner | FileCheck %s

target triple = "aarch64-unknown-linux-gnu"

declare void @foo(i32, i32, i32, i32) minsize

;; TargetOpcode::FENTRY_CALL at the start of the function expands to a __fentry__
;; call which must be present. Don't outline it.
define void @fentry0(i1 %a) nounwind "fentry-call"="true" {
; CHECK-LABEL: fentry0:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: # FEntry call
; CHECK: // %bb.1:
; CHECK-NEXT: bl OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

define void @fentry1(i1 %a) nounwind "fentry-call"="true" {
; CHECK-LABEL: fentry1:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: # FEntry call
; CHECK: // %bb.1:
; CHECK-NEXT: bl OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

;; TargetOpcode::PATCHABLE_FUNCTION_ENTER at the start of the function expands to
;; NOPs which must be present. Don't outline them.
define void @patchable0(i1 %a) nounwind "patchable-function-entry"="2" {
; CHECK-LABEL: patchable0:
; CHECK-NEXT: .Lfunc_begin0:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: nop
; CHECK-NEXT: nop
; CHECK: // %bb.1:
; CHECK-NEXT: bl OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

define void @patchable1(i1 %a) nounwind "patchable-function-entry"="2" {
; CHECK-LABEL: patchable1:
; CHECK-NEXT: .Lfunc_begin1:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: nop
; CHECK-NEXT: nop
; CHECK: // %bb.1:
; CHECK-NEXT: bl OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

;; Similar to "patchable-function-entry".
define void @xray0(i1 %a) nounwind "function-instrument"="xray-always" {
; CHECK-LABEL: xray0:
; CHECK-NEXT: .Lfunc_begin2:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: .Lxray_sled_0:
; CHECK: // %bb.1:
; CHECK-NEXT: bl OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

define void @xray1(i1 %a) nounwind "function-instrument"="xray-always" {
; CHECK-LABEL: xray1:
; CHECK-NEXT: .Lfunc_begin3:
; CHECK-NEXT: // %bb.0:
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: .Lxray_sled_2:
; CHECK: // %bb.1:
; CHECK-NEXT: bl OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}
77 changes: 77 additions & 0 deletions llvm/test/CodeGen/RISCV/machine-outliner-patchable.ll
@@ -0,0 +1,77 @@
; RUN: llc < %s -verify-machineinstrs -enable-machine-outliner | FileCheck %s

target triple = "riscv64-unknown-linux-gnu"

declare void @foo(i32, i32, i32, i32) minsize

;; TargetOpcode::FENTRY_CALL at the start of the function expands to a __fentry__
;; call which must be present. Don't outline it.
define void @fentry0(i1 %a) nounwind "fentry-call"="true" {
; CHECK-LABEL: fentry0:
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: # FEntry call
; CHECK: # %bb.1:
; CHECK-NEXT: call t0, OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

define void @fentry1(i1 %a) nounwind "fentry-call"="true" {
; CHECK-LABEL: fentry1:
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: # FEntry call
; CHECK: # %bb.1:
; CHECK-NEXT: call t0, OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

;; TargetOpcode::PATCHABLE_FUNCTION_ENTER at the start of the function expands to
;; NOPs which must be present. Don't outline them.
define void @patchable0(i1 %a) nounwind "patchable-function-entry"="2" {
; CHECK-LABEL: patchable0:
; CHECK-NEXT: .Lfunc_begin0:
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: nop
; CHECK-NEXT: nop
; CHECK: # %bb.1:
; CHECK-NEXT: call t0, OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

define void @patchable1(i1 %a) nounwind "patchable-function-entry"="2" {
; CHECK-LABEL: patchable1:
; CHECK-NEXT: .Lfunc_begin1:
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: nop
; CHECK-NEXT: nop
; CHECK: # %bb.1:
; CHECK-NEXT: call t0, OUTLINED_FUNCTION_1
entry:
br i1 %a, label %if.then, label %if.end
if.then:
call void @foo(i32 1, i32 2, i32 3, i32 4)
br label %if.end
if.end:
call void @foo(i32 5, i32 6, i32 7, i32 8)
ret void
}

0 comments on commit a6a07a5

Please sign in to comment.