From 0e094e1e8e3c1c6b55ec27f5efd9d7e93e9e18c5 Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Tue, 18 Feb 2025 20:57:48 +0530 Subject: [PATCH 1/3] Pre commit test --- .../machine-outliner-call-x5-liveout.mir | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir diff --git a/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir new file mode 100644 index 0000000000000..b2ca01faebce2 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir @@ -0,0 +1,140 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5 +# RUN: llc -mtriple=riscv32 -x mir -run-pass=machine-outliner -simplify-mir -verify-machineinstrs < %s \ +# RUN: | FileCheck -check-prefixes=RV32I-MO %s +# RUN: llc -mtriple=riscv64 -x mir -run-pass=machine-outliner -simplify-mir -verify-machineinstrs < %s \ +# RUN: | FileCheck -check-prefixes=RV64I-MO %s + +# MIR has been edited by hand to have x5 as live out in @dont_outline + +--- | + define i32 @outline_0(i32 %a, i32 %b) { ret i32 0 } + + ; Can't outline if x5 is live out of the MBB + define i32 @dont_outline(i32 %a, i32 %b) { ret i32 0 } + + define i32 @outline_1(i32 %a, i32 %b) { ret i32 0 } + + define i32 @outline_2(i32 %a, i32 %b) { ret i32 0 } +... +--- + +name: outline_0 +tracksRegLiveness: true +isOutlined: false +body: | + bb.0: + liveins: $x10, $x11 + + ; RV32I-MO-LABEL: name: outline_0 + ; RV32I-MO: liveins: $x10, $x11 + ; RV32I-MO-NEXT: {{ $}} + ; RV32I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV32I-MO-NEXT: PseudoRET implicit $x11 + ; + ; RV64I-MO-LABEL: name: outline_0 + ; RV64I-MO: liveins: $x10, $x11 + ; RV64I-MO-NEXT: {{ $}} + ; RV64I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV64I-MO-NEXT: PseudoRET implicit $x11 + $x11 = ORI $x11, 1023 + $x12 = ADDI $x10, 17 + $x11 = AND $x12, $x11 + $x10 = SUB $x10, $x11 + PseudoRET implicit $x11 + +... +--- + +name: dont_outline +tracksRegLiveness: true +isOutlined: false +body: | + ; RV32I-MO-LABEL: name: dont_outline + ; RV32I-MO: bb.0: + ; RV32I-MO-NEXT: liveins: $x10, $x11 + ; RV32I-MO-NEXT: {{ $}} + ; RV32I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV32I-MO-NEXT: BEQ $x10, $x11, %bb.1 + ; RV32I-MO-NEXT: {{ $}} + ; RV32I-MO-NEXT: bb.1: + ; RV32I-MO-NEXT: liveins: $x10, $x5 + ; RV32I-MO-NEXT: {{ $}} + ; RV32I-MO-NEXT: PseudoRET implicit $x10, implicit $x5 + ; + ; RV64I-MO-LABEL: name: dont_outline + ; RV64I-MO: bb.0: + ; RV64I-MO-NEXT: liveins: $x10, $x11 + ; RV64I-MO-NEXT: {{ $}} + ; RV64I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV64I-MO-NEXT: BEQ $x10, $x11, %bb.1 + ; RV64I-MO-NEXT: {{ $}} + ; RV64I-MO-NEXT: bb.1: + ; RV64I-MO-NEXT: liveins: $x10, $x5 + ; RV64I-MO-NEXT: {{ $}} + ; RV64I-MO-NEXT: PseudoRET implicit $x10, implicit $x5 + bb.0: + liveins: $x10, $x11 + + $x11 = ORI $x11, 1023 + $x12 = ADDI $x10, 17 + $x11 = AND $x12, $x11 + $x10 = SUB $x10, $x11 + BEQ $x10, $x11, %bb.1 + + bb.1: + liveins: $x10, $x5 + PseudoRET implicit $x10, implicit $x5 + +... +--- + +name: outline_1 +tracksRegLiveness: true +isOutlined: false +body: | + bb.0: + liveins: $x10, $x11 + + ; RV32I-MO-LABEL: name: outline_1 + ; RV32I-MO: liveins: $x10, $x11 + ; RV32I-MO-NEXT: {{ $}} + ; RV32I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV32I-MO-NEXT: PseudoRET implicit $x10 + ; + ; RV64I-MO-LABEL: name: outline_1 + ; RV64I-MO: liveins: $x10, $x11 + ; RV64I-MO-NEXT: {{ $}} + ; RV64I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV64I-MO-NEXT: PseudoRET implicit $x10 + $x11 = ORI $x11, 1023 + $x12 = ADDI $x10, 17 + $x11 = AND $x12, $x11 + $x10 = SUB $x10, $x11 + PseudoRET implicit $x10 + +... +--- +name: outline_2 +tracksRegLiveness: true +isOutlined: false +body: | + bb.0: + liveins: $x10, $x11 + + ; RV32I-MO-LABEL: name: outline_2 + ; RV32I-MO: liveins: $x10, $x11 + ; RV32I-MO-NEXT: {{ $}} + ; RV32I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV32I-MO-NEXT: PseudoRET implicit $x12 + ; + ; RV64I-MO-LABEL: name: outline_2 + ; RV64I-MO: liveins: $x10, $x11 + ; RV64I-MO-NEXT: {{ $}} + ; RV64I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV64I-MO-NEXT: PseudoRET implicit $x12 + $x11 = ORI $x11, 1023 + $x12 = ADDI $x10, 17 + $x11 = AND $x12, $x11 + $x10 = SUB $x10, $x11 + PseudoRET implicit $x12 +... From 588fef888ade1f58665d8c705376fa189450138d Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Tue, 18 Feb 2025 21:33:06 +0530 Subject: [PATCH 2/3] Analyze all candidates --- llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 52 ++++++++----------- .../machine-outliner-call-x5-liveout.mir | 10 +++- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp index 456fb66917216..bc859887c4aac 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -3015,30 +3015,25 @@ static bool cannotInsertTailCall(const MachineBasicBlock &MBB) { return false; } -static std::optional -analyzeCandidate(outliner::Candidate &C) { +static bool analyzeCandidate(outliner::Candidate &C) { // If last instruction is return then we can rely on // the verification already performed in the getOutliningTypeImpl. if (C.back().isReturn()) { assert(!cannotInsertTailCall(*C.getMBB()) && "The candidate who uses return instruction must be outlined " "using tail call"); - return MachineOutlinerTailCall; + return false; } - auto CandidateUsesX5 = [](outliner::Candidate &C) { - const TargetRegisterInfo *TRI = C.getMF()->getSubtarget().getRegisterInfo(); - if (std::any_of(C.begin(), C.end(), [TRI](const MachineInstr &MI) { - return isMIModifiesReg(MI, TRI, RISCV::X5); - })) - return true; - return !C.isAvailableAcrossAndOutOfSeq(RISCV::X5, *TRI); - }; - - if (!CandidateUsesX5(C)) - return MachineOutlinerDefault; + // Filter out candidates where the X5 register (t0) can't be used to setup + // the function call. + const TargetRegisterInfo *TRI = C.getMF()->getSubtarget().getRegisterInfo(); + if (std::any_of(C.begin(), C.end(), [TRI](const MachineInstr &MI) { + return isMIModifiesReg(MI, TRI, RISCV::X5); + })) + return true; - return std::nullopt; + return !C.isAvailableAcrossAndOutOfSeq(RISCV::X5, *TRI); } std::optional> @@ -3047,35 +3042,32 @@ RISCVInstrInfo::getOutliningCandidateInfo( std::vector &RepeatedSequenceLocs, unsigned MinRepeats) const { - // Each RepeatedSequenceLoc is identical. - outliner::Candidate &Candidate = RepeatedSequenceLocs[0]; - auto CandidateInfo = analyzeCandidate(Candidate); - if (!CandidateInfo) - RepeatedSequenceLocs.clear(); + // Analyze each candidate and erase the ones that are not viable. + llvm::erase_if(RepeatedSequenceLocs, analyzeCandidate); // If the sequence doesn't have enough candidates left, then we're done. if (RepeatedSequenceLocs.size() < MinRepeats) return std::nullopt; + // Each RepeatedSequenceLoc is identical. + outliner::Candidate &Candidate = RepeatedSequenceLocs[0]; unsigned InstrSizeCExt = Candidate.getMF()->getSubtarget().hasStdExtCOrZca() ? 2 : 4; unsigned CallOverhead = 0, FrameOverhead = 0; - MachineOutlinerConstructionID MOCI = CandidateInfo.value(); - switch (MOCI) { - case MachineOutlinerDefault: - // call t0, function = 8 bytes. - CallOverhead = 8; - // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled. - FrameOverhead = InstrSizeCExt; - break; - case MachineOutlinerTailCall: + MachineOutlinerConstructionID MOCI = MachineOutlinerDefault; + if (Candidate.back().isReturn()) { + MOCI = MachineOutlinerTailCall; // tail call = auipc + jalr in the worst case without linker relaxation. CallOverhead = 4 + InstrSizeCExt; // Using tail call we move ret instruction from caller to callee. FrameOverhead = 0; - break; + } else { + // call t0, function = 8 bytes. + CallOverhead = 8; + // jr t0 = 4 bytes, 2 bytes if compressed instructions are enabled. + FrameOverhead = InstrSizeCExt; } for (auto &C : RepeatedSequenceLocs) diff --git a/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir index b2ca01faebce2..5da06850e5a67 100644 --- a/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir +++ b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir @@ -53,7 +53,10 @@ body: | ; RV32I-MO: bb.0: ; RV32I-MO-NEXT: liveins: $x10, $x11 ; RV32I-MO-NEXT: {{ $}} - ; RV32I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV32I-MO-NEXT: $x11 = ORI $x11, 1023 + ; RV32I-MO-NEXT: $x12 = ADDI $x10, 17 + ; RV32I-MO-NEXT: $x11 = AND $x12, $x11 + ; RV32I-MO-NEXT: $x10 = SUB $x10, $x11 ; RV32I-MO-NEXT: BEQ $x10, $x11, %bb.1 ; RV32I-MO-NEXT: {{ $}} ; RV32I-MO-NEXT: bb.1: @@ -65,7 +68,10 @@ body: | ; RV64I-MO: bb.0: ; RV64I-MO-NEXT: liveins: $x10, $x11 ; RV64I-MO-NEXT: {{ $}} - ; RV64I-MO-NEXT: $x5 = PseudoCALLReg target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit-def $x5, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x10, implicit $x11 + ; RV64I-MO-NEXT: $x11 = ORI $x11, 1023 + ; RV64I-MO-NEXT: $x12 = ADDI $x10, 17 + ; RV64I-MO-NEXT: $x11 = AND $x12, $x11 + ; RV64I-MO-NEXT: $x10 = SUB $x10, $x11 ; RV64I-MO-NEXT: BEQ $x10, $x11, %bb.1 ; RV64I-MO-NEXT: {{ $}} ; RV64I-MO-NEXT: bb.1: From 16e0ce728aa6546650304a5a0847df1836aad524 Mon Sep 17 00:00:00 2001 From: Sudharsan Veeravalli Date: Wed, 19 Feb 2025 07:08:18 +0530 Subject: [PATCH 3/3] Remove IR from test --- .../CodeGen/RISCV/machine-outliner-call-x5-liveout.mir | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir index 5da06850e5a67..f7bea33e52885 100644 --- a/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir +++ b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir @@ -6,16 +6,6 @@ # MIR has been edited by hand to have x5 as live out in @dont_outline ---- | - define i32 @outline_0(i32 %a, i32 %b) { ret i32 0 } - - ; Can't outline if x5 is live out of the MBB - define i32 @dont_outline(i32 %a, i32 %b) { ret i32 0 } - - define i32 @outline_1(i32 %a, i32 %b) { ret i32 0 } - - define i32 @outline_2(i32 %a, i32 %b) { ret i32 0 } -... --- name: outline_0