[mips][microMIPS] Extending size reduction pass with MOVEP
authorSimon Atanasyan <simon@atanasyan.com>
Wed, 19 Sep 2018 18:46:29 +0000 (18:46 +0000)
committerSimon Atanasyan <simon@atanasyan.com>
Wed, 19 Sep 2018 18:46:29 +0000 (18:46 +0000)
The patch extends size reduction pass for MicroMIPS. Two MOVE
instructions are transformed into one MOVEP instrucition.

Patch by Milena Vujosevic Janicic.

Differential revision: https://reviews.llvm.org/D52037

llvm-svn: 342572

llvm/lib/Target/Mips/MicroMipsSizeReduction.cpp
llvm/lib/Target/Mips/MipsDelaySlotFiller.cpp
llvm/test/CodeGen/Mips/micromips-sizereduction/micromips-movep.ll [new file with mode: 0644]
llvm/test/CodeGen/Mips/micromips-sizereduction/micromips-movep.mir [new file with mode: 0644]

index 568cdfb..f9062cc 100644 (file)
@@ -31,13 +31,14 @@ namespace {
 /// 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 @@ private:
   // 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 @@ ReduceEntryVector MicroMipsSizeReduce::ReduceTable = {
      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 @@ bool MicroMipsSizeReduce::ReduceSXtoSX16(ReduceEntryFunArgs *Arguments) {
   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 @@ bool MicroMipsSizeReduce::ReplaceInstruction(MachineInstr *MI,
       }
       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 33f03b9..e3823e0 100644 (file)
@@ -728,9 +728,10 @@ bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
         (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;
diff --git a/llvm/test/CodeGen/Mips/micromips-sizereduction/micromips-movep.ll b/llvm/test/CodeGen/Mips/micromips-sizereduction/micromips-movep.ll
new file mode 100644 (file)
index 0000000..84998a3
--- /dev/null
@@ -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()
+
diff --git a/llvm/test/CodeGen/Mips/micromips-sizereduction/micromips-movep.mir b/llvm/test/CodeGen/Mips/micromips-sizereduction/micromips-movep.mir
new file mode 100644 (file)
index 0000000..73b0b54
--- /dev/null
@@ -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
+
+...
+---
+
+