llvm-6502/lib/Target/Mips/Mips16ISelLowering.cpp
Reed Kotler 46090914b7 Checkin in of first of several patches to finish implementation of
mips16/mips32 floating point interoperability. 

This patch fixes returns from mips16 functions so that if the function
was in fact called by a mips32 hard float routine, then values
that would have been returned in floating point registers are so returned.

Mips16 mode has no floating point instructions so there is no way to
load values into floating point registers.

This is needed when returning float, double, single complex, double complex
in the Mips ABI.

Helper functions in libc for mips16 are available to do this.

For efficiency purposes, these helper functions have a different calling
convention from normal Mips calls.

Registers v0,v1,a0,a1 are used to pass parameters instead of
a0,a1,a2,a3.

This is because v0,v1,a0,a1 are the natural registers used to return
floating point values in soft float. These values can then be moved
to the appropriate floating point registers with no extra cost.

The only register that is modified is ra in this call.

The helper functions make sure that the return values are in the floating
point registers that they would be in if soft float was not in effect
(which it is for mips16, though the soft float is implemented using a mips32
library that uses hard float).
 


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181641 91177308-0d34-0410-b5e6-96231b3b80d8
2013-05-10 22:25:39 +00:00

688 lines
25 KiB
C++

//===-- Mips16ISelLowering.h - Mips16 DAG Lowering Interface ----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Subclass of MipsTargetLowering specialized for mips16.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-lower"
#include "Mips16ISelLowering.h"
#include "MipsRegisterInfo.h"
#include "MipsTargetMachine.h"
#include "MCTargetDesc/MipsBaseInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include <set>
using namespace llvm;
static cl::opt<bool> DontExpandCondPseudos16(
"mips16-dont-expand-cond-pseudo",
cl::init(false),
cl::desc("Dont expand conditional move related "
"pseudos for Mips 16"),
cl::Hidden);
namespace {
std::set<const char*, MipsTargetLowering::LTStr> NoHelperNeeded;
}
Mips16TargetLowering::Mips16TargetLowering(MipsTargetMachine &TM)
: MipsTargetLowering(TM) {
//
// set up as if mips32 and then revert so we can test the mechanism
// for switching
addRegisterClass(MVT::i32, &Mips::CPURegsRegClass);
addRegisterClass(MVT::f32, &Mips::FGR32RegClass);
computeRegisterProperties();
clearRegisterClasses();
// Set up the register classes
addRegisterClass(MVT::i32, &Mips::CPU16RegsRegClass);
if (Subtarget->inMips16HardFloat())
setMips16HardFloatLibCalls();
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand);
setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand);
setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand);
computeRegisterProperties();
}
const MipsTargetLowering *
llvm::createMips16TargetLowering(MipsTargetMachine &TM) {
return new Mips16TargetLowering(TM);
}
bool
Mips16TargetLowering::allowsUnalignedMemoryAccesses(EVT VT, bool *Fast) const {
return false;
}
MachineBasicBlock *
Mips16TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
MachineBasicBlock *BB) const {
switch (MI->getOpcode()) {
default:
return MipsTargetLowering::EmitInstrWithCustomInserter(MI, BB);
case Mips::SelBeqZ:
return emitSel16(Mips::BeqzRxImm16, MI, BB);
case Mips::SelBneZ:
return emitSel16(Mips::BnezRxImm16, MI, BB);
case Mips::SelTBteqZCmpi:
return emitSeliT16(Mips::BteqzX16, Mips::CmpiRxImmX16, MI, BB);
case Mips::SelTBteqZSlti:
return emitSeliT16(Mips::BteqzX16, Mips::SltiRxImmX16, MI, BB);
case Mips::SelTBteqZSltiu:
return emitSeliT16(Mips::BteqzX16, Mips::SltiuRxImmX16, MI, BB);
case Mips::SelTBtneZCmpi:
return emitSeliT16(Mips::BtnezX16, Mips::CmpiRxImmX16, MI, BB);
case Mips::SelTBtneZSlti:
return emitSeliT16(Mips::BtnezX16, Mips::SltiRxImmX16, MI, BB);
case Mips::SelTBtneZSltiu:
return emitSeliT16(Mips::BtnezX16, Mips::SltiuRxImmX16, MI, BB);
case Mips::SelTBteqZCmp:
return emitSelT16(Mips::BteqzX16, Mips::CmpRxRy16, MI, BB);
case Mips::SelTBteqZSlt:
return emitSelT16(Mips::BteqzX16, Mips::SltRxRy16, MI, BB);
case Mips::SelTBteqZSltu:
return emitSelT16(Mips::BteqzX16, Mips::SltuRxRy16, MI, BB);
case Mips::SelTBtneZCmp:
return emitSelT16(Mips::BtnezX16, Mips::CmpRxRy16, MI, BB);
case Mips::SelTBtneZSlt:
return emitSelT16(Mips::BtnezX16, Mips::SltRxRy16, MI, BB);
case Mips::SelTBtneZSltu:
return emitSelT16(Mips::BtnezX16, Mips::SltuRxRy16, MI, BB);
case Mips::BteqzT8CmpX16:
return emitFEXT_T8I816_ins(Mips::BteqzX16, Mips::CmpRxRy16, MI, BB);
case Mips::BteqzT8SltX16:
return emitFEXT_T8I816_ins(Mips::BteqzX16, Mips::SltRxRy16, MI, BB);
case Mips::BteqzT8SltuX16:
// TBD: figure out a way to get this or remove the instruction
// altogether.
return emitFEXT_T8I816_ins(Mips::BteqzX16, Mips::SltuRxRy16, MI, BB);
case Mips::BtnezT8CmpX16:
return emitFEXT_T8I816_ins(Mips::BtnezX16, Mips::CmpRxRy16, MI, BB);
case Mips::BtnezT8SltX16:
return emitFEXT_T8I816_ins(Mips::BtnezX16, Mips::SltRxRy16, MI, BB);
case Mips::BtnezT8SltuX16:
// TBD: figure out a way to get this or remove the instruction
// altogether.
return emitFEXT_T8I816_ins(Mips::BtnezX16, Mips::SltuRxRy16, MI, BB);
case Mips::BteqzT8CmpiX16: return emitFEXT_T8I8I16_ins(
Mips::BteqzX16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, MI, BB);
case Mips::BteqzT8SltiX16: return emitFEXT_T8I8I16_ins(
Mips::BteqzX16, Mips::SltiRxImm16, Mips::SltiRxImmX16, MI, BB);
case Mips::BteqzT8SltiuX16: return emitFEXT_T8I8I16_ins(
Mips::BteqzX16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, MI, BB);
case Mips::BtnezT8CmpiX16: return emitFEXT_T8I8I16_ins(
Mips::BtnezX16, Mips::CmpiRxImm16, Mips::CmpiRxImmX16, MI, BB);
case Mips::BtnezT8SltiX16: return emitFEXT_T8I8I16_ins(
Mips::BtnezX16, Mips::SltiRxImm16, Mips::SltiRxImmX16, MI, BB);
case Mips::BtnezT8SltiuX16: return emitFEXT_T8I8I16_ins(
Mips::BtnezX16, Mips::SltiuRxImm16, Mips::SltiuRxImmX16, MI, BB);
break;
case Mips::SltCCRxRy16:
return emitFEXT_CCRX16_ins(Mips::SltRxRy16, MI, BB);
break;
case Mips::SltiCCRxImmX16:
return emitFEXT_CCRXI16_ins
(Mips::SltiRxImm16, Mips::SltiRxImmX16, MI, BB);
case Mips::SltiuCCRxImmX16:
return emitFEXT_CCRXI16_ins
(Mips::SltiuRxImm16, Mips::SltiuRxImmX16, MI, BB);
case Mips::SltuCCRxRy16:
return emitFEXT_CCRX16_ins
(Mips::SltuRxRy16, MI, BB);
}
}
bool Mips16TargetLowering::
isEligibleForTailCallOptimization(const MipsCC &MipsCCInfo,
unsigned NextStackOffset,
const MipsFunctionInfo& FI) const {
// No tail call optimization for mips16.
return false;
}
void Mips16TargetLowering::setMips16LibcallName
(RTLIB::Libcall L, const char *Name) {
setLibcallName(L, Name);
NoHelperNeeded.insert(Name);
}
void Mips16TargetLowering::setMips16HardFloatLibCalls() {
setMips16LibcallName(RTLIB::ADD_F32, "__mips16_addsf3");
setMips16LibcallName(RTLIB::ADD_F64, "__mips16_adddf3");
setMips16LibcallName(RTLIB::SUB_F32, "__mips16_subsf3");
setMips16LibcallName(RTLIB::SUB_F64, "__mips16_subdf3");
setMips16LibcallName(RTLIB::MUL_F32, "__mips16_mulsf3");
setMips16LibcallName(RTLIB::MUL_F64, "__mips16_muldf3");
setMips16LibcallName(RTLIB::DIV_F32, "__mips16_divsf3");
setMips16LibcallName(RTLIB::DIV_F64, "__mips16_divdf3");
setMips16LibcallName(RTLIB::FPEXT_F32_F64, "__mips16_extendsfdf2");
setMips16LibcallName(RTLIB::FPROUND_F64_F32, "__mips16_truncdfsf2");
setMips16LibcallName(RTLIB::FPTOSINT_F32_I32, "__mips16_fix_truncsfsi");
setMips16LibcallName(RTLIB::FPTOSINT_F64_I32, "__mips16_fix_truncdfsi");
setMips16LibcallName(RTLIB::SINTTOFP_I32_F32, "__mips16_floatsisf");
setMips16LibcallName(RTLIB::SINTTOFP_I32_F64, "__mips16_floatsidf");
setMips16LibcallName(RTLIB::UINTTOFP_I32_F32, "__mips16_floatunsisf");
setMips16LibcallName(RTLIB::UINTTOFP_I32_F64, "__mips16_floatunsidf");
setMips16LibcallName(RTLIB::OEQ_F32, "__mips16_eqsf2");
setMips16LibcallName(RTLIB::OEQ_F64, "__mips16_eqdf2");
setMips16LibcallName(RTLIB::UNE_F32, "__mips16_nesf2");
setMips16LibcallName(RTLIB::UNE_F64, "__mips16_nedf2");
setMips16LibcallName(RTLIB::OGE_F32, "__mips16_gesf2");
setMips16LibcallName(RTLIB::OGE_F64, "__mips16_gedf2");
setMips16LibcallName(RTLIB::OLT_F32, "__mips16_ltsf2");
setMips16LibcallName(RTLIB::OLT_F64, "__mips16_ltdf2");
setMips16LibcallName(RTLIB::OLE_F32, "__mips16_lesf2");
setMips16LibcallName(RTLIB::OLE_F64, "__mips16_ledf2");
setMips16LibcallName(RTLIB::OGT_F32, "__mips16_gtsf2");
setMips16LibcallName(RTLIB::OGT_F64, "__mips16_gtdf2");
setMips16LibcallName(RTLIB::UO_F32, "__mips16_unordsf2");
setMips16LibcallName(RTLIB::UO_F64, "__mips16_unorddf2");
setMips16LibcallName(RTLIB::O_F32, "__mips16_unordsf2");
setMips16LibcallName(RTLIB::O_F64, "__mips16_unorddf2");
}
//
// The Mips16 hard float is a crazy quilt inherited from gcc. I have a much
// cleaner way to do all of this but it will have to wait until the traditional
// gcc mechanism is completed.
//
// For Pic, in order for Mips16 code to call Mips32 code which according the abi
// have either arguments or returned values placed in floating point registers,
// we use a set of helper functions. (This includes functions which return type
// complex which on Mips are returned in a pair of floating point registers).
//
// This is an encoding that we inherited from gcc.
// In Mips traditional O32, N32 ABI, floating point numbers are passed in
// floating point argument registers 1,2 only when the first and optionally
// the second arguments are float (sf) or double (df).
// For Mips16 we are only concerned with the situations where floating point
// arguments are being passed in floating point registers by the ABI, because
// Mips16 mode code cannot execute floating point instructions to load those
// values and hence helper functions are needed.
// The possibilities are (), (sf), (sf, sf), (sf, df), (df), (df, sf), (df, df)
// the helper function suffixs for these are:
// 0, 1, 5, 9, 2, 6, 10
// this suffix can then be calculated as follows:
// for a given argument Arg:
// Arg1x, Arg2x = 1 : Arg is sf
// 2 : Arg is df
// 0: Arg is neither sf or df
// So this stub is the string for number Arg1x + Arg2x*4.
// However not all numbers between 0 and 10 are possible, we check anyway and
// assert if the impossible exists.
//
unsigned int Mips16TargetLowering::getMips16HelperFunctionStubNumber
(ArgListTy &Args) const {
unsigned int resultNum = 0;
if (Args.size() >= 1) {
Type *t = Args[0].Ty;
if (t->isFloatTy()) {
resultNum = 1;
}
else if (t->isDoubleTy()) {
resultNum = 2;
}
}
if (resultNum) {
if (Args.size() >=2) {
Type *t = Args[1].Ty;
if (t->isFloatTy()) {
resultNum += 4;
}
else if (t->isDoubleTy()) {
resultNum += 8;
}
}
}
return resultNum;
}
//
// prefixs are attached to stub numbers depending on the return type .
// return type: float sf_
// double df_
// single complex sc_
// double complext dc_
// others NO PREFIX
//
//
// The full name of a helper function is__mips16_call_stub +
// return type dependent prefix + stub number
//
//
// This is something that probably should be in a different source file and
// perhaps done differently but my main purpose is to not waste runtime
// on something that we can enumerate in the source. Another possibility is
// to have a python script to generate these mapping tables. This will do
// for now. There are a whole series of helper function mapping arrays, one
// for each return type class as outlined above. There there are 11 possible
// entries. Ones with 0 are ones which should never be selected
//
// All the arrays are similar except for ones which return neither
// sf, df, sc, dc, in which only care about ones which have sf or df as a
// first parameter.
//
#define P_ "__mips16_call_stub_"
#define MAX_STUB_NUMBER 10
#define T1 P "1", P "2", 0, 0, P "5", P "6", 0, 0, P "9", P "10"
#define T P "0" , T1
#define P P_
static char const * vMips16Helper[MAX_STUB_NUMBER+1] =
{0, T1 };
#undef P
#define P P_ "sf_"
static char const * sfMips16Helper[MAX_STUB_NUMBER+1] =
{ T };
#undef P
#define P P_ "df_"
static char const * dfMips16Helper[MAX_STUB_NUMBER+1] =
{ T };
#undef P
#define P P_ "sc_"
static char const * scMips16Helper[MAX_STUB_NUMBER+1] =
{ T };
#undef P
#define P P_ "dc_"
static char const * dcMips16Helper[MAX_STUB_NUMBER+1] =
{ T };
#undef P
#undef P_
const char* Mips16TargetLowering::
getMips16HelperFunction
(Type* RetTy, ArgListTy &Args, bool &needHelper) const {
const unsigned int stubNum = getMips16HelperFunctionStubNumber(Args);
#ifndef NDEBUG
const unsigned int maxStubNum = 10;
assert(stubNum <= maxStubNum);
const bool validStubNum[maxStubNum+1] =
{true, true, true, false, false, true, true, false, false, true, true};
assert(validStubNum[stubNum]);
#endif
const char *result;
if (RetTy->isFloatTy()) {
result = sfMips16Helper[stubNum];
}
else if (RetTy ->isDoubleTy()) {
result = dfMips16Helper[stubNum];
}
else if (RetTy->isStructTy()) {
// check if it's complex
if (RetTy->getNumContainedTypes() == 2) {
if ((RetTy->getContainedType(0)->isFloatTy()) &&
(RetTy->getContainedType(1)->isFloatTy())) {
result = scMips16Helper[stubNum];
}
else if ((RetTy->getContainedType(0)->isDoubleTy()) &&
(RetTy->getContainedType(1)->isDoubleTy())) {
result = dcMips16Helper[stubNum];
}
else {
llvm_unreachable("Uncovered condition");
}
}
else {
llvm_unreachable("Uncovered condition");
}
}
else {
if (stubNum == 0) {
needHelper = false;
return "";
}
result = vMips16Helper[stubNum];
}
needHelper = true;
return result;
}
void Mips16TargetLowering::
getOpndList(SmallVectorImpl<SDValue> &Ops,
std::deque< std::pair<unsigned, SDValue> > &RegsToPass,
bool IsPICCall, bool GlobalOrExternal, bool InternalLinkage,
CallLoweringInfo &CLI, SDValue Callee, SDValue Chain) const {
SelectionDAG &DAG = CLI.DAG;
const char* Mips16HelperFunction = 0;
bool NeedMips16Helper = false;
if (getTargetMachine().Options.UseSoftFloat &&
Subtarget->inMips16HardFloat()) {
//
// currently we don't have symbols tagged with the mips16 or mips32
// qualifier so we will assume that we don't know what kind it is.
// and generate the helper
//
bool LookupHelper = true;
if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(CLI.Callee)) {
if (NoHelperNeeded.find(S->getSymbol()) != NoHelperNeeded.end()) {
LookupHelper = false;
}
}
if (LookupHelper) Mips16HelperFunction =
getMips16HelperFunction(CLI.RetTy, CLI.Args, NeedMips16Helper);
}
SDValue JumpTarget = Callee;
// T9 should contain the address of the callee function if
// -reloction-model=pic or it is an indirect call.
if (IsPICCall || !GlobalOrExternal) {
unsigned V0Reg = Mips::V0;
if (NeedMips16Helper) {
RegsToPass.push_front(std::make_pair(V0Reg, Callee));
JumpTarget = DAG.getExternalSymbol(Mips16HelperFunction, getPointerTy());
JumpTarget = getAddrGlobal(JumpTarget, DAG, MipsII::MO_GOT);
} else
RegsToPass.push_front(std::make_pair((unsigned)Mips::T9, Callee));
}
Ops.push_back(JumpTarget);
MipsTargetLowering::getOpndList(Ops, RegsToPass, IsPICCall, GlobalOrExternal,
InternalLinkage, CLI, Callee, Chain);
}
MachineBasicBlock *Mips16TargetLowering::
emitSel16(unsigned Opc, MachineInstr *MI, MachineBasicBlock *BB) const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
DebugLoc DL = MI->getDebugLoc();
// To "insert" a SELECT_CC instruction, we actually have to insert the
// diamond control-flow pattern. The incoming instruction knows the
// destination vreg to set, the condition code register to branch on, the
// true/false values to select between, and a branch opcode to use.
const BasicBlock *LLVM_BB = BB->getBasicBlock();
MachineFunction::iterator It = BB;
++It;
// thisMBB:
// ...
// TrueVal = ...
// setcc r1, r2, r3
// bNE r1, r0, copy1MBB
// fallthrough --> copy0MBB
MachineBasicBlock *thisMBB = BB;
MachineFunction *F = BB->getParent();
MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
F->insert(It, copy0MBB);
F->insert(It, sinkMBB);
// Transfer the remainder of BB and its successor edges to sinkMBB.
sinkMBB->splice(sinkMBB->begin(), BB,
llvm::next(MachineBasicBlock::iterator(MI)),
BB->end());
sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
// Next, add the true and fallthrough blocks as its successors.
BB->addSuccessor(copy0MBB);
BB->addSuccessor(sinkMBB);
BuildMI(BB, DL, TII->get(Opc)).addReg(MI->getOperand(3).getReg())
.addMBB(sinkMBB);
// copy0MBB:
// %FalseValue = ...
// # fallthrough to sinkMBB
BB = copy0MBB;
// Update machine-CFG edges
BB->addSuccessor(sinkMBB);
// sinkMBB:
// %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ]
// ...
BB = sinkMBB;
BuildMI(*BB, BB->begin(), DL,
TII->get(Mips::PHI), MI->getOperand(0).getReg())
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB)
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}
MachineBasicBlock *Mips16TargetLowering::emitSelT16
(unsigned Opc1, unsigned Opc2,
MachineInstr *MI, MachineBasicBlock *BB) const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
DebugLoc DL = MI->getDebugLoc();
// To "insert" a SELECT_CC instruction, we actually have to insert the
// diamond control-flow pattern. The incoming instruction knows the
// destination vreg to set, the condition code register to branch on, the
// true/false values to select between, and a branch opcode to use.
const BasicBlock *LLVM_BB = BB->getBasicBlock();
MachineFunction::iterator It = BB;
++It;
// thisMBB:
// ...
// TrueVal = ...
// setcc r1, r2, r3
// bNE r1, r0, copy1MBB
// fallthrough --> copy0MBB
MachineBasicBlock *thisMBB = BB;
MachineFunction *F = BB->getParent();
MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
F->insert(It, copy0MBB);
F->insert(It, sinkMBB);
// Transfer the remainder of BB and its successor edges to sinkMBB.
sinkMBB->splice(sinkMBB->begin(), BB,
llvm::next(MachineBasicBlock::iterator(MI)),
BB->end());
sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
// Next, add the true and fallthrough blocks as its successors.
BB->addSuccessor(copy0MBB);
BB->addSuccessor(sinkMBB);
BuildMI(BB, DL, TII->get(Opc2)).addReg(MI->getOperand(3).getReg())
.addReg(MI->getOperand(4).getReg());
BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB);
// copy0MBB:
// %FalseValue = ...
// # fallthrough to sinkMBB
BB = copy0MBB;
// Update machine-CFG edges
BB->addSuccessor(sinkMBB);
// sinkMBB:
// %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ]
// ...
BB = sinkMBB;
BuildMI(*BB, BB->begin(), DL,
TII->get(Mips::PHI), MI->getOperand(0).getReg())
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB)
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}
MachineBasicBlock *Mips16TargetLowering::emitSeliT16
(unsigned Opc1, unsigned Opc2,
MachineInstr *MI, MachineBasicBlock *BB) const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
DebugLoc DL = MI->getDebugLoc();
// To "insert" a SELECT_CC instruction, we actually have to insert the
// diamond control-flow pattern. The incoming instruction knows the
// destination vreg to set, the condition code register to branch on, the
// true/false values to select between, and a branch opcode to use.
const BasicBlock *LLVM_BB = BB->getBasicBlock();
MachineFunction::iterator It = BB;
++It;
// thisMBB:
// ...
// TrueVal = ...
// setcc r1, r2, r3
// bNE r1, r0, copy1MBB
// fallthrough --> copy0MBB
MachineBasicBlock *thisMBB = BB;
MachineFunction *F = BB->getParent();
MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
F->insert(It, copy0MBB);
F->insert(It, sinkMBB);
// Transfer the remainder of BB and its successor edges to sinkMBB.
sinkMBB->splice(sinkMBB->begin(), BB,
llvm::next(MachineBasicBlock::iterator(MI)),
BB->end());
sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
// Next, add the true and fallthrough blocks as its successors.
BB->addSuccessor(copy0MBB);
BB->addSuccessor(sinkMBB);
BuildMI(BB, DL, TII->get(Opc2)).addReg(MI->getOperand(3).getReg())
.addImm(MI->getOperand(4).getImm());
BuildMI(BB, DL, TII->get(Opc1)).addMBB(sinkMBB);
// copy0MBB:
// %FalseValue = ...
// # fallthrough to sinkMBB
BB = copy0MBB;
// Update machine-CFG edges
BB->addSuccessor(sinkMBB);
// sinkMBB:
// %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copy0MBB ]
// ...
BB = sinkMBB;
BuildMI(*BB, BB->begin(), DL,
TII->get(Mips::PHI), MI->getOperand(0).getReg())
.addReg(MI->getOperand(1).getReg()).addMBB(thisMBB)
.addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}
MachineBasicBlock
*Mips16TargetLowering::emitFEXT_T8I816_ins(unsigned BtOpc, unsigned CmpOpc,
MachineInstr *MI,
MachineBasicBlock *BB) const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
unsigned regX = MI->getOperand(0).getReg();
unsigned regY = MI->getOperand(1).getReg();
MachineBasicBlock *target = MI->getOperand(2).getMBB();
BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(CmpOpc)).addReg(regX)
.addReg(regY);
BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(BtOpc)).addMBB(target);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}
MachineBasicBlock *Mips16TargetLowering::emitFEXT_T8I8I16_ins(
unsigned BtOpc, unsigned CmpiOpc, unsigned CmpiXOpc,
MachineInstr *MI, MachineBasicBlock *BB) const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
unsigned regX = MI->getOperand(0).getReg();
int64_t imm = MI->getOperand(1).getImm();
MachineBasicBlock *target = MI->getOperand(2).getMBB();
unsigned CmpOpc;
if (isUInt<8>(imm))
CmpOpc = CmpiOpc;
else if (isUInt<16>(imm))
CmpOpc = CmpiXOpc;
else
llvm_unreachable("immediate field not usable");
BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(CmpOpc)).addReg(regX)
.addImm(imm);
BuildMI(*BB, MI, MI->getDebugLoc(), TII->get(BtOpc)).addMBB(target);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}
static unsigned Mips16WhichOp8uOr16simm
(unsigned shortOp, unsigned longOp, int64_t Imm) {
if (isUInt<8>(Imm))
return shortOp;
else if (isInt<16>(Imm))
return longOp;
else
llvm_unreachable("immediate field not usable");
}
MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRX16_ins(
unsigned SltOpc,
MachineInstr *MI, MachineBasicBlock *BB) const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
unsigned CC = MI->getOperand(0).getReg();
unsigned regX = MI->getOperand(1).getReg();
unsigned regY = MI->getOperand(2).getReg();
BuildMI(*BB, MI, MI->getDebugLoc(),
TII->get(SltOpc)).addReg(regX).addReg(regY);
BuildMI(*BB, MI, MI->getDebugLoc(),
TII->get(Mips::MoveR3216), CC).addReg(Mips::T8);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}
MachineBasicBlock *Mips16TargetLowering::emitFEXT_CCRXI16_ins(
unsigned SltiOpc, unsigned SltiXOpc,
MachineInstr *MI, MachineBasicBlock *BB )const {
if (DontExpandCondPseudos16)
return BB;
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
unsigned CC = MI->getOperand(0).getReg();
unsigned regX = MI->getOperand(1).getReg();
int64_t Imm = MI->getOperand(2).getImm();
unsigned SltOpc = Mips16WhichOp8uOr16simm(SltiOpc, SltiXOpc, Imm);
BuildMI(*BB, MI, MI->getDebugLoc(),
TII->get(SltOpc)).addReg(regX).addImm(Imm);
BuildMI(*BB, MI, MI->getDebugLoc(),
TII->get(Mips::MoveR3216), CC).addReg(Mips::T8);
MI->eraseFromParent(); // The pseudo instruction is gone now.
return BB;
}