llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
Daniel Sanders eacb2ec057 [mips] MIPS32R6 compact branch support
Summary:
MIPSR6 introduces a class of branches called compact branches. Unlike the
traditional MIPS branches which have a delay slot, compact branches do not
have a delay slot. The instruction following the compact branch is only
executed if the branch is not taken and must not be a branch.

It works by generating compact branches for MIPS32R6 when the delay slot
filler cannot fill a delay slot. Then, inspecting the generated code for
forbidden slot hazards (a compact branch with an adjacent branch or other
CTI) and inserting nops to clear this hazard.

Patch by Simon Dardis.

Reviewers: vkalintiris, dsanders

Subscribers: MatzeB, dsanders, llvm-commits

Differential Revision: http://reviews.llvm.org/D16353


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@263444 91177308-0d34-0410-b5e6-96231b3b80d8
2016-03-14 16:24:05 +00:00

727 lines
28 KiB
C++

//===-- MipsSEInstrInfo.cpp - Mips32/64 Instruction Information -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the Mips32/64 implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#include "MipsSEInstrInfo.h"
#include "MipsAnalyzeImmediate.h"
#include "InstPrinter/MipsInstPrinter.h"
#include "MipsMachineFunction.h"
#include "MipsTargetMachine.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
MipsSEInstrInfo::MipsSEInstrInfo(const MipsSubtarget &STI)
: MipsInstrInfo(STI, STI.getRelocationModel() == Reloc::PIC_ ? Mips::B
: Mips::J),
RI() {}
const MipsRegisterInfo &MipsSEInstrInfo::getRegisterInfo() const {
return RI;
}
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
unsigned MipsSEInstrInfo::isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
unsigned Opc = MI->getOpcode();
if ((Opc == Mips::LW) || (Opc == Mips::LD) ||
(Opc == Mips::LWC1) || (Opc == Mips::LDC1) || (Opc == Mips::LDC164)) {
if ((MI->getOperand(1).isFI()) && // is a stack slot
(MI->getOperand(2).isImm()) && // the imm is zero
(isZeroImm(MI->getOperand(2)))) {
FrameIndex = MI->getOperand(1).getIndex();
return MI->getOperand(0).getReg();
}
}
return 0;
}
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
unsigned MipsSEInstrInfo::isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const {
unsigned Opc = MI->getOpcode();
if ((Opc == Mips::SW) || (Opc == Mips::SD) ||
(Opc == Mips::SWC1) || (Opc == Mips::SDC1) || (Opc == Mips::SDC164)) {
if ((MI->getOperand(1).isFI()) && // is a stack slot
(MI->getOperand(2).isImm()) && // the imm is zero
(isZeroImm(MI->getOperand(2)))) {
FrameIndex = MI->getOperand(1).getIndex();
return MI->getOperand(0).getReg();
}
}
return 0;
}
void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, DebugLoc DL,
unsigned DestReg, unsigned SrcReg,
bool KillSrc) const {
unsigned Opc = 0, ZeroReg = 0;
bool isMicroMips = Subtarget.inMicroMipsMode();
if (Mips::GPR32RegClass.contains(DestReg)) { // Copy to CPU Reg.
if (Mips::GPR32RegClass.contains(SrcReg)) {
if (isMicroMips)
Opc = Mips::MOVE16_MM;
else
Opc = Mips::OR, ZeroReg = Mips::ZERO;
} else if (Mips::CCRRegClass.contains(SrcReg))
Opc = Mips::CFC1;
else if (Mips::FGR32RegClass.contains(SrcReg))
Opc = Mips::MFC1;
else if (Mips::HI32RegClass.contains(SrcReg)) {
Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI;
SrcReg = 0;
} else if (Mips::LO32RegClass.contains(SrcReg)) {
Opc = isMicroMips ? Mips::MFLO16_MM : Mips::MFLO;
SrcReg = 0;
} else if (Mips::HI32DSPRegClass.contains(SrcReg))
Opc = Mips::MFHI_DSP;
else if (Mips::LO32DSPRegClass.contains(SrcReg))
Opc = Mips::MFLO_DSP;
else if (Mips::DSPCCRegClass.contains(SrcReg)) {
BuildMI(MBB, I, DL, get(Mips::RDDSP), DestReg).addImm(1 << 4)
.addReg(SrcReg, RegState::Implicit | getKillRegState(KillSrc));
return;
}
else if (Mips::MSACtrlRegClass.contains(SrcReg))
Opc = Mips::CFCMSA;
}
else if (Mips::GPR32RegClass.contains(SrcReg)) { // Copy from CPU Reg.
if (Mips::CCRRegClass.contains(DestReg))
Opc = Mips::CTC1;
else if (Mips::FGR32RegClass.contains(DestReg))
Opc = Mips::MTC1;
else if (Mips::HI32RegClass.contains(DestReg))
Opc = Mips::MTHI, DestReg = 0;
else if (Mips::LO32RegClass.contains(DestReg))
Opc = Mips::MTLO, DestReg = 0;
else if (Mips::HI32DSPRegClass.contains(DestReg))
Opc = Mips::MTHI_DSP;
else if (Mips::LO32DSPRegClass.contains(DestReg))
Opc = Mips::MTLO_DSP;
else if (Mips::DSPCCRegClass.contains(DestReg)) {
BuildMI(MBB, I, DL, get(Mips::WRDSP))
.addReg(SrcReg, getKillRegState(KillSrc)).addImm(1 << 4)
.addReg(DestReg, RegState::ImplicitDefine);
return;
}
else if (Mips::MSACtrlRegClass.contains(DestReg))
Opc = Mips::CTCMSA;
}
else if (Mips::FGR32RegClass.contains(DestReg, SrcReg))
Opc = Mips::FMOV_S;
else if (Mips::AFGR64RegClass.contains(DestReg, SrcReg))
Opc = Mips::FMOV_D32;
else if (Mips::FGR64RegClass.contains(DestReg, SrcReg))
Opc = Mips::FMOV_D64;
else if (Mips::GPR64RegClass.contains(DestReg)) { // Copy to CPU64 Reg.
if (Mips::GPR64RegClass.contains(SrcReg))
Opc = Mips::OR64, ZeroReg = Mips::ZERO_64;
else if (Mips::HI64RegClass.contains(SrcReg))
Opc = Mips::MFHI64, SrcReg = 0;
else if (Mips::LO64RegClass.contains(SrcReg))
Opc = Mips::MFLO64, SrcReg = 0;
else if (Mips::FGR64RegClass.contains(SrcReg))
Opc = Mips::DMFC1;
}
else if (Mips::GPR64RegClass.contains(SrcReg)) { // Copy from CPU64 Reg.
if (Mips::HI64RegClass.contains(DestReg))
Opc = Mips::MTHI64, DestReg = 0;
else if (Mips::LO64RegClass.contains(DestReg))
Opc = Mips::MTLO64, DestReg = 0;
else if (Mips::FGR64RegClass.contains(DestReg))
Opc = Mips::DMTC1;
}
else if (Mips::MSA128BRegClass.contains(DestReg)) { // Copy to MSA reg
if (Mips::MSA128BRegClass.contains(SrcReg))
Opc = Mips::MOVE_V;
}
assert(Opc && "Cannot copy registers");
MachineInstrBuilder MIB = BuildMI(MBB, I, DL, get(Opc));
if (DestReg)
MIB.addReg(DestReg, RegState::Define);
if (SrcReg)
MIB.addReg(SrcReg, getKillRegState(KillSrc));
if (ZeroReg)
MIB.addReg(ZeroReg);
}
void MipsSEInstrInfo::
storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned SrcReg, bool isKill, int FI,
const TargetRegisterClass *RC, const TargetRegisterInfo *TRI,
int64_t Offset) const {
DebugLoc DL;
MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOStore);
unsigned Opc = 0;
if (Mips::GPR32RegClass.hasSubClassEq(RC))
Opc = Mips::SW;
else if (Mips::GPR64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
else if (Mips::ACC64RegClass.hasSubClassEq(RC))
Opc = Mips::STORE_ACC64;
else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC))
Opc = Mips::STORE_ACC64DSP;
else if (Mips::ACC128RegClass.hasSubClassEq(RC))
Opc = Mips::STORE_ACC128;
else if (Mips::DSPCCRegClass.hasSubClassEq(RC))
Opc = Mips::STORE_CCOND_DSP;
else if (Mips::FGR32RegClass.hasSubClassEq(RC))
Opc = Mips::SWC1;
else if (Mips::AFGR64RegClass.hasSubClassEq(RC))
Opc = Mips::SDC1;
else if (Mips::FGR64RegClass.hasSubClassEq(RC))
Opc = Mips::SDC164;
else if (RC->hasType(MVT::v16i8))
Opc = Mips::ST_B;
else if (RC->hasType(MVT::v8i16) || RC->hasType(MVT::v8f16))
Opc = Mips::ST_H;
else if (RC->hasType(MVT::v4i32) || RC->hasType(MVT::v4f32))
Opc = Mips::ST_W;
else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64))
Opc = Mips::ST_D;
else if (Mips::LO32RegClass.hasSubClassEq(RC))
Opc = Mips::SW;
else if (Mips::LO64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
else if (Mips::HI32RegClass.hasSubClassEq(RC))
Opc = Mips::SW;
else if (Mips::HI64RegClass.hasSubClassEq(RC))
Opc = Mips::SD;
// Hi, Lo are normally caller save but they are callee save
// for interrupt handling.
const Function *Func = MBB.getParent()->getFunction();
if (Func->hasFnAttribute("interrupt")) {
if (Mips::HI32RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFHI), Mips::K0);
SrcReg = Mips::K0;
} else if (Mips::HI64RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFHI64), Mips::K0_64);
SrcReg = Mips::K0_64;
} else if (Mips::LO32RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFLO), Mips::K0);
SrcReg = Mips::K0;
} else if (Mips::LO64RegClass.hasSubClassEq(RC)) {
BuildMI(MBB, I, DL, get(Mips::MFLO64), Mips::K0_64);
SrcReg = Mips::K0_64;
}
}
assert(Opc && "Register class not handled!");
BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill))
.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO);
}
void MipsSEInstrInfo::
loadRegFromStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
unsigned DestReg, int FI, const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI, int64_t Offset) const {
DebugLoc DL;
if (I != MBB.end()) DL = I->getDebugLoc();
MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad);
unsigned Opc = 0;
const Function *Func = MBB.getParent()->getFunction();
bool ReqIndirectLoad = Func->hasFnAttribute("interrupt") &&
(DestReg == Mips::LO0 || DestReg == Mips::LO0_64 ||
DestReg == Mips::HI0 || DestReg == Mips::HI0_64);
if (Mips::GPR32RegClass.hasSubClassEq(RC))
Opc = Mips::LW;
else if (Mips::GPR64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
else if (Mips::ACC64RegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_ACC64;
else if (Mips::ACC64DSPRegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_ACC64DSP;
else if (Mips::ACC128RegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_ACC128;
else if (Mips::DSPCCRegClass.hasSubClassEq(RC))
Opc = Mips::LOAD_CCOND_DSP;
else if (Mips::FGR32RegClass.hasSubClassEq(RC))
Opc = Mips::LWC1;
else if (Mips::AFGR64RegClass.hasSubClassEq(RC))
Opc = Mips::LDC1;
else if (Mips::FGR64RegClass.hasSubClassEq(RC))
Opc = Mips::LDC164;
else if (RC->hasType(MVT::v16i8))
Opc = Mips::LD_B;
else if (RC->hasType(MVT::v8i16) || RC->hasType(MVT::v8f16))
Opc = Mips::LD_H;
else if (RC->hasType(MVT::v4i32) || RC->hasType(MVT::v4f32))
Opc = Mips::LD_W;
else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64))
Opc = Mips::LD_D;
else if (Mips::HI32RegClass.hasSubClassEq(RC))
Opc = Mips::LW;
else if (Mips::HI64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
else if (Mips::LO32RegClass.hasSubClassEq(RC))
Opc = Mips::LW;
else if (Mips::LO64RegClass.hasSubClassEq(RC))
Opc = Mips::LD;
assert(Opc && "Register class not handled!");
if (!ReqIndirectLoad)
BuildMI(MBB, I, DL, get(Opc), DestReg)
.addFrameIndex(FI)
.addImm(Offset)
.addMemOperand(MMO);
else {
// Load HI/LO through K0. Notably the DestReg is encoded into the
// instruction itself.
unsigned Reg = Mips::K0;
unsigned LdOp = Mips::MTLO;
if (DestReg == Mips::HI0)
LdOp = Mips::MTHI;
if (Subtarget.getABI().ArePtrs64bit()) {
Reg = Mips::K0_64;
if (DestReg == Mips::HI0_64)
LdOp = Mips::MTHI64;
else
LdOp = Mips::MTLO64;
}
BuildMI(MBB, I, DL, get(Opc), Reg)
.addFrameIndex(FI)
.addImm(Offset)
.addMemOperand(MMO);
BuildMI(MBB, I, DL, get(LdOp)).addReg(Reg);
}
}
bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
MachineBasicBlock &MBB = *MI->getParent();
bool isMicroMips = Subtarget.inMicroMipsMode();
unsigned Opc;
switch(MI->getDesc().getOpcode()) {
default:
return false;
case Mips::RetRA:
expandRetRA(MBB, MI);
break;
case Mips::ERet:
expandERet(MBB, MI);
break;
case Mips::PseudoMFHI:
Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI;
expandPseudoMFHiLo(MBB, MI, Opc);
break;
case Mips::PseudoMFLO:
Opc = isMicroMips ? Mips::MFLO16_MM : Mips::MFLO;
expandPseudoMFHiLo(MBB, MI, Opc);
break;
case Mips::PseudoMFHI64:
expandPseudoMFHiLo(MBB, MI, Mips::MFHI64);
break;
case Mips::PseudoMFLO64:
expandPseudoMFHiLo(MBB, MI, Mips::MFLO64);
break;
case Mips::PseudoMTLOHI:
expandPseudoMTLoHi(MBB, MI, Mips::MTLO, Mips::MTHI, false);
break;
case Mips::PseudoMTLOHI64:
expandPseudoMTLoHi(MBB, MI, Mips::MTLO64, Mips::MTHI64, false);
break;
case Mips::PseudoMTLOHI_DSP:
expandPseudoMTLoHi(MBB, MI, Mips::MTLO_DSP, Mips::MTHI_DSP, true);
break;
case Mips::PseudoCVT_S_W:
expandCvtFPInt(MBB, MI, Mips::CVT_S_W, Mips::MTC1, false);
break;
case Mips::PseudoCVT_D32_W:
expandCvtFPInt(MBB, MI, Mips::CVT_D32_W, Mips::MTC1, false);
break;
case Mips::PseudoCVT_S_L:
expandCvtFPInt(MBB, MI, Mips::CVT_S_L, Mips::DMTC1, true);
break;
case Mips::PseudoCVT_D64_W:
expandCvtFPInt(MBB, MI, Mips::CVT_D64_W, Mips::MTC1, true);
break;
case Mips::PseudoCVT_D64_L:
expandCvtFPInt(MBB, MI, Mips::CVT_D64_L, Mips::DMTC1, true);
break;
case Mips::BuildPairF64:
expandBuildPairF64(MBB, MI, false);
break;
case Mips::BuildPairF64_64:
expandBuildPairF64(MBB, MI, true);
break;
case Mips::ExtractElementF64:
expandExtractElementF64(MBB, MI, false);
break;
case Mips::ExtractElementF64_64:
expandExtractElementF64(MBB, MI, true);
break;
case Mips::MIPSeh_return32:
case Mips::MIPSeh_return64:
expandEhReturn(MBB, MI);
break;
}
MBB.erase(MI);
return true;
}
/// getOppositeBranchOpc - Return the inverse of the specified
/// opcode, e.g. turning BEQ to BNE.
unsigned MipsSEInstrInfo::getOppositeBranchOpc(unsigned Opc) const {
switch (Opc) {
default: llvm_unreachable("Illegal opcode!");
case Mips::BEQ: return Mips::BNE;
case Mips::BNE: return Mips::BEQ;
case Mips::BGTZ: return Mips::BLEZ;
case Mips::BGEZ: return Mips::BLTZ;
case Mips::BLTZ: return Mips::BGEZ;
case Mips::BLEZ: return Mips::BGTZ;
case Mips::BEQ64: return Mips::BNE64;
case Mips::BNE64: return Mips::BEQ64;
case Mips::BGTZ64: return Mips::BLEZ64;
case Mips::BGEZ64: return Mips::BLTZ64;
case Mips::BLTZ64: return Mips::BGEZ64;
case Mips::BLEZ64: return Mips::BGTZ64;
case Mips::BC1T: return Mips::BC1F;
case Mips::BC1F: return Mips::BC1T;
case Mips::BEQZC_MM: return Mips::BNEZC_MM;
case Mips::BNEZC_MM: return Mips::BEQZC_MM;
case Mips::BEQZC: return Mips::BNEZC;
case Mips::BNEZC: return Mips::BEQZC;
case Mips::BEQC: return Mips::BNEC;
case Mips::BNEC: return Mips::BEQC;
case Mips::BGTZC: return Mips::BLEZC;
case Mips::BGEZC: return Mips::BLTZC;
case Mips::BLTZC: return Mips::BGEZC;
case Mips::BLEZC: return Mips::BGTZC;
}
}
/// Adjust SP by Amount bytes.
void MipsSEInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
MipsABIInfo ABI = Subtarget.getABI();
DebugLoc DL;
unsigned ADDu = ABI.GetPtrAdduOp();
unsigned ADDiu = ABI.GetPtrAddiuOp();
if (Amount == 0)
return;
if (isInt<16>(Amount))// addi sp, sp, amount
BuildMI(MBB, I, DL, get(ADDiu), SP).addReg(SP).addImm(Amount);
else { // Expand immediate that doesn't fit in 16-bit.
unsigned Reg = loadImmediate(Amount, MBB, I, DL, nullptr);
BuildMI(MBB, I, DL, get(ADDu), SP).addReg(SP).addReg(Reg, RegState::Kill);
}
}
/// This function generates the sequence of instructions needed to get the
/// result of adding register REG and immediate IMM.
unsigned
MipsSEInstrInfo::loadImmediate(int64_t Imm, MachineBasicBlock &MBB,
MachineBasicBlock::iterator II, DebugLoc DL,
unsigned *NewImm) const {
MipsAnalyzeImmediate AnalyzeImm;
const MipsSubtarget &STI = Subtarget;
MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
unsigned Size = STI.isABI_N64() ? 64 : 32;
unsigned LUi = STI.isABI_N64() ? Mips::LUi64 : Mips::LUi;
unsigned ZEROReg = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO;
const TargetRegisterClass *RC = STI.isABI_N64() ?
&Mips::GPR64RegClass : &Mips::GPR32RegClass;
bool LastInstrIsADDiu = NewImm;
const MipsAnalyzeImmediate::InstSeq &Seq =
AnalyzeImm.Analyze(Imm, Size, LastInstrIsADDiu);
MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin();
assert(Seq.size() && (!LastInstrIsADDiu || (Seq.size() > 1)));
// The first instruction can be a LUi, which is different from other
// instructions (ADDiu, ORI and SLL) in that it does not have a register
// operand.
unsigned Reg = RegInfo.createVirtualRegister(RC);
if (Inst->Opc == LUi)
BuildMI(MBB, II, DL, get(LUi), Reg).addImm(SignExtend64<16>(Inst->ImmOpnd));
else
BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(ZEROReg)
.addImm(SignExtend64<16>(Inst->ImmOpnd));
// Build the remaining instructions in Seq.
for (++Inst; Inst != Seq.end() - LastInstrIsADDiu; ++Inst)
BuildMI(MBB, II, DL, get(Inst->Opc), Reg).addReg(Reg, RegState::Kill)
.addImm(SignExtend64<16>(Inst->ImmOpnd));
if (LastInstrIsADDiu)
*NewImm = Inst->ImmOpnd;
return Reg;
}
unsigned MipsSEInstrInfo::getAnalyzableBrOpc(unsigned Opc) const {
return (Opc == Mips::BEQ || Opc == Mips::BNE || Opc == Mips::BGTZ ||
Opc == Mips::BGEZ || Opc == Mips::BLTZ || Opc == Mips::BLEZ ||
Opc == Mips::BEQ64 || Opc == Mips::BNE64 || Opc == Mips::BGTZ64 ||
Opc == Mips::BGEZ64 || Opc == Mips::BLTZ64 || Opc == Mips::BLEZ64 ||
Opc == Mips::BC1T || Opc == Mips::BC1F || Opc == Mips::B ||
Opc == Mips::J || Opc == Mips::BEQZC_MM || Opc == Mips::BNEZC_MM ||
Opc == Mips::BEQC || Opc == Mips::BNEC || Opc == Mips::BLTC ||
Opc == Mips::BGEC || Opc == Mips::BLTUC || Opc == Mips::BGEUC ||
Opc == Mips::BGTZC || Opc == Mips::BLEZC || Opc == Mips::BGEZC ||
Opc == Mips::BGTZC || Opc == Mips::BEQZC || Opc == Mips::BNEZC ||
Opc == Mips::BC) ? Opc : 0;
}
void MipsSEInstrInfo::expandRetRA(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
if (Subtarget.isGP64bit())
BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn64))
.addReg(Mips::RA_64);
else
BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn)).addReg(Mips::RA);
}
void MipsSEInstrInfo::expandERet(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
BuildMI(MBB, I, I->getDebugLoc(), get(Mips::ERET));
}
std::pair<bool, bool>
MipsSEInstrInfo::compareOpndSize(unsigned Opc,
const MachineFunction &MF) const {
const MCInstrDesc &Desc = get(Opc);
assert(Desc.NumOperands == 2 && "Unary instruction expected.");
const MipsRegisterInfo *RI = &getRegisterInfo();
unsigned DstRegSize = getRegClass(Desc, 0, RI, MF)->getSize();
unsigned SrcRegSize = getRegClass(Desc, 1, RI, MF)->getSize();
return std::make_pair(DstRegSize > SrcRegSize, DstRegSize < SrcRegSize);
}
void MipsSEInstrInfo::expandPseudoMFHiLo(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned NewOpc) const {
BuildMI(MBB, I, I->getDebugLoc(), get(NewOpc), I->getOperand(0).getReg());
}
void MipsSEInstrInfo::expandPseudoMTLoHi(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned LoOpc,
unsigned HiOpc,
bool HasExplicitDef) const {
// Expand
// lo_hi pseudomtlohi $gpr0, $gpr1
// to these two instructions:
// mtlo $gpr0
// mthi $gpr1
DebugLoc DL = I->getDebugLoc();
const MachineOperand &SrcLo = I->getOperand(1), &SrcHi = I->getOperand(2);
MachineInstrBuilder LoInst = BuildMI(MBB, I, DL, get(LoOpc));
MachineInstrBuilder HiInst = BuildMI(MBB, I, DL, get(HiOpc));
// Add lo/hi registers if the mtlo/hi instructions created have explicit
// def registers.
if (HasExplicitDef) {
unsigned DstReg = I->getOperand(0).getReg();
unsigned DstLo = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo);
unsigned DstHi = getRegisterInfo().getSubReg(DstReg, Mips::sub_hi);
LoInst.addReg(DstLo, RegState::Define);
HiInst.addReg(DstHi, RegState::Define);
}
LoInst.addReg(SrcLo.getReg(), getKillRegState(SrcLo.isKill()));
HiInst.addReg(SrcHi.getReg(), getKillRegState(SrcHi.isKill()));
}
void MipsSEInstrInfo::expandCvtFPInt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
unsigned CvtOpc, unsigned MovOpc,
bool IsI64) const {
const MCInstrDesc &CvtDesc = get(CvtOpc), &MovDesc = get(MovOpc);
const MachineOperand &Dst = I->getOperand(0), &Src = I->getOperand(1);
unsigned DstReg = Dst.getReg(), SrcReg = Src.getReg(), TmpReg = DstReg;
unsigned KillSrc = getKillRegState(Src.isKill());
DebugLoc DL = I->getDebugLoc();
bool DstIsLarger, SrcIsLarger;
std::tie(DstIsLarger, SrcIsLarger) =
compareOpndSize(CvtOpc, *MBB.getParent());
if (DstIsLarger)
TmpReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo);
if (SrcIsLarger)
DstReg = getRegisterInfo().getSubReg(DstReg, Mips::sub_lo);
BuildMI(MBB, I, DL, MovDesc, TmpReg).addReg(SrcReg, KillSrc);
BuildMI(MBB, I, DL, CvtDesc, DstReg).addReg(TmpReg, RegState::Kill);
}
void MipsSEInstrInfo::expandExtractElementF64(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
bool FP64) const {
unsigned DstReg = I->getOperand(0).getReg();
unsigned SrcReg = I->getOperand(1).getReg();
unsigned N = I->getOperand(2).getImm();
DebugLoc dl = I->getDebugLoc();
assert(N < 2 && "Invalid immediate");
unsigned SubIdx = N ? Mips::sub_hi : Mips::sub_lo;
unsigned SubReg = getRegisterInfo().getSubReg(SrcReg, SubIdx);
// FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2()));
// FP64A (FP64 with nooddspreg) should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg()));
if (SubIdx == Mips::sub_hi && Subtarget.hasMTHC1()) {
// FIXME: Strictly speaking MFHC1 only reads the top 32-bits however, we
// claim to read the whole 64-bits as part of a white lie used to
// temporarily work around a widespread bug in the -mfp64 support.
// The problem is that none of the 32-bit fpu ops mention the fact
// that they clobber the upper 32-bits of the 64-bit FPR. Fixing that
// requires a major overhaul of the FPU implementation which can't
// be done right now due to time constraints.
// MFHC1 is one of two instructions that are affected since they are
// the only instructions that don't read the lower 32-bits.
// We therefore pretend that it reads the bottom 32-bits to
// artificially create a dependency and prevent the scheduler
// changing the behaviour of the code.
BuildMI(MBB, I, dl, get(FP64 ? Mips::MFHC1_D64 : Mips::MFHC1_D32), DstReg)
.addReg(SrcReg);
} else
BuildMI(MBB, I, dl, get(Mips::MFC1), DstReg).addReg(SubReg);
}
void MipsSEInstrInfo::expandBuildPairF64(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I,
bool FP64) const {
unsigned DstReg = I->getOperand(0).getReg();
unsigned LoReg = I->getOperand(1).getReg(), HiReg = I->getOperand(2).getReg();
const MCInstrDesc& Mtc1Tdd = get(Mips::MTC1);
DebugLoc dl = I->getDebugLoc();
const TargetRegisterInfo &TRI = getRegisterInfo();
// When mthc1 is available, use:
// mtc1 Lo, $fp
// mthc1 Hi, $fp
//
// Otherwise, for O32 FPXX ABI:
// spill + reload via ldc1
// This case is handled by the frame lowering code.
//
// Otherwise, for FP32:
// mtc1 Lo, $fp
// mtc1 Hi, $fp + 1
//
// The case where dmtc1 is available doesn't need to be handled here
// because it never creates a BuildPairF64 node.
// FPXX on MIPS-II or MIPS32r1 should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isABI_FPXX() && !Subtarget.hasMips32r2()));
// FP64A (FP64 with nooddspreg) should have been handled with a spill/reload
// in MipsSEFrameLowering.cpp.
assert(!(Subtarget.isFP64bit() && !Subtarget.useOddSPReg()));
BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_lo))
.addReg(LoReg);
if (Subtarget.hasMTHC1()) {
// FIXME: The .addReg(DstReg) is a white lie used to temporarily work
// around a widespread bug in the -mfp64 support.
// The problem is that none of the 32-bit fpu ops mention the fact
// that they clobber the upper 32-bits of the 64-bit FPR. Fixing that
// requires a major overhaul of the FPU implementation which can't
// be done right now due to time constraints.
// MTHC1 is one of two instructions that are affected since they are
// the only instructions that don't read the lower 32-bits.
// We therefore pretend that it reads the bottom 32-bits to
// artificially create a dependency and prevent the scheduler
// changing the behaviour of the code.
BuildMI(MBB, I, dl, get(FP64 ? Mips::MTHC1_D64 : Mips::MTHC1_D32), DstReg)
.addReg(DstReg)
.addReg(HiReg);
} else if (Subtarget.isABI_FPXX())
llvm_unreachable("BuildPairF64 not expanded in frame lowering code!");
else
BuildMI(MBB, I, dl, Mtc1Tdd, TRI.getSubReg(DstReg, Mips::sub_hi))
.addReg(HiReg);
}
void MipsSEInstrInfo::expandEhReturn(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
// This pseudo instruction is generated as part of the lowering of
// ISD::EH_RETURN. We convert it to a stack increment by OffsetReg, and
// indirect jump to TargetReg
MipsABIInfo ABI = Subtarget.getABI();
unsigned ADDU = ABI.GetPtrAdduOp();
unsigned SP = Subtarget.isGP64bit() ? Mips::SP_64 : Mips::SP;
unsigned RA = Subtarget.isGP64bit() ? Mips::RA_64 : Mips::RA;
unsigned T9 = Subtarget.isGP64bit() ? Mips::T9_64 : Mips::T9;
unsigned ZERO = Subtarget.isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
unsigned OffsetReg = I->getOperand(0).getReg();
unsigned TargetReg = I->getOperand(1).getReg();
// addu $ra, $v0, $zero
// addu $sp, $sp, $v1
// jr $ra (via RetRA)
const TargetMachine &TM = MBB.getParent()->getTarget();
if (TM.getRelocationModel() == Reloc::PIC_)
BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), T9)
.addReg(TargetReg)
.addReg(ZERO);
BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), RA)
.addReg(TargetReg)
.addReg(ZERO);
BuildMI(MBB, I, I->getDebugLoc(), get(ADDU), SP).addReg(SP).addReg(OffsetReg);
expandRetRA(MBB, I);
}
const MipsInstrInfo *llvm::createMipsSEInstrInfo(const MipsSubtarget &STI) {
return new MipsSEInstrInfo(STI);
}