1f37b6182SDimitry Andric //=== MicroMipsSizeReduction.cpp - MicroMips size reduction pass --------===//
2f37b6182SDimitry Andric //
3f37b6182SDimitry Andric // The LLVM Compiler Infrastructure
4f37b6182SDimitry Andric //
5f37b6182SDimitry Andric // This file is distributed under the University of Illinois Open Source
6f37b6182SDimitry Andric // License. See LICENSE.TXT for details.
7f37b6182SDimitry Andric //
8f37b6182SDimitry Andric //===----------------------------------------------------------------------===//
9f37b6182SDimitry Andric ///\file
10f37b6182SDimitry Andric /// This pass is used to reduce the size of instructions where applicable.
11f37b6182SDimitry Andric ///
12f37b6182SDimitry Andric /// TODO: Implement microMIPS64 support.
13f37b6182SDimitry Andric //===----------------------------------------------------------------------===//
14f37b6182SDimitry Andric #include "Mips.h"
15f37b6182SDimitry Andric #include "MipsInstrInfo.h"
16f37b6182SDimitry Andric #include "MipsSubtarget.h"
17f37b6182SDimitry Andric #include "llvm/ADT/Statistic.h"
18f37b6182SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
19f37b6182SDimitry Andric #include "llvm/Support/Debug.h"
20f37b6182SDimitry Andric
21f37b6182SDimitry Andric using namespace llvm;
22f37b6182SDimitry Andric
23f37b6182SDimitry Andric #define DEBUG_TYPE "micromips-reduce-size"
244ba319b5SDimitry Andric #define MICROMIPS_SIZE_REDUCE_NAME "MicroMips instruction size reduce pass"
25f37b6182SDimitry Andric
264ba319b5SDimitry Andric STATISTIC(NumReduced, "Number of instructions reduced (32-bit to 16-bit ones, "
274ba319b5SDimitry Andric "or two instructions into one");
28f37b6182SDimitry Andric
29f37b6182SDimitry Andric namespace {
30f37b6182SDimitry Andric
31f37b6182SDimitry Andric /// Order of operands to transfer
32f37b6182SDimitry Andric // TODO: Will be extended when additional optimizations are added
33f37b6182SDimitry Andric enum OperandTransfer {
34f37b6182SDimitry Andric OT_NA, ///< Not applicable
35f37b6182SDimitry Andric OT_OperandsAll, ///< Transfer all operands
362cab237bSDimitry Andric OT_Operands02, ///< Transfer operands 0 and 2
372cab237bSDimitry Andric OT_Operand2, ///< Transfer just operand 2
382cab237bSDimitry Andric OT_OperandsXOR, ///< Transfer operands for XOR16
394ba319b5SDimitry Andric OT_OperandsLwp, ///< Transfer operands for LWP
404ba319b5SDimitry Andric OT_OperandsSwp, ///< Transfer operands for SWP
41*b5893f02SDimitry Andric OT_OperandsMovep, ///< Transfer operands for MOVEP
42f37b6182SDimitry Andric };
43f37b6182SDimitry Andric
44f37b6182SDimitry Andric /// Reduction type
45f37b6182SDimitry Andric // TODO: Will be extended when additional optimizations are added
46f37b6182SDimitry Andric enum ReduceType {
474ba319b5SDimitry Andric RT_TwoInstr, ///< Reduce two instructions into one instruction
48f37b6182SDimitry Andric RT_OneInstr ///< Reduce one instruction into a smaller instruction
49f37b6182SDimitry Andric };
50f37b6182SDimitry Andric
51f37b6182SDimitry Andric // Information about immediate field restrictions
52f37b6182SDimitry Andric struct ImmField {
ImmField__anon3b2e6ace0111::ImmField53f37b6182SDimitry Andric ImmField() : ImmFieldOperand(-1), Shift(0), LBound(0), HBound(0) {}
ImmField__anon3b2e6ace0111::ImmField54f37b6182SDimitry Andric ImmField(uint8_t Shift, int16_t LBound, int16_t HBound,
55f37b6182SDimitry Andric int8_t ImmFieldOperand)
56f37b6182SDimitry Andric : ImmFieldOperand(ImmFieldOperand), Shift(Shift), LBound(LBound),
57f37b6182SDimitry Andric HBound(HBound) {}
58f37b6182SDimitry Andric int8_t ImmFieldOperand; // Immediate operand, -1 if it does not exist
59f37b6182SDimitry Andric uint8_t Shift; // Shift value
60f37b6182SDimitry Andric int16_t LBound; // Low bound of the immediate operand
61f37b6182SDimitry Andric int16_t HBound; // High bound of the immediate operand
62f37b6182SDimitry Andric };
63f37b6182SDimitry Andric
64f37b6182SDimitry Andric /// Information about operands
65f37b6182SDimitry Andric // TODO: Will be extended when additional optimizations are added
66f37b6182SDimitry Andric struct OpInfo {
OpInfo__anon3b2e6ace0111::OpInfo67f37b6182SDimitry Andric OpInfo(enum OperandTransfer TransferOperands)
68f37b6182SDimitry Andric : TransferOperands(TransferOperands) {}
OpInfo__anon3b2e6ace0111::OpInfo69f37b6182SDimitry Andric OpInfo() : TransferOperands(OT_NA) {}
70f37b6182SDimitry Andric
71f37b6182SDimitry Andric enum OperandTransfer
72f37b6182SDimitry Andric TransferOperands; ///< Operands to transfer to the new instruction
73f37b6182SDimitry Andric };
74f37b6182SDimitry Andric
75f37b6182SDimitry Andric // Information about opcodes
76f37b6182SDimitry Andric struct OpCodes {
OpCodes__anon3b2e6ace0111::OpCodes77f37b6182SDimitry Andric OpCodes(unsigned WideOpc, unsigned NarrowOpc)
78f37b6182SDimitry Andric : WideOpc(WideOpc), NarrowOpc(NarrowOpc) {}
79f37b6182SDimitry Andric
80f37b6182SDimitry Andric unsigned WideOpc; ///< Wide opcode
81f37b6182SDimitry Andric unsigned NarrowOpc; ///< Narrow opcode
82f37b6182SDimitry Andric };
83f37b6182SDimitry Andric
844ba319b5SDimitry Andric typedef struct ReduceEntryFunArgs ReduceEntryFunArgs;
854ba319b5SDimitry Andric
86f37b6182SDimitry Andric /// ReduceTable - A static table with information on mapping from wide
87f37b6182SDimitry Andric /// opcodes to narrow
88f37b6182SDimitry Andric struct ReduceEntry {
89f37b6182SDimitry Andric
90f37b6182SDimitry Andric enum ReduceType eRType; ///< Reduction type
91f37b6182SDimitry Andric bool (*ReduceFunction)(
924ba319b5SDimitry Andric ReduceEntryFunArgs *Arguments); ///< Pointer to reduce function
93f37b6182SDimitry Andric struct OpCodes Ops; ///< All relevant OpCodes
94f37b6182SDimitry Andric struct OpInfo OpInf; ///< Characteristics of operands
95f37b6182SDimitry Andric struct ImmField Imm; ///< Characteristics of immediate field
96f37b6182SDimitry Andric
ReduceEntry__anon3b2e6ace0111::ReduceEntry97f37b6182SDimitry Andric ReduceEntry(enum ReduceType RType, struct OpCodes Op,
984ba319b5SDimitry Andric bool (*F)(ReduceEntryFunArgs *Arguments), struct OpInfo OpInf,
994ba319b5SDimitry Andric struct ImmField Imm)
100f37b6182SDimitry Andric : eRType(RType), ReduceFunction(F), Ops(Op), OpInf(OpInf), Imm(Imm) {}
101f37b6182SDimitry Andric
NarrowOpc__anon3b2e6ace0111::ReduceEntry102f37b6182SDimitry Andric unsigned NarrowOpc() const { return Ops.NarrowOpc; }
WideOpc__anon3b2e6ace0111::ReduceEntry103f37b6182SDimitry Andric unsigned WideOpc() const { return Ops.WideOpc; }
LBound__anon3b2e6ace0111::ReduceEntry104f37b6182SDimitry Andric int16_t LBound() const { return Imm.LBound; }
HBound__anon3b2e6ace0111::ReduceEntry105f37b6182SDimitry Andric int16_t HBound() const { return Imm.HBound; }
Shift__anon3b2e6ace0111::ReduceEntry106f37b6182SDimitry Andric uint8_t Shift() const { return Imm.Shift; }
ImmField__anon3b2e6ace0111::ReduceEntry107f37b6182SDimitry Andric int8_t ImmField() const { return Imm.ImmFieldOperand; }
TransferOperands__anon3b2e6ace0111::ReduceEntry108f37b6182SDimitry Andric enum OperandTransfer TransferOperands() const {
109f37b6182SDimitry Andric return OpInf.TransferOperands;
110f37b6182SDimitry Andric }
RType__anon3b2e6ace0111::ReduceEntry111f37b6182SDimitry Andric enum ReduceType RType() const { return eRType; }
112f37b6182SDimitry Andric
113f37b6182SDimitry Andric // operator used by std::equal_range
operator <__anon3b2e6ace0111::ReduceEntry114f37b6182SDimitry Andric bool operator<(const unsigned int r) const { return (WideOpc() < r); }
115f37b6182SDimitry Andric
116f37b6182SDimitry Andric // operator used by std::equal_range
operator <(const unsigned int r,const struct ReduceEntry & re)117f37b6182SDimitry Andric friend bool operator<(const unsigned int r, const struct ReduceEntry &re) {
118f37b6182SDimitry Andric return (r < re.WideOpc());
119f37b6182SDimitry Andric }
120f37b6182SDimitry Andric };
121f37b6182SDimitry Andric
1224ba319b5SDimitry Andric // Function arguments for ReduceFunction
1234ba319b5SDimitry Andric struct ReduceEntryFunArgs {
1244ba319b5SDimitry Andric MachineInstr *MI; // Instruction
1254ba319b5SDimitry Andric const ReduceEntry &Entry; // Entry field
1264ba319b5SDimitry Andric MachineBasicBlock::instr_iterator
1274ba319b5SDimitry Andric &NextMII; // Iterator to next instruction in block
1284ba319b5SDimitry Andric
ReduceEntryFunArgs__anon3b2e6ace0111::ReduceEntryFunArgs1294ba319b5SDimitry Andric ReduceEntryFunArgs(MachineInstr *argMI, const ReduceEntry &argEntry,
1304ba319b5SDimitry Andric MachineBasicBlock::instr_iterator &argNextMII)
1314ba319b5SDimitry Andric : MI(argMI), Entry(argEntry), NextMII(argNextMII) {}
1324ba319b5SDimitry Andric };
1334ba319b5SDimitry Andric
1344ba319b5SDimitry Andric typedef llvm::SmallVector<ReduceEntry, 32> ReduceEntryVector;
1354ba319b5SDimitry Andric
136f37b6182SDimitry Andric class MicroMipsSizeReduce : public MachineFunctionPass {
137f37b6182SDimitry Andric public:
138f37b6182SDimitry Andric static char ID;
139f37b6182SDimitry Andric MicroMipsSizeReduce();
140f37b6182SDimitry Andric
141f37b6182SDimitry Andric static const MipsInstrInfo *MipsII;
142f37b6182SDimitry Andric const MipsSubtarget *Subtarget;
143f37b6182SDimitry Andric
144f37b6182SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
145f37b6182SDimitry Andric
getPassName() const146f37b6182SDimitry Andric llvm::StringRef getPassName() const override {
147f37b6182SDimitry Andric return "microMIPS instruction size reduction pass";
148f37b6182SDimitry Andric }
149f37b6182SDimitry Andric
150f37b6182SDimitry Andric private:
151f37b6182SDimitry Andric /// Reduces width of instructions in the specified basic block.
152f37b6182SDimitry Andric bool ReduceMBB(MachineBasicBlock &MBB);
153f37b6182SDimitry Andric
154f37b6182SDimitry Andric /// Attempts to reduce MI, returns true on success.
1554ba319b5SDimitry Andric bool ReduceMI(const MachineBasicBlock::instr_iterator &MII,
1564ba319b5SDimitry Andric MachineBasicBlock::instr_iterator &NextMII);
157f37b6182SDimitry Andric
158f37b6182SDimitry Andric // Attempts to reduce LW/SW instruction into LWSP/SWSP,
159f37b6182SDimitry Andric // returns true on success.
1604ba319b5SDimitry Andric static bool ReduceXWtoXWSP(ReduceEntryFunArgs *Arguments);
1614ba319b5SDimitry Andric
1624ba319b5SDimitry Andric // Attempts to reduce two LW/SW instructions into LWP/SWP instruction,
1634ba319b5SDimitry Andric // returns true on success.
1644ba319b5SDimitry Andric static bool ReduceXWtoXWP(ReduceEntryFunArgs *Arguments);
165f37b6182SDimitry Andric
1666d97bb29SDimitry Andric // Attempts to reduce LBU/LHU instruction into LBU16/LHU16,
1676d97bb29SDimitry Andric // returns true on success.
1684ba319b5SDimitry Andric static bool ReduceLXUtoLXU16(ReduceEntryFunArgs *Arguments);
1696d97bb29SDimitry Andric
1706d97bb29SDimitry Andric // Attempts to reduce SB/SH instruction into SB16/SH16,
1716d97bb29SDimitry Andric // returns true on success.
1724ba319b5SDimitry Andric static bool ReduceSXtoSX16(ReduceEntryFunArgs *Arguments);
1736d97bb29SDimitry Andric
174*b5893f02SDimitry Andric // Attempts to reduce two MOVE instructions into MOVEP instruction,
175*b5893f02SDimitry Andric // returns true on success.
176*b5893f02SDimitry Andric static bool ReduceMoveToMovep(ReduceEntryFunArgs *Arguments);
177*b5893f02SDimitry Andric
1782cab237bSDimitry Andric // Attempts to reduce arithmetic instructions, returns true on success.
1794ba319b5SDimitry Andric static bool ReduceArithmeticInstructions(ReduceEntryFunArgs *Arguments);
180f37b6182SDimitry Andric
1812cab237bSDimitry Andric // Attempts to reduce ADDIU into ADDIUSP instruction,
1822cab237bSDimitry Andric // returns true on success.
1834ba319b5SDimitry Andric static bool ReduceADDIUToADDIUSP(ReduceEntryFunArgs *Arguments);
1842cab237bSDimitry Andric
1852cab237bSDimitry Andric // Attempts to reduce ADDIU into ADDIUR1SP instruction,
1862cab237bSDimitry Andric // returns true on success.
1874ba319b5SDimitry Andric static bool ReduceADDIUToADDIUR1SP(ReduceEntryFunArgs *Arguments);
1882cab237bSDimitry Andric
1892cab237bSDimitry Andric // Attempts to reduce XOR into XOR16 instruction,
1902cab237bSDimitry Andric // returns true on success.
1914ba319b5SDimitry Andric static bool ReduceXORtoXOR16(ReduceEntryFunArgs *Arguments);
1922cab237bSDimitry Andric
1934ba319b5SDimitry Andric // Changes opcode of an instruction, replaces an instruction with a
1944ba319b5SDimitry Andric // new one, or replaces two instructions with a new instruction
1954ba319b5SDimitry Andric // depending on their order i.e. if these are consecutive forward
1964ba319b5SDimitry Andric // or consecutive backward
1974ba319b5SDimitry Andric static bool ReplaceInstruction(MachineInstr *MI, const ReduceEntry &Entry,
1984ba319b5SDimitry Andric MachineInstr *MI2 = nullptr,
1994ba319b5SDimitry Andric bool ConsecutiveForward = true);
200f37b6182SDimitry Andric
2012cab237bSDimitry Andric // Table with transformation rules for each instruction.
2024ba319b5SDimitry Andric static ReduceEntryVector ReduceTable;
203f37b6182SDimitry Andric };
204f37b6182SDimitry Andric
205f37b6182SDimitry Andric char MicroMipsSizeReduce::ID = 0;
206f37b6182SDimitry Andric const MipsInstrInfo *MicroMipsSizeReduce::MipsII;
207f37b6182SDimitry Andric
208f37b6182SDimitry Andric // This table must be sorted by WideOpc as a main criterion and
2092cab237bSDimitry Andric // ReduceType as a sub-criterion (when wide opcodes are the same).
2104ba319b5SDimitry Andric ReduceEntryVector MicroMipsSizeReduce::ReduceTable = {
211f37b6182SDimitry Andric
212f37b6182SDimitry Andric // ReduceType, OpCodes, ReduceFunction,
213f37b6182SDimitry Andric // OpInfo(TransferOperands),
214f37b6182SDimitry Andric // ImmField(Shift, LBound, HBound, ImmFieldPosition)
2152cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::ADDiu, Mips::ADDIUR1SP_MM),
2162cab237bSDimitry Andric ReduceADDIUToADDIUR1SP, OpInfo(OT_Operands02), ImmField(2, 0, 64, 2)},
2172cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::ADDiu, Mips::ADDIUSP_MM), ReduceADDIUToADDIUSP,
2182cab237bSDimitry Andric OpInfo(OT_Operand2), ImmField(0, 0, 0, 2)},
2192cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::ADDiu_MM, Mips::ADDIUR1SP_MM),
2202cab237bSDimitry Andric ReduceADDIUToADDIUR1SP, OpInfo(OT_Operands02), ImmField(2, 0, 64, 2)},
2212cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::ADDiu_MM, Mips::ADDIUSP_MM),
2222cab237bSDimitry Andric ReduceADDIUToADDIUSP, OpInfo(OT_Operand2), ImmField(0, 0, 0, 2)},
223f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::ADDu, Mips::ADDU16_MM),
224f37b6182SDimitry Andric ReduceArithmeticInstructions, OpInfo(OT_OperandsAll),
225f37b6182SDimitry Andric ImmField(0, 0, 0, -1)},
226f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::ADDu_MM, Mips::ADDU16_MM),
227f37b6182SDimitry Andric ReduceArithmeticInstructions, OpInfo(OT_OperandsAll),
228f37b6182SDimitry Andric ImmField(0, 0, 0, -1)},
2296d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::LBu, Mips::LBU16_MM), ReduceLXUtoLXU16,
2306d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(0, -1, 15, 2)},
2316d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::LBu_MM, Mips::LBU16_MM), ReduceLXUtoLXU16,
2326d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(0, -1, 15, 2)},
2332cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::LEA_ADDiu, Mips::ADDIUR1SP_MM),
2342cab237bSDimitry Andric ReduceADDIUToADDIUR1SP, OpInfo(OT_Operands02), ImmField(2, 0, 64, 2)},
2354ba319b5SDimitry Andric {RT_OneInstr, OpCodes(Mips::LEA_ADDiu_MM, Mips::ADDIUR1SP_MM),
2364ba319b5SDimitry Andric ReduceADDIUToADDIUR1SP, OpInfo(OT_Operands02), ImmField(2, 0, 64, 2)},
2376d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::LHu, Mips::LHU16_MM), ReduceLXUtoLXU16,
2386d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)},
2396d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::LHu_MM, Mips::LHU16_MM), ReduceLXUtoLXU16,
2406d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)},
2414ba319b5SDimitry Andric {RT_TwoInstr, OpCodes(Mips::LW, Mips::LWP_MM), ReduceXWtoXWP,
2424ba319b5SDimitry Andric OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)},
243f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::LW, Mips::LWSP_MM), ReduceXWtoXWSP,
244f37b6182SDimitry Andric OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
2454ba319b5SDimitry Andric {RT_TwoInstr, OpCodes(Mips::LW16_MM, Mips::LWP_MM), ReduceXWtoXWP,
2464ba319b5SDimitry Andric OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)},
2474ba319b5SDimitry Andric {RT_TwoInstr, OpCodes(Mips::LW_MM, Mips::LWP_MM), ReduceXWtoXWP,
2484ba319b5SDimitry Andric OpInfo(OT_OperandsLwp), ImmField(0, -2048, 2048, 2)},
249f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::LW_MM, Mips::LWSP_MM), ReduceXWtoXWSP,
250f37b6182SDimitry Andric OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
251*b5893f02SDimitry Andric {RT_TwoInstr, OpCodes(Mips::MOVE16_MM, Mips::MOVEP_MM), ReduceMoveToMovep,
252*b5893f02SDimitry Andric OpInfo(OT_OperandsMovep), ImmField(0, 0, 0, -1)},
2536d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::SB, Mips::SB16_MM), ReduceSXtoSX16,
2546d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(0, 0, 16, 2)},
2556d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::SB_MM, Mips::SB16_MM), ReduceSXtoSX16,
2566d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(0, 0, 16, 2)},
2576d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::SH, Mips::SH16_MM), ReduceSXtoSX16,
2586d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)},
2596d97bb29SDimitry Andric {RT_OneInstr, OpCodes(Mips::SH_MM, Mips::SH16_MM), ReduceSXtoSX16,
2606d97bb29SDimitry Andric OpInfo(OT_OperandsAll), ImmField(1, 0, 16, 2)},
261f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::SUBu, Mips::SUBU16_MM),
262f37b6182SDimitry Andric ReduceArithmeticInstructions, OpInfo(OT_OperandsAll),
263f37b6182SDimitry Andric ImmField(0, 0, 0, -1)},
264f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::SUBu_MM, Mips::SUBU16_MM),
265f37b6182SDimitry Andric ReduceArithmeticInstructions, OpInfo(OT_OperandsAll),
266f37b6182SDimitry Andric ImmField(0, 0, 0, -1)},
2674ba319b5SDimitry Andric {RT_TwoInstr, OpCodes(Mips::SW, Mips::SWP_MM), ReduceXWtoXWP,
2684ba319b5SDimitry Andric OpInfo(OT_OperandsSwp), ImmField(0, -2048, 2048, 2)},
269f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::SW, Mips::SWSP_MM), ReduceXWtoXWSP,
270f37b6182SDimitry Andric OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
2714ba319b5SDimitry Andric {RT_TwoInstr, OpCodes(Mips::SW16_MM, Mips::SWP_MM), ReduceXWtoXWP,
2724ba319b5SDimitry Andric OpInfo(OT_OperandsSwp), ImmField(0, -2048, 2048, 2)},
2734ba319b5SDimitry Andric {RT_TwoInstr, OpCodes(Mips::SW_MM, Mips::SWP_MM), ReduceXWtoXWP,
2744ba319b5SDimitry Andric OpInfo(OT_OperandsSwp), ImmField(0, -2048, 2048, 2)},
275f37b6182SDimitry Andric {RT_OneInstr, OpCodes(Mips::SW_MM, Mips::SWSP_MM), ReduceXWtoXWSP,
276f37b6182SDimitry Andric OpInfo(OT_OperandsAll), ImmField(2, 0, 32, 2)},
2772cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::XOR, Mips::XOR16_MM), ReduceXORtoXOR16,
2782cab237bSDimitry Andric OpInfo(OT_OperandsXOR), ImmField(0, 0, 0, -1)},
2792cab237bSDimitry Andric {RT_OneInstr, OpCodes(Mips::XOR_MM, Mips::XOR16_MM), ReduceXORtoXOR16,
2802cab237bSDimitry Andric OpInfo(OT_OperandsXOR), ImmField(0, 0, 0, -1)}};
2814ba319b5SDimitry Andric } // end anonymous namespace
2824ba319b5SDimitry Andric
INITIALIZE_PASS(MicroMipsSizeReduce,DEBUG_TYPE,MICROMIPS_SIZE_REDUCE_NAME,false,false)2834ba319b5SDimitry Andric INITIALIZE_PASS(MicroMipsSizeReduce, DEBUG_TYPE, MICROMIPS_SIZE_REDUCE_NAME,
2844ba319b5SDimitry Andric false, false)
285f37b6182SDimitry Andric
2862cab237bSDimitry Andric // Returns true if the machine operand MO is register SP.
287f37b6182SDimitry Andric static bool IsSP(const MachineOperand &MO) {
288f37b6182SDimitry Andric if (MO.isReg() && ((MO.getReg() == Mips::SP)))
289f37b6182SDimitry Andric return true;
290f37b6182SDimitry Andric return false;
291f37b6182SDimitry Andric }
292f37b6182SDimitry Andric
293f37b6182SDimitry Andric // Returns true if the machine operand MO is register $16, $17, or $2-$7.
isMMThreeBitGPRegister(const MachineOperand & MO)294f37b6182SDimitry Andric static bool isMMThreeBitGPRegister(const MachineOperand &MO) {
295f37b6182SDimitry Andric if (MO.isReg() && Mips::GPRMM16RegClass.contains(MO.getReg()))
296f37b6182SDimitry Andric return true;
297f37b6182SDimitry Andric return false;
298f37b6182SDimitry Andric }
299f37b6182SDimitry Andric
3006d97bb29SDimitry Andric // Returns true if the machine operand MO is register $0, $17, or $2-$7.
isMMSourceRegister(const MachineOperand & MO)3016d97bb29SDimitry Andric static bool isMMSourceRegister(const MachineOperand &MO) {
3026d97bb29SDimitry Andric if (MO.isReg() && Mips::GPRMM16ZeroRegClass.contains(MO.getReg()))
3036d97bb29SDimitry Andric return true;
3046d97bb29SDimitry Andric return false;
3056d97bb29SDimitry Andric }
3066d97bb29SDimitry Andric
307f37b6182SDimitry Andric // Returns true if the operand Op is an immediate value
3082cab237bSDimitry Andric // and writes the immediate value into variable Imm.
GetImm(MachineInstr * MI,unsigned Op,int64_t & Imm)309f37b6182SDimitry Andric static bool GetImm(MachineInstr *MI, unsigned Op, int64_t &Imm) {
310f37b6182SDimitry Andric
311f37b6182SDimitry Andric if (!MI->getOperand(Op).isImm())
312f37b6182SDimitry Andric return false;
313f37b6182SDimitry Andric Imm = MI->getOperand(Op).getImm();
314f37b6182SDimitry Andric return true;
315f37b6182SDimitry Andric }
316f37b6182SDimitry Andric
3172cab237bSDimitry Andric // Returns true if the value is a valid immediate for ADDIUSP.
AddiuspImmValue(int64_t Value)3182cab237bSDimitry Andric static bool AddiuspImmValue(int64_t Value) {
3192cab237bSDimitry Andric int64_t Value2 = Value >> 2;
3202cab237bSDimitry Andric if (((Value & (int64_t)maskTrailingZeros<uint64_t>(2)) == Value) &&
3212cab237bSDimitry Andric ((Value2 >= 2 && Value2 <= 257) || (Value2 >= -258 && Value2 <= -3)))
322f37b6182SDimitry Andric return true;
323f37b6182SDimitry Andric return false;
324f37b6182SDimitry Andric }
325f37b6182SDimitry Andric
3262cab237bSDimitry Andric // Returns true if the variable Value has the number of least-significant zero
3272cab237bSDimitry Andric // bits equal to Shift and if the shifted value is between the bounds.
InRange(int64_t Value,unsigned short Shift,int LBound,int HBound)3282cab237bSDimitry Andric static bool InRange(int64_t Value, unsigned short Shift, int LBound,
3292cab237bSDimitry Andric int HBound) {
3302cab237bSDimitry Andric int64_t Value2 = Value >> Shift;
3312cab237bSDimitry Andric if (((Value & (int64_t)maskTrailingZeros<uint64_t>(Shift)) == Value) &&
3322cab237bSDimitry Andric (Value2 >= LBound) && (Value2 < HBound))
3332cab237bSDimitry Andric return true;
3342cab237bSDimitry Andric return false;
3352cab237bSDimitry Andric }
3362cab237bSDimitry Andric
3372cab237bSDimitry Andric // Returns true if immediate operand is in range.
ImmInRange(MachineInstr * MI,const ReduceEntry & Entry)338f37b6182SDimitry Andric static bool ImmInRange(MachineInstr *MI, const ReduceEntry &Entry) {
339f37b6182SDimitry Andric
340f37b6182SDimitry Andric int64_t offset;
341f37b6182SDimitry Andric
342f37b6182SDimitry Andric if (!GetImm(MI, Entry.ImmField(), offset))
343f37b6182SDimitry Andric return false;
344f37b6182SDimitry Andric
345f37b6182SDimitry Andric if (!InRange(offset, Entry.Shift(), Entry.LBound(), Entry.HBound()))
346f37b6182SDimitry Andric return false;
347f37b6182SDimitry Andric
348f37b6182SDimitry Andric return true;
349f37b6182SDimitry Andric }
350f37b6182SDimitry Andric
3514ba319b5SDimitry Andric // Returns true if MI can be reduced to lwp/swp instruction
CheckXWPInstr(MachineInstr * MI,bool ReduceToLwp,const ReduceEntry & Entry)3524ba319b5SDimitry Andric static bool CheckXWPInstr(MachineInstr *MI, bool ReduceToLwp,
3534ba319b5SDimitry Andric const ReduceEntry &Entry) {
3544ba319b5SDimitry Andric
3554ba319b5SDimitry Andric if (ReduceToLwp &&
3564ba319b5SDimitry Andric !(MI->getOpcode() == Mips::LW || MI->getOpcode() == Mips::LW_MM ||
3574ba319b5SDimitry Andric MI->getOpcode() == Mips::LW16_MM))
3584ba319b5SDimitry Andric return false;
3594ba319b5SDimitry Andric
3604ba319b5SDimitry Andric if (!ReduceToLwp &&
3614ba319b5SDimitry Andric !(MI->getOpcode() == Mips::SW || MI->getOpcode() == Mips::SW_MM ||
3624ba319b5SDimitry Andric MI->getOpcode() == Mips::SW16_MM))
3634ba319b5SDimitry Andric return false;
3644ba319b5SDimitry Andric
3654ba319b5SDimitry Andric unsigned reg = MI->getOperand(0).getReg();
3664ba319b5SDimitry Andric if (reg == Mips::RA)
3674ba319b5SDimitry Andric return false;
3684ba319b5SDimitry Andric
3694ba319b5SDimitry Andric if (!ImmInRange(MI, Entry))
3704ba319b5SDimitry Andric return false;
3714ba319b5SDimitry Andric
3724ba319b5SDimitry Andric if (ReduceToLwp && (MI->getOperand(0).getReg() == MI->getOperand(1).getReg()))
3734ba319b5SDimitry Andric return false;
3744ba319b5SDimitry Andric
3754ba319b5SDimitry Andric return true;
3764ba319b5SDimitry Andric }
3774ba319b5SDimitry Andric
3784ba319b5SDimitry Andric // Returns true if the registers Reg1 and Reg2 are consecutive
ConsecutiveRegisters(unsigned Reg1,unsigned Reg2)3794ba319b5SDimitry Andric static bool ConsecutiveRegisters(unsigned Reg1, unsigned Reg2) {
3804ba319b5SDimitry Andric static SmallVector<unsigned, 31> Registers = {
3814ba319b5SDimitry Andric Mips::AT, Mips::V0, Mips::V1, Mips::A0, Mips::A1, Mips::A2, Mips::A3,
3824ba319b5SDimitry Andric Mips::T0, Mips::T1, Mips::T2, Mips::T3, Mips::T4, Mips::T5, Mips::T6,
3834ba319b5SDimitry Andric Mips::T7, Mips::S0, Mips::S1, Mips::S2, Mips::S3, Mips::S4, Mips::S5,
3844ba319b5SDimitry Andric Mips::S6, Mips::S7, Mips::T8, Mips::T9, Mips::K0, Mips::K1, Mips::GP,
3854ba319b5SDimitry Andric Mips::SP, Mips::FP, Mips::RA};
3864ba319b5SDimitry Andric
3874ba319b5SDimitry Andric for (uint8_t i = 0; i < Registers.size() - 1; i++) {
3884ba319b5SDimitry Andric if (Registers[i] == Reg1) {
3894ba319b5SDimitry Andric if (Registers[i + 1] == Reg2)
3904ba319b5SDimitry Andric return true;
3914ba319b5SDimitry Andric else
3924ba319b5SDimitry Andric return false;
3934ba319b5SDimitry Andric }
3944ba319b5SDimitry Andric }
3954ba319b5SDimitry Andric return false;
3964ba319b5SDimitry Andric }
3974ba319b5SDimitry Andric
3984ba319b5SDimitry Andric // Returns true if registers and offsets are consecutive
ConsecutiveInstr(MachineInstr * MI1,MachineInstr * MI2)3994ba319b5SDimitry Andric static bool ConsecutiveInstr(MachineInstr *MI1, MachineInstr *MI2) {
4004ba319b5SDimitry Andric
4014ba319b5SDimitry Andric int64_t Offset1, Offset2;
4024ba319b5SDimitry Andric if (!GetImm(MI1, 2, Offset1))
4034ba319b5SDimitry Andric return false;
4044ba319b5SDimitry Andric if (!GetImm(MI2, 2, Offset2))
4054ba319b5SDimitry Andric return false;
4064ba319b5SDimitry Andric
4074ba319b5SDimitry Andric unsigned Reg1 = MI1->getOperand(0).getReg();
4084ba319b5SDimitry Andric unsigned Reg2 = MI2->getOperand(0).getReg();
4094ba319b5SDimitry Andric
4104ba319b5SDimitry Andric return ((Offset1 == (Offset2 - 4)) && (ConsecutiveRegisters(Reg1, Reg2)));
4114ba319b5SDimitry Andric }
4124ba319b5SDimitry Andric
MicroMipsSizeReduce()413f37b6182SDimitry Andric MicroMipsSizeReduce::MicroMipsSizeReduce() : MachineFunctionPass(ID) {}
414f37b6182SDimitry Andric
ReduceMI(const MachineBasicBlock::instr_iterator & MII,MachineBasicBlock::instr_iterator & NextMII)4154ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceMI(const MachineBasicBlock::instr_iterator &MII,
4164ba319b5SDimitry Andric MachineBasicBlock::instr_iterator &NextMII) {
417f37b6182SDimitry Andric
418f37b6182SDimitry Andric MachineInstr *MI = &*MII;
419f37b6182SDimitry Andric unsigned Opcode = MI->getOpcode();
420f37b6182SDimitry Andric
421f37b6182SDimitry Andric // Search the table.
4224ba319b5SDimitry Andric ReduceEntryVector::const_iterator Start = std::begin(ReduceTable);
4234ba319b5SDimitry Andric ReduceEntryVector::const_iterator End = std::end(ReduceTable);
424f37b6182SDimitry Andric
4254ba319b5SDimitry Andric std::pair<ReduceEntryVector::const_iterator,
4264ba319b5SDimitry Andric ReduceEntryVector::const_iterator>
427f37b6182SDimitry Andric Range = std::equal_range(Start, End, Opcode);
428f37b6182SDimitry Andric
429f37b6182SDimitry Andric if (Range.first == Range.second)
430f37b6182SDimitry Andric return false;
431f37b6182SDimitry Andric
4324ba319b5SDimitry Andric for (ReduceEntryVector::const_iterator Entry = Range.first;
4334ba319b5SDimitry Andric Entry != Range.second; ++Entry) {
4344ba319b5SDimitry Andric ReduceEntryFunArgs Arguments(&(*MII), *Entry, NextMII);
4354ba319b5SDimitry Andric if (((*Entry).ReduceFunction)(&Arguments))
436f37b6182SDimitry Andric return true;
4374ba319b5SDimitry Andric }
438f37b6182SDimitry Andric return false;
439f37b6182SDimitry Andric }
440f37b6182SDimitry Andric
ReduceXWtoXWSP(ReduceEntryFunArgs * Arguments)4414ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceXWtoXWSP(ReduceEntryFunArgs *Arguments) {
4424ba319b5SDimitry Andric
4434ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
4444ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
445f37b6182SDimitry Andric
446f37b6182SDimitry Andric if (!ImmInRange(MI, Entry))
447f37b6182SDimitry Andric return false;
448f37b6182SDimitry Andric
449f37b6182SDimitry Andric if (!IsSP(MI->getOperand(1)))
450f37b6182SDimitry Andric return false;
451f37b6182SDimitry Andric
452f37b6182SDimitry Andric return ReplaceInstruction(MI, Entry);
453f37b6182SDimitry Andric }
454f37b6182SDimitry Andric
ReduceXWtoXWP(ReduceEntryFunArgs * Arguments)4554ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceXWtoXWP(ReduceEntryFunArgs *Arguments) {
4564ba319b5SDimitry Andric
4574ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
4584ba319b5SDimitry Andric MachineBasicBlock::instr_iterator &NextMII = Arguments->NextMII;
4594ba319b5SDimitry Andric const MachineBasicBlock::instr_iterator &E =
4604ba319b5SDimitry Andric Arguments->MI->getParent()->instr_end();
4614ba319b5SDimitry Andric
4624ba319b5SDimitry Andric if (NextMII == E)
4634ba319b5SDimitry Andric return false;
4644ba319b5SDimitry Andric
4654ba319b5SDimitry Andric MachineInstr *MI1 = Arguments->MI;
4664ba319b5SDimitry Andric MachineInstr *MI2 = &*NextMII;
4674ba319b5SDimitry Andric
4684ba319b5SDimitry Andric // ReduceToLwp = true/false - reduce to LWP/SWP instruction
4694ba319b5SDimitry Andric bool ReduceToLwp = (MI1->getOpcode() == Mips::LW) ||
4704ba319b5SDimitry Andric (MI1->getOpcode() == Mips::LW_MM) ||
4714ba319b5SDimitry Andric (MI1->getOpcode() == Mips::LW16_MM);
4724ba319b5SDimitry Andric
4734ba319b5SDimitry Andric if (!CheckXWPInstr(MI1, ReduceToLwp, Entry))
4744ba319b5SDimitry Andric return false;
4754ba319b5SDimitry Andric
4764ba319b5SDimitry Andric if (!CheckXWPInstr(MI2, ReduceToLwp, Entry))
4774ba319b5SDimitry Andric return false;
4784ba319b5SDimitry Andric
4794ba319b5SDimitry Andric unsigned Reg1 = MI1->getOperand(1).getReg();
4804ba319b5SDimitry Andric unsigned Reg2 = MI2->getOperand(1).getReg();
4814ba319b5SDimitry Andric
4824ba319b5SDimitry Andric if (Reg1 != Reg2)
4834ba319b5SDimitry Andric return false;
4844ba319b5SDimitry Andric
4854ba319b5SDimitry Andric bool ConsecutiveForward = ConsecutiveInstr(MI1, MI2);
4864ba319b5SDimitry Andric bool ConsecutiveBackward = ConsecutiveInstr(MI2, MI1);
4874ba319b5SDimitry Andric
4884ba319b5SDimitry Andric if (!(ConsecutiveForward || ConsecutiveBackward))
4894ba319b5SDimitry Andric return false;
4904ba319b5SDimitry Andric
4914ba319b5SDimitry Andric NextMII = std::next(NextMII);
4924ba319b5SDimitry Andric return ReplaceInstruction(MI1, Entry, MI2, ConsecutiveForward);
4934ba319b5SDimitry Andric }
4944ba319b5SDimitry Andric
ReduceArithmeticInstructions(ReduceEntryFunArgs * Arguments)495f37b6182SDimitry Andric bool MicroMipsSizeReduce::ReduceArithmeticInstructions(
4964ba319b5SDimitry Andric ReduceEntryFunArgs *Arguments) {
4974ba319b5SDimitry Andric
4984ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
4994ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
500f37b6182SDimitry Andric
501f37b6182SDimitry Andric if (!isMMThreeBitGPRegister(MI->getOperand(0)) ||
502f37b6182SDimitry Andric !isMMThreeBitGPRegister(MI->getOperand(1)) ||
503f37b6182SDimitry Andric !isMMThreeBitGPRegister(MI->getOperand(2)))
504f37b6182SDimitry Andric return false;
505f37b6182SDimitry Andric
506f37b6182SDimitry Andric return ReplaceInstruction(MI, Entry);
507f37b6182SDimitry Andric }
508f37b6182SDimitry Andric
ReduceADDIUToADDIUR1SP(ReduceEntryFunArgs * Arguments)5094ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceADDIUToADDIUR1SP(
5104ba319b5SDimitry Andric ReduceEntryFunArgs *Arguments) {
5114ba319b5SDimitry Andric
5124ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
5134ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
5142cab237bSDimitry Andric
5152cab237bSDimitry Andric if (!ImmInRange(MI, Entry))
5162cab237bSDimitry Andric return false;
5172cab237bSDimitry Andric
5182cab237bSDimitry Andric if (!isMMThreeBitGPRegister(MI->getOperand(0)) || !IsSP(MI->getOperand(1)))
5192cab237bSDimitry Andric return false;
5202cab237bSDimitry Andric
5212cab237bSDimitry Andric return ReplaceInstruction(MI, Entry);
5222cab237bSDimitry Andric }
5232cab237bSDimitry Andric
ReduceADDIUToADDIUSP(ReduceEntryFunArgs * Arguments)5244ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceADDIUToADDIUSP(ReduceEntryFunArgs *Arguments) {
5254ba319b5SDimitry Andric
5264ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
5274ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
5282cab237bSDimitry Andric
5292cab237bSDimitry Andric int64_t ImmValue;
5302cab237bSDimitry Andric if (!GetImm(MI, Entry.ImmField(), ImmValue))
5312cab237bSDimitry Andric return false;
5322cab237bSDimitry Andric
5332cab237bSDimitry Andric if (!AddiuspImmValue(ImmValue))
5342cab237bSDimitry Andric return false;
5352cab237bSDimitry Andric
5362cab237bSDimitry Andric if (!IsSP(MI->getOperand(0)) || !IsSP(MI->getOperand(1)))
5372cab237bSDimitry Andric return false;
5382cab237bSDimitry Andric
5392cab237bSDimitry Andric return ReplaceInstruction(MI, Entry);
5402cab237bSDimitry Andric }
5412cab237bSDimitry Andric
ReduceLXUtoLXU16(ReduceEntryFunArgs * Arguments)5424ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceLXUtoLXU16(ReduceEntryFunArgs *Arguments) {
5434ba319b5SDimitry Andric
5444ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
5454ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
5466d97bb29SDimitry Andric
5476d97bb29SDimitry Andric if (!ImmInRange(MI, Entry))
5486d97bb29SDimitry Andric return false;
5496d97bb29SDimitry Andric
5506d97bb29SDimitry Andric if (!isMMThreeBitGPRegister(MI->getOperand(0)) ||
5516d97bb29SDimitry Andric !isMMThreeBitGPRegister(MI->getOperand(1)))
5526d97bb29SDimitry Andric return false;
5536d97bb29SDimitry Andric
5546d97bb29SDimitry Andric return ReplaceInstruction(MI, Entry);
5556d97bb29SDimitry Andric }
5566d97bb29SDimitry Andric
ReduceSXtoSX16(ReduceEntryFunArgs * Arguments)5574ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceSXtoSX16(ReduceEntryFunArgs *Arguments) {
5584ba319b5SDimitry Andric
5594ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
5604ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
5616d97bb29SDimitry Andric
5626d97bb29SDimitry Andric if (!ImmInRange(MI, Entry))
5636d97bb29SDimitry Andric return false;
5646d97bb29SDimitry Andric
5656d97bb29SDimitry Andric if (!isMMSourceRegister(MI->getOperand(0)) ||
5666d97bb29SDimitry Andric !isMMThreeBitGPRegister(MI->getOperand(1)))
5676d97bb29SDimitry Andric return false;
5686d97bb29SDimitry Andric
5696d97bb29SDimitry Andric return ReplaceInstruction(MI, Entry);
5706d97bb29SDimitry Andric }
5716d97bb29SDimitry Andric
572*b5893f02SDimitry Andric // Returns true if Reg can be a source register
573*b5893f02SDimitry Andric // of MOVEP instruction
IsMovepSrcRegister(unsigned Reg)574*b5893f02SDimitry Andric static bool IsMovepSrcRegister(unsigned Reg) {
575*b5893f02SDimitry Andric
576*b5893f02SDimitry Andric if (Reg == Mips::ZERO || Reg == Mips::V0 || Reg == Mips::V1 ||
577*b5893f02SDimitry Andric Reg == Mips::S0 || Reg == Mips::S1 || Reg == Mips::S2 ||
578*b5893f02SDimitry Andric Reg == Mips::S3 || Reg == Mips::S4)
579*b5893f02SDimitry Andric return true;
580*b5893f02SDimitry Andric
581*b5893f02SDimitry Andric return false;
582*b5893f02SDimitry Andric }
583*b5893f02SDimitry Andric
584*b5893f02SDimitry Andric // Returns true if Reg can be a destination register
585*b5893f02SDimitry Andric // of MOVEP instruction
IsMovepDestinationReg(unsigned Reg)586*b5893f02SDimitry Andric static bool IsMovepDestinationReg(unsigned Reg) {
587*b5893f02SDimitry Andric
588*b5893f02SDimitry Andric if (Reg == Mips::A0 || Reg == Mips::A1 || Reg == Mips::A2 ||
589*b5893f02SDimitry Andric Reg == Mips::A3 || Reg == Mips::S5 || Reg == Mips::S6)
590*b5893f02SDimitry Andric return true;
591*b5893f02SDimitry Andric
592*b5893f02SDimitry Andric return false;
593*b5893f02SDimitry Andric }
594*b5893f02SDimitry Andric
595*b5893f02SDimitry Andric // Returns true if the registers can be a pair of destination
596*b5893f02SDimitry Andric // registers in MOVEP instruction
IsMovepDestinationRegPair(unsigned R0,unsigned R1)597*b5893f02SDimitry Andric static bool IsMovepDestinationRegPair(unsigned R0, unsigned R1) {
598*b5893f02SDimitry Andric
599*b5893f02SDimitry Andric if ((R0 == Mips::A0 && R1 == Mips::S5) ||
600*b5893f02SDimitry Andric (R0 == Mips::A0 && R1 == Mips::S6) ||
601*b5893f02SDimitry Andric (R0 == Mips::A0 && R1 == Mips::A1) ||
602*b5893f02SDimitry Andric (R0 == Mips::A0 && R1 == Mips::A2) ||
603*b5893f02SDimitry Andric (R0 == Mips::A0 && R1 == Mips::A3) ||
604*b5893f02SDimitry Andric (R0 == Mips::A1 && R1 == Mips::A2) ||
605*b5893f02SDimitry Andric (R0 == Mips::A1 && R1 == Mips::A3) ||
606*b5893f02SDimitry Andric (R0 == Mips::A2 && R1 == Mips::A3))
607*b5893f02SDimitry Andric return true;
608*b5893f02SDimitry Andric
609*b5893f02SDimitry Andric return false;
610*b5893f02SDimitry Andric }
611*b5893f02SDimitry Andric
ReduceMoveToMovep(ReduceEntryFunArgs * Arguments)612*b5893f02SDimitry Andric bool MicroMipsSizeReduce::ReduceMoveToMovep(ReduceEntryFunArgs *Arguments) {
613*b5893f02SDimitry Andric
614*b5893f02SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
615*b5893f02SDimitry Andric MachineBasicBlock::instr_iterator &NextMII = Arguments->NextMII;
616*b5893f02SDimitry Andric const MachineBasicBlock::instr_iterator &E =
617*b5893f02SDimitry Andric Arguments->MI->getParent()->instr_end();
618*b5893f02SDimitry Andric
619*b5893f02SDimitry Andric if (NextMII == E)
620*b5893f02SDimitry Andric return false;
621*b5893f02SDimitry Andric
622*b5893f02SDimitry Andric MachineInstr *MI1 = Arguments->MI;
623*b5893f02SDimitry Andric MachineInstr *MI2 = &*NextMII;
624*b5893f02SDimitry Andric
625*b5893f02SDimitry Andric unsigned RegDstMI1 = MI1->getOperand(0).getReg();
626*b5893f02SDimitry Andric unsigned RegSrcMI1 = MI1->getOperand(1).getReg();
627*b5893f02SDimitry Andric
628*b5893f02SDimitry Andric if (!IsMovepSrcRegister(RegSrcMI1))
629*b5893f02SDimitry Andric return false;
630*b5893f02SDimitry Andric
631*b5893f02SDimitry Andric if (!IsMovepDestinationReg(RegDstMI1))
632*b5893f02SDimitry Andric return false;
633*b5893f02SDimitry Andric
634*b5893f02SDimitry Andric if (MI2->getOpcode() != Entry.WideOpc())
635*b5893f02SDimitry Andric return false;
636*b5893f02SDimitry Andric
637*b5893f02SDimitry Andric unsigned RegDstMI2 = MI2->getOperand(0).getReg();
638*b5893f02SDimitry Andric unsigned RegSrcMI2 = MI2->getOperand(1).getReg();
639*b5893f02SDimitry Andric
640*b5893f02SDimitry Andric if (!IsMovepSrcRegister(RegSrcMI2))
641*b5893f02SDimitry Andric return false;
642*b5893f02SDimitry Andric
643*b5893f02SDimitry Andric bool ConsecutiveForward;
644*b5893f02SDimitry Andric if (IsMovepDestinationRegPair(RegDstMI1, RegDstMI2)) {
645*b5893f02SDimitry Andric ConsecutiveForward = true;
646*b5893f02SDimitry Andric } else if (IsMovepDestinationRegPair(RegDstMI2, RegDstMI1)) {
647*b5893f02SDimitry Andric ConsecutiveForward = false;
648*b5893f02SDimitry Andric } else
649*b5893f02SDimitry Andric return false;
650*b5893f02SDimitry Andric
651*b5893f02SDimitry Andric NextMII = std::next(NextMII);
652*b5893f02SDimitry Andric return ReplaceInstruction(MI1, Entry, MI2, ConsecutiveForward);
653*b5893f02SDimitry Andric }
654*b5893f02SDimitry Andric
ReduceXORtoXOR16(ReduceEntryFunArgs * Arguments)6554ba319b5SDimitry Andric bool MicroMipsSizeReduce::ReduceXORtoXOR16(ReduceEntryFunArgs *Arguments) {
6564ba319b5SDimitry Andric
6574ba319b5SDimitry Andric MachineInstr *MI = Arguments->MI;
6584ba319b5SDimitry Andric const ReduceEntry &Entry = Arguments->Entry;
6594ba319b5SDimitry Andric
6602cab237bSDimitry Andric if (!isMMThreeBitGPRegister(MI->getOperand(0)) ||
6612cab237bSDimitry Andric !isMMThreeBitGPRegister(MI->getOperand(1)) ||
6622cab237bSDimitry Andric !isMMThreeBitGPRegister(MI->getOperand(2)))
6632cab237bSDimitry Andric return false;
6642cab237bSDimitry Andric
6652cab237bSDimitry Andric if (!(MI->getOperand(0).getReg() == MI->getOperand(2).getReg()) &&
6662cab237bSDimitry Andric !(MI->getOperand(0).getReg() == MI->getOperand(1).getReg()))
6672cab237bSDimitry Andric return false;
6682cab237bSDimitry Andric
6692cab237bSDimitry Andric return ReplaceInstruction(MI, Entry);
6702cab237bSDimitry Andric }
6712cab237bSDimitry Andric
ReduceMBB(MachineBasicBlock & MBB)672f37b6182SDimitry Andric bool MicroMipsSizeReduce::ReduceMBB(MachineBasicBlock &MBB) {
673f37b6182SDimitry Andric bool Modified = false;
674f37b6182SDimitry Andric MachineBasicBlock::instr_iterator MII = MBB.instr_begin(),
675f37b6182SDimitry Andric E = MBB.instr_end();
676f37b6182SDimitry Andric MachineBasicBlock::instr_iterator NextMII;
677f37b6182SDimitry Andric
678f37b6182SDimitry Andric // Iterate through the instructions in the basic block
679f37b6182SDimitry Andric for (; MII != E; MII = NextMII) {
680f37b6182SDimitry Andric NextMII = std::next(MII);
681f37b6182SDimitry Andric MachineInstr *MI = &*MII;
682f37b6182SDimitry Andric
683f37b6182SDimitry Andric // Don't reduce bundled instructions or pseudo operations
684f37b6182SDimitry Andric if (MI->isBundle() || MI->isTransient())
685f37b6182SDimitry Andric continue;
686f37b6182SDimitry Andric
687f37b6182SDimitry Andric // Try to reduce 32-bit instruction into 16-bit instruction
6884ba319b5SDimitry Andric Modified |= ReduceMI(MII, NextMII);
689f37b6182SDimitry Andric }
690f37b6182SDimitry Andric
691f37b6182SDimitry Andric return Modified;
692f37b6182SDimitry Andric }
693f37b6182SDimitry Andric
ReplaceInstruction(MachineInstr * MI,const ReduceEntry & Entry,MachineInstr * MI2,bool ConsecutiveForward)694f37b6182SDimitry Andric bool MicroMipsSizeReduce::ReplaceInstruction(MachineInstr *MI,
6954ba319b5SDimitry Andric const ReduceEntry &Entry,
6964ba319b5SDimitry Andric MachineInstr *MI2,
6974ba319b5SDimitry Andric bool ConsecutiveForward) {
698f37b6182SDimitry Andric
6992cab237bSDimitry Andric enum OperandTransfer OpTransfer = Entry.TransferOperands();
7002cab237bSDimitry Andric
7014ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Converting 32-bit: " << *MI);
702f37b6182SDimitry Andric ++NumReduced;
7032cab237bSDimitry Andric
7042cab237bSDimitry Andric if (OpTransfer == OT_OperandsAll) {
7052cab237bSDimitry Andric MI->setDesc(MipsII->get(Entry.NarrowOpc()));
7064ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << " to 16-bit: " << *MI);
707f37b6182SDimitry Andric return true;
7082cab237bSDimitry Andric } else {
7092cab237bSDimitry Andric MachineBasicBlock &MBB = *MI->getParent();
7102cab237bSDimitry Andric const MCInstrDesc &NewMCID = MipsII->get(Entry.NarrowOpc());
7112cab237bSDimitry Andric DebugLoc dl = MI->getDebugLoc();
7122cab237bSDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);
7132cab237bSDimitry Andric switch (OpTransfer) {
7142cab237bSDimitry Andric case OT_Operand2:
7152cab237bSDimitry Andric MIB.add(MI->getOperand(2));
7162cab237bSDimitry Andric break;
7172cab237bSDimitry Andric case OT_Operands02: {
7182cab237bSDimitry Andric MIB.add(MI->getOperand(0));
7192cab237bSDimitry Andric MIB.add(MI->getOperand(2));
7202cab237bSDimitry Andric break;
7212cab237bSDimitry Andric }
7222cab237bSDimitry Andric case OT_OperandsXOR: {
7232cab237bSDimitry Andric if (MI->getOperand(0).getReg() == MI->getOperand(2).getReg()) {
7242cab237bSDimitry Andric MIB.add(MI->getOperand(0));
7252cab237bSDimitry Andric MIB.add(MI->getOperand(1));
7262cab237bSDimitry Andric MIB.add(MI->getOperand(2));
7272cab237bSDimitry Andric } else {
7282cab237bSDimitry Andric MIB.add(MI->getOperand(0));
7292cab237bSDimitry Andric MIB.add(MI->getOperand(2));
7302cab237bSDimitry Andric MIB.add(MI->getOperand(1));
7312cab237bSDimitry Andric }
7322cab237bSDimitry Andric break;
7332cab237bSDimitry Andric }
734*b5893f02SDimitry Andric case OT_OperandsMovep:
7354ba319b5SDimitry Andric case OT_OperandsLwp:
7364ba319b5SDimitry Andric case OT_OperandsSwp: {
7374ba319b5SDimitry Andric if (ConsecutiveForward) {
7384ba319b5SDimitry Andric MIB.add(MI->getOperand(0));
7394ba319b5SDimitry Andric MIB.add(MI2->getOperand(0));
7404ba319b5SDimitry Andric MIB.add(MI->getOperand(1));
741*b5893f02SDimitry Andric if (OpTransfer == OT_OperandsMovep)
742*b5893f02SDimitry Andric MIB.add(MI2->getOperand(1));
743*b5893f02SDimitry Andric else
7444ba319b5SDimitry Andric MIB.add(MI->getOperand(2));
7454ba319b5SDimitry Andric } else { // consecutive backward
7464ba319b5SDimitry Andric MIB.add(MI2->getOperand(0));
7474ba319b5SDimitry Andric MIB.add(MI->getOperand(0));
7484ba319b5SDimitry Andric MIB.add(MI2->getOperand(1));
749*b5893f02SDimitry Andric if (OpTransfer == OT_OperandsMovep)
750*b5893f02SDimitry Andric MIB.add(MI->getOperand(1));
751*b5893f02SDimitry Andric else
7524ba319b5SDimitry Andric MIB.add(MI2->getOperand(2));
7534ba319b5SDimitry Andric }
7544ba319b5SDimitry Andric
7554ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "and converting 32-bit: " << *MI2
7564ba319b5SDimitry Andric << " to: " << *MIB);
7574ba319b5SDimitry Andric
7584ba319b5SDimitry Andric MBB.erase_instr(MI);
7594ba319b5SDimitry Andric MBB.erase_instr(MI2);
7604ba319b5SDimitry Andric return true;
7614ba319b5SDimitry Andric }
7622cab237bSDimitry Andric default:
7632cab237bSDimitry Andric llvm_unreachable("Unknown operand transfer!");
7642cab237bSDimitry Andric }
7652cab237bSDimitry Andric
7662cab237bSDimitry Andric // Transfer MI flags.
7672cab237bSDimitry Andric MIB.setMIFlags(MI->getFlags());
7682cab237bSDimitry Andric
7694ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << " to 16-bit: " << *MIB);
7702cab237bSDimitry Andric MBB.erase_instr(MI);
7712cab237bSDimitry Andric return true;
7722cab237bSDimitry Andric }
7732cab237bSDimitry Andric return false;
774f37b6182SDimitry Andric }
775f37b6182SDimitry Andric
runOnMachineFunction(MachineFunction & MF)776f37b6182SDimitry Andric bool MicroMipsSizeReduce::runOnMachineFunction(MachineFunction &MF) {
777f37b6182SDimitry Andric
778f37b6182SDimitry Andric Subtarget = &static_cast<const MipsSubtarget &>(MF.getSubtarget());
779f37b6182SDimitry Andric
7802cab237bSDimitry Andric // TODO: Add support for the subtarget microMIPS32R6.
7812cab237bSDimitry Andric if (!Subtarget->inMicroMipsMode() || !Subtarget->hasMips32r2() ||
7822cab237bSDimitry Andric Subtarget->hasMips32r6())
783f37b6182SDimitry Andric return false;
784f37b6182SDimitry Andric
785f37b6182SDimitry Andric MipsII = static_cast<const MipsInstrInfo *>(Subtarget->getInstrInfo());
786f37b6182SDimitry Andric
787f37b6182SDimitry Andric bool Modified = false;
788f37b6182SDimitry Andric MachineFunction::iterator I = MF.begin(), E = MF.end();
789f37b6182SDimitry Andric
790f37b6182SDimitry Andric for (; I != E; ++I)
791f37b6182SDimitry Andric Modified |= ReduceMBB(*I);
792f37b6182SDimitry Andric return Modified;
793f37b6182SDimitry Andric }
794f37b6182SDimitry Andric
795f37b6182SDimitry Andric /// Returns an instance of the MicroMips size reduction pass.
createMicroMipsSizeReducePass()7964ba319b5SDimitry Andric FunctionPass *llvm::createMicroMipsSizeReducePass() {
797f37b6182SDimitry Andric return new MicroMipsSizeReduce();
798f37b6182SDimitry Andric }
799