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 1710b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 1720b57cec5SDimitry Andric return MachineFunctionProperties().set( 1730b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry 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 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 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. 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 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 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 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 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 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 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 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 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 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 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 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. 1100*0fca6ea1SDimitry Andric if (BundleMI->killsRegister(ARM::CPSR, /*TRI=*/nullptr)) 11010b57cec5SDimitry Andric LiveCPSR = false; 1102*0fca6ea1SDimitry Andric MachineOperand *MO = 1103*0fca6ea1SDimitry Andric BundleMI->findRegisterDefOperand(ARM::CPSR, /*TRI=*/nullptr); 11040b57cec5SDimitry Andric if (MO && !MO->isDead()) 11050b57cec5SDimitry Andric LiveCPSR = true; 1106*0fca6ea1SDimitry Andric MO = BundleMI->findRegisterUseOperand(ARM::CPSR, /*TRI=*/nullptr); 11070b57cec5SDimitry Andric if (MO && !MO->isKill()) 11080b57cec5SDimitry Andric LiveCPSR = true; 11090b57cec5SDimitry Andric } 11100b57cec5SDimitry Andric 11110b57cec5SDimitry Andric bool DefCPSR = false; 11120b57cec5SDimitry Andric LiveCPSR = UpdateCPSRDef(*MI, LiveCPSR, DefCPSR); 11130b57cec5SDimitry Andric if (MI->isCall()) { 11140b57cec5SDimitry Andric // Calls don't really set CPSR. 11150b57cec5SDimitry Andric CPSRDef = nullptr; 11160b57cec5SDimitry Andric HighLatencyCPSR = false; 11170b57cec5SDimitry Andric IsSelfLoop = false; 11180b57cec5SDimitry Andric } else if (DefCPSR) { 11190b57cec5SDimitry Andric // This is the last CPSR defining instruction. 11200b57cec5SDimitry Andric CPSRDef = MI; 11210b57cec5SDimitry Andric HighLatencyCPSR = isHighLatencyCPSR(CPSRDef); 11220b57cec5SDimitry Andric IsSelfLoop = false; 11230b57cec5SDimitry Andric } 11240b57cec5SDimitry Andric } 11250b57cec5SDimitry Andric 11260b57cec5SDimitry Andric MBBInfo &Info = BlockInfo[MBB.getNumber()]; 11270b57cec5SDimitry Andric Info.HighLatencyCPSR = HighLatencyCPSR; 11280b57cec5SDimitry Andric Info.Visited = true; 11290b57cec5SDimitry Andric return Modified; 11300b57cec5SDimitry Andric } 11310b57cec5SDimitry Andric 11320b57cec5SDimitry Andric bool Thumb2SizeReduce::runOnMachineFunction(MachineFunction &MF) { 11330b57cec5SDimitry Andric if (PredicateFtor && !PredicateFtor(MF.getFunction())) 11340b57cec5SDimitry Andric return false; 11350b57cec5SDimitry Andric 113681ad6265SDimitry Andric STI = &MF.getSubtarget<ARMSubtarget>(); 11370b57cec5SDimitry Andric if (STI->isThumb1Only() || STI->prefers32BitThumb()) 11380b57cec5SDimitry Andric return false; 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric TII = static_cast<const Thumb2InstrInfo *>(STI->getInstrInfo()); 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric // Optimizing / minimizing size? Minimizing size implies optimizing for size. 11430b57cec5SDimitry Andric OptimizeSize = MF.getFunction().hasOptSize(); 11440b57cec5SDimitry Andric MinimizeSize = STI->hasMinSize(); 11450b57cec5SDimitry Andric 11460b57cec5SDimitry Andric BlockInfo.clear(); 11470b57cec5SDimitry Andric BlockInfo.resize(MF.getNumBlockIDs()); 11480b57cec5SDimitry Andric 11490b57cec5SDimitry Andric // Visit blocks in reverse post-order so LastCPSRDef is known for all 11500b57cec5SDimitry Andric // predecessors. 11510b57cec5SDimitry Andric ReversePostOrderTraversal<MachineFunction*> RPOT(&MF); 11520b57cec5SDimitry Andric bool Modified = false; 115381ad6265SDimitry Andric bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() && 115481ad6265SDimitry Andric MF.getFunction().needsUnwindTableEntry(); 115504eeddc0SDimitry Andric for (MachineBasicBlock *MBB : RPOT) 115681ad6265SDimitry Andric Modified |= ReduceMBB(*MBB, /*SkipPrologueEpilogue=*/NeedsWinCFI); 11570b57cec5SDimitry Andric return Modified; 11580b57cec5SDimitry Andric } 11590b57cec5SDimitry Andric 11600b57cec5SDimitry Andric /// createThumb2SizeReductionPass - Returns an instance of the Thumb2 size 11610b57cec5SDimitry Andric /// reduction pass. 11620b57cec5SDimitry Andric FunctionPass *llvm::createThumb2SizeReductionPass( 11630b57cec5SDimitry Andric std::function<bool(const Function &)> Ftor) { 11640b57cec5SDimitry Andric return new Thumb2SizeReduce(std::move(Ftor)); 11650b57cec5SDimitry Andric } 1166