10b57cec5SDimitry Andric //===-- Thumb2SizeReduction.cpp - Thumb2 code size reduction pass -*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "ARM.h"
100b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h"
110b57cec5SDimitry Andric #include "ARMSubtarget.h"
120b57cec5SDimitry Andric #include "MCTargetDesc/ARMBaseInfo.h"
130b57cec5SDimitry Andric #include "Thumb2InstrInfo.h"
140b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
150b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
180b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
190b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
200b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
280b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h"
290b57cec5SDimitry Andric #include "llvm/IR/Function.h"
3081ad6265SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
310b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
330b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
340b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
350b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
360b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
370b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
380b57cec5SDimitry Andric #include <algorithm>
390b57cec5SDimitry Andric #include <cassert>
400b57cec5SDimitry Andric #include <cstdint>
410b57cec5SDimitry Andric #include <functional>
420b57cec5SDimitry Andric #include <iterator>
430b57cec5SDimitry Andric #include <utility>
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric using namespace llvm;
460b57cec5SDimitry Andric 
47e8d8bef9SDimitry Andric #define DEBUG_TYPE "thumb2-reduce-size"
480b57cec5SDimitry Andric #define THUMB2_SIZE_REDUCE_NAME "Thumb2 instruction size reduce pass"
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric STATISTIC(NumNarrows,  "Number of 32-bit instrs reduced to 16-bit ones");
510b57cec5SDimitry Andric STATISTIC(Num2Addrs,   "Number of 32-bit instrs reduced to 2addr 16-bit ones");
520b57cec5SDimitry Andric STATISTIC(NumLdSts,    "Number of 32-bit load / store reduced to 16-bit ones");
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric static cl::opt<int> ReduceLimit("t2-reduce-limit",
550b57cec5SDimitry Andric                                 cl::init(-1), cl::Hidden);
560b57cec5SDimitry Andric static cl::opt<int> ReduceLimit2Addr("t2-reduce-limit2",
570b57cec5SDimitry Andric                                      cl::init(-1), cl::Hidden);
580b57cec5SDimitry Andric static cl::opt<int> ReduceLimitLdSt("t2-reduce-limit3",
590b57cec5SDimitry Andric                                      cl::init(-1), cl::Hidden);
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric namespace {
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   /// ReduceTable - A static table with information on mapping from wide
640b57cec5SDimitry Andric   /// opcodes to narrow
650b57cec5SDimitry Andric   struct ReduceEntry {
660b57cec5SDimitry Andric     uint16_t WideOpc;      // Wide opcode
670b57cec5SDimitry Andric     uint16_t NarrowOpc1;   // Narrow opcode to transform to
680b57cec5SDimitry Andric     uint16_t NarrowOpc2;   // Narrow opcode when it's two-address
690b57cec5SDimitry Andric     uint8_t  Imm1Limit;    // Limit of immediate field (bits)
700b57cec5SDimitry Andric     uint8_t  Imm2Limit;    // Limit of immediate field when it's two-address
710b57cec5SDimitry Andric     unsigned LowRegs1 : 1; // Only possible if low-registers are used
720b57cec5SDimitry Andric     unsigned LowRegs2 : 1; // Only possible if low-registers are used (2addr)
730b57cec5SDimitry Andric     unsigned PredCC1  : 2; // 0 - If predicated, cc is on and vice versa.
740b57cec5SDimitry Andric                            // 1 - No cc field.
750b57cec5SDimitry Andric                            // 2 - Always set CPSR.
760b57cec5SDimitry Andric     unsigned PredCC2  : 2;
770b57cec5SDimitry Andric     unsigned PartFlag : 1; // 16-bit instruction does partial flag update
780b57cec5SDimitry Andric     unsigned Special  : 1; // Needs to be dealt with specially
790b57cec5SDimitry Andric     unsigned AvoidMovs: 1; // Avoid movs with shifter operand (for Swift)
800b57cec5SDimitry Andric   };
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   static const ReduceEntry ReduceTable[] = {
830b57cec5SDimitry Andric   // Wide,        Narrow1,      Narrow2,     imm1,imm2, lo1, lo2, P/C,PF,S,AM
840b57cec5SDimitry Andric   { ARM::t2ADCrr, 0,            ARM::tADC,     0,   0,   0,   1,  0,0, 0,0,0 },
850b57cec5SDimitry Andric   { ARM::t2ADDri, ARM::tADDi3,  ARM::tADDi8,   3,   8,   1,   1,  0,0, 0,1,0 },
860b57cec5SDimitry Andric   { ARM::t2ADDrr, ARM::tADDrr,  ARM::tADDhirr, 0,   0,   1,   0,  0,1, 0,0,0 },
870b57cec5SDimitry Andric   { ARM::t2ADDSri,ARM::tADDi3,  ARM::tADDi8,   3,   8,   1,   1,  2,2, 0,1,0 },
880b57cec5SDimitry Andric   { ARM::t2ADDSrr,ARM::tADDrr,  0,             0,   0,   1,   0,  2,0, 0,1,0 },
890b57cec5SDimitry Andric   { ARM::t2ANDrr, 0,            ARM::tAND,     0,   0,   0,   1,  0,0, 1,0,0 },
900b57cec5SDimitry Andric   { ARM::t2ASRri, ARM::tASRri,  0,             5,   0,   1,   0,  0,0, 1,0,1 },
910b57cec5SDimitry Andric   { ARM::t2ASRrr, 0,            ARM::tASRrr,   0,   0,   0,   1,  0,0, 1,0,1 },
920b57cec5SDimitry Andric   { ARM::t2BICrr, 0,            ARM::tBIC,     0,   0,   0,   1,  0,0, 1,0,0 },
930b57cec5SDimitry Andric   //FIXME: Disable CMN, as CCodes are backwards from compare expectations
940b57cec5SDimitry Andric   //{ ARM::t2CMNrr, ARM::tCMN,  0,             0,   0,   1,   0,  2,0, 0,0,0 },
950b57cec5SDimitry Andric   { ARM::t2CMNzrr, ARM::tCMNz,  0,             0,   0,   1,   0,  2,0, 0,0,0 },
960b57cec5SDimitry Andric   { ARM::t2CMPri, ARM::tCMPi8,  0,             8,   0,   1,   0,  2,0, 0,0,0 },
970b57cec5SDimitry Andric   { ARM::t2CMPrr, ARM::tCMPhir, 0,             0,   0,   0,   0,  2,0, 0,1,0 },
980b57cec5SDimitry Andric   { ARM::t2EORrr, 0,            ARM::tEOR,     0,   0,   0,   1,  0,0, 1,0,0 },
990b57cec5SDimitry Andric   // FIXME: adr.n immediate offset must be multiple of 4.
1000b57cec5SDimitry Andric   //{ ARM::t2LEApcrelJT,ARM::tLEApcrelJT, 0,   0,   0,   1,   0,  1,0, 0,0,0 },
1010b57cec5SDimitry Andric   { ARM::t2LSLri, ARM::tLSLri,  0,             5,   0,   1,   0,  0,0, 1,0,1 },
1020b57cec5SDimitry Andric   { ARM::t2LSLrr, 0,            ARM::tLSLrr,   0,   0,   0,   1,  0,0, 1,0,1 },
1030b57cec5SDimitry Andric   { ARM::t2LSRri, ARM::tLSRri,  0,             5,   0,   1,   0,  0,0, 1,0,1 },
1040b57cec5SDimitry Andric   { ARM::t2LSRrr, 0,            ARM::tLSRrr,   0,   0,   0,   1,  0,0, 1,0,1 },
1050b57cec5SDimitry Andric   { ARM::t2MOVi,  ARM::tMOVi8,  0,             8,   0,   1,   0,  0,0, 1,0,0 },
1060b57cec5SDimitry Andric   { ARM::t2MOVi16,ARM::tMOVi8,  0,             8,   0,   1,   0,  0,0, 1,1,0 },
1070b57cec5SDimitry Andric   // FIXME: Do we need the 16-bit 'S' variant?
1080b57cec5SDimitry Andric   { ARM::t2MOVr,ARM::tMOVr,     0,             0,   0,   0,   0,  1,0, 0,0,0 },
1090b57cec5SDimitry Andric   { ARM::t2MUL,   0,            ARM::tMUL,     0,   0,   0,   1,  0,0, 1,0,0 },
1100b57cec5SDimitry Andric   { ARM::t2MVNr,  ARM::tMVN,    0,             0,   0,   1,   0,  0,0, 0,0,0 },
1110b57cec5SDimitry Andric   { ARM::t2ORRrr, 0,            ARM::tORR,     0,   0,   0,   1,  0,0, 1,0,0 },
1120b57cec5SDimitry Andric   { ARM::t2REV,   ARM::tREV,    0,             0,   0,   1,   0,  1,0, 0,0,0 },
1130b57cec5SDimitry Andric   { ARM::t2REV16, ARM::tREV16,  0,             0,   0,   1,   0,  1,0, 0,0,0 },
1140b57cec5SDimitry Andric   { ARM::t2REVSH, ARM::tREVSH,  0,             0,   0,   1,   0,  1,0, 0,0,0 },
1150b57cec5SDimitry Andric   { ARM::t2RORrr, 0,            ARM::tROR,     0,   0,   0,   1,  0,0, 1,0,0 },
1160b57cec5SDimitry Andric   { ARM::t2RSBri, ARM::tRSB,    0,             0,   0,   1,   0,  0,0, 0,1,0 },
1170b57cec5SDimitry Andric   { ARM::t2RSBSri,ARM::tRSB,    0,             0,   0,   1,   0,  2,0, 0,1,0 },
1180b57cec5SDimitry Andric   { ARM::t2SBCrr, 0,            ARM::tSBC,     0,   0,   0,   1,  0,0, 0,0,0 },
1190b57cec5SDimitry Andric   { ARM::t2SUBri, ARM::tSUBi3,  ARM::tSUBi8,   3,   8,   1,   1,  0,0, 0,0,0 },
1200b57cec5SDimitry Andric   { ARM::t2SUBrr, ARM::tSUBrr,  0,             0,   0,   1,   0,  0,0, 0,0,0 },
1210b57cec5SDimitry Andric   { ARM::t2SUBSri,ARM::tSUBi3,  ARM::tSUBi8,   3,   8,   1,   1,  2,2, 0,0,0 },
1220b57cec5SDimitry Andric   { ARM::t2SUBSrr,ARM::tSUBrr,  0,             0,   0,   1,   0,  2,0, 0,0,0 },
1230b57cec5SDimitry Andric   { ARM::t2SXTB,  ARM::tSXTB,   0,             0,   0,   1,   0,  1,0, 0,1,0 },
1240b57cec5SDimitry Andric   { ARM::t2SXTH,  ARM::tSXTH,   0,             0,   0,   1,   0,  1,0, 0,1,0 },
1250b57cec5SDimitry Andric   { ARM::t2TEQrr, ARM::tEOR,    0,             0,   0,   1,   0,  2,0, 0,1,0 },
1260b57cec5SDimitry Andric   { ARM::t2TSTrr, ARM::tTST,    0,             0,   0,   1,   0,  2,0, 0,0,0 },
1270b57cec5SDimitry Andric   { ARM::t2UXTB,  ARM::tUXTB,   0,             0,   0,   1,   0,  1,0, 0,1,0 },
1280b57cec5SDimitry Andric   { ARM::t2UXTH,  ARM::tUXTH,   0,             0,   0,   1,   0,  1,0, 0,1,0 },
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   // FIXME: Clean this up after splitting each Thumb load / store opcode
1310b57cec5SDimitry Andric   // into multiple ones.
1320b57cec5SDimitry Andric   { ARM::t2LDRi12,ARM::tLDRi,   ARM::tLDRspi,  5,   8,   1,   0,  0,0, 0,1,0 },
1330b57cec5SDimitry Andric   { ARM::t2LDRs,  ARM::tLDRr,   0,             0,   0,   1,   0,  0,0, 0,1,0 },
1340b57cec5SDimitry Andric   { ARM::t2LDRBi12,ARM::tLDRBi, 0,             5,   0,   1,   0,  0,0, 0,1,0 },
1350b57cec5SDimitry Andric   { ARM::t2LDRBs, ARM::tLDRBr,  0,             0,   0,   1,   0,  0,0, 0,1,0 },
1360b57cec5SDimitry Andric   { ARM::t2LDRHi12,ARM::tLDRHi, 0,             5,   0,   1,   0,  0,0, 0,1,0 },
1370b57cec5SDimitry Andric   { ARM::t2LDRHs, ARM::tLDRHr,  0,             0,   0,   1,   0,  0,0, 0,1,0 },
1380b57cec5SDimitry Andric   { ARM::t2LDRSBs,ARM::tLDRSB,  0,             0,   0,   1,   0,  0,0, 0,1,0 },
1390b57cec5SDimitry Andric   { ARM::t2LDRSHs,ARM::tLDRSH,  0,             0,   0,   1,   0,  0,0, 0,1,0 },
1400b57cec5SDimitry Andric   { ARM::t2LDR_POST,ARM::tLDMIA_UPD,0,         0,   0,   1,   0,  0,0, 0,1,0 },
1410b57cec5SDimitry Andric   { ARM::t2STRi12,ARM::tSTRi,   ARM::tSTRspi,  5,   8,   1,   0,  0,0, 0,1,0 },
1420b57cec5SDimitry Andric   { ARM::t2STRs,  ARM::tSTRr,   0,             0,   0,   1,   0,  0,0, 0,1,0 },
1430b57cec5SDimitry Andric   { ARM::t2STRBi12,ARM::tSTRBi, 0,             5,   0,   1,   0,  0,0, 0,1,0 },
1440b57cec5SDimitry Andric   { ARM::t2STRBs, ARM::tSTRBr,  0,             0,   0,   1,   0,  0,0, 0,1,0 },
1450b57cec5SDimitry Andric   { ARM::t2STRHi12,ARM::tSTRHi, 0,             5,   0,   1,   0,  0,0, 0,1,0 },
1460b57cec5SDimitry Andric   { ARM::t2STRHs, ARM::tSTRHr,  0,             0,   0,   1,   0,  0,0, 0,1,0 },
1470b57cec5SDimitry Andric   { ARM::t2STR_POST,ARM::tSTMIA_UPD,0,         0,   0,   1,   0,  0,0, 0,1,0 },
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   { ARM::t2LDMIA, ARM::tLDMIA,  0,             0,   0,   1,   1,  1,1, 0,1,0 },
1500b57cec5SDimitry Andric   { ARM::t2LDMIA_RET,0,         ARM::tPOP_RET, 0,   0,   1,   1,  1,1, 0,1,0 },
1510b57cec5SDimitry Andric   { ARM::t2LDMIA_UPD,ARM::tLDMIA_UPD,ARM::tPOP,0,   0,   1,   1,  1,1, 0,1,0 },
1520b57cec5SDimitry Andric   // ARM::t2STMIA (with no basereg writeback) has no Thumb1 equivalent.
1530b57cec5SDimitry Andric   // tSTMIA_UPD is a change in semantics which can only be used if the base
1540b57cec5SDimitry Andric   // register is killed. This difference is correctly handled elsewhere.
1550b57cec5SDimitry Andric   { ARM::t2STMIA, ARM::tSTMIA_UPD, 0,          0,   0,   1,   1,  1,1, 0,1,0 },
1560b57cec5SDimitry Andric   { ARM::t2STMIA_UPD,ARM::tSTMIA_UPD, 0,       0,   0,   1,   1,  1,1, 0,1,0 },
1570b57cec5SDimitry Andric   { ARM::t2STMDB_UPD, 0,        ARM::tPUSH,    0,   0,   1,   1,  1,1, 0,1,0 }
1580b57cec5SDimitry Andric   };
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   class Thumb2SizeReduce : public MachineFunctionPass {
1610b57cec5SDimitry Andric   public:
1620b57cec5SDimitry Andric     static char ID;
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric     const Thumb2InstrInfo *TII;
1650b57cec5SDimitry Andric     const ARMSubtarget *STI;
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric     Thumb2SizeReduce(std::function<bool(const Function &)> Ftor = nullptr);
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric     bool runOnMachineFunction(MachineFunction &MF) override;
1700b57cec5SDimitry Andric 
getRequiredProperties() const1710b57cec5SDimitry Andric     MachineFunctionProperties getRequiredProperties() const override {
1720b57cec5SDimitry Andric       return MachineFunctionProperties().set(
1730b57cec5SDimitry Andric           MachineFunctionProperties::Property::NoVRegs);
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric 
getPassName() const1760b57cec5SDimitry Andric     StringRef getPassName() const override {
1770b57cec5SDimitry Andric       return THUMB2_SIZE_REDUCE_NAME;
1780b57cec5SDimitry Andric     }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   private:
1810b57cec5SDimitry Andric     /// ReduceOpcodeMap - Maps wide opcode to index of entry in ReduceTable.
1820b57cec5SDimitry Andric     DenseMap<unsigned, unsigned> ReduceOpcodeMap;
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric     bool canAddPseudoFlagDep(MachineInstr *Use, bool IsSelfLoop);
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric     bool VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry,
1870b57cec5SDimitry Andric                          bool is2Addr, ARMCC::CondCodes Pred,
1880b57cec5SDimitry Andric                          bool LiveCPSR, bool &HasCC, bool &CCDead);
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric     bool ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
1910b57cec5SDimitry Andric                          const ReduceEntry &Entry);
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric     bool ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,
1940b57cec5SDimitry Andric                        const ReduceEntry &Entry, bool LiveCPSR, bool IsSelfLoop);
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric     /// ReduceTo2Addr - Reduce a 32-bit instruction to a 16-bit two-address
1970b57cec5SDimitry Andric     /// instruction.
1980b57cec5SDimitry Andric     bool ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,
1990b57cec5SDimitry Andric                        const ReduceEntry &Entry, bool LiveCPSR,
2000b57cec5SDimitry Andric                        bool IsSelfLoop);
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric     /// ReduceToNarrow - Reduce a 32-bit instruction to a 16-bit
2030b57cec5SDimitry Andric     /// non-two-address instruction.
2040b57cec5SDimitry Andric     bool ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,
2050b57cec5SDimitry Andric                         const ReduceEntry &Entry, bool LiveCPSR,
2060b57cec5SDimitry Andric                         bool IsSelfLoop);
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric     /// ReduceMI - Attempt to reduce MI, return true on success.
20981ad6265SDimitry Andric     bool ReduceMI(MachineBasicBlock &MBB, MachineInstr *MI, bool LiveCPSR,
21081ad6265SDimitry Andric                   bool IsSelfLoop, bool SkipPrologueEpilogue);
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric     /// ReduceMBB - Reduce width of instructions in the specified basic block.
21381ad6265SDimitry Andric     bool ReduceMBB(MachineBasicBlock &MBB, bool SkipPrologueEpilogue);
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     bool OptimizeSize;
2160b57cec5SDimitry Andric     bool MinimizeSize;
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric     // Last instruction to define CPSR in the current block.
2190b57cec5SDimitry Andric     MachineInstr *CPSRDef;
2200b57cec5SDimitry Andric     // Was CPSR last defined by a high latency instruction?
2210b57cec5SDimitry Andric     // When CPSRDef is null, this refers to CPSR defs in predecessors.
2220b57cec5SDimitry Andric     bool HighLatencyCPSR;
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric     struct MBBInfo {
2250b57cec5SDimitry Andric       // The flags leaving this block have high latency.
2260b57cec5SDimitry Andric       bool HighLatencyCPSR = false;
2270b57cec5SDimitry Andric       // Has this block been visited yet?
2280b57cec5SDimitry Andric       bool Visited = false;
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric       MBBInfo() = default;
2310b57cec5SDimitry Andric     };
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric     SmallVector<MBBInfo, 8> BlockInfo;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric     std::function<bool(const Function &)> PredicateFtor;
2360b57cec5SDimitry Andric   };
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   char Thumb2SizeReduce::ID = 0;
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric } // end anonymous namespace
2410b57cec5SDimitry Andric 
INITIALIZE_PASS(Thumb2SizeReduce,DEBUG_TYPE,THUMB2_SIZE_REDUCE_NAME,false,false)2420b57cec5SDimitry Andric INITIALIZE_PASS(Thumb2SizeReduce, DEBUG_TYPE, THUMB2_SIZE_REDUCE_NAME, false,
2430b57cec5SDimitry Andric                 false)
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric Thumb2SizeReduce::Thumb2SizeReduce(std::function<bool(const Function &)> Ftor)
2460b57cec5SDimitry Andric     : MachineFunctionPass(ID), PredicateFtor(std::move(Ftor)) {
2470b57cec5SDimitry Andric   OptimizeSize = MinimizeSize = false;
248bdd1243dSDimitry Andric   for (unsigned i = 0, e = std::size(ReduceTable); i != e; ++i) {
2490b57cec5SDimitry Andric     unsigned FromOpc = ReduceTable[i].WideOpc;
2500b57cec5SDimitry Andric     if (!ReduceOpcodeMap.insert(std::make_pair(FromOpc, i)).second)
2510b57cec5SDimitry Andric       llvm_unreachable("Duplicated entries?");
2520b57cec5SDimitry Andric   }
2530b57cec5SDimitry Andric }
2540b57cec5SDimitry Andric 
HasImplicitCPSRDef(const MCInstrDesc & MCID)2550b57cec5SDimitry Andric static bool HasImplicitCPSRDef(const MCInstrDesc &MCID) {
256bdd1243dSDimitry Andric   return is_contained(MCID.implicit_defs(), ARM::CPSR);
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric // Check for a likely high-latency flag def.
isHighLatencyCPSR(MachineInstr * Def)2600b57cec5SDimitry Andric static bool isHighLatencyCPSR(MachineInstr *Def) {
2610b57cec5SDimitry Andric   switch(Def->getOpcode()) {
2620b57cec5SDimitry Andric   case ARM::FMSTAT:
2630b57cec5SDimitry Andric   case ARM::tMUL:
2640b57cec5SDimitry Andric     return true;
2650b57cec5SDimitry Andric   }
2660b57cec5SDimitry Andric   return false;
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric /// canAddPseudoFlagDep - For A9 (and other out-of-order) implementations,
2700b57cec5SDimitry Andric /// the 's' 16-bit instruction partially update CPSR. Abort the
2710b57cec5SDimitry Andric /// transformation to avoid adding false dependency on last CPSR setting
2720b57cec5SDimitry Andric /// instruction which hurts the ability for out-of-order execution engine
2730b57cec5SDimitry Andric /// to do register renaming magic.
2740b57cec5SDimitry Andric /// This function checks if there is a read-of-write dependency between the
2750b57cec5SDimitry Andric /// last instruction that defines the CPSR and the current instruction. If there
2760b57cec5SDimitry Andric /// is, then there is no harm done since the instruction cannot be retired
2770b57cec5SDimitry Andric /// before the CPSR setting instruction anyway.
2780b57cec5SDimitry Andric /// Note, we are not doing full dependency analysis here for the sake of compile
2790b57cec5SDimitry Andric /// time. We're not looking for cases like:
2800b57cec5SDimitry Andric /// r0 = muls ...
2810b57cec5SDimitry Andric /// r1 = add.w r0, ...
2820b57cec5SDimitry Andric /// ...
2830b57cec5SDimitry Andric ///    = mul.w r1
2840b57cec5SDimitry Andric /// In this case it would have been ok to narrow the mul.w to muls since there
2850b57cec5SDimitry Andric /// are indirect RAW dependency between the muls and the mul.w
2860b57cec5SDimitry Andric bool
canAddPseudoFlagDep(MachineInstr * Use,bool FirstInSelfLoop)2870b57cec5SDimitry Andric Thumb2SizeReduce::canAddPseudoFlagDep(MachineInstr *Use, bool FirstInSelfLoop) {
2880b57cec5SDimitry Andric   // Disable the check for -Oz (aka OptimizeForSizeHarder).
2890b57cec5SDimitry Andric   if (MinimizeSize || !STI->avoidCPSRPartialUpdate())
2900b57cec5SDimitry Andric     return false;
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   if (!CPSRDef)
2930b57cec5SDimitry Andric     // If this BB loops back to itself, conservatively avoid narrowing the
2940b57cec5SDimitry Andric     // first instruction that does partial flag update.
2950b57cec5SDimitry Andric     return HighLatencyCPSR || FirstInSelfLoop;
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric   SmallSet<unsigned, 2> Defs;
2980b57cec5SDimitry Andric   for (const MachineOperand &MO : CPSRDef->operands()) {
2990b57cec5SDimitry Andric     if (!MO.isReg() || MO.isUndef() || MO.isUse())
3000b57cec5SDimitry Andric       continue;
3018bcb0991SDimitry Andric     Register Reg = MO.getReg();
3020b57cec5SDimitry Andric     if (Reg == 0 || Reg == ARM::CPSR)
3030b57cec5SDimitry Andric       continue;
3040b57cec5SDimitry Andric     Defs.insert(Reg);
3050b57cec5SDimitry Andric   }
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric   for (const MachineOperand &MO : Use->operands()) {
3080b57cec5SDimitry Andric     if (!MO.isReg() || MO.isUndef() || MO.isDef())
3090b57cec5SDimitry Andric       continue;
3108bcb0991SDimitry Andric     Register Reg = MO.getReg();
3110b57cec5SDimitry Andric     if (Defs.count(Reg))
3120b57cec5SDimitry Andric       return false;
3130b57cec5SDimitry Andric   }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   // If the current CPSR has high latency, try to avoid the false dependency.
3160b57cec5SDimitry Andric   if (HighLatencyCPSR)
3170b57cec5SDimitry Andric     return true;
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   // tMOVi8 usually doesn't start long dependency chains, and there are a lot
3200b57cec5SDimitry Andric   // of them, so always shrink them when CPSR doesn't have high latency.
3210b57cec5SDimitry Andric   if (Use->getOpcode() == ARM::t2MOVi ||
3220b57cec5SDimitry Andric       Use->getOpcode() == ARM::t2MOVi16)
3230b57cec5SDimitry Andric     return false;
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   // No read-after-write dependency. The narrowing will add false dependency.
3260b57cec5SDimitry Andric   return true;
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric bool
VerifyPredAndCC(MachineInstr * MI,const ReduceEntry & Entry,bool is2Addr,ARMCC::CondCodes Pred,bool LiveCPSR,bool & HasCC,bool & CCDead)3300b57cec5SDimitry Andric Thumb2SizeReduce::VerifyPredAndCC(MachineInstr *MI, const ReduceEntry &Entry,
3310b57cec5SDimitry Andric                                   bool is2Addr, ARMCC::CondCodes Pred,
3320b57cec5SDimitry Andric                                   bool LiveCPSR, bool &HasCC, bool &CCDead) {
3330b57cec5SDimitry Andric   if ((is2Addr  && Entry.PredCC2 == 0) ||
3340b57cec5SDimitry Andric       (!is2Addr && Entry.PredCC1 == 0)) {
3350b57cec5SDimitry Andric     if (Pred == ARMCC::AL) {
3360b57cec5SDimitry Andric       // Not predicated, must set CPSR.
3370b57cec5SDimitry Andric       if (!HasCC) {
3380b57cec5SDimitry Andric         // Original instruction was not setting CPSR, but CPSR is not
3390b57cec5SDimitry Andric         // currently live anyway. It's ok to set it. The CPSR def is
3400b57cec5SDimitry Andric         // dead though.
3410b57cec5SDimitry Andric         if (!LiveCPSR) {
3420b57cec5SDimitry Andric           HasCC = true;
3430b57cec5SDimitry Andric           CCDead = true;
3440b57cec5SDimitry Andric           return true;
3450b57cec5SDimitry Andric         }
3460b57cec5SDimitry Andric         return false;
3470b57cec5SDimitry Andric       }
3480b57cec5SDimitry Andric     } else {
3490b57cec5SDimitry Andric       // Predicated, must not set CPSR.
3500b57cec5SDimitry Andric       if (HasCC)
3510b57cec5SDimitry Andric         return false;
3520b57cec5SDimitry Andric     }
3530b57cec5SDimitry Andric   } else if ((is2Addr  && Entry.PredCC2 == 2) ||
3540b57cec5SDimitry Andric              (!is2Addr && Entry.PredCC1 == 2)) {
3550b57cec5SDimitry Andric     /// Old opcode has an optional def of CPSR.
3560b57cec5SDimitry Andric     if (HasCC)
3570b57cec5SDimitry Andric       return true;
3580b57cec5SDimitry Andric     // If old opcode does not implicitly define CPSR, then it's not ok since
3590b57cec5SDimitry Andric     // these new opcodes' CPSR def is not meant to be thrown away. e.g. CMP.
3600b57cec5SDimitry Andric     if (!HasImplicitCPSRDef(MI->getDesc()))
3610b57cec5SDimitry Andric       return false;
3620b57cec5SDimitry Andric     HasCC = true;
3630b57cec5SDimitry Andric   } else {
3640b57cec5SDimitry Andric     // 16-bit instruction does not set CPSR.
3650b57cec5SDimitry Andric     if (HasCC)
3660b57cec5SDimitry Andric       return false;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   return true;
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric 
VerifyLowRegs(MachineInstr * MI)3720b57cec5SDimitry Andric static bool VerifyLowRegs(MachineInstr *MI) {
3730b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
3740b57cec5SDimitry Andric   bool isPCOk = (Opc == ARM::t2LDMIA_RET || Opc == ARM::t2LDMIA_UPD);
3750b57cec5SDimitry Andric   bool isLROk = (Opc == ARM::t2STMDB_UPD);
3760b57cec5SDimitry Andric   bool isSPOk = isPCOk || isLROk;
3770b57cec5SDimitry Andric   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
3780b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(i);
3790b57cec5SDimitry Andric     if (!MO.isReg() || MO.isImplicit())
3800b57cec5SDimitry Andric       continue;
3818bcb0991SDimitry Andric     Register Reg = MO.getReg();
3820b57cec5SDimitry Andric     if (Reg == 0 || Reg == ARM::CPSR)
3830b57cec5SDimitry Andric       continue;
3840b57cec5SDimitry Andric     if (isPCOk && Reg == ARM::PC)
3850b57cec5SDimitry Andric       continue;
3860b57cec5SDimitry Andric     if (isLROk && Reg == ARM::LR)
3870b57cec5SDimitry Andric       continue;
3880b57cec5SDimitry Andric     if (Reg == ARM::SP) {
3890b57cec5SDimitry Andric       if (isSPOk)
3900b57cec5SDimitry Andric         continue;
3910b57cec5SDimitry Andric       if (i == 1 && (Opc == ARM::t2LDRi12 || Opc == ARM::t2STRi12))
3920b57cec5SDimitry Andric         // Special case for these ldr / str with sp as base register.
3930b57cec5SDimitry Andric         continue;
3940b57cec5SDimitry Andric     }
3950b57cec5SDimitry Andric     if (!isARMLowRegister(Reg))
3960b57cec5SDimitry Andric       return false;
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric   return true;
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric bool
ReduceLoadStore(MachineBasicBlock & MBB,MachineInstr * MI,const ReduceEntry & Entry)4020b57cec5SDimitry Andric Thumb2SizeReduce::ReduceLoadStore(MachineBasicBlock &MBB, MachineInstr *MI,
4030b57cec5SDimitry Andric                                   const ReduceEntry &Entry) {
4040b57cec5SDimitry Andric   if (ReduceLimitLdSt != -1 && ((int)NumLdSts >= ReduceLimitLdSt))
4050b57cec5SDimitry Andric     return false;
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   unsigned Scale = 1;
4080b57cec5SDimitry Andric   bool HasImmOffset = false;
4090b57cec5SDimitry Andric   bool HasShift = false;
4100b57cec5SDimitry Andric   bool HasOffReg = true;
4110b57cec5SDimitry Andric   bool isLdStMul = false;
4120b57cec5SDimitry Andric   unsigned Opc = Entry.NarrowOpc1;
4130b57cec5SDimitry Andric   unsigned OpNum = 3; // First 'rest' of operands.
4140b57cec5SDimitry Andric   uint8_t  ImmLimit = Entry.Imm1Limit;
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   switch (Entry.WideOpc) {
4170b57cec5SDimitry Andric   default:
4180b57cec5SDimitry Andric     llvm_unreachable("Unexpected Thumb2 load / store opcode!");
4190b57cec5SDimitry Andric   case ARM::t2LDRi12:
4200b57cec5SDimitry Andric   case ARM::t2STRi12:
4210b57cec5SDimitry Andric     if (MI->getOperand(1).getReg() == ARM::SP) {
4220b57cec5SDimitry Andric       Opc = Entry.NarrowOpc2;
4230b57cec5SDimitry Andric       ImmLimit = Entry.Imm2Limit;
4240b57cec5SDimitry Andric     }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric     Scale = 4;
4270b57cec5SDimitry Andric     HasImmOffset = true;
4280b57cec5SDimitry Andric     HasOffReg = false;
4290b57cec5SDimitry Andric     break;
4300b57cec5SDimitry Andric   case ARM::t2LDRBi12:
4310b57cec5SDimitry Andric   case ARM::t2STRBi12:
4320b57cec5SDimitry Andric     HasImmOffset = true;
4330b57cec5SDimitry Andric     HasOffReg = false;
4340b57cec5SDimitry Andric     break;
4350b57cec5SDimitry Andric   case ARM::t2LDRHi12:
4360b57cec5SDimitry Andric   case ARM::t2STRHi12:
4370b57cec5SDimitry Andric     Scale = 2;
4380b57cec5SDimitry Andric     HasImmOffset = true;
4390b57cec5SDimitry Andric     HasOffReg = false;
4400b57cec5SDimitry Andric     break;
4410b57cec5SDimitry Andric   case ARM::t2LDRs:
4420b57cec5SDimitry Andric   case ARM::t2LDRBs:
4430b57cec5SDimitry Andric   case ARM::t2LDRHs:
4440b57cec5SDimitry Andric   case ARM::t2LDRSBs:
4450b57cec5SDimitry Andric   case ARM::t2LDRSHs:
4460b57cec5SDimitry Andric   case ARM::t2STRs:
4470b57cec5SDimitry Andric   case ARM::t2STRBs:
4480b57cec5SDimitry Andric   case ARM::t2STRHs:
4490b57cec5SDimitry Andric     HasShift = true;
4500b57cec5SDimitry Andric     OpNum = 4;
4510b57cec5SDimitry Andric     break;
4520b57cec5SDimitry Andric   case ARM::t2LDR_POST:
4530b57cec5SDimitry Andric   case ARM::t2STR_POST: {
4540b57cec5SDimitry Andric     if (!MinimizeSize)
4550b57cec5SDimitry Andric       return false;
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric     if (!MI->hasOneMemOperand() ||
4585ffd83dbSDimitry Andric         (*MI->memoperands_begin())->getAlign() < Align(4))
4590b57cec5SDimitry Andric       return false;
4600b57cec5SDimitry Andric 
4610b57cec5SDimitry Andric     // We're creating a completely different type of load/store - LDM from LDR.
4620b57cec5SDimitry Andric     // For this reason we can't reuse the logic at the end of this function; we
4630b57cec5SDimitry Andric     // have to implement the MI building here.
4640b57cec5SDimitry Andric     bool IsStore = Entry.WideOpc == ARM::t2STR_POST;
4658bcb0991SDimitry Andric     Register Rt = MI->getOperand(IsStore ? 1 : 0).getReg();
4668bcb0991SDimitry Andric     Register Rn = MI->getOperand(IsStore ? 0 : 1).getReg();
4670b57cec5SDimitry Andric     unsigned Offset = MI->getOperand(3).getImm();
4680b57cec5SDimitry Andric     unsigned PredImm = MI->getOperand(4).getImm();
4698bcb0991SDimitry Andric     Register PredReg = MI->getOperand(5).getReg();
4700b57cec5SDimitry Andric     assert(isARMLowRegister(Rt));
4710b57cec5SDimitry Andric     assert(isARMLowRegister(Rn));
4720b57cec5SDimitry Andric 
4730b57cec5SDimitry Andric     if (Offset != 4)
4740b57cec5SDimitry Andric       return false;
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric     // Add the 16-bit load / store instruction.
4770b57cec5SDimitry Andric     DebugLoc dl = MI->getDebugLoc();
4780b57cec5SDimitry Andric     auto MIB = BuildMI(MBB, MI, dl, TII->get(Entry.NarrowOpc1))
4790b57cec5SDimitry Andric                    .addReg(Rn, RegState::Define)
4800b57cec5SDimitry Andric                    .addReg(Rn)
4810b57cec5SDimitry Andric                    .addImm(PredImm)
4820b57cec5SDimitry Andric                    .addReg(PredReg)
4830b57cec5SDimitry Andric                    .addReg(Rt, IsStore ? 0 : RegState::Define);
4840b57cec5SDimitry Andric 
4850b57cec5SDimitry Andric     // Transfer memoperands.
4860b57cec5SDimitry Andric     MIB.setMemRefs(MI->memoperands());
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric     // Transfer MI flags.
4890b57cec5SDimitry Andric     MIB.setMIFlags(MI->getFlags());
4900b57cec5SDimitry Andric 
4910b57cec5SDimitry Andric     // Kill the old instruction.
4920b57cec5SDimitry Andric     MI->eraseFromBundle();
4930b57cec5SDimitry Andric     ++NumLdSts;
4940b57cec5SDimitry Andric     return true;
4950b57cec5SDimitry Andric   }
4960b57cec5SDimitry Andric   case ARM::t2LDMIA: {
4978bcb0991SDimitry Andric     Register BaseReg = MI->getOperand(0).getReg();
4980b57cec5SDimitry Andric     assert(isARMLowRegister(BaseReg));
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric     // For the non-writeback version (this one), the base register must be
5010b57cec5SDimitry Andric     // one of the registers being loaded.
5020b57cec5SDimitry Andric     bool isOK = false;
5034824e7fdSDimitry Andric     for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 3)) {
5044824e7fdSDimitry Andric       if (MO.getReg() == BaseReg) {
5050b57cec5SDimitry Andric         isOK = true;
5060b57cec5SDimitry Andric         break;
5070b57cec5SDimitry Andric       }
5080b57cec5SDimitry Andric     }
5090b57cec5SDimitry Andric 
5100b57cec5SDimitry Andric     if (!isOK)
5110b57cec5SDimitry Andric       return false;
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric     OpNum = 0;
5140b57cec5SDimitry Andric     isLdStMul = true;
5150b57cec5SDimitry Andric     break;
5160b57cec5SDimitry Andric   }
5175ffd83dbSDimitry Andric   case ARM::t2STMIA: {
5185ffd83dbSDimitry Andric     // t2STMIA is reduced to tSTMIA_UPD which has writeback. We can only do this
5195ffd83dbSDimitry Andric     // if the base register is killed, as then it doesn't matter what its value
5205ffd83dbSDimitry Andric     // is after the instruction.
5210b57cec5SDimitry Andric     if (!MI->getOperand(0).isKill())
5220b57cec5SDimitry Andric       return false;
5230b57cec5SDimitry Andric 
5245ffd83dbSDimitry Andric     // If the base register is in the register list and isn't the lowest
5255ffd83dbSDimitry Andric     // numbered register (i.e. it's in operand 4 onwards) then with writeback
5265ffd83dbSDimitry Andric     // the stored value is unknown, so we can't convert to tSTMIA_UPD.
5275ffd83dbSDimitry Andric     Register BaseReg = MI->getOperand(0).getReg();
5284824e7fdSDimitry Andric     for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 4))
5294824e7fdSDimitry Andric       if (MO.getReg() == BaseReg)
5305ffd83dbSDimitry Andric         return false;
5315ffd83dbSDimitry Andric 
5320b57cec5SDimitry Andric     break;
5335ffd83dbSDimitry Andric   }
5340b57cec5SDimitry Andric   case ARM::t2LDMIA_RET: {
5358bcb0991SDimitry Andric     Register BaseReg = MI->getOperand(1).getReg();
5360b57cec5SDimitry Andric     if (BaseReg != ARM::SP)
5370b57cec5SDimitry Andric       return false;
5380b57cec5SDimitry Andric     Opc = Entry.NarrowOpc2; // tPOP_RET
5390b57cec5SDimitry Andric     OpNum = 2;
5400b57cec5SDimitry Andric     isLdStMul = true;
5410b57cec5SDimitry Andric     break;
5420b57cec5SDimitry Andric   }
5430b57cec5SDimitry Andric   case ARM::t2LDMIA_UPD:
5440b57cec5SDimitry Andric   case ARM::t2STMIA_UPD:
5450b57cec5SDimitry Andric   case ARM::t2STMDB_UPD: {
5460b57cec5SDimitry Andric     OpNum = 0;
5470b57cec5SDimitry Andric 
5488bcb0991SDimitry Andric     Register BaseReg = MI->getOperand(1).getReg();
5490b57cec5SDimitry Andric     if (BaseReg == ARM::SP &&
5500b57cec5SDimitry Andric         (Entry.WideOpc == ARM::t2LDMIA_UPD ||
5510b57cec5SDimitry Andric          Entry.WideOpc == ARM::t2STMDB_UPD)) {
5520b57cec5SDimitry Andric       Opc = Entry.NarrowOpc2; // tPOP or tPUSH
5530b57cec5SDimitry Andric       OpNum = 2;
5540b57cec5SDimitry Andric     } else if (!isARMLowRegister(BaseReg) ||
5550b57cec5SDimitry Andric                (Entry.WideOpc != ARM::t2LDMIA_UPD &&
5560b57cec5SDimitry Andric                 Entry.WideOpc != ARM::t2STMIA_UPD)) {
5570b57cec5SDimitry Andric       return false;
5580b57cec5SDimitry Andric     }
5590b57cec5SDimitry Andric 
5600b57cec5SDimitry Andric     isLdStMul = true;
5610b57cec5SDimitry Andric     break;
5620b57cec5SDimitry Andric   }
5630b57cec5SDimitry Andric   }
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   unsigned OffsetReg = 0;
5660b57cec5SDimitry Andric   bool OffsetKill = false;
5670b57cec5SDimitry Andric   bool OffsetInternal = false;
5680b57cec5SDimitry Andric   if (HasShift) {
5690b57cec5SDimitry Andric     OffsetReg  = MI->getOperand(2).getReg();
5700b57cec5SDimitry Andric     OffsetKill = MI->getOperand(2).isKill();
5710b57cec5SDimitry Andric     OffsetInternal = MI->getOperand(2).isInternalRead();
5720b57cec5SDimitry Andric 
5730b57cec5SDimitry Andric     if (MI->getOperand(3).getImm())
5740b57cec5SDimitry Andric       // Thumb1 addressing mode doesn't support shift.
5750b57cec5SDimitry Andric       return false;
5760b57cec5SDimitry Andric   }
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric   unsigned OffsetImm = 0;
5790b57cec5SDimitry Andric   if (HasImmOffset) {
5800b57cec5SDimitry Andric     OffsetImm = MI->getOperand(2).getImm();
5810b57cec5SDimitry Andric     unsigned MaxOffset = ((1 << ImmLimit) - 1) * Scale;
5820b57cec5SDimitry Andric 
5830b57cec5SDimitry Andric     if ((OffsetImm & (Scale - 1)) || OffsetImm > MaxOffset)
5840b57cec5SDimitry Andric       // Make sure the immediate field fits.
5850b57cec5SDimitry Andric       return false;
5860b57cec5SDimitry Andric   }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric   // Add the 16-bit load / store instruction.
5890b57cec5SDimitry Andric   DebugLoc dl = MI->getDebugLoc();
5900b57cec5SDimitry Andric   MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, TII->get(Opc));
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   // tSTMIA_UPD takes a defining register operand. We've already checked that
5930b57cec5SDimitry Andric   // the register is killed, so mark it as dead here.
5940b57cec5SDimitry Andric   if (Entry.WideOpc == ARM::t2STMIA)
5950b57cec5SDimitry Andric     MIB.addReg(MI->getOperand(0).getReg(), RegState::Define | RegState::Dead);
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric   if (!isLdStMul) {
5980b57cec5SDimitry Andric     MIB.add(MI->getOperand(0));
5990b57cec5SDimitry Andric     MIB.add(MI->getOperand(1));
6000b57cec5SDimitry Andric 
6010b57cec5SDimitry Andric     if (HasImmOffset)
6020b57cec5SDimitry Andric       MIB.addImm(OffsetImm / Scale);
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric     assert((!HasShift || OffsetReg) && "Invalid so_reg load / store address!");
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric     if (HasOffReg)
6070b57cec5SDimitry Andric       MIB.addReg(OffsetReg, getKillRegState(OffsetKill) |
6080b57cec5SDimitry Andric                             getInternalReadRegState(OffsetInternal));
6090b57cec5SDimitry Andric   }
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   // Transfer the rest of operands.
6124824e7fdSDimitry Andric   for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), OpNum))
6134824e7fdSDimitry Andric     MIB.add(MO);
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric   // Transfer memoperands.
6160b57cec5SDimitry Andric   MIB.setMemRefs(MI->memoperands());
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric   // Transfer MI flags.
6190b57cec5SDimitry Andric   MIB.setMIFlags(MI->getFlags());
6200b57cec5SDimitry Andric 
62181ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Converted 32-bit: " << *MI
6220b57cec5SDimitry Andric                     << "       to 16-bit: " << *MIB);
6230b57cec5SDimitry Andric 
6240b57cec5SDimitry Andric   MBB.erase_instr(MI);
6250b57cec5SDimitry Andric   ++NumLdSts;
6260b57cec5SDimitry Andric   return true;
6270b57cec5SDimitry Andric }
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric bool
ReduceSpecial(MachineBasicBlock & MBB,MachineInstr * MI,const ReduceEntry & Entry,bool LiveCPSR,bool IsSelfLoop)6300b57cec5SDimitry Andric Thumb2SizeReduce::ReduceSpecial(MachineBasicBlock &MBB, MachineInstr *MI,
6310b57cec5SDimitry Andric                                 const ReduceEntry &Entry,
6320b57cec5SDimitry Andric                                 bool LiveCPSR, bool IsSelfLoop) {
6330b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
6340b57cec5SDimitry Andric   if (Opc == ARM::t2ADDri) {
6350b57cec5SDimitry Andric     // If the source register is SP, try to reduce to tADDrSPi, otherwise
6360b57cec5SDimitry Andric     // it's a normal reduce.
6370b57cec5SDimitry Andric     if (MI->getOperand(1).getReg() != ARM::SP) {
6380b57cec5SDimitry Andric       if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
6390b57cec5SDimitry Andric         return true;
6400b57cec5SDimitry Andric       return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
6410b57cec5SDimitry Andric     }
6420b57cec5SDimitry Andric     // Try to reduce to tADDrSPi.
6430b57cec5SDimitry Andric     unsigned Imm = MI->getOperand(2).getImm();
6440b57cec5SDimitry Andric     // The immediate must be in range, the destination register must be a low
6450b57cec5SDimitry Andric     // reg, the predicate must be "always" and the condition flags must not
6460b57cec5SDimitry Andric     // be being set.
6470b57cec5SDimitry Andric     if (Imm & 3 || Imm > 1020)
6480b57cec5SDimitry Andric       return false;
6490b57cec5SDimitry Andric     if (!isARMLowRegister(MI->getOperand(0).getReg()))
6500b57cec5SDimitry Andric       return false;
6510b57cec5SDimitry Andric     if (MI->getOperand(3).getImm() != ARMCC::AL)
6520b57cec5SDimitry Andric       return false;
6530b57cec5SDimitry Andric     const MCInstrDesc &MCID = MI->getDesc();
6540b57cec5SDimitry Andric     if (MCID.hasOptionalDef() &&
6550b57cec5SDimitry Andric         MI->getOperand(MCID.getNumOperands()-1).getReg() == ARM::CPSR)
6560b57cec5SDimitry Andric       return false;
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric     MachineInstrBuilder MIB =
6590b57cec5SDimitry Andric         BuildMI(MBB, MI, MI->getDebugLoc(),
6600b57cec5SDimitry Andric                 TII->get(ARM::tADDrSPi))
6610b57cec5SDimitry Andric             .add(MI->getOperand(0))
6620b57cec5SDimitry Andric             .add(MI->getOperand(1))
6630b57cec5SDimitry Andric             .addImm(Imm / 4) // The tADDrSPi has an implied scale by four.
6640b57cec5SDimitry Andric             .add(predOps(ARMCC::AL));
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric     // Transfer MI flags.
6670b57cec5SDimitry Andric     MIB.setMIFlags(MI->getFlags());
6680b57cec5SDimitry Andric 
66981ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "Converted 32-bit: " << *MI
6700b57cec5SDimitry Andric                       << "       to 16-bit: " << *MIB);
6710b57cec5SDimitry Andric 
6720b57cec5SDimitry Andric     MBB.erase_instr(MI);
6730b57cec5SDimitry Andric     ++NumNarrows;
6740b57cec5SDimitry Andric     return true;
6750b57cec5SDimitry Andric   }
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric   if (Entry.LowRegs1 && !VerifyLowRegs(MI))
6780b57cec5SDimitry Andric     return false;
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   if (MI->mayLoadOrStore())
6810b57cec5SDimitry Andric     return ReduceLoadStore(MBB, MI, Entry);
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric   switch (Opc) {
6840b57cec5SDimitry Andric   default: break;
6850b57cec5SDimitry Andric   case ARM::t2ADDSri:
6860b57cec5SDimitry Andric   case ARM::t2ADDSrr: {
6875ffd83dbSDimitry Andric     Register PredReg;
6880b57cec5SDimitry Andric     if (getInstrPredicate(*MI, PredReg) == ARMCC::AL) {
6890b57cec5SDimitry Andric       switch (Opc) {
6900b57cec5SDimitry Andric       default: break;
6910b57cec5SDimitry Andric       case ARM::t2ADDSri:
6920b57cec5SDimitry Andric         if (ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
6930b57cec5SDimitry Andric           return true;
694bdd1243dSDimitry Andric         [[fallthrough]];
6950b57cec5SDimitry Andric       case ARM::t2ADDSrr:
6960b57cec5SDimitry Andric         return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
6970b57cec5SDimitry Andric       }
6980b57cec5SDimitry Andric     }
6990b57cec5SDimitry Andric     break;
7000b57cec5SDimitry Andric   }
7010b57cec5SDimitry Andric   case ARM::t2RSBri:
7020b57cec5SDimitry Andric   case ARM::t2RSBSri:
7030b57cec5SDimitry Andric   case ARM::t2SXTB:
7040b57cec5SDimitry Andric   case ARM::t2SXTH:
7050b57cec5SDimitry Andric   case ARM::t2UXTB:
7060b57cec5SDimitry Andric   case ARM::t2UXTH:
7070b57cec5SDimitry Andric     if (MI->getOperand(2).getImm() == 0)
7080b57cec5SDimitry Andric       return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
7090b57cec5SDimitry Andric     break;
7100b57cec5SDimitry Andric   case ARM::t2MOVi16:
7110b57cec5SDimitry Andric     // Can convert only 'pure' immediate operands, not immediates obtained as
7120b57cec5SDimitry Andric     // globals' addresses.
7130b57cec5SDimitry Andric     if (MI->getOperand(1).isImm())
7140b57cec5SDimitry Andric       return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
7150b57cec5SDimitry Andric     break;
7160b57cec5SDimitry Andric   case ARM::t2CMPrr: {
7170b57cec5SDimitry Andric     // Try to reduce to the lo-reg only version first. Why there are two
7180b57cec5SDimitry Andric     // versions of the instruction is a mystery.
7195e801ac6SDimitry Andric     // It would be nice to just have two entries in the main table that
7200b57cec5SDimitry Andric     // are prioritized, but the table assumes a unique entry for each
7210b57cec5SDimitry Andric     // source insn opcode. So for now, we hack a local entry record to use.
7220b57cec5SDimitry Andric     static const ReduceEntry NarrowEntry =
7230b57cec5SDimitry Andric       { ARM::t2CMPrr,ARM::tCMPr, 0, 0, 0, 1, 1,2, 0, 0,1,0 };
7240b57cec5SDimitry Andric     if (ReduceToNarrow(MBB, MI, NarrowEntry, LiveCPSR, IsSelfLoop))
7250b57cec5SDimitry Andric       return true;
7260b57cec5SDimitry Andric     return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
7270b57cec5SDimitry Andric   }
7280b57cec5SDimitry Andric   case ARM::t2TEQrr: {
7295ffd83dbSDimitry Andric     Register PredReg;
7300b57cec5SDimitry Andric     // Can only convert to eors if we're not in an IT block.
7310b57cec5SDimitry Andric     if (getInstrPredicate(*MI, PredReg) != ARMCC::AL)
7320b57cec5SDimitry Andric       break;
7330b57cec5SDimitry Andric     // TODO if Operand 0 is not killed but Operand 1 is, then we could write
7340b57cec5SDimitry Andric     // to Op1 instead.
7350b57cec5SDimitry Andric     if (MI->getOperand(0).isKill())
7360b57cec5SDimitry Andric       return ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
7370b57cec5SDimitry Andric   }
7380b57cec5SDimitry Andric   }
7390b57cec5SDimitry Andric   return false;
7400b57cec5SDimitry Andric }
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric bool
ReduceTo2Addr(MachineBasicBlock & MBB,MachineInstr * MI,const ReduceEntry & Entry,bool LiveCPSR,bool IsSelfLoop)7430b57cec5SDimitry Andric Thumb2SizeReduce::ReduceTo2Addr(MachineBasicBlock &MBB, MachineInstr *MI,
7440b57cec5SDimitry Andric                                 const ReduceEntry &Entry,
7450b57cec5SDimitry Andric                                 bool LiveCPSR, bool IsSelfLoop) {
7460b57cec5SDimitry Andric   if (ReduceLimit2Addr != -1 && ((int)Num2Addrs >= ReduceLimit2Addr))
7470b57cec5SDimitry Andric     return false;
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric   if (!OptimizeSize && Entry.AvoidMovs && STI->avoidMOVsShifterOperand())
7500b57cec5SDimitry Andric     // Don't issue movs with shifter operand for some CPUs unless we
7510b57cec5SDimitry Andric     // are optimizing for size.
7520b57cec5SDimitry Andric     return false;
7530b57cec5SDimitry Andric 
7548bcb0991SDimitry Andric   Register Reg0 = MI->getOperand(0).getReg();
7558bcb0991SDimitry Andric   Register Reg1 = MI->getOperand(1).getReg();
7560b57cec5SDimitry Andric   // t2MUL is "special". The tied source operand is second, not first.
7570b57cec5SDimitry Andric   if (MI->getOpcode() == ARM::t2MUL) {
7588bcb0991SDimitry Andric     Register Reg2 = MI->getOperand(2).getReg();
7590b57cec5SDimitry Andric     // Early exit if the regs aren't all low regs.
7600b57cec5SDimitry Andric     if (!isARMLowRegister(Reg0) || !isARMLowRegister(Reg1)
7610b57cec5SDimitry Andric         || !isARMLowRegister(Reg2))
7620b57cec5SDimitry Andric       return false;
7630b57cec5SDimitry Andric     if (Reg0 != Reg2) {
7640b57cec5SDimitry Andric       // If the other operand also isn't the same as the destination, we
7650b57cec5SDimitry Andric       // can't reduce.
7660b57cec5SDimitry Andric       if (Reg1 != Reg0)
7670b57cec5SDimitry Andric         return false;
7680b57cec5SDimitry Andric       // Try to commute the operands to make it a 2-address instruction.
7690b57cec5SDimitry Andric       MachineInstr *CommutedMI = TII->commuteInstruction(*MI);
7700b57cec5SDimitry Andric       if (!CommutedMI)
7710b57cec5SDimitry Andric         return false;
7720b57cec5SDimitry Andric     }
7730b57cec5SDimitry Andric   } else if (Reg0 != Reg1) {
7740b57cec5SDimitry Andric     // Try to commute the operands to make it a 2-address instruction.
7750b57cec5SDimitry Andric     unsigned CommOpIdx1 = 1;
7760b57cec5SDimitry Andric     unsigned CommOpIdx2 = TargetInstrInfo::CommuteAnyOperandIndex;
7770b57cec5SDimitry Andric     if (!TII->findCommutedOpIndices(*MI, CommOpIdx1, CommOpIdx2) ||
7780b57cec5SDimitry Andric         MI->getOperand(CommOpIdx2).getReg() != Reg0)
7790b57cec5SDimitry Andric       return false;
7800b57cec5SDimitry Andric     MachineInstr *CommutedMI =
7810b57cec5SDimitry Andric         TII->commuteInstruction(*MI, false, CommOpIdx1, CommOpIdx2);
7820b57cec5SDimitry Andric     if (!CommutedMI)
7830b57cec5SDimitry Andric       return false;
7840b57cec5SDimitry Andric   }
7850b57cec5SDimitry Andric   if (Entry.LowRegs2 && !isARMLowRegister(Reg0))
7860b57cec5SDimitry Andric     return false;
7870b57cec5SDimitry Andric   if (Entry.Imm2Limit) {
7880b57cec5SDimitry Andric     unsigned Imm = MI->getOperand(2).getImm();
7890b57cec5SDimitry Andric     unsigned Limit = (1 << Entry.Imm2Limit) - 1;
7900b57cec5SDimitry Andric     if (Imm > Limit)
7910b57cec5SDimitry Andric       return false;
7920b57cec5SDimitry Andric   } else {
7938bcb0991SDimitry Andric     Register Reg2 = MI->getOperand(2).getReg();
7940b57cec5SDimitry Andric     if (Entry.LowRegs2 && !isARMLowRegister(Reg2))
7950b57cec5SDimitry Andric       return false;
7960b57cec5SDimitry Andric   }
7970b57cec5SDimitry Andric 
7980b57cec5SDimitry Andric   // Check if it's possible / necessary to transfer the predicate.
7990b57cec5SDimitry Andric   const MCInstrDesc &NewMCID = TII->get(Entry.NarrowOpc2);
8005ffd83dbSDimitry Andric   Register PredReg;
8010b57cec5SDimitry Andric   ARMCC::CondCodes Pred = getInstrPredicate(*MI, PredReg);
8020b57cec5SDimitry Andric   bool SkipPred = false;
8030b57cec5SDimitry Andric   if (Pred != ARMCC::AL) {
8040b57cec5SDimitry Andric     if (!NewMCID.isPredicable())
8050b57cec5SDimitry Andric       // Can't transfer predicate, fail.
8060b57cec5SDimitry Andric       return false;
8070b57cec5SDimitry Andric   } else {
8080b57cec5SDimitry Andric     SkipPred = !NewMCID.isPredicable();
8090b57cec5SDimitry Andric   }
8100b57cec5SDimitry Andric 
8110b57cec5SDimitry Andric   bool HasCC = false;
8120b57cec5SDimitry Andric   bool CCDead = false;
8130b57cec5SDimitry Andric   const MCInstrDesc &MCID = MI->getDesc();
8140b57cec5SDimitry Andric   if (MCID.hasOptionalDef()) {
8150b57cec5SDimitry Andric     unsigned NumOps = MCID.getNumOperands();
8160b57cec5SDimitry Andric     HasCC = (MI->getOperand(NumOps-1).getReg() == ARM::CPSR);
8170b57cec5SDimitry Andric     if (HasCC && MI->getOperand(NumOps-1).isDead())
8180b57cec5SDimitry Andric       CCDead = true;
8190b57cec5SDimitry Andric   }
8200b57cec5SDimitry Andric   if (!VerifyPredAndCC(MI, Entry, true, Pred, LiveCPSR, HasCC, CCDead))
8210b57cec5SDimitry Andric     return false;
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric   // Avoid adding a false dependency on partial flag update by some 16-bit
8240b57cec5SDimitry Andric   // instructions which has the 's' bit set.
8250b57cec5SDimitry Andric   if (Entry.PartFlag && NewMCID.hasOptionalDef() && HasCC &&
8260b57cec5SDimitry Andric       canAddPseudoFlagDep(MI, IsSelfLoop))
8270b57cec5SDimitry Andric     return false;
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   // Add the 16-bit instruction.
8300b57cec5SDimitry Andric   DebugLoc dl = MI->getDebugLoc();
8310b57cec5SDimitry Andric   MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);
8320b57cec5SDimitry Andric   MIB.add(MI->getOperand(0));
8330b57cec5SDimitry Andric   if (NewMCID.hasOptionalDef())
8340b57cec5SDimitry Andric     MIB.add(HasCC ? t1CondCodeOp(CCDead) : condCodeOp());
8350b57cec5SDimitry Andric 
8360b57cec5SDimitry Andric   // Transfer the rest of operands.
8370b57cec5SDimitry Andric   unsigned NumOps = MCID.getNumOperands();
8380b57cec5SDimitry Andric   for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
839bdd1243dSDimitry Andric     if (i < NumOps && MCID.operands()[i].isOptionalDef())
8400b57cec5SDimitry Andric       continue;
841bdd1243dSDimitry Andric     if (SkipPred && MCID.operands()[i].isPredicate())
8420b57cec5SDimitry Andric       continue;
8430b57cec5SDimitry Andric     MIB.add(MI->getOperand(i));
8440b57cec5SDimitry Andric   }
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric   // Transfer MI flags.
8470b57cec5SDimitry Andric   MIB.setMIFlags(MI->getFlags());
8480b57cec5SDimitry Andric 
84981ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Converted 32-bit: " << *MI
8500b57cec5SDimitry Andric                     << "       to 16-bit: " << *MIB);
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric   MBB.erase_instr(MI);
8530b57cec5SDimitry Andric   ++Num2Addrs;
8540b57cec5SDimitry Andric   return true;
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric 
8570b57cec5SDimitry Andric bool
ReduceToNarrow(MachineBasicBlock & MBB,MachineInstr * MI,const ReduceEntry & Entry,bool LiveCPSR,bool IsSelfLoop)8580b57cec5SDimitry Andric Thumb2SizeReduce::ReduceToNarrow(MachineBasicBlock &MBB, MachineInstr *MI,
8590b57cec5SDimitry Andric                                  const ReduceEntry &Entry,
8600b57cec5SDimitry Andric                                  bool LiveCPSR, bool IsSelfLoop) {
8610b57cec5SDimitry Andric   if (ReduceLimit != -1 && ((int)NumNarrows >= ReduceLimit))
8620b57cec5SDimitry Andric     return false;
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   if (!OptimizeSize && Entry.AvoidMovs && STI->avoidMOVsShifterOperand())
8650b57cec5SDimitry Andric     // Don't issue movs with shifter operand for some CPUs unless we
8660b57cec5SDimitry Andric     // are optimizing for size.
8670b57cec5SDimitry Andric     return false;
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric   unsigned Limit = ~0U;
8700b57cec5SDimitry Andric   if (Entry.Imm1Limit)
8710b57cec5SDimitry Andric     Limit = (1 << Entry.Imm1Limit) - 1;
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric   const MCInstrDesc &MCID = MI->getDesc();
8740b57cec5SDimitry Andric   for (unsigned i = 0, e = MCID.getNumOperands(); i != e; ++i) {
875bdd1243dSDimitry Andric     if (MCID.operands()[i].isPredicate())
8760b57cec5SDimitry Andric       continue;
8770b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(i);
8780b57cec5SDimitry Andric     if (MO.isReg()) {
8798bcb0991SDimitry Andric       Register Reg = MO.getReg();
8800b57cec5SDimitry Andric       if (!Reg || Reg == ARM::CPSR)
8810b57cec5SDimitry Andric         continue;
8820b57cec5SDimitry Andric       if (Entry.LowRegs1 && !isARMLowRegister(Reg))
8830b57cec5SDimitry Andric         return false;
884bdd1243dSDimitry Andric     } else if (MO.isImm() && !MCID.operands()[i].isPredicate()) {
8850b57cec5SDimitry Andric       if (((unsigned)MO.getImm()) > Limit)
8860b57cec5SDimitry Andric         return false;
8870b57cec5SDimitry Andric     }
8880b57cec5SDimitry Andric   }
8890b57cec5SDimitry Andric 
8900b57cec5SDimitry Andric   // Check if it's possible / necessary to transfer the predicate.
8910b57cec5SDimitry Andric   const MCInstrDesc &NewMCID = TII->get(Entry.NarrowOpc1);
8925ffd83dbSDimitry Andric   Register PredReg;
8930b57cec5SDimitry Andric   ARMCC::CondCodes Pred = getInstrPredicate(*MI, PredReg);
8940b57cec5SDimitry Andric   bool SkipPred = false;
8950b57cec5SDimitry Andric   if (Pred != ARMCC::AL) {
8960b57cec5SDimitry Andric     if (!NewMCID.isPredicable())
8970b57cec5SDimitry Andric       // Can't transfer predicate, fail.
8980b57cec5SDimitry Andric       return false;
8990b57cec5SDimitry Andric   } else {
9000b57cec5SDimitry Andric     SkipPred = !NewMCID.isPredicable();
9010b57cec5SDimitry Andric   }
9020b57cec5SDimitry Andric 
9030b57cec5SDimitry Andric   bool HasCC = false;
9040b57cec5SDimitry Andric   bool CCDead = false;
9050b57cec5SDimitry Andric   if (MCID.hasOptionalDef()) {
9060b57cec5SDimitry Andric     unsigned NumOps = MCID.getNumOperands();
9070b57cec5SDimitry Andric     HasCC = (MI->getOperand(NumOps-1).getReg() == ARM::CPSR);
9080b57cec5SDimitry Andric     if (HasCC && MI->getOperand(NumOps-1).isDead())
9090b57cec5SDimitry Andric       CCDead = true;
9100b57cec5SDimitry Andric   }
9110b57cec5SDimitry Andric   if (!VerifyPredAndCC(MI, Entry, false, Pred, LiveCPSR, HasCC, CCDead))
9120b57cec5SDimitry Andric     return false;
9130b57cec5SDimitry Andric 
9140b57cec5SDimitry Andric   // Avoid adding a false dependency on partial flag update by some 16-bit
9150b57cec5SDimitry Andric   // instructions which has the 's' bit set.
9160b57cec5SDimitry Andric   if (Entry.PartFlag && NewMCID.hasOptionalDef() && HasCC &&
9170b57cec5SDimitry Andric       canAddPseudoFlagDep(MI, IsSelfLoop))
9180b57cec5SDimitry Andric     return false;
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric   // Add the 16-bit instruction.
9210b57cec5SDimitry Andric   DebugLoc dl = MI->getDebugLoc();
9220b57cec5SDimitry Andric   MachineInstrBuilder MIB = BuildMI(MBB, MI, dl, NewMCID);
9230b57cec5SDimitry Andric 
9240b57cec5SDimitry Andric   // TEQ is special in that it doesn't define a register but we're converting
9250b57cec5SDimitry Andric   // it into an EOR which does. So add the first operand as a def and then
9260b57cec5SDimitry Andric   // again as a use.
9270b57cec5SDimitry Andric   if (MCID.getOpcode() == ARM::t2TEQrr) {
9280b57cec5SDimitry Andric     MIB.add(MI->getOperand(0));
9290b57cec5SDimitry Andric     MIB->getOperand(0).setIsKill(false);
9300b57cec5SDimitry Andric     MIB->getOperand(0).setIsDef(true);
9310b57cec5SDimitry Andric     MIB->getOperand(0).setIsDead(true);
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric     if (NewMCID.hasOptionalDef())
9340b57cec5SDimitry Andric       MIB.add(HasCC ? t1CondCodeOp(CCDead) : condCodeOp());
9350b57cec5SDimitry Andric     MIB.add(MI->getOperand(0));
9360b57cec5SDimitry Andric   } else {
9370b57cec5SDimitry Andric     MIB.add(MI->getOperand(0));
9380b57cec5SDimitry Andric     if (NewMCID.hasOptionalDef())
9390b57cec5SDimitry Andric       MIB.add(HasCC ? t1CondCodeOp(CCDead) : condCodeOp());
9400b57cec5SDimitry Andric   }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   // Transfer the rest of operands.
9430b57cec5SDimitry Andric   unsigned NumOps = MCID.getNumOperands();
9440b57cec5SDimitry Andric   for (unsigned i = 1, e = MI->getNumOperands(); i != e; ++i) {
945bdd1243dSDimitry Andric     if (i < NumOps && MCID.operands()[i].isOptionalDef())
9460b57cec5SDimitry Andric       continue;
9470b57cec5SDimitry Andric     if ((MCID.getOpcode() == ARM::t2RSBSri ||
9480b57cec5SDimitry Andric          MCID.getOpcode() == ARM::t2RSBri ||
9490b57cec5SDimitry Andric          MCID.getOpcode() == ARM::t2SXTB ||
9500b57cec5SDimitry Andric          MCID.getOpcode() == ARM::t2SXTH ||
9510b57cec5SDimitry Andric          MCID.getOpcode() == ARM::t2UXTB ||
9520b57cec5SDimitry Andric          MCID.getOpcode() == ARM::t2UXTH) && i == 2)
9530b57cec5SDimitry Andric       // Skip the zero immediate operand, it's now implicit.
9540b57cec5SDimitry Andric       continue;
955bdd1243dSDimitry Andric     bool isPred = (i < NumOps && MCID.operands()[i].isPredicate());
9560b57cec5SDimitry Andric     if (SkipPred && isPred)
9570b57cec5SDimitry Andric         continue;
9580b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(i);
9590b57cec5SDimitry Andric     if (MO.isReg() && MO.isImplicit() && MO.getReg() == ARM::CPSR)
9600b57cec5SDimitry Andric       // Skip implicit def of CPSR. Either it's modeled as an optional
9610b57cec5SDimitry Andric       // def now or it's already an implicit def on the new instruction.
9620b57cec5SDimitry Andric       continue;
9630b57cec5SDimitry Andric     MIB.add(MO);
9640b57cec5SDimitry Andric   }
9650b57cec5SDimitry Andric   if (!MCID.isPredicable() && NewMCID.isPredicable())
9660b57cec5SDimitry Andric     MIB.add(predOps(ARMCC::AL));
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric   // Transfer MI flags.
9690b57cec5SDimitry Andric   MIB.setMIFlags(MI->getFlags());
9700b57cec5SDimitry Andric 
97181ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Converted 32-bit: " << *MI
9720b57cec5SDimitry Andric                     << "       to 16-bit: " << *MIB);
9730b57cec5SDimitry Andric 
9740b57cec5SDimitry Andric   MBB.erase_instr(MI);
9750b57cec5SDimitry Andric   ++NumNarrows;
9760b57cec5SDimitry Andric   return true;
9770b57cec5SDimitry Andric }
9780b57cec5SDimitry Andric 
UpdateCPSRDef(MachineInstr & MI,bool LiveCPSR,bool & DefCPSR)9790b57cec5SDimitry Andric static bool UpdateCPSRDef(MachineInstr &MI, bool LiveCPSR, bool &DefCPSR) {
9800b57cec5SDimitry Andric   bool HasDef = false;
9810b57cec5SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
9820b57cec5SDimitry Andric     if (!MO.isReg() || MO.isUndef() || MO.isUse())
9830b57cec5SDimitry Andric       continue;
9840b57cec5SDimitry Andric     if (MO.getReg() != ARM::CPSR)
9850b57cec5SDimitry Andric       continue;
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric     DefCPSR = true;
9880b57cec5SDimitry Andric     if (!MO.isDead())
9890b57cec5SDimitry Andric       HasDef = true;
9900b57cec5SDimitry Andric   }
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric   return HasDef || LiveCPSR;
9930b57cec5SDimitry Andric }
9940b57cec5SDimitry Andric 
UpdateCPSRUse(MachineInstr & MI,bool LiveCPSR)9950b57cec5SDimitry Andric static bool UpdateCPSRUse(MachineInstr &MI, bool LiveCPSR) {
9960b57cec5SDimitry Andric   for (const MachineOperand &MO : MI.operands()) {
9970b57cec5SDimitry Andric     if (!MO.isReg() || MO.isUndef() || MO.isDef())
9980b57cec5SDimitry Andric       continue;
9990b57cec5SDimitry Andric     if (MO.getReg() != ARM::CPSR)
10000b57cec5SDimitry Andric       continue;
10010b57cec5SDimitry Andric     assert(LiveCPSR && "CPSR liveness tracking is wrong!");
10020b57cec5SDimitry Andric     if (MO.isKill()) {
10030b57cec5SDimitry Andric       LiveCPSR = false;
10040b57cec5SDimitry Andric       break;
10050b57cec5SDimitry Andric     }
10060b57cec5SDimitry Andric   }
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric   return LiveCPSR;
10090b57cec5SDimitry Andric }
10100b57cec5SDimitry Andric 
ReduceMI(MachineBasicBlock & MBB,MachineInstr * MI,bool LiveCPSR,bool IsSelfLoop,bool SkipPrologueEpilogue)10110b57cec5SDimitry Andric bool Thumb2SizeReduce::ReduceMI(MachineBasicBlock &MBB, MachineInstr *MI,
101281ad6265SDimitry Andric                                 bool LiveCPSR, bool IsSelfLoop,
101381ad6265SDimitry Andric                                 bool SkipPrologueEpilogue) {
10140b57cec5SDimitry Andric   unsigned Opcode = MI->getOpcode();
10150b57cec5SDimitry Andric   DenseMap<unsigned, unsigned>::iterator OPI = ReduceOpcodeMap.find(Opcode);
10160b57cec5SDimitry Andric   if (OPI == ReduceOpcodeMap.end())
10170b57cec5SDimitry Andric     return false;
101881ad6265SDimitry Andric   if (SkipPrologueEpilogue && (MI->getFlag(MachineInstr::FrameSetup) ||
101981ad6265SDimitry Andric                                MI->getFlag(MachineInstr::FrameDestroy)))
102081ad6265SDimitry Andric     return false;
10210b57cec5SDimitry Andric   const ReduceEntry &Entry = ReduceTable[OPI->second];
10220b57cec5SDimitry Andric 
10230b57cec5SDimitry Andric   // Don't attempt normal reductions on "special" cases for now.
10240b57cec5SDimitry Andric   if (Entry.Special)
10250b57cec5SDimitry Andric     return ReduceSpecial(MBB, MI, Entry, LiveCPSR, IsSelfLoop);
10260b57cec5SDimitry Andric 
10270b57cec5SDimitry Andric   // Try to transform to a 16-bit two-address instruction.
10280b57cec5SDimitry Andric   if (Entry.NarrowOpc2 &&
10290b57cec5SDimitry Andric       ReduceTo2Addr(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
10300b57cec5SDimitry Andric     return true;
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric   // Try to transform to a 16-bit non-two-address instruction.
10330b57cec5SDimitry Andric   if (Entry.NarrowOpc1 &&
10340b57cec5SDimitry Andric       ReduceToNarrow(MBB, MI, Entry, LiveCPSR, IsSelfLoop))
10350b57cec5SDimitry Andric     return true;
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric   return false;
10380b57cec5SDimitry Andric }
10390b57cec5SDimitry Andric 
ReduceMBB(MachineBasicBlock & MBB,bool SkipPrologueEpilogue)104081ad6265SDimitry Andric bool Thumb2SizeReduce::ReduceMBB(MachineBasicBlock &MBB,
104181ad6265SDimitry Andric                                  bool SkipPrologueEpilogue) {
10420b57cec5SDimitry Andric   bool Modified = false;
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric   // Yes, CPSR could be livein.
10450b57cec5SDimitry Andric   bool LiveCPSR = MBB.isLiveIn(ARM::CPSR);
10460b57cec5SDimitry Andric   MachineInstr *BundleMI = nullptr;
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric   CPSRDef = nullptr;
10490b57cec5SDimitry Andric   HighLatencyCPSR = false;
10500b57cec5SDimitry Andric 
10510b57cec5SDimitry Andric   // Check predecessors for the latest CPSRDef.
10520b57cec5SDimitry Andric   for (auto *Pred : MBB.predecessors()) {
10530b57cec5SDimitry Andric     const MBBInfo &PInfo = BlockInfo[Pred->getNumber()];
10540b57cec5SDimitry Andric     if (!PInfo.Visited) {
10550b57cec5SDimitry Andric       // Since blocks are visited in RPO, this must be a back-edge.
10560b57cec5SDimitry Andric       continue;
10570b57cec5SDimitry Andric     }
10580b57cec5SDimitry Andric     if (PInfo.HighLatencyCPSR) {
10590b57cec5SDimitry Andric       HighLatencyCPSR = true;
10600b57cec5SDimitry Andric       break;
10610b57cec5SDimitry Andric     }
10620b57cec5SDimitry Andric   }
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric   // If this BB loops back to itself, conservatively avoid narrowing the
10650b57cec5SDimitry Andric   // first instruction that does partial flag update.
10660b57cec5SDimitry Andric   bool IsSelfLoop = MBB.isSuccessor(&MBB);
10670b57cec5SDimitry Andric   MachineBasicBlock::instr_iterator MII = MBB.instr_begin(),E = MBB.instr_end();
10680b57cec5SDimitry Andric   MachineBasicBlock::instr_iterator NextMII;
10690b57cec5SDimitry Andric   for (; MII != E; MII = NextMII) {
10700b57cec5SDimitry Andric     NextMII = std::next(MII);
10710b57cec5SDimitry Andric 
10720b57cec5SDimitry Andric     MachineInstr *MI = &*MII;
10730b57cec5SDimitry Andric     if (MI->isBundle()) {
10740b57cec5SDimitry Andric       BundleMI = MI;
10750b57cec5SDimitry Andric       continue;
10760b57cec5SDimitry Andric     }
10770b57cec5SDimitry Andric     if (MI->isDebugInstr())
10780b57cec5SDimitry Andric       continue;
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric     LiveCPSR = UpdateCPSRUse(*MI, LiveCPSR);
10810b57cec5SDimitry Andric 
10820b57cec5SDimitry Andric     // Does NextMII belong to the same bundle as MI?
10830b57cec5SDimitry Andric     bool NextInSameBundle = NextMII != E && NextMII->isBundledWithPred();
10840b57cec5SDimitry Andric 
108581ad6265SDimitry Andric     if (ReduceMI(MBB, MI, LiveCPSR, IsSelfLoop, SkipPrologueEpilogue)) {
10860b57cec5SDimitry Andric       Modified = true;
10870b57cec5SDimitry Andric       MachineBasicBlock::instr_iterator I = std::prev(NextMII);
10880b57cec5SDimitry Andric       MI = &*I;
10890b57cec5SDimitry Andric       // Removing and reinserting the first instruction in a bundle will break
10900b57cec5SDimitry Andric       // up the bundle. Fix the bundling if it was broken.
10910b57cec5SDimitry Andric       if (NextInSameBundle && !NextMII->isBundledWithPred())
10920b57cec5SDimitry Andric         NextMII->bundleWithPred();
10930b57cec5SDimitry Andric     }
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric     if (BundleMI && !NextInSameBundle && MI->isInsideBundle()) {
10960b57cec5SDimitry Andric       // FIXME: Since post-ra scheduler operates on bundles, the CPSR kill
10970b57cec5SDimitry Andric       // marker is only on the BUNDLE instruction. Process the BUNDLE
10980b57cec5SDimitry Andric       // instruction as we finish with the bundled instruction to work around
10990b57cec5SDimitry Andric       // the inconsistency.
11000b57cec5SDimitry Andric       if (BundleMI->killsRegister(ARM::CPSR))
11010b57cec5SDimitry Andric         LiveCPSR = false;
11020b57cec5SDimitry Andric       MachineOperand *MO = BundleMI->findRegisterDefOperand(ARM::CPSR);
11030b57cec5SDimitry Andric       if (MO && !MO->isDead())
11040b57cec5SDimitry Andric         LiveCPSR = true;
11050b57cec5SDimitry Andric       MO = BundleMI->findRegisterUseOperand(ARM::CPSR);
11060b57cec5SDimitry Andric       if (MO && !MO->isKill())
11070b57cec5SDimitry Andric         LiveCPSR = true;
11080b57cec5SDimitry Andric     }
11090b57cec5SDimitry Andric 
11100b57cec5SDimitry Andric     bool DefCPSR = false;
11110b57cec5SDimitry Andric     LiveCPSR = UpdateCPSRDef(*MI, LiveCPSR, DefCPSR);
11120b57cec5SDimitry Andric     if (MI->isCall()) {
11130b57cec5SDimitry Andric       // Calls don't really set CPSR.
11140b57cec5SDimitry Andric       CPSRDef = nullptr;
11150b57cec5SDimitry Andric       HighLatencyCPSR = false;
11160b57cec5SDimitry Andric       IsSelfLoop = false;
11170b57cec5SDimitry Andric     } else if (DefCPSR) {
11180b57cec5SDimitry Andric       // This is the last CPSR defining instruction.
11190b57cec5SDimitry Andric       CPSRDef = MI;
11200b57cec5SDimitry Andric       HighLatencyCPSR = isHighLatencyCPSR(CPSRDef);
11210b57cec5SDimitry Andric       IsSelfLoop = false;
11220b57cec5SDimitry Andric     }
11230b57cec5SDimitry Andric   }
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric   MBBInfo &Info = BlockInfo[MBB.getNumber()];
11260b57cec5SDimitry Andric   Info.HighLatencyCPSR = HighLatencyCPSR;
11270b57cec5SDimitry Andric   Info.Visited = true;
11280b57cec5SDimitry Andric   return Modified;
11290b57cec5SDimitry Andric }
11300b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)11310b57cec5SDimitry Andric bool Thumb2SizeReduce::runOnMachineFunction(MachineFunction &MF) {
11320b57cec5SDimitry Andric   if (PredicateFtor && !PredicateFtor(MF.getFunction()))
11330b57cec5SDimitry Andric     return false;
11340b57cec5SDimitry Andric 
113581ad6265SDimitry Andric   STI = &MF.getSubtarget<ARMSubtarget>();
11360b57cec5SDimitry Andric   if (STI->isThumb1Only() || STI->prefers32BitThumb())
11370b57cec5SDimitry Andric     return false;
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric   TII = static_cast<const Thumb2InstrInfo *>(STI->getInstrInfo());
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric   // Optimizing / minimizing size? Minimizing size implies optimizing for size.
11420b57cec5SDimitry Andric   OptimizeSize = MF.getFunction().hasOptSize();
11430b57cec5SDimitry Andric   MinimizeSize = STI->hasMinSize();
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric   BlockInfo.clear();
11460b57cec5SDimitry Andric   BlockInfo.resize(MF.getNumBlockIDs());
11470b57cec5SDimitry Andric 
11480b57cec5SDimitry Andric   // Visit blocks in reverse post-order so LastCPSRDef is known for all
11490b57cec5SDimitry Andric   // predecessors.
11500b57cec5SDimitry Andric   ReversePostOrderTraversal<MachineFunction*> RPOT(&MF);
11510b57cec5SDimitry Andric   bool Modified = false;
115281ad6265SDimitry Andric   bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
115381ad6265SDimitry Andric                      MF.getFunction().needsUnwindTableEntry();
115404eeddc0SDimitry Andric   for (MachineBasicBlock *MBB : RPOT)
115581ad6265SDimitry Andric     Modified |= ReduceMBB(*MBB, /*SkipPrologueEpilogue=*/NeedsWinCFI);
11560b57cec5SDimitry Andric   return Modified;
11570b57cec5SDimitry Andric }
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric /// createThumb2SizeReductionPass - Returns an instance of the Thumb2 size
11600b57cec5SDimitry Andric /// reduction pass.
createThumb2SizeReductionPass(std::function<bool (const Function &)> Ftor)11610b57cec5SDimitry Andric FunctionPass *llvm::createThumb2SizeReductionPass(
11620b57cec5SDimitry Andric     std::function<bool(const Function &)> Ftor) {
11630b57cec5SDimitry Andric   return new Thumb2SizeReduce(std::move(Ftor));
11640b57cec5SDimitry Andric }
1165