diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -21,6 +21,8 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/MC/MCDwarf.h" +#include + using namespace llvm; // For now we use x18, a.k.a s2, as pointer to shadow call stack. @@ -941,14 +943,48 @@ return std::make_pair(StackSize, RVVStackAlign); } -static bool hasRVVSpillWithFIs(MachineFunction &MF) { +static unsigned getScavSlotsNumForRVV(MachineFunction &MF) { + // For RVV spill, scalable stack offsets computing requires up to two scratch + // registers + static constexpr unsigned ScavSlotsNumRVVSpillScalableObject = 2; + + // For RVV spill, non-scalable stack offsets computing requires up to one + // scratch register. + static constexpr unsigned ScavSlotsNumRVVSpillNonScalableObject = 1; + + // ADDI instruction's destination register can be used for computing + // offsets. So Scalable stack offsets require up to one scratch register. + static constexpr unsigned ScavSlotsADDIScalableObject = 1; + + static constexpr unsigned MaxScavSlotsNumKnown = + std::max({ScavSlotsADDIScalableObject, ScavSlotsNumRVVSpillScalableObject, + ScavSlotsNumRVVSpillNonScalableObject}); + + unsigned MaxScavSlotsNum = 0; if (!MF.getSubtarget().hasVInstructions()) return false; for (const MachineBasicBlock &MBB : MF) - for (const MachineInstr &MI : MBB) - if (RISCV::isRVVSpill(MI, /*CheckFIs*/ true)) - return true; - return false; + for (const MachineInstr &MI : MBB) { + bool IsRVVSpill = RISCV::isRVVSpill(MI); + for (auto &MO : MI.operands()) { + if (!MO.isFI()) + continue; + bool IsScalableVectorID = MF.getFrameInfo().getStackID(MO.getIndex()) == + TargetStackID::ScalableVector; + if (IsRVVSpill) { + MaxScavSlotsNum = std::max( + MaxScavSlotsNum, IsScalableVectorID + ? ScavSlotsNumRVVSpillScalableObject + : ScavSlotsNumRVVSpillNonScalableObject); + } else if (MI.getOpcode() == RISCV::ADDI && IsScalableVectorID) { + MaxScavSlotsNum = + std::max(MaxScavSlotsNum, ScavSlotsADDIScalableObject); + } + } + if (MaxScavSlotsNum == MaxScavSlotsNumKnown) + return MaxScavSlotsNumKnown; + } + return MaxScavSlotsNum; } void RISCVFrameLowering::processFunctionBeforeFrameFinalized( @@ -980,17 +1016,14 @@ // RVV loads & stores have no capacity to hold the immediate address offsets // so we must always reserve an emergency spill slot if the MachineFunction // contains any RVV spills. - if (!isInt<11>(MFI.estimateStackSize(MF)) || hasRVVSpillWithFIs(MF)) { - int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC), - RegInfo->getSpillAlign(*RC), false); - RS->addScavengingFrameIndex(RegScavFI); - // For RVV, scalable stack offsets require up to two scratch registers to - // compute the final offset. Reserve an additional emergency spill slot. - if (RVVStackSize != 0) { - int RVVRegScavFI = MFI.CreateStackObject( - RegInfo->getSpillSize(*RC), RegInfo->getSpillAlign(*RC), false); - RS->addScavengingFrameIndex(RVVRegScavFI); - } + unsigned ScavSlotsNum = 0; + if (!isInt<11>(MFI.estimateStackSize(MF))) + ScavSlotsNum = 1; + + ScavSlotsNum = std::max(ScavSlotsNum, getScavSlotsNumForRVV(MF)); + for (unsigned i = 0; i < ScavSlotsNum; i++) { + RS->addScavengingFrameIndex(MFI.CreateStackObject( + RegInfo->getSpillSize(*RC), RegInfo->getSpillAlign(*RC), false)); } if (MFI.getCalleeSavedInfo().empty() || RVFI->useSaveRestoreLibCalls(MF)) { diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h @@ -184,9 +184,8 @@ namespace RISCV { // Returns true if the given MI is an RVV instruction opcode for which we may -// expect to see a FrameIndex operand. When CheckFIs is true, the instruction -// must contain at least one FrameIndex operand. -bool isRVVSpill(const MachineInstr &MI, bool CheckFIs); +// expect to see a FrameIndex operand. +bool isRVVSpill(const MachineInstr &MI); Optional> isRVVSpillForZvlsseg(unsigned Opcode); diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -1880,16 +1880,14 @@ } } -bool RISCV::isRVVSpill(const MachineInstr &MI, bool CheckFIs) { +bool RISCV::isRVVSpill(const MachineInstr &MI) { // RVV lacks any support for immediate addressing for stack addresses, so be // conservative. unsigned Opcode = MI.getOpcode(); if (!RISCVVPseudosTable::getPseudoInfo(Opcode) && !isRVVWholeLoadStore(Opcode) && !isRVVSpillForZvlsseg(Opcode)) return false; - return !CheckFIs || any_of(MI.operands(), [](const MachineOperand &MO) { - return MO.isFI(); - }); + return true; } Optional> diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -174,7 +174,7 @@ Register FrameReg; StackOffset Offset = getFrameLowering(MF)->getFrameIndexReference(MF, FrameIndex, FrameReg); - bool IsRVVSpill = RISCV::isRVVSpill(MI, /*CheckFIs*/ false); + bool IsRVVSpill = RISCV::isRVVSpill(MI); if (!IsRVVSpill) Offset += StackOffset::getFixed(MI.getOperand(FIOperandNum + 1).getImm()); diff --git a/llvm/test/CodeGen/RISCV/rvv/addi-rvv-stack-object.mir b/llvm/test/CodeGen/RISCV/rvv/addi-rvv-stack-object.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/addi-rvv-stack-object.mir @@ -0,0 +1,60 @@ +# RUN: llc -mtriple=riscv64 -mattr=+v -run-pass prologepilog %s -o - | FileCheck %s +--- | + declare void @extern(*) #0 + + define void @addi_rvv_stack_object() #0 { + %local0 = alloca , align 16 + call void @extern(* %local0) + ret void + } + + attributes #0 = { "target-features"="+v" } + +... +--- +name: addi_rvv_stack_object +alignment: 4 +frameInfo: + isFrameAddressTaken: false + isReturnAddressTaken: false + hasStackMap: false + hasPatchPoint: false + stackSize: 0 + offsetAdjustment: 0 + maxAlignment: 16 + adjustsStack: false + hasCalls: true + stackProtector: '' + functionContext: '' + maxCallFrameSize: 4294967295 + cvBytesOfCalleeSavedRegisters: 0 + hasOpaqueSPAdjustment: false + hasVAStart: false + hasMustTailInVarArgFunc: false + hasTailCall: false + localFrameSize: 0 + savePoint: '' + restorePoint: '' +fixedStack: [] +stack: + - { id: 0, name: local0, type: default, offset: 0, size: 16, alignment: 16, + stack-id: scalable-vector, callee-saved-register: '', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +# CHECK: - { id: 2, name: '', type: default, offset: -16, size: 8, alignment: 8, +# CHECK: stack-id: default, callee-saved-register: '', callee-saved-restored: true, +# CHECK: debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +callSites: [] +debugValueSubstitutions: [] +constants: [] +machineFunctionInfo: + varArgsFrameIndex: 0 + varArgsSaveSize: 0 +body: | + bb.0 (%ir-block.0): + ADJCALLSTACKDOWN 0, 0, implicit-def dead $x2, implicit $x2 + $x10 = ADDI %stack.0.local0, 0 + PseudoCALL target-flags(riscv-plt) @extern, csr_ilp32d_lp64d, implicit-def dead $x1, implicit killed $x10, implicit-def $x2 + ADJCALLSTACKUP 0, 0, implicit-def dead $x2, implicit $x2 + PseudoRET + +... diff --git a/llvm/test/CodeGen/RISCV/rvv/rvv-stack-align.mir b/llvm/test/CodeGen/RISCV/rvv/rvv-stack-align.mir --- a/llvm/test/CodeGen/RISCV/rvv/rvv-stack-align.mir +++ b/llvm/test/CodeGen/RISCV/rvv/rvv-stack-align.mir @@ -122,22 +122,22 @@ ; ; RV64-LABEL: rvv_stack_align32: ; RV64: # %bb.0: - ; RV64-NEXT: addi sp, sp, -48 - ; RV64-NEXT: sd ra, 40(sp) # 8-byte Folded Spill - ; RV64-NEXT: sd s0, 32(sp) # 8-byte Folded Spill - ; RV64-NEXT: addi s0, sp, 48 + ; RV64-NEXT: addi sp, sp, -80 + ; RV64-NEXT: sd ra, 72(sp) # 8-byte Folded Spill + ; RV64-NEXT: sd s0, 64(sp) # 8-byte Folded Spill + ; RV64-NEXT: addi s0, sp, 80 ; RV64-NEXT: csrr a0, vlenb ; RV64-NEXT: slli a0, a0, 2 ; RV64-NEXT: sub sp, sp, a0 ; RV64-NEXT: andi sp, sp, -32 - ; RV64-NEXT: addi a0, sp, 32 - ; RV64-NEXT: addi a1, sp, 8 - ; RV64-NEXT: mv a2, sp + ; RV64-NEXT: addi a0, sp, 64 + ; RV64-NEXT: addi a1, sp, 40 + ; RV64-NEXT: addi a2, sp, 32 ; RV64-NEXT: call extern@plt - ; RV64-NEXT: addi sp, s0, -48 - ; RV64-NEXT: ld ra, 40(sp) # 8-byte Folded Reload - ; RV64-NEXT: ld s0, 32(sp) # 8-byte Folded Reload - ; RV64-NEXT: addi sp, sp, 48 + ; RV64-NEXT: addi sp, s0, -80 + ; RV64-NEXT: ld ra, 72(sp) # 8-byte Folded Reload + ; RV64-NEXT: ld s0, 64(sp) # 8-byte Folded Reload + ; RV64-NEXT: addi sp, sp, 80 ; RV64-NEXT: ret %a = alloca , align 32 %b = alloca i64 diff --git a/llvm/test/CodeGen/RISCV/rvv/scalar-stack-align.ll b/llvm/test/CodeGen/RISCV/rvv/scalar-stack-align.ll --- a/llvm/test/CodeGen/RISCV/rvv/scalar-stack-align.ll +++ b/llvm/test/CodeGen/RISCV/rvv/scalar-stack-align.ll @@ -13,36 +13,36 @@ define i64* @scalar_stack_align16() nounwind { ; RV32-LABEL: scalar_stack_align16: ; RV32: # %bb.0: -; RV32-NEXT: addi sp, sp, -32 -; RV32-NEXT: sw ra, 28(sp) # 4-byte Folded Spill +; RV32-NEXT: addi sp, sp, -48 +; RV32-NEXT: sw ra, 44(sp) # 4-byte Folded Spill ; RV32-NEXT: csrr a0, vlenb ; RV32-NEXT: slli a0, a0, 1 ; RV32-NEXT: sub sp, sp, a0 -; RV32-NEXT: addi a0, sp, 16 +; RV32-NEXT: addi a0, sp, 32 ; RV32-NEXT: call extern@plt -; RV32-NEXT: mv a0, sp +; RV32-NEXT: addi a0, sp, 16 ; RV32-NEXT: csrr a1, vlenb ; RV32-NEXT: slli a1, a1, 1 ; RV32-NEXT: add sp, sp, a1 -; RV32-NEXT: lw ra, 28(sp) # 4-byte Folded Reload -; RV32-NEXT: addi sp, sp, 32 +; RV32-NEXT: lw ra, 44(sp) # 4-byte Folded Reload +; RV32-NEXT: addi sp, sp, 48 ; RV32-NEXT: ret ; ; RV64-LABEL: scalar_stack_align16: ; RV64: # %bb.0: -; RV64-NEXT: addi sp, sp, -32 -; RV64-NEXT: sd ra, 24(sp) # 8-byte Folded Spill +; RV64-NEXT: addi sp, sp, -48 +; RV64-NEXT: sd ra, 40(sp) # 8-byte Folded Spill ; RV64-NEXT: csrr a0, vlenb ; RV64-NEXT: slli a0, a0, 1 ; RV64-NEXT: sub sp, sp, a0 -; RV64-NEXT: addi a0, sp, 16 +; RV64-NEXT: addi a0, sp, 32 ; RV64-NEXT: call extern@plt -; RV64-NEXT: mv a0, sp +; RV64-NEXT: addi a0, sp, 16 ; RV64-NEXT: csrr a1, vlenb ; RV64-NEXT: slli a1, a1, 1 ; RV64-NEXT: add sp, sp, a1 -; RV64-NEXT: ld ra, 24(sp) # 8-byte Folded Reload -; RV64-NEXT: addi sp, sp, 32 +; RV64-NEXT: ld ra, 40(sp) # 8-byte Folded Reload +; RV64-NEXT: addi sp, sp, 48 ; RV64-NEXT: ret %a = alloca %c = alloca i64, align 16