Index: lib/Target/Mips/MicroMipsSizeReduction.cpp =================================================================== --- lib/Target/Mips/MicroMipsSizeReduction.cpp +++ lib/Target/Mips/MicroMipsSizeReduction.cpp @@ -31,13 +31,14 @@ /// Order of operands to transfer // TODO: Will be extended when additional optimizations are added enum OperandTransfer { - OT_NA, ///< Not applicable - OT_OperandsAll, ///< Transfer all operands - OT_Operands02, ///< Transfer operands 0 and 2 - OT_Operand2, ///< Transfer just operand 2 - OT_OperandsXOR, ///< Transfer operands for XOR16 - OT_OperandsLwp, ///< Transfer operands for LWP - OT_OperandsSwp, ///< Transfer operands for SWP + OT_NA, ///< Not applicable + OT_OperandsAll, ///< Transfer all operands + OT_Operands02, ///< Transfer operands 0 and 2 + OT_Operand2, ///< Transfer just operand 2 + OT_OperandsXOR, ///< Transfer operands for XOR16 + OT_OperandsLwp, ///< Transfer operands for LWP + OT_OperandsSwp, ///< Transfer operands for SWP + OT_OperandsMovep, ///< Transfer operands for MOVEP }; /// Reduction type @@ -170,6 +171,10 @@ // returns true on success. static bool ReduceSXtoSX16(ReduceEntryFunArgs *Arguments); + // Attempts to reduce two MOVE instructions into MOVEP instruction, + // returns true on success. + static bool ReduceMoveToMovep(ReduceEntryFunArgs *Arguments); + // Attempts to reduce arithmetic instructions, returns true on success. static bool ReduceArithmeticInstructions(ReduceEntryFunArgs *Arguments); @@ -243,6 +248,8 @@ OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)}, {RT_OneInstr, OpCodes(Mips::LW_MM, Mips::LWSP_MM), ReduceXWtoXWSP, OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)}, + {RT_TwoInstr, OpCodes(Mips::MOVE16_MM, Mips::MOVEP_MM), ReduceMoveToMovep, + OpInfo(OT_OperandsMovep), ImmField(0, 0, 0, -1)}, {RT_OneInstr, OpCodes(Mips::SB, Mips::SB16_MM), ReduceSXtoSX16, OpInfo(OT_OperandsAll), ImmField(0, 0, 16, 2)}, {RT_OneInstr, OpCodes(Mips::SB_MM, Mips::SB16_MM), ReduceSXtoSX16, @@ -562,6 +569,89 @@ return ReplaceInstruction(MI, Entry); } +// Returns true if Reg can be a source register +// of MOVEP instruction +static bool IsMovepSrcRegister(unsigned Reg) { + + if (Reg == Mips::ZERO || Reg == Mips::V0 || Reg == Mips::V1 || + Reg == Mips::S0 || Reg == Mips::S1 || Reg == Mips::S2 || + Reg == Mips::S3 || Reg == Mips::S4) + return true; + + return false; +} + +// Returns true if Reg can be a destination register +// of MOVEP instruction +static bool IsMovepDestinationReg(unsigned Reg) { + + if (Reg == Mips::A0 || Reg == Mips::A1 || Reg == Mips::A2 || + Reg == Mips::A3 || Reg == Mips::S5 || Reg == Mips::S6) + return true; + + return false; +} + +// Returns true if the registers can be a pair of destination +// registers in MOVEP instruction +static bool IsMovepDestinationRegPair(unsigned R0, unsigned R1) { + + if ((R0 == Mips::A0 && R1 == Mips::S5) || + (R0 == Mips::A0 && R1 == Mips::S6) || + (R0 == Mips::A0 && R1 == Mips::A1) || + (R0 == Mips::A0 && R1 == Mips::A2) || + (R0 == Mips::A0 && R1 == Mips::A3) || + (R0 == Mips::A1 && R1 == Mips::A2) || + (R0 == Mips::A1 && R1 == Mips::A3) || + (R0 == Mips::A2 && R1 == Mips::A3)) + return true; + + return false; +} + +bool MicroMipsSizeReduce::ReduceMoveToMovep(ReduceEntryFunArgs *Arguments) { + + const ReduceEntry &Entry = Arguments->Entry; + MachineBasicBlock::instr_iterator &NextMII = Arguments->NextMII; + const MachineBasicBlock::instr_iterator &E = + Arguments->MI->getParent()->instr_end(); + + if (NextMII == E) + return false; + + MachineInstr *MI1 = Arguments->MI; + MachineInstr *MI2 = &*NextMII; + + unsigned RegDstMI1 = MI1->getOperand(0).getReg(); + unsigned RegSrcMI1 = MI1->getOperand(1).getReg(); + + if (!IsMovepSrcRegister(RegSrcMI1)) + return false; + + if (!IsMovepDestinationReg(RegDstMI1)) + return false; + + if (MI2->getOpcode() != Entry.WideOpc()) + return false; + + unsigned RegDstMI2 = MI2->getOperand(0).getReg(); + unsigned RegSrcMI2 = MI2->getOperand(1).getReg(); + + if (!IsMovepSrcRegister(RegSrcMI2)) + return false; + + bool ConsecutiveForward; + if (IsMovepDestinationRegPair(RegDstMI1, RegDstMI2)) { + ConsecutiveForward = true; + } else if (IsMovepDestinationRegPair(RegDstMI2, RegDstMI1)) { + ConsecutiveForward = false; + } else + return false; + + NextMII = std::next(NextMII); + return ReplaceInstruction(MI1, Entry, MI2, ConsecutiveForward); +} + bool MicroMipsSizeReduce::ReduceXORtoXOR16(ReduceEntryFunArgs *Arguments) { MachineInstr *MI = Arguments->MI; @@ -641,18 +731,25 @@ } break; } + case OT_OperandsMovep: case OT_OperandsLwp: case OT_OperandsSwp: { if (ConsecutiveForward) { MIB.add(MI->getOperand(0)); MIB.add(MI2->getOperand(0)); MIB.add(MI->getOperand(1)); - MIB.add(MI->getOperand(2)); + if (OpTransfer == OT_OperandsMovep) + MIB.add(MI2->getOperand(1)); + else + MIB.add(MI->getOperand(2)); } else { // consecutive backward MIB.add(MI2->getOperand(0)); MIB.add(MI->getOperand(0)); MIB.add(MI2->getOperand(1)); - MIB.add(MI2->getOperand(2)); + if (OpTransfer == OT_OperandsMovep) + MIB.add(MI->getOperand(1)); + else + MIB.add(MI2->getOperand(2)); } LLVM_DEBUG(dbgs() << "and converting 32-bit: " << *MI2 Index: lib/Target/Mips/MipsDelaySlotFiller.cpp =================================================================== --- lib/Target/Mips/MipsDelaySlotFiller.cpp +++ lib/Target/Mips/MipsDelaySlotFiller.cpp @@ -728,9 +728,10 @@ (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch || Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL)) continue; - // Instructions LWP/SWP should not be in a delay slot as that + // Instructions LWP/SWP and MOVEP should not be in a delay slot as that // results in unpredictable behaviour - if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM)) + if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM || + Opcode == Mips::MOVEP_MM)) continue; Filler = CurrI; Index: test/CodeGen/Mips/micromips-sizereduction/micromips-movep.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/micromips-sizereduction/micromips-movep.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=mipsel-unknown-linux-gnu -mattr=+micromips -mcpu=mips32r2 \ +; RUN: -verify-machineinstrs < %s | FileCheck %s + +; Function Attrs: nounwind +define i64 @move() { +; CHECK-LABEL: move: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addiusp -24 +; CHECK-NEXT: .cfi_def_cfa_offset 24 +; CHECK-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill +; CHECK-NEXT: .cfi_offset 31, -4 +; CHECK-NEXT: jal g +; CHECK-NEXT: nop +; CHECK-NEXT: movep $4, $5, $2, $3 +; CHECK-NEXT: jal f +; CHECK-NEXT: nop +; CHECK-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload +; CHECK-NEXT: addiusp 24 +; CHECK-NEXT: jrc $ra +entry: + %call = call i64 @g() + %call1 = call i64 @f(i64 signext %call) + ret i64 %call1 +} + +declare i64 @f(i64 signext %a) +declare i64 @g() + Index: test/CodeGen/Mips/micromips-sizereduction/micromips-movep.mir =================================================================== --- /dev/null +++ test/CodeGen/Mips/micromips-sizereduction/micromips-movep.mir @@ -0,0 +1,86 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple=mipsel-unknown-linux-gnu -mattr=+micromips -mcpu=mips32r2 \ +# RUN: -verify-machineinstrs -run-pass micromips-reduce-size \ +# RUN: %s -o - | FileCheck %s + +--- | + define i64 @move1() { ret i64 0 } + define i64 @move2() { ret i64 0 } + + declare i64 @f(i64 signext) + declare i64 @g() + +... +--- +name: move1 +stack: + - { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$ra', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +constants: +body: | + bb.0: + liveins: $ra + + ; CHECK-LABEL: name: move1 + ; CHECK: ADDIUSP_MM -24 + ; CHECK: CFI_INSTRUCTION def_cfa_offset 24 + ; CHECK: SWSP_MM killed $ra, $sp, 20 :: (store 4 into %stack.0) + ; CHECK: CFI_INSTRUCTION offset $ra_64, -4 + ; CHECK: JAL_MM @g, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def $v0, implicit-def $v1 + ; CHECK: $a0, $a1 = MOVEP_MM $v0, $v1 + ; CHECK: JAL_MM @f, csr_o32, implicit-def dead $ra, implicit $a0, implicit $a1, implicit-def $sp, implicit-def $v0, implicit-def $v1 + ; CHECK: $ra = LWSP_MM $sp, 20 :: (load 4 from %stack.0) + ; CHECK: ADDIUSP_MM 24 + ; CHECK: PseudoReturn undef $ra, implicit $v0, implicit $v1 + $sp = ADDiu $sp, -24 + CFI_INSTRUCTION def_cfa_offset 24 + SW killed $ra, $sp, 20 :: (store 4 into %stack.0) + CFI_INSTRUCTION offset $ra_64, -4 + JAL_MM @g, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def $v0, implicit-def $v1 + $a0 = MOVE16_MM $v0 + $a1 = MOVE16_MM $v1 + JAL_MM @f, csr_o32, implicit-def dead $ra, implicit $a0, implicit $a1, implicit-def $sp, implicit-def $v0, implicit-def $v1 + $ra = LW $sp, 20 :: (load 4 from %stack.0) + $sp = ADDiu $sp, 24 + PseudoReturn undef $ra, implicit $v0, implicit $v1 + +... +--- +name: move2 +stack: + - { id: 0, name: '', type: spill-slot, offset: -4, size: 4, alignment: 4, + stack-id: 0, callee-saved-register: '$ra', callee-saved-restored: true, + debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } +constants: +body: | + bb.0: + liveins: $ra + + ; CHECK-LABEL: name: move2 + ; CHECK: ADDIUSP_MM -24 + ; CHECK: CFI_INSTRUCTION def_cfa_offset 24 + ; CHECK: SWSP_MM killed $ra, $sp, 20 :: (store 4 into %stack.0) + ; CHECK: CFI_INSTRUCTION offset $ra_64, -4 + ; CHECK: JAL_MM @g, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def $v0, implicit-def $v1 + ; CHECK: $a0, $a1 = MOVEP_MM $v0, $v1 + ; CHECK: JAL_MM @f, csr_o32, implicit-def dead $ra, implicit $a0, implicit $a1, implicit-def $sp, implicit-def $v0, implicit-def $v1 + ; CHECK: $ra = LWSP_MM $sp, 20 :: (load 4 from %stack.0) + ; CHECK: ADDIUSP_MM 24 + ; CHECK: PseudoReturn undef $ra, implicit $v0, implicit $v1 + $sp = ADDiu $sp, -24 + CFI_INSTRUCTION def_cfa_offset 24 + SW killed $ra, $sp, 20 :: (store 4 into %stack.0) + CFI_INSTRUCTION offset $ra_64, -4 + JAL_MM @g, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def $v0, implicit-def $v1 + $a1 = MOVE16_MM $v1 + $a0 = MOVE16_MM $v0 + JAL_MM @f, csr_o32, implicit-def dead $ra, implicit $a0, implicit $a1, implicit-def $sp, implicit-def $v0, implicit-def $v1 + $ra = LW $sp, 20 :: (load 4 from %stack.0) + $sp = ADDiu $sp, 24 + PseudoReturn undef $ra, implicit $v0, implicit $v1 + +... +--- + +