mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
4750d08150
https://reviews.llvm.org/D55294 Previously MachineIRBuilder::buildInstr used to accept variadic arguments for sources (which were either unsigned or MachineInstrBuilder). While this worked well in common cases, it doesn't allow us to build instructions that have multiple destinations. Additionally passing in other optional parameters in the end (such as flags) is not possible trivially. Also a trivial call such as B.buildInstr(Opc, Reg1, Reg2, Reg3) can be interpreted differently based on the opcode (2defs + 1 src for unmerge vs 1 def + 2srcs). This patch refactors the buildInstr to buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>) where DstOps and SrcOps are typed unions that know how to add itself to MachineInstrBuilder. After this patch, most invocations would look like B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..}); Now all the other calls (such as buildAdd, buildSub etc) forward to buildInstr. It also makes it possible to build instructions with multiple defs. Additionally in a subsequent patch, we should make it possible to add flags directly while building instructions. Additionally, the main buildInstr method is now virtual and other builders now only have to override buildInstr (for say constant folding/cseing) is straightforward. Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy patch that should upgrade the API calls if necessary. llvm-svn: 348815
291 lines
9.3 KiB
C++
291 lines
9.3 KiB
C++
//===- MipsInstructionSelector.cpp ------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
/// This file implements the targeting of the InstructionSelector class for
|
|
/// Mips.
|
|
/// \todo This should be generated by TableGen.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MipsRegisterBankInfo.h"
|
|
#include "MipsTargetMachine.h"
|
|
#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h"
|
|
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
|
|
|
#define DEBUG_TYPE "mips-isel"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
#define GET_GLOBALISEL_PREDICATE_BITSET
|
|
#include "MipsGenGlobalISel.inc"
|
|
#undef GET_GLOBALISEL_PREDICATE_BITSET
|
|
|
|
class MipsInstructionSelector : public InstructionSelector {
|
|
public:
|
|
MipsInstructionSelector(const MipsTargetMachine &TM, const MipsSubtarget &STI,
|
|
const MipsRegisterBankInfo &RBI);
|
|
|
|
bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override;
|
|
static const char *getName() { return DEBUG_TYPE; }
|
|
|
|
private:
|
|
bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;
|
|
|
|
const MipsTargetMachine &TM;
|
|
const MipsSubtarget &STI;
|
|
const MipsInstrInfo &TII;
|
|
const MipsRegisterInfo &TRI;
|
|
const MipsRegisterBankInfo &RBI;
|
|
|
|
#define GET_GLOBALISEL_PREDICATES_DECL
|
|
#include "MipsGenGlobalISel.inc"
|
|
#undef GET_GLOBALISEL_PREDICATES_DECL
|
|
|
|
#define GET_GLOBALISEL_TEMPORARIES_DECL
|
|
#include "MipsGenGlobalISel.inc"
|
|
#undef GET_GLOBALISEL_TEMPORARIES_DECL
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
#define GET_GLOBALISEL_IMPL
|
|
#include "MipsGenGlobalISel.inc"
|
|
#undef GET_GLOBALISEL_IMPL
|
|
|
|
MipsInstructionSelector::MipsInstructionSelector(
|
|
const MipsTargetMachine &TM, const MipsSubtarget &STI,
|
|
const MipsRegisterBankInfo &RBI)
|
|
: InstructionSelector(), TM(TM), STI(STI), TII(*STI.getInstrInfo()),
|
|
TRI(*STI.getRegisterInfo()), RBI(RBI),
|
|
|
|
#define GET_GLOBALISEL_PREDICATES_INIT
|
|
#include "MipsGenGlobalISel.inc"
|
|
#undef GET_GLOBALISEL_PREDICATES_INIT
|
|
#define GET_GLOBALISEL_TEMPORARIES_INIT
|
|
#include "MipsGenGlobalISel.inc"
|
|
#undef GET_GLOBALISEL_TEMPORARIES_INIT
|
|
{
|
|
}
|
|
|
|
static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
|
|
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
|
|
const RegisterBankInfo &RBI) {
|
|
unsigned DstReg = I.getOperand(0).getReg();
|
|
if (TargetRegisterInfo::isPhysicalRegister(DstReg))
|
|
return true;
|
|
|
|
const TargetRegisterClass *RC = &Mips::GPR32RegClass;
|
|
|
|
if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
|
|
LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
|
|
<< " operand\n");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MipsInstructionSelector::select(MachineInstr &I,
|
|
CodeGenCoverage &CoverageInfo) const {
|
|
|
|
MachineBasicBlock &MBB = *I.getParent();
|
|
MachineFunction &MF = *MBB.getParent();
|
|
MachineRegisterInfo &MRI = MF.getRegInfo();
|
|
|
|
if (!isPreISelGenericOpcode(I.getOpcode())) {
|
|
if (I.isCopy())
|
|
return selectCopy(I, TII, MRI, TRI, RBI);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (selectImpl(I, CoverageInfo)) {
|
|
return true;
|
|
}
|
|
|
|
MachineInstr *MI = nullptr;
|
|
using namespace TargetOpcode;
|
|
|
|
switch (I.getOpcode()) {
|
|
case G_GEP: {
|
|
MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDu))
|
|
.add(I.getOperand(0))
|
|
.add(I.getOperand(1))
|
|
.add(I.getOperand(2));
|
|
break;
|
|
}
|
|
case G_FRAME_INDEX: {
|
|
MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
|
|
.add(I.getOperand(0))
|
|
.add(I.getOperand(1))
|
|
.addImm(0);
|
|
break;
|
|
}
|
|
case G_STORE:
|
|
case G_LOAD: {
|
|
const unsigned DestReg = I.getOperand(0).getReg();
|
|
const unsigned DestRegBank = RBI.getRegBank(DestReg, MRI, TRI)->getID();
|
|
const unsigned OpSize = MRI.getType(DestReg).getSizeInBits();
|
|
|
|
if (DestRegBank != Mips::GPRBRegBankID || OpSize != 32)
|
|
return false;
|
|
|
|
const unsigned NewOpc = I.getOpcode() == G_STORE ? Mips::SW : Mips::LW;
|
|
|
|
MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
|
|
.add(I.getOperand(0))
|
|
.add(I.getOperand(1))
|
|
.addImm(0)
|
|
.addMemOperand(*I.memoperands_begin());
|
|
break;
|
|
}
|
|
case G_CONSTANT: {
|
|
int Imm = I.getOperand(1).getCImm()->getValue().getLimitedValue();
|
|
unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
|
|
MachineInstr *LUi, *ORi;
|
|
|
|
LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
|
|
.addDef(LUiReg)
|
|
.addImm(Imm >> 16);
|
|
|
|
ORi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ORi))
|
|
.addDef(I.getOperand(0).getReg())
|
|
.addUse(LUiReg)
|
|
.addImm(Imm & 0xFFFF);
|
|
|
|
if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
|
|
return false;
|
|
if (!constrainSelectedInstRegOperands(*ORi, TII, TRI, RBI))
|
|
return false;
|
|
|
|
I.eraseFromParent();
|
|
return true;
|
|
}
|
|
case G_GLOBAL_VALUE: {
|
|
if (MF.getTarget().isPositionIndependent())
|
|
return false;
|
|
|
|
const llvm::GlobalValue *GVal = I.getOperand(1).getGlobal();
|
|
unsigned LUiReg = MRI.createVirtualRegister(&Mips::GPR32RegClass);
|
|
MachineInstr *LUi, *ADDiu;
|
|
|
|
LUi = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::LUi))
|
|
.addDef(LUiReg)
|
|
.addGlobalAddress(GVal);
|
|
LUi->getOperand(1).setTargetFlags(MipsII::MO_ABS_HI);
|
|
|
|
ADDiu = BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::ADDiu))
|
|
.addDef(I.getOperand(0).getReg())
|
|
.addUse(LUiReg)
|
|
.addGlobalAddress(GVal);
|
|
ADDiu->getOperand(2).setTargetFlags(MipsII::MO_ABS_LO);
|
|
|
|
if (!constrainSelectedInstRegOperands(*LUi, TII, TRI, RBI))
|
|
return false;
|
|
if (!constrainSelectedInstRegOperands(*ADDiu, TII, TRI, RBI))
|
|
return false;
|
|
|
|
I.eraseFromParent();
|
|
return true;
|
|
}
|
|
case G_ICMP: {
|
|
struct Instr {
|
|
unsigned Opcode, Def, LHS, RHS;
|
|
Instr(unsigned Opcode, unsigned Def, unsigned LHS, unsigned RHS)
|
|
: Opcode(Opcode), Def(Def), LHS(LHS), RHS(RHS){};
|
|
|
|
bool hasImm() const {
|
|
if (Opcode == Mips::SLTiu || Opcode == Mips::XORi)
|
|
return true;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
SmallVector<struct Instr, 2> Instructions;
|
|
unsigned ICMPReg = I.getOperand(0).getReg();
|
|
unsigned Temp = MRI.createVirtualRegister(&Mips::GPR32RegClass);
|
|
unsigned LHS = I.getOperand(2).getReg();
|
|
unsigned RHS = I.getOperand(3).getReg();
|
|
CmpInst::Predicate Cond =
|
|
static_cast<CmpInst::Predicate>(I.getOperand(1).getPredicate());
|
|
|
|
switch (Cond) {
|
|
case CmpInst::ICMP_EQ: // LHS == RHS -> (LHS ^ RHS) < 1
|
|
Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
|
|
Instructions.emplace_back(Mips::SLTiu, ICMPReg, Temp, 1);
|
|
break;
|
|
case CmpInst::ICMP_NE: // LHS != RHS -> 0 < (LHS ^ RHS)
|
|
Instructions.emplace_back(Mips::XOR, Temp, LHS, RHS);
|
|
Instructions.emplace_back(Mips::SLTu, ICMPReg, Mips::ZERO, Temp);
|
|
break;
|
|
case CmpInst::ICMP_UGT: // LHS > RHS -> RHS < LHS
|
|
Instructions.emplace_back(Mips::SLTu, ICMPReg, RHS, LHS);
|
|
break;
|
|
case CmpInst::ICMP_UGE: // LHS >= RHS -> !(LHS < RHS)
|
|
Instructions.emplace_back(Mips::SLTu, Temp, LHS, RHS);
|
|
Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
|
|
break;
|
|
case CmpInst::ICMP_ULT: // LHS < RHS -> LHS < RHS
|
|
Instructions.emplace_back(Mips::SLTu, ICMPReg, LHS, RHS);
|
|
break;
|
|
case CmpInst::ICMP_ULE: // LHS <= RHS -> !(RHS < LHS)
|
|
Instructions.emplace_back(Mips::SLTu, Temp, RHS, LHS);
|
|
Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
|
|
break;
|
|
case CmpInst::ICMP_SGT: // LHS > RHS -> RHS < LHS
|
|
Instructions.emplace_back(Mips::SLT, ICMPReg, RHS, LHS);
|
|
break;
|
|
case CmpInst::ICMP_SGE: // LHS >= RHS -> !(LHS < RHS)
|
|
Instructions.emplace_back(Mips::SLT, Temp, LHS, RHS);
|
|
Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
|
|
break;
|
|
case CmpInst::ICMP_SLT: // LHS < RHS -> LHS < RHS
|
|
Instructions.emplace_back(Mips::SLT, ICMPReg, LHS, RHS);
|
|
break;
|
|
case CmpInst::ICMP_SLE: // LHS <= RHS -> !(RHS < LHS)
|
|
Instructions.emplace_back(Mips::SLT, Temp, RHS, LHS);
|
|
Instructions.emplace_back(Mips::XORi, ICMPReg, Temp, 1);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
MachineIRBuilder B(I);
|
|
for (const struct Instr &Instruction : Instructions) {
|
|
MachineInstrBuilder MIB = B.buildInstr(
|
|
Instruction.Opcode, {Instruction.Def}, {Instruction.LHS});
|
|
|
|
if (Instruction.hasImm())
|
|
MIB.addImm(Instruction.RHS);
|
|
else
|
|
MIB.addUse(Instruction.RHS);
|
|
|
|
if (!MIB.constrainAllUses(TII, TRI, RBI))
|
|
return false;
|
|
}
|
|
|
|
I.eraseFromParent();
|
|
return true;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
I.eraseFromParent();
|
|
return constrainSelectedInstRegOperands(*MI, TII, TRI, RBI);
|
|
}
|
|
|
|
namespace llvm {
|
|
InstructionSelector *createMipsInstructionSelector(const MipsTargetMachine &TM,
|
|
MipsSubtarget &Subtarget,
|
|
MipsRegisterBankInfo &RBI) {
|
|
return new MipsInstructionSelector(TM, Subtarget, RBI);
|
|
}
|
|
} // end namespace llvm
|