| //===- MipsRegisterBankInfo.h -----------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| /// \file |
| /// This file declares the targeting of the RegisterBankInfo class for Mips. |
| /// \todo This should be generated by TableGen. |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H |
| #define LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H |
| |
| #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" |
| |
| #define GET_REGBANK_DECLARATIONS |
| #include "MipsGenRegisterBank.inc" |
| |
| namespace llvm { |
| |
| class TargetRegisterInfo; |
| |
| class MipsGenRegisterBankInfo : public RegisterBankInfo { |
| #define GET_TARGET_REGBANK_CLASS |
| #include "MipsGenRegisterBank.inc" |
| }; |
| |
| /// This class provides the information for the target register banks. |
| class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo { |
| public: |
| MipsRegisterBankInfo(const TargetRegisterInfo &TRI); |
| |
| const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC, |
| LLT) const override; |
| |
| const InstructionMapping & |
| getInstrMapping(const MachineInstr &MI) const override; |
| |
| /// Here we have to narrowScalar s64 operands to s32, combine away G_MERGE or |
| /// G_UNMERGE and erase instructions that became dead in the process. We |
| /// manually assign bank to def operand of all new instructions that were |
| /// created in the process since they will not end up in RegBankSelect loop. |
| void applyMappingImpl(const OperandsMapper &OpdMapper) const override; |
| |
| /// RegBankSelect determined that s64 operand is better to be split into two |
| /// s32 operands in gprb. Here we manually set register banks of def operands |
| /// of newly created instructions since they will not get regbankselected. |
| void setRegBank(MachineInstr &MI, MachineRegisterInfo &MRI) const; |
| |
| private: |
| /// Some instructions are used with both floating point and integer operands. |
| /// We assign InstType to such instructions as it helps us to avoid cross bank |
| /// copies. InstType deppends on context. |
| enum InstType { |
| /// Temporary type, when visit(..., nullptr) finishes will convert to one of |
| /// the remaining types: Integer, FloatingPoint or Ambiguous. |
| NotDetermined, |
| /// Connected with instruction that interprets 'bags of bits' as integers. |
| /// Select gprb to avoid cross bank copies. |
| Integer, |
| /// Connected with instruction that interprets 'bags of bits' as floating |
| /// point numbers. Select fprb to avoid cross bank copies. |
| FloatingPoint, |
| /// Represents moving 'bags of bits' around. Select same bank for entire |
| /// chain to avoid cross bank copies. Currently we select fprb for s64 and |
| /// gprb for s32 Ambiguous operands. |
| Ambiguous, |
| /// Only used for s64. Unlike Ambiguous s64, AmbiguousWithMergeOrUnmerge s64 |
| /// is mapped to gprb (legalized using narrow scalar to s32). |
| AmbiguousWithMergeOrUnmerge |
| }; |
| |
| bool isAmbiguous_64(InstType InstTy, unsigned OpSize) const { |
| if (InstTy == InstType::Ambiguous && OpSize == 64) |
| return true; |
| return false; |
| } |
| |
| bool isAmbiguous_32(InstType InstTy, unsigned OpSize) const { |
| if (InstTy == InstType::Ambiguous && OpSize == 32) |
| return true; |
| return false; |
| } |
| |
| bool isAmbiguous_32or64(InstType InstTy, unsigned OpSize) const { |
| if (InstTy == InstType::Ambiguous && (OpSize == 32 || OpSize == 64)) |
| return true; |
| return false; |
| } |
| |
| bool isAmbiguousWithMergeOrUnmerge_64(InstType InstTy, |
| unsigned OpSize) const { |
| if (InstTy == InstType::AmbiguousWithMergeOrUnmerge && OpSize == 64) |
| return true; |
| return false; |
| } |
| |
| bool isFloatingPoint_32or64(InstType InstTy, unsigned OpSize) const { |
| if (InstTy == InstType::FloatingPoint && (OpSize == 32 || OpSize == 64)) |
| return true; |
| return false; |
| } |
| |
| bool isFloatingPoint_64(InstType InstTy, unsigned OpSize) const { |
| if (InstTy == InstType::FloatingPoint && OpSize == 64) |
| return true; |
| return false; |
| } |
| |
| bool isInteger_32(InstType InstTy, unsigned OpSize) const { |
| if (InstTy == InstType::Integer && OpSize == 32) |
| return true; |
| return false; |
| } |
| |
| /// Some generic instructions have operands that can be mapped to either fprb |
| /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1 |
| /// is always gprb since it is a pointer. |
| /// This class provides containers for MI's ambiguous: |
| /// DefUses : MachineInstrs that use one of MI's ambiguous def operands. |
| /// UseDefs : MachineInstrs that define MI's ambiguous use operands. |
| class AmbiguousRegDefUseContainer { |
| SmallVector<MachineInstr *, 2> DefUses; |
| SmallVector<MachineInstr *, 2> UseDefs; |
| |
| void addDefUses(Register Reg, const MachineRegisterInfo &MRI); |
| void addUseDef(Register Reg, const MachineRegisterInfo &MRI); |
| |
| /// Skip copy instructions until we get to a non-copy instruction or to a |
| /// copy with phys register as def. Used during search for DefUses. |
| /// MI : %5 = COPY %4 |
| /// %6 = COPY %5 |
| /// $v0 = COPY %6 <- we want this one. |
| MachineInstr *skipCopiesOutgoing(MachineInstr *MI) const; |
| |
| /// Skip copy instructions until we get to a non-copy instruction or to a |
| /// copy with phys register as use. Used during search for UseDefs. |
| /// %1 = COPY $a1 <- we want this one. |
| /// %2 = COPY %1 |
| /// MI = %3 = COPY %2 |
| MachineInstr *skipCopiesIncoming(MachineInstr *MI) const; |
| |
| public: |
| AmbiguousRegDefUseContainer(const MachineInstr *MI); |
| SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; } |
| SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; } |
| }; |
| |
| class TypeInfoForMF { |
| /// MachineFunction name is used to recognise when MF changes. |
| std::string MFName; |
| /// <key, value> : value is vector of all MachineInstrs that are waiting for |
| /// key to figure out type of some of its ambiguous operands. |
| DenseMap<const MachineInstr *, SmallVector<const MachineInstr *, 2>> |
| WaitingQueues; |
| /// Recorded InstTypes for visited instructions. |
| DenseMap<const MachineInstr *, InstType> Types; |
| |
| /// Recursively visit MI's adjacent instructions and find MI's InstType. |
| bool visit(const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI, |
| InstType &AmbiguousTy); |
| |
| /// Visit MI's adjacent UseDefs or DefUses. |
| bool visitAdjacentInstrs(const MachineInstr *MI, |
| SmallVectorImpl<MachineInstr *> &AdjacentInstrs, |
| bool isDefUse, InstType &AmbiguousTy); |
| |
| /// Set type for MI, and recursively for all instructions that are |
| /// waiting for MI's type. |
| void setTypes(const MachineInstr *MI, InstType ITy); |
| |
| /// InstType for MI is determined, set it to InstType that corresponds to |
| /// physical regisiter that is operand number Op in CopyInst. |
| void setTypesAccordingToPhysicalRegister(const MachineInstr *MI, |
| const MachineInstr *CopyInst, |
| unsigned Op); |
| |
| /// Set default values for MI in order to start visit. |
| void startVisit(const MachineInstr *MI) { |
| Types.try_emplace(MI, InstType::NotDetermined); |
| WaitingQueues.try_emplace(MI); |
| } |
| |
| /// Returns true if instruction was already visited. Type might not be |
| /// determined at this point but will be when visit(..., nullptr) finishes. |
| bool wasVisited(const MachineInstr *MI) const { return Types.count(MI); }; |
| |
| /// Returns recorded type for instruction. |
| const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const { |
| assert(wasVisited(MI) && "Instruction was not visited!"); |
| return Types.find(MI)->getSecond(); |
| }; |
| |
| /// Change recorded type for instruction. |
| void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) { |
| assert(wasVisited(MI) && "Instruction was not visited!"); |
| Types.find(MI)->getSecond() = InstTy; |
| }; |
| |
| /// Returns WaitingQueue for instruction. |
| const SmallVectorImpl<const MachineInstr *> & |
| getWaitingQueueFor(const MachineInstr *MI) const { |
| assert(WaitingQueues.count(MI) && "Instruction was not visited!"); |
| return WaitingQueues.find(MI)->getSecond(); |
| }; |
| |
| /// Add WaitingForMI to MI's WaitingQueue. |
| void addToWaitingQueue(const MachineInstr *MI, |
| const MachineInstr *WaitingForMI) { |
| assert(WaitingQueues.count(MI) && "Instruction was not visited!"); |
| WaitingQueues.find(MI)->getSecond().push_back(WaitingForMI); |
| }; |
| |
| public: |
| InstType determineInstType(const MachineInstr *MI); |
| |
| void cleanupIfNewFunction(llvm::StringRef FunctionName); |
| |
| /// MI is about to get destroyed (using narrow scalar). Internal data is |
| /// saved based on MI's address, clear it since it is no longer valid. |
| void clearTypeInfoData(const MachineInstr *MI) { |
| Types.erase(MI); |
| WaitingQueues.erase(MI); |
| }; |
| }; |
| }; |
| } // end namespace llvm |
| #endif |