1 //===- MipsRegisterBankInfo.h -----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// This file declares the targeting of the RegisterBankInfo class for Mips. 10 /// \todo This should be generated by TableGen. 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H 14 #define LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H 15 16 #include "llvm/CodeGen/RegisterBankInfo.h" 17 18 #define GET_REGBANK_DECLARATIONS 19 #include "MipsGenRegisterBank.inc" 20 21 namespace llvm { 22 23 class TargetRegisterInfo; 24 25 class MipsGenRegisterBankInfo : public RegisterBankInfo { 26 #define GET_TARGET_REGBANK_CLASS 27 #include "MipsGenRegisterBank.inc" 28 }; 29 30 /// This class provides the information for the target register banks. 31 class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo { 32 public: 33 MipsRegisterBankInfo(const TargetRegisterInfo &TRI); 34 35 const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC, 36 LLT) const override; 37 38 const InstructionMapping & 39 getInstrMapping(const MachineInstr &MI) const override; 40 41 /// Here we have to narrowScalar s64 operands to s32, combine away G_MERGE or 42 /// G_UNMERGE and erase instructions that became dead in the process. We 43 /// manually assign bank to def operand of all new instructions that were 44 /// created in the process since they will not end up in RegBankSelect loop. 45 void applyMappingImpl(MachineIRBuilder &Builder, 46 const OperandsMapper &OpdMapper) const override; 47 48 /// RegBankSelect determined that s64 operand is better to be split into two 49 /// s32 operands in gprb. Here we manually set register banks of def operands 50 /// of newly created instructions since they will not get regbankselected. 51 void setRegBank(MachineInstr &MI, MachineRegisterInfo &MRI) const; 52 53 private: 54 /// Some instructions are used with both floating point and integer operands. 55 /// We assign InstType to such instructions as it helps us to avoid cross bank 56 /// copies. InstType deppends on context. 57 enum InstType { 58 /// Temporary type, when visit(..., nullptr) finishes will convert to one of 59 /// the remaining types: Integer, FloatingPoint or Ambiguous. 60 NotDetermined, 61 /// Connected with instruction that interprets 'bags of bits' as integers. 62 /// Select gprb to avoid cross bank copies. 63 Integer, 64 /// Connected with instruction that interprets 'bags of bits' as floating 65 /// point numbers. Select fprb to avoid cross bank copies. 66 FloatingPoint, 67 /// Represents moving 'bags of bits' around. Select same bank for entire 68 /// chain to avoid cross bank copies. Currently we select fprb for s64 and 69 /// gprb for s32 Ambiguous operands. 70 Ambiguous, 71 /// Only used for s64. Unlike Ambiguous s64, AmbiguousWithMergeOrUnmerge s64 72 /// is mapped to gprb (legalized using narrow scalar to s32). 73 AmbiguousWithMergeOrUnmerge 74 }; 75 76 bool isAmbiguous_64(InstType InstTy, unsigned OpSize) const { 77 if (InstTy == InstType::Ambiguous && OpSize == 64) 78 return true; 79 return false; 80 } 81 82 bool isAmbiguous_32(InstType InstTy, unsigned OpSize) const { 83 if (InstTy == InstType::Ambiguous && OpSize == 32) 84 return true; 85 return false; 86 } 87 88 bool isAmbiguous_32or64(InstType InstTy, unsigned OpSize) const { 89 if (InstTy == InstType::Ambiguous && (OpSize == 32 || OpSize == 64)) 90 return true; 91 return false; 92 } 93 94 bool isAmbiguousWithMergeOrUnmerge_64(InstType InstTy, 95 unsigned OpSize) const { 96 if (InstTy == InstType::AmbiguousWithMergeOrUnmerge && OpSize == 64) 97 return true; 98 return false; 99 } 100 101 bool isFloatingPoint_32or64(InstType InstTy, unsigned OpSize) const { 102 if (InstTy == InstType::FloatingPoint && (OpSize == 32 || OpSize == 64)) 103 return true; 104 return false; 105 } 106 107 bool isFloatingPoint_64(InstType InstTy, unsigned OpSize) const { 108 if (InstTy == InstType::FloatingPoint && OpSize == 64) 109 return true; 110 return false; 111 } 112 113 bool isInteger_32(InstType InstTy, unsigned OpSize) const { 114 if (InstTy == InstType::Integer && OpSize == 32) 115 return true; 116 return false; 117 } 118 119 /// Some generic instructions have operands that can be mapped to either fprb 120 /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1 121 /// is always gprb since it is a pointer. 122 /// This class provides containers for MI's ambiguous: 123 /// DefUses : MachineInstrs that use one of MI's ambiguous def operands. 124 /// UseDefs : MachineInstrs that define MI's ambiguous use operands. 125 class AmbiguousRegDefUseContainer { 126 SmallVector<MachineInstr *, 2> DefUses; 127 SmallVector<MachineInstr *, 2> UseDefs; 128 129 void addDefUses(Register Reg, const MachineRegisterInfo &MRI); 130 void addUseDef(Register Reg, const MachineRegisterInfo &MRI); 131 132 /// Skip copy instructions until we get to a non-copy instruction or to a 133 /// copy with phys register as def. Used during search for DefUses. 134 /// MI : %5 = COPY %4 135 /// %6 = COPY %5 136 /// $v0 = COPY %6 <- we want this one. 137 MachineInstr *skipCopiesOutgoing(MachineInstr *MI) const; 138 139 /// Skip copy instructions until we get to a non-copy instruction or to a 140 /// copy with phys register as use. Used during search for UseDefs. 141 /// %1 = COPY $a1 <- we want this one. 142 /// %2 = COPY %1 143 /// MI = %3 = COPY %2 144 MachineInstr *skipCopiesIncoming(MachineInstr *MI) const; 145 146 public: 147 AmbiguousRegDefUseContainer(const MachineInstr *MI); 148 SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; } 149 SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; } 150 }; 151 152 class TypeInfoForMF { 153 /// MachineFunction name is used to recognise when MF changes. 154 std::string MFName; 155 /// <key, value> : value is vector of all MachineInstrs that are waiting for 156 /// key to figure out type of some of its ambiguous operands. 157 DenseMap<const MachineInstr *, SmallVector<const MachineInstr *, 2>> 158 WaitingQueues; 159 /// Recorded InstTypes for visited instructions. 160 DenseMap<const MachineInstr *, InstType> Types; 161 162 /// Recursively visit MI's adjacent instructions and find MI's InstType. 163 bool visit(const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI, 164 InstType &AmbiguousTy); 165 166 /// Visit MI's adjacent UseDefs or DefUses. 167 bool visitAdjacentInstrs(const MachineInstr *MI, 168 SmallVectorImpl<MachineInstr *> &AdjacentInstrs, 169 bool isDefUse, InstType &AmbiguousTy); 170 171 /// Set type for MI, and recursively for all instructions that are 172 /// waiting for MI's type. 173 void setTypes(const MachineInstr *MI, InstType ITy); 174 175 /// InstType for MI is determined, set it to InstType that corresponds to 176 /// physical regisiter that is operand number Op in CopyInst. 177 void setTypesAccordingToPhysicalRegister(const MachineInstr *MI, 178 const MachineInstr *CopyInst, 179 unsigned Op); 180 181 /// Set default values for MI in order to start visit. 182 void startVisit(const MachineInstr *MI) { 183 Types.try_emplace(MI, InstType::NotDetermined); 184 WaitingQueues.try_emplace(MI); 185 } 186 187 /// Returns true if instruction was already visited. Type might not be 188 /// determined at this point but will be when visit(..., nullptr) finishes. 189 bool wasVisited(const MachineInstr *MI) const { return Types.count(MI); }; 190 191 /// Returns recorded type for instruction. 192 const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const { 193 assert(wasVisited(MI) && "Instruction was not visited!"); 194 return Types.find(MI)->getSecond(); 195 }; 196 197 /// Change recorded type for instruction. 198 void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) { 199 assert(wasVisited(MI) && "Instruction was not visited!"); 200 Types.find(MI)->getSecond() = InstTy; 201 }; 202 203 /// Returns WaitingQueue for instruction. 204 const SmallVectorImpl<const MachineInstr *> & 205 getWaitingQueueFor(const MachineInstr *MI) const { 206 assert(WaitingQueues.count(MI) && "Instruction was not visited!"); 207 return WaitingQueues.find(MI)->getSecond(); 208 }; 209 210 /// Add WaitingForMI to MI's WaitingQueue. 211 void addToWaitingQueue(const MachineInstr *MI, 212 const MachineInstr *WaitingForMI) { 213 assert(WaitingQueues.count(MI) && "Instruction was not visited!"); 214 WaitingQueues.find(MI)->getSecond().push_back(WaitingForMI); 215 }; 216 217 public: 218 InstType determineInstType(const MachineInstr *MI); 219 220 void cleanupIfNewFunction(llvm::StringRef FunctionName); 221 222 /// MI is about to get destroyed (using narrow scalar). Internal data is 223 /// saved based on MI's address, clear it since it is no longer valid. 224 void clearTypeInfoData(const MachineInstr *MI) { 225 Types.erase(MI); 226 WaitingQueues.erase(MI); 227 }; 228 }; 229 }; 230 } // end namespace llvm 231 #endif 232