| //===- 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/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 |