10b57cec5SDimitry Andric //===- ARMLoadStoreOptimizer.cpp - ARM load / store opt. pass -------------===// 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 /// \file This file contains a pass that performs load / store related peephole 100b57cec5SDimitry Andric /// optimizations. This pass should be run after register allocation. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "ARM.h" 150b57cec5SDimitry Andric #include "ARMBaseInstrInfo.h" 160b57cec5SDimitry Andric #include "ARMBaseRegisterInfo.h" 170b57cec5SDimitry Andric #include "ARMISelLowering.h" 180b57cec5SDimitry Andric #include "ARMMachineFunctionInfo.h" 190b57cec5SDimitry Andric #include "ARMSubtarget.h" 200b57cec5SDimitry Andric #include "MCTargetDesc/ARMAddressingModes.h" 210b57cec5SDimitry Andric #include "MCTargetDesc/ARMBaseInfo.h" 220b57cec5SDimitry Andric #include "Utils/ARMBaseInfo.h" 230b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h" 240b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 250b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 260b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 2781ad6265SDimitry Andric #include "llvm/ADT/SetVector.h" 280b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 290b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 300b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 310b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 320b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h" 330b57cec5SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 34*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveRegUnits.h" 350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 365ffd83dbSDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 3781ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 380b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 390b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 400b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 410b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 420b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 430b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 440b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 450b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h" 460b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h" 470b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 480b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 490b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 500b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 510b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 520b57cec5SDimitry Andric #include "llvm/IR/DebugLoc.h" 530b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 540b57cec5SDimitry Andric #include "llvm/IR/Function.h" 550b57cec5SDimitry Andric #include "llvm/IR/Type.h" 565ffd83dbSDimitry Andric #include "llvm/InitializePasses.h" 570b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 580b57cec5SDimitry Andric #include "llvm/Pass.h" 590b57cec5SDimitry Andric #include "llvm/Support/Allocator.h" 600b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 610b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 620b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 630b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 640b57cec5SDimitry Andric #include <algorithm> 650b57cec5SDimitry Andric #include <cassert> 660b57cec5SDimitry Andric #include <cstddef> 670b57cec5SDimitry Andric #include <cstdlib> 680b57cec5SDimitry Andric #include <iterator> 690b57cec5SDimitry Andric #include <limits> 700b57cec5SDimitry Andric #include <utility> 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric using namespace llvm; 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric #define DEBUG_TYPE "arm-ldst-opt" 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric STATISTIC(NumLDMGened , "Number of ldm instructions generated"); 770b57cec5SDimitry Andric STATISTIC(NumSTMGened , "Number of stm instructions generated"); 780b57cec5SDimitry Andric STATISTIC(NumVLDMGened, "Number of vldm instructions generated"); 790b57cec5SDimitry Andric STATISTIC(NumVSTMGened, "Number of vstm instructions generated"); 800b57cec5SDimitry Andric STATISTIC(NumLdStMoved, "Number of load / store instructions moved"); 810b57cec5SDimitry Andric STATISTIC(NumLDRDFormed,"Number of ldrd created before allocation"); 820b57cec5SDimitry Andric STATISTIC(NumSTRDFormed,"Number of strd created before allocation"); 830b57cec5SDimitry Andric STATISTIC(NumLDRD2LDM, "Number of ldrd instructions turned back into ldm"); 840b57cec5SDimitry Andric STATISTIC(NumSTRD2STM, "Number of strd instructions turned back into stm"); 850b57cec5SDimitry Andric STATISTIC(NumLDRD2LDR, "Number of ldrd instructions turned back into ldr's"); 860b57cec5SDimitry Andric STATISTIC(NumSTRD2STR, "Number of strd instructions turned back into str's"); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// This switch disables formation of double/multi instructions that could 890b57cec5SDimitry Andric /// potentially lead to (new) alignment traps even with CCR.UNALIGN_TRP 900b57cec5SDimitry Andric /// disabled. This can be used to create libraries that are robust even when 910b57cec5SDimitry Andric /// users provoke undefined behaviour by supplying misaligned pointers. 920b57cec5SDimitry Andric /// \see mayCombineMisaligned() 930b57cec5SDimitry Andric static cl::opt<bool> 940b57cec5SDimitry Andric AssumeMisalignedLoadStores("arm-assume-misaligned-load-store", cl::Hidden, 950b57cec5SDimitry Andric cl::init(false), cl::desc("Be more conservative in ARM load/store opt")); 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric #define ARM_LOAD_STORE_OPT_NAME "ARM load / store optimization pass" 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric namespace { 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric /// Post- register allocation pass the combine load / store instructions to 1020b57cec5SDimitry Andric /// form ldm / stm instructions. 1030b57cec5SDimitry Andric struct ARMLoadStoreOpt : public MachineFunctionPass { 1040b57cec5SDimitry Andric static char ID; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric const MachineFunction *MF; 1070b57cec5SDimitry Andric const TargetInstrInfo *TII; 1080b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 1090b57cec5SDimitry Andric const ARMSubtarget *STI; 1100b57cec5SDimitry Andric const TargetLowering *TL; 1110b57cec5SDimitry Andric ARMFunctionInfo *AFI; 112*0fca6ea1SDimitry Andric LiveRegUnits LiveRegs; 1130b57cec5SDimitry Andric RegisterClassInfo RegClassInfo; 1140b57cec5SDimitry Andric MachineBasicBlock::const_iterator LiveRegPos; 1150b57cec5SDimitry Andric bool LiveRegsValid; 1160b57cec5SDimitry Andric bool RegClassInfoValid; 1170b57cec5SDimitry Andric bool isThumb1, isThumb2; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric ARMLoadStoreOpt() : MachineFunctionPass(ID) {} 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 1240b57cec5SDimitry Andric return MachineFunctionProperties().set( 1250b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric StringRef getPassName() const override { return ARM_LOAD_STORE_OPT_NAME; } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric private: 1310b57cec5SDimitry Andric /// A set of load/store MachineInstrs with same base register sorted by 1320b57cec5SDimitry Andric /// offset. 1330b57cec5SDimitry Andric struct MemOpQueueEntry { 1340b57cec5SDimitry Andric MachineInstr *MI; 1350b57cec5SDimitry Andric int Offset; ///< Load/Store offset. 1360b57cec5SDimitry Andric unsigned Position; ///< Position as counted from end of basic block. 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric MemOpQueueEntry(MachineInstr &MI, int Offset, unsigned Position) 1390b57cec5SDimitry Andric : MI(&MI), Offset(Offset), Position(Position) {} 1400b57cec5SDimitry Andric }; 1410b57cec5SDimitry Andric using MemOpQueue = SmallVector<MemOpQueueEntry, 8>; 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric /// A set of MachineInstrs that fulfill (nearly all) conditions to get 1440b57cec5SDimitry Andric /// merged into a LDM/STM. 1450b57cec5SDimitry Andric struct MergeCandidate { 1460b57cec5SDimitry Andric /// List of instructions ordered by load/store offset. 1470b57cec5SDimitry Andric SmallVector<MachineInstr*, 4> Instrs; 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric /// Index in Instrs of the instruction being latest in the schedule. 1500b57cec5SDimitry Andric unsigned LatestMIIdx; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric /// Index in Instrs of the instruction being earliest in the schedule. 1530b57cec5SDimitry Andric unsigned EarliestMIIdx; 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric /// Index into the basic block where the merged instruction will be 1560b57cec5SDimitry Andric /// inserted. (See MemOpQueueEntry.Position) 1570b57cec5SDimitry Andric unsigned InsertPos; 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric /// Whether the instructions can be merged into a ldm/stm instruction. 1600b57cec5SDimitry Andric bool CanMergeToLSMulti; 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric /// Whether the instructions can be merged into a ldrd/strd instruction. 1630b57cec5SDimitry Andric bool CanMergeToLSDouble; 1640b57cec5SDimitry Andric }; 1650b57cec5SDimitry Andric SpecificBumpPtrAllocator<MergeCandidate> Allocator; 1660b57cec5SDimitry Andric SmallVector<const MergeCandidate*,4> Candidates; 1670b57cec5SDimitry Andric SmallVector<MachineInstr*,4> MergeBaseCandidates; 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric void moveLiveRegsBefore(const MachineBasicBlock &MBB, 1700b57cec5SDimitry Andric MachineBasicBlock::const_iterator Before); 1710b57cec5SDimitry Andric unsigned findFreeReg(const TargetRegisterClass &RegClass); 1720b57cec5SDimitry Andric void UpdateBaseRegUses(MachineBasicBlock &MBB, 1730b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI, const DebugLoc &DL, 1740b57cec5SDimitry Andric unsigned Base, unsigned WordOffset, 1750b57cec5SDimitry Andric ARMCC::CondCodes Pred, unsigned PredReg); 1760b57cec5SDimitry Andric MachineInstr *CreateLoadStoreMulti( 1770b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, 1780b57cec5SDimitry Andric int Offset, unsigned Base, bool BaseKill, unsigned Opcode, 1790b57cec5SDimitry Andric ARMCC::CondCodes Pred, unsigned PredReg, const DebugLoc &DL, 1800b57cec5SDimitry Andric ArrayRef<std::pair<unsigned, bool>> Regs, 1810b57cec5SDimitry Andric ArrayRef<MachineInstr*> Instrs); 1820b57cec5SDimitry Andric MachineInstr *CreateLoadStoreDouble( 1830b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, 1840b57cec5SDimitry Andric int Offset, unsigned Base, bool BaseKill, unsigned Opcode, 1850b57cec5SDimitry Andric ARMCC::CondCodes Pred, unsigned PredReg, const DebugLoc &DL, 1860b57cec5SDimitry Andric ArrayRef<std::pair<unsigned, bool>> Regs, 1870b57cec5SDimitry Andric ArrayRef<MachineInstr*> Instrs) const; 1880b57cec5SDimitry Andric void FormCandidates(const MemOpQueue &MemOps); 1890b57cec5SDimitry Andric MachineInstr *MergeOpsUpdate(const MergeCandidate &Cand); 1900b57cec5SDimitry Andric bool FixInvalidRegPairOp(MachineBasicBlock &MBB, 1910b57cec5SDimitry Andric MachineBasicBlock::iterator &MBBI); 1920b57cec5SDimitry Andric bool MergeBaseUpdateLoadStore(MachineInstr *MI); 1930b57cec5SDimitry Andric bool MergeBaseUpdateLSMultiple(MachineInstr *MI); 1940b57cec5SDimitry Andric bool MergeBaseUpdateLSDouble(MachineInstr &MI) const; 1950b57cec5SDimitry Andric bool LoadStoreMultipleOpti(MachineBasicBlock &MBB); 1960b57cec5SDimitry Andric bool MergeReturnIntoLDM(MachineBasicBlock &MBB); 1970b57cec5SDimitry Andric bool CombineMovBx(MachineBasicBlock &MBB); 1980b57cec5SDimitry Andric }; 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric } // end anonymous namespace 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric char ARMLoadStoreOpt::ID = 0; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric INITIALIZE_PASS(ARMLoadStoreOpt, "arm-ldst-opt", ARM_LOAD_STORE_OPT_NAME, false, 2050b57cec5SDimitry Andric false) 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric static bool definesCPSR(const MachineInstr &MI) { 2080b57cec5SDimitry Andric for (const auto &MO : MI.operands()) { 2090b57cec5SDimitry Andric if (!MO.isReg()) 2100b57cec5SDimitry Andric continue; 2110b57cec5SDimitry Andric if (MO.isDef() && MO.getReg() == ARM::CPSR && !MO.isDead()) 2120b57cec5SDimitry Andric // If the instruction has live CPSR def, then it's not safe to fold it 2130b57cec5SDimitry Andric // into load / store. 2140b57cec5SDimitry Andric return true; 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric return false; 2180b57cec5SDimitry Andric } 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric static int getMemoryOpOffset(const MachineInstr &MI) { 2210b57cec5SDimitry Andric unsigned Opcode = MI.getOpcode(); 2220b57cec5SDimitry Andric bool isAM3 = Opcode == ARM::LDRD || Opcode == ARM::STRD; 2230b57cec5SDimitry Andric unsigned NumOperands = MI.getDesc().getNumOperands(); 2240b57cec5SDimitry Andric unsigned OffField = MI.getOperand(NumOperands - 3).getImm(); 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric if (Opcode == ARM::t2LDRi12 || Opcode == ARM::t2LDRi8 || 2270b57cec5SDimitry Andric Opcode == ARM::t2STRi12 || Opcode == ARM::t2STRi8 || 2280b57cec5SDimitry Andric Opcode == ARM::t2LDRDi8 || Opcode == ARM::t2STRDi8 || 2290b57cec5SDimitry Andric Opcode == ARM::LDRi12 || Opcode == ARM::STRi12) 2300b57cec5SDimitry Andric return OffField; 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // Thumb1 immediate offsets are scaled by 4 2330b57cec5SDimitry Andric if (Opcode == ARM::tLDRi || Opcode == ARM::tSTRi || 2340b57cec5SDimitry Andric Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi) 2350b57cec5SDimitry Andric return OffField * 4; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric int Offset = isAM3 ? ARM_AM::getAM3Offset(OffField) 2380b57cec5SDimitry Andric : ARM_AM::getAM5Offset(OffField) * 4; 2390b57cec5SDimitry Andric ARM_AM::AddrOpc Op = isAM3 ? ARM_AM::getAM3Op(OffField) 2400b57cec5SDimitry Andric : ARM_AM::getAM5Op(OffField); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric if (Op == ARM_AM::sub) 2430b57cec5SDimitry Andric return -Offset; 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric return Offset; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric static const MachineOperand &getLoadStoreBaseOp(const MachineInstr &MI) { 2490b57cec5SDimitry Andric return MI.getOperand(1); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric static const MachineOperand &getLoadStoreRegOp(const MachineInstr &MI) { 2530b57cec5SDimitry Andric return MI.getOperand(0); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric static int getLoadStoreMultipleOpcode(unsigned Opcode, ARM_AM::AMSubMode Mode) { 2570b57cec5SDimitry Andric switch (Opcode) { 2580b57cec5SDimitry Andric default: llvm_unreachable("Unhandled opcode!"); 2590b57cec5SDimitry Andric case ARM::LDRi12: 2600b57cec5SDimitry Andric ++NumLDMGened; 2610b57cec5SDimitry Andric switch (Mode) { 2620b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 2630b57cec5SDimitry Andric case ARM_AM::ia: return ARM::LDMIA; 2640b57cec5SDimitry Andric case ARM_AM::da: return ARM::LDMDA; 2650b57cec5SDimitry Andric case ARM_AM::db: return ARM::LDMDB; 2660b57cec5SDimitry Andric case ARM_AM::ib: return ARM::LDMIB; 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric case ARM::STRi12: 2690b57cec5SDimitry Andric ++NumSTMGened; 2700b57cec5SDimitry Andric switch (Mode) { 2710b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 2720b57cec5SDimitry Andric case ARM_AM::ia: return ARM::STMIA; 2730b57cec5SDimitry Andric case ARM_AM::da: return ARM::STMDA; 2740b57cec5SDimitry Andric case ARM_AM::db: return ARM::STMDB; 2750b57cec5SDimitry Andric case ARM_AM::ib: return ARM::STMIB; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric case ARM::tLDRi: 2780b57cec5SDimitry Andric case ARM::tLDRspi: 2790b57cec5SDimitry Andric // tLDMIA is writeback-only - unless the base register is in the input 2800b57cec5SDimitry Andric // reglist. 2810b57cec5SDimitry Andric ++NumLDMGened; 2820b57cec5SDimitry Andric switch (Mode) { 2830b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 2840b57cec5SDimitry Andric case ARM_AM::ia: return ARM::tLDMIA; 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric case ARM::tSTRi: 2870b57cec5SDimitry Andric case ARM::tSTRspi: 2880b57cec5SDimitry Andric // There is no non-writeback tSTMIA either. 2890b57cec5SDimitry Andric ++NumSTMGened; 2900b57cec5SDimitry Andric switch (Mode) { 2910b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 2920b57cec5SDimitry Andric case ARM_AM::ia: return ARM::tSTMIA_UPD; 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric case ARM::t2LDRi8: 2950b57cec5SDimitry Andric case ARM::t2LDRi12: 2960b57cec5SDimitry Andric ++NumLDMGened; 2970b57cec5SDimitry Andric switch (Mode) { 2980b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 2990b57cec5SDimitry Andric case ARM_AM::ia: return ARM::t2LDMIA; 3000b57cec5SDimitry Andric case ARM_AM::db: return ARM::t2LDMDB; 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric case ARM::t2STRi8: 3030b57cec5SDimitry Andric case ARM::t2STRi12: 3040b57cec5SDimitry Andric ++NumSTMGened; 3050b57cec5SDimitry Andric switch (Mode) { 3060b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 3070b57cec5SDimitry Andric case ARM_AM::ia: return ARM::t2STMIA; 3080b57cec5SDimitry Andric case ARM_AM::db: return ARM::t2STMDB; 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric case ARM::VLDRS: 3110b57cec5SDimitry Andric ++NumVLDMGened; 3120b57cec5SDimitry Andric switch (Mode) { 3130b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 3140b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VLDMSIA; 3150b57cec5SDimitry Andric case ARM_AM::db: return 0; // Only VLDMSDB_UPD exists. 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric case ARM::VSTRS: 3180b57cec5SDimitry Andric ++NumVSTMGened; 3190b57cec5SDimitry Andric switch (Mode) { 3200b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 3210b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VSTMSIA; 3220b57cec5SDimitry Andric case ARM_AM::db: return 0; // Only VSTMSDB_UPD exists. 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric case ARM::VLDRD: 3250b57cec5SDimitry Andric ++NumVLDMGened; 3260b57cec5SDimitry Andric switch (Mode) { 3270b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 3280b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VLDMDIA; 3290b57cec5SDimitry Andric case ARM_AM::db: return 0; // Only VLDMDDB_UPD exists. 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric case ARM::VSTRD: 3320b57cec5SDimitry Andric ++NumVSTMGened; 3330b57cec5SDimitry Andric switch (Mode) { 3340b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 3350b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VSTMDIA; 3360b57cec5SDimitry Andric case ARM_AM::db: return 0; // Only VSTMDDB_UPD exists. 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric static ARM_AM::AMSubMode getLoadStoreMultipleSubMode(unsigned Opcode) { 3420b57cec5SDimitry Andric switch (Opcode) { 3430b57cec5SDimitry Andric default: llvm_unreachable("Unhandled opcode!"); 3440b57cec5SDimitry Andric case ARM::LDMIA_RET: 3450b57cec5SDimitry Andric case ARM::LDMIA: 3460b57cec5SDimitry Andric case ARM::LDMIA_UPD: 3470b57cec5SDimitry Andric case ARM::STMIA: 3480b57cec5SDimitry Andric case ARM::STMIA_UPD: 3490b57cec5SDimitry Andric case ARM::tLDMIA: 3500b57cec5SDimitry Andric case ARM::tLDMIA_UPD: 3510b57cec5SDimitry Andric case ARM::tSTMIA_UPD: 3520b57cec5SDimitry Andric case ARM::t2LDMIA_RET: 3530b57cec5SDimitry Andric case ARM::t2LDMIA: 3540b57cec5SDimitry Andric case ARM::t2LDMIA_UPD: 3550b57cec5SDimitry Andric case ARM::t2STMIA: 3560b57cec5SDimitry Andric case ARM::t2STMIA_UPD: 3570b57cec5SDimitry Andric case ARM::VLDMSIA: 3580b57cec5SDimitry Andric case ARM::VLDMSIA_UPD: 3590b57cec5SDimitry Andric case ARM::VSTMSIA: 3600b57cec5SDimitry Andric case ARM::VSTMSIA_UPD: 3610b57cec5SDimitry Andric case ARM::VLDMDIA: 3620b57cec5SDimitry Andric case ARM::VLDMDIA_UPD: 3630b57cec5SDimitry Andric case ARM::VSTMDIA: 3640b57cec5SDimitry Andric case ARM::VSTMDIA_UPD: 3650b57cec5SDimitry Andric return ARM_AM::ia; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric case ARM::LDMDA: 3680b57cec5SDimitry Andric case ARM::LDMDA_UPD: 3690b57cec5SDimitry Andric case ARM::STMDA: 3700b57cec5SDimitry Andric case ARM::STMDA_UPD: 3710b57cec5SDimitry Andric return ARM_AM::da; 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric case ARM::LDMDB: 3740b57cec5SDimitry Andric case ARM::LDMDB_UPD: 3750b57cec5SDimitry Andric case ARM::STMDB: 3760b57cec5SDimitry Andric case ARM::STMDB_UPD: 3770b57cec5SDimitry Andric case ARM::t2LDMDB: 3780b57cec5SDimitry Andric case ARM::t2LDMDB_UPD: 3790b57cec5SDimitry Andric case ARM::t2STMDB: 3800b57cec5SDimitry Andric case ARM::t2STMDB_UPD: 3810b57cec5SDimitry Andric case ARM::VLDMSDB_UPD: 3820b57cec5SDimitry Andric case ARM::VSTMSDB_UPD: 3830b57cec5SDimitry Andric case ARM::VLDMDDB_UPD: 3840b57cec5SDimitry Andric case ARM::VSTMDDB_UPD: 3850b57cec5SDimitry Andric return ARM_AM::db; 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric case ARM::LDMIB: 3880b57cec5SDimitry Andric case ARM::LDMIB_UPD: 3890b57cec5SDimitry Andric case ARM::STMIB: 3900b57cec5SDimitry Andric case ARM::STMIB_UPD: 3910b57cec5SDimitry Andric return ARM_AM::ib; 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric static bool isT1i32Load(unsigned Opc) { 3960b57cec5SDimitry Andric return Opc == ARM::tLDRi || Opc == ARM::tLDRspi; 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric static bool isT2i32Load(unsigned Opc) { 4000b57cec5SDimitry Andric return Opc == ARM::t2LDRi12 || Opc == ARM::t2LDRi8; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric static bool isi32Load(unsigned Opc) { 4040b57cec5SDimitry Andric return Opc == ARM::LDRi12 || isT1i32Load(Opc) || isT2i32Load(Opc) ; 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric static bool isT1i32Store(unsigned Opc) { 4080b57cec5SDimitry Andric return Opc == ARM::tSTRi || Opc == ARM::tSTRspi; 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric 4110b57cec5SDimitry Andric static bool isT2i32Store(unsigned Opc) { 4120b57cec5SDimitry Andric return Opc == ARM::t2STRi12 || Opc == ARM::t2STRi8; 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric static bool isi32Store(unsigned Opc) { 4160b57cec5SDimitry Andric return Opc == ARM::STRi12 || isT1i32Store(Opc) || isT2i32Store(Opc); 4170b57cec5SDimitry Andric } 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric static bool isLoadSingle(unsigned Opc) { 4200b57cec5SDimitry Andric return isi32Load(Opc) || Opc == ARM::VLDRS || Opc == ARM::VLDRD; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric static unsigned getImmScale(unsigned Opc) { 4240b57cec5SDimitry Andric switch (Opc) { 4250b57cec5SDimitry Andric default: llvm_unreachable("Unhandled opcode!"); 4260b57cec5SDimitry Andric case ARM::tLDRi: 4270b57cec5SDimitry Andric case ARM::tSTRi: 4280b57cec5SDimitry Andric case ARM::tLDRspi: 4290b57cec5SDimitry Andric case ARM::tSTRspi: 4300b57cec5SDimitry Andric return 1; 4310b57cec5SDimitry Andric case ARM::tLDRHi: 4320b57cec5SDimitry Andric case ARM::tSTRHi: 4330b57cec5SDimitry Andric return 2; 4340b57cec5SDimitry Andric case ARM::tLDRBi: 4350b57cec5SDimitry Andric case ARM::tSTRBi: 4360b57cec5SDimitry Andric return 4; 4370b57cec5SDimitry Andric } 4380b57cec5SDimitry Andric } 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric static unsigned getLSMultipleTransferSize(const MachineInstr *MI) { 4410b57cec5SDimitry Andric switch (MI->getOpcode()) { 4420b57cec5SDimitry Andric default: return 0; 4430b57cec5SDimitry Andric case ARM::LDRi12: 4440b57cec5SDimitry Andric case ARM::STRi12: 4450b57cec5SDimitry Andric case ARM::tLDRi: 4460b57cec5SDimitry Andric case ARM::tSTRi: 4470b57cec5SDimitry Andric case ARM::tLDRspi: 4480b57cec5SDimitry Andric case ARM::tSTRspi: 4490b57cec5SDimitry Andric case ARM::t2LDRi8: 4500b57cec5SDimitry Andric case ARM::t2LDRi12: 4510b57cec5SDimitry Andric case ARM::t2STRi8: 4520b57cec5SDimitry Andric case ARM::t2STRi12: 4530b57cec5SDimitry Andric case ARM::VLDRS: 4540b57cec5SDimitry Andric case ARM::VSTRS: 4550b57cec5SDimitry Andric return 4; 4560b57cec5SDimitry Andric case ARM::VLDRD: 4570b57cec5SDimitry Andric case ARM::VSTRD: 4580b57cec5SDimitry Andric return 8; 4590b57cec5SDimitry Andric case ARM::LDMIA: 4600b57cec5SDimitry Andric case ARM::LDMDA: 4610b57cec5SDimitry Andric case ARM::LDMDB: 4620b57cec5SDimitry Andric case ARM::LDMIB: 4630b57cec5SDimitry Andric case ARM::STMIA: 4640b57cec5SDimitry Andric case ARM::STMDA: 4650b57cec5SDimitry Andric case ARM::STMDB: 4660b57cec5SDimitry Andric case ARM::STMIB: 4670b57cec5SDimitry Andric case ARM::tLDMIA: 4680b57cec5SDimitry Andric case ARM::tLDMIA_UPD: 4690b57cec5SDimitry Andric case ARM::tSTMIA_UPD: 4700b57cec5SDimitry Andric case ARM::t2LDMIA: 4710b57cec5SDimitry Andric case ARM::t2LDMDB: 4720b57cec5SDimitry Andric case ARM::t2STMIA: 4730b57cec5SDimitry Andric case ARM::t2STMDB: 4740b57cec5SDimitry Andric case ARM::VLDMSIA: 4750b57cec5SDimitry Andric case ARM::VSTMSIA: 4760b57cec5SDimitry Andric return (MI->getNumOperands() - MI->getDesc().getNumOperands() + 1) * 4; 4770b57cec5SDimitry Andric case ARM::VLDMDIA: 4780b57cec5SDimitry Andric case ARM::VSTMDIA: 4790b57cec5SDimitry Andric return (MI->getNumOperands() - MI->getDesc().getNumOperands() + 1) * 8; 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric /// Update future uses of the base register with the offset introduced 4840b57cec5SDimitry Andric /// due to writeback. This function only works on Thumb1. 4850b57cec5SDimitry Andric void ARMLoadStoreOpt::UpdateBaseRegUses(MachineBasicBlock &MBB, 4860b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI, 4870b57cec5SDimitry Andric const DebugLoc &DL, unsigned Base, 4880b57cec5SDimitry Andric unsigned WordOffset, 4890b57cec5SDimitry Andric ARMCC::CondCodes Pred, 4900b57cec5SDimitry Andric unsigned PredReg) { 4910b57cec5SDimitry Andric assert(isThumb1 && "Can only update base register uses for Thumb1!"); 4920b57cec5SDimitry Andric // Start updating any instructions with immediate offsets. Insert a SUB before 4930b57cec5SDimitry Andric // the first non-updateable instruction (if any). 4940b57cec5SDimitry Andric for (; MBBI != MBB.end(); ++MBBI) { 4950b57cec5SDimitry Andric bool InsertSub = false; 4960b57cec5SDimitry Andric unsigned Opc = MBBI->getOpcode(); 4970b57cec5SDimitry Andric 498*0fca6ea1SDimitry Andric if (MBBI->readsRegister(Base, /*TRI=*/nullptr)) { 4990b57cec5SDimitry Andric int Offset; 5000b57cec5SDimitry Andric bool IsLoad = 5010b57cec5SDimitry Andric Opc == ARM::tLDRi || Opc == ARM::tLDRHi || Opc == ARM::tLDRBi; 5020b57cec5SDimitry Andric bool IsStore = 5030b57cec5SDimitry Andric Opc == ARM::tSTRi || Opc == ARM::tSTRHi || Opc == ARM::tSTRBi; 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric if (IsLoad || IsStore) { 5060b57cec5SDimitry Andric // Loads and stores with immediate offsets can be updated, but only if 5070b57cec5SDimitry Andric // the new offset isn't negative. 5080b57cec5SDimitry Andric // The MachineOperand containing the offset immediate is the last one 5090b57cec5SDimitry Andric // before predicates. 5100b57cec5SDimitry Andric MachineOperand &MO = 5110b57cec5SDimitry Andric MBBI->getOperand(MBBI->getDesc().getNumOperands() - 3); 5120b57cec5SDimitry Andric // The offsets are scaled by 1, 2 or 4 depending on the Opcode. 5130b57cec5SDimitry Andric Offset = MO.getImm() - WordOffset * getImmScale(Opc); 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric // If storing the base register, it needs to be reset first. 5168bcb0991SDimitry Andric Register InstrSrcReg = getLoadStoreRegOp(*MBBI).getReg(); 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric if (Offset >= 0 && !(IsStore && InstrSrcReg == Base)) 5190b57cec5SDimitry Andric MO.setImm(Offset); 5200b57cec5SDimitry Andric else 5210b57cec5SDimitry Andric InsertSub = true; 5220b57cec5SDimitry Andric } else if ((Opc == ARM::tSUBi8 || Opc == ARM::tADDi8) && 5230b57cec5SDimitry Andric !definesCPSR(*MBBI)) { 5240b57cec5SDimitry Andric // SUBS/ADDS using this register, with a dead def of the CPSR. 5250b57cec5SDimitry Andric // Merge it with the update; if the merged offset is too large, 5260b57cec5SDimitry Andric // insert a new sub instead. 5270b57cec5SDimitry Andric MachineOperand &MO = 5280b57cec5SDimitry Andric MBBI->getOperand(MBBI->getDesc().getNumOperands() - 3); 5290b57cec5SDimitry Andric Offset = (Opc == ARM::tSUBi8) ? 5300b57cec5SDimitry Andric MO.getImm() + WordOffset * 4 : 5310b57cec5SDimitry Andric MO.getImm() - WordOffset * 4 ; 5320b57cec5SDimitry Andric if (Offset >= 0 && TL->isLegalAddImmediate(Offset)) { 5330b57cec5SDimitry Andric // FIXME: Swap ADDS<->SUBS if Offset < 0, erase instruction if 5340b57cec5SDimitry Andric // Offset == 0. 5350b57cec5SDimitry Andric MO.setImm(Offset); 5360b57cec5SDimitry Andric // The base register has now been reset, so exit early. 5370b57cec5SDimitry Andric return; 5380b57cec5SDimitry Andric } else { 5390b57cec5SDimitry Andric InsertSub = true; 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric } else { 5420b57cec5SDimitry Andric // Can't update the instruction. 5430b57cec5SDimitry Andric InsertSub = true; 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric } else if (definesCPSR(*MBBI) || MBBI->isCall() || MBBI->isBranch()) { 5460b57cec5SDimitry Andric // Since SUBS sets the condition flags, we can't place the base reset 5470b57cec5SDimitry Andric // after an instruction that has a live CPSR def. 5480b57cec5SDimitry Andric // The base register might also contain an argument for a function call. 5490b57cec5SDimitry Andric InsertSub = true; 5500b57cec5SDimitry Andric } 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric if (InsertSub) { 5530b57cec5SDimitry Andric // An instruction above couldn't be updated, so insert a sub. 5540b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(ARM::tSUBi8), Base) 5550b57cec5SDimitry Andric .add(t1CondCodeOp(true)) 5560b57cec5SDimitry Andric .addReg(Base) 5570b57cec5SDimitry Andric .addImm(WordOffset * 4) 5580b57cec5SDimitry Andric .addImm(Pred) 5590b57cec5SDimitry Andric .addReg(PredReg); 5600b57cec5SDimitry Andric return; 5610b57cec5SDimitry Andric } 5620b57cec5SDimitry Andric 563*0fca6ea1SDimitry Andric if (MBBI->killsRegister(Base, /*TRI=*/nullptr) || 564*0fca6ea1SDimitry Andric MBBI->definesRegister(Base, /*TRI=*/nullptr)) 5650b57cec5SDimitry Andric // Register got killed. Stop updating. 5660b57cec5SDimitry Andric return; 5670b57cec5SDimitry Andric } 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric // End of block was reached. 570349cc55cSDimitry Andric if (!MBB.succ_empty()) { 5710b57cec5SDimitry Andric // FIXME: Because of a bug, live registers are sometimes missing from 5720b57cec5SDimitry Andric // the successor blocks' live-in sets. This means we can't trust that 5730b57cec5SDimitry Andric // information and *always* have to reset at the end of a block. 5740b57cec5SDimitry Andric // See PR21029. 5750b57cec5SDimitry Andric if (MBBI != MBB.end()) --MBBI; 5760b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(ARM::tSUBi8), Base) 5770b57cec5SDimitry Andric .add(t1CondCodeOp(true)) 5780b57cec5SDimitry Andric .addReg(Base) 5790b57cec5SDimitry Andric .addImm(WordOffset * 4) 5800b57cec5SDimitry Andric .addImm(Pred) 5810b57cec5SDimitry Andric .addReg(PredReg); 5820b57cec5SDimitry Andric } 5830b57cec5SDimitry Andric } 5840b57cec5SDimitry Andric 5850b57cec5SDimitry Andric /// Return the first register of class \p RegClass that is not in \p Regs. 5860b57cec5SDimitry Andric unsigned ARMLoadStoreOpt::findFreeReg(const TargetRegisterClass &RegClass) { 5870b57cec5SDimitry Andric if (!RegClassInfoValid) { 5880b57cec5SDimitry Andric RegClassInfo.runOnMachineFunction(*MF); 5890b57cec5SDimitry Andric RegClassInfoValid = true; 5900b57cec5SDimitry Andric } 5910b57cec5SDimitry Andric 5920b57cec5SDimitry Andric for (unsigned Reg : RegClassInfo.getOrder(&RegClass)) 593*0fca6ea1SDimitry Andric if (LiveRegs.available(Reg) && !MF->getRegInfo().isReserved(Reg)) 5940b57cec5SDimitry Andric return Reg; 5950b57cec5SDimitry Andric return 0; 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric /// Compute live registers just before instruction \p Before (in normal schedule 5990b57cec5SDimitry Andric /// direction). Computes backwards so multiple queries in the same block must 6000b57cec5SDimitry Andric /// come in reverse order. 6010b57cec5SDimitry Andric void ARMLoadStoreOpt::moveLiveRegsBefore(const MachineBasicBlock &MBB, 6020b57cec5SDimitry Andric MachineBasicBlock::const_iterator Before) { 6030b57cec5SDimitry Andric // Initialize if we never queried in this block. 6040b57cec5SDimitry Andric if (!LiveRegsValid) { 6050b57cec5SDimitry Andric LiveRegs.init(*TRI); 6060b57cec5SDimitry Andric LiveRegs.addLiveOuts(MBB); 6070b57cec5SDimitry Andric LiveRegPos = MBB.end(); 6080b57cec5SDimitry Andric LiveRegsValid = true; 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric // Move backward just before the "Before" position. 6110b57cec5SDimitry Andric while (LiveRegPos != Before) { 6120b57cec5SDimitry Andric --LiveRegPos; 6130b57cec5SDimitry Andric LiveRegs.stepBackward(*LiveRegPos); 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric } 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric static bool ContainsReg(const ArrayRef<std::pair<unsigned, bool>> &Regs, 6180b57cec5SDimitry Andric unsigned Reg) { 6190b57cec5SDimitry Andric for (const std::pair<unsigned, bool> &R : Regs) 6200b57cec5SDimitry Andric if (R.first == Reg) 6210b57cec5SDimitry Andric return true; 6220b57cec5SDimitry Andric return false; 6230b57cec5SDimitry Andric } 6240b57cec5SDimitry Andric 6250b57cec5SDimitry Andric /// Create and insert a LDM or STM with Base as base register and registers in 6260b57cec5SDimitry Andric /// Regs as the register operands that would be loaded / stored. It returns 6270b57cec5SDimitry Andric /// true if the transformation is done. 6280b57cec5SDimitry Andric MachineInstr *ARMLoadStoreOpt::CreateLoadStoreMulti( 6290b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, 6300b57cec5SDimitry Andric int Offset, unsigned Base, bool BaseKill, unsigned Opcode, 6310b57cec5SDimitry Andric ARMCC::CondCodes Pred, unsigned PredReg, const DebugLoc &DL, 6320b57cec5SDimitry Andric ArrayRef<std::pair<unsigned, bool>> Regs, 6330b57cec5SDimitry Andric ArrayRef<MachineInstr*> Instrs) { 6340b57cec5SDimitry Andric unsigned NumRegs = Regs.size(); 6350b57cec5SDimitry Andric assert(NumRegs > 1); 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric // For Thumb1 targets, it might be necessary to clobber the CPSR to merge. 6380b57cec5SDimitry Andric // Compute liveness information for that register to make the decision. 6390b57cec5SDimitry Andric bool SafeToClobberCPSR = !isThumb1 || 6400b57cec5SDimitry Andric (MBB.computeRegisterLiveness(TRI, ARM::CPSR, InsertBefore, 20) == 6410b57cec5SDimitry Andric MachineBasicBlock::LQR_Dead); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric bool Writeback = isThumb1; // Thumb1 LDM/STM have base reg writeback. 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric // Exception: If the base register is in the input reglist, Thumb1 LDM is 6460b57cec5SDimitry Andric // non-writeback. 6470b57cec5SDimitry Andric // It's also not possible to merge an STR of the base register in Thumb1. 6480b57cec5SDimitry Andric if (isThumb1 && ContainsReg(Regs, Base)) { 6490b57cec5SDimitry Andric assert(Base != ARM::SP && "Thumb1 does not allow SP in register list"); 6500b57cec5SDimitry Andric if (Opcode == ARM::tLDRi) 6510b57cec5SDimitry Andric Writeback = false; 6520b57cec5SDimitry Andric else if (Opcode == ARM::tSTRi) 6530b57cec5SDimitry Andric return nullptr; 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric ARM_AM::AMSubMode Mode = ARM_AM::ia; 6570b57cec5SDimitry Andric // VFP and Thumb2 do not support IB or DA modes. Thumb1 only supports IA. 6580b57cec5SDimitry Andric bool isNotVFP = isi32Load(Opcode) || isi32Store(Opcode); 6590b57cec5SDimitry Andric bool haveIBAndDA = isNotVFP && !isThumb2 && !isThumb1; 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric if (Offset == 4 && haveIBAndDA) { 6620b57cec5SDimitry Andric Mode = ARM_AM::ib; 6630b57cec5SDimitry Andric } else if (Offset == -4 * (int)NumRegs + 4 && haveIBAndDA) { 6640b57cec5SDimitry Andric Mode = ARM_AM::da; 6650b57cec5SDimitry Andric } else if (Offset == -4 * (int)NumRegs && isNotVFP && !isThumb1) { 6660b57cec5SDimitry Andric // VLDM/VSTM do not support DB mode without also updating the base reg. 6670b57cec5SDimitry Andric Mode = ARM_AM::db; 6680b57cec5SDimitry Andric } else if (Offset != 0 || Opcode == ARM::tLDRspi || Opcode == ARM::tSTRspi) { 6690b57cec5SDimitry Andric // Check if this is a supported opcode before inserting instructions to 6700b57cec5SDimitry Andric // calculate a new base register. 6710b57cec5SDimitry Andric if (!getLoadStoreMultipleOpcode(Opcode, Mode)) return nullptr; 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric // If starting offset isn't zero, insert a MI to materialize a new base. 6740b57cec5SDimitry Andric // But only do so if it is cost effective, i.e. merging more than two 6750b57cec5SDimitry Andric // loads / stores. 6760b57cec5SDimitry Andric if (NumRegs <= 2) 6770b57cec5SDimitry Andric return nullptr; 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric // On Thumb1, it's not worth materializing a new base register without 6800b57cec5SDimitry Andric // clobbering the CPSR (i.e. not using ADDS/SUBS). 6810b57cec5SDimitry Andric if (!SafeToClobberCPSR) 6820b57cec5SDimitry Andric return nullptr; 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric unsigned NewBase; 6850b57cec5SDimitry Andric if (isi32Load(Opcode)) { 6860b57cec5SDimitry Andric // If it is a load, then just use one of the destination registers 6870b57cec5SDimitry Andric // as the new base. Will no longer be writeback in Thumb1. 6880b57cec5SDimitry Andric NewBase = Regs[NumRegs-1].first; 6890b57cec5SDimitry Andric Writeback = false; 6900b57cec5SDimitry Andric } else { 6910b57cec5SDimitry Andric // Find a free register that we can use as scratch register. 6920b57cec5SDimitry Andric moveLiveRegsBefore(MBB, InsertBefore); 6930b57cec5SDimitry Andric // The merged instruction does not exist yet but will use several Regs if 6940b57cec5SDimitry Andric // it is a Store. 6950b57cec5SDimitry Andric if (!isLoadSingle(Opcode)) 6960b57cec5SDimitry Andric for (const std::pair<unsigned, bool> &R : Regs) 6970b57cec5SDimitry Andric LiveRegs.addReg(R.first); 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andric NewBase = findFreeReg(isThumb1 ? ARM::tGPRRegClass : ARM::GPRRegClass); 7000b57cec5SDimitry Andric if (NewBase == 0) 7010b57cec5SDimitry Andric return nullptr; 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric 704480093f4SDimitry Andric int BaseOpc = isThumb2 ? (BaseKill && Base == ARM::SP ? ARM::t2ADDspImm 705480093f4SDimitry Andric : ARM::t2ADDri) 706480093f4SDimitry Andric : (isThumb1 && Base == ARM::SP) 707480093f4SDimitry Andric ? ARM::tADDrSPi 708480093f4SDimitry Andric : (isThumb1 && Offset < 8) 709480093f4SDimitry Andric ? ARM::tADDi3 710480093f4SDimitry Andric : isThumb1 ? ARM::tADDi8 : ARM::ADDri; 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric if (Offset < 0) { 713480093f4SDimitry Andric // FIXME: There are no Thumb1 load/store instructions with negative 714480093f4SDimitry Andric // offsets. So the Base != ARM::SP might be unnecessary. 7150b57cec5SDimitry Andric Offset = -Offset; 716480093f4SDimitry Andric BaseOpc = isThumb2 ? (BaseKill && Base == ARM::SP ? ARM::t2SUBspImm 717480093f4SDimitry Andric : ARM::t2SUBri) 718480093f4SDimitry Andric : (isThumb1 && Offset < 8 && Base != ARM::SP) 719480093f4SDimitry Andric ? ARM::tSUBi3 720480093f4SDimitry Andric : isThumb1 ? ARM::tSUBi8 : ARM::SUBri; 7210b57cec5SDimitry Andric } 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric if (!TL->isLegalAddImmediate(Offset)) 7240b57cec5SDimitry Andric // FIXME: Try add with register operand? 7250b57cec5SDimitry Andric return nullptr; // Probably not worth it then. 7260b57cec5SDimitry Andric 7270b57cec5SDimitry Andric // We can only append a kill flag to the add/sub input if the value is not 7280b57cec5SDimitry Andric // used in the register list of the stm as well. 7290b57cec5SDimitry Andric bool KillOldBase = BaseKill && 7300b57cec5SDimitry Andric (!isi32Store(Opcode) || !ContainsReg(Regs, Base)); 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric if (isThumb1) { 7330b57cec5SDimitry Andric // Thumb1: depending on immediate size, use either 7340b57cec5SDimitry Andric // ADDS NewBase, Base, #imm3 7350b57cec5SDimitry Andric // or 7360b57cec5SDimitry Andric // MOV NewBase, Base 7370b57cec5SDimitry Andric // ADDS NewBase, #imm8. 7380b57cec5SDimitry Andric if (Base != NewBase && 7390b57cec5SDimitry Andric (BaseOpc == ARM::tADDi8 || BaseOpc == ARM::tSUBi8)) { 7400b57cec5SDimitry Andric // Need to insert a MOV to the new base first. 7410b57cec5SDimitry Andric if (isARMLowRegister(NewBase) && isARMLowRegister(Base) && 7420b57cec5SDimitry Andric !STI->hasV6Ops()) { 7430b57cec5SDimitry Andric // thumbv4t doesn't have lo->lo copies, and we can't predicate tMOVSr 7440b57cec5SDimitry Andric if (Pred != ARMCC::AL) 7450b57cec5SDimitry Andric return nullptr; 7460b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, DL, TII->get(ARM::tMOVSr), NewBase) 7470b57cec5SDimitry Andric .addReg(Base, getKillRegState(KillOldBase)); 7480b57cec5SDimitry Andric } else 7490b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, DL, TII->get(ARM::tMOVr), NewBase) 7500b57cec5SDimitry Andric .addReg(Base, getKillRegState(KillOldBase)) 7510b57cec5SDimitry Andric .add(predOps(Pred, PredReg)); 7520b57cec5SDimitry Andric 7530b57cec5SDimitry Andric // The following ADDS/SUBS becomes an update. 7540b57cec5SDimitry Andric Base = NewBase; 7550b57cec5SDimitry Andric KillOldBase = true; 7560b57cec5SDimitry Andric } 7570b57cec5SDimitry Andric if (BaseOpc == ARM::tADDrSPi) { 7580b57cec5SDimitry Andric assert(Offset % 4 == 0 && "tADDrSPi offset is scaled by 4"); 7590b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, DL, TII->get(BaseOpc), NewBase) 7600b57cec5SDimitry Andric .addReg(Base, getKillRegState(KillOldBase)) 7610b57cec5SDimitry Andric .addImm(Offset / 4) 7620b57cec5SDimitry Andric .add(predOps(Pred, PredReg)); 7630b57cec5SDimitry Andric } else 7640b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, DL, TII->get(BaseOpc), NewBase) 7650b57cec5SDimitry Andric .add(t1CondCodeOp(true)) 7660b57cec5SDimitry Andric .addReg(Base, getKillRegState(KillOldBase)) 7670b57cec5SDimitry Andric .addImm(Offset) 7680b57cec5SDimitry Andric .add(predOps(Pred, PredReg)); 7690b57cec5SDimitry Andric } else { 7700b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, DL, TII->get(BaseOpc), NewBase) 7710b57cec5SDimitry Andric .addReg(Base, getKillRegState(KillOldBase)) 7720b57cec5SDimitry Andric .addImm(Offset) 7730b57cec5SDimitry Andric .add(predOps(Pred, PredReg)) 7740b57cec5SDimitry Andric .add(condCodeOp()); 7750b57cec5SDimitry Andric } 7760b57cec5SDimitry Andric Base = NewBase; 7770b57cec5SDimitry Andric BaseKill = true; // New base is always killed straight away. 7780b57cec5SDimitry Andric } 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andric bool isDef = isLoadSingle(Opcode); 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric // Get LS multiple opcode. Note that for Thumb1 this might be an opcode with 7830b57cec5SDimitry Andric // base register writeback. 7840b57cec5SDimitry Andric Opcode = getLoadStoreMultipleOpcode(Opcode, Mode); 7850b57cec5SDimitry Andric if (!Opcode) 7860b57cec5SDimitry Andric return nullptr; 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric // Check if a Thumb1 LDM/STM merge is safe. This is the case if: 7890b57cec5SDimitry Andric // - There is no writeback (LDM of base register), 7900b57cec5SDimitry Andric // - the base register is killed by the merged instruction, 7910b57cec5SDimitry Andric // - or it's safe to overwrite the condition flags, i.e. to insert a SUBS 7920b57cec5SDimitry Andric // to reset the base register. 7930b57cec5SDimitry Andric // Otherwise, don't merge. 7940b57cec5SDimitry Andric // It's safe to return here since the code to materialize a new base register 7950b57cec5SDimitry Andric // above is also conditional on SafeToClobberCPSR. 7960b57cec5SDimitry Andric if (isThumb1 && !SafeToClobberCPSR && Writeback && !BaseKill) 7970b57cec5SDimitry Andric return nullptr; 7980b57cec5SDimitry Andric 7990b57cec5SDimitry Andric MachineInstrBuilder MIB; 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric if (Writeback) { 8020b57cec5SDimitry Andric assert(isThumb1 && "expected Writeback only inThumb1"); 8030b57cec5SDimitry Andric if (Opcode == ARM::tLDMIA) { 8040b57cec5SDimitry Andric assert(!(ContainsReg(Regs, Base)) && "Thumb1 can't LDM ! with Base in Regs"); 8050b57cec5SDimitry Andric // Update tLDMIA with writeback if necessary. 8060b57cec5SDimitry Andric Opcode = ARM::tLDMIA_UPD; 8070b57cec5SDimitry Andric } 8080b57cec5SDimitry Andric 8090b57cec5SDimitry Andric MIB = BuildMI(MBB, InsertBefore, DL, TII->get(Opcode)); 8100b57cec5SDimitry Andric 8110b57cec5SDimitry Andric // Thumb1: we might need to set base writeback when building the MI. 8120b57cec5SDimitry Andric MIB.addReg(Base, getDefRegState(true)) 8130b57cec5SDimitry Andric .addReg(Base, getKillRegState(BaseKill)); 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric // The base isn't dead after a merged instruction with writeback. 8160b57cec5SDimitry Andric // Insert a sub instruction after the newly formed instruction to reset. 8170b57cec5SDimitry Andric if (!BaseKill) 8180b57cec5SDimitry Andric UpdateBaseRegUses(MBB, InsertBefore, DL, Base, NumRegs, Pred, PredReg); 8190b57cec5SDimitry Andric } else { 8200b57cec5SDimitry Andric // No writeback, simply build the MachineInstr. 8210b57cec5SDimitry Andric MIB = BuildMI(MBB, InsertBefore, DL, TII->get(Opcode)); 8220b57cec5SDimitry Andric MIB.addReg(Base, getKillRegState(BaseKill)); 8230b57cec5SDimitry Andric } 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric MIB.addImm(Pred).addReg(PredReg); 8260b57cec5SDimitry Andric 8270b57cec5SDimitry Andric for (const std::pair<unsigned, bool> &R : Regs) 8280b57cec5SDimitry Andric MIB.addReg(R.first, getDefRegState(isDef) | getKillRegState(R.second)); 8290b57cec5SDimitry Andric 8300b57cec5SDimitry Andric MIB.cloneMergedMemRefs(Instrs); 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric return MIB.getInstr(); 8330b57cec5SDimitry Andric } 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric MachineInstr *ARMLoadStoreOpt::CreateLoadStoreDouble( 8360b57cec5SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator InsertBefore, 8370b57cec5SDimitry Andric int Offset, unsigned Base, bool BaseKill, unsigned Opcode, 8380b57cec5SDimitry Andric ARMCC::CondCodes Pred, unsigned PredReg, const DebugLoc &DL, 8390b57cec5SDimitry Andric ArrayRef<std::pair<unsigned, bool>> Regs, 8400b57cec5SDimitry Andric ArrayRef<MachineInstr*> Instrs) const { 8410b57cec5SDimitry Andric bool IsLoad = isi32Load(Opcode); 8420b57cec5SDimitry Andric assert((IsLoad || isi32Store(Opcode)) && "Must have integer load or store"); 8430b57cec5SDimitry Andric unsigned LoadStoreOpcode = IsLoad ? ARM::t2LDRDi8 : ARM::t2STRDi8; 8440b57cec5SDimitry Andric 8450b57cec5SDimitry Andric assert(Regs.size() == 2); 8460b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, InsertBefore, DL, 8470b57cec5SDimitry Andric TII->get(LoadStoreOpcode)); 8480b57cec5SDimitry Andric if (IsLoad) { 8490b57cec5SDimitry Andric MIB.addReg(Regs[0].first, RegState::Define) 8500b57cec5SDimitry Andric .addReg(Regs[1].first, RegState::Define); 8510b57cec5SDimitry Andric } else { 8520b57cec5SDimitry Andric MIB.addReg(Regs[0].first, getKillRegState(Regs[0].second)) 8530b57cec5SDimitry Andric .addReg(Regs[1].first, getKillRegState(Regs[1].second)); 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric MIB.addReg(Base).addImm(Offset).addImm(Pred).addReg(PredReg); 8560b57cec5SDimitry Andric MIB.cloneMergedMemRefs(Instrs); 8570b57cec5SDimitry Andric return MIB.getInstr(); 8580b57cec5SDimitry Andric } 8590b57cec5SDimitry Andric 8600b57cec5SDimitry Andric /// Call MergeOps and update MemOps and merges accordingly on success. 8610b57cec5SDimitry Andric MachineInstr *ARMLoadStoreOpt::MergeOpsUpdate(const MergeCandidate &Cand) { 8620b57cec5SDimitry Andric const MachineInstr *First = Cand.Instrs.front(); 8630b57cec5SDimitry Andric unsigned Opcode = First->getOpcode(); 8640b57cec5SDimitry Andric bool IsLoad = isLoadSingle(Opcode); 8650b57cec5SDimitry Andric SmallVector<std::pair<unsigned, bool>, 8> Regs; 8660b57cec5SDimitry Andric SmallVector<unsigned, 4> ImpDefs; 8670b57cec5SDimitry Andric DenseSet<unsigned> KilledRegs; 8680b57cec5SDimitry Andric DenseSet<unsigned> UsedRegs; 8690b57cec5SDimitry Andric // Determine list of registers and list of implicit super-register defs. 8700b57cec5SDimitry Andric for (const MachineInstr *MI : Cand.Instrs) { 8710b57cec5SDimitry Andric const MachineOperand &MO = getLoadStoreRegOp(*MI); 8728bcb0991SDimitry Andric Register Reg = MO.getReg(); 8730b57cec5SDimitry Andric bool IsKill = MO.isKill(); 8740b57cec5SDimitry Andric if (IsKill) 8750b57cec5SDimitry Andric KilledRegs.insert(Reg); 8760b57cec5SDimitry Andric Regs.push_back(std::make_pair(Reg, IsKill)); 8770b57cec5SDimitry Andric UsedRegs.insert(Reg); 8780b57cec5SDimitry Andric 8790b57cec5SDimitry Andric if (IsLoad) { 8800b57cec5SDimitry Andric // Collect any implicit defs of super-registers, after merging we can't 8810b57cec5SDimitry Andric // be sure anymore that we properly preserved these live ranges and must 8820b57cec5SDimitry Andric // removed these implicit operands. 8830b57cec5SDimitry Andric for (const MachineOperand &MO : MI->implicit_operands()) { 8840b57cec5SDimitry Andric if (!MO.isReg() || !MO.isDef() || MO.isDead()) 8850b57cec5SDimitry Andric continue; 8860b57cec5SDimitry Andric assert(MO.isImplicit()); 8878bcb0991SDimitry Andric Register DefReg = MO.getReg(); 8880b57cec5SDimitry Andric 8890b57cec5SDimitry Andric if (is_contained(ImpDefs, DefReg)) 8900b57cec5SDimitry Andric continue; 8910b57cec5SDimitry Andric // We can ignore cases where the super-reg is read and written. 892*0fca6ea1SDimitry Andric if (MI->readsRegister(DefReg, /*TRI=*/nullptr)) 8930b57cec5SDimitry Andric continue; 8940b57cec5SDimitry Andric ImpDefs.push_back(DefReg); 8950b57cec5SDimitry Andric } 8960b57cec5SDimitry Andric } 8970b57cec5SDimitry Andric } 8980b57cec5SDimitry Andric 8990b57cec5SDimitry Andric // Attempt the merge. 9000b57cec5SDimitry Andric using iterator = MachineBasicBlock::iterator; 9010b57cec5SDimitry Andric 9020b57cec5SDimitry Andric MachineInstr *LatestMI = Cand.Instrs[Cand.LatestMIIdx]; 9030b57cec5SDimitry Andric iterator InsertBefore = std::next(iterator(LatestMI)); 9040b57cec5SDimitry Andric MachineBasicBlock &MBB = *LatestMI->getParent(); 9050b57cec5SDimitry Andric unsigned Offset = getMemoryOpOffset(*First); 9068bcb0991SDimitry Andric Register Base = getLoadStoreBaseOp(*First).getReg(); 907*0fca6ea1SDimitry Andric bool BaseKill = LatestMI->killsRegister(Base, /*TRI=*/nullptr); 9085ffd83dbSDimitry Andric Register PredReg; 9090b57cec5SDimitry Andric ARMCC::CondCodes Pred = getInstrPredicate(*First, PredReg); 9100b57cec5SDimitry Andric DebugLoc DL = First->getDebugLoc(); 9110b57cec5SDimitry Andric MachineInstr *Merged = nullptr; 9120b57cec5SDimitry Andric if (Cand.CanMergeToLSDouble) 9130b57cec5SDimitry Andric Merged = CreateLoadStoreDouble(MBB, InsertBefore, Offset, Base, BaseKill, 9140b57cec5SDimitry Andric Opcode, Pred, PredReg, DL, Regs, 9150b57cec5SDimitry Andric Cand.Instrs); 9160b57cec5SDimitry Andric if (!Merged && Cand.CanMergeToLSMulti) 9170b57cec5SDimitry Andric Merged = CreateLoadStoreMulti(MBB, InsertBefore, Offset, Base, BaseKill, 9180b57cec5SDimitry Andric Opcode, Pred, PredReg, DL, Regs, Cand.Instrs); 9190b57cec5SDimitry Andric if (!Merged) 9200b57cec5SDimitry Andric return nullptr; 9210b57cec5SDimitry Andric 9220b57cec5SDimitry Andric // Determine earliest instruction that will get removed. We then keep an 9230b57cec5SDimitry Andric // iterator just above it so the following erases don't invalidated it. 9240b57cec5SDimitry Andric iterator EarliestI(Cand.Instrs[Cand.EarliestMIIdx]); 9250b57cec5SDimitry Andric bool EarliestAtBegin = false; 9260b57cec5SDimitry Andric if (EarliestI == MBB.begin()) { 9270b57cec5SDimitry Andric EarliestAtBegin = true; 9280b57cec5SDimitry Andric } else { 9290b57cec5SDimitry Andric EarliestI = std::prev(EarliestI); 9300b57cec5SDimitry Andric } 9310b57cec5SDimitry Andric 9320b57cec5SDimitry Andric // Remove instructions which have been merged. 9330b57cec5SDimitry Andric for (MachineInstr *MI : Cand.Instrs) 9340b57cec5SDimitry Andric MBB.erase(MI); 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric // Determine range between the earliest removed instruction and the new one. 9370b57cec5SDimitry Andric if (EarliestAtBegin) 9380b57cec5SDimitry Andric EarliestI = MBB.begin(); 9390b57cec5SDimitry Andric else 9400b57cec5SDimitry Andric EarliestI = std::next(EarliestI); 9410b57cec5SDimitry Andric auto FixupRange = make_range(EarliestI, iterator(Merged)); 9420b57cec5SDimitry Andric 9430b57cec5SDimitry Andric if (isLoadSingle(Opcode)) { 9440b57cec5SDimitry Andric // If the previous loads defined a super-reg, then we have to mark earlier 9450b57cec5SDimitry Andric // operands undef; Replicate the super-reg def on the merged instruction. 9460b57cec5SDimitry Andric for (MachineInstr &MI : FixupRange) { 9470b57cec5SDimitry Andric for (unsigned &ImpDefReg : ImpDefs) { 9480b57cec5SDimitry Andric for (MachineOperand &MO : MI.implicit_operands()) { 9490b57cec5SDimitry Andric if (!MO.isReg() || MO.getReg() != ImpDefReg) 9500b57cec5SDimitry Andric continue; 9510b57cec5SDimitry Andric if (MO.readsReg()) 9520b57cec5SDimitry Andric MO.setIsUndef(); 9530b57cec5SDimitry Andric else if (MO.isDef()) 9540b57cec5SDimitry Andric ImpDefReg = 0; 9550b57cec5SDimitry Andric } 9560b57cec5SDimitry Andric } 9570b57cec5SDimitry Andric } 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric MachineInstrBuilder MIB(*Merged->getParent()->getParent(), Merged); 9600b57cec5SDimitry Andric for (unsigned ImpDef : ImpDefs) 9610b57cec5SDimitry Andric MIB.addReg(ImpDef, RegState::ImplicitDefine); 9620b57cec5SDimitry Andric } else { 9630b57cec5SDimitry Andric // Remove kill flags: We are possibly storing the values later now. 9640b57cec5SDimitry Andric assert(isi32Store(Opcode) || Opcode == ARM::VSTRS || Opcode == ARM::VSTRD); 9650b57cec5SDimitry Andric for (MachineInstr &MI : FixupRange) { 9660b57cec5SDimitry Andric for (MachineOperand &MO : MI.uses()) { 9670b57cec5SDimitry Andric if (!MO.isReg() || !MO.isKill()) 9680b57cec5SDimitry Andric continue; 9690b57cec5SDimitry Andric if (UsedRegs.count(MO.getReg())) 9700b57cec5SDimitry Andric MO.setIsKill(false); 9710b57cec5SDimitry Andric } 9720b57cec5SDimitry Andric } 9730b57cec5SDimitry Andric assert(ImpDefs.empty()); 9740b57cec5SDimitry Andric } 9750b57cec5SDimitry Andric 9760b57cec5SDimitry Andric return Merged; 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric static bool isValidLSDoubleOffset(int Offset) { 9800b57cec5SDimitry Andric unsigned Value = abs(Offset); 9810b57cec5SDimitry Andric // t2LDRDi8/t2STRDi8 supports an 8 bit immediate which is internally 9820b57cec5SDimitry Andric // multiplied by 4. 9830b57cec5SDimitry Andric return (Value % 4) == 0 && Value < 1024; 9840b57cec5SDimitry Andric } 9850b57cec5SDimitry Andric 9860b57cec5SDimitry Andric /// Return true for loads/stores that can be combined to a double/multi 9870b57cec5SDimitry Andric /// operation without increasing the requirements for alignment. 9880b57cec5SDimitry Andric static bool mayCombineMisaligned(const TargetSubtargetInfo &STI, 9890b57cec5SDimitry Andric const MachineInstr &MI) { 9900b57cec5SDimitry Andric // vldr/vstr trap on misaligned pointers anyway, forming vldm makes no 9910b57cec5SDimitry Andric // difference. 9920b57cec5SDimitry Andric unsigned Opcode = MI.getOpcode(); 9930b57cec5SDimitry Andric if (!isi32Load(Opcode) && !isi32Store(Opcode)) 9940b57cec5SDimitry Andric return true; 9950b57cec5SDimitry Andric 9960b57cec5SDimitry Andric // Stack pointer alignment is out of the programmers control so we can trust 9970b57cec5SDimitry Andric // SP-relative loads/stores. 9980b57cec5SDimitry Andric if (getLoadStoreBaseOp(MI).getReg() == ARM::SP && 9995ffd83dbSDimitry Andric STI.getFrameLowering()->getTransientStackAlign() >= Align(4)) 10000b57cec5SDimitry Andric return true; 10010b57cec5SDimitry Andric return false; 10020b57cec5SDimitry Andric } 10030b57cec5SDimitry Andric 10040b57cec5SDimitry Andric /// Find candidates for load/store multiple merge in list of MemOpQueueEntries. 10050b57cec5SDimitry Andric void ARMLoadStoreOpt::FormCandidates(const MemOpQueue &MemOps) { 10060b57cec5SDimitry Andric const MachineInstr *FirstMI = MemOps[0].MI; 10070b57cec5SDimitry Andric unsigned Opcode = FirstMI->getOpcode(); 10080b57cec5SDimitry Andric bool isNotVFP = isi32Load(Opcode) || isi32Store(Opcode); 10090b57cec5SDimitry Andric unsigned Size = getLSMultipleTransferSize(FirstMI); 10100b57cec5SDimitry Andric 10110b57cec5SDimitry Andric unsigned SIndex = 0; 10120b57cec5SDimitry Andric unsigned EIndex = MemOps.size(); 10130b57cec5SDimitry Andric do { 10140b57cec5SDimitry Andric // Look at the first instruction. 10150b57cec5SDimitry Andric const MachineInstr *MI = MemOps[SIndex].MI; 10160b57cec5SDimitry Andric int Offset = MemOps[SIndex].Offset; 10170b57cec5SDimitry Andric const MachineOperand &PMO = getLoadStoreRegOp(*MI); 10188bcb0991SDimitry Andric Register PReg = PMO.getReg(); 10190b57cec5SDimitry Andric unsigned PRegNum = PMO.isUndef() ? std::numeric_limits<unsigned>::max() 10200b57cec5SDimitry Andric : TRI->getEncodingValue(PReg); 10210b57cec5SDimitry Andric unsigned Latest = SIndex; 10220b57cec5SDimitry Andric unsigned Earliest = SIndex; 10230b57cec5SDimitry Andric unsigned Count = 1; 10240b57cec5SDimitry Andric bool CanMergeToLSDouble = 10250b57cec5SDimitry Andric STI->isThumb2() && isNotVFP && isValidLSDoubleOffset(Offset); 10260b57cec5SDimitry Andric // ARM errata 602117: LDRD with base in list may result in incorrect base 10270b57cec5SDimitry Andric // register when interrupted or faulted. 10280b57cec5SDimitry Andric if (STI->isCortexM3() && isi32Load(Opcode) && 10290b57cec5SDimitry Andric PReg == getLoadStoreBaseOp(*MI).getReg()) 10300b57cec5SDimitry Andric CanMergeToLSDouble = false; 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric bool CanMergeToLSMulti = true; 10330b57cec5SDimitry Andric // On swift vldm/vstm starting with an odd register number as that needs 10340b57cec5SDimitry Andric // more uops than single vldrs. 10350b57cec5SDimitry Andric if (STI->hasSlowOddRegister() && !isNotVFP && (PRegNum % 2) == 1) 10360b57cec5SDimitry Andric CanMergeToLSMulti = false; 10370b57cec5SDimitry Andric 10380b57cec5SDimitry Andric // LDRD/STRD do not allow SP/PC. LDM/STM do not support it or have it 10390b57cec5SDimitry Andric // deprecated; LDM to PC is fine but cannot happen here. 10400b57cec5SDimitry Andric if (PReg == ARM::SP || PReg == ARM::PC) 10410b57cec5SDimitry Andric CanMergeToLSMulti = CanMergeToLSDouble = false; 10420b57cec5SDimitry Andric 10430b57cec5SDimitry Andric // Should we be conservative? 10440b57cec5SDimitry Andric if (AssumeMisalignedLoadStores && !mayCombineMisaligned(*STI, *MI)) 10450b57cec5SDimitry Andric CanMergeToLSMulti = CanMergeToLSDouble = false; 10460b57cec5SDimitry Andric 10470b57cec5SDimitry Andric // vldm / vstm limit are 32 for S variants, 16 for D variants. 10480b57cec5SDimitry Andric unsigned Limit; 10490b57cec5SDimitry Andric switch (Opcode) { 10500b57cec5SDimitry Andric default: 10510b57cec5SDimitry Andric Limit = UINT_MAX; 10520b57cec5SDimitry Andric break; 10530b57cec5SDimitry Andric case ARM::VLDRD: 10540b57cec5SDimitry Andric case ARM::VSTRD: 10550b57cec5SDimitry Andric Limit = 16; 10560b57cec5SDimitry Andric break; 10570b57cec5SDimitry Andric } 10580b57cec5SDimitry Andric 10590b57cec5SDimitry Andric // Merge following instructions where possible. 10600b57cec5SDimitry Andric for (unsigned I = SIndex+1; I < EIndex; ++I, ++Count) { 10610b57cec5SDimitry Andric int NewOffset = MemOps[I].Offset; 10620b57cec5SDimitry Andric if (NewOffset != Offset + (int)Size) 10630b57cec5SDimitry Andric break; 10640b57cec5SDimitry Andric const MachineOperand &MO = getLoadStoreRegOp(*MemOps[I].MI); 10658bcb0991SDimitry Andric Register Reg = MO.getReg(); 10660b57cec5SDimitry Andric if (Reg == ARM::SP || Reg == ARM::PC) 10670b57cec5SDimitry Andric break; 10680b57cec5SDimitry Andric if (Count == Limit) 10690b57cec5SDimitry Andric break; 10700b57cec5SDimitry Andric 10710b57cec5SDimitry Andric // See if the current load/store may be part of a multi load/store. 10720b57cec5SDimitry Andric unsigned RegNum = MO.isUndef() ? std::numeric_limits<unsigned>::max() 10730b57cec5SDimitry Andric : TRI->getEncodingValue(Reg); 10740b57cec5SDimitry Andric bool PartOfLSMulti = CanMergeToLSMulti; 10750b57cec5SDimitry Andric if (PartOfLSMulti) { 10760b57cec5SDimitry Andric // Register numbers must be in ascending order. 10770b57cec5SDimitry Andric if (RegNum <= PRegNum) 10780b57cec5SDimitry Andric PartOfLSMulti = false; 10790b57cec5SDimitry Andric // For VFP / NEON load/store multiples, the registers must be 10800b57cec5SDimitry Andric // consecutive and within the limit on the number of registers per 10810b57cec5SDimitry Andric // instruction. 10820b57cec5SDimitry Andric else if (!isNotVFP && RegNum != PRegNum+1) 10830b57cec5SDimitry Andric PartOfLSMulti = false; 10840b57cec5SDimitry Andric } 10850b57cec5SDimitry Andric // See if the current load/store may be part of a double load/store. 10860b57cec5SDimitry Andric bool PartOfLSDouble = CanMergeToLSDouble && Count <= 1; 10870b57cec5SDimitry Andric 10880b57cec5SDimitry Andric if (!PartOfLSMulti && !PartOfLSDouble) 10890b57cec5SDimitry Andric break; 10900b57cec5SDimitry Andric CanMergeToLSMulti &= PartOfLSMulti; 10910b57cec5SDimitry Andric CanMergeToLSDouble &= PartOfLSDouble; 10920b57cec5SDimitry Andric // Track MemOp with latest and earliest position (Positions are 10930b57cec5SDimitry Andric // counted in reverse). 10940b57cec5SDimitry Andric unsigned Position = MemOps[I].Position; 10950b57cec5SDimitry Andric if (Position < MemOps[Latest].Position) 10960b57cec5SDimitry Andric Latest = I; 10970b57cec5SDimitry Andric else if (Position > MemOps[Earliest].Position) 10980b57cec5SDimitry Andric Earliest = I; 10990b57cec5SDimitry Andric // Prepare for next MemOp. 11000b57cec5SDimitry Andric Offset += Size; 11010b57cec5SDimitry Andric PRegNum = RegNum; 11020b57cec5SDimitry Andric } 11030b57cec5SDimitry Andric 11040b57cec5SDimitry Andric // Form a candidate from the Ops collected so far. 11050b57cec5SDimitry Andric MergeCandidate *Candidate = new(Allocator.Allocate()) MergeCandidate; 11060b57cec5SDimitry Andric for (unsigned C = SIndex, CE = SIndex + Count; C < CE; ++C) 11070b57cec5SDimitry Andric Candidate->Instrs.push_back(MemOps[C].MI); 11080b57cec5SDimitry Andric Candidate->LatestMIIdx = Latest - SIndex; 11090b57cec5SDimitry Andric Candidate->EarliestMIIdx = Earliest - SIndex; 11100b57cec5SDimitry Andric Candidate->InsertPos = MemOps[Latest].Position; 11110b57cec5SDimitry Andric if (Count == 1) 11120b57cec5SDimitry Andric CanMergeToLSMulti = CanMergeToLSDouble = false; 11130b57cec5SDimitry Andric Candidate->CanMergeToLSMulti = CanMergeToLSMulti; 11140b57cec5SDimitry Andric Candidate->CanMergeToLSDouble = CanMergeToLSDouble; 11150b57cec5SDimitry Andric Candidates.push_back(Candidate); 11160b57cec5SDimitry Andric // Continue after the chain. 11170b57cec5SDimitry Andric SIndex += Count; 11180b57cec5SDimitry Andric } while (SIndex < EIndex); 11190b57cec5SDimitry Andric } 11200b57cec5SDimitry Andric 11210b57cec5SDimitry Andric static unsigned getUpdatingLSMultipleOpcode(unsigned Opc, 11220b57cec5SDimitry Andric ARM_AM::AMSubMode Mode) { 11230b57cec5SDimitry Andric switch (Opc) { 11240b57cec5SDimitry Andric default: llvm_unreachable("Unhandled opcode!"); 11250b57cec5SDimitry Andric case ARM::LDMIA: 11260b57cec5SDimitry Andric case ARM::LDMDA: 11270b57cec5SDimitry Andric case ARM::LDMDB: 11280b57cec5SDimitry Andric case ARM::LDMIB: 11290b57cec5SDimitry Andric switch (Mode) { 11300b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11310b57cec5SDimitry Andric case ARM_AM::ia: return ARM::LDMIA_UPD; 11320b57cec5SDimitry Andric case ARM_AM::ib: return ARM::LDMIB_UPD; 11330b57cec5SDimitry Andric case ARM_AM::da: return ARM::LDMDA_UPD; 11340b57cec5SDimitry Andric case ARM_AM::db: return ARM::LDMDB_UPD; 11350b57cec5SDimitry Andric } 11360b57cec5SDimitry Andric case ARM::STMIA: 11370b57cec5SDimitry Andric case ARM::STMDA: 11380b57cec5SDimitry Andric case ARM::STMDB: 11390b57cec5SDimitry Andric case ARM::STMIB: 11400b57cec5SDimitry Andric switch (Mode) { 11410b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11420b57cec5SDimitry Andric case ARM_AM::ia: return ARM::STMIA_UPD; 11430b57cec5SDimitry Andric case ARM_AM::ib: return ARM::STMIB_UPD; 11440b57cec5SDimitry Andric case ARM_AM::da: return ARM::STMDA_UPD; 11450b57cec5SDimitry Andric case ARM_AM::db: return ARM::STMDB_UPD; 11460b57cec5SDimitry Andric } 11470b57cec5SDimitry Andric case ARM::t2LDMIA: 11480b57cec5SDimitry Andric case ARM::t2LDMDB: 11490b57cec5SDimitry Andric switch (Mode) { 11500b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11510b57cec5SDimitry Andric case ARM_AM::ia: return ARM::t2LDMIA_UPD; 11520b57cec5SDimitry Andric case ARM_AM::db: return ARM::t2LDMDB_UPD; 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric case ARM::t2STMIA: 11550b57cec5SDimitry Andric case ARM::t2STMDB: 11560b57cec5SDimitry Andric switch (Mode) { 11570b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11580b57cec5SDimitry Andric case ARM_AM::ia: return ARM::t2STMIA_UPD; 11590b57cec5SDimitry Andric case ARM_AM::db: return ARM::t2STMDB_UPD; 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric case ARM::VLDMSIA: 11620b57cec5SDimitry Andric switch (Mode) { 11630b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11640b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VLDMSIA_UPD; 11650b57cec5SDimitry Andric case ARM_AM::db: return ARM::VLDMSDB_UPD; 11660b57cec5SDimitry Andric } 11670b57cec5SDimitry Andric case ARM::VLDMDIA: 11680b57cec5SDimitry Andric switch (Mode) { 11690b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11700b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VLDMDIA_UPD; 11710b57cec5SDimitry Andric case ARM_AM::db: return ARM::VLDMDDB_UPD; 11720b57cec5SDimitry Andric } 11730b57cec5SDimitry Andric case ARM::VSTMSIA: 11740b57cec5SDimitry Andric switch (Mode) { 11750b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11760b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VSTMSIA_UPD; 11770b57cec5SDimitry Andric case ARM_AM::db: return ARM::VSTMSDB_UPD; 11780b57cec5SDimitry Andric } 11790b57cec5SDimitry Andric case ARM::VSTMDIA: 11800b57cec5SDimitry Andric switch (Mode) { 11810b57cec5SDimitry Andric default: llvm_unreachable("Unhandled submode!"); 11820b57cec5SDimitry Andric case ARM_AM::ia: return ARM::VSTMDIA_UPD; 11830b57cec5SDimitry Andric case ARM_AM::db: return ARM::VSTMDDB_UPD; 11840b57cec5SDimitry Andric } 11850b57cec5SDimitry Andric } 11860b57cec5SDimitry Andric } 11870b57cec5SDimitry Andric 11880b57cec5SDimitry Andric /// Check if the given instruction increments or decrements a register and 11890b57cec5SDimitry Andric /// return the amount it is incremented/decremented. Returns 0 if the CPSR flags 11900b57cec5SDimitry Andric /// generated by the instruction are possibly read as well. 11915ffd83dbSDimitry Andric static int isIncrementOrDecrement(const MachineInstr &MI, Register Reg, 11925ffd83dbSDimitry Andric ARMCC::CondCodes Pred, Register PredReg) { 11930b57cec5SDimitry Andric bool CheckCPSRDef; 11940b57cec5SDimitry Andric int Scale; 11950b57cec5SDimitry Andric switch (MI.getOpcode()) { 11960b57cec5SDimitry Andric case ARM::tADDi8: Scale = 4; CheckCPSRDef = true; break; 11970b57cec5SDimitry Andric case ARM::tSUBi8: Scale = -4; CheckCPSRDef = true; break; 11980b57cec5SDimitry Andric case ARM::t2SUBri: 1199480093f4SDimitry Andric case ARM::t2SUBspImm: 12000b57cec5SDimitry Andric case ARM::SUBri: Scale = -1; CheckCPSRDef = true; break; 12010b57cec5SDimitry Andric case ARM::t2ADDri: 1202480093f4SDimitry Andric case ARM::t2ADDspImm: 12030b57cec5SDimitry Andric case ARM::ADDri: Scale = 1; CheckCPSRDef = true; break; 12040b57cec5SDimitry Andric case ARM::tADDspi: Scale = 4; CheckCPSRDef = false; break; 12050b57cec5SDimitry Andric case ARM::tSUBspi: Scale = -4; CheckCPSRDef = false; break; 12060b57cec5SDimitry Andric default: return 0; 12070b57cec5SDimitry Andric } 12080b57cec5SDimitry Andric 12095ffd83dbSDimitry Andric Register MIPredReg; 12100b57cec5SDimitry Andric if (MI.getOperand(0).getReg() != Reg || 12110b57cec5SDimitry Andric MI.getOperand(1).getReg() != Reg || 12120b57cec5SDimitry Andric getInstrPredicate(MI, MIPredReg) != Pred || 12130b57cec5SDimitry Andric MIPredReg != PredReg) 12140b57cec5SDimitry Andric return 0; 12150b57cec5SDimitry Andric 12160b57cec5SDimitry Andric if (CheckCPSRDef && definesCPSR(MI)) 12170b57cec5SDimitry Andric return 0; 12180b57cec5SDimitry Andric return MI.getOperand(2).getImm() * Scale; 12190b57cec5SDimitry Andric } 12200b57cec5SDimitry Andric 12210b57cec5SDimitry Andric /// Searches for an increment or decrement of \p Reg before \p MBBI. 12220b57cec5SDimitry Andric static MachineBasicBlock::iterator 12235ffd83dbSDimitry Andric findIncDecBefore(MachineBasicBlock::iterator MBBI, Register Reg, 12245ffd83dbSDimitry Andric ARMCC::CondCodes Pred, Register PredReg, int &Offset) { 12250b57cec5SDimitry Andric Offset = 0; 12260b57cec5SDimitry Andric MachineBasicBlock &MBB = *MBBI->getParent(); 12270b57cec5SDimitry Andric MachineBasicBlock::iterator BeginMBBI = MBB.begin(); 12280b57cec5SDimitry Andric MachineBasicBlock::iterator EndMBBI = MBB.end(); 12290b57cec5SDimitry Andric if (MBBI == BeginMBBI) 12300b57cec5SDimitry Andric return EndMBBI; 12310b57cec5SDimitry Andric 12320b57cec5SDimitry Andric // Skip debug values. 12330b57cec5SDimitry Andric MachineBasicBlock::iterator PrevMBBI = std::prev(MBBI); 12340b57cec5SDimitry Andric while (PrevMBBI->isDebugInstr() && PrevMBBI != BeginMBBI) 12350b57cec5SDimitry Andric --PrevMBBI; 12360b57cec5SDimitry Andric 12370b57cec5SDimitry Andric Offset = isIncrementOrDecrement(*PrevMBBI, Reg, Pred, PredReg); 12380b57cec5SDimitry Andric return Offset == 0 ? EndMBBI : PrevMBBI; 12390b57cec5SDimitry Andric } 12400b57cec5SDimitry Andric 12410b57cec5SDimitry Andric /// Searches for a increment or decrement of \p Reg after \p MBBI. 12420b57cec5SDimitry Andric static MachineBasicBlock::iterator 12435ffd83dbSDimitry Andric findIncDecAfter(MachineBasicBlock::iterator MBBI, Register Reg, 1244fe6060f1SDimitry Andric ARMCC::CondCodes Pred, Register PredReg, int &Offset, 1245fe6060f1SDimitry Andric const TargetRegisterInfo *TRI) { 12460b57cec5SDimitry Andric Offset = 0; 12470b57cec5SDimitry Andric MachineBasicBlock &MBB = *MBBI->getParent(); 12480b57cec5SDimitry Andric MachineBasicBlock::iterator EndMBBI = MBB.end(); 12490b57cec5SDimitry Andric MachineBasicBlock::iterator NextMBBI = std::next(MBBI); 1250fe6060f1SDimitry Andric while (NextMBBI != EndMBBI) { 12510b57cec5SDimitry Andric // Skip debug values. 12520b57cec5SDimitry Andric while (NextMBBI != EndMBBI && NextMBBI->isDebugInstr()) 12530b57cec5SDimitry Andric ++NextMBBI; 12540b57cec5SDimitry Andric if (NextMBBI == EndMBBI) 12550b57cec5SDimitry Andric return EndMBBI; 12560b57cec5SDimitry Andric 1257fe6060f1SDimitry Andric unsigned Off = isIncrementOrDecrement(*NextMBBI, Reg, Pred, PredReg); 1258fe6060f1SDimitry Andric if (Off) { 1259fe6060f1SDimitry Andric Offset = Off; 1260fe6060f1SDimitry Andric return NextMBBI; 1261fe6060f1SDimitry Andric } 1262fe6060f1SDimitry Andric 1263fe6060f1SDimitry Andric // SP can only be combined if it is the next instruction after the original 1264fe6060f1SDimitry Andric // MBBI, otherwise we may be incrementing the stack pointer (invalidating 1265fe6060f1SDimitry Andric // anything below the new pointer) when its frame elements are still in 1266fe6060f1SDimitry Andric // use. Other registers can attempt to look further, until a different use 1267fe6060f1SDimitry Andric // or def of the register is found. 1268fe6060f1SDimitry Andric if (Reg == ARM::SP || NextMBBI->readsRegister(Reg, TRI) || 1269fe6060f1SDimitry Andric NextMBBI->definesRegister(Reg, TRI)) 1270fe6060f1SDimitry Andric return EndMBBI; 1271fe6060f1SDimitry Andric 1272fe6060f1SDimitry Andric ++NextMBBI; 1273fe6060f1SDimitry Andric } 1274fe6060f1SDimitry Andric return EndMBBI; 12750b57cec5SDimitry Andric } 12760b57cec5SDimitry Andric 12770b57cec5SDimitry Andric /// Fold proceeding/trailing inc/dec of base register into the 12780b57cec5SDimitry Andric /// LDM/STM/VLDM{D|S}/VSTM{D|S} op when possible: 12790b57cec5SDimitry Andric /// 12800b57cec5SDimitry Andric /// stmia rn, <ra, rb, rc> 12810b57cec5SDimitry Andric /// rn := rn + 4 * 3; 12820b57cec5SDimitry Andric /// => 12830b57cec5SDimitry Andric /// stmia rn!, <ra, rb, rc> 12840b57cec5SDimitry Andric /// 12850b57cec5SDimitry Andric /// rn := rn - 4 * 3; 12860b57cec5SDimitry Andric /// ldmia rn, <ra, rb, rc> 12870b57cec5SDimitry Andric /// => 12880b57cec5SDimitry Andric /// ldmdb rn!, <ra, rb, rc> 12890b57cec5SDimitry Andric bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineInstr *MI) { 12900b57cec5SDimitry Andric // Thumb1 is already using updating loads/stores. 12910b57cec5SDimitry Andric if (isThumb1) return false; 1292e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Attempting to merge update of: " << *MI); 12930b57cec5SDimitry Andric 12940b57cec5SDimitry Andric const MachineOperand &BaseOP = MI->getOperand(0); 12958bcb0991SDimitry Andric Register Base = BaseOP.getReg(); 12960b57cec5SDimitry Andric bool BaseKill = BaseOP.isKill(); 12975ffd83dbSDimitry Andric Register PredReg; 12980b57cec5SDimitry Andric ARMCC::CondCodes Pred = getInstrPredicate(*MI, PredReg); 12990b57cec5SDimitry Andric unsigned Opcode = MI->getOpcode(); 13000b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 13010b57cec5SDimitry Andric 13020b57cec5SDimitry Andric // Can't use an updating ld/st if the base register is also a dest 13030b57cec5SDimitry Andric // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined. 13044824e7fdSDimitry Andric for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 2)) 13054824e7fdSDimitry Andric if (MO.getReg() == Base) 13060b57cec5SDimitry Andric return false; 13070b57cec5SDimitry Andric 13080b57cec5SDimitry Andric int Bytes = getLSMultipleTransferSize(MI); 13090b57cec5SDimitry Andric MachineBasicBlock &MBB = *MI->getParent(); 13100b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI(MI); 13110b57cec5SDimitry Andric int Offset; 13120b57cec5SDimitry Andric MachineBasicBlock::iterator MergeInstr 13130b57cec5SDimitry Andric = findIncDecBefore(MBBI, Base, Pred, PredReg, Offset); 13140b57cec5SDimitry Andric ARM_AM::AMSubMode Mode = getLoadStoreMultipleSubMode(Opcode); 13150b57cec5SDimitry Andric if (Mode == ARM_AM::ia && Offset == -Bytes) { 13160b57cec5SDimitry Andric Mode = ARM_AM::db; 13170b57cec5SDimitry Andric } else if (Mode == ARM_AM::ib && Offset == -Bytes) { 13180b57cec5SDimitry Andric Mode = ARM_AM::da; 13190b57cec5SDimitry Andric } else { 1320fe6060f1SDimitry Andric MergeInstr = findIncDecAfter(MBBI, Base, Pred, PredReg, Offset, TRI); 13210b57cec5SDimitry Andric if (((Mode != ARM_AM::ia && Mode != ARM_AM::ib) || Offset != Bytes) && 13220b57cec5SDimitry Andric ((Mode != ARM_AM::da && Mode != ARM_AM::db) || Offset != -Bytes)) { 13230b57cec5SDimitry Andric 13240b57cec5SDimitry Andric // We couldn't find an inc/dec to merge. But if the base is dead, we 13250b57cec5SDimitry Andric // can still change to a writeback form as that will save us 2 bytes 13260b57cec5SDimitry Andric // of code size. It can create WAW hazards though, so only do it if 13270b57cec5SDimitry Andric // we're minimizing code size. 13280b57cec5SDimitry Andric if (!STI->hasMinSize() || !BaseKill) 13290b57cec5SDimitry Andric return false; 13300b57cec5SDimitry Andric 13310b57cec5SDimitry Andric bool HighRegsUsed = false; 13324824e7fdSDimitry Andric for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 2)) 13334824e7fdSDimitry Andric if (MO.getReg() >= ARM::R8) { 13340b57cec5SDimitry Andric HighRegsUsed = true; 13350b57cec5SDimitry Andric break; 13360b57cec5SDimitry Andric } 13370b57cec5SDimitry Andric 13380b57cec5SDimitry Andric if (!HighRegsUsed) 13390b57cec5SDimitry Andric MergeInstr = MBB.end(); 13400b57cec5SDimitry Andric else 13410b57cec5SDimitry Andric return false; 13420b57cec5SDimitry Andric } 13430b57cec5SDimitry Andric } 1344e8d8bef9SDimitry Andric if (MergeInstr != MBB.end()) { 1345e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Erasing old increment: " << *MergeInstr); 13460b57cec5SDimitry Andric MBB.erase(MergeInstr); 1347e8d8bef9SDimitry Andric } 13480b57cec5SDimitry Andric 13490b57cec5SDimitry Andric unsigned NewOpc = getUpdatingLSMultipleOpcode(Opcode, Mode); 13500b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(NewOpc)) 13510b57cec5SDimitry Andric .addReg(Base, getDefRegState(true)) // WB base register 13520b57cec5SDimitry Andric .addReg(Base, getKillRegState(BaseKill)) 13530b57cec5SDimitry Andric .addImm(Pred).addReg(PredReg); 13540b57cec5SDimitry Andric 13550b57cec5SDimitry Andric // Transfer the rest of operands. 13564824e7fdSDimitry Andric for (const MachineOperand &MO : llvm::drop_begin(MI->operands(), 3)) 13574824e7fdSDimitry Andric MIB.add(MO); 13580b57cec5SDimitry Andric 13590b57cec5SDimitry Andric // Transfer memoperands. 13600b57cec5SDimitry Andric MIB.setMemRefs(MI->memoperands()); 13610b57cec5SDimitry Andric 1362e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new load/store: " << *MIB); 13630b57cec5SDimitry Andric MBB.erase(MBBI); 13640b57cec5SDimitry Andric return true; 13650b57cec5SDimitry Andric } 13660b57cec5SDimitry Andric 13670b57cec5SDimitry Andric static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc, 13680b57cec5SDimitry Andric ARM_AM::AddrOpc Mode) { 13690b57cec5SDimitry Andric switch (Opc) { 13700b57cec5SDimitry Andric case ARM::LDRi12: 13710b57cec5SDimitry Andric return ARM::LDR_PRE_IMM; 13720b57cec5SDimitry Andric case ARM::STRi12: 13730b57cec5SDimitry Andric return ARM::STR_PRE_IMM; 13740b57cec5SDimitry Andric case ARM::VLDRS: 13750b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VLDMSIA_UPD : ARM::VLDMSDB_UPD; 13760b57cec5SDimitry Andric case ARM::VLDRD: 13770b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VLDMDIA_UPD : ARM::VLDMDDB_UPD; 13780b57cec5SDimitry Andric case ARM::VSTRS: 13790b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VSTMSIA_UPD : ARM::VSTMSDB_UPD; 13800b57cec5SDimitry Andric case ARM::VSTRD: 13810b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VSTMDIA_UPD : ARM::VSTMDDB_UPD; 13820b57cec5SDimitry Andric case ARM::t2LDRi8: 13830b57cec5SDimitry Andric case ARM::t2LDRi12: 13840b57cec5SDimitry Andric return ARM::t2LDR_PRE; 13850b57cec5SDimitry Andric case ARM::t2STRi8: 13860b57cec5SDimitry Andric case ARM::t2STRi12: 13870b57cec5SDimitry Andric return ARM::t2STR_PRE; 13880b57cec5SDimitry Andric default: llvm_unreachable("Unhandled opcode!"); 13890b57cec5SDimitry Andric } 13900b57cec5SDimitry Andric } 13910b57cec5SDimitry Andric 13920b57cec5SDimitry Andric static unsigned getPostIndexedLoadStoreOpcode(unsigned Opc, 13930b57cec5SDimitry Andric ARM_AM::AddrOpc Mode) { 13940b57cec5SDimitry Andric switch (Opc) { 13950b57cec5SDimitry Andric case ARM::LDRi12: 13960b57cec5SDimitry Andric return ARM::LDR_POST_IMM; 13970b57cec5SDimitry Andric case ARM::STRi12: 13980b57cec5SDimitry Andric return ARM::STR_POST_IMM; 13990b57cec5SDimitry Andric case ARM::VLDRS: 14000b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VLDMSIA_UPD : ARM::VLDMSDB_UPD; 14010b57cec5SDimitry Andric case ARM::VLDRD: 14020b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VLDMDIA_UPD : ARM::VLDMDDB_UPD; 14030b57cec5SDimitry Andric case ARM::VSTRS: 14040b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VSTMSIA_UPD : ARM::VSTMSDB_UPD; 14050b57cec5SDimitry Andric case ARM::VSTRD: 14060b57cec5SDimitry Andric return Mode == ARM_AM::add ? ARM::VSTMDIA_UPD : ARM::VSTMDDB_UPD; 14070b57cec5SDimitry Andric case ARM::t2LDRi8: 14080b57cec5SDimitry Andric case ARM::t2LDRi12: 14090b57cec5SDimitry Andric return ARM::t2LDR_POST; 1410e8d8bef9SDimitry Andric case ARM::t2LDRBi8: 1411e8d8bef9SDimitry Andric case ARM::t2LDRBi12: 1412e8d8bef9SDimitry Andric return ARM::t2LDRB_POST; 1413e8d8bef9SDimitry Andric case ARM::t2LDRSBi8: 1414e8d8bef9SDimitry Andric case ARM::t2LDRSBi12: 1415e8d8bef9SDimitry Andric return ARM::t2LDRSB_POST; 1416e8d8bef9SDimitry Andric case ARM::t2LDRHi8: 1417e8d8bef9SDimitry Andric case ARM::t2LDRHi12: 1418e8d8bef9SDimitry Andric return ARM::t2LDRH_POST; 1419e8d8bef9SDimitry Andric case ARM::t2LDRSHi8: 1420e8d8bef9SDimitry Andric case ARM::t2LDRSHi12: 1421e8d8bef9SDimitry Andric return ARM::t2LDRSH_POST; 14220b57cec5SDimitry Andric case ARM::t2STRi8: 14230b57cec5SDimitry Andric case ARM::t2STRi12: 14240b57cec5SDimitry Andric return ARM::t2STR_POST; 1425e8d8bef9SDimitry Andric case ARM::t2STRBi8: 1426e8d8bef9SDimitry Andric case ARM::t2STRBi12: 1427e8d8bef9SDimitry Andric return ARM::t2STRB_POST; 1428e8d8bef9SDimitry Andric case ARM::t2STRHi8: 1429e8d8bef9SDimitry Andric case ARM::t2STRHi12: 1430e8d8bef9SDimitry Andric return ARM::t2STRH_POST; 14315ffd83dbSDimitry Andric 14325ffd83dbSDimitry Andric case ARM::MVE_VLDRBS16: 14335ffd83dbSDimitry Andric return ARM::MVE_VLDRBS16_post; 14345ffd83dbSDimitry Andric case ARM::MVE_VLDRBS32: 14355ffd83dbSDimitry Andric return ARM::MVE_VLDRBS32_post; 14365ffd83dbSDimitry Andric case ARM::MVE_VLDRBU16: 14375ffd83dbSDimitry Andric return ARM::MVE_VLDRBU16_post; 14385ffd83dbSDimitry Andric case ARM::MVE_VLDRBU32: 14395ffd83dbSDimitry Andric return ARM::MVE_VLDRBU32_post; 14405ffd83dbSDimitry Andric case ARM::MVE_VLDRHS32: 14415ffd83dbSDimitry Andric return ARM::MVE_VLDRHS32_post; 14425ffd83dbSDimitry Andric case ARM::MVE_VLDRHU32: 14435ffd83dbSDimitry Andric return ARM::MVE_VLDRHU32_post; 14445ffd83dbSDimitry Andric case ARM::MVE_VLDRBU8: 14455ffd83dbSDimitry Andric return ARM::MVE_VLDRBU8_post; 14465ffd83dbSDimitry Andric case ARM::MVE_VLDRHU16: 14475ffd83dbSDimitry Andric return ARM::MVE_VLDRHU16_post; 14485ffd83dbSDimitry Andric case ARM::MVE_VLDRWU32: 14495ffd83dbSDimitry Andric return ARM::MVE_VLDRWU32_post; 14505ffd83dbSDimitry Andric case ARM::MVE_VSTRB16: 14515ffd83dbSDimitry Andric return ARM::MVE_VSTRB16_post; 14525ffd83dbSDimitry Andric case ARM::MVE_VSTRB32: 14535ffd83dbSDimitry Andric return ARM::MVE_VSTRB32_post; 14545ffd83dbSDimitry Andric case ARM::MVE_VSTRH32: 14555ffd83dbSDimitry Andric return ARM::MVE_VSTRH32_post; 14565ffd83dbSDimitry Andric case ARM::MVE_VSTRBU8: 14575ffd83dbSDimitry Andric return ARM::MVE_VSTRBU8_post; 14585ffd83dbSDimitry Andric case ARM::MVE_VSTRHU16: 14595ffd83dbSDimitry Andric return ARM::MVE_VSTRHU16_post; 14605ffd83dbSDimitry Andric case ARM::MVE_VSTRWU32: 14615ffd83dbSDimitry Andric return ARM::MVE_VSTRWU32_post; 14625ffd83dbSDimitry Andric 14630b57cec5SDimitry Andric default: llvm_unreachable("Unhandled opcode!"); 14640b57cec5SDimitry Andric } 14650b57cec5SDimitry Andric } 14660b57cec5SDimitry Andric 14670b57cec5SDimitry Andric /// Fold proceeding/trailing inc/dec of base register into the 14680b57cec5SDimitry Andric /// LDR/STR/FLD{D|S}/FST{D|S} op when possible: 14690b57cec5SDimitry Andric bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineInstr *MI) { 14700b57cec5SDimitry Andric // Thumb1 doesn't have updating LDR/STR. 14710b57cec5SDimitry Andric // FIXME: Use LDM/STM with single register instead. 14720b57cec5SDimitry Andric if (isThumb1) return false; 1473e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Attempting to merge update of: " << *MI); 14740b57cec5SDimitry Andric 14758bcb0991SDimitry Andric Register Base = getLoadStoreBaseOp(*MI).getReg(); 14760b57cec5SDimitry Andric bool BaseKill = getLoadStoreBaseOp(*MI).isKill(); 14770b57cec5SDimitry Andric unsigned Opcode = MI->getOpcode(); 14780b57cec5SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 14790b57cec5SDimitry Andric bool isAM5 = (Opcode == ARM::VLDRD || Opcode == ARM::VLDRS || 14800b57cec5SDimitry Andric Opcode == ARM::VSTRD || Opcode == ARM::VSTRS); 14810b57cec5SDimitry Andric bool isAM2 = (Opcode == ARM::LDRi12 || Opcode == ARM::STRi12); 14820b57cec5SDimitry Andric if (isi32Load(Opcode) || isi32Store(Opcode)) 14830b57cec5SDimitry Andric if (MI->getOperand(2).getImm() != 0) 14840b57cec5SDimitry Andric return false; 14850b57cec5SDimitry Andric if (isAM5 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0) 14860b57cec5SDimitry Andric return false; 14870b57cec5SDimitry Andric 14880b57cec5SDimitry Andric // Can't do the merge if the destination register is the same as the would-be 14890b57cec5SDimitry Andric // writeback register. 14900b57cec5SDimitry Andric if (MI->getOperand(0).getReg() == Base) 14910b57cec5SDimitry Andric return false; 14920b57cec5SDimitry Andric 14935ffd83dbSDimitry Andric Register PredReg; 14940b57cec5SDimitry Andric ARMCC::CondCodes Pred = getInstrPredicate(*MI, PredReg); 14950b57cec5SDimitry Andric int Bytes = getLSMultipleTransferSize(MI); 14960b57cec5SDimitry Andric MachineBasicBlock &MBB = *MI->getParent(); 14970b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI(MI); 14980b57cec5SDimitry Andric int Offset; 14990b57cec5SDimitry Andric MachineBasicBlock::iterator MergeInstr 15000b57cec5SDimitry Andric = findIncDecBefore(MBBI, Base, Pred, PredReg, Offset); 15010b57cec5SDimitry Andric unsigned NewOpc; 15020b57cec5SDimitry Andric if (!isAM5 && Offset == Bytes) { 15030b57cec5SDimitry Andric NewOpc = getPreIndexedLoadStoreOpcode(Opcode, ARM_AM::add); 15040b57cec5SDimitry Andric } else if (Offset == -Bytes) { 15050b57cec5SDimitry Andric NewOpc = getPreIndexedLoadStoreOpcode(Opcode, ARM_AM::sub); 15060b57cec5SDimitry Andric } else { 1507fe6060f1SDimitry Andric MergeInstr = findIncDecAfter(MBBI, Base, Pred, PredReg, Offset, TRI); 1508fe6060f1SDimitry Andric if (MergeInstr == MBB.end()) 15090b57cec5SDimitry Andric return false; 1510fe6060f1SDimitry Andric 1511fe6060f1SDimitry Andric NewOpc = getPostIndexedLoadStoreOpcode(Opcode, ARM_AM::add); 1512fe6060f1SDimitry Andric if ((isAM5 && Offset != Bytes) || 1513fe6060f1SDimitry Andric (!isAM5 && !isLegalAddressImm(NewOpc, Offset, TII))) { 1514fe6060f1SDimitry Andric NewOpc = getPostIndexedLoadStoreOpcode(Opcode, ARM_AM::sub); 1515fe6060f1SDimitry Andric if (isAM5 || !isLegalAddressImm(NewOpc, Offset, TII)) 1516fe6060f1SDimitry Andric return false; 1517fe6060f1SDimitry Andric } 15180b57cec5SDimitry Andric } 1519e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Erasing old increment: " << *MergeInstr); 15200b57cec5SDimitry Andric MBB.erase(MergeInstr); 15210b57cec5SDimitry Andric 15220b57cec5SDimitry Andric ARM_AM::AddrOpc AddSub = Offset < 0 ? ARM_AM::sub : ARM_AM::add; 15230b57cec5SDimitry Andric 15240b57cec5SDimitry Andric bool isLd = isLoadSingle(Opcode); 15250b57cec5SDimitry Andric if (isAM5) { 15260b57cec5SDimitry Andric // VLDM[SD]_UPD, VSTM[SD]_UPD 15270b57cec5SDimitry Andric // (There are no base-updating versions of VLDR/VSTR instructions, but the 15280b57cec5SDimitry Andric // updating load/store-multiple instructions can be used with only one 15290b57cec5SDimitry Andric // register.) 15300b57cec5SDimitry Andric MachineOperand &MO = MI->getOperand(0); 1531e8d8bef9SDimitry Andric auto MIB = BuildMI(MBB, MBBI, DL, TII->get(NewOpc)) 15320b57cec5SDimitry Andric .addReg(Base, getDefRegState(true)) // WB base register 15330b57cec5SDimitry Andric .addReg(Base, getKillRegState(isLd ? BaseKill : false)) 1534e8d8bef9SDimitry Andric .addImm(Pred) 1535e8d8bef9SDimitry Andric .addReg(PredReg) 1536e8d8bef9SDimitry Andric .addReg(MO.getReg(), (isLd ? getDefRegState(true) 1537e8d8bef9SDimitry Andric : getKillRegState(MO.isKill()))) 15380b57cec5SDimitry Andric .cloneMemRefs(*MI); 1539e8d8bef9SDimitry Andric (void)MIB; 1540e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new instruction: " << *MIB); 15410b57cec5SDimitry Andric } else if (isLd) { 15420b57cec5SDimitry Andric if (isAM2) { 15430b57cec5SDimitry Andric // LDR_PRE, LDR_POST 15440b57cec5SDimitry Andric if (NewOpc == ARM::LDR_PRE_IMM || NewOpc == ARM::LDRB_PRE_IMM) { 1545e8d8bef9SDimitry Andric auto MIB = 15460b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(NewOpc), MI->getOperand(0).getReg()) 15470b57cec5SDimitry Andric .addReg(Base, RegState::Define) 1548e8d8bef9SDimitry Andric .addReg(Base) 1549e8d8bef9SDimitry Andric .addImm(Offset) 1550e8d8bef9SDimitry Andric .addImm(Pred) 1551e8d8bef9SDimitry Andric .addReg(PredReg) 15520b57cec5SDimitry Andric .cloneMemRefs(*MI); 1553e8d8bef9SDimitry Andric (void)MIB; 1554e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new instruction: " << *MIB); 15550b57cec5SDimitry Andric } else { 1556fe6060f1SDimitry Andric int Imm = ARM_AM::getAM2Opc(AddSub, abs(Offset), ARM_AM::no_shift); 1557e8d8bef9SDimitry Andric auto MIB = 15580b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(NewOpc), MI->getOperand(0).getReg()) 15590b57cec5SDimitry Andric .addReg(Base, RegState::Define) 15600b57cec5SDimitry Andric .addReg(Base) 15610b57cec5SDimitry Andric .addReg(0) 15620b57cec5SDimitry Andric .addImm(Imm) 15630b57cec5SDimitry Andric .add(predOps(Pred, PredReg)) 15640b57cec5SDimitry Andric .cloneMemRefs(*MI); 1565e8d8bef9SDimitry Andric (void)MIB; 1566e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new instruction: " << *MIB); 15670b57cec5SDimitry Andric } 15680b57cec5SDimitry Andric } else { 15690b57cec5SDimitry Andric // t2LDR_PRE, t2LDR_POST 1570e8d8bef9SDimitry Andric auto MIB = 15710b57cec5SDimitry Andric BuildMI(MBB, MBBI, DL, TII->get(NewOpc), MI->getOperand(0).getReg()) 15720b57cec5SDimitry Andric .addReg(Base, RegState::Define) 15730b57cec5SDimitry Andric .addReg(Base) 15740b57cec5SDimitry Andric .addImm(Offset) 15750b57cec5SDimitry Andric .add(predOps(Pred, PredReg)) 15760b57cec5SDimitry Andric .cloneMemRefs(*MI); 1577e8d8bef9SDimitry Andric (void)MIB; 1578e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new instruction: " << *MIB); 15790b57cec5SDimitry Andric } 15800b57cec5SDimitry Andric } else { 15810b57cec5SDimitry Andric MachineOperand &MO = MI->getOperand(0); 15820b57cec5SDimitry Andric // FIXME: post-indexed stores use am2offset_imm, which still encodes 15830b57cec5SDimitry Andric // the vestigal zero-reg offset register. When that's fixed, this clause 15840b57cec5SDimitry Andric // can be removed entirely. 15850b57cec5SDimitry Andric if (isAM2 && NewOpc == ARM::STR_POST_IMM) { 1586fe6060f1SDimitry Andric int Imm = ARM_AM::getAM2Opc(AddSub, abs(Offset), ARM_AM::no_shift); 15870b57cec5SDimitry Andric // STR_PRE, STR_POST 1588e8d8bef9SDimitry Andric auto MIB = BuildMI(MBB, MBBI, DL, TII->get(NewOpc), Base) 15890b57cec5SDimitry Andric .addReg(MO.getReg(), getKillRegState(MO.isKill())) 15900b57cec5SDimitry Andric .addReg(Base) 15910b57cec5SDimitry Andric .addReg(0) 15920b57cec5SDimitry Andric .addImm(Imm) 15930b57cec5SDimitry Andric .add(predOps(Pred, PredReg)) 15940b57cec5SDimitry Andric .cloneMemRefs(*MI); 1595e8d8bef9SDimitry Andric (void)MIB; 1596e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new instruction: " << *MIB); 15970b57cec5SDimitry Andric } else { 15980b57cec5SDimitry Andric // t2STR_PRE, t2STR_POST 1599e8d8bef9SDimitry Andric auto MIB = BuildMI(MBB, MBBI, DL, TII->get(NewOpc), Base) 16000b57cec5SDimitry Andric .addReg(MO.getReg(), getKillRegState(MO.isKill())) 16010b57cec5SDimitry Andric .addReg(Base) 16020b57cec5SDimitry Andric .addImm(Offset) 16030b57cec5SDimitry Andric .add(predOps(Pred, PredReg)) 16040b57cec5SDimitry Andric .cloneMemRefs(*MI); 1605e8d8bef9SDimitry Andric (void)MIB; 1606e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new instruction: " << *MIB); 16070b57cec5SDimitry Andric } 16080b57cec5SDimitry Andric } 16090b57cec5SDimitry Andric MBB.erase(MBBI); 16100b57cec5SDimitry Andric 16110b57cec5SDimitry Andric return true; 16120b57cec5SDimitry Andric } 16130b57cec5SDimitry Andric 16140b57cec5SDimitry Andric bool ARMLoadStoreOpt::MergeBaseUpdateLSDouble(MachineInstr &MI) const { 16150b57cec5SDimitry Andric unsigned Opcode = MI.getOpcode(); 16160b57cec5SDimitry Andric assert((Opcode == ARM::t2LDRDi8 || Opcode == ARM::t2STRDi8) && 16170b57cec5SDimitry Andric "Must have t2STRDi8 or t2LDRDi8"); 16180b57cec5SDimitry Andric if (MI.getOperand(3).getImm() != 0) 16190b57cec5SDimitry Andric return false; 1620e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "Attempting to merge update of: " << MI); 16210b57cec5SDimitry Andric 16220b57cec5SDimitry Andric // Behaviour for writeback is undefined if base register is the same as one 16230b57cec5SDimitry Andric // of the others. 16240b57cec5SDimitry Andric const MachineOperand &BaseOp = MI.getOperand(2); 16258bcb0991SDimitry Andric Register Base = BaseOp.getReg(); 16260b57cec5SDimitry Andric const MachineOperand &Reg0Op = MI.getOperand(0); 16270b57cec5SDimitry Andric const MachineOperand &Reg1Op = MI.getOperand(1); 16280b57cec5SDimitry Andric if (Reg0Op.getReg() == Base || Reg1Op.getReg() == Base) 16290b57cec5SDimitry Andric return false; 16300b57cec5SDimitry Andric 16315ffd83dbSDimitry Andric Register PredReg; 16320b57cec5SDimitry Andric ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg); 16330b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI(MI); 16340b57cec5SDimitry Andric MachineBasicBlock &MBB = *MI.getParent(); 16350b57cec5SDimitry Andric int Offset; 16360b57cec5SDimitry Andric MachineBasicBlock::iterator MergeInstr = findIncDecBefore(MBBI, Base, Pred, 16370b57cec5SDimitry Andric PredReg, Offset); 16380b57cec5SDimitry Andric unsigned NewOpc; 16390b57cec5SDimitry Andric if (Offset == 8 || Offset == -8) { 16400b57cec5SDimitry Andric NewOpc = Opcode == ARM::t2LDRDi8 ? ARM::t2LDRD_PRE : ARM::t2STRD_PRE; 16410b57cec5SDimitry Andric } else { 1642fe6060f1SDimitry Andric MergeInstr = findIncDecAfter(MBBI, Base, Pred, PredReg, Offset, TRI); 1643fe6060f1SDimitry Andric if (MergeInstr == MBB.end()) 1644fe6060f1SDimitry Andric return false; 16450b57cec5SDimitry Andric NewOpc = Opcode == ARM::t2LDRDi8 ? ARM::t2LDRD_POST : ARM::t2STRD_POST; 1646fe6060f1SDimitry Andric if (!isLegalAddressImm(NewOpc, Offset, TII)) 16470b57cec5SDimitry Andric return false; 16480b57cec5SDimitry Andric } 1649e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Erasing old increment: " << *MergeInstr); 16500b57cec5SDimitry Andric MBB.erase(MergeInstr); 16510b57cec5SDimitry Andric 16520b57cec5SDimitry Andric DebugLoc DL = MI.getDebugLoc(); 16530b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, TII->get(NewOpc)); 16540b57cec5SDimitry Andric if (NewOpc == ARM::t2LDRD_PRE || NewOpc == ARM::t2LDRD_POST) { 16550b57cec5SDimitry Andric MIB.add(Reg0Op).add(Reg1Op).addReg(BaseOp.getReg(), RegState::Define); 16560b57cec5SDimitry Andric } else { 16570b57cec5SDimitry Andric assert(NewOpc == ARM::t2STRD_PRE || NewOpc == ARM::t2STRD_POST); 16580b57cec5SDimitry Andric MIB.addReg(BaseOp.getReg(), RegState::Define).add(Reg0Op).add(Reg1Op); 16590b57cec5SDimitry Andric } 16600b57cec5SDimitry Andric MIB.addReg(BaseOp.getReg(), RegState::Kill) 16610b57cec5SDimitry Andric .addImm(Offset).addImm(Pred).addReg(PredReg); 16620b57cec5SDimitry Andric assert(TII->get(Opcode).getNumOperands() == 6 && 16630b57cec5SDimitry Andric TII->get(NewOpc).getNumOperands() == 7 && 16640b57cec5SDimitry Andric "Unexpected number of operands in Opcode specification."); 16650b57cec5SDimitry Andric 16660b57cec5SDimitry Andric // Transfer implicit operands. 16670b57cec5SDimitry Andric for (const MachineOperand &MO : MI.implicit_operands()) 16680b57cec5SDimitry Andric MIB.add(MO); 16690b57cec5SDimitry Andric MIB.cloneMemRefs(MI); 16700b57cec5SDimitry Andric 1671e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Added new load/store: " << *MIB); 16720b57cec5SDimitry Andric MBB.erase(MBBI); 16730b57cec5SDimitry Andric return true; 16740b57cec5SDimitry Andric } 16750b57cec5SDimitry Andric 16760b57cec5SDimitry Andric /// Returns true if instruction is a memory operation that this pass is capable 16770b57cec5SDimitry Andric /// of operating on. 16780b57cec5SDimitry Andric static bool isMemoryOp(const MachineInstr &MI) { 16790b57cec5SDimitry Andric unsigned Opcode = MI.getOpcode(); 16800b57cec5SDimitry Andric switch (Opcode) { 16810b57cec5SDimitry Andric case ARM::VLDRS: 16820b57cec5SDimitry Andric case ARM::VSTRS: 16830b57cec5SDimitry Andric case ARM::VLDRD: 16840b57cec5SDimitry Andric case ARM::VSTRD: 16850b57cec5SDimitry Andric case ARM::LDRi12: 16860b57cec5SDimitry Andric case ARM::STRi12: 16870b57cec5SDimitry Andric case ARM::tLDRi: 16880b57cec5SDimitry Andric case ARM::tSTRi: 16890b57cec5SDimitry Andric case ARM::tLDRspi: 16900b57cec5SDimitry Andric case ARM::tSTRspi: 16910b57cec5SDimitry Andric case ARM::t2LDRi8: 16920b57cec5SDimitry Andric case ARM::t2LDRi12: 16930b57cec5SDimitry Andric case ARM::t2STRi8: 16940b57cec5SDimitry Andric case ARM::t2STRi12: 16950b57cec5SDimitry Andric break; 16960b57cec5SDimitry Andric default: 16970b57cec5SDimitry Andric return false; 16980b57cec5SDimitry Andric } 16990b57cec5SDimitry Andric if (!MI.getOperand(1).isReg()) 17000b57cec5SDimitry Andric return false; 17010b57cec5SDimitry Andric 17020b57cec5SDimitry Andric // When no memory operands are present, conservatively assume unaligned, 17030b57cec5SDimitry Andric // volatile, unfoldable. 17040b57cec5SDimitry Andric if (!MI.hasOneMemOperand()) 17050b57cec5SDimitry Andric return false; 17060b57cec5SDimitry Andric 17070b57cec5SDimitry Andric const MachineMemOperand &MMO = **MI.memoperands_begin(); 17080b57cec5SDimitry Andric 17090b57cec5SDimitry Andric // Don't touch volatile memory accesses - we may be changing their order. 17100b57cec5SDimitry Andric // TODO: We could allow unordered and monotonic atomics here, but we need to 17110b57cec5SDimitry Andric // make sure the resulting ldm/stm is correctly marked as atomic. 17120b57cec5SDimitry Andric if (MMO.isVolatile() || MMO.isAtomic()) 17130b57cec5SDimitry Andric return false; 17140b57cec5SDimitry Andric 17150b57cec5SDimitry Andric // Unaligned ldr/str is emulated by some kernels, but unaligned ldm/stm is 17160b57cec5SDimitry Andric // not. 17175ffd83dbSDimitry Andric if (MMO.getAlign() < Align(4)) 17180b57cec5SDimitry Andric return false; 17190b57cec5SDimitry Andric 17200b57cec5SDimitry Andric // str <undef> could probably be eliminated entirely, but for now we just want 17210b57cec5SDimitry Andric // to avoid making a mess of it. 17220b57cec5SDimitry Andric // FIXME: Use str <undef> as a wildcard to enable better stm folding. 17230b57cec5SDimitry Andric if (MI.getOperand(0).isReg() && MI.getOperand(0).isUndef()) 17240b57cec5SDimitry Andric return false; 17250b57cec5SDimitry Andric 17260b57cec5SDimitry Andric // Likewise don't mess with references to undefined addresses. 17270b57cec5SDimitry Andric if (MI.getOperand(1).isUndef()) 17280b57cec5SDimitry Andric return false; 17290b57cec5SDimitry Andric 17300b57cec5SDimitry Andric return true; 17310b57cec5SDimitry Andric } 17320b57cec5SDimitry Andric 17330b57cec5SDimitry Andric static void InsertLDR_STR(MachineBasicBlock &MBB, 17340b57cec5SDimitry Andric MachineBasicBlock::iterator &MBBI, int Offset, 17350b57cec5SDimitry Andric bool isDef, unsigned NewOpc, unsigned Reg, 17360b57cec5SDimitry Andric bool RegDeadKill, bool RegUndef, unsigned BaseReg, 17370b57cec5SDimitry Andric bool BaseKill, bool BaseUndef, ARMCC::CondCodes Pred, 17380b57cec5SDimitry Andric unsigned PredReg, const TargetInstrInfo *TII, 17390b57cec5SDimitry Andric MachineInstr *MI) { 17400b57cec5SDimitry Andric if (isDef) { 17410b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MBBI->getDebugLoc(), 17420b57cec5SDimitry Andric TII->get(NewOpc)) 17430b57cec5SDimitry Andric .addReg(Reg, getDefRegState(true) | getDeadRegState(RegDeadKill)) 17440b57cec5SDimitry Andric .addReg(BaseReg, getKillRegState(BaseKill)|getUndefRegState(BaseUndef)); 17450b57cec5SDimitry Andric MIB.addImm(Offset).addImm(Pred).addReg(PredReg); 17460b57cec5SDimitry Andric // FIXME: This is overly conservative; the new instruction accesses 4 17470b57cec5SDimitry Andric // bytes, not 8. 17480b57cec5SDimitry Andric MIB.cloneMemRefs(*MI); 17490b57cec5SDimitry Andric } else { 17500b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, MBBI->getDebugLoc(), 17510b57cec5SDimitry Andric TII->get(NewOpc)) 17520b57cec5SDimitry Andric .addReg(Reg, getKillRegState(RegDeadKill) | getUndefRegState(RegUndef)) 17530b57cec5SDimitry Andric .addReg(BaseReg, getKillRegState(BaseKill)|getUndefRegState(BaseUndef)); 17540b57cec5SDimitry Andric MIB.addImm(Offset).addImm(Pred).addReg(PredReg); 17550b57cec5SDimitry Andric // FIXME: This is overly conservative; the new instruction accesses 4 17560b57cec5SDimitry Andric // bytes, not 8. 17570b57cec5SDimitry Andric MIB.cloneMemRefs(*MI); 17580b57cec5SDimitry Andric } 17590b57cec5SDimitry Andric } 17600b57cec5SDimitry Andric 17610b57cec5SDimitry Andric bool ARMLoadStoreOpt::FixInvalidRegPairOp(MachineBasicBlock &MBB, 17620b57cec5SDimitry Andric MachineBasicBlock::iterator &MBBI) { 17630b57cec5SDimitry Andric MachineInstr *MI = &*MBBI; 17640b57cec5SDimitry Andric unsigned Opcode = MI->getOpcode(); 17650b57cec5SDimitry Andric // FIXME: Code/comments below check Opcode == t2STRDi8, but this check returns 17660b57cec5SDimitry Andric // if we see this opcode. 17670b57cec5SDimitry Andric if (Opcode != ARM::LDRD && Opcode != ARM::STRD && Opcode != ARM::t2LDRDi8) 17680b57cec5SDimitry Andric return false; 17690b57cec5SDimitry Andric 17700b57cec5SDimitry Andric const MachineOperand &BaseOp = MI->getOperand(2); 17718bcb0991SDimitry Andric Register BaseReg = BaseOp.getReg(); 17728bcb0991SDimitry Andric Register EvenReg = MI->getOperand(0).getReg(); 17738bcb0991SDimitry Andric Register OddReg = MI->getOperand(1).getReg(); 17740b57cec5SDimitry Andric unsigned EvenRegNum = TRI->getDwarfRegNum(EvenReg, false); 17750b57cec5SDimitry Andric unsigned OddRegNum = TRI->getDwarfRegNum(OddReg, false); 17760b57cec5SDimitry Andric 17770b57cec5SDimitry Andric // ARM errata 602117: LDRD with base in list may result in incorrect base 17780b57cec5SDimitry Andric // register when interrupted or faulted. 17790b57cec5SDimitry Andric bool Errata602117 = EvenReg == BaseReg && 17800b57cec5SDimitry Andric (Opcode == ARM::LDRD || Opcode == ARM::t2LDRDi8) && STI->isCortexM3(); 17810b57cec5SDimitry Andric // ARM LDRD/STRD needs consecutive registers. 17820b57cec5SDimitry Andric bool NonConsecutiveRegs = (Opcode == ARM::LDRD || Opcode == ARM::STRD) && 17830b57cec5SDimitry Andric (EvenRegNum % 2 != 0 || EvenRegNum + 1 != OddRegNum); 17840b57cec5SDimitry Andric 17850b57cec5SDimitry Andric if (!Errata602117 && !NonConsecutiveRegs) 17860b57cec5SDimitry Andric return false; 17870b57cec5SDimitry Andric 17880b57cec5SDimitry Andric bool isT2 = Opcode == ARM::t2LDRDi8 || Opcode == ARM::t2STRDi8; 17890b57cec5SDimitry Andric bool isLd = Opcode == ARM::LDRD || Opcode == ARM::t2LDRDi8; 17900b57cec5SDimitry Andric bool EvenDeadKill = isLd ? 17910b57cec5SDimitry Andric MI->getOperand(0).isDead() : MI->getOperand(0).isKill(); 17920b57cec5SDimitry Andric bool EvenUndef = MI->getOperand(0).isUndef(); 17930b57cec5SDimitry Andric bool OddDeadKill = isLd ? 17940b57cec5SDimitry Andric MI->getOperand(1).isDead() : MI->getOperand(1).isKill(); 17950b57cec5SDimitry Andric bool OddUndef = MI->getOperand(1).isUndef(); 17960b57cec5SDimitry Andric bool BaseKill = BaseOp.isKill(); 17970b57cec5SDimitry Andric bool BaseUndef = BaseOp.isUndef(); 17980b57cec5SDimitry Andric assert((isT2 || MI->getOperand(3).getReg() == ARM::NoRegister) && 17990b57cec5SDimitry Andric "register offset not handled below"); 18000b57cec5SDimitry Andric int OffImm = getMemoryOpOffset(*MI); 18015ffd83dbSDimitry Andric Register PredReg; 18020b57cec5SDimitry Andric ARMCC::CondCodes Pred = getInstrPredicate(*MI, PredReg); 18030b57cec5SDimitry Andric 18040b57cec5SDimitry Andric if (OddRegNum > EvenRegNum && OffImm == 0) { 18050b57cec5SDimitry Andric // Ascending register numbers and no offset. It's safe to change it to a 18060b57cec5SDimitry Andric // ldm or stm. 18070b57cec5SDimitry Andric unsigned NewOpc = (isLd) 18080b57cec5SDimitry Andric ? (isT2 ? ARM::t2LDMIA : ARM::LDMIA) 18090b57cec5SDimitry Andric : (isT2 ? ARM::t2STMIA : ARM::STMIA); 18100b57cec5SDimitry Andric if (isLd) { 18110b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc)) 18120b57cec5SDimitry Andric .addReg(BaseReg, getKillRegState(BaseKill)) 18130b57cec5SDimitry Andric .addImm(Pred).addReg(PredReg) 18140b57cec5SDimitry Andric .addReg(EvenReg, getDefRegState(isLd) | getDeadRegState(EvenDeadKill)) 18150b57cec5SDimitry Andric .addReg(OddReg, getDefRegState(isLd) | getDeadRegState(OddDeadKill)) 18160b57cec5SDimitry Andric .cloneMemRefs(*MI); 18170b57cec5SDimitry Andric ++NumLDRD2LDM; 18180b57cec5SDimitry Andric } else { 18190b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc)) 18200b57cec5SDimitry Andric .addReg(BaseReg, getKillRegState(BaseKill)) 18210b57cec5SDimitry Andric .addImm(Pred).addReg(PredReg) 18220b57cec5SDimitry Andric .addReg(EvenReg, 18230b57cec5SDimitry Andric getKillRegState(EvenDeadKill) | getUndefRegState(EvenUndef)) 18240b57cec5SDimitry Andric .addReg(OddReg, 18250b57cec5SDimitry Andric getKillRegState(OddDeadKill) | getUndefRegState(OddUndef)) 18260b57cec5SDimitry Andric .cloneMemRefs(*MI); 18270b57cec5SDimitry Andric ++NumSTRD2STM; 18280b57cec5SDimitry Andric } 18290b57cec5SDimitry Andric } else { 18300b57cec5SDimitry Andric // Split into two instructions. 18310b57cec5SDimitry Andric unsigned NewOpc = (isLd) 18320b57cec5SDimitry Andric ? (isT2 ? (OffImm < 0 ? ARM::t2LDRi8 : ARM::t2LDRi12) : ARM::LDRi12) 18330b57cec5SDimitry Andric : (isT2 ? (OffImm < 0 ? ARM::t2STRi8 : ARM::t2STRi12) : ARM::STRi12); 18340b57cec5SDimitry Andric // Be extra careful for thumb2. t2LDRi8 can't reference a zero offset, 18350b57cec5SDimitry Andric // so adjust and use t2LDRi12 here for that. 18360b57cec5SDimitry Andric unsigned NewOpc2 = (isLd) 18370b57cec5SDimitry Andric ? (isT2 ? (OffImm+4 < 0 ? ARM::t2LDRi8 : ARM::t2LDRi12) : ARM::LDRi12) 18380b57cec5SDimitry Andric : (isT2 ? (OffImm+4 < 0 ? ARM::t2STRi8 : ARM::t2STRi12) : ARM::STRi12); 18390b57cec5SDimitry Andric // If this is a load, make sure the first load does not clobber the base 18400b57cec5SDimitry Andric // register before the second load reads it. 18410b57cec5SDimitry Andric if (isLd && TRI->regsOverlap(EvenReg, BaseReg)) { 18420b57cec5SDimitry Andric assert(!TRI->regsOverlap(OddReg, BaseReg)); 18430b57cec5SDimitry Andric InsertLDR_STR(MBB, MBBI, OffImm + 4, isLd, NewOpc2, OddReg, OddDeadKill, 18440b57cec5SDimitry Andric false, BaseReg, false, BaseUndef, Pred, PredReg, TII, MI); 18450b57cec5SDimitry Andric InsertLDR_STR(MBB, MBBI, OffImm, isLd, NewOpc, EvenReg, EvenDeadKill, 18460b57cec5SDimitry Andric false, BaseReg, BaseKill, BaseUndef, Pred, PredReg, TII, 18470b57cec5SDimitry Andric MI); 18480b57cec5SDimitry Andric } else { 18490b57cec5SDimitry Andric if (OddReg == EvenReg && EvenDeadKill) { 18500b57cec5SDimitry Andric // If the two source operands are the same, the kill marker is 18510b57cec5SDimitry Andric // probably on the first one. e.g. 18520b57cec5SDimitry Andric // t2STRDi8 killed %r5, %r5, killed %r9, 0, 14, %reg0 18530b57cec5SDimitry Andric EvenDeadKill = false; 18540b57cec5SDimitry Andric OddDeadKill = true; 18550b57cec5SDimitry Andric } 18560b57cec5SDimitry Andric // Never kill the base register in the first instruction. 18570b57cec5SDimitry Andric if (EvenReg == BaseReg) 18580b57cec5SDimitry Andric EvenDeadKill = false; 18590b57cec5SDimitry Andric InsertLDR_STR(MBB, MBBI, OffImm, isLd, NewOpc, EvenReg, EvenDeadKill, 18600b57cec5SDimitry Andric EvenUndef, BaseReg, false, BaseUndef, Pred, PredReg, TII, 18610b57cec5SDimitry Andric MI); 18620b57cec5SDimitry Andric InsertLDR_STR(MBB, MBBI, OffImm + 4, isLd, NewOpc2, OddReg, OddDeadKill, 18630b57cec5SDimitry Andric OddUndef, BaseReg, BaseKill, BaseUndef, Pred, PredReg, TII, 18640b57cec5SDimitry Andric MI); 18650b57cec5SDimitry Andric } 18660b57cec5SDimitry Andric if (isLd) 18670b57cec5SDimitry Andric ++NumLDRD2LDR; 18680b57cec5SDimitry Andric else 18690b57cec5SDimitry Andric ++NumSTRD2STR; 18700b57cec5SDimitry Andric } 18710b57cec5SDimitry Andric 18720b57cec5SDimitry Andric MBBI = MBB.erase(MBBI); 18730b57cec5SDimitry Andric return true; 18740b57cec5SDimitry Andric } 18750b57cec5SDimitry Andric 18760b57cec5SDimitry Andric /// An optimization pass to turn multiple LDR / STR ops of the same base and 18770b57cec5SDimitry Andric /// incrementing offset into LDM / STM ops. 18780b57cec5SDimitry Andric bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) { 18790b57cec5SDimitry Andric MemOpQueue MemOps; 18800b57cec5SDimitry Andric unsigned CurrBase = 0; 18810b57cec5SDimitry Andric unsigned CurrOpc = ~0u; 18820b57cec5SDimitry Andric ARMCC::CondCodes CurrPred = ARMCC::AL; 18830b57cec5SDimitry Andric unsigned Position = 0; 18840b57cec5SDimitry Andric assert(Candidates.size() == 0); 18850b57cec5SDimitry Andric assert(MergeBaseCandidates.size() == 0); 18860b57cec5SDimitry Andric LiveRegsValid = false; 18870b57cec5SDimitry Andric 18880b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = MBB.end(), MBBI; I != MBB.begin(); 18890b57cec5SDimitry Andric I = MBBI) { 18900b57cec5SDimitry Andric // The instruction in front of the iterator is the one we look at. 18910b57cec5SDimitry Andric MBBI = std::prev(I); 18920b57cec5SDimitry Andric if (FixInvalidRegPairOp(MBB, MBBI)) 18930b57cec5SDimitry Andric continue; 18940b57cec5SDimitry Andric ++Position; 18950b57cec5SDimitry Andric 18960b57cec5SDimitry Andric if (isMemoryOp(*MBBI)) { 18970b57cec5SDimitry Andric unsigned Opcode = MBBI->getOpcode(); 18980b57cec5SDimitry Andric const MachineOperand &MO = MBBI->getOperand(0); 18998bcb0991SDimitry Andric Register Reg = MO.getReg(); 19008bcb0991SDimitry Andric Register Base = getLoadStoreBaseOp(*MBBI).getReg(); 19015ffd83dbSDimitry Andric Register PredReg; 19020b57cec5SDimitry Andric ARMCC::CondCodes Pred = getInstrPredicate(*MBBI, PredReg); 19030b57cec5SDimitry Andric int Offset = getMemoryOpOffset(*MBBI); 19040b57cec5SDimitry Andric if (CurrBase == 0) { 19050b57cec5SDimitry Andric // Start of a new chain. 19060b57cec5SDimitry Andric CurrBase = Base; 19070b57cec5SDimitry Andric CurrOpc = Opcode; 19080b57cec5SDimitry Andric CurrPred = Pred; 19090b57cec5SDimitry Andric MemOps.push_back(MemOpQueueEntry(*MBBI, Offset, Position)); 19100b57cec5SDimitry Andric continue; 19110b57cec5SDimitry Andric } 19120b57cec5SDimitry Andric // Note: No need to match PredReg in the next if. 19130b57cec5SDimitry Andric if (CurrOpc == Opcode && CurrBase == Base && CurrPred == Pred) { 19140b57cec5SDimitry Andric // Watch out for: 19150b57cec5SDimitry Andric // r4 := ldr [r0, #8] 19160b57cec5SDimitry Andric // r4 := ldr [r0, #4] 19170b57cec5SDimitry Andric // or 19180b57cec5SDimitry Andric // r0 := ldr [r0] 19190b57cec5SDimitry Andric // If a load overrides the base register or a register loaded by 19200b57cec5SDimitry Andric // another load in our chain, we cannot take this instruction. 19210b57cec5SDimitry Andric bool Overlap = false; 19220b57cec5SDimitry Andric if (isLoadSingle(Opcode)) { 19230b57cec5SDimitry Andric Overlap = (Base == Reg); 19240b57cec5SDimitry Andric if (!Overlap) { 19250b57cec5SDimitry Andric for (const MemOpQueueEntry &E : MemOps) { 19260b57cec5SDimitry Andric if (TRI->regsOverlap(Reg, E.MI->getOperand(0).getReg())) { 19270b57cec5SDimitry Andric Overlap = true; 19280b57cec5SDimitry Andric break; 19290b57cec5SDimitry Andric } 19300b57cec5SDimitry Andric } 19310b57cec5SDimitry Andric } 19320b57cec5SDimitry Andric } 19330b57cec5SDimitry Andric 19340b57cec5SDimitry Andric if (!Overlap) { 19350b57cec5SDimitry Andric // Check offset and sort memory operation into the current chain. 19360b57cec5SDimitry Andric if (Offset > MemOps.back().Offset) { 19370b57cec5SDimitry Andric MemOps.push_back(MemOpQueueEntry(*MBBI, Offset, Position)); 19380b57cec5SDimitry Andric continue; 19390b57cec5SDimitry Andric } else { 19400b57cec5SDimitry Andric MemOpQueue::iterator MI, ME; 19410b57cec5SDimitry Andric for (MI = MemOps.begin(), ME = MemOps.end(); MI != ME; ++MI) { 19420b57cec5SDimitry Andric if (Offset < MI->Offset) { 19430b57cec5SDimitry Andric // Found a place to insert. 19440b57cec5SDimitry Andric break; 19450b57cec5SDimitry Andric } 19460b57cec5SDimitry Andric if (Offset == MI->Offset) { 19470b57cec5SDimitry Andric // Collision, abort. 19480b57cec5SDimitry Andric MI = ME; 19490b57cec5SDimitry Andric break; 19500b57cec5SDimitry Andric } 19510b57cec5SDimitry Andric } 19520b57cec5SDimitry Andric if (MI != MemOps.end()) { 19530b57cec5SDimitry Andric MemOps.insert(MI, MemOpQueueEntry(*MBBI, Offset, Position)); 19540b57cec5SDimitry Andric continue; 19550b57cec5SDimitry Andric } 19560b57cec5SDimitry Andric } 19570b57cec5SDimitry Andric } 19580b57cec5SDimitry Andric } 19590b57cec5SDimitry Andric 19600b57cec5SDimitry Andric // Don't advance the iterator; The op will start a new chain next. 19610b57cec5SDimitry Andric MBBI = I; 19620b57cec5SDimitry Andric --Position; 19630b57cec5SDimitry Andric // Fallthrough to look into existing chain. 19640b57cec5SDimitry Andric } else if (MBBI->isDebugInstr()) { 19650b57cec5SDimitry Andric continue; 19660b57cec5SDimitry Andric } else if (MBBI->getOpcode() == ARM::t2LDRDi8 || 19670b57cec5SDimitry Andric MBBI->getOpcode() == ARM::t2STRDi8) { 19680b57cec5SDimitry Andric // ARMPreAllocLoadStoreOpt has already formed some LDRD/STRD instructions 19690b57cec5SDimitry Andric // remember them because we may still be able to merge add/sub into them. 19700b57cec5SDimitry Andric MergeBaseCandidates.push_back(&*MBBI); 19710b57cec5SDimitry Andric } 19720b57cec5SDimitry Andric 19730b57cec5SDimitry Andric // If we are here then the chain is broken; Extract candidates for a merge. 19740b57cec5SDimitry Andric if (MemOps.size() > 0) { 19750b57cec5SDimitry Andric FormCandidates(MemOps); 19760b57cec5SDimitry Andric // Reset for the next chain. 19770b57cec5SDimitry Andric CurrBase = 0; 19780b57cec5SDimitry Andric CurrOpc = ~0u; 19790b57cec5SDimitry Andric CurrPred = ARMCC::AL; 19800b57cec5SDimitry Andric MemOps.clear(); 19810b57cec5SDimitry Andric } 19820b57cec5SDimitry Andric } 19830b57cec5SDimitry Andric if (MemOps.size() > 0) 19840b57cec5SDimitry Andric FormCandidates(MemOps); 19850b57cec5SDimitry Andric 19860b57cec5SDimitry Andric // Sort candidates so they get processed from end to begin of the basic 19870b57cec5SDimitry Andric // block later; This is necessary for liveness calculation. 19880b57cec5SDimitry Andric auto LessThan = [](const MergeCandidate* M0, const MergeCandidate *M1) { 19890b57cec5SDimitry Andric return M0->InsertPos < M1->InsertPos; 19900b57cec5SDimitry Andric }; 19910b57cec5SDimitry Andric llvm::sort(Candidates, LessThan); 19920b57cec5SDimitry Andric 19930b57cec5SDimitry Andric // Go through list of candidates and merge. 19940b57cec5SDimitry Andric bool Changed = false; 19950b57cec5SDimitry Andric for (const MergeCandidate *Candidate : Candidates) { 19960b57cec5SDimitry Andric if (Candidate->CanMergeToLSMulti || Candidate->CanMergeToLSDouble) { 19970b57cec5SDimitry Andric MachineInstr *Merged = MergeOpsUpdate(*Candidate); 19980b57cec5SDimitry Andric // Merge preceding/trailing base inc/dec into the merged op. 19990b57cec5SDimitry Andric if (Merged) { 20000b57cec5SDimitry Andric Changed = true; 20010b57cec5SDimitry Andric unsigned Opcode = Merged->getOpcode(); 20020b57cec5SDimitry Andric if (Opcode == ARM::t2STRDi8 || Opcode == ARM::t2LDRDi8) 20030b57cec5SDimitry Andric MergeBaseUpdateLSDouble(*Merged); 20040b57cec5SDimitry Andric else 20050b57cec5SDimitry Andric MergeBaseUpdateLSMultiple(Merged); 20060b57cec5SDimitry Andric } else { 20070b57cec5SDimitry Andric for (MachineInstr *MI : Candidate->Instrs) { 20080b57cec5SDimitry Andric if (MergeBaseUpdateLoadStore(MI)) 20090b57cec5SDimitry Andric Changed = true; 20100b57cec5SDimitry Andric } 20110b57cec5SDimitry Andric } 20120b57cec5SDimitry Andric } else { 20130b57cec5SDimitry Andric assert(Candidate->Instrs.size() == 1); 20140b57cec5SDimitry Andric if (MergeBaseUpdateLoadStore(Candidate->Instrs.front())) 20150b57cec5SDimitry Andric Changed = true; 20160b57cec5SDimitry Andric } 20170b57cec5SDimitry Andric } 20180b57cec5SDimitry Andric Candidates.clear(); 20190b57cec5SDimitry Andric // Try to fold add/sub into the LDRD/STRD formed by ARMPreAllocLoadStoreOpt. 20200b57cec5SDimitry Andric for (MachineInstr *MI : MergeBaseCandidates) 20210b57cec5SDimitry Andric MergeBaseUpdateLSDouble(*MI); 20220b57cec5SDimitry Andric MergeBaseCandidates.clear(); 20230b57cec5SDimitry Andric 20240b57cec5SDimitry Andric return Changed; 20250b57cec5SDimitry Andric } 20260b57cec5SDimitry Andric 20270b57cec5SDimitry Andric /// If this is a exit BB, try merging the return ops ("bx lr" and "mov pc, lr") 20280b57cec5SDimitry Andric /// into the preceding stack restore so it directly restore the value of LR 20290b57cec5SDimitry Andric /// into pc. 20300b57cec5SDimitry Andric /// ldmfd sp!, {..., lr} 20310b57cec5SDimitry Andric /// bx lr 20320b57cec5SDimitry Andric /// or 20330b57cec5SDimitry Andric /// ldmfd sp!, {..., lr} 20340b57cec5SDimitry Andric /// mov pc, lr 20350b57cec5SDimitry Andric /// => 20360b57cec5SDimitry Andric /// ldmfd sp!, {..., pc} 20370b57cec5SDimitry Andric bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) { 20380b57cec5SDimitry Andric // Thumb1 LDM doesn't allow high registers. 20390b57cec5SDimitry Andric if (isThumb1) return false; 20400b57cec5SDimitry Andric if (MBB.empty()) return false; 20410b57cec5SDimitry Andric 20420b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); 20430b57cec5SDimitry Andric if (MBBI != MBB.begin() && MBBI != MBB.end() && 20440b57cec5SDimitry Andric (MBBI->getOpcode() == ARM::BX_RET || 20450b57cec5SDimitry Andric MBBI->getOpcode() == ARM::tBX_RET || 20460b57cec5SDimitry Andric MBBI->getOpcode() == ARM::MOVPCLR)) { 20470b57cec5SDimitry Andric MachineBasicBlock::iterator PrevI = std::prev(MBBI); 20480b57cec5SDimitry Andric // Ignore any debug instructions. 20490b57cec5SDimitry Andric while (PrevI->isDebugInstr() && PrevI != MBB.begin()) 20500b57cec5SDimitry Andric --PrevI; 20510b57cec5SDimitry Andric MachineInstr &PrevMI = *PrevI; 20520b57cec5SDimitry Andric unsigned Opcode = PrevMI.getOpcode(); 20530b57cec5SDimitry Andric if (Opcode == ARM::LDMIA_UPD || Opcode == ARM::LDMDA_UPD || 20540b57cec5SDimitry Andric Opcode == ARM::LDMDB_UPD || Opcode == ARM::LDMIB_UPD || 20550b57cec5SDimitry Andric Opcode == ARM::t2LDMIA_UPD || Opcode == ARM::t2LDMDB_UPD) { 20560b57cec5SDimitry Andric MachineOperand &MO = PrevMI.getOperand(PrevMI.getNumOperands() - 1); 20570b57cec5SDimitry Andric if (MO.getReg() != ARM::LR) 20580b57cec5SDimitry Andric return false; 20590b57cec5SDimitry Andric unsigned NewOpc = (isThumb2 ? ARM::t2LDMIA_RET : ARM::LDMIA_RET); 20600b57cec5SDimitry Andric assert(((isThumb2 && Opcode == ARM::t2LDMIA_UPD) || 20610b57cec5SDimitry Andric Opcode == ARM::LDMIA_UPD) && "Unsupported multiple load-return!"); 20620b57cec5SDimitry Andric PrevMI.setDesc(TII->get(NewOpc)); 20630b57cec5SDimitry Andric MO.setReg(ARM::PC); 20640b57cec5SDimitry Andric PrevMI.copyImplicitOps(*MBB.getParent(), *MBBI); 20650b57cec5SDimitry Andric MBB.erase(MBBI); 20660b57cec5SDimitry Andric return true; 20670b57cec5SDimitry Andric } 20680b57cec5SDimitry Andric } 20690b57cec5SDimitry Andric return false; 20700b57cec5SDimitry Andric } 20710b57cec5SDimitry Andric 20720b57cec5SDimitry Andric bool ARMLoadStoreOpt::CombineMovBx(MachineBasicBlock &MBB) { 20730b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); 20740b57cec5SDimitry Andric if (MBBI == MBB.begin() || MBBI == MBB.end() || 20750b57cec5SDimitry Andric MBBI->getOpcode() != ARM::tBX_RET) 20760b57cec5SDimitry Andric return false; 20770b57cec5SDimitry Andric 20780b57cec5SDimitry Andric MachineBasicBlock::iterator Prev = MBBI; 20790b57cec5SDimitry Andric --Prev; 2080*0fca6ea1SDimitry Andric if (Prev->getOpcode() != ARM::tMOVr || 2081*0fca6ea1SDimitry Andric !Prev->definesRegister(ARM::LR, /*TRI=*/nullptr)) 20820b57cec5SDimitry Andric return false; 20830b57cec5SDimitry Andric 20840b57cec5SDimitry Andric for (auto Use : Prev->uses()) 20850b57cec5SDimitry Andric if (Use.isKill()) { 20860b57cec5SDimitry Andric assert(STI->hasV4TOps()); 20870b57cec5SDimitry Andric BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(ARM::tBX)) 20880b57cec5SDimitry Andric .addReg(Use.getReg(), RegState::Kill) 20890b57cec5SDimitry Andric .add(predOps(ARMCC::AL)) 20900b57cec5SDimitry Andric .copyImplicitOps(*MBBI); 20910b57cec5SDimitry Andric MBB.erase(MBBI); 20920b57cec5SDimitry Andric MBB.erase(Prev); 20930b57cec5SDimitry Andric return true; 20940b57cec5SDimitry Andric } 20950b57cec5SDimitry Andric 20960b57cec5SDimitry Andric llvm_unreachable("tMOVr doesn't kill a reg before tBX_RET?"); 20970b57cec5SDimitry Andric } 20980b57cec5SDimitry Andric 20990b57cec5SDimitry Andric bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) { 21000b57cec5SDimitry Andric if (skipFunction(Fn.getFunction())) 21010b57cec5SDimitry Andric return false; 21020b57cec5SDimitry Andric 21030b57cec5SDimitry Andric MF = &Fn; 210481ad6265SDimitry Andric STI = &Fn.getSubtarget<ARMSubtarget>(); 21050b57cec5SDimitry Andric TL = STI->getTargetLowering(); 21060b57cec5SDimitry Andric AFI = Fn.getInfo<ARMFunctionInfo>(); 21070b57cec5SDimitry Andric TII = STI->getInstrInfo(); 21080b57cec5SDimitry Andric TRI = STI->getRegisterInfo(); 21090b57cec5SDimitry Andric 21100b57cec5SDimitry Andric RegClassInfoValid = false; 21110b57cec5SDimitry Andric isThumb2 = AFI->isThumb2Function(); 21120b57cec5SDimitry Andric isThumb1 = AFI->isThumbFunction() && !isThumb2; 21130b57cec5SDimitry Andric 2114439352acSDimitry Andric bool Modified = false, ModifiedLDMReturn = false; 21154824e7fdSDimitry Andric for (MachineBasicBlock &MBB : Fn) { 21160b57cec5SDimitry Andric Modified |= LoadStoreMultipleOpti(MBB); 21170eae32dcSDimitry Andric if (STI->hasV5TOps() && !AFI->shouldSignReturnAddress()) 2118439352acSDimitry Andric ModifiedLDMReturn |= MergeReturnIntoLDM(MBB); 21190b57cec5SDimitry Andric if (isThumb1) 21200b57cec5SDimitry Andric Modified |= CombineMovBx(MBB); 21210b57cec5SDimitry Andric } 2122439352acSDimitry Andric Modified |= ModifiedLDMReturn; 2123439352acSDimitry Andric 2124439352acSDimitry Andric // If we merged a BX instruction into an LDM, we need to re-calculate whether 2125439352acSDimitry Andric // LR is restored. This check needs to consider the whole function, not just 2126439352acSDimitry Andric // the instruction(s) we changed, because there may be other BX returns which 2127439352acSDimitry Andric // still need LR to be restored. 2128439352acSDimitry Andric if (ModifiedLDMReturn) 2129439352acSDimitry Andric ARMFrameLowering::updateLRRestored(Fn); 21300b57cec5SDimitry Andric 21310b57cec5SDimitry Andric Allocator.DestroyAll(); 21320b57cec5SDimitry Andric return Modified; 21330b57cec5SDimitry Andric } 21340b57cec5SDimitry Andric 21350b57cec5SDimitry Andric #define ARM_PREALLOC_LOAD_STORE_OPT_NAME \ 21360b57cec5SDimitry Andric "ARM pre- register allocation load / store optimization pass" 21370b57cec5SDimitry Andric 21380b57cec5SDimitry Andric namespace { 21390b57cec5SDimitry Andric 21400b57cec5SDimitry Andric /// Pre- register allocation pass that move load / stores from consecutive 21410b57cec5SDimitry Andric /// locations close to make it more likely they will be combined later. 21420b57cec5SDimitry Andric struct ARMPreAllocLoadStoreOpt : public MachineFunctionPass{ 21430b57cec5SDimitry Andric static char ID; 21440b57cec5SDimitry Andric 21450b57cec5SDimitry Andric AliasAnalysis *AA; 21460b57cec5SDimitry Andric const DataLayout *TD; 21470b57cec5SDimitry Andric const TargetInstrInfo *TII; 21480b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 21490b57cec5SDimitry Andric const ARMSubtarget *STI; 21500b57cec5SDimitry Andric MachineRegisterInfo *MRI; 21515ffd83dbSDimitry Andric MachineDominatorTree *DT; 21520b57cec5SDimitry Andric MachineFunction *MF; 21530b57cec5SDimitry Andric 21540b57cec5SDimitry Andric ARMPreAllocLoadStoreOpt() : MachineFunctionPass(ID) {} 21550b57cec5SDimitry Andric 21560b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override; 21570b57cec5SDimitry Andric 21580b57cec5SDimitry Andric StringRef getPassName() const override { 21590b57cec5SDimitry Andric return ARM_PREALLOC_LOAD_STORE_OPT_NAME; 21600b57cec5SDimitry Andric } 21610b57cec5SDimitry Andric 21620b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 21630b57cec5SDimitry Andric AU.addRequired<AAResultsWrapperPass>(); 2164*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 2165*0fca6ea1SDimitry Andric AU.addPreserved<MachineDominatorTreeWrapperPass>(); 21660b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 21670b57cec5SDimitry Andric } 21680b57cec5SDimitry Andric 21690b57cec5SDimitry Andric private: 21700b57cec5SDimitry Andric bool CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1, DebugLoc &dl, 21715ffd83dbSDimitry Andric unsigned &NewOpc, Register &EvenReg, Register &OddReg, 21725ffd83dbSDimitry Andric Register &BaseReg, int &Offset, Register &PredReg, 21735ffd83dbSDimitry Andric ARMCC::CondCodes &Pred, bool &isT2); 217406c3fb27SDimitry Andric bool RescheduleOps( 217506c3fb27SDimitry Andric MachineBasicBlock *MBB, SmallVectorImpl<MachineInstr *> &Ops, 217606c3fb27SDimitry Andric unsigned Base, bool isLd, DenseMap<MachineInstr *, unsigned> &MI2LocMap, 217706c3fb27SDimitry Andric SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> &RegisterMap); 21780b57cec5SDimitry Andric bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB); 21795ffd83dbSDimitry Andric bool DistributeIncrements(); 21805ffd83dbSDimitry Andric bool DistributeIncrements(Register Base); 21810b57cec5SDimitry Andric }; 21820b57cec5SDimitry Andric 21830b57cec5SDimitry Andric } // end anonymous namespace 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric char ARMPreAllocLoadStoreOpt::ID = 0; 21860b57cec5SDimitry Andric 21875ffd83dbSDimitry Andric INITIALIZE_PASS_BEGIN(ARMPreAllocLoadStoreOpt, "arm-prera-ldst-opt", 21885ffd83dbSDimitry Andric ARM_PREALLOC_LOAD_STORE_OPT_NAME, false, false) 2189*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 21905ffd83dbSDimitry Andric INITIALIZE_PASS_END(ARMPreAllocLoadStoreOpt, "arm-prera-ldst-opt", 21910b57cec5SDimitry Andric ARM_PREALLOC_LOAD_STORE_OPT_NAME, false, false) 21920b57cec5SDimitry Andric 21930b57cec5SDimitry Andric // Limit the number of instructions to be rescheduled. 21940b57cec5SDimitry Andric // FIXME: tune this limit, and/or come up with some better heuristics. 21950b57cec5SDimitry Andric static cl::opt<unsigned> InstReorderLimit("arm-prera-ldst-opt-reorder-limit", 21960b57cec5SDimitry Andric cl::init(8), cl::Hidden); 21970b57cec5SDimitry Andric 21980b57cec5SDimitry Andric bool ARMPreAllocLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) { 21990b57cec5SDimitry Andric if (AssumeMisalignedLoadStores || skipFunction(Fn.getFunction())) 22000b57cec5SDimitry Andric return false; 22010b57cec5SDimitry Andric 22020b57cec5SDimitry Andric TD = &Fn.getDataLayout(); 220381ad6265SDimitry Andric STI = &Fn.getSubtarget<ARMSubtarget>(); 22040b57cec5SDimitry Andric TII = STI->getInstrInfo(); 22050b57cec5SDimitry Andric TRI = STI->getRegisterInfo(); 22060b57cec5SDimitry Andric MRI = &Fn.getRegInfo(); 2207*0fca6ea1SDimitry Andric DT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 22080b57cec5SDimitry Andric MF = &Fn; 22090b57cec5SDimitry Andric AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); 22100b57cec5SDimitry Andric 22115ffd83dbSDimitry Andric bool Modified = DistributeIncrements(); 22120b57cec5SDimitry Andric for (MachineBasicBlock &MFI : Fn) 22130b57cec5SDimitry Andric Modified |= RescheduleLoadStoreInstrs(&MFI); 22140b57cec5SDimitry Andric 22150b57cec5SDimitry Andric return Modified; 22160b57cec5SDimitry Andric } 22170b57cec5SDimitry Andric 22180b57cec5SDimitry Andric static bool IsSafeAndProfitableToMove(bool isLd, unsigned Base, 22190b57cec5SDimitry Andric MachineBasicBlock::iterator I, 22200b57cec5SDimitry Andric MachineBasicBlock::iterator E, 22210b57cec5SDimitry Andric SmallPtrSetImpl<MachineInstr*> &MemOps, 22220b57cec5SDimitry Andric SmallSet<unsigned, 4> &MemRegs, 22230b57cec5SDimitry Andric const TargetRegisterInfo *TRI, 22240b57cec5SDimitry Andric AliasAnalysis *AA) { 22250b57cec5SDimitry Andric // Are there stores / loads / calls between them? 22260b57cec5SDimitry Andric SmallSet<unsigned, 4> AddedRegPressure; 22270b57cec5SDimitry Andric while (++I != E) { 22280b57cec5SDimitry Andric if (I->isDebugInstr() || MemOps.count(&*I)) 22290b57cec5SDimitry Andric continue; 22300b57cec5SDimitry Andric if (I->isCall() || I->isTerminator() || I->hasUnmodeledSideEffects()) 22310b57cec5SDimitry Andric return false; 22320b57cec5SDimitry Andric if (I->mayStore() || (!isLd && I->mayLoad())) 22330b57cec5SDimitry Andric for (MachineInstr *MemOp : MemOps) 22340b57cec5SDimitry Andric if (I->mayAlias(AA, *MemOp, /*UseTBAA*/ false)) 22350b57cec5SDimitry Andric return false; 22360b57cec5SDimitry Andric for (unsigned j = 0, NumOps = I->getNumOperands(); j != NumOps; ++j) { 22370b57cec5SDimitry Andric MachineOperand &MO = I->getOperand(j); 22380b57cec5SDimitry Andric if (!MO.isReg()) 22390b57cec5SDimitry Andric continue; 22408bcb0991SDimitry Andric Register Reg = MO.getReg(); 22410b57cec5SDimitry Andric if (MO.isDef() && TRI->regsOverlap(Reg, Base)) 22420b57cec5SDimitry Andric return false; 22430b57cec5SDimitry Andric if (Reg != Base && !MemRegs.count(Reg)) 22440b57cec5SDimitry Andric AddedRegPressure.insert(Reg); 22450b57cec5SDimitry Andric } 22460b57cec5SDimitry Andric } 22470b57cec5SDimitry Andric 22480b57cec5SDimitry Andric // Estimate register pressure increase due to the transformation. 22490b57cec5SDimitry Andric if (MemRegs.size() <= 4) 22500b57cec5SDimitry Andric // Ok if we are moving small number of instructions. 22510b57cec5SDimitry Andric return true; 22520b57cec5SDimitry Andric return AddedRegPressure.size() <= MemRegs.size() * 2; 22530b57cec5SDimitry Andric } 22540b57cec5SDimitry Andric 22555ffd83dbSDimitry Andric bool ARMPreAllocLoadStoreOpt::CanFormLdStDWord( 22565ffd83dbSDimitry Andric MachineInstr *Op0, MachineInstr *Op1, DebugLoc &dl, unsigned &NewOpc, 22575ffd83dbSDimitry Andric Register &FirstReg, Register &SecondReg, Register &BaseReg, int &Offset, 22585ffd83dbSDimitry Andric Register &PredReg, ARMCC::CondCodes &Pred, bool &isT2) { 22590b57cec5SDimitry Andric // Make sure we're allowed to generate LDRD/STRD. 22600b57cec5SDimitry Andric if (!STI->hasV5TEOps()) 22610b57cec5SDimitry Andric return false; 22620b57cec5SDimitry Andric 22630b57cec5SDimitry Andric // FIXME: VLDRS / VSTRS -> VLDRD / VSTRD 22640b57cec5SDimitry Andric unsigned Scale = 1; 22650b57cec5SDimitry Andric unsigned Opcode = Op0->getOpcode(); 22660b57cec5SDimitry Andric if (Opcode == ARM::LDRi12) { 22670b57cec5SDimitry Andric NewOpc = ARM::LDRD; 22680b57cec5SDimitry Andric } else if (Opcode == ARM::STRi12) { 22690b57cec5SDimitry Andric NewOpc = ARM::STRD; 22700b57cec5SDimitry Andric } else if (Opcode == ARM::t2LDRi8 || Opcode == ARM::t2LDRi12) { 22710b57cec5SDimitry Andric NewOpc = ARM::t2LDRDi8; 22720b57cec5SDimitry Andric Scale = 4; 22730b57cec5SDimitry Andric isT2 = true; 22740b57cec5SDimitry Andric } else if (Opcode == ARM::t2STRi8 || Opcode == ARM::t2STRi12) { 22750b57cec5SDimitry Andric NewOpc = ARM::t2STRDi8; 22760b57cec5SDimitry Andric Scale = 4; 22770b57cec5SDimitry Andric isT2 = true; 22780b57cec5SDimitry Andric } else { 22790b57cec5SDimitry Andric return false; 22800b57cec5SDimitry Andric } 22810b57cec5SDimitry Andric 22820b57cec5SDimitry Andric // Make sure the base address satisfies i64 ld / st alignment requirement. 22830b57cec5SDimitry Andric // At the moment, we ignore the memoryoperand's value. 22840b57cec5SDimitry Andric // If we want to use AliasAnalysis, we should check it accordingly. 22850b57cec5SDimitry Andric if (!Op0->hasOneMemOperand() || 22860b57cec5SDimitry Andric (*Op0->memoperands_begin())->isVolatile() || 22870b57cec5SDimitry Andric (*Op0->memoperands_begin())->isAtomic()) 22880b57cec5SDimitry Andric return false; 22890b57cec5SDimitry Andric 22905ffd83dbSDimitry Andric Align Alignment = (*Op0->memoperands_begin())->getAlign(); 229106c3fb27SDimitry Andric Align ReqAlign = STI->getDualLoadStoreAlignment(); 22925ffd83dbSDimitry Andric if (Alignment < ReqAlign) 22930b57cec5SDimitry Andric return false; 22940b57cec5SDimitry Andric 22950b57cec5SDimitry Andric // Then make sure the immediate offset fits. 22960b57cec5SDimitry Andric int OffImm = getMemoryOpOffset(*Op0); 22970b57cec5SDimitry Andric if (isT2) { 22980b57cec5SDimitry Andric int Limit = (1 << 8) * Scale; 22990b57cec5SDimitry Andric if (OffImm >= Limit || (OffImm <= -Limit) || (OffImm & (Scale-1))) 23000b57cec5SDimitry Andric return false; 23010b57cec5SDimitry Andric Offset = OffImm; 23020b57cec5SDimitry Andric } else { 23030b57cec5SDimitry Andric ARM_AM::AddrOpc AddSub = ARM_AM::add; 23040b57cec5SDimitry Andric if (OffImm < 0) { 23050b57cec5SDimitry Andric AddSub = ARM_AM::sub; 23060b57cec5SDimitry Andric OffImm = - OffImm; 23070b57cec5SDimitry Andric } 23080b57cec5SDimitry Andric int Limit = (1 << 8) * Scale; 23090b57cec5SDimitry Andric if (OffImm >= Limit || (OffImm & (Scale-1))) 23100b57cec5SDimitry Andric return false; 23110b57cec5SDimitry Andric Offset = ARM_AM::getAM3Opc(AddSub, OffImm); 23120b57cec5SDimitry Andric } 23130b57cec5SDimitry Andric FirstReg = Op0->getOperand(0).getReg(); 23140b57cec5SDimitry Andric SecondReg = Op1->getOperand(0).getReg(); 23150b57cec5SDimitry Andric if (FirstReg == SecondReg) 23160b57cec5SDimitry Andric return false; 23170b57cec5SDimitry Andric BaseReg = Op0->getOperand(1).getReg(); 23180b57cec5SDimitry Andric Pred = getInstrPredicate(*Op0, PredReg); 23190b57cec5SDimitry Andric dl = Op0->getDebugLoc(); 23200b57cec5SDimitry Andric return true; 23210b57cec5SDimitry Andric } 23220b57cec5SDimitry Andric 232306c3fb27SDimitry Andric bool ARMPreAllocLoadStoreOpt::RescheduleOps( 232406c3fb27SDimitry Andric MachineBasicBlock *MBB, SmallVectorImpl<MachineInstr *> &Ops, unsigned Base, 232506c3fb27SDimitry Andric bool isLd, DenseMap<MachineInstr *, unsigned> &MI2LocMap, 232606c3fb27SDimitry Andric SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> &RegisterMap) { 23270b57cec5SDimitry Andric bool RetVal = false; 23280b57cec5SDimitry Andric 23290b57cec5SDimitry Andric // Sort by offset (in reverse order). 23300b57cec5SDimitry Andric llvm::sort(Ops, [](const MachineInstr *LHS, const MachineInstr *RHS) { 23310b57cec5SDimitry Andric int LOffset = getMemoryOpOffset(*LHS); 23320b57cec5SDimitry Andric int ROffset = getMemoryOpOffset(*RHS); 23330b57cec5SDimitry Andric assert(LHS == RHS || LOffset != ROffset); 23340b57cec5SDimitry Andric return LOffset > ROffset; 23350b57cec5SDimitry Andric }); 23360b57cec5SDimitry Andric 23370b57cec5SDimitry Andric // The loads / stores of the same base are in order. Scan them from first to 23380b57cec5SDimitry Andric // last and check for the following: 23390b57cec5SDimitry Andric // 1. Any def of base. 23400b57cec5SDimitry Andric // 2. Any gaps. 23410b57cec5SDimitry Andric while (Ops.size() > 1) { 23420b57cec5SDimitry Andric unsigned FirstLoc = ~0U; 23430b57cec5SDimitry Andric unsigned LastLoc = 0; 23440b57cec5SDimitry Andric MachineInstr *FirstOp = nullptr; 23450b57cec5SDimitry Andric MachineInstr *LastOp = nullptr; 23460b57cec5SDimitry Andric int LastOffset = 0; 23470b57cec5SDimitry Andric unsigned LastOpcode = 0; 23480b57cec5SDimitry Andric unsigned LastBytes = 0; 23490b57cec5SDimitry Andric unsigned NumMove = 0; 23500eae32dcSDimitry Andric for (MachineInstr *Op : llvm::reverse(Ops)) { 23510b57cec5SDimitry Andric // Make sure each operation has the same kind. 23520b57cec5SDimitry Andric unsigned LSMOpcode 23530b57cec5SDimitry Andric = getLoadStoreMultipleOpcode(Op->getOpcode(), ARM_AM::ia); 23540b57cec5SDimitry Andric if (LastOpcode && LSMOpcode != LastOpcode) 23550b57cec5SDimitry Andric break; 23560b57cec5SDimitry Andric 23570b57cec5SDimitry Andric // Check that we have a continuous set of offsets. 23580b57cec5SDimitry Andric int Offset = getMemoryOpOffset(*Op); 23590b57cec5SDimitry Andric unsigned Bytes = getLSMultipleTransferSize(Op); 23600b57cec5SDimitry Andric if (LastBytes) { 23610b57cec5SDimitry Andric if (Bytes != LastBytes || Offset != (LastOffset + (int)Bytes)) 23620b57cec5SDimitry Andric break; 23630b57cec5SDimitry Andric } 23640b57cec5SDimitry Andric 23650b57cec5SDimitry Andric // Don't try to reschedule too many instructions. 23660b57cec5SDimitry Andric if (NumMove == InstReorderLimit) 23670b57cec5SDimitry Andric break; 23680b57cec5SDimitry Andric 23690b57cec5SDimitry Andric // Found a mergable instruction; save information about it. 23700b57cec5SDimitry Andric ++NumMove; 23710b57cec5SDimitry Andric LastOffset = Offset; 23720b57cec5SDimitry Andric LastBytes = Bytes; 23730b57cec5SDimitry Andric LastOpcode = LSMOpcode; 23740b57cec5SDimitry Andric 23750b57cec5SDimitry Andric unsigned Loc = MI2LocMap[Op]; 23760b57cec5SDimitry Andric if (Loc <= FirstLoc) { 23770b57cec5SDimitry Andric FirstLoc = Loc; 23780b57cec5SDimitry Andric FirstOp = Op; 23790b57cec5SDimitry Andric } 23800b57cec5SDimitry Andric if (Loc >= LastLoc) { 23810b57cec5SDimitry Andric LastLoc = Loc; 23820b57cec5SDimitry Andric LastOp = Op; 23830b57cec5SDimitry Andric } 23840b57cec5SDimitry Andric } 23850b57cec5SDimitry Andric 23860b57cec5SDimitry Andric if (NumMove <= 1) 23870b57cec5SDimitry Andric Ops.pop_back(); 23880b57cec5SDimitry Andric else { 23890b57cec5SDimitry Andric SmallPtrSet<MachineInstr*, 4> MemOps; 23900b57cec5SDimitry Andric SmallSet<unsigned, 4> MemRegs; 23910b57cec5SDimitry Andric for (size_t i = Ops.size() - NumMove, e = Ops.size(); i != e; ++i) { 23920b57cec5SDimitry Andric MemOps.insert(Ops[i]); 23930b57cec5SDimitry Andric MemRegs.insert(Ops[i]->getOperand(0).getReg()); 23940b57cec5SDimitry Andric } 23950b57cec5SDimitry Andric 23960b57cec5SDimitry Andric // Be conservative, if the instructions are too far apart, don't 23970b57cec5SDimitry Andric // move them. We want to limit the increase of register pressure. 23980b57cec5SDimitry Andric bool DoMove = (LastLoc - FirstLoc) <= NumMove*4; // FIXME: Tune this. 23990b57cec5SDimitry Andric if (DoMove) 24000b57cec5SDimitry Andric DoMove = IsSafeAndProfitableToMove(isLd, Base, FirstOp, LastOp, 24010b57cec5SDimitry Andric MemOps, MemRegs, TRI, AA); 24020b57cec5SDimitry Andric if (!DoMove) { 24030b57cec5SDimitry Andric for (unsigned i = 0; i != NumMove; ++i) 24040b57cec5SDimitry Andric Ops.pop_back(); 24050b57cec5SDimitry Andric } else { 24060b57cec5SDimitry Andric // This is the new location for the loads / stores. 24070b57cec5SDimitry Andric MachineBasicBlock::iterator InsertPos = isLd ? FirstOp : LastOp; 24080b57cec5SDimitry Andric while (InsertPos != MBB->end() && 24090b57cec5SDimitry Andric (MemOps.count(&*InsertPos) || InsertPos->isDebugInstr())) 24100b57cec5SDimitry Andric ++InsertPos; 24110b57cec5SDimitry Andric 24120b57cec5SDimitry Andric // If we are moving a pair of loads / stores, see if it makes sense 24130b57cec5SDimitry Andric // to try to allocate a pair of registers that can form register pairs. 24140b57cec5SDimitry Andric MachineInstr *Op0 = Ops.back(); 24150b57cec5SDimitry Andric MachineInstr *Op1 = Ops[Ops.size()-2]; 24165ffd83dbSDimitry Andric Register FirstReg, SecondReg; 24175ffd83dbSDimitry Andric Register BaseReg, PredReg; 24180b57cec5SDimitry Andric ARMCC::CondCodes Pred = ARMCC::AL; 24190b57cec5SDimitry Andric bool isT2 = false; 24200b57cec5SDimitry Andric unsigned NewOpc = 0; 24210b57cec5SDimitry Andric int Offset = 0; 24220b57cec5SDimitry Andric DebugLoc dl; 24230b57cec5SDimitry Andric if (NumMove == 2 && CanFormLdStDWord(Op0, Op1, dl, NewOpc, 24240b57cec5SDimitry Andric FirstReg, SecondReg, BaseReg, 24250b57cec5SDimitry Andric Offset, PredReg, Pred, isT2)) { 24260b57cec5SDimitry Andric Ops.pop_back(); 24270b57cec5SDimitry Andric Ops.pop_back(); 24280b57cec5SDimitry Andric 24290b57cec5SDimitry Andric const MCInstrDesc &MCID = TII->get(NewOpc); 24300b57cec5SDimitry Andric const TargetRegisterClass *TRC = TII->getRegClass(MCID, 0, TRI, *MF); 24310b57cec5SDimitry Andric MRI->constrainRegClass(FirstReg, TRC); 24320b57cec5SDimitry Andric MRI->constrainRegClass(SecondReg, TRC); 24330b57cec5SDimitry Andric 24340b57cec5SDimitry Andric // Form the pair instruction. 24350b57cec5SDimitry Andric if (isLd) { 24360b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(*MBB, InsertPos, dl, MCID) 24370b57cec5SDimitry Andric .addReg(FirstReg, RegState::Define) 24380b57cec5SDimitry Andric .addReg(SecondReg, RegState::Define) 24390b57cec5SDimitry Andric .addReg(BaseReg); 24400b57cec5SDimitry Andric // FIXME: We're converting from LDRi12 to an insn that still 24410b57cec5SDimitry Andric // uses addrmode2, so we need an explicit offset reg. It should 24420b57cec5SDimitry Andric // always by reg0 since we're transforming LDRi12s. 24430b57cec5SDimitry Andric if (!isT2) 24440b57cec5SDimitry Andric MIB.addReg(0); 24450b57cec5SDimitry Andric MIB.addImm(Offset).addImm(Pred).addReg(PredReg); 24460b57cec5SDimitry Andric MIB.cloneMergedMemRefs({Op0, Op1}); 24470b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Formed " << *MIB << "\n"); 24480b57cec5SDimitry Andric ++NumLDRDFormed; 24490b57cec5SDimitry Andric } else { 24500b57cec5SDimitry Andric MachineInstrBuilder MIB = BuildMI(*MBB, InsertPos, dl, MCID) 24510b57cec5SDimitry Andric .addReg(FirstReg) 24520b57cec5SDimitry Andric .addReg(SecondReg) 24530b57cec5SDimitry Andric .addReg(BaseReg); 24540b57cec5SDimitry Andric // FIXME: We're converting from LDRi12 to an insn that still 24550b57cec5SDimitry Andric // uses addrmode2, so we need an explicit offset reg. It should 24560b57cec5SDimitry Andric // always by reg0 since we're transforming STRi12s. 24570b57cec5SDimitry Andric if (!isT2) 24580b57cec5SDimitry Andric MIB.addReg(0); 24590b57cec5SDimitry Andric MIB.addImm(Offset).addImm(Pred).addReg(PredReg); 24600b57cec5SDimitry Andric MIB.cloneMergedMemRefs({Op0, Op1}); 24610b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Formed " << *MIB << "\n"); 24620b57cec5SDimitry Andric ++NumSTRDFormed; 24630b57cec5SDimitry Andric } 24640b57cec5SDimitry Andric MBB->erase(Op0); 24650b57cec5SDimitry Andric MBB->erase(Op1); 24660b57cec5SDimitry Andric 24670b57cec5SDimitry Andric if (!isT2) { 24680b57cec5SDimitry Andric // Add register allocation hints to form register pairs. 24690b57cec5SDimitry Andric MRI->setRegAllocationHint(FirstReg, ARMRI::RegPairEven, SecondReg); 24700b57cec5SDimitry Andric MRI->setRegAllocationHint(SecondReg, ARMRI::RegPairOdd, FirstReg); 24710b57cec5SDimitry Andric } 24720b57cec5SDimitry Andric } else { 24730b57cec5SDimitry Andric for (unsigned i = 0; i != NumMove; ++i) { 2474349cc55cSDimitry Andric MachineInstr *Op = Ops.pop_back_val(); 247506c3fb27SDimitry Andric if (isLd) { 247606c3fb27SDimitry Andric // Populate RegisterMap with all Registers defined by loads. 247706c3fb27SDimitry Andric Register Reg = Op->getOperand(0).getReg(); 247806c3fb27SDimitry Andric RegisterMap[Reg]; 247906c3fb27SDimitry Andric } 248006c3fb27SDimitry Andric 24810b57cec5SDimitry Andric MBB->splice(InsertPos, MBB, Op); 24820b57cec5SDimitry Andric } 24830b57cec5SDimitry Andric } 24840b57cec5SDimitry Andric 24850b57cec5SDimitry Andric NumLdStMoved += NumMove; 24860b57cec5SDimitry Andric RetVal = true; 24870b57cec5SDimitry Andric } 24880b57cec5SDimitry Andric } 24890b57cec5SDimitry Andric } 24900b57cec5SDimitry Andric 24910b57cec5SDimitry Andric return RetVal; 24920b57cec5SDimitry Andric } 24930b57cec5SDimitry Andric 249406c3fb27SDimitry Andric static void forEachDbgRegOperand(MachineInstr *MI, 249506c3fb27SDimitry Andric std::function<void(MachineOperand &)> Fn) { 249606c3fb27SDimitry Andric if (MI->isNonListDebugValue()) { 249706c3fb27SDimitry Andric auto &Op = MI->getOperand(0); 249806c3fb27SDimitry Andric if (Op.isReg()) 249906c3fb27SDimitry Andric Fn(Op); 250006c3fb27SDimitry Andric } else { 250106c3fb27SDimitry Andric for (unsigned I = 2; I < MI->getNumOperands(); I++) { 250206c3fb27SDimitry Andric auto &Op = MI->getOperand(I); 250306c3fb27SDimitry Andric if (Op.isReg()) 250406c3fb27SDimitry Andric Fn(Op); 250506c3fb27SDimitry Andric } 250606c3fb27SDimitry Andric } 250706c3fb27SDimitry Andric } 250806c3fb27SDimitry Andric 250906c3fb27SDimitry Andric // Update the RegisterMap with the instruction that was moved because a 251006c3fb27SDimitry Andric // DBG_VALUE_LIST may need to be moved again. 251106c3fb27SDimitry Andric static void updateRegisterMapForDbgValueListAfterMove( 251206c3fb27SDimitry Andric SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> &RegisterMap, 251306c3fb27SDimitry Andric MachineInstr *DbgValueListInstr, MachineInstr *InstrToReplace) { 251406c3fb27SDimitry Andric 251506c3fb27SDimitry Andric forEachDbgRegOperand(DbgValueListInstr, [&](MachineOperand &Op) { 251606c3fb27SDimitry Andric auto RegIt = RegisterMap.find(Op.getReg()); 251706c3fb27SDimitry Andric if (RegIt == RegisterMap.end()) 251806c3fb27SDimitry Andric return; 251906c3fb27SDimitry Andric auto &InstrVec = RegIt->getSecond(); 252006c3fb27SDimitry Andric for (unsigned I = 0; I < InstrVec.size(); I++) 252106c3fb27SDimitry Andric if (InstrVec[I] == InstrToReplace) 252206c3fb27SDimitry Andric InstrVec[I] = DbgValueListInstr; 252306c3fb27SDimitry Andric }); 252406c3fb27SDimitry Andric } 252506c3fb27SDimitry Andric 252606c3fb27SDimitry Andric static DebugVariable createDebugVariableFromMachineInstr(MachineInstr *MI) { 252706c3fb27SDimitry Andric auto DbgVar = DebugVariable(MI->getDebugVariable(), MI->getDebugExpression(), 252806c3fb27SDimitry Andric MI->getDebugLoc()->getInlinedAt()); 252906c3fb27SDimitry Andric return DbgVar; 253006c3fb27SDimitry Andric } 253106c3fb27SDimitry Andric 25320b57cec5SDimitry Andric bool 25330b57cec5SDimitry Andric ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) { 25340b57cec5SDimitry Andric bool RetVal = false; 25350b57cec5SDimitry Andric 25360b57cec5SDimitry Andric DenseMap<MachineInstr*, unsigned> MI2LocMap; 25370b57cec5SDimitry Andric using MapIt = DenseMap<unsigned, SmallVector<MachineInstr *, 4>>::iterator; 25380b57cec5SDimitry Andric using Base2InstMap = DenseMap<unsigned, SmallVector<MachineInstr *, 4>>; 25390b57cec5SDimitry Andric using BaseVec = SmallVector<unsigned, 4>; 25400b57cec5SDimitry Andric Base2InstMap Base2LdsMap; 25410b57cec5SDimitry Andric Base2InstMap Base2StsMap; 25420b57cec5SDimitry Andric BaseVec LdBases; 25430b57cec5SDimitry Andric BaseVec StBases; 254406c3fb27SDimitry Andric // This map is used to track the relationship between the virtual 254506c3fb27SDimitry Andric // register that is the result of a load that is moved and the DBG_VALUE 254606c3fb27SDimitry Andric // MachineInstr pointer that uses that virtual register. 254706c3fb27SDimitry Andric SmallDenseMap<Register, SmallVector<MachineInstr *>, 8> RegisterMap; 25480b57cec5SDimitry Andric 25490b57cec5SDimitry Andric unsigned Loc = 0; 25500b57cec5SDimitry Andric MachineBasicBlock::iterator MBBI = MBB->begin(); 25510b57cec5SDimitry Andric MachineBasicBlock::iterator E = MBB->end(); 25520b57cec5SDimitry Andric while (MBBI != E) { 25530b57cec5SDimitry Andric for (; MBBI != E; ++MBBI) { 25540b57cec5SDimitry Andric MachineInstr &MI = *MBBI; 25550b57cec5SDimitry Andric if (MI.isCall() || MI.isTerminator()) { 25560b57cec5SDimitry Andric // Stop at barriers. 25570b57cec5SDimitry Andric ++MBBI; 25580b57cec5SDimitry Andric break; 25590b57cec5SDimitry Andric } 25600b57cec5SDimitry Andric 25610b57cec5SDimitry Andric if (!MI.isDebugInstr()) 25620b57cec5SDimitry Andric MI2LocMap[&MI] = ++Loc; 25630b57cec5SDimitry Andric 25640b57cec5SDimitry Andric if (!isMemoryOp(MI)) 25650b57cec5SDimitry Andric continue; 25665ffd83dbSDimitry Andric Register PredReg; 25670b57cec5SDimitry Andric if (getInstrPredicate(MI, PredReg) != ARMCC::AL) 25680b57cec5SDimitry Andric continue; 25690b57cec5SDimitry Andric 25700b57cec5SDimitry Andric int Opc = MI.getOpcode(); 25710b57cec5SDimitry Andric bool isLd = isLoadSingle(Opc); 25728bcb0991SDimitry Andric Register Base = MI.getOperand(1).getReg(); 25730b57cec5SDimitry Andric int Offset = getMemoryOpOffset(MI); 25740b57cec5SDimitry Andric bool StopHere = false; 25750b57cec5SDimitry Andric auto FindBases = [&] (Base2InstMap &Base2Ops, BaseVec &Bases) { 25760b57cec5SDimitry Andric MapIt BI = Base2Ops.find(Base); 25770b57cec5SDimitry Andric if (BI == Base2Ops.end()) { 25780b57cec5SDimitry Andric Base2Ops[Base].push_back(&MI); 25790b57cec5SDimitry Andric Bases.push_back(Base); 25800b57cec5SDimitry Andric return; 25810b57cec5SDimitry Andric } 2582*0fca6ea1SDimitry Andric for (const MachineInstr *MI : BI->second) { 2583*0fca6ea1SDimitry Andric if (Offset == getMemoryOpOffset(*MI)) { 25840b57cec5SDimitry Andric StopHere = true; 25850b57cec5SDimitry Andric break; 25860b57cec5SDimitry Andric } 25870b57cec5SDimitry Andric } 25880b57cec5SDimitry Andric if (!StopHere) 25890b57cec5SDimitry Andric BI->second.push_back(&MI); 25900b57cec5SDimitry Andric }; 25910b57cec5SDimitry Andric 25920b57cec5SDimitry Andric if (isLd) 25930b57cec5SDimitry Andric FindBases(Base2LdsMap, LdBases); 25940b57cec5SDimitry Andric else 25950b57cec5SDimitry Andric FindBases(Base2StsMap, StBases); 25960b57cec5SDimitry Andric 25970b57cec5SDimitry Andric if (StopHere) { 25980b57cec5SDimitry Andric // Found a duplicate (a base+offset combination that's seen earlier). 25990b57cec5SDimitry Andric // Backtrack. 26000b57cec5SDimitry Andric --Loc; 26010b57cec5SDimitry Andric break; 26020b57cec5SDimitry Andric } 26030b57cec5SDimitry Andric } 26040b57cec5SDimitry Andric 26050b57cec5SDimitry Andric // Re-schedule loads. 2606cb14a3feSDimitry Andric for (unsigned Base : LdBases) { 26070b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &Lds = Base2LdsMap[Base]; 26080b57cec5SDimitry Andric if (Lds.size() > 1) 260906c3fb27SDimitry Andric RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap, RegisterMap); 26100b57cec5SDimitry Andric } 26110b57cec5SDimitry Andric 26120b57cec5SDimitry Andric // Re-schedule stores. 2613cb14a3feSDimitry Andric for (unsigned Base : StBases) { 26140b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &Sts = Base2StsMap[Base]; 26150b57cec5SDimitry Andric if (Sts.size() > 1) 261606c3fb27SDimitry Andric RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap, RegisterMap); 26170b57cec5SDimitry Andric } 26180b57cec5SDimitry Andric 26190b57cec5SDimitry Andric if (MBBI != E) { 26200b57cec5SDimitry Andric Base2LdsMap.clear(); 26210b57cec5SDimitry Andric Base2StsMap.clear(); 26220b57cec5SDimitry Andric LdBases.clear(); 26230b57cec5SDimitry Andric StBases.clear(); 26240b57cec5SDimitry Andric } 26250b57cec5SDimitry Andric } 26260b57cec5SDimitry Andric 262706c3fb27SDimitry Andric // Reschedule DBG_VALUEs to match any loads that were moved. When a load is 262806c3fb27SDimitry Andric // sunk beyond a DBG_VALUE that is referring to it, the DBG_VALUE becomes a 262906c3fb27SDimitry Andric // use-before-def, resulting in a loss of debug info. 263006c3fb27SDimitry Andric 263106c3fb27SDimitry Andric // Example: 263206c3fb27SDimitry Andric // Before the Pre Register Allocation Load Store Pass 263306c3fb27SDimitry Andric // inst_a 263406c3fb27SDimitry Andric // %2 = ld ... 263506c3fb27SDimitry Andric // inst_b 263606c3fb27SDimitry Andric // DBG_VALUE %2, "x", ... 263706c3fb27SDimitry Andric // %3 = ld ... 263806c3fb27SDimitry Andric 263906c3fb27SDimitry Andric // After the Pass: 264006c3fb27SDimitry Andric // inst_a 264106c3fb27SDimitry Andric // inst_b 264206c3fb27SDimitry Andric // DBG_VALUE %2, "x", ... 264306c3fb27SDimitry Andric // %2 = ld ... 264406c3fb27SDimitry Andric // %3 = ld ... 264506c3fb27SDimitry Andric 264606c3fb27SDimitry Andric // The code below addresses this by moving the DBG_VALUE to the position 264706c3fb27SDimitry Andric // immediately after the load. 264806c3fb27SDimitry Andric 264906c3fb27SDimitry Andric // Example: 265006c3fb27SDimitry Andric // After the code below: 265106c3fb27SDimitry Andric // inst_a 265206c3fb27SDimitry Andric // inst_b 265306c3fb27SDimitry Andric // %2 = ld ... 265406c3fb27SDimitry Andric // DBG_VALUE %2, "x", ... 265506c3fb27SDimitry Andric // %3 = ld ... 265606c3fb27SDimitry Andric 265706c3fb27SDimitry Andric // The algorithm works in two phases: First RescheduleOps() populates the 265806c3fb27SDimitry Andric // RegisterMap with registers that were moved as keys, there is no value 265906c3fb27SDimitry Andric // inserted. In the next phase, every MachineInstr in a basic block is 266006c3fb27SDimitry Andric // iterated over. If it is a valid DBG_VALUE or DBG_VALUE_LIST and it uses one 266106c3fb27SDimitry Andric // or more registers in the RegisterMap, the RegisterMap and InstrMap are 266206c3fb27SDimitry Andric // populated with the MachineInstr. If the DBG_VALUE or DBG_VALUE_LIST 266306c3fb27SDimitry Andric // describes debug information for a variable that already exists in the 266406c3fb27SDimitry Andric // DbgValueSinkCandidates, the MachineInstr in the DbgValueSinkCandidates must 266506c3fb27SDimitry Andric // be set to undef. If the current MachineInstr is a load that was moved, 266606c3fb27SDimitry Andric // undef the corresponding DBG_VALUE or DBG_VALUE_LIST and clone it to below 266706c3fb27SDimitry Andric // the load. 266806c3fb27SDimitry Andric 266906c3fb27SDimitry Andric // To illustrate the above algorithm visually let's take this example. 267006c3fb27SDimitry Andric 267106c3fb27SDimitry Andric // Before the Pre Register Allocation Load Store Pass: 267206c3fb27SDimitry Andric // %2 = ld ... 267306c3fb27SDimitry Andric // DBG_VALUE %2, A, .... # X 267406c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 267506c3fb27SDimitry Andric // %3 = ld ... 267606c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 267706c3fb27SDimitry Andric // %4 = ld ... 267806c3fb27SDimitry Andric 267906c3fb27SDimitry Andric // After Pre Register Allocation Load Store Pass: 268006c3fb27SDimitry Andric // DBG_VALUE %2, A, .... # X 268106c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 268206c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 268306c3fb27SDimitry Andric // %2 = ld ... 268406c3fb27SDimitry Andric // %3 = ld ... 268506c3fb27SDimitry Andric // %4 = ld ... 268606c3fb27SDimitry Andric 268706c3fb27SDimitry Andric // The algorithm below does the following: 268806c3fb27SDimitry Andric 268906c3fb27SDimitry Andric // In the beginning, the RegisterMap will have been populated with the virtual 269006c3fb27SDimitry Andric // registers %2, and %3, the DbgValueSinkCandidates and the InstrMap will be 269106c3fb27SDimitry Andric // empty. DbgValueSinkCandidates = {}, RegisterMap = {2 -> {}, 3 -> {}}, 269206c3fb27SDimitry Andric // InstrMap {} 269306c3fb27SDimitry Andric // -> DBG_VALUE %2, A, .... # X 269406c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 269506c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 269606c3fb27SDimitry Andric // %2 = ld ... 269706c3fb27SDimitry Andric // %3 = ld ... 269806c3fb27SDimitry Andric // %4 = ld ... 269906c3fb27SDimitry Andric 270006c3fb27SDimitry Andric // After the first DBG_VALUE (denoted with an X) is processed, the 270106c3fb27SDimitry Andric // DbgValueSinkCandidates and InstrMap will be populated and the RegisterMap 270206c3fb27SDimitry Andric // entry for %2 will be populated as well. DbgValueSinkCandidates = {A -> X}, 270306c3fb27SDimitry Andric // RegisterMap = {2 -> {X}, 3 -> {}}, InstrMap {X -> 2} 270406c3fb27SDimitry Andric // DBG_VALUE %2, A, .... # X 270506c3fb27SDimitry Andric // -> DBG_VALUE 0, A, ... # Y 270606c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 270706c3fb27SDimitry Andric // %2 = ld ... 270806c3fb27SDimitry Andric // %3 = ld ... 270906c3fb27SDimitry Andric // %4 = ld ... 271006c3fb27SDimitry Andric 271106c3fb27SDimitry Andric // After the DBG_VALUE Y is processed, the DbgValueSinkCandidates is updated 271206c3fb27SDimitry Andric // to now hold Y for A and the RegisterMap is also updated to remove X from 271306c3fb27SDimitry Andric // %2, this is because both X and Y describe the same debug variable A. X is 271406c3fb27SDimitry Andric // also updated to have a $noreg as the first operand. 271506c3fb27SDimitry Andric // DbgValueSinkCandidates = {A -> {Y}}, RegisterMap = {2 -> {}, 3 -> {}}, 271606c3fb27SDimitry Andric // InstrMap = {X-> 2} 271706c3fb27SDimitry Andric // DBG_VALUE $noreg, A, .... # X 271806c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 271906c3fb27SDimitry Andric // -> DBG_VALUE %3, A, ..., # Z 272006c3fb27SDimitry Andric // %2 = ld ... 272106c3fb27SDimitry Andric // %3 = ld ... 272206c3fb27SDimitry Andric // %4 = ld ... 272306c3fb27SDimitry Andric 272406c3fb27SDimitry Andric // After DBG_VALUE Z is processed, the DbgValueSinkCandidates is updated to 272506c3fb27SDimitry Andric // hold Z fr A, the RegisterMap is updated to hold Z for %3, and the InstrMap 272606c3fb27SDimitry Andric // is updated to have Z mapped to %3. This is again because Z describes the 272706c3fb27SDimitry Andric // debug variable A, Y is not updated to have $noreg as first operand because 272806c3fb27SDimitry Andric // its first operand is an immediate, not a register. 272906c3fb27SDimitry Andric // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, 273006c3fb27SDimitry Andric // InstrMap = {X -> 2, Z -> 3} 273106c3fb27SDimitry Andric // DBG_VALUE $noreg, A, .... # X 273206c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 273306c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 273406c3fb27SDimitry Andric // -> %2 = ld ... 273506c3fb27SDimitry Andric // %3 = ld ... 273606c3fb27SDimitry Andric // %4 = ld ... 273706c3fb27SDimitry Andric 273806c3fb27SDimitry Andric // Nothing happens here since the RegisterMap for %2 contains no value. 273906c3fb27SDimitry Andric // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, 274006c3fb27SDimitry Andric // InstrMap = {X -> 2, Z -> 3} 274106c3fb27SDimitry Andric // DBG_VALUE $noreg, A, .... # X 274206c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 274306c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 274406c3fb27SDimitry Andric // %2 = ld ... 274506c3fb27SDimitry Andric // -> %3 = ld ... 274606c3fb27SDimitry Andric // %4 = ld ... 274706c3fb27SDimitry Andric 274806c3fb27SDimitry Andric // Since the RegisterMap contains Z as a value for %3, the MachineInstr 274906c3fb27SDimitry Andric // pointer Z is copied to come after the load for %3 and the old Z's first 275006c3fb27SDimitry Andric // operand is changed to $noreg the Basic Block iterator is moved to after the 275106c3fb27SDimitry Andric // DBG_VALUE Z's new position. 275206c3fb27SDimitry Andric // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, 275306c3fb27SDimitry Andric // InstrMap = {X -> 2, Z -> 3} 275406c3fb27SDimitry Andric // DBG_VALUE $noreg, A, .... # X 275506c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 275606c3fb27SDimitry Andric // DBG_VALUE $noreg, A, ..., # Old Z 275706c3fb27SDimitry Andric // %2 = ld ... 275806c3fb27SDimitry Andric // %3 = ld ... 275906c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 276006c3fb27SDimitry Andric // -> %4 = ld ... 276106c3fb27SDimitry Andric 276206c3fb27SDimitry Andric // Nothing happens for %4 and the algorithm exits having processed the entire 276306c3fb27SDimitry Andric // Basic Block. 276406c3fb27SDimitry Andric // DbgValueSinkCandidates = {A -> {Z}}, RegisterMap = {2 -> {}, 3 -> {Z}}, 276506c3fb27SDimitry Andric // InstrMap = {X -> 2, Z -> 3} 276606c3fb27SDimitry Andric // DBG_VALUE $noreg, A, .... # X 276706c3fb27SDimitry Andric // DBG_VALUE 0, A, ... # Y 276806c3fb27SDimitry Andric // DBG_VALUE $noreg, A, ..., # Old Z 276906c3fb27SDimitry Andric // %2 = ld ... 277006c3fb27SDimitry Andric // %3 = ld ... 277106c3fb27SDimitry Andric // DBG_VALUE %3, A, ..., # Z 277206c3fb27SDimitry Andric // %4 = ld ... 277306c3fb27SDimitry Andric 277406c3fb27SDimitry Andric // This map is used to track the relationship between 277506c3fb27SDimitry Andric // a Debug Variable and the DBG_VALUE MachineInstr pointer that describes the 277606c3fb27SDimitry Andric // debug information for that Debug Variable. 277706c3fb27SDimitry Andric SmallDenseMap<DebugVariable, MachineInstr *, 8> DbgValueSinkCandidates; 277806c3fb27SDimitry Andric // This map is used to track the relationship between a DBG_VALUE or 277906c3fb27SDimitry Andric // DBG_VALUE_LIST MachineInstr pointer and Registers that it uses. 278006c3fb27SDimitry Andric SmallDenseMap<MachineInstr *, SmallVector<Register>, 8> InstrMap; 278106c3fb27SDimitry Andric for (MBBI = MBB->begin(), E = MBB->end(); MBBI != E; ++MBBI) { 278206c3fb27SDimitry Andric MachineInstr &MI = *MBBI; 278306c3fb27SDimitry Andric 278406c3fb27SDimitry Andric auto PopulateRegisterAndInstrMapForDebugInstr = [&](Register Reg) { 278506c3fb27SDimitry Andric auto RegIt = RegisterMap.find(Reg); 278606c3fb27SDimitry Andric if (RegIt == RegisterMap.end()) 278706c3fb27SDimitry Andric return; 278806c3fb27SDimitry Andric auto &InstrVec = RegIt->getSecond(); 278906c3fb27SDimitry Andric InstrVec.push_back(&MI); 279006c3fb27SDimitry Andric InstrMap[&MI].push_back(Reg); 279106c3fb27SDimitry Andric }; 279206c3fb27SDimitry Andric 279306c3fb27SDimitry Andric if (MI.isDebugValue()) { 279406c3fb27SDimitry Andric assert(MI.getDebugVariable() && 279506c3fb27SDimitry Andric "DBG_VALUE or DBG_VALUE_LIST must contain a DILocalVariable"); 279606c3fb27SDimitry Andric 279706c3fb27SDimitry Andric auto DbgVar = createDebugVariableFromMachineInstr(&MI); 279806c3fb27SDimitry Andric // If the first operand is a register and it exists in the RegisterMap, we 279906c3fb27SDimitry Andric // know this is a DBG_VALUE that uses the result of a load that was moved, 280006c3fb27SDimitry Andric // and is therefore a candidate to also be moved, add it to the 280106c3fb27SDimitry Andric // RegisterMap and InstrMap. 280206c3fb27SDimitry Andric forEachDbgRegOperand(&MI, [&](MachineOperand &Op) { 280306c3fb27SDimitry Andric PopulateRegisterAndInstrMapForDebugInstr(Op.getReg()); 280406c3fb27SDimitry Andric }); 280506c3fb27SDimitry Andric 280606c3fb27SDimitry Andric // If the current DBG_VALUE describes the same variable as one of the 280706c3fb27SDimitry Andric // in-flight DBG_VALUEs, remove the candidate from the list and set it to 280806c3fb27SDimitry Andric // undef. Moving one DBG_VALUE past another would result in the variable's 280906c3fb27SDimitry Andric // value going back in time when stepping through the block in the 281006c3fb27SDimitry Andric // debugger. 281106c3fb27SDimitry Andric auto InstrIt = DbgValueSinkCandidates.find(DbgVar); 281206c3fb27SDimitry Andric if (InstrIt != DbgValueSinkCandidates.end()) { 281306c3fb27SDimitry Andric auto *Instr = InstrIt->getSecond(); 281406c3fb27SDimitry Andric auto RegIt = InstrMap.find(Instr); 281506c3fb27SDimitry Andric if (RegIt != InstrMap.end()) { 281606c3fb27SDimitry Andric const auto &RegVec = RegIt->getSecond(); 281706c3fb27SDimitry Andric // For every Register in the RegVec, remove the MachineInstr in the 281806c3fb27SDimitry Andric // RegisterMap that describes the DbgVar. 281906c3fb27SDimitry Andric for (auto &Reg : RegVec) { 282006c3fb27SDimitry Andric auto RegIt = RegisterMap.find(Reg); 282106c3fb27SDimitry Andric if (RegIt == RegisterMap.end()) 282206c3fb27SDimitry Andric continue; 282306c3fb27SDimitry Andric auto &InstrVec = RegIt->getSecond(); 282406c3fb27SDimitry Andric auto IsDbgVar = [&](MachineInstr *I) -> bool { 282506c3fb27SDimitry Andric auto Var = createDebugVariableFromMachineInstr(I); 282606c3fb27SDimitry Andric return Var == DbgVar; 282706c3fb27SDimitry Andric }; 282806c3fb27SDimitry Andric 28295f757f3fSDimitry Andric llvm::erase_if(InstrVec, IsDbgVar); 283006c3fb27SDimitry Andric } 283106c3fb27SDimitry Andric forEachDbgRegOperand(Instr, 283206c3fb27SDimitry Andric [&](MachineOperand &Op) { Op.setReg(0); }); 283306c3fb27SDimitry Andric } 283406c3fb27SDimitry Andric } 283506c3fb27SDimitry Andric DbgValueSinkCandidates[DbgVar] = &MI; 283606c3fb27SDimitry Andric } else { 283706c3fb27SDimitry Andric // If the first operand of a load matches with a DBG_VALUE in RegisterMap, 283806c3fb27SDimitry Andric // then move that DBG_VALUE to below the load. 283906c3fb27SDimitry Andric auto Opc = MI.getOpcode(); 284006c3fb27SDimitry Andric if (!isLoadSingle(Opc)) 284106c3fb27SDimitry Andric continue; 284206c3fb27SDimitry Andric auto Reg = MI.getOperand(0).getReg(); 284306c3fb27SDimitry Andric auto RegIt = RegisterMap.find(Reg); 284406c3fb27SDimitry Andric if (RegIt == RegisterMap.end()) 284506c3fb27SDimitry Andric continue; 284606c3fb27SDimitry Andric auto &DbgInstrVec = RegIt->getSecond(); 284706c3fb27SDimitry Andric if (!DbgInstrVec.size()) 284806c3fb27SDimitry Andric continue; 284906c3fb27SDimitry Andric for (auto *DbgInstr : DbgInstrVec) { 285006c3fb27SDimitry Andric MachineBasicBlock::iterator InsertPos = std::next(MBBI); 285106c3fb27SDimitry Andric auto *ClonedMI = MI.getMF()->CloneMachineInstr(DbgInstr); 285206c3fb27SDimitry Andric MBB->insert(InsertPos, ClonedMI); 285306c3fb27SDimitry Andric MBBI++; 285406c3fb27SDimitry Andric // Erase the entry into the DbgValueSinkCandidates for the DBG_VALUE 285506c3fb27SDimitry Andric // that was moved. 285606c3fb27SDimitry Andric auto DbgVar = createDebugVariableFromMachineInstr(DbgInstr); 285706c3fb27SDimitry Andric auto DbgIt = DbgValueSinkCandidates.find(DbgVar); 285806c3fb27SDimitry Andric // If the instruction is a DBG_VALUE_LIST, it may have already been 285906c3fb27SDimitry Andric // erased from the DbgValueSinkCandidates. Only erase if it exists in 286006c3fb27SDimitry Andric // the DbgValueSinkCandidates. 286106c3fb27SDimitry Andric if (DbgIt != DbgValueSinkCandidates.end()) 286206c3fb27SDimitry Andric DbgValueSinkCandidates.erase(DbgIt); 286306c3fb27SDimitry Andric // Zero out original dbg instr 286406c3fb27SDimitry Andric forEachDbgRegOperand(DbgInstr, 286506c3fb27SDimitry Andric [&](MachineOperand &Op) { Op.setReg(0); }); 286606c3fb27SDimitry Andric // Update RegisterMap with ClonedMI because it might have to be moved 286706c3fb27SDimitry Andric // again. 286806c3fb27SDimitry Andric if (DbgInstr->isDebugValueList()) 286906c3fb27SDimitry Andric updateRegisterMapForDbgValueListAfterMove(RegisterMap, ClonedMI, 287006c3fb27SDimitry Andric DbgInstr); 287106c3fb27SDimitry Andric } 287206c3fb27SDimitry Andric } 287306c3fb27SDimitry Andric } 28740b57cec5SDimitry Andric return RetVal; 28750b57cec5SDimitry Andric } 28760b57cec5SDimitry Andric 28775ffd83dbSDimitry Andric // Get the Base register operand index from the memory access MachineInst if we 28785ffd83dbSDimitry Andric // should attempt to distribute postinc on it. Return -1 if not of a valid 28795ffd83dbSDimitry Andric // instruction type. If it returns an index, it is assumed that instruction is a 28805ffd83dbSDimitry Andric // r+i indexing mode, and getBaseOperandIndex() + 1 is the Offset index. 28815ffd83dbSDimitry Andric static int getBaseOperandIndex(MachineInstr &MI) { 28825ffd83dbSDimitry Andric switch (MI.getOpcode()) { 28835ffd83dbSDimitry Andric case ARM::MVE_VLDRBS16: 28845ffd83dbSDimitry Andric case ARM::MVE_VLDRBS32: 28855ffd83dbSDimitry Andric case ARM::MVE_VLDRBU16: 28865ffd83dbSDimitry Andric case ARM::MVE_VLDRBU32: 28875ffd83dbSDimitry Andric case ARM::MVE_VLDRHS32: 28885ffd83dbSDimitry Andric case ARM::MVE_VLDRHU32: 28895ffd83dbSDimitry Andric case ARM::MVE_VLDRBU8: 28905ffd83dbSDimitry Andric case ARM::MVE_VLDRHU16: 28915ffd83dbSDimitry Andric case ARM::MVE_VLDRWU32: 28925ffd83dbSDimitry Andric case ARM::MVE_VSTRB16: 28935ffd83dbSDimitry Andric case ARM::MVE_VSTRB32: 28945ffd83dbSDimitry Andric case ARM::MVE_VSTRH32: 28955ffd83dbSDimitry Andric case ARM::MVE_VSTRBU8: 28965ffd83dbSDimitry Andric case ARM::MVE_VSTRHU16: 28975ffd83dbSDimitry Andric case ARM::MVE_VSTRWU32: 2898e8d8bef9SDimitry Andric case ARM::t2LDRHi8: 2899e8d8bef9SDimitry Andric case ARM::t2LDRHi12: 2900e8d8bef9SDimitry Andric case ARM::t2LDRSHi8: 2901e8d8bef9SDimitry Andric case ARM::t2LDRSHi12: 2902e8d8bef9SDimitry Andric case ARM::t2LDRBi8: 2903e8d8bef9SDimitry Andric case ARM::t2LDRBi12: 2904e8d8bef9SDimitry Andric case ARM::t2LDRSBi8: 2905e8d8bef9SDimitry Andric case ARM::t2LDRSBi12: 2906e8d8bef9SDimitry Andric case ARM::t2STRBi8: 2907e8d8bef9SDimitry Andric case ARM::t2STRBi12: 2908e8d8bef9SDimitry Andric case ARM::t2STRHi8: 2909e8d8bef9SDimitry Andric case ARM::t2STRHi12: 29105ffd83dbSDimitry Andric return 1; 2911e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS16_post: 2912e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS32_post: 2913e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU16_post: 2914e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU32_post: 2915e8d8bef9SDimitry Andric case ARM::MVE_VLDRHS32_post: 2916e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU32_post: 2917e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU8_post: 2918e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU16_post: 2919e8d8bef9SDimitry Andric case ARM::MVE_VLDRWU32_post: 2920e8d8bef9SDimitry Andric case ARM::MVE_VSTRB16_post: 2921e8d8bef9SDimitry Andric case ARM::MVE_VSTRB32_post: 2922e8d8bef9SDimitry Andric case ARM::MVE_VSTRH32_post: 2923e8d8bef9SDimitry Andric case ARM::MVE_VSTRBU8_post: 2924e8d8bef9SDimitry Andric case ARM::MVE_VSTRHU16_post: 2925e8d8bef9SDimitry Andric case ARM::MVE_VSTRWU32_post: 2926e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS16_pre: 2927e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS32_pre: 2928e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU16_pre: 2929e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU32_pre: 2930e8d8bef9SDimitry Andric case ARM::MVE_VLDRHS32_pre: 2931e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU32_pre: 2932e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU8_pre: 2933e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU16_pre: 2934e8d8bef9SDimitry Andric case ARM::MVE_VLDRWU32_pre: 2935e8d8bef9SDimitry Andric case ARM::MVE_VSTRB16_pre: 2936e8d8bef9SDimitry Andric case ARM::MVE_VSTRB32_pre: 2937e8d8bef9SDimitry Andric case ARM::MVE_VSTRH32_pre: 2938e8d8bef9SDimitry Andric case ARM::MVE_VSTRBU8_pre: 2939e8d8bef9SDimitry Andric case ARM::MVE_VSTRHU16_pre: 2940e8d8bef9SDimitry Andric case ARM::MVE_VSTRWU32_pre: 2941e8d8bef9SDimitry Andric return 2; 29425ffd83dbSDimitry Andric } 29435ffd83dbSDimitry Andric return -1; 29445ffd83dbSDimitry Andric } 29455ffd83dbSDimitry Andric 2946e8d8bef9SDimitry Andric static bool isPostIndex(MachineInstr &MI) { 2947e8d8bef9SDimitry Andric switch (MI.getOpcode()) { 2948e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS16_post: 2949e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS32_post: 2950e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU16_post: 2951e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU32_post: 2952e8d8bef9SDimitry Andric case ARM::MVE_VLDRHS32_post: 2953e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU32_post: 2954e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU8_post: 2955e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU16_post: 2956e8d8bef9SDimitry Andric case ARM::MVE_VLDRWU32_post: 2957e8d8bef9SDimitry Andric case ARM::MVE_VSTRB16_post: 2958e8d8bef9SDimitry Andric case ARM::MVE_VSTRB32_post: 2959e8d8bef9SDimitry Andric case ARM::MVE_VSTRH32_post: 2960e8d8bef9SDimitry Andric case ARM::MVE_VSTRBU8_post: 2961e8d8bef9SDimitry Andric case ARM::MVE_VSTRHU16_post: 2962e8d8bef9SDimitry Andric case ARM::MVE_VSTRWU32_post: 2963e8d8bef9SDimitry Andric return true; 2964e8d8bef9SDimitry Andric } 2965e8d8bef9SDimitry Andric return false; 2966e8d8bef9SDimitry Andric } 2967e8d8bef9SDimitry Andric 2968e8d8bef9SDimitry Andric static bool isPreIndex(MachineInstr &MI) { 2969e8d8bef9SDimitry Andric switch (MI.getOpcode()) { 2970e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS16_pre: 2971e8d8bef9SDimitry Andric case ARM::MVE_VLDRBS32_pre: 2972e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU16_pre: 2973e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU32_pre: 2974e8d8bef9SDimitry Andric case ARM::MVE_VLDRHS32_pre: 2975e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU32_pre: 2976e8d8bef9SDimitry Andric case ARM::MVE_VLDRBU8_pre: 2977e8d8bef9SDimitry Andric case ARM::MVE_VLDRHU16_pre: 2978e8d8bef9SDimitry Andric case ARM::MVE_VLDRWU32_pre: 2979e8d8bef9SDimitry Andric case ARM::MVE_VSTRB16_pre: 2980e8d8bef9SDimitry Andric case ARM::MVE_VSTRB32_pre: 2981e8d8bef9SDimitry Andric case ARM::MVE_VSTRH32_pre: 2982e8d8bef9SDimitry Andric case ARM::MVE_VSTRBU8_pre: 2983e8d8bef9SDimitry Andric case ARM::MVE_VSTRHU16_pre: 2984e8d8bef9SDimitry Andric case ARM::MVE_VSTRWU32_pre: 2985e8d8bef9SDimitry Andric return true; 2986e8d8bef9SDimitry Andric } 2987e8d8bef9SDimitry Andric return false; 2988e8d8bef9SDimitry Andric } 2989e8d8bef9SDimitry Andric 2990e8d8bef9SDimitry Andric // Given a memory access Opcode, check that the give Imm would be a valid Offset 2991e8d8bef9SDimitry Andric // for this instruction (same as isLegalAddressImm), Or if the instruction 2992e8d8bef9SDimitry Andric // could be easily converted to one where that was valid. For example converting 2993e8d8bef9SDimitry Andric // t2LDRi12 to t2LDRi8 for negative offsets. Works in conjunction with 2994e8d8bef9SDimitry Andric // AdjustBaseAndOffset below. 2995e8d8bef9SDimitry Andric static bool isLegalOrConvertableAddressImm(unsigned Opcode, int Imm, 2996e8d8bef9SDimitry Andric const TargetInstrInfo *TII, 2997e8d8bef9SDimitry Andric int &CodesizeEstimate) { 2998e8d8bef9SDimitry Andric if (isLegalAddressImm(Opcode, Imm, TII)) 2999e8d8bef9SDimitry Andric return true; 3000e8d8bef9SDimitry Andric 30014824e7fdSDimitry Andric // We can convert AddrModeT2_i12 to AddrModeT2_i8neg. 3002e8d8bef9SDimitry Andric const MCInstrDesc &Desc = TII->get(Opcode); 3003e8d8bef9SDimitry Andric unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); 3004e8d8bef9SDimitry Andric switch (AddrMode) { 3005e8d8bef9SDimitry Andric case ARMII::AddrModeT2_i12: 3006e8d8bef9SDimitry Andric CodesizeEstimate += 1; 30074824e7fdSDimitry Andric return Imm < 0 && -Imm < ((1 << 8) * 1); 3008e8d8bef9SDimitry Andric } 3009e8d8bef9SDimitry Andric return false; 3010e8d8bef9SDimitry Andric } 3011e8d8bef9SDimitry Andric 3012e8d8bef9SDimitry Andric // Given an MI adjust its address BaseReg to use NewBaseReg and address offset 3013e8d8bef9SDimitry Andric // by -Offset. This can either happen in-place or be a replacement as MI is 3014e8d8bef9SDimitry Andric // converted to another instruction type. 3015e8d8bef9SDimitry Andric static void AdjustBaseAndOffset(MachineInstr *MI, Register NewBaseReg, 3016fe6060f1SDimitry Andric int Offset, const TargetInstrInfo *TII, 3017fe6060f1SDimitry Andric const TargetRegisterInfo *TRI) { 3018fe6060f1SDimitry Andric // Set the Base reg 3019e8d8bef9SDimitry Andric unsigned BaseOp = getBaseOperandIndex(*MI); 3020e8d8bef9SDimitry Andric MI->getOperand(BaseOp).setReg(NewBaseReg); 3021fe6060f1SDimitry Andric // and constrain the reg class to that required by the instruction. 3022fe6060f1SDimitry Andric MachineFunction *MF = MI->getMF(); 3023fe6060f1SDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 3024fe6060f1SDimitry Andric const MCInstrDesc &MCID = TII->get(MI->getOpcode()); 3025fe6060f1SDimitry Andric const TargetRegisterClass *TRC = TII->getRegClass(MCID, BaseOp, TRI, *MF); 3026fe6060f1SDimitry Andric MRI.constrainRegClass(NewBaseReg, TRC); 3027fe6060f1SDimitry Andric 3028e8d8bef9SDimitry Andric int OldOffset = MI->getOperand(BaseOp + 1).getImm(); 3029e8d8bef9SDimitry Andric if (isLegalAddressImm(MI->getOpcode(), OldOffset - Offset, TII)) 3030e8d8bef9SDimitry Andric MI->getOperand(BaseOp + 1).setImm(OldOffset - Offset); 3031e8d8bef9SDimitry Andric else { 3032e8d8bef9SDimitry Andric unsigned ConvOpcode; 3033e8d8bef9SDimitry Andric switch (MI->getOpcode()) { 3034e8d8bef9SDimitry Andric case ARM::t2LDRHi12: 3035e8d8bef9SDimitry Andric ConvOpcode = ARM::t2LDRHi8; 3036e8d8bef9SDimitry Andric break; 3037e8d8bef9SDimitry Andric case ARM::t2LDRSHi12: 3038e8d8bef9SDimitry Andric ConvOpcode = ARM::t2LDRSHi8; 3039e8d8bef9SDimitry Andric break; 3040e8d8bef9SDimitry Andric case ARM::t2LDRBi12: 3041e8d8bef9SDimitry Andric ConvOpcode = ARM::t2LDRBi8; 3042e8d8bef9SDimitry Andric break; 3043e8d8bef9SDimitry Andric case ARM::t2LDRSBi12: 3044e8d8bef9SDimitry Andric ConvOpcode = ARM::t2LDRSBi8; 3045e8d8bef9SDimitry Andric break; 3046e8d8bef9SDimitry Andric case ARM::t2STRHi12: 3047e8d8bef9SDimitry Andric ConvOpcode = ARM::t2STRHi8; 3048e8d8bef9SDimitry Andric break; 3049e8d8bef9SDimitry Andric case ARM::t2STRBi12: 3050e8d8bef9SDimitry Andric ConvOpcode = ARM::t2STRBi8; 3051e8d8bef9SDimitry Andric break; 3052e8d8bef9SDimitry Andric default: 3053e8d8bef9SDimitry Andric llvm_unreachable("Unhandled convertable opcode"); 3054e8d8bef9SDimitry Andric } 3055e8d8bef9SDimitry Andric assert(isLegalAddressImm(ConvOpcode, OldOffset - Offset, TII) && 3056e8d8bef9SDimitry Andric "Illegal Address Immediate after convert!"); 3057e8d8bef9SDimitry Andric 3058e8d8bef9SDimitry Andric const MCInstrDesc &MCID = TII->get(ConvOpcode); 3059e8d8bef9SDimitry Andric BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), MCID) 3060e8d8bef9SDimitry Andric .add(MI->getOperand(0)) 3061e8d8bef9SDimitry Andric .add(MI->getOperand(1)) 3062e8d8bef9SDimitry Andric .addImm(OldOffset - Offset) 3063e8d8bef9SDimitry Andric .add(MI->getOperand(3)) 3064e8d8bef9SDimitry Andric .add(MI->getOperand(4)) 3065e8d8bef9SDimitry Andric .cloneMemRefs(*MI); 3066e8d8bef9SDimitry Andric MI->eraseFromParent(); 3067e8d8bef9SDimitry Andric } 3068e8d8bef9SDimitry Andric } 3069e8d8bef9SDimitry Andric 30705ffd83dbSDimitry Andric static MachineInstr *createPostIncLoadStore(MachineInstr *MI, int Offset, 30715ffd83dbSDimitry Andric Register NewReg, 30725ffd83dbSDimitry Andric const TargetInstrInfo *TII, 30735ffd83dbSDimitry Andric const TargetRegisterInfo *TRI) { 30745ffd83dbSDimitry Andric MachineFunction *MF = MI->getMF(); 30755ffd83dbSDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 30765ffd83dbSDimitry Andric 30775ffd83dbSDimitry Andric unsigned NewOpcode = getPostIndexedLoadStoreOpcode( 30785ffd83dbSDimitry Andric MI->getOpcode(), Offset > 0 ? ARM_AM::add : ARM_AM::sub); 30795ffd83dbSDimitry Andric 30805ffd83dbSDimitry Andric const MCInstrDesc &MCID = TII->get(NewOpcode); 30815ffd83dbSDimitry Andric // Constrain the def register class 30825ffd83dbSDimitry Andric const TargetRegisterClass *TRC = TII->getRegClass(MCID, 0, TRI, *MF); 30835ffd83dbSDimitry Andric MRI.constrainRegClass(NewReg, TRC); 30845ffd83dbSDimitry Andric // And do the same for the base operand 30855ffd83dbSDimitry Andric TRC = TII->getRegClass(MCID, 2, TRI, *MF); 30865ffd83dbSDimitry Andric MRI.constrainRegClass(MI->getOperand(1).getReg(), TRC); 30875ffd83dbSDimitry Andric 3088e8d8bef9SDimitry Andric unsigned AddrMode = (MCID.TSFlags & ARMII::AddrModeMask); 3089e8d8bef9SDimitry Andric switch (AddrMode) { 3090e8d8bef9SDimitry Andric case ARMII::AddrModeT2_i7: 3091e8d8bef9SDimitry Andric case ARMII::AddrModeT2_i7s2: 3092e8d8bef9SDimitry Andric case ARMII::AddrModeT2_i7s4: 3093e8d8bef9SDimitry Andric // Any MVE load/store 3094e8d8bef9SDimitry Andric return BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), MCID) 3095e8d8bef9SDimitry Andric .addReg(NewReg, RegState::Define) 3096e8d8bef9SDimitry Andric .add(MI->getOperand(0)) 3097e8d8bef9SDimitry Andric .add(MI->getOperand(1)) 3098e8d8bef9SDimitry Andric .addImm(Offset) 3099e8d8bef9SDimitry Andric .add(MI->getOperand(3)) 3100e8d8bef9SDimitry Andric .add(MI->getOperand(4)) 3101349cc55cSDimitry Andric .add(MI->getOperand(5)) 3102e8d8bef9SDimitry Andric .cloneMemRefs(*MI); 3103e8d8bef9SDimitry Andric case ARMII::AddrModeT2_i8: 3104e8d8bef9SDimitry Andric if (MI->mayLoad()) { 3105e8d8bef9SDimitry Andric return BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), MCID) 3106e8d8bef9SDimitry Andric .add(MI->getOperand(0)) 3107e8d8bef9SDimitry Andric .addReg(NewReg, RegState::Define) 3108e8d8bef9SDimitry Andric .add(MI->getOperand(1)) 3109e8d8bef9SDimitry Andric .addImm(Offset) 3110e8d8bef9SDimitry Andric .add(MI->getOperand(3)) 3111e8d8bef9SDimitry Andric .add(MI->getOperand(4)) 3112e8d8bef9SDimitry Andric .cloneMemRefs(*MI); 3113e8d8bef9SDimitry Andric } else { 31145ffd83dbSDimitry Andric return BuildMI(*MI->getParent(), MI, MI->getDebugLoc(), MCID) 31155ffd83dbSDimitry Andric .addReg(NewReg, RegState::Define) 31165ffd83dbSDimitry Andric .add(MI->getOperand(0)) 31175ffd83dbSDimitry Andric .add(MI->getOperand(1)) 31185ffd83dbSDimitry Andric .addImm(Offset) 31195ffd83dbSDimitry Andric .add(MI->getOperand(3)) 31205ffd83dbSDimitry Andric .add(MI->getOperand(4)) 31215ffd83dbSDimitry Andric .cloneMemRefs(*MI); 31225ffd83dbSDimitry Andric } 3123e8d8bef9SDimitry Andric default: 3124e8d8bef9SDimitry Andric llvm_unreachable("Unhandled createPostIncLoadStore"); 3125e8d8bef9SDimitry Andric } 3126e8d8bef9SDimitry Andric } 31275ffd83dbSDimitry Andric 31285ffd83dbSDimitry Andric // Given a Base Register, optimise the load/store uses to attempt to create more 3129e8d8bef9SDimitry Andric // post-inc accesses and less register moves. We do this by taking zero offset 3130e8d8bef9SDimitry Andric // loads/stores with an add, and convert them to a postinc load/store of the 3131e8d8bef9SDimitry Andric // same type. Any subsequent accesses will be adjusted to use and account for 3132e8d8bef9SDimitry Andric // the post-inc value. 31335ffd83dbSDimitry Andric // For example: 31345ffd83dbSDimitry Andric // LDR #0 LDR_POSTINC #16 31355ffd83dbSDimitry Andric // LDR #4 LDR #-12 31365ffd83dbSDimitry Andric // LDR #8 LDR #-8 31375ffd83dbSDimitry Andric // LDR #12 LDR #-4 31385ffd83dbSDimitry Andric // ADD #16 3139e8d8bef9SDimitry Andric // 3140e8d8bef9SDimitry Andric // At the same time if we do not find an increment but do find an existing 3141e8d8bef9SDimitry Andric // pre/post inc instruction, we can still adjust the offsets of subsequent 3142e8d8bef9SDimitry Andric // instructions to save the register move that would otherwise be needed for the 3143e8d8bef9SDimitry Andric // in-place increment. 31445ffd83dbSDimitry Andric bool ARMPreAllocLoadStoreOpt::DistributeIncrements(Register Base) { 31455ffd83dbSDimitry Andric // We are looking for: 31465ffd83dbSDimitry Andric // One zero offset load/store that can become postinc 31475ffd83dbSDimitry Andric MachineInstr *BaseAccess = nullptr; 3148e8d8bef9SDimitry Andric MachineInstr *PrePostInc = nullptr; 31495ffd83dbSDimitry Andric // An increment that can be folded in 31505ffd83dbSDimitry Andric MachineInstr *Increment = nullptr; 31515ffd83dbSDimitry Andric // Other accesses after BaseAccess that will need to be updated to use the 3152e8d8bef9SDimitry Andric // postinc value. 31535ffd83dbSDimitry Andric SmallPtrSet<MachineInstr *, 8> OtherAccesses; 31545ffd83dbSDimitry Andric for (auto &Use : MRI->use_nodbg_instructions(Base)) { 31555ffd83dbSDimitry Andric if (!Increment && getAddSubImmediate(Use) != 0) { 31565ffd83dbSDimitry Andric Increment = &Use; 31575ffd83dbSDimitry Andric continue; 31585ffd83dbSDimitry Andric } 31595ffd83dbSDimitry Andric 31605ffd83dbSDimitry Andric int BaseOp = getBaseOperandIndex(Use); 31615ffd83dbSDimitry Andric if (BaseOp == -1) 31625ffd83dbSDimitry Andric return false; 31635ffd83dbSDimitry Andric 31645ffd83dbSDimitry Andric if (!Use.getOperand(BaseOp).isReg() || 31655ffd83dbSDimitry Andric Use.getOperand(BaseOp).getReg() != Base) 31665ffd83dbSDimitry Andric return false; 3167e8d8bef9SDimitry Andric if (isPreIndex(Use) || isPostIndex(Use)) 3168e8d8bef9SDimitry Andric PrePostInc = &Use; 3169e8d8bef9SDimitry Andric else if (Use.getOperand(BaseOp + 1).getImm() == 0) 31705ffd83dbSDimitry Andric BaseAccess = &Use; 31715ffd83dbSDimitry Andric else 31725ffd83dbSDimitry Andric OtherAccesses.insert(&Use); 31735ffd83dbSDimitry Andric } 31745ffd83dbSDimitry Andric 3175e8d8bef9SDimitry Andric int IncrementOffset; 3176e8d8bef9SDimitry Andric Register NewBaseReg; 3177e8d8bef9SDimitry Andric if (BaseAccess && Increment) { 3178e8d8bef9SDimitry Andric if (PrePostInc || BaseAccess->getParent() != Increment->getParent()) 31795ffd83dbSDimitry Andric return false; 31805ffd83dbSDimitry Andric Register PredReg; 3181*0fca6ea1SDimitry Andric if (Increment->definesRegister(ARM::CPSR, /*TRI=*/nullptr) || 31825ffd83dbSDimitry Andric getInstrPredicate(*Increment, PredReg) != ARMCC::AL) 31835ffd83dbSDimitry Andric return false; 31845ffd83dbSDimitry Andric 31855ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "\nAttempting to distribute increments on VirtualReg " 31865ffd83dbSDimitry Andric << Base.virtRegIndex() << "\n"); 31875ffd83dbSDimitry Andric 318881ad6265SDimitry Andric // Make sure that Increment has no uses before BaseAccess that are not PHI 318981ad6265SDimitry Andric // uses. 31905ffd83dbSDimitry Andric for (MachineInstr &Use : 31915ffd83dbSDimitry Andric MRI->use_nodbg_instructions(Increment->getOperand(0).getReg())) { 319281ad6265SDimitry Andric if (&Use == BaseAccess || (Use.getOpcode() != TargetOpcode::PHI && 319381ad6265SDimitry Andric !DT->dominates(BaseAccess, &Use))) { 31945ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " BaseAccess doesn't dominate use of increment\n"); 31955ffd83dbSDimitry Andric return false; 31965ffd83dbSDimitry Andric } 31975ffd83dbSDimitry Andric } 31985ffd83dbSDimitry Andric 31995ffd83dbSDimitry Andric // Make sure that Increment can be folded into Base 3200e8d8bef9SDimitry Andric IncrementOffset = getAddSubImmediate(*Increment); 32015ffd83dbSDimitry Andric unsigned NewPostIncOpcode = getPostIndexedLoadStoreOpcode( 32025ffd83dbSDimitry Andric BaseAccess->getOpcode(), IncrementOffset > 0 ? ARM_AM::add : ARM_AM::sub); 32035ffd83dbSDimitry Andric if (!isLegalAddressImm(NewPostIncOpcode, IncrementOffset, TII)) { 32045ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " Illegal addressing mode immediate on postinc\n"); 32055ffd83dbSDimitry Andric return false; 32065ffd83dbSDimitry Andric } 3207e8d8bef9SDimitry Andric } 3208e8d8bef9SDimitry Andric else if (PrePostInc) { 3209e8d8bef9SDimitry Andric // If we already have a pre/post index load/store then set BaseAccess, 3210e8d8bef9SDimitry Andric // IncrementOffset and NewBaseReg to the values it already produces, 3211e8d8bef9SDimitry Andric // allowing us to update and subsequent uses of BaseOp reg with the 3212e8d8bef9SDimitry Andric // incremented value. 3213e8d8bef9SDimitry Andric if (Increment) 3214e8d8bef9SDimitry Andric return false; 3215e8d8bef9SDimitry Andric 3216e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "\nAttempting to distribute increments on already " 3217e8d8bef9SDimitry Andric << "indexed VirtualReg " << Base.virtRegIndex() << "\n"); 3218e8d8bef9SDimitry Andric int BaseOp = getBaseOperandIndex(*PrePostInc); 3219e8d8bef9SDimitry Andric IncrementOffset = PrePostInc->getOperand(BaseOp+1).getImm(); 3220e8d8bef9SDimitry Andric BaseAccess = PrePostInc; 3221e8d8bef9SDimitry Andric NewBaseReg = PrePostInc->getOperand(0).getReg(); 3222e8d8bef9SDimitry Andric } 3223e8d8bef9SDimitry Andric else 3224e8d8bef9SDimitry Andric return false; 32255ffd83dbSDimitry Andric 32265ffd83dbSDimitry Andric // And make sure that the negative value of increment can be added to all 32275ffd83dbSDimitry Andric // other offsets after the BaseAccess. We rely on either 32285ffd83dbSDimitry Andric // dominates(BaseAccess, OtherAccess) or dominates(OtherAccess, BaseAccess) 32295ffd83dbSDimitry Andric // to keep things simple. 3230e8d8bef9SDimitry Andric // This also adds a simple codesize metric, to detect if an instruction (like 3231e8d8bef9SDimitry Andric // t2LDRBi12) which can often be shrunk to a thumb1 instruction (tLDRBi) 3232e8d8bef9SDimitry Andric // cannot because it is converted to something else (t2LDRBi8). We start this 3233e8d8bef9SDimitry Andric // at -1 for the gain from removing the increment. 32345ffd83dbSDimitry Andric SmallPtrSet<MachineInstr *, 4> SuccessorAccesses; 3235e8d8bef9SDimitry Andric int CodesizeEstimate = -1; 32365ffd83dbSDimitry Andric for (auto *Use : OtherAccesses) { 32375ffd83dbSDimitry Andric if (DT->dominates(BaseAccess, Use)) { 32385ffd83dbSDimitry Andric SuccessorAccesses.insert(Use); 32395ffd83dbSDimitry Andric unsigned BaseOp = getBaseOperandIndex(*Use); 3240e8d8bef9SDimitry Andric if (!isLegalOrConvertableAddressImm(Use->getOpcode(), 3241e8d8bef9SDimitry Andric Use->getOperand(BaseOp + 1).getImm() - 3242e8d8bef9SDimitry Andric IncrementOffset, 3243e8d8bef9SDimitry Andric TII, CodesizeEstimate)) { 32445ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " Illegal addressing mode immediate on use\n"); 32455ffd83dbSDimitry Andric return false; 32465ffd83dbSDimitry Andric } 32475ffd83dbSDimitry Andric } else if (!DT->dominates(Use, BaseAccess)) { 32485ffd83dbSDimitry Andric LLVM_DEBUG( 32495ffd83dbSDimitry Andric dbgs() << " Unknown dominance relation between Base and Use\n"); 32505ffd83dbSDimitry Andric return false; 32515ffd83dbSDimitry Andric } 32525ffd83dbSDimitry Andric } 3253e8d8bef9SDimitry Andric if (STI->hasMinSize() && CodesizeEstimate > 0) { 3254e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << " Expected to grow instructions under minsize\n"); 3255e8d8bef9SDimitry Andric return false; 3256e8d8bef9SDimitry Andric } 32575ffd83dbSDimitry Andric 3258e8d8bef9SDimitry Andric if (!PrePostInc) { 32595ffd83dbSDimitry Andric // Replace BaseAccess with a post inc 32605ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Changing: "; BaseAccess->dump()); 32615ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " And : "; Increment->dump()); 3262e8d8bef9SDimitry Andric NewBaseReg = Increment->getOperand(0).getReg(); 32635ffd83dbSDimitry Andric MachineInstr *BaseAccessPost = 32645ffd83dbSDimitry Andric createPostIncLoadStore(BaseAccess, IncrementOffset, NewBaseReg, TII, TRI); 32655ffd83dbSDimitry Andric BaseAccess->eraseFromParent(); 32665ffd83dbSDimitry Andric Increment->eraseFromParent(); 32675ffd83dbSDimitry Andric (void)BaseAccessPost; 32685ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " To : "; BaseAccessPost->dump()); 3269e8d8bef9SDimitry Andric } 32705ffd83dbSDimitry Andric 32715ffd83dbSDimitry Andric for (auto *Use : SuccessorAccesses) { 32725ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Changing: "; Use->dump()); 3273fe6060f1SDimitry Andric AdjustBaseAndOffset(Use, NewBaseReg, IncrementOffset, TII, TRI); 32745ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << " To : "; Use->dump()); 32755ffd83dbSDimitry Andric } 32765ffd83dbSDimitry Andric 32775ffd83dbSDimitry Andric // Remove the kill flag from all uses of NewBaseReg, in case any old uses 32785ffd83dbSDimitry Andric // remain. 32795ffd83dbSDimitry Andric for (MachineOperand &Op : MRI->use_nodbg_operands(NewBaseReg)) 32805ffd83dbSDimitry Andric Op.setIsKill(false); 32815ffd83dbSDimitry Andric return true; 32825ffd83dbSDimitry Andric } 32835ffd83dbSDimitry Andric 32845ffd83dbSDimitry Andric bool ARMPreAllocLoadStoreOpt::DistributeIncrements() { 32855ffd83dbSDimitry Andric bool Changed = false; 32865ffd83dbSDimitry Andric SmallSetVector<Register, 4> Visited; 32875ffd83dbSDimitry Andric for (auto &MBB : *MF) { 32885ffd83dbSDimitry Andric for (auto &MI : MBB) { 32895ffd83dbSDimitry Andric int BaseOp = getBaseOperandIndex(MI); 32905ffd83dbSDimitry Andric if (BaseOp == -1 || !MI.getOperand(BaseOp).isReg()) 32915ffd83dbSDimitry Andric continue; 32925ffd83dbSDimitry Andric 32935ffd83dbSDimitry Andric Register Base = MI.getOperand(BaseOp).getReg(); 32945ffd83dbSDimitry Andric if (!Base.isVirtual() || Visited.count(Base)) 32955ffd83dbSDimitry Andric continue; 32965ffd83dbSDimitry Andric 32975ffd83dbSDimitry Andric Visited.insert(Base); 32985ffd83dbSDimitry Andric } 32995ffd83dbSDimitry Andric } 33005ffd83dbSDimitry Andric 33015ffd83dbSDimitry Andric for (auto Base : Visited) 33025ffd83dbSDimitry Andric Changed |= DistributeIncrements(Base); 33035ffd83dbSDimitry Andric 33045ffd83dbSDimitry Andric return Changed; 33055ffd83dbSDimitry Andric } 33065ffd83dbSDimitry Andric 33070b57cec5SDimitry Andric /// Returns an instance of the load / store optimization pass. 33080b57cec5SDimitry Andric FunctionPass *llvm::createARMLoadStoreOptimizationPass(bool PreAlloc) { 33090b57cec5SDimitry Andric if (PreAlloc) 33100b57cec5SDimitry Andric return new ARMPreAllocLoadStoreOpt(); 33110b57cec5SDimitry Andric return new ARMLoadStoreOpt(); 33120b57cec5SDimitry Andric } 3313