xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Mips/MipsRegisterBankInfo.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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