10b57cec5SDimitry Andric //===- MipsRegisterBankInfo.h -----------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This file declares the targeting of the RegisterBankInfo class for Mips. 100b57cec5SDimitry Andric /// \todo This should be generated by TableGen. 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H 140b57cec5SDimitry Andric #define LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H 150b57cec5SDimitry Andric 1681ad6265SDimitry Andric #include "llvm/CodeGen/RegisterBankInfo.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #define GET_REGBANK_DECLARATIONS 190b57cec5SDimitry Andric #include "MipsGenRegisterBank.inc" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace llvm { 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric class TargetRegisterInfo; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric class MipsGenRegisterBankInfo : public RegisterBankInfo { 260b57cec5SDimitry Andric #define GET_TARGET_REGBANK_CLASS 270b57cec5SDimitry Andric #include "MipsGenRegisterBank.inc" 280b57cec5SDimitry Andric }; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric /// This class provides the information for the target register banks. 310b57cec5SDimitry Andric class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo { 320b57cec5SDimitry Andric public: 330b57cec5SDimitry Andric MipsRegisterBankInfo(const TargetRegisterInfo &TRI); 340b57cec5SDimitry Andric 35480093f4SDimitry Andric const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC, 36480093f4SDimitry Andric LLT) const override; 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric const InstructionMapping & 390b57cec5SDimitry Andric getInstrMapping(const MachineInstr &MI) const override; 400b57cec5SDimitry Andric 418bcb0991SDimitry Andric /// Here we have to narrowScalar s64 operands to s32, combine away G_MERGE or 428bcb0991SDimitry Andric /// G_UNMERGE and erase instructions that became dead in the process. We 438bcb0991SDimitry Andric /// manually assign bank to def operand of all new instructions that were 448bcb0991SDimitry Andric /// created in the process since they will not end up in RegBankSelect loop. 45*5f757f3fSDimitry Andric void applyMappingImpl(MachineIRBuilder &Builder, 46*5f757f3fSDimitry Andric const OperandsMapper &OpdMapper) const override; 470b57cec5SDimitry Andric 488bcb0991SDimitry Andric /// RegBankSelect determined that s64 operand is better to be split into two 498bcb0991SDimitry Andric /// s32 operands in gprb. Here we manually set register banks of def operands 508bcb0991SDimitry Andric /// of newly created instructions since they will not get regbankselected. 518bcb0991SDimitry Andric void setRegBank(MachineInstr &MI, MachineRegisterInfo &MRI) const; 528bcb0991SDimitry Andric 530b57cec5SDimitry Andric private: 540b57cec5SDimitry Andric /// Some instructions are used with both floating point and integer operands. 550b57cec5SDimitry Andric /// We assign InstType to such instructions as it helps us to avoid cross bank 560b57cec5SDimitry Andric /// copies. InstType deppends on context. 570b57cec5SDimitry Andric enum InstType { 580b57cec5SDimitry Andric /// Temporary type, when visit(..., nullptr) finishes will convert to one of 590b57cec5SDimitry Andric /// the remaining types: Integer, FloatingPoint or Ambiguous. 600b57cec5SDimitry Andric NotDetermined, 610b57cec5SDimitry Andric /// Connected with instruction that interprets 'bags of bits' as integers. 620b57cec5SDimitry Andric /// Select gprb to avoid cross bank copies. 630b57cec5SDimitry Andric Integer, 640b57cec5SDimitry Andric /// Connected with instruction that interprets 'bags of bits' as floating 650b57cec5SDimitry Andric /// point numbers. Select fprb to avoid cross bank copies. 660b57cec5SDimitry Andric FloatingPoint, 670b57cec5SDimitry Andric /// Represents moving 'bags of bits' around. Select same bank for entire 680b57cec5SDimitry Andric /// chain to avoid cross bank copies. Currently we select fprb for s64 and 690b57cec5SDimitry Andric /// gprb for s32 Ambiguous operands. 705ffd83dbSDimitry Andric Ambiguous, 715ffd83dbSDimitry Andric /// Only used for s64. Unlike Ambiguous s64, AmbiguousWithMergeOrUnmerge s64 725ffd83dbSDimitry Andric /// is mapped to gprb (legalized using narrow scalar to s32). 735ffd83dbSDimitry Andric AmbiguousWithMergeOrUnmerge 740b57cec5SDimitry Andric }; 750b57cec5SDimitry Andric 765ffd83dbSDimitry Andric bool isAmbiguous_64(InstType InstTy, unsigned OpSize) const { 775ffd83dbSDimitry Andric if (InstTy == InstType::Ambiguous && OpSize == 64) 785ffd83dbSDimitry Andric return true; 795ffd83dbSDimitry Andric return false; 805ffd83dbSDimitry Andric } 815ffd83dbSDimitry Andric 825ffd83dbSDimitry Andric bool isAmbiguous_32(InstType InstTy, unsigned OpSize) const { 835ffd83dbSDimitry Andric if (InstTy == InstType::Ambiguous && OpSize == 32) 845ffd83dbSDimitry Andric return true; 855ffd83dbSDimitry Andric return false; 865ffd83dbSDimitry Andric } 875ffd83dbSDimitry Andric 885ffd83dbSDimitry Andric bool isAmbiguous_32or64(InstType InstTy, unsigned OpSize) const { 895ffd83dbSDimitry Andric if (InstTy == InstType::Ambiguous && (OpSize == 32 || OpSize == 64)) 905ffd83dbSDimitry Andric return true; 915ffd83dbSDimitry Andric return false; 925ffd83dbSDimitry Andric } 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric bool isAmbiguousWithMergeOrUnmerge_64(InstType InstTy, 955ffd83dbSDimitry Andric unsigned OpSize) const { 965ffd83dbSDimitry Andric if (InstTy == InstType::AmbiguousWithMergeOrUnmerge && OpSize == 64) 975ffd83dbSDimitry Andric return true; 985ffd83dbSDimitry Andric return false; 995ffd83dbSDimitry Andric } 1005ffd83dbSDimitry Andric 1015ffd83dbSDimitry Andric bool isFloatingPoint_32or64(InstType InstTy, unsigned OpSize) const { 1025ffd83dbSDimitry Andric if (InstTy == InstType::FloatingPoint && (OpSize == 32 || OpSize == 64)) 1035ffd83dbSDimitry Andric return true; 1045ffd83dbSDimitry Andric return false; 1055ffd83dbSDimitry Andric } 1065ffd83dbSDimitry Andric 1075ffd83dbSDimitry Andric bool isFloatingPoint_64(InstType InstTy, unsigned OpSize) const { 1085ffd83dbSDimitry Andric if (InstTy == InstType::FloatingPoint && OpSize == 64) 1095ffd83dbSDimitry Andric return true; 1105ffd83dbSDimitry Andric return false; 1115ffd83dbSDimitry Andric } 1125ffd83dbSDimitry Andric 1135ffd83dbSDimitry Andric bool isInteger_32(InstType InstTy, unsigned OpSize) const { 1145ffd83dbSDimitry Andric if (InstTy == InstType::Integer && OpSize == 32) 1155ffd83dbSDimitry Andric return true; 1165ffd83dbSDimitry Andric return false; 1175ffd83dbSDimitry Andric } 1185ffd83dbSDimitry Andric 1190b57cec5SDimitry Andric /// Some generic instructions have operands that can be mapped to either fprb 1200b57cec5SDimitry Andric /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1 1210b57cec5SDimitry Andric /// is always gprb since it is a pointer. 1220b57cec5SDimitry Andric /// This class provides containers for MI's ambiguous: 1230b57cec5SDimitry Andric /// DefUses : MachineInstrs that use one of MI's ambiguous def operands. 1240b57cec5SDimitry Andric /// UseDefs : MachineInstrs that define MI's ambiguous use operands. 1250b57cec5SDimitry Andric class AmbiguousRegDefUseContainer { 1260b57cec5SDimitry Andric SmallVector<MachineInstr *, 2> DefUses; 1270b57cec5SDimitry Andric SmallVector<MachineInstr *, 2> UseDefs; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric void addDefUses(Register Reg, const MachineRegisterInfo &MRI); 1300b57cec5SDimitry Andric void addUseDef(Register Reg, const MachineRegisterInfo &MRI); 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric /// Skip copy instructions until we get to a non-copy instruction or to a 1330b57cec5SDimitry Andric /// copy with phys register as def. Used during search for DefUses. 1340b57cec5SDimitry Andric /// MI : %5 = COPY %4 1350b57cec5SDimitry Andric /// %6 = COPY %5 1360b57cec5SDimitry Andric /// $v0 = COPY %6 <- we want this one. 1370b57cec5SDimitry Andric MachineInstr *skipCopiesOutgoing(MachineInstr *MI) const; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric /// Skip copy instructions until we get to a non-copy instruction or to a 1400b57cec5SDimitry Andric /// copy with phys register as use. Used during search for UseDefs. 1410b57cec5SDimitry Andric /// %1 = COPY $a1 <- we want this one. 1420b57cec5SDimitry Andric /// %2 = COPY %1 1430b57cec5SDimitry Andric /// MI = %3 = COPY %2 1440b57cec5SDimitry Andric MachineInstr *skipCopiesIncoming(MachineInstr *MI) const; 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric public: 1470b57cec5SDimitry Andric AmbiguousRegDefUseContainer(const MachineInstr *MI); 1480b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; } 1490b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; } 1500b57cec5SDimitry Andric }; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric class TypeInfoForMF { 1530b57cec5SDimitry Andric /// MachineFunction name is used to recognise when MF changes. 154e8d8bef9SDimitry Andric std::string MFName; 1550b57cec5SDimitry Andric /// <key, value> : value is vector of all MachineInstrs that are waiting for 1560b57cec5SDimitry Andric /// key to figure out type of some of its ambiguous operands. 1570b57cec5SDimitry Andric DenseMap<const MachineInstr *, SmallVector<const MachineInstr *, 2>> 1580b57cec5SDimitry Andric WaitingQueues; 1590b57cec5SDimitry Andric /// Recorded InstTypes for visited instructions. 1600b57cec5SDimitry Andric DenseMap<const MachineInstr *, InstType> Types; 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric /// Recursively visit MI's adjacent instructions and find MI's InstType. 1635ffd83dbSDimitry Andric bool visit(const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI, 1645ffd83dbSDimitry Andric InstType &AmbiguousTy); 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric /// Visit MI's adjacent UseDefs or DefUses. 1670b57cec5SDimitry Andric bool visitAdjacentInstrs(const MachineInstr *MI, 1680b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> &AdjacentInstrs, 1695ffd83dbSDimitry Andric bool isDefUse, InstType &AmbiguousTy); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric /// Set type for MI, and recursively for all instructions that are 1720b57cec5SDimitry Andric /// waiting for MI's type. 1730b57cec5SDimitry Andric void setTypes(const MachineInstr *MI, InstType ITy); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric /// InstType for MI is determined, set it to InstType that corresponds to 1760b57cec5SDimitry Andric /// physical regisiter that is operand number Op in CopyInst. 1770b57cec5SDimitry Andric void setTypesAccordingToPhysicalRegister(const MachineInstr *MI, 1780b57cec5SDimitry Andric const MachineInstr *CopyInst, 1790b57cec5SDimitry Andric unsigned Op); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric /// Set default values for MI in order to start visit. 1820b57cec5SDimitry Andric void startVisit(const MachineInstr *MI) { 1830b57cec5SDimitry Andric Types.try_emplace(MI, InstType::NotDetermined); 1840b57cec5SDimitry Andric WaitingQueues.try_emplace(MI); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric /// Returns true if instruction was already visited. Type might not be 1880b57cec5SDimitry Andric /// determined at this point but will be when visit(..., nullptr) finishes. 1890b57cec5SDimitry Andric bool wasVisited(const MachineInstr *MI) const { return Types.count(MI); }; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric /// Returns recorded type for instruction. 1920b57cec5SDimitry Andric const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const { 1930b57cec5SDimitry Andric assert(wasVisited(MI) && "Instruction was not visited!"); 1940b57cec5SDimitry Andric return Types.find(MI)->getSecond(); 1950b57cec5SDimitry Andric }; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric /// Change recorded type for instruction. 1980b57cec5SDimitry Andric void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) { 1990b57cec5SDimitry Andric assert(wasVisited(MI) && "Instruction was not visited!"); 2000b57cec5SDimitry Andric Types.find(MI)->getSecond() = InstTy; 2010b57cec5SDimitry Andric }; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric /// Returns WaitingQueue for instruction. 2040b57cec5SDimitry Andric const SmallVectorImpl<const MachineInstr *> & 2050b57cec5SDimitry Andric getWaitingQueueFor(const MachineInstr *MI) const { 2060b57cec5SDimitry Andric assert(WaitingQueues.count(MI) && "Instruction was not visited!"); 2070b57cec5SDimitry Andric return WaitingQueues.find(MI)->getSecond(); 2080b57cec5SDimitry Andric }; 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric /// Add WaitingForMI to MI's WaitingQueue. 2110b57cec5SDimitry Andric void addToWaitingQueue(const MachineInstr *MI, 2120b57cec5SDimitry Andric const MachineInstr *WaitingForMI) { 2130b57cec5SDimitry Andric assert(WaitingQueues.count(MI) && "Instruction was not visited!"); 2140b57cec5SDimitry Andric WaitingQueues.find(MI)->getSecond().push_back(WaitingForMI); 2150b57cec5SDimitry Andric }; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric public: 2180b57cec5SDimitry Andric InstType determineInstType(const MachineInstr *MI); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric void cleanupIfNewFunction(llvm::StringRef FunctionName); 2215ffd83dbSDimitry Andric 2225ffd83dbSDimitry Andric /// MI is about to get destroyed (using narrow scalar). Internal data is 2235ffd83dbSDimitry Andric /// saved based on MI's address, clear it since it is no longer valid. 2245ffd83dbSDimitry Andric void clearTypeInfoData(const MachineInstr *MI) { 2255ffd83dbSDimitry Andric Types.erase(MI); 2265ffd83dbSDimitry Andric WaitingQueues.erase(MI); 2275ffd83dbSDimitry Andric }; 2280b57cec5SDimitry Andric }; 2290b57cec5SDimitry Andric }; 2300b57cec5SDimitry Andric } // end namespace llvm 2310b57cec5SDimitry Andric #endif 232