231 lines
9.1 KiB
C++
231 lines
9.1 KiB
C++
//===- 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
|