[mips][microMIPS] Extending size reduction pass with LWP and SWP

Author: milena.vujosevic.janicic
Reviewers: sdardis
The patch extends size reduction pass for MicroMIPS.
It introduces reduction of two instructions into one instruction:
Two SW instructions are transformed into one SWP instrucition.
Two LW instructions are transformed into one LWP instrucition.
Differential Revision: https://reviews.llvm.org/D39115

llvm-svn: 334595
This commit is contained in:
Zoran Jovanovic 2018-06-13 12:51:37 +00:00
parent 36b816f814
commit 3a7654c15d
13 changed files with 828 additions and 73 deletions

View File

@ -10,7 +10,6 @@
/// This pass is used to reduce the size of instructions where applicable. /// This pass is used to reduce the size of instructions where applicable.
/// ///
/// TODO: Implement microMIPS64 support. /// TODO: Implement microMIPS64 support.
/// TODO: Implement support for reducing into lwp/swp instruction.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "Mips.h" #include "Mips.h"
#include "MipsInstrInfo.h" #include "MipsInstrInfo.h"
@ -22,8 +21,10 @@
using namespace llvm; using namespace llvm;
#define DEBUG_TYPE "micromips-reduce-size" #define DEBUG_TYPE "micromips-reduce-size"
#define MICROMIPS_SIZE_REDUCE_NAME "MicroMips instruction size reduce pass"
STATISTIC(NumReduced, "Number of 32-bit instructions reduced to 16-bit ones"); STATISTIC(NumReduced, "Number of instructions reduced (32-bit to 16-bit ones, "
"or two instructions into one");
namespace { namespace {
@ -35,11 +36,14 @@ enum OperandTransfer {
OT_Operands02, ///< Transfer operands 0 and 2 OT_Operands02, ///< Transfer operands 0 and 2
OT_Operand2, ///< Transfer just operand 2 OT_Operand2, ///< Transfer just operand 2
OT_OperandsXOR, ///< Transfer operands for XOR16 OT_OperandsXOR, ///< Transfer operands for XOR16
OT_OperandsLwp, ///< Transfer operands for LWP
OT_OperandsSwp, ///< Transfer operands for SWP
}; };
/// Reduction type /// Reduction type
// TODO: Will be extended when additional optimizations are added // TODO: Will be extended when additional optimizations are added
enum ReduceType { enum ReduceType {
RT_TwoInstr, ///< Reduce two instructions into one instruction
RT_OneInstr ///< Reduce one instruction into a smaller instruction RT_OneInstr ///< Reduce one instruction into a smaller instruction
}; };
@ -76,21 +80,22 @@ struct OpCodes {
unsigned NarrowOpc; ///< Narrow opcode unsigned NarrowOpc; ///< Narrow opcode
}; };
typedef struct ReduceEntryFunArgs ReduceEntryFunArgs;
/// ReduceTable - A static table with information on mapping from wide /// ReduceTable - A static table with information on mapping from wide
/// opcodes to narrow /// opcodes to narrow
struct ReduceEntry { struct ReduceEntry {
enum ReduceType eRType; ///< Reduction type enum ReduceType eRType; ///< Reduction type
bool (*ReduceFunction)( bool (*ReduceFunction)(
MachineInstr *MI, ReduceEntryFunArgs *Arguments); ///< Pointer to reduce function
const ReduceEntry &Entry); ///< Pointer to reduce function
struct OpCodes Ops; ///< All relevant OpCodes struct OpCodes Ops; ///< All relevant OpCodes
struct OpInfo OpInf; ///< Characteristics of operands struct OpInfo OpInf; ///< Characteristics of operands
struct ImmField Imm; ///< Characteristics of immediate field struct ImmField Imm; ///< Characteristics of immediate field
ReduceEntry(enum ReduceType RType, struct OpCodes Op, ReduceEntry(enum ReduceType RType, struct OpCodes Op,
bool (*F)(MachineInstr *MI, const ReduceEntry &Entry), bool (*F)(ReduceEntryFunArgs *Arguments), struct OpInfo OpInf,
struct OpInfo OpInf, struct ImmField Imm) struct ImmField Imm)
: eRType(RType), ReduceFunction(F), Ops(Op), OpInf(OpInf), Imm(Imm) {} : eRType(RType), ReduceFunction(F), Ops(Op), OpInf(OpInf), Imm(Imm) {}
unsigned NarrowOpc() const { return Ops.NarrowOpc; } unsigned NarrowOpc() const { return Ops.NarrowOpc; }
@ -113,6 +118,20 @@ struct ReduceEntry {
} }
}; };
// Function arguments for ReduceFunction
struct ReduceEntryFunArgs {
MachineInstr *MI; // Instruction
const ReduceEntry &Entry; // Entry field
MachineBasicBlock::instr_iterator
&NextMII; // Iterator to next instruction in block
ReduceEntryFunArgs(MachineInstr *argMI, const ReduceEntry &argEntry,
MachineBasicBlock::instr_iterator &argNextMII)
: MI(argMI), Entry(argEntry), NextMII(argNextMII) {}
};
typedef llvm::SmallVector<ReduceEntry, 32> ReduceEntryVector;
class MicroMipsSizeReduce : public MachineFunctionPass { class MicroMipsSizeReduce : public MachineFunctionPass {
public: public:
static char ID; static char ID;
@ -132,42 +151,50 @@ private:
bool ReduceMBB(MachineBasicBlock &MBB); bool ReduceMBB(MachineBasicBlock &MBB);
/// Attempts to reduce MI, returns true on success. /// Attempts to reduce MI, returns true on success.
bool ReduceMI(const MachineBasicBlock::instr_iterator &MII); bool ReduceMI(const MachineBasicBlock::instr_iterator &MII,
MachineBasicBlock::instr_iterator &NextMII);
// Attempts to reduce LW/SW instruction into LWSP/SWSP, // Attempts to reduce LW/SW instruction into LWSP/SWSP,
// returns true on success. // returns true on success.
static bool ReduceXWtoXWSP(MachineInstr *MI, const ReduceEntry &Entry); static bool ReduceXWtoXWSP(ReduceEntryFunArgs *Arguments);
// Attempts to reduce two LW/SW instructions into LWP/SWP instruction,
// returns true on success.
static bool ReduceXWtoXWP(ReduceEntryFunArgs *Arguments);
// Attempts to reduce LBU/LHU instruction into LBU16/LHU16, // Attempts to reduce LBU/LHU instruction into LBU16/LHU16,
// returns true on success. // returns true on success.
static bool ReduceLXUtoLXU16(MachineInstr *MI, const ReduceEntry &Entry); static bool ReduceLXUtoLXU16(ReduceEntryFunArgs *Arguments);
// Attempts to reduce SB/SH instruction into SB16/SH16, // Attempts to reduce SB/SH instruction into SB16/SH16,
// returns true on success. // returns true on success.
static bool ReduceSXtoSX16(MachineInstr *MI, const ReduceEntry &Entry); static bool ReduceSXtoSX16(ReduceEntryFunArgs *Arguments);
// Attempts to reduce arithmetic instructions, returns true on success. // Attempts to reduce arithmetic instructions, returns true on success.
static bool ReduceArithmeticInstructions(MachineInstr *MI, static bool ReduceArithmeticInstructions(ReduceEntryFunArgs *Arguments);
const ReduceEntry &Entry);
// Attempts to reduce ADDIU into ADDIUSP instruction, // Attempts to reduce ADDIU into ADDIUSP instruction,
// returns true on success. // returns true on success.
static bool ReduceADDIUToADDIUSP(MachineInstr *MI, const ReduceEntry &Entry); static bool ReduceADDIUToADDIUSP(ReduceEntryFunArgs *Arguments);
// Attempts to reduce ADDIU into ADDIUR1SP instruction, // Attempts to reduce ADDIU into ADDIUR1SP instruction,
// returns true on success. // returns true on success.
static bool ReduceADDIUToADDIUR1SP(MachineInstr *MI, static bool ReduceADDIUToADDIUR1SP(ReduceEntryFunArgs *Arguments);
const ReduceEntry &Entry);
// Attempts to reduce XOR into XOR16 instruction, // Attempts to reduce XOR into XOR16 instruction,
// returns true on success. // returns true on success.
static bool ReduceXORtoXOR16(MachineInstr *MI, const ReduceEntry &Entry); static bool ReduceXORtoXOR16(ReduceEntryFunArgs *Arguments);
// Changes opcode of an instruction. // Changes opcode of an instruction, replaces an instruction with a
static bool ReplaceInstruction(MachineInstr *MI, const ReduceEntry &Entry); // new one, or replaces two instructions with a new instruction
// depending on their order i.e. if these are consecutive forward
// or consecutive backward
static bool ReplaceInstruction(MachineInstr *MI, const ReduceEntry &Entry,
MachineInstr *MI2 = nullptr,
bool ConsecutiveForward = true);
// Table with transformation rules for each instruction. // Table with transformation rules for each instruction.
static llvm::SmallVector<ReduceEntry, 16> ReduceTable; static ReduceEntryVector ReduceTable;
}; };
char MicroMipsSizeReduce::ID = 0; char MicroMipsSizeReduce::ID = 0;
@ -175,7 +202,7 @@ const MipsInstrInfo *MicroMipsSizeReduce::MipsII;
// This table must be sorted by WideOpc as a main criterion and // This table must be sorted by WideOpc as a main criterion and
// ReduceType as a sub-criterion (when wide opcodes are the same). // ReduceType as a sub-criterion (when wide opcodes are the same).
llvm::SmallVector<ReduceEntry, 16> MicroMipsSizeReduce::ReduceTable = { ReduceEntryVector MicroMipsSizeReduce::ReduceTable = {
// ReduceType, OpCodes, ReduceFunction, // ReduceType, OpCodes, ReduceFunction,
// OpInfo(TransferOperands), // OpInfo(TransferOperands),
@ -206,8 +233,14 @@ llvm::SmallVector<ReduceEntry, 16> MicroMipsSizeReduce::ReduceTable = {
OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)}, OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)},
{RT_OneInstr, OpCodes(Mips::LHu_MM, Mips::LHU16_MM), ReduceLXUtoLXU16, {RT_OneInstr, OpCodes(Mips::LHu_MM, Mips::LHU16_MM), ReduceLXUtoLXU16,
OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)}, OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)},
{RT_TwoInstr, OpCodes(Mips::LW, Mips::LWP_MM), ReduceXWtoXWP,
OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)},
{RT_OneInstr, OpCodes(Mips::LW, Mips::LWSP_MM), ReduceXWtoXWSP, {RT_OneInstr, OpCodes(Mips::LW, Mips::LWSP_MM), ReduceXWtoXWSP,
OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)}, OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
{RT_TwoInstr, OpCodes(Mips::LW16_MM, Mips::LWP_MM), ReduceXWtoXWP,
OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)},
{RT_TwoInstr, OpCodes(Mips::LW_MM, Mips::LWP_MM), ReduceXWtoXWP,
OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)},
{RT_OneInstr, OpCodes(Mips::LW_MM, Mips::LWSP_MM), ReduceXWtoXWSP, {RT_OneInstr, OpCodes(Mips::LW_MM, Mips::LWSP_MM), ReduceXWtoXWSP,
OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)}, OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
{RT_OneInstr, OpCodes(Mips::SB, Mips::SB16_MM), ReduceSXtoSX16, {RT_OneInstr, OpCodes(Mips::SB, Mips::SB16_MM), ReduceSXtoSX16,
@ -224,15 +257,24 @@ llvm::SmallVector<ReduceEntry, 16> MicroMipsSizeReduce::ReduceTable = {
{RT_OneInstr, OpCodes(Mips::SUBu_MM, Mips::SUBU16_MM), {RT_OneInstr, OpCodes(Mips::SUBu_MM, Mips::SUBU16_MM),
ReduceArithmeticInstructions, OpInfo(OT_OperandsAll), ReduceArithmeticInstructions, OpInfo(OT_OperandsAll),
ImmField(0, 0, 0, -1)}, ImmField(0, 0, 0, -1)},
{RT_TwoInstr, OpCodes(Mips::SW, Mips::SWP_MM), ReduceXWtoXWP,
OpInfo(OT_OperandsSwp), ImmField(0, -2048, 2048, 2)},
{RT_OneInstr, OpCodes(Mips::SW, Mips::SWSP_MM), ReduceXWtoXWSP, {RT_OneInstr, OpCodes(Mips::SW, Mips::SWSP_MM), ReduceXWtoXWSP,
OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)}, OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
{RT_TwoInstr, OpCodes(Mips::SW16_MM, Mips::SWP_MM), ReduceXWtoXWP,
OpInfo(OT_OperandsSwp), ImmField(0, -2048, 2048, 2)},
{RT_TwoInstr, OpCodes(Mips::SW_MM, Mips::SWP_MM), ReduceXWtoXWP,
OpInfo(OT_OperandsSwp), ImmField(0, -2048, 2048, 2)},
{RT_OneInstr, OpCodes(Mips::SW_MM, Mips::SWSP_MM), ReduceXWtoXWSP, {RT_OneInstr, OpCodes(Mips::SW_MM, Mips::SWSP_MM), ReduceXWtoXWSP,
OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)}, OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
{RT_OneInstr, OpCodes(Mips::XOR, Mips::XOR16_MM), ReduceXORtoXOR16, {RT_OneInstr, OpCodes(Mips::XOR, Mips::XOR16_MM), ReduceXORtoXOR16,
OpInfo(OT_OperandsXOR), ImmField(0, 0, 0, -1)}, OpInfo(OT_OperandsXOR), ImmField(0, 0, 0, -1)},
{RT_OneInstr, OpCodes(Mips::XOR_MM, Mips::XOR16_MM), ReduceXORtoXOR16, {RT_OneInstr, OpCodes(Mips::XOR_MM, Mips::XOR16_MM), ReduceXORtoXOR16,
OpInfo(OT_OperandsXOR), ImmField(0, 0, 0, -1)}}; OpInfo(OT_OperandsXOR), ImmField(0, 0, 0, -1)}};
} // namespace } // end anonymous namespace
INITIALIZE_PASS(MicroMipsSizeReduce, DEBUG_TYPE, MICROMIPS_SIZE_REDUCE_NAME,
false, false)
// Returns true if the machine operand MO is register SP. // Returns true if the machine operand MO is register SP.
static bool IsSP(const MachineOperand &MO) { static bool IsSP(const MachineOperand &MO) {
@ -299,37 +341,100 @@ static bool ImmInRange(MachineInstr *MI, const ReduceEntry &Entry) {
return true; return true;
} }
// Returns true if MI can be reduced to lwp/swp instruction
static bool CheckXWPInstr(MachineInstr *MI, bool ReduceToLwp,
const ReduceEntry &Entry) {
if (ReduceToLwp &&
!(MI->getOpcode() == Mips::LW || MI->getOpcode() == Mips::LW_MM ||
MI->getOpcode() == Mips::LW16_MM))
return false;
if (!ReduceToLwp &&
!(MI->getOpcode() == Mips::SW || MI->getOpcode() == Mips::SW_MM ||
MI->getOpcode() == Mips::SW16_MM))
return false;
unsigned reg = MI->getOperand(0).getReg();
if (reg == Mips::RA)
return false;
if (!ImmInRange(MI, Entry))
return false;
if (ReduceToLwp && (MI->getOperand(0).getReg() == MI->getOperand(1).getReg()))
return false;
return true;
}
// Returns true if the registers Reg1 and Reg2 are consecutive
static bool ConsecutiveRegisters(unsigned Reg1, unsigned Reg2) {
static SmallVector<unsigned, 31> Registers = {
Mips::AT, Mips::V0, Mips::V1, Mips::A0, Mips::A1, Mips::A2, Mips::A3,
Mips::T0, Mips::T1, Mips::T2, Mips::T3, Mips::T4, Mips::T5, Mips::T6,
Mips::T7, Mips::S0, Mips::S1, Mips::S2, Mips::S3, Mips::S4, Mips::S5,
Mips::S6, Mips::S7, Mips::T8, Mips::T9, Mips::K0, Mips::K1, Mips::GP,
Mips::SP, Mips::FP, Mips::RA};
for (uint8_t i = 0; i < Registers.size() - 1; i++) {
if (Registers[i] == Reg1) {
if (Registers[i + 1] == Reg2)
return true;
else
return false;
}
}
return false;
}
// Returns true if registers and offsets are consecutive
static bool ConsecutiveInstr(MachineInstr *MI1, MachineInstr *MI2) {
int64_t Offset1, Offset2;
if (!GetImm(MI1, 2, Offset1))
return false;
if (!GetImm(MI2, 2, Offset2))
return false;
unsigned Reg1 = MI1->getOperand(0).getReg();
unsigned Reg2 = MI2->getOperand(0).getReg();
return ((Offset1 == (Offset2 - 4)) && (ConsecutiveRegisters(Reg1, Reg2)));
}
MicroMipsSizeReduce::MicroMipsSizeReduce() : MachineFunctionPass(ID) {} MicroMipsSizeReduce::MicroMipsSizeReduce() : MachineFunctionPass(ID) {}
bool MicroMipsSizeReduce::ReduceMI( bool MicroMipsSizeReduce::ReduceMI(const MachineBasicBlock::instr_iterator &MII,
const MachineBasicBlock::instr_iterator &MII) { MachineBasicBlock::instr_iterator &NextMII) {
MachineInstr *MI = &*MII; MachineInstr *MI = &*MII;
unsigned Opcode = MI->getOpcode(); unsigned Opcode = MI->getOpcode();
// Search the table. // Search the table.
llvm::SmallVector<ReduceEntry, 16>::const_iterator Start = ReduceEntryVector::const_iterator Start = std::begin(ReduceTable);
std::begin(ReduceTable); ReduceEntryVector::const_iterator End = std::end(ReduceTable);
llvm::SmallVector<ReduceEntry, 16>::const_iterator End =
std::end(ReduceTable);
std::pair<llvm::SmallVector<ReduceEntry, 16>::const_iterator, std::pair<ReduceEntryVector::const_iterator,
llvm::SmallVector<ReduceEntry, 16>::const_iterator> ReduceEntryVector::const_iterator>
Range = std::equal_range(Start, End, Opcode); Range = std::equal_range(Start, End, Opcode);
if (Range.first == Range.second) if (Range.first == Range.second)
return false; return false;
for (llvm::SmallVector<ReduceEntry, 16>::const_iterator Entry = Range.first; for (ReduceEntryVector::const_iterator Entry = Range.first;
Entry != Range.second; ++Entry) Entry != Range.second; ++Entry) {
if (((*Entry).ReduceFunction)(&(*MII), *Entry)) ReduceEntryFunArgs Arguments(&(*MII), *Entry, NextMII);
if (((*Entry).ReduceFunction)(&Arguments))
return true; return true;
}
return false; return false;
} }
bool MicroMipsSizeReduce::ReduceXWtoXWSP(MachineInstr *MI, bool MicroMipsSizeReduce::ReduceXWtoXWSP(ReduceEntryFunArgs *Arguments) {
const ReduceEntry &Entry) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
if (!ImmInRange(MI, Entry)) if (!ImmInRange(MI, Entry))
return false; return false;
@ -340,8 +445,51 @@ bool MicroMipsSizeReduce::ReduceXWtoXWSP(MachineInstr *MI,
return ReplaceInstruction(MI, Entry); return ReplaceInstruction(MI, Entry);
} }
bool MicroMipsSizeReduce::ReduceXWtoXWP(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;
// ReduceToLwp = true/false - reduce to LWP/SWP instruction
bool ReduceToLwp = (MI1->getOpcode() == Mips::LW) ||
(MI1->getOpcode() == Mips::LW_MM) ||
(MI1->getOpcode() == Mips::LW16_MM);
if (!CheckXWPInstr(MI1, ReduceToLwp, Entry))
return false;
if (!CheckXWPInstr(MI2, ReduceToLwp, Entry))
return false;
unsigned Reg1 = MI1->getOperand(1).getReg();
unsigned Reg2 = MI2->getOperand(1).getReg();
if (Reg1 != Reg2)
return false;
bool ConsecutiveForward = ConsecutiveInstr(MI1, MI2);
bool ConsecutiveBackward = ConsecutiveInstr(MI2, MI1);
if (!(ConsecutiveForward || ConsecutiveBackward))
return false;
NextMII = std::next(NextMII);
return ReplaceInstruction(MI1, Entry, MI2, ConsecutiveForward);
}
bool MicroMipsSizeReduce::ReduceArithmeticInstructions( bool MicroMipsSizeReduce::ReduceArithmeticInstructions(
MachineInstr *MI, const ReduceEntry &Entry) { ReduceEntryFunArgs *Arguments) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
if (!isMMThreeBitGPRegister(MI->getOperand(0)) || if (!isMMThreeBitGPRegister(MI->getOperand(0)) ||
!isMMThreeBitGPRegister(MI->getOperand(1)) || !isMMThreeBitGPRegister(MI->getOperand(1)) ||
@ -351,8 +499,11 @@ bool MicroMipsSizeReduce::ReduceArithmeticInstructions(
return ReplaceInstruction(MI, Entry); return ReplaceInstruction(MI, Entry);
} }
bool MicroMipsSizeReduce::ReduceADDIUToADDIUR1SP(MachineInstr *MI, bool MicroMipsSizeReduce::ReduceADDIUToADDIUR1SP(
const ReduceEntry &Entry) { ReduceEntryFunArgs *Arguments) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
if (!ImmInRange(MI, Entry)) if (!ImmInRange(MI, Entry))
return false; return false;
@ -363,8 +514,10 @@ bool MicroMipsSizeReduce::ReduceADDIUToADDIUR1SP(MachineInstr *MI,
return ReplaceInstruction(MI, Entry); return ReplaceInstruction(MI, Entry);
} }
bool MicroMipsSizeReduce::ReduceADDIUToADDIUSP(MachineInstr *MI, bool MicroMipsSizeReduce::ReduceADDIUToADDIUSP(ReduceEntryFunArgs *Arguments) {
const ReduceEntry &Entry) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
int64_t ImmValue; int64_t ImmValue;
if (!GetImm(MI, Entry.ImmField(), ImmValue)) if (!GetImm(MI, Entry.ImmField(), ImmValue))
@ -379,8 +532,10 @@ bool MicroMipsSizeReduce::ReduceADDIUToADDIUSP(MachineInstr *MI,
return ReplaceInstruction(MI, Entry); return ReplaceInstruction(MI, Entry);
} }
bool MicroMipsSizeReduce::ReduceLXUtoLXU16(MachineInstr *MI, bool MicroMipsSizeReduce::ReduceLXUtoLXU16(ReduceEntryFunArgs *Arguments) {
const ReduceEntry &Entry) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
if (!ImmInRange(MI, Entry)) if (!ImmInRange(MI, Entry))
return false; return false;
@ -392,8 +547,10 @@ bool MicroMipsSizeReduce::ReduceLXUtoLXU16(MachineInstr *MI,
return ReplaceInstruction(MI, Entry); return ReplaceInstruction(MI, Entry);
} }
bool MicroMipsSizeReduce::ReduceSXtoSX16(MachineInstr *MI, bool MicroMipsSizeReduce::ReduceSXtoSX16(ReduceEntryFunArgs *Arguments) {
const ReduceEntry &Entry) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
if (!ImmInRange(MI, Entry)) if (!ImmInRange(MI, Entry))
return false; return false;
@ -405,8 +562,11 @@ bool MicroMipsSizeReduce::ReduceSXtoSX16(MachineInstr *MI,
return ReplaceInstruction(MI, Entry); return ReplaceInstruction(MI, Entry);
} }
bool MicroMipsSizeReduce::ReduceXORtoXOR16(MachineInstr *MI, bool MicroMipsSizeReduce::ReduceXORtoXOR16(ReduceEntryFunArgs *Arguments) {
const ReduceEntry &Entry) {
MachineInstr *MI = Arguments->MI;
const ReduceEntry &Entry = Arguments->Entry;
if (!isMMThreeBitGPRegister(MI->getOperand(0)) || if (!isMMThreeBitGPRegister(MI->getOperand(0)) ||
!isMMThreeBitGPRegister(MI->getOperand(1)) || !isMMThreeBitGPRegister(MI->getOperand(1)) ||
!isMMThreeBitGPRegister(MI->getOperand(2))) !isMMThreeBitGPRegister(MI->getOperand(2)))
@ -435,14 +595,16 @@ bool MicroMipsSizeReduce::ReduceMBB(MachineBasicBlock &MBB) {
continue; continue;
// Try to reduce 32-bit instruction into 16-bit instruction // Try to reduce 32-bit instruction into 16-bit instruction
Modified |= ReduceMI(MII); Modified |= ReduceMI(MII, NextMII);
} }
return Modified; return Modified;
} }
bool MicroMipsSizeReduce::ReplaceInstruction(MachineInstr *MI, bool MicroMipsSizeReduce::ReplaceInstruction(MachineInstr *MI,
const ReduceEntry &Entry) { const ReduceEntry &Entry,
MachineInstr *MI2,
bool ConsecutiveForward) {
enum OperandTransfer OpTransfer = Entry.TransferOperands(); enum OperandTransfer OpTransfer = Entry.TransferOperands();
@ -479,6 +641,27 @@ bool MicroMipsSizeReduce::ReplaceInstruction(MachineInstr *MI,
} }
break; break;
} }
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));
} else { // consecutive backward
MIB.add(MI2->getOperand(0));
MIB.add(MI->getOperand(0));
MIB.add(MI2->getOperand(1));
MIB.add(MI2->getOperand(2));
}
LLVM_DEBUG(dbgs() << "and converting 32-bit: " << *MI2
<< " to: " << *MIB);
MBB.erase_instr(MI);
MBB.erase_instr(MI2);
return true;
}
default: default:
llvm_unreachable("Unknown operand transfer!"); llvm_unreachable("Unknown operand transfer!");
} }
@ -513,6 +696,6 @@ bool MicroMipsSizeReduce::runOnMachineFunction(MachineFunction &MF) {
} }
/// Returns an instance of the MicroMips size reduction pass. /// Returns an instance of the MicroMips size reduction pass.
FunctionPass *llvm::createMicroMipsSizeReductionPass() { FunctionPass *llvm::createMicroMipsSizeReducePass() {
return new MicroMipsSizeReduce(); return new MicroMipsSizeReduce();
} }

View File

@ -26,6 +26,7 @@ namespace llvm {
class MipsSubtarget; class MipsSubtarget;
class MipsTargetMachine; class MipsTargetMachine;
class InstructionSelector; class InstructionSelector;
class PassRegistry;
ModulePass *createMipsOs16Pass(); ModulePass *createMipsOs16Pass();
ModulePass *createMips16HardFloatPass(); ModulePass *createMips16HardFloatPass();
@ -35,7 +36,7 @@ namespace llvm {
FunctionPass *createMipsDelaySlotFillerPass(); FunctionPass *createMipsDelaySlotFillerPass();
FunctionPass *createMipsBranchExpansion(); FunctionPass *createMipsBranchExpansion();
FunctionPass *createMipsConstantIslandPass(); FunctionPass *createMipsConstantIslandPass();
FunctionPass *createMicroMipsSizeReductionPass(); FunctionPass *createMicroMipsSizeReducePass();
InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &, InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &,
MipsSubtarget &, MipsSubtarget &,
@ -43,6 +44,7 @@ namespace llvm {
void initializeMipsDelaySlotFillerPass(PassRegistry &); void initializeMipsDelaySlotFillerPass(PassRegistry &);
void initializeMipsBranchExpansionPass(PassRegistry &); void initializeMipsBranchExpansionPass(PassRegistry &);
void initializeMicroMipsSizeReducePass(PassRegistry &);
} // end namespace llvm; } // end namespace llvm;
#endif #endif

View File

@ -728,6 +728,10 @@ bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
(Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch || (Opcode == Mips::JR || Opcode == Mips::PseudoIndirectBranch ||
Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL)) Opcode == Mips::PseudoReturn || Opcode == Mips::TAILCALL))
continue; continue;
// Instructions LWP/SWP should not be in a delay slot as that
// results in unpredictable behaviour
if (InMicroMipsMode && (Opcode == Mips::LWP_MM || Opcode == Mips::SWP_MM))
continue;
Filler = CurrI; Filler = CurrI;
return true; return true;

View File

@ -55,6 +55,7 @@ extern "C" void LLVMInitializeMipsTarget() {
initializeGlobalISel(*PR); initializeGlobalISel(*PR);
initializeMipsDelaySlotFillerPass(*PR); initializeMipsDelaySlotFillerPass(*PR);
initializeMipsBranchExpansionPass(*PR); initializeMipsBranchExpansionPass(*PR);
initializeMicroMipsSizeReducePass(*PR);
} }
static std::string computeDataLayout(const Triple &TT, StringRef CPU, static std::string computeDataLayout(const Triple &TT, StringRef CPU,
@ -288,7 +289,7 @@ MipsTargetMachine::getTargetTransformInfo(const Function &F) {
// machine code is emitted. return true if -print-machineinstrs should // machine code is emitted. return true if -print-machineinstrs should
// print out the code after the passes. // print out the code after the passes.
void MipsPassConfig::addPreEmitPass() { void MipsPassConfig::addPreEmitPass() {
addPass(createMicroMipsSizeReductionPass()); addPass(createMicroMipsSizeReducePass());
// The delay slot filler pass can potientially create forbidden slot hazards // The delay slot filler pass can potientially create forbidden slot hazards
// for MIPSR6 and therefore it should go before MipsBranchExpansion pass. // for MIPSR6 and therefore it should go before MipsBranchExpansion pass.

View File

@ -335,8 +335,7 @@ define signext i128 @and_i128(i128 signext %a, i128 signext %b) {
; ;
; MM32R3-LABEL: and_i128: ; MM32R3-LABEL: and_i128:
; MM32R3: # %bb.0: # %entry ; MM32R3: # %bb.0: # %entry
; MM32R3-NEXT: lw $3, 20($sp) ; MM32R3-NEXT: lwp $2, 16($sp)
; MM32R3-NEXT: lw $2, 16($sp)
; MM32R3-NEXT: and16 $2, $4 ; MM32R3-NEXT: and16 $2, $4
; MM32R3-NEXT: and16 $3, $5 ; MM32R3-NEXT: and16 $3, $5
; MM32R3-NEXT: lw $4, 24($sp) ; MM32R3-NEXT: lw $4, 24($sp)

View File

@ -791,8 +791,7 @@ define signext i128 @ashr_i128(i128 signext %a, i128 signext %b) {
; MMR3: # %bb.0: # %entry ; MMR3: # %bb.0: # %entry
; MMR3-NEXT: addiusp -48 ; MMR3-NEXT: addiusp -48
; MMR3-NEXT: .cfi_def_cfa_offset 48 ; MMR3-NEXT: .cfi_def_cfa_offset 48
; MMR3-NEXT: sw $17, 44($sp) # 4-byte Folded Spill ; MMR3-NEXT: swp $16, 40($sp)
; MMR3-NEXT: sw $16, 40($sp) # 4-byte Folded Spill
; MMR3-NEXT: .cfi_offset 17, -4 ; MMR3-NEXT: .cfi_offset 17, -4
; MMR3-NEXT: .cfi_offset 16, -8 ; MMR3-NEXT: .cfi_offset 16, -8
; MMR3-NEXT: move $8, $7 ; MMR3-NEXT: move $8, $7
@ -870,8 +869,7 @@ define signext i128 @ashr_i128(i128 signext %a, i128 signext %b) {
; MMR3-NEXT: movn $2, $11, $10 ; MMR3-NEXT: movn $2, $11, $10
; MMR3-NEXT: move $3, $8 ; MMR3-NEXT: move $3, $8
; MMR3-NEXT: move $4, $1 ; MMR3-NEXT: move $4, $1
; MMR3-NEXT: lw $16, 40($sp) # 4-byte Folded Reload ; MMR3-NEXT: lwp $16, 40($sp)
; MMR3-NEXT: lw $17, 44($sp) # 4-byte Folded Reload
; MMR3-NEXT: addiusp 48 ; MMR3-NEXT: addiusp 48
; MMR3-NEXT: jrc $ra ; MMR3-NEXT: jrc $ra
; ;

View File

@ -818,8 +818,7 @@ define signext i128 @lshr_i128(i128 signext %a, i128 signext %b) {
; MMR3: # %bb.0: # %entry ; MMR3: # %bb.0: # %entry
; MMR3-NEXT: addiusp -40 ; MMR3-NEXT: addiusp -40
; MMR3-NEXT: .cfi_def_cfa_offset 40 ; MMR3-NEXT: .cfi_def_cfa_offset 40
; MMR3-NEXT: sw $17, 36($sp) # 4-byte Folded Spill ; MMR3-NEXT: swp $16, 32($sp)
; MMR3-NEXT: sw $16, 32($sp) # 4-byte Folded Spill
; MMR3-NEXT: .cfi_offset 17, -4 ; MMR3-NEXT: .cfi_offset 17, -4
; MMR3-NEXT: .cfi_offset 16, -8 ; MMR3-NEXT: .cfi_offset 16, -8
; MMR3-NEXT: move $8, $7 ; MMR3-NEXT: move $8, $7
@ -896,8 +895,7 @@ define signext i128 @lshr_i128(i128 signext %a, i128 signext %b) {
; MMR3-NEXT: li16 $4, 0 ; MMR3-NEXT: li16 $4, 0
; MMR3-NEXT: movz $2, $4, $10 ; MMR3-NEXT: movz $2, $4, $10
; MMR3-NEXT: move $4, $1 ; MMR3-NEXT: move $4, $1
; MMR3-NEXT: lw $16, 32($sp) # 4-byte Folded Reload ; MMR3-NEXT: lwp $16, 32($sp)
; MMR3-NEXT: lw $17, 36($sp) # 4-byte Folded Reload
; MMR3-NEXT: addiusp 40 ; MMR3-NEXT: addiusp 40
; MMR3-NEXT: jrc $ra ; MMR3-NEXT: jrc $ra
; ;

View File

@ -176,8 +176,7 @@ define signext i128 @or_i128(i128 signext %a, i128 signext %b) {
; ;
; MM32-LABEL: or_i128: ; MM32-LABEL: or_i128:
; MM32: # %bb.0: # %entry ; MM32: # %bb.0: # %entry
; MM32-NEXT: lw $3, 20($sp) ; MM32-NEXT: lwp $2, 16($sp)
; MM32-NEXT: lw $2, 16($sp)
; MM32-NEXT: or16 $2, $4 ; MM32-NEXT: or16 $2, $4
; MM32-NEXT: or16 $3, $5 ; MM32-NEXT: or16 $3, $5
; MM32-NEXT: lw $4, 24($sp) ; MM32-NEXT: lw $4, 24($sp)

View File

@ -847,8 +847,7 @@ define signext i128 @shl_i128(i128 signext %a, i128 signext %b) {
; MMR3: # %bb.0: # %entry ; MMR3: # %bb.0: # %entry
; MMR3-NEXT: addiusp -40 ; MMR3-NEXT: addiusp -40
; MMR3-NEXT: .cfi_def_cfa_offset 40 ; MMR3-NEXT: .cfi_def_cfa_offset 40
; MMR3-NEXT: sw $17, 36($sp) # 4-byte Folded Spill ; MMR3-NEXT: swp $16, 32($sp)
; MMR3-NEXT: sw $16, 32($sp) # 4-byte Folded Spill
; MMR3-NEXT: .cfi_offset 17, -4 ; MMR3-NEXT: .cfi_offset 17, -4
; MMR3-NEXT: .cfi_offset 16, -8 ; MMR3-NEXT: .cfi_offset 16, -8
; MMR3-NEXT: move $17, $7 ; MMR3-NEXT: move $17, $7
@ -926,8 +925,7 @@ define signext i128 @shl_i128(i128 signext %a, i128 signext %b) {
; MMR3-NEXT: movz $6, $3, $10 ; MMR3-NEXT: movz $6, $3, $10
; MMR3-NEXT: move $3, $8 ; MMR3-NEXT: move $3, $8
; MMR3-NEXT: move $5, $6 ; MMR3-NEXT: move $5, $6
; MMR3-NEXT: lw $16, 32($sp) # 4-byte Folded Reload ; MMR3-NEXT: lwp $16, 32($sp)
; MMR3-NEXT: lw $17, 36($sp) # 4-byte Folded Reload
; MMR3-NEXT: addiusp 40 ; MMR3-NEXT: addiusp 40
; MMR3-NEXT: jrc $ra ; MMR3-NEXT: jrc $ra
; ;

View File

@ -333,8 +333,7 @@ define signext i128 @xor_i128(i128 signext %a, i128 signext %b) {
; ;
; MM32R3-LABEL: xor_i128: ; MM32R3-LABEL: xor_i128:
; MM32R3: # %bb.0: # %entry ; MM32R3: # %bb.0: # %entry
; MM32R3-NEXT: lw $3, 20($sp) ; MM32R3-NEXT: lwp $2, 16($sp)
; MM32R3-NEXT: lw $2, 16($sp)
; MM32R3-NEXT: xor16 $2, $4 ; MM32R3-NEXT: xor16 $2, $4
; MM32R3-NEXT: xor16 $3, $5 ; MM32R3-NEXT: xor16 $3, $5
; MM32R3-NEXT: lw $4, 24($sp) ; MM32R3-NEXT: lw $4, 24($sp)

View File

@ -0,0 +1,33 @@
; 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 i32 @fun(i32* %adr, i32 %val) {
; CHECK-LABEL: fun:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: addiusp -32
; CHECK-NEXT: .cfi_def_cfa_offset 32
; CHECK-NEXT: sw $ra, 28($sp) # 4-byte Folded Spill
; CHECK-NEXT: swp $16, 20($sp)
; CHECK-NEXT: .cfi_offset 31, -4
; CHECK-NEXT: .cfi_offset 17, -8
; CHECK-NEXT: .cfi_offset 16, -12
; CHECK-NEXT: move $17, $5
; CHECK-NEXT: move $16, $4
; CHECK-NEXT: jal fun1
; CHECK-NEXT: nop
; CHECK-NEXT: sw16 $17, 0($16)
; CHECK-NEXT: li16 $2, 0
; CHECK-NEXT: lwp $16, 20($sp)
; CHECK-NEXT: lw $ra, 28($sp) # 4-byte Folded Reload
; CHECK-NEXT: addiusp 32
; CHECK-NEXT: jrc $ra
entry:
%call1 = call i32* @fun1()
store i32 %val, i32* %adr, align 4
ret i32 0
}
declare i32* @fun1()

View File

@ -0,0 +1,289 @@
# 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 void @f1(i32* %adr, i32 %val) { ret void }
define void @f2(i32* %adr, i32 %val) { ret void }
define void @f3(i32* %adr, i32 %val) { ret void }
define void @f4(i32* %adr, i32 %val) { ret void }
declare i32* @f()
; Function Attrs: nounwind
declare void @llvm.stackprotector(i8*, i8**)
...
---
# CHECK-LABEL: name: f1
# CHECK: SWP_MM
# CHECK: LWP_MM
name: f1
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a0', virtual-reg: '' }
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 32
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s1', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
- { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a0, $a1, $ra, $s1, $s0
$sp = ADDiu $sp, -32
CFI_INSTRUCTION def_cfa_offset 32
SW killed $ra, $sp, 28 :: (store 4 into %stack.0)
SW killed $s1, $sp, 24 :: (store 4 into %stack.1)
SW killed $s0, $sp, 20 :: (store 4 into %stack.2)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s1_64, -8
CFI_INSTRUCTION offset $s0_64, -12
$s1 = MOVE16_MM $a1
$s0 = MOVE16_MM $a0
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
SW16_MM killed renamable $s1, killed renamable $s0, 0 :: (store 4 into %ir.adr)
$v0 = LI16_MM 0
$s0 = LW $sp, 20 :: (load 4 from %stack.2)
$s1 = LW $sp, 24 :: (load 4 from %stack.1)
$ra = LW $sp, 28 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 32
PseudoReturn undef $ra, implicit killed $v0
...
---
# CHECK-LABEL: name: f2
# CHECK: SWP_MM
# CHECK: LWP_MM
name: f2
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a0', virtual-reg: '' }
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 32
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s1', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
- { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a0, $a1, $ra, $s1, $s0
$sp = ADDiu $sp, -32
CFI_INSTRUCTION def_cfa_offset 32
SW killed $ra, $sp, 28 :: (store 4 into %stack.0)
SW_MM killed $s1, $sp, 24 :: (store 4 into %stack.1)
SW_MM killed $s0, $sp, 20 :: (store 4 into %stack.2)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s1_64, -8
CFI_INSTRUCTION offset $s0_64, -12
$s1 = MOVE16_MM $a1
$s0 = MOVE16_MM $a0
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
SW16_MM killed renamable $s1, killed renamable $s0, 0 :: (store 4 into %ir.adr)
$v0 = LI16_MM 0
$s0 = LW_MM $sp, 20 :: (load 4 from %stack.2)
$s1 = LW_MM $sp, 24 :: (load 4 from %stack.1)
$ra = LW $sp, 28 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 32
PseudoReturn undef $ra, implicit killed $v0
...
---
# CHECK-LABEL: name: f3
# CHECK: SWP_MM
# CHECK: LWP_MM
name: f3
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a0', virtual-reg: '' }
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 32
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s1', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
- { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a0, $a1, $ra, $s1, $s0
$sp = ADDiu $sp, -32
CFI_INSTRUCTION def_cfa_offset 32
SW killed $ra, $sp, 28 :: (store 4 into %stack.0)
SW_MM killed $s1, $sp, 24 :: (store 4 into %stack.1)
SW killed $s0, $sp, 20 :: (store 4 into %stack.2)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s1_64, -8
CFI_INSTRUCTION offset $s0_64, -12
$s1 = MOVE16_MM $a1
$s0 = MOVE16_MM $a0
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
SW16_MM killed renamable $s1, killed renamable $s0, 0 :: (store 4 into %ir.adr)
$v0 = LI16_MM 0
$s0 = LW_MM $sp, 20 :: (load 4 from %stack.2)
$s1 = LW $sp, 24 :: (load 4 from %stack.1)
$ra = LW $sp, 28 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 32
PseudoReturn undef $ra, implicit killed $v0
...
---
# CHECK-LABEL: name: f4
# CHECK: SWP_MM
# CHECK: LWP_MM
name: f4
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a0', virtual-reg: '' }
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 32
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s1', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
- { id: 2, name: '', type: spill-slot, offset: -12, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a0, $a1, $ra, $s1, $s0
$sp = ADDiu $sp, -32
CFI_INSTRUCTION def_cfa_offset 32
SW killed $ra, $sp, 28 :: (store 4 into %stack.0)
SW killed $s1, $sp, 24 :: (store 4 into %stack.1)
SW_MM killed $s0, $sp, 20 :: (store 4 into %stack.2)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s1_64, -8
CFI_INSTRUCTION offset $s0_64, -12
$s1 = MOVE16_MM $a1
$s0 = MOVE16_MM $a0
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
SW16_MM killed renamable $s1, killed renamable $s0, 0 :: (store 4 into %ir.adr)
$v0 = LI16_MM 0
$s0 = LW $sp, 20 :: (load 4 from %stack.2)
$s1 = LW_MM $sp, 24 :: (load 4 from %stack.1)
$ra = LW $sp, 28 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 32
PseudoReturn undef $ra, implicit killed $v0
...

View File

@ -0,0 +1,252 @@
# 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 void @f1(i32* %adr, i32 %val) { ret void }
define void @f2(i32* %adr, i32 %val) { ret void }
define void @f3(i32* %adr, i32 %val) { ret void }
define void @f4(i32* %adr, i32 %val) { ret void }
declare i32* @f()
; Function Attrs: nounwind
declare void @llvm.stackprotector(i8*, i8**)
...
---
# CHECK-LABEL: name: f1
# CHECK-NOT: SWP_MM
# CHECK-NOT: LWP_MM
name: f1
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 24
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a1, $ra, $s0
$sp = ADDiu $sp, -24
CFI_INSTRUCTION def_cfa_offset 24
SW killed $ra, $sp, 20 :: (store 4 into %stack.0)
SW killed $s0, $sp, 16 :: (store 4 into %stack.1)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s0_64, -8
$s0 = MOVE16_MM $a1
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
$v0 = MOVE16_MM killed $s0
$s0 = LW $sp, 16 :: (load 4 from %stack.1)
$ra = LW $sp, 20 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 24
PseudoReturn undef $ra, implicit killed $v0
...
---
# CHECK-LABEL: name: f2
# CHECK-NOT: SWP_MM
# CHECK-NOT: LWP_MM
name: f2
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 24
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a1, $ra, $s0
$sp = ADDiu $sp, -24
CFI_INSTRUCTION def_cfa_offset 24
SW_MM killed $ra, $sp, 20 :: (store 4 into %stack.0)
SW_MM killed $s0, $sp, 16 :: (store 4 into %stack.1)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s0_64, -8
$s0 = MOVE16_MM $a1
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
$v0 = MOVE16_MM killed $s0
$s0 = LW_MM $sp, 16 :: (load 4 from %stack.1)
$ra = LW_MM $sp, 20 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 24
PseudoReturn undef $ra, implicit killed $v0
...
---
# CHECK-LABEL: name: f3
# CHECK-NOT: SWP_MM
# CHECK-NOT: LWP_MM
name: f3
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 24
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a1, $ra, $s0
$sp = ADDiu $sp, -24
CFI_INSTRUCTION def_cfa_offset 24
SW_MM killed $ra, $sp, 20 :: (store 4 into %stack.0)
SW killed $s0, $sp, 16 :: (store 4 into %stack.1)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s0_64, -8
$s0 = MOVE16_MM $a1
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
$v0 = MOVE16_MM killed $s0
$s0 = LW_MM $sp, 16 :: (load 4 from %stack.1)
$ra = LW $sp, 20 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 24
PseudoReturn undef $ra, implicit killed $v0
...
---
# CHECK-LABEL: name: f4
# CHECK-NOT: SWP_MM
# CHECK-NOT: LWP_MM
name: f4
alignment: 2
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
registers:
liveins:
- { reg: '$a1', virtual-reg: '' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 24
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
stackProtector: ''
maxCallFrameSize: 16
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
savePoint: ''
restorePoint: ''
fixedStack:
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: '' }
- { id: 1, name: '', type: spill-slot, offset: -8, size: 4, alignment: 4,
stack-id: 0, callee-saved-register: '$s0', callee-saved-restored: true,
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
constants:
body: |
bb.0:
liveins: $a1, $ra, $s0
$sp = ADDiu $sp, -24
CFI_INSTRUCTION def_cfa_offset 24
SW killed $ra, $sp, 20 :: (store 4 into %stack.0)
SW_MM killed $s0, $sp, 16 :: (store 4 into %stack.1)
CFI_INSTRUCTION offset $ra_64, -4
CFI_INSTRUCTION offset $s0_64, -8
$s0 = MOVE16_MM $a1
JAL @f, csr_o32, implicit-def dead $ra, implicit-def $sp, implicit-def dead $v0
$v0 = MOVE16_MM killed $s0
$s0 = LW $sp, 16 :: (load 4 from %stack.1)
$ra = LW_MM $sp, 20 :: (load 4 from %stack.0)
$sp = ADDiu $sp, 24
PseudoReturn undef $ra, implicit killed $v0
...