109467b48Spatrick //===- MipsRegisterBankInfo.h -----------------------------------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick /// \file
909467b48Spatrick /// This file declares the targeting of the RegisterBankInfo class for Mips.
1009467b48Spatrick /// \todo This should be generated by TableGen.
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #ifndef LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H
1409467b48Spatrick #define LLVM_LIB_TARGET_MIPS_MIPSREGISTERBANKINFO_H
1509467b48Spatrick 
16*d415bd75Srobert #include "llvm/CodeGen/RegisterBankInfo.h"
1709467b48Spatrick 
1809467b48Spatrick #define GET_REGBANK_DECLARATIONS
1909467b48Spatrick #include "MipsGenRegisterBank.inc"
2009467b48Spatrick 
2109467b48Spatrick namespace llvm {
2209467b48Spatrick 
2309467b48Spatrick class TargetRegisterInfo;
2409467b48Spatrick 
2509467b48Spatrick class MipsGenRegisterBankInfo : public RegisterBankInfo {
2609467b48Spatrick #define GET_TARGET_REGBANK_CLASS
2709467b48Spatrick #include "MipsGenRegisterBank.inc"
2809467b48Spatrick };
2909467b48Spatrick 
3009467b48Spatrick /// This class provides the information for the target register banks.
3109467b48Spatrick class MipsRegisterBankInfo final : public MipsGenRegisterBankInfo {
3209467b48Spatrick public:
3309467b48Spatrick   MipsRegisterBankInfo(const TargetRegisterInfo &TRI);
3409467b48Spatrick 
3509467b48Spatrick   const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC,
3609467b48Spatrick                                              LLT) const override;
3709467b48Spatrick 
3809467b48Spatrick   const InstructionMapping &
3909467b48Spatrick   getInstrMapping(const MachineInstr &MI) const override;
4009467b48Spatrick 
4109467b48Spatrick   /// Here we have to narrowScalar s64 operands to s32, combine away G_MERGE or
4209467b48Spatrick   /// G_UNMERGE and erase instructions that became dead in the process. We
4309467b48Spatrick   /// manually assign bank to def operand of all new instructions that were
4409467b48Spatrick   /// created in the process since they will not end up in RegBankSelect loop.
4509467b48Spatrick   void applyMappingImpl(const OperandsMapper &OpdMapper) const override;
4609467b48Spatrick 
4709467b48Spatrick   /// RegBankSelect determined that s64 operand is better to be split into two
4809467b48Spatrick   /// s32 operands in gprb. Here we manually set register banks of def operands
4909467b48Spatrick   /// of newly created instructions since they will not get regbankselected.
5009467b48Spatrick   void setRegBank(MachineInstr &MI, MachineRegisterInfo &MRI) const;
5109467b48Spatrick 
5209467b48Spatrick private:
5309467b48Spatrick   /// Some instructions are used with both floating point and integer operands.
5409467b48Spatrick   /// We assign InstType to such instructions as it helps us to avoid cross bank
5509467b48Spatrick   /// copies. InstType deppends on context.
5609467b48Spatrick   enum InstType {
5709467b48Spatrick     /// Temporary type, when visit(..., nullptr) finishes will convert to one of
5809467b48Spatrick     /// the remaining types: Integer, FloatingPoint or Ambiguous.
5909467b48Spatrick     NotDetermined,
6009467b48Spatrick     /// Connected with instruction that interprets 'bags of bits' as integers.
6109467b48Spatrick     /// Select gprb to avoid cross bank copies.
6209467b48Spatrick     Integer,
6309467b48Spatrick     /// Connected with instruction that interprets 'bags of bits' as floating
6409467b48Spatrick     /// point numbers. Select fprb to avoid cross bank copies.
6509467b48Spatrick     FloatingPoint,
6609467b48Spatrick     /// Represents moving 'bags of bits' around. Select same bank for entire
6709467b48Spatrick     /// chain to avoid cross bank copies. Currently we select fprb for s64 and
6809467b48Spatrick     /// gprb for s32 Ambiguous operands.
69097a140dSpatrick     Ambiguous,
70097a140dSpatrick     /// Only used for s64. Unlike Ambiguous s64, AmbiguousWithMergeOrUnmerge s64
71097a140dSpatrick     /// is mapped to gprb (legalized using narrow scalar to s32).
72097a140dSpatrick     AmbiguousWithMergeOrUnmerge
7309467b48Spatrick   };
7409467b48Spatrick 
isAmbiguous_64(InstType InstTy,unsigned OpSize)75097a140dSpatrick   bool isAmbiguous_64(InstType InstTy, unsigned OpSize) const {
76097a140dSpatrick     if (InstTy == InstType::Ambiguous && OpSize == 64)
77097a140dSpatrick       return true;
78097a140dSpatrick     return false;
79097a140dSpatrick   }
80097a140dSpatrick 
isAmbiguous_32(InstType InstTy,unsigned OpSize)81097a140dSpatrick   bool isAmbiguous_32(InstType InstTy, unsigned OpSize) const {
82097a140dSpatrick     if (InstTy == InstType::Ambiguous && OpSize == 32)
83097a140dSpatrick       return true;
84097a140dSpatrick     return false;
85097a140dSpatrick   }
86097a140dSpatrick 
isAmbiguous_32or64(InstType InstTy,unsigned OpSize)87097a140dSpatrick   bool isAmbiguous_32or64(InstType InstTy, unsigned OpSize) const {
88097a140dSpatrick     if (InstTy == InstType::Ambiguous && (OpSize == 32 || OpSize == 64))
89097a140dSpatrick       return true;
90097a140dSpatrick     return false;
91097a140dSpatrick   }
92097a140dSpatrick 
isAmbiguousWithMergeOrUnmerge_64(InstType InstTy,unsigned OpSize)93097a140dSpatrick   bool isAmbiguousWithMergeOrUnmerge_64(InstType InstTy,
94097a140dSpatrick                                         unsigned OpSize) const {
95097a140dSpatrick     if (InstTy == InstType::AmbiguousWithMergeOrUnmerge && OpSize == 64)
96097a140dSpatrick       return true;
97097a140dSpatrick     return false;
98097a140dSpatrick   }
99097a140dSpatrick 
isFloatingPoint_32or64(InstType InstTy,unsigned OpSize)100097a140dSpatrick   bool isFloatingPoint_32or64(InstType InstTy, unsigned OpSize) const {
101097a140dSpatrick     if (InstTy == InstType::FloatingPoint && (OpSize == 32 || OpSize == 64))
102097a140dSpatrick       return true;
103097a140dSpatrick     return false;
104097a140dSpatrick   }
105097a140dSpatrick 
isFloatingPoint_64(InstType InstTy,unsigned OpSize)106097a140dSpatrick   bool isFloatingPoint_64(InstType InstTy, unsigned OpSize) const {
107097a140dSpatrick     if (InstTy == InstType::FloatingPoint && OpSize == 64)
108097a140dSpatrick       return true;
109097a140dSpatrick     return false;
110097a140dSpatrick   }
111097a140dSpatrick 
isInteger_32(InstType InstTy,unsigned OpSize)112097a140dSpatrick   bool isInteger_32(InstType InstTy, unsigned OpSize) const {
113097a140dSpatrick     if (InstTy == InstType::Integer && OpSize == 32)
114097a140dSpatrick       return true;
115097a140dSpatrick     return false;
116097a140dSpatrick   }
117097a140dSpatrick 
11809467b48Spatrick   /// Some generic instructions have operands that can be mapped to either fprb
11909467b48Spatrick   /// or gprb e.g. for G_LOAD we consider only operand 0 as ambiguous, operand 1
12009467b48Spatrick   /// is always gprb since it is a pointer.
12109467b48Spatrick   /// This class provides containers for MI's ambiguous:
12209467b48Spatrick   /// DefUses : MachineInstrs that use one of MI's ambiguous def operands.
12309467b48Spatrick   /// UseDefs : MachineInstrs that define MI's ambiguous use operands.
12409467b48Spatrick   class AmbiguousRegDefUseContainer {
12509467b48Spatrick     SmallVector<MachineInstr *, 2> DefUses;
12609467b48Spatrick     SmallVector<MachineInstr *, 2> UseDefs;
12709467b48Spatrick 
12809467b48Spatrick     void addDefUses(Register Reg, const MachineRegisterInfo &MRI);
12909467b48Spatrick     void addUseDef(Register Reg, const MachineRegisterInfo &MRI);
13009467b48Spatrick 
13109467b48Spatrick     /// Skip copy instructions until we get to a non-copy instruction or to a
13209467b48Spatrick     /// copy with phys register as def. Used during search for DefUses.
13309467b48Spatrick     /// MI :  %5 = COPY %4
13409467b48Spatrick     ///       %6 = COPY %5
13509467b48Spatrick     ///       $v0 = COPY %6 <- we want this one.
13609467b48Spatrick     MachineInstr *skipCopiesOutgoing(MachineInstr *MI) const;
13709467b48Spatrick 
13809467b48Spatrick     /// Skip copy instructions until we get to a non-copy instruction or to a
13909467b48Spatrick     /// copy with phys register as use. Used during search for UseDefs.
14009467b48Spatrick     ///       %1 = COPY $a1 <- we want this one.
14109467b48Spatrick     ///       %2 = COPY %1
14209467b48Spatrick     /// MI =  %3 = COPY %2
14309467b48Spatrick     MachineInstr *skipCopiesIncoming(MachineInstr *MI) const;
14409467b48Spatrick 
14509467b48Spatrick   public:
14609467b48Spatrick     AmbiguousRegDefUseContainer(const MachineInstr *MI);
getDefUses()14709467b48Spatrick     SmallVectorImpl<MachineInstr *> &getDefUses() { return DefUses; }
getUseDefs()14809467b48Spatrick     SmallVectorImpl<MachineInstr *> &getUseDefs() { return UseDefs; }
14909467b48Spatrick   };
15009467b48Spatrick 
15109467b48Spatrick   class TypeInfoForMF {
15209467b48Spatrick     /// MachineFunction name is used to recognise when MF changes.
15373471bf0Spatrick     std::string MFName;
15409467b48Spatrick     /// <key, value> : value is vector of all MachineInstrs that are waiting for
15509467b48Spatrick     /// key to figure out type of some of its ambiguous operands.
15609467b48Spatrick     DenseMap<const MachineInstr *, SmallVector<const MachineInstr *, 2>>
15709467b48Spatrick         WaitingQueues;
15809467b48Spatrick     /// Recorded InstTypes for visited instructions.
15909467b48Spatrick     DenseMap<const MachineInstr *, InstType> Types;
16009467b48Spatrick 
16109467b48Spatrick     /// Recursively visit MI's adjacent instructions and find MI's InstType.
162097a140dSpatrick     bool visit(const MachineInstr *MI, const MachineInstr *WaitingForTypeOfMI,
163097a140dSpatrick                InstType &AmbiguousTy);
16409467b48Spatrick 
16509467b48Spatrick     /// Visit MI's adjacent UseDefs or DefUses.
16609467b48Spatrick     bool visitAdjacentInstrs(const MachineInstr *MI,
16709467b48Spatrick                              SmallVectorImpl<MachineInstr *> &AdjacentInstrs,
168097a140dSpatrick                              bool isDefUse, InstType &AmbiguousTy);
16909467b48Spatrick 
17009467b48Spatrick     /// Set type for MI, and recursively for all instructions that are
17109467b48Spatrick     /// waiting for MI's type.
17209467b48Spatrick     void setTypes(const MachineInstr *MI, InstType ITy);
17309467b48Spatrick 
17409467b48Spatrick     /// InstType for MI is determined, set it to InstType that corresponds to
17509467b48Spatrick     /// physical regisiter that is operand number Op in CopyInst.
17609467b48Spatrick     void setTypesAccordingToPhysicalRegister(const MachineInstr *MI,
17709467b48Spatrick                                              const MachineInstr *CopyInst,
17809467b48Spatrick                                              unsigned Op);
17909467b48Spatrick 
18009467b48Spatrick     /// Set default values for MI in order to start visit.
startVisit(const MachineInstr * MI)18109467b48Spatrick     void startVisit(const MachineInstr *MI) {
18209467b48Spatrick       Types.try_emplace(MI, InstType::NotDetermined);
18309467b48Spatrick       WaitingQueues.try_emplace(MI);
18409467b48Spatrick     }
18509467b48Spatrick 
18609467b48Spatrick     /// Returns true if instruction was already visited. Type might not be
18709467b48Spatrick     /// determined at this point but will be when visit(..., nullptr) finishes.
wasVisited(const MachineInstr * MI)18809467b48Spatrick     bool wasVisited(const MachineInstr *MI) const { return Types.count(MI); };
18909467b48Spatrick 
19009467b48Spatrick     /// Returns recorded type for instruction.
getRecordedTypeForInstr(const MachineInstr * MI)19109467b48Spatrick     const InstType &getRecordedTypeForInstr(const MachineInstr *MI) const {
19209467b48Spatrick       assert(wasVisited(MI) && "Instruction was not visited!");
19309467b48Spatrick       return Types.find(MI)->getSecond();
19409467b48Spatrick     };
19509467b48Spatrick 
19609467b48Spatrick     /// Change recorded type for instruction.
changeRecordedTypeForInstr(const MachineInstr * MI,InstType InstTy)19709467b48Spatrick     void changeRecordedTypeForInstr(const MachineInstr *MI, InstType InstTy) {
19809467b48Spatrick       assert(wasVisited(MI) && "Instruction was not visited!");
19909467b48Spatrick       Types.find(MI)->getSecond() = InstTy;
20009467b48Spatrick     };
20109467b48Spatrick 
20209467b48Spatrick     /// Returns WaitingQueue for instruction.
20309467b48Spatrick     const SmallVectorImpl<const MachineInstr *> &
getWaitingQueueFor(const MachineInstr * MI)20409467b48Spatrick     getWaitingQueueFor(const MachineInstr *MI) const {
20509467b48Spatrick       assert(WaitingQueues.count(MI) && "Instruction was not visited!");
20609467b48Spatrick       return WaitingQueues.find(MI)->getSecond();
20709467b48Spatrick     };
20809467b48Spatrick 
20909467b48Spatrick     /// Add WaitingForMI to MI's WaitingQueue.
addToWaitingQueue(const MachineInstr * MI,const MachineInstr * WaitingForMI)21009467b48Spatrick     void addToWaitingQueue(const MachineInstr *MI,
21109467b48Spatrick                            const MachineInstr *WaitingForMI) {
21209467b48Spatrick       assert(WaitingQueues.count(MI) && "Instruction was not visited!");
21309467b48Spatrick       WaitingQueues.find(MI)->getSecond().push_back(WaitingForMI);
21409467b48Spatrick     };
21509467b48Spatrick 
21609467b48Spatrick   public:
21709467b48Spatrick     InstType determineInstType(const MachineInstr *MI);
21809467b48Spatrick 
21909467b48Spatrick     void cleanupIfNewFunction(llvm::StringRef FunctionName);
220097a140dSpatrick 
221097a140dSpatrick     /// MI is about to get destroyed (using narrow scalar). Internal data is
222097a140dSpatrick     /// saved based on MI's address, clear it since it is no longer valid.
clearTypeInfoData(const MachineInstr * MI)223097a140dSpatrick     void clearTypeInfoData(const MachineInstr *MI) {
224097a140dSpatrick       Types.erase(MI);
225097a140dSpatrick       WaitingQueues.erase(MI);
226097a140dSpatrick     };
22709467b48Spatrick   };
22809467b48Spatrick };
22909467b48Spatrick } // end namespace llvm
23009467b48Spatrick #endif
231