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 new file mode 100644 index 0000000000000..f7bea33e52885 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/machine-outliner-call-x5-liveout.mir @@ -0,0 +1,136 @@ +# 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 + +--- + +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: $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: + ; 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: $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: + ; 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 +...