diff --git a/lib/Target/Mips/MipsSERegisterInfo.cpp b/lib/Target/Mips/MipsSERegisterInfo.cpp index 2be054eef5e..2d440840aaf 100644 --- a/lib/Target/Mips/MipsSERegisterInfo.cpp +++ b/lib/Target/Mips/MipsSERegisterInfo.cpp @@ -62,6 +62,24 @@ MipsSERegisterInfo::intRegClass(unsigned Size) const { return &Mips::GPR64RegClass; } +/// Determine whether a given opcode is an MSA load/store (supporting 10-bit +/// offsets) or a non-MSA load/store (supporting 16-bit offsets). +static inline bool isMSALoadOrStore(const unsigned Opcode) { + switch (Opcode) { + case Mips::LD_B: + case Mips::LD_H: + case Mips::LD_W: + case Mips::LD_D: + case Mips::ST_B: + case Mips::ST_H: + case Mips::ST_W: + case Mips::ST_D: + return true; + default: + return false; + } +} + void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, unsigned OpNo, int FrameIndex, uint64_t StackSize, @@ -111,18 +129,42 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, DEBUG(errs() << "Offset : " << Offset << "\n" << "<--------->\n"); - // If MI is not a debug value, make sure Offset fits in the 16-bit immediate - // field. if (!MI.isDebugValue()) { - if (!isInt<16>(Offset)) { + // Make sure Offset fits within the field available. + // For MSA instructions, this is a 10-bit signed immediate, otherwise it is + // a 16-bit signed immediate. + unsigned OffsetBitSize = isMSALoadOrStore(MI.getOpcode()) ? 10 : 16; + + if (OffsetBitSize == 10 && !isInt<10>(Offset) && isInt<16>(Offset)) { + // If we have an offset that needs to fit into a signed 10-bit immediate + // and doesn't, but does fit into 16-bits then use an ADDiu MachineBasicBlock &MBB = *MI.getParent(); DebugLoc DL = II->getDebugLoc(); - unsigned ADDu = Subtarget.isABI_N64() ? Mips::DADDu : Mips::ADDu; - unsigned NewImm; + unsigned ADDiu = Subtarget.isABI_N64() ? Mips::DADDiu : Mips::ADDiu; + const TargetRegisterClass *RC = + Subtarget.isABI_N64() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; + MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); + unsigned Reg = RegInfo.createVirtualRegister(RC); const MipsSEInstrInfo &TII = *static_cast( MBB.getParent()->getTarget().getInstrInfo()); - unsigned Reg = TII.loadImmediate(Offset, MBB, II, DL, &NewImm); + BuildMI(MBB, II, DL, TII.get(ADDiu), Reg).addReg(FrameReg).addImm(Offset); + + FrameReg = Reg; + Offset = 0; + IsKill = true; + } else if (!isInt<16>(Offset)) { + // Otherwise split the offset into 16-bit pieces and add it in multiple + // instructions. + MachineBasicBlock &MBB = *MI.getParent(); + DebugLoc DL = II->getDebugLoc(); + unsigned ADDu = Subtarget.isABI_N64() ? Mips::DADDu : Mips::ADDu; + unsigned NewImm = 0; + const MipsSEInstrInfo &TII = + *static_cast( + MBB.getParent()->getTarget().getInstrInfo()); + unsigned Reg = TII.loadImmediate(Offset, MBB, II, DL, + OffsetBitSize == 16 ? &NewImm : NULL); BuildMI(MBB, II, DL, TII.get(ADDu), Reg).addReg(FrameReg) .addReg(Reg, RegState::Kill); diff --git a/test/CodeGen/Mips/msa/frameindex.ll b/test/CodeGen/Mips/msa/frameindex.ll new file mode 100644 index 00000000000..3088e1ba989 --- /dev/null +++ b/test/CodeGen/Mips/msa/frameindex.ll @@ -0,0 +1,85 @@ +; RUN: llc -march=mips -mattr=+msa,+fp64 < %s | FileCheck -check-prefix=MIPS32-AE -check-prefix=MIPS32-BE %s +; RUN: llc -march=mipsel -mattr=+msa,+fp64 < %s | FileCheck -check-prefix=MIPS32-AE -check-prefix=MIPS32-LE %s + +define void @loadstore_v16i8_near() nounwind { + ; MIPS32-AE: loadstore_v16i8_near: + + %1 = alloca <16 x i8> + %2 = load volatile <16 x i8>* %1 + ; MIPS32-AE: ld.b [[R1:\$w[0-9]+]], 0($sp) + store volatile <16 x i8> %2, <16 x i8>* %1 + ; MIPS32-AE: st.b [[R1]], 0($sp) + + ret void + ; MIPS32-AE: .size loadstore_v16i8_near +} + +define void @loadstore_v16i8_just_under_simm10() nounwind { + ; MIPS32-AE: loadstore_v16i8_just_under_simm10: + + %1 = alloca <16 x i8> + %2 = alloca [496 x i8] ; Push the frame right up to 512 bytes + + %3 = load volatile <16 x i8>* %1 + ; MIPS32-AE: ld.b [[R1:\$w[0-9]+]], 496($sp) + store volatile <16 x i8> %3, <16 x i8>* %1 + ; MIPS32-AE: st.b [[R1]], 496($sp) + + ret void + ; MIPS32-AE: .size loadstore_v16i8_just_under_simm10 +} + +define void @loadstore_v16i8_just_over_simm10() nounwind { + ; MIPS32-AE: loadstore_v16i8_just_over_simm10: + + %1 = alloca <16 x i8> + %2 = alloca [497 x i8] ; Push the frame just over 512 bytes + + %3 = load volatile <16 x i8>* %1 + ; MIPS32-AE: addiu [[BASE:\$[0-9]+]], $sp, 512 + ; MIPS32-AE: ld.b [[R1:\$w[0-9]+]], 0([[BASE]]) + store volatile <16 x i8> %3, <16 x i8>* %1 + ; MIPS32-AE: addiu [[BASE:\$[0-9]+]], $sp, 512 + ; MIPS32-AE: st.b [[R1]], 0([[BASE]]) + + ret void + ; MIPS32-AE: .size loadstore_v16i8_just_over_simm10 +} + +define void @loadstore_v16i8_just_under_simm16() nounwind { + ; MIPS32-AE: loadstore_v16i8_just_under_simm16: + + %1 = alloca <16 x i8> + %2 = alloca [32752 x i8] ; Push the frame right up to 32768 bytes + + %3 = load volatile <16 x i8>* %1 + ; MIPS32-AE: ori [[R2:\$[0-9]+]], $zero, 32768 + ; MIPS32-AE: addu [[BASE:\$[0-9]+]], $sp, [[R2]] + ; MIPS32-AE: ld.b [[R1:\$w[0-9]+]], 0([[BASE]]) + store volatile <16 x i8> %3, <16 x i8>* %1 + ; MIPS32-AE: ori [[R2:\$[0-9]+]], $zero, 32768 + ; MIPS32-AE: addu [[BASE:\$[0-9]+]], $sp, [[R2]] + ; MIPS32-AE: st.b [[R1]], 0([[BASE]]) + + ret void + ; MIPS32-AE: .size loadstore_v16i8_just_under_simm16 +} + +define void @loadstore_v16i8_just_over_simm16() nounwind { + ; MIPS32-AE: loadstore_v16i8_just_over_simm16: + + %1 = alloca <16 x i8> + %2 = alloca [32753 x i8] ; Push the frame just over 32768 bytes + + %3 = load volatile <16 x i8>* %1 + ; MIPS32-AE: ori [[R2:\$[0-9]+]], $zero, 32768 + ; MIPS32-AE: addu [[BASE:\$[0-9]+]], $sp, [[R2]] + ; MIPS32-AE: ld.b [[R1:\$w[0-9]+]], 0([[BASE]]) + store volatile <16 x i8> %3, <16 x i8>* %1 + ; MIPS32-AE: ori [[R2:\$[0-9]+]], $zero, 32768 + ; MIPS32-AE: addu [[BASE:\$[0-9]+]], $sp, [[R2]] + ; MIPS32-AE: st.b [[R1]], 0([[BASE]]) + + ret void + ; MIPS32-AE: .size loadstore_v16i8_just_over_simm16 +}