forked from OSchip/llvm-project
[mips][microMIPS] Extending size reduction pass with MOVEP
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
This commit is contained in:
parent
852dd83be8
commit
a9e8765e3e
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
||||
...
|
||||
---
|
||||
|
||||
|
Loading…
Reference in New Issue