diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -5824,31 +5824,43 @@ else if (C.UsedInSequence.available(ARM::SP)) { NumBytesNoStackCalls += Costs.CallDefault; C.setCallInfo(MachineOutlinerDefault, Costs.CallDefault); - SetCandidateCallInfo(MachineOutlinerDefault, Costs.CallDefault); CandidatesWithoutStackFixups.push_back(C); - } else - return outliner::OutlinedFunction(); - } + } - // Does every candidate's MBB contain a call? If so, then we might have a - // call in the range. - if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) { - // check if the range contains a call. These require a save + restore of - // the link register. - if (std::any_of(FirstCand.front(), FirstCand.back(), - [](const MachineInstr &MI) { return MI.isCall(); })) - NumBytesToCreateFrame += Costs.SaveRestoreLROnStack; - - // Handle the last instruction separately. If it is tail call, then the - // last instruction is a call, we don't want to save + restore in this - // case. However, it could be possible that the last instruction is a - // call without it being valid to tail call this sequence. We should - // consider this as well. - else if (FrameID != MachineOutlinerThunk && - FrameID != MachineOutlinerTailCall && FirstCand.back()->isCall()) - NumBytesToCreateFrame += Costs.SaveRestoreLROnStack; + // If we outline this, we need to modify the stack. Pretend we don't + // outline this by saving all of its bytes. + else + NumBytesNoStackCalls += SequenceSize; } - RepeatedSequenceLocs = CandidatesWithoutStackFixups; + + // If there are no places where we have to save LR, then note that we don't + // have to update the stack. Otherwise, give every candidate the default + // call type + if (NumBytesNoStackCalls <= + RepeatedSequenceLocs.size() * Costs.CallDefault) { + RepeatedSequenceLocs = CandidatesWithoutStackFixups; + FrameID = MachineOutlinerNoLRSave; + } else + SetCandidateCallInfo(MachineOutlinerDefault, Costs.CallDefault); + } + + // Does every candidate's MBB contain a call? If so, then we might have a + // call in the range. + if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) { + // check if the range contains a call. These require a save + restore of + // the link register. + if (std::any_of(FirstCand.front(), FirstCand.back(), + [](const MachineInstr &MI) { return MI.isCall(); })) + NumBytesToCreateFrame += Costs.SaveRestoreLROnStack; + + // Handle the last instruction separately. If it is tail call, then the + // last instruction is a call, we don't want to save + restore in this + // case. However, it could be possible that the last instruction is a + // call without it being valid to tail call this sequence. We should + // consider this as well. + else if (FrameID != MachineOutlinerThunk && + FrameID != MachineOutlinerTailCall && FirstCand.back()->isCall()) + NumBytesToCreateFrame += Costs.SaveRestoreLROnStack; } return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize, diff --git a/llvm/test/CodeGen/ARM/machine-outliner-calls.mir b/llvm/test/CodeGen/ARM/machine-outliner-calls.mir --- a/llvm/test/CodeGen/ARM/machine-outliner-calls.mir +++ b/llvm/test/CodeGen/ARM/machine-outliner-calls.mir @@ -88,15 +88,15 @@ ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 ; CHECK: frame-setup CFI_INSTRUCTION offset $r7, -8 - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 ; CHECK: bb.1: - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 ; CHECK: bb.2: - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 ; CHECK: bb.3: - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 ; CHECK: bb.4: - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 ; CHECK: bb.5: ; CHECK: $sp = frame-destroy t2LDMIA_RET $sp, 14 /* CC::al */, $noreg, def $r7, def $pc bb.0: @@ -139,12 +139,14 @@ ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 ; CHECK: frame-setup CFI_INSTRUCTION offset $r4, -8 - ; CHECK: BL @OUTLINED_FUNCTION_2 + ; CHECK: BL @OUTLINED_FUNCTION_1 ; CHECK: bb.1: - ; CHECK: BL @OUTLINED_FUNCTION_2 + ; CHECK: BL @OUTLINED_FUNCTION_1 ; CHECK: bb.2: - ; CHECK: BL @OUTLINED_FUNCTION_2 + ; CHECK: BL @OUTLINED_FUNCTION_1 ; CHECK: bb.3: + ; CHECK: BL @OUTLINED_FUNCTION_1 + ; CHECK: bb.4: ; CHECK: $sp = frame-destroy LDMIA_UPD $sp, 14 /* CC::al */, $noreg, def $r4, def $lr ; CHECK: BX_RET 14 /* CC::al */, $noreg bb.0: @@ -172,6 +174,14 @@ $r4 = MOVi 2, 14, $noreg, $noreg BL @bar, implicit-def dead $lr, implicit $sp bb.3: + BL @bar, implicit-def dead $lr, implicit $sp + $r0 = MOVi 2, 14, $noreg, $noreg + $r1 = MOVi 2, 14, $noreg, $noreg + $r2 = MOVi 2, 14, $noreg, $noreg + $r3 = MOVi 2, 14, $noreg, $noreg + $r4 = MOVi 2, 14, $noreg, $noreg + BL @bar, implicit-def dead $lr, implicit $sp + bb.4: BX_RET 14, $noreg ... --- @@ -186,12 +196,14 @@ ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 ; CHECK: frame-setup CFI_INSTRUCTION offset $r7, -8 - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 ; CHECK: bb.1: - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 ; CHECK: bb.2: - ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_4 + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 ; CHECK: bb.3: + ; CHECK: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_3 + ; CHECK: bb.4: ; CHECK: $sp = frame-destroy t2LDMIA_RET $sp, 14 /* CC::al */, $noreg, def $r7, def $pc bb.0: tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp @@ -212,6 +224,12 @@ $r2 = t2MOVi 2, 14, $noreg, $noreg tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp bb.3: + tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp + $r0 = t2MOVi 2, 14, $noreg, $noreg + $r1 = t2MOVi 2, 14, $noreg, $noreg + $r2 = t2MOVi 2, 14, $noreg, $noreg + tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp + bb.4: tBX_RET 14, $noreg ... --- @@ -227,19 +245,19 @@ ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -4 ; CHECK: frame-setup CFI_INSTRUCTION offset $r4, -8 ; CHECK: BL @"\01mcount", csr_aapcs, implicit-def dead $lr, implicit $sp - ; CHECK: BL @OUTLINED_FUNCTION_1 + ; CHECK: BL @OUTLINED_FUNCTION_2 ; CHECK: bb.1: ; CHECK: BL @"\01mcount", csr_aapcs, implicit-def dead $lr, implicit $sp - ; CHECK: BL @OUTLINED_FUNCTION_1 + ; CHECK: BL @OUTLINED_FUNCTION_2 ; CHECK: bb.2: ; CHECK: BL @"\01mcount", csr_aapcs, implicit-def dead $lr, implicit $sp - ; CHECK: BL @OUTLINED_FUNCTION_1 + ; CHECK: BL @OUTLINED_FUNCTION_2 ; CHECK: bb.3: ; CHECK: BL @"\01mcount", csr_aapcs, implicit-def dead $lr, implicit $sp - ; CHECK: BL @OUTLINED_FUNCTION_1 + ; CHECK: BL @OUTLINED_FUNCTION_2 ; CHECK: bb.4: ; CHECK: BL @"\01mcount", csr_aapcs, implicit-def dead $lr, implicit $sp - ; CHECK: BL @OUTLINED_FUNCTION_1 + ; CHECK: BL @OUTLINED_FUNCTION_2 ; CHECK: bb.5: ; CHECK: $sp = frame-destroy LDMIA_UPD $sp, 14 /* CC::al */, $noreg, def $r4, def $lr ; CHECK: BX_RET 14 /* CC::al */, $noreg @@ -307,16 +325,6 @@ ; CHECK-LABEL: name: OUTLINED_FUNCTION_1 ; CHECK: bb.0: - ; CHECK: liveins: $r11, $r10, $r9, $r8, $r7, $r6, $r5, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8 - ; CHECK: $r0 = MOVi 3, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r1 = MOVi 3, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r2 = MOVi 3, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r3 = MOVi 3, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r4 = MOVi 3, 14 /* CC::al */, $noreg, $noreg - ; CHECK: MOVPCLR 14 /* CC::al */, $noreg - - ; CHECK-LABEL: name: OUTLINED_FUNCTION_2 - ; CHECK: bb.0: ; CHECK: liveins: $r11, $r10, $r9, $r8, $r7, $r6, $r5, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8, $lr ; CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 @@ -330,6 +338,16 @@ ; CHECK: $lr, $sp = LDR_POST_IMM $sp, $noreg, 8, 14 /* CC::al */, $noreg ; CHECK: TAILJMPd @bar, implicit $sp + ; CHECK-LABEL: name: OUTLINED_FUNCTION_2 + ; CHECK: bb.0: + ; CHECK: liveins: $r11, $r10, $r9, $r8, $r7, $r6, $r5, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8 + ; CHECK: $r0 = MOVi 3, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r1 = MOVi 3, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r2 = MOVi 3, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r3 = MOVi 3, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r4 = MOVi 3, 14 /* CC::al */, $noreg, $noreg + ; CHECK: MOVPCLR 14 /* CC::al */, $noreg + ; CHECK-LABEL: name: OUTLINED_FUNCTION_3 ; CHECK: bb.0: ; CHECK: liveins: $r11, $r10, $r9, $r8, $r6, $r5, $r4, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8, $lr @@ -337,11 +355,11 @@ ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -8 ; CHECK: tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp - ; CHECK: $r0 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r1 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r2 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r0 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r1 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r2 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg ; CHECK: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg - ; CHECK: tBX_RET 14 /* CC::al */, $noreg + ; CHECK: tTAILJMPdND @bar, 14 /* CC::al */, $noreg, implicit $sp ; CHECK-LABEL: name: OUTLINED_FUNCTION_4 ; CHECK: bb.0: @@ -350,11 +368,11 @@ ; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8 ; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -8 ; CHECK: tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp - ; CHECK: $r0 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r1 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg - ; CHECK: $r2 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r0 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r1 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg + ; CHECK: $r2 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg ; CHECK: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg - ; CHECK: tTAILJMPdND @bar, 14 /* CC::al */, $noreg, implicit $sp + ; CHECK: tBX_RET 14 /* CC::al */, $noreg diff --git a/llvm/test/CodeGen/ARM/machine-outliner-stack-use.mir b/llvm/test/CodeGen/ARM/machine-outliner-stack-use.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/machine-outliner-stack-use.mir @@ -0,0 +1,58 @@ +# RUN: llc -mtriple=arm-- -run-pass=machine-outliner -verify-machineinstrs \ +# RUN: %s -o - | FileCheck %s + +--- | + define void @stack_use_no_lr_save_1() #0 { ret void } + define void @stack_use_no_lr_save_2() #0 { ret void } + + attributes #0 = { minsize optsize } +... +--- + +name: stack_use_no_lr_save_1 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: stack_use_no_lr_save_1 + ; CHECK: BL @OUTLINED_FUNCTION_0 + $r0 = MOVi 1, 14, $noreg, $noreg + $r0 = MOVi 1, 14, $noreg, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = MOVi 1, 14, $noreg, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = MOVi 1, 14, $noreg, $noreg + bb.1: + liveins: $r0, $r1, $r2, $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11 + BX_RET 14, $noreg +... +--- + +name: stack_use_no_lr_save_2 +tracksRegLiveness: true +body: | + bb.0: + ; CHECK-LABEL: name: stack_use_no_lr_save_2 + ; CHECK: BL @OUTLINED_FUNCTION_0 + $r0 = MOVi 1, 14, $noreg, $noreg + $r0 = MOVi 1, 14, $noreg, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = MOVi 1, 14, $noreg, $noreg + $r0 = LDRi12 $sp, 0, 14, $noreg + $r0 = MOVi 1, 14, $noreg, $noreg + bb.1: + BX_RET 14, $noreg + + ;CHECK: name: OUTLINED_FUNCTION_0 + ;CHECK: $r0 = MOVi 1, 14 /* CC::al */, $noreg, $noreg + ;CHECK-NEXT: $r0 = MOVi 1, 14 /* CC::al */, $noreg, $noreg + ;CHECK-NEXT: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg + ;CHECK-NEXT: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg + ;CHECK-NEXT: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg + ;CHECK-NEXT: $r0 = MOVi 1, 14 /* CC::al */, $noreg, $noreg + ;CHECK-NEXT: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg + ;CHECK-NEXT: $r0 = MOVi 1, 14 /* CC::al */, $noreg, $noreg + ;CHECK-NEXT: MOVPCLR 14 /* CC::al */, $noreg