llvm-6502/lib/Target/Mips/MipsSEISelDAGToDAG.cpp

556 lines
19 KiB
C++
Raw Normal View History

//===-- MipsSEISelDAGToDAG.cpp - A Dag to Dag Inst Selector for MipsSE ----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Subclass of MipsDAGToDAGISel specialized for mips32/64.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "mips-isel"
#include "MipsSEISelDAGToDAG.h"
#include "Mips.h"
#include "MCTargetDesc/MipsBaseInfo.h"
#include "MipsAnalyzeImmediate.h"
#include "MipsMachineFunction.h"
#include "MipsRegisterInfo.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
This patch enables llvm to switch between compiling for mips32/mips64 and mips16 on a per function basis. Because this patch is somewhat involved I have provide an overview of the key pieces of it. The patch is written so as to not change the behavior of the non mixed mode. We have tested this a lot but it is something new to switch subtargets so we don't want any chance of regression in the mainline compiler until we have more confidence in this. Mips32/64 are very different from Mip16 as is the case of ARM vs Thumb1. For that reason there are derived versions of the register info, frame info, instruction info and instruction selection classes. Now we register three separate passes for instruction selection. One which is used to switch subtargets (MipsModuleISelDAGToDAG.cpp) and then one for each of the current subtargets (Mips16ISelDAGToDAG.cpp and MipsSEISelDAGToDAG.cpp). When the ModuleISel pass runs, it determines if there is a need to switch subtargets and if so, the owning pointers in MipsTargetMachine are appropriately changed. When 16Isel or SEIsel is run, they will return immediately without doing any work if the current subtarget mode does not apply to them. In addition, MipsAsmPrinter needs to be reset on a function basis. The pass BasicTargetTransformInfo is substituted with a null pass since the pass is immutable and really needs to be a function pass for it to be used with changing subtargets. This will be fixed in a follow on patch. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@179118 91177308-0d34-0410-b5e6-96231b3b80d8
2013-04-09 19:46:01 +00:00
bool MipsSEDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
if (Subtarget.inMips16Mode())
return false;
return MipsDAGToDAGISel::runOnMachineFunction(MF);
}
void MipsSEDAGToDAGISel::addDSPCtrlRegOperands(bool IsDef, MachineInstr &MI,
MachineFunction &MF) {
MachineInstrBuilder MIB(MF, &MI);
unsigned Mask = MI.getOperand(1).getImm();
unsigned Flag = IsDef ? RegState::ImplicitDefine : RegState::Implicit;
if (Mask & 1)
MIB.addReg(Mips::DSPPos, Flag);
if (Mask & 2)
MIB.addReg(Mips::DSPSCount, Flag);
if (Mask & 4)
MIB.addReg(Mips::DSPCarry, Flag);
if (Mask & 8)
MIB.addReg(Mips::DSPOutFlag, Flag);
if (Mask & 16)
MIB.addReg(Mips::DSPCCond, Flag);
if (Mask & 32)
MIB.addReg(Mips::DSPEFI, Flag);
}
unsigned MipsSEDAGToDAGISel::getMSACtrlReg(const SDValue RegIdx) const {
switch (cast<ConstantSDNode>(RegIdx)->getZExtValue()) {
default:
llvm_unreachable("Could not map int to register");
case 0: return Mips::MSAIR;
case 1: return Mips::MSACSR;
case 2: return Mips::MSAAccess;
case 3: return Mips::MSASave;
case 4: return Mips::MSAModify;
case 5: return Mips::MSARequest;
case 6: return Mips::MSAMap;
case 7: return Mips::MSAUnmap;
}
}
bool MipsSEDAGToDAGISel::replaceUsesWithZeroReg(MachineRegisterInfo *MRI,
const MachineInstr& MI) {
unsigned DstReg = 0, ZeroReg = 0;
// Check if MI is "addiu $dst, $zero, 0" or "daddiu $dst, $zero, 0".
if ((MI.getOpcode() == Mips::ADDiu) &&
(MI.getOperand(1).getReg() == Mips::ZERO) &&
(MI.getOperand(2).getImm() == 0)) {
DstReg = MI.getOperand(0).getReg();
ZeroReg = Mips::ZERO;
} else if ((MI.getOpcode() == Mips::DADDiu) &&
(MI.getOperand(1).getReg() == Mips::ZERO_64) &&
(MI.getOperand(2).getImm() == 0)) {
DstReg = MI.getOperand(0).getReg();
ZeroReg = Mips::ZERO_64;
}
if (!DstReg)
return false;
// Replace uses with ZeroReg.
for (MachineRegisterInfo::use_iterator U = MRI->use_begin(DstReg),
E = MRI->use_end(); U != E;) {
MachineOperand &MO = U.getOperand();
unsigned OpNo = U.getOperandNo();
MachineInstr *MI = MO.getParent();
++U;
// Do not replace if it is a phi's operand or is tied to def operand.
if (MI->isPHI() || MI->isRegTiedToDefOperand(OpNo) || MI->isPseudo())
continue;
MO.setReg(ZeroReg);
}
return true;
}
void MipsSEDAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) {
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
if (!MipsFI->globalBaseRegSet())
return;
MachineBasicBlock &MBB = MF.front();
MachineBasicBlock::iterator I = MBB.begin();
MachineRegisterInfo &RegInfo = MF.getRegInfo();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
unsigned V0, V1, GlobalBaseReg = MipsFI->getGlobalBaseReg();
const TargetRegisterClass *RC;
if (Subtarget.isABI_N64())
RC = (const TargetRegisterClass*)&Mips::GPR64RegClass;
else
RC = (const TargetRegisterClass*)&Mips::GPR32RegClass;
V0 = RegInfo.createVirtualRegister(RC);
V1 = RegInfo.createVirtualRegister(RC);
if (Subtarget.isABI_N64()) {
MF.getRegInfo().addLiveIn(Mips::T9_64);
MBB.addLiveIn(Mips::T9_64);
// lui $v0, %hi(%neg(%gp_rel(fname)))
// daddu $v1, $v0, $t9
// daddiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname)))
const GlobalValue *FName = MF.getFunction();
BuildMI(MBB, I, DL, TII.get(Mips::LUi64), V0)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
BuildMI(MBB, I, DL, TII.get(Mips::DADDu), V1).addReg(V0)
.addReg(Mips::T9_64);
BuildMI(MBB, I, DL, TII.get(Mips::DADDiu), GlobalBaseReg).addReg(V1)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
return;
}
if (MF.getTarget().getRelocationModel() == Reloc::Static) {
// Set global register to __gnu_local_gp.
//
// lui $v0, %hi(__gnu_local_gp)
// addiu $globalbasereg, $v0, %lo(__gnu_local_gp)
BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0)
.addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_HI);
BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V0)
.addExternalSymbol("__gnu_local_gp", MipsII::MO_ABS_LO);
return;
}
MF.getRegInfo().addLiveIn(Mips::T9);
MBB.addLiveIn(Mips::T9);
if (Subtarget.isABI_N32()) {
// lui $v0, %hi(%neg(%gp_rel(fname)))
// addu $v1, $v0, $t9
// addiu $globalbasereg, $v1, %lo(%neg(%gp_rel(fname)))
const GlobalValue *FName = MF.getFunction();
BuildMI(MBB, I, DL, TII.get(Mips::LUi), V0)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_HI);
BuildMI(MBB, I, DL, TII.get(Mips::ADDu), V1).addReg(V0).addReg(Mips::T9);
BuildMI(MBB, I, DL, TII.get(Mips::ADDiu), GlobalBaseReg).addReg(V1)
.addGlobalAddress(FName, 0, MipsII::MO_GPOFF_LO);
return;
}
assert(Subtarget.isABI_O32());
// For O32 ABI, the following instruction sequence is emitted to initialize
// the global base register:
//
// 0. lui $2, %hi(_gp_disp)
// 1. addiu $2, $2, %lo(_gp_disp)
// 2. addu $globalbasereg, $2, $t9
//
// We emit only the last instruction here.
//
// GNU linker requires that the first two instructions appear at the beginning
// of a function and no instructions be inserted before or between them.
// The two instructions are emitted during lowering to MC layer in order to
// avoid any reordering.
//
// Register $2 (Mips::V0) is added to the list of live-in registers to ensure
// the value instruction 1 (addiu) defines is valid when instruction 2 (addu)
// reads it.
MF.getRegInfo().addLiveIn(Mips::V0);
MBB.addLiveIn(Mips::V0);
BuildMI(MBB, I, DL, TII.get(Mips::ADDu), GlobalBaseReg)
.addReg(Mips::V0).addReg(Mips::T9);
}
void MipsSEDAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) {
initGlobalBaseReg(MF);
MachineRegisterInfo *MRI = &MF.getRegInfo();
for (MachineFunction::iterator MFI = MF.begin(), MFE = MF.end(); MFI != MFE;
++MFI)
for (MachineBasicBlock::iterator I = MFI->begin(); I != MFI->end(); ++I) {
if (I->getOpcode() == Mips::RDDSP)
addDSPCtrlRegOperands(false, *I, MF);
else if (I->getOpcode() == Mips::WRDSP)
addDSPCtrlRegOperands(true, *I, MF);
else
replaceUsesWithZeroReg(MRI, *I);
}
}
SDNode *MipsSEDAGToDAGISel::selectAddESubE(unsigned MOp, SDValue InFlag,
SDValue CmpLHS, SDLoc DL,
SDNode *Node) const {
unsigned Opc = InFlag.getOpcode(); (void)Opc;
assert(((Opc == ISD::ADDC || Opc == ISD::ADDE) ||
(Opc == ISD::SUBC || Opc == ISD::SUBE)) &&
"(ADD|SUB)E flag operand must come from (ADD|SUB)C/E insn");
SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) };
SDValue LHS = Node->getOperand(0), RHS = Node->getOperand(1);
EVT VT = LHS.getValueType();
SDNode *Carry = CurDAG->getMachineNode(Mips::SLTu, DL, VT, Ops);
SDNode *AddCarry = CurDAG->getMachineNode(Mips::ADDu, DL, VT,
SDValue(Carry, 0), RHS);
return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue, LHS,
SDValue(AddCarry, 0));
}
/// ComplexPattern used on MipsInstrInfo
/// Used on Mips Load/Store instructions
bool MipsSEDAGToDAGISel::selectAddrRegImm(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
EVT ValTy = Addr.getValueType();
// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
Offset = CurDAG->getTargetConstant(0, ValTy);
return true;
}
// on PIC code Load GA
if (Addr.getOpcode() == MipsISD::Wrapper) {
Base = Addr.getOperand(0);
Offset = Addr.getOperand(1);
return true;
}
if (TM.getRelocationModel() != Reloc::PIC_) {
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
Addr.getOpcode() == ISD::TargetGlobalAddress))
return false;
}
// Addresses of the form FI+const or FI|const
if (CurDAG->isBaseWithConstantOffset(Addr)) {
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
if (isInt<16>(CN->getSExtValue())) {
// If the first operand is a FI, get the TargetFI Node
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>
(Addr.getOperand(0)))
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
else
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy);
return true;
}
}
// Operand is a result from an ADD.
if (Addr.getOpcode() == ISD::ADD) {
// When loading from constant pools, load the lower address part in
// the instruction itself. Example, instead of:
// lui $2, %hi($CPI1_0)
// addiu $2, $2, %lo($CPI1_0)
// lwc1 $f0, 0($2)
// Generate:
// lui $2, %hi($CPI1_0)
// lwc1 $f0, %lo($CPI1_0)($2)
if (Addr.getOperand(1).getOpcode() == MipsISD::Lo ||
Addr.getOperand(1).getOpcode() == MipsISD::GPRel) {
SDValue Opnd0 = Addr.getOperand(1).getOperand(0);
if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) ||
isa<JumpTableSDNode>(Opnd0)) {
Base = Addr.getOperand(0);
Offset = Opnd0;
return true;
}
}
}
return false;
}
/// ComplexPattern used on MipsInstrInfo
/// Used on Mips Load/Store instructions
bool MipsSEDAGToDAGISel::selectAddrRegReg(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
// Operand is a result from an ADD.
if (Addr.getOpcode() == ISD::ADD) {
Base = Addr.getOperand(0);
Offset = Addr.getOperand(1);
return true;
}
return false;
}
bool MipsSEDAGToDAGISel::selectAddrDefault(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
Base = Addr;
Offset = CurDAG->getTargetConstant(0, Addr.getValueType());
return true;
}
bool MipsSEDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
return selectAddrRegImm(Addr, Base, Offset) ||
selectAddrDefault(Addr, Base, Offset);
}
/// Used on microMIPS Load/Store unaligned instructions (12-bit offset)
bool MipsSEDAGToDAGISel::selectAddrRegImm12(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
EVT ValTy = Addr.getValueType();
// Addresses of the form FI+const or FI|const
if (CurDAG->isBaseWithConstantOffset(Addr)) {
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
if (isInt<12>(CN->getSExtValue())) {
// If the first operand is a FI, get the TargetFI Node
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>
(Addr.getOperand(0)))
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
else
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy);
return true;
}
}
return false;
}
bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
return selectAddrRegImm12(Addr, Base, Offset) ||
selectAddrDefault(Addr, Base, Offset);
}
std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) {
unsigned Opcode = Node->getOpcode();
SDLoc DL(Node);
///
// Instruction Selection not handled by the auto-generated
// tablegen selection should be handled here.
///
SDNode *Result;
switch(Opcode) {
default: break;
case ISD::SUBE: {
SDValue InFlag = Node->getOperand(2);
Result = selectAddESubE(Mips::SUBu, InFlag, InFlag.getOperand(0), DL, Node);
return std::make_pair(true, Result);
}
case ISD::ADDE: {
if (Subtarget.hasDSP()) // Select DSP instructions, ADDSC and ADDWC.
break;
SDValue InFlag = Node->getOperand(2);
Result = selectAddESubE(Mips::ADDu, InFlag, InFlag.getValue(0), DL, Node);
return std::make_pair(true, Result);
}
case ISD::ConstantFP: {
ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node);
if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) {
if (Subtarget.hasMips64()) {
SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
Mips::ZERO_64, MVT::i64);
Result = CurDAG->getMachineNode(Mips::DMTC1, DL, MVT::f64, Zero);
} else {
SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
Mips::ZERO, MVT::i32);
Result = CurDAG->getMachineNode(Mips::BuildPairF64, DL, MVT::f64, Zero,
Zero);
}
return std::make_pair(true, Result);
}
break;
}
case ISD::Constant: {
const ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node);
unsigned Size = CN->getValueSizeInBits(0);
if (Size == 32)
break;
MipsAnalyzeImmediate AnalyzeImm;
int64_t Imm = CN->getSExtValue();
const MipsAnalyzeImmediate::InstSeq &Seq =
AnalyzeImm.Analyze(Imm, Size, false);
MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin();
SDLoc DL(CN);
SDNode *RegOpnd;
SDValue ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd),
MVT::i64);
// 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.
if (Inst->Opc == Mips::LUi64)
RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, ImmOpnd);
else
RegOpnd =
CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64,
CurDAG->getRegister(Mips::ZERO_64, MVT::i64),
ImmOpnd);
// The remaining instructions in the sequence are handled here.
for (++Inst; Inst != Seq.end(); ++Inst) {
ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd),
MVT::i64);
RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64,
SDValue(RegOpnd, 0), ImmOpnd);
}
return std::make_pair(true, RegOpnd);
}
case ISD::INTRINSIC_W_CHAIN: {
switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) {
default:
break;
case Intrinsic::mips_cfcmsa: {
SDValue ChainIn = Node->getOperand(0);
SDValue RegIdx = Node->getOperand(2);
SDValue Reg = CurDAG->getCopyFromReg(ChainIn, DL,
getMSACtrlReg(RegIdx), MVT::i32);
return std::make_pair(true, Reg.getNode());
}
}
break;
}
case ISD::INTRINSIC_WO_CHAIN: {
switch (cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue()) {
default:
break;
case Intrinsic::mips_move_v:
// Like an assignment but will always produce a move.v even if
// unnecessary.
return std::make_pair(true,
CurDAG->getMachineNode(Mips::MOVE_V, DL,
Node->getValueType(0),
Node->getOperand(1)));
}
break;
}
case ISD::INTRINSIC_VOID: {
switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) {
default:
break;
case Intrinsic::mips_ctcmsa: {
SDValue ChainIn = Node->getOperand(0);
SDValue RegIdx = Node->getOperand(2);
SDValue Value = Node->getOperand(3);
SDValue ChainOut = CurDAG->getCopyToReg(ChainIn, DL,
getMSACtrlReg(RegIdx), Value);
return std::make_pair(true, ChainOut.getNode());
}
}
break;
}
case MipsISD::ThreadPointer: {
EVT PtrVT = getTargetLowering()->getPointerTy();
unsigned RdhwrOpc, DestReg;
if (PtrVT == MVT::i32) {
RdhwrOpc = Mips::RDHWR;
DestReg = Mips::V1;
} else {
RdhwrOpc = Mips::RDHWR64;
DestReg = Mips::V1_64;
}
SDNode *Rdhwr =
CurDAG->getMachineNode(RdhwrOpc, SDLoc(Node),
Node->getValueType(0),
CurDAG->getRegister(Mips::HWR29, MVT::i32));
SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, DestReg,
SDValue(Rdhwr, 0));
SDValue ResNode = CurDAG->getCopyFromReg(Chain, DL, DestReg, PtrVT);
ReplaceUses(SDValue(Node, 0), ResNode);
return std::make_pair(true, ResNode.getNode());
}
case MipsISD::InsertLOHI: {
unsigned RCID = Subtarget.hasDSP() ? Mips::ACC64DSPRegClassID :
Mips::ACC64RegClassID;
SDValue RegClass = CurDAG->getTargetConstant(RCID, MVT::i32);
SDValue LoIdx = CurDAG->getTargetConstant(Mips::sub_lo, MVT::i32);
SDValue HiIdx = CurDAG->getTargetConstant(Mips::sub_hi, MVT::i32);
const SDValue Ops[] = { RegClass, Node->getOperand(0), LoIdx,
Node->getOperand(1), HiIdx };
SDNode *Res = CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, DL,
MVT::Untyped, Ops);
return std::make_pair(true, Res);
}
}
return std::make_pair(false, (SDNode*)NULL);
}
FunctionPass *llvm::createMipsSEISelDag(MipsTargetMachine &TM) {
return new MipsSEDAGToDAGISel(TM);
}