mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-09-06 09:54:49 +00:00
Sooooo many of these had incorrect or strange main module includes. I have manually inspected all of these, and fixed the main module include to be the nearest plausible thing I could find. If you own or care about any of these source files, I encourage you to take some time and check that these edits were sensible. I can't have broken anything (I strictly added headers, and reordered them, never removed), but they may not be the headers you'd really like to identify as containing the API being implemented. Many forward declarations and missing includes were added to a header files to allow them to parse cleanly when included first. The main module rule does in fact have its merits. =] git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@169131 91177308-0d34-0410-b5e6-96231b3b80d8
771 lines
26 KiB
C++
771 lines
26 KiB
C++
//===-- MipsISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips --------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines an instruction selector for the MIPS target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "mips-isel"
|
|
#include "Mips.h"
|
|
#include "MCTargetDesc/MipsBaseInfo.h"
|
|
#include "MipsAnalyzeImmediate.h"
|
|
#include "MipsMachineFunction.h"
|
|
#include "MipsRegisterInfo.h"
|
|
#include "MipsSubtarget.h"
|
|
#include "MipsTargetMachine.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/SelectionDAGISel.h"
|
|
#include "llvm/CodeGen/SelectionDAGNodes.h"
|
|
#include "llvm/GlobalValue.h"
|
|
#include "llvm/Instructions.h"
|
|
#include "llvm/Intrinsics.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"
|
|
#include "llvm/Type.h"
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Selector Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// MipsDAGToDAGISel - MIPS specific code to select MIPS machine
|
|
// instructions for SelectionDAG operations.
|
|
//===----------------------------------------------------------------------===//
|
|
namespace {
|
|
|
|
class MipsDAGToDAGISel : public SelectionDAGISel {
|
|
|
|
/// TM - Keep a reference to MipsTargetMachine.
|
|
MipsTargetMachine &TM;
|
|
|
|
/// Subtarget - Keep a pointer to the MipsSubtarget around so that we can
|
|
/// make the right decision when generating code for different targets.
|
|
const MipsSubtarget &Subtarget;
|
|
|
|
public:
|
|
explicit MipsDAGToDAGISel(MipsTargetMachine &tm) :
|
|
SelectionDAGISel(tm),
|
|
TM(tm), Subtarget(tm.getSubtarget<MipsSubtarget>()) {}
|
|
|
|
// Pass Name
|
|
virtual const char *getPassName() const {
|
|
return "MIPS DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
virtual bool runOnMachineFunction(MachineFunction &MF);
|
|
|
|
private:
|
|
// Include the pieces autogenerated from the target description.
|
|
#include "MipsGenDAGISel.inc"
|
|
|
|
/// getTargetMachine - Return a reference to the TargetMachine, casted
|
|
/// to the target-specific type.
|
|
const MipsTargetMachine &getTargetMachine() {
|
|
return static_cast<const MipsTargetMachine &>(TM);
|
|
}
|
|
|
|
/// getInstrInfo - Return a reference to the TargetInstrInfo, casted
|
|
/// to the target-specific type.
|
|
const MipsInstrInfo *getInstrInfo() {
|
|
return getTargetMachine().getInstrInfo();
|
|
}
|
|
|
|
SDNode *getGlobalBaseReg();
|
|
|
|
SDValue getMips16SPAliasReg();
|
|
|
|
void getMips16SPRefReg(SDNode *parent, SDValue &AliasReg);
|
|
|
|
std::pair<SDNode*, SDNode*> SelectMULT(SDNode *N, unsigned Opc, DebugLoc dl,
|
|
EVT Ty, bool HasLo, bool HasHi);
|
|
|
|
SDNode *Select(SDNode *N);
|
|
|
|
// Complex Pattern.
|
|
bool SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset);
|
|
|
|
bool SelectAddr16(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset,
|
|
SDValue &Alias);
|
|
|
|
// getImm - Return a target constant with the specified value.
|
|
inline SDValue getImm(const SDNode *Node, unsigned Imm) {
|
|
return CurDAG->getTargetConstant(Imm, Node->getValueType(0));
|
|
}
|
|
|
|
void ProcessFunctionAfterISel(MachineFunction &MF);
|
|
bool ReplaceUsesWithZeroReg(MachineRegisterInfo *MRI, const MachineInstr&);
|
|
void InitGlobalBaseReg(MachineFunction &MF);
|
|
void InitMips16SPAliasReg(MachineFunction &MF);
|
|
|
|
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
|
|
char ConstraintCode,
|
|
std::vector<SDValue> &OutOps);
|
|
};
|
|
|
|
}
|
|
|
|
// Insert instructions to initialize the global base register in the
|
|
// first MBB of the function. When the ABI is O32 and the relocation model is
|
|
// PIC, the necessary instructions are emitted later to prevent optimization
|
|
// passes from moving them.
|
|
void MipsDAGToDAGISel::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, V2, GlobalBaseReg = MipsFI->getGlobalBaseReg();
|
|
const TargetRegisterClass *RC;
|
|
|
|
if (Subtarget.isABI_N64())
|
|
RC = (const TargetRegisterClass*)&Mips::CPU64RegsRegClass;
|
|
else if (Subtarget.inMips16Mode())
|
|
RC = (const TargetRegisterClass*)&Mips::CPU16RegsRegClass;
|
|
else
|
|
RC = (const TargetRegisterClass*)&Mips::CPURegsRegClass;
|
|
|
|
V0 = RegInfo.createVirtualRegister(RC);
|
|
V1 = RegInfo.createVirtualRegister(RC);
|
|
V2 = 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 (Subtarget.inMips16Mode()) {
|
|
BuildMI(MBB, I, DL, TII.get(Mips::LiRxImmX16), V0)
|
|
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI);
|
|
BuildMI(MBB, I, DL, TII.get(Mips::AddiuRxPcImmX16), V1)
|
|
.addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO);
|
|
BuildMI(MBB, I, DL, TII.get(Mips::SllX16), V2).addReg(V0).addImm(16);
|
|
BuildMI(MBB, I, DL, TII.get(Mips::AdduRxRyRz16), GlobalBaseReg)
|
|
.addReg(V1).addReg(V2);
|
|
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);
|
|
}
|
|
|
|
// Insert instructions to initialize the Mips16 SP Alias register in the
|
|
// first MBB of the function.
|
|
//
|
|
void MipsDAGToDAGISel::InitMips16SPAliasReg(MachineFunction &MF) {
|
|
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
|
|
|
if (!MipsFI->mips16SPAliasRegSet())
|
|
return;
|
|
|
|
MachineBasicBlock &MBB = MF.front();
|
|
MachineBasicBlock::iterator I = MBB.begin();
|
|
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
|
|
DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
|
|
unsigned Mips16SPAliasReg = MipsFI->getMips16SPAliasReg();
|
|
|
|
BuildMI(MBB, I, DL, TII.get(Mips::MoveR3216), Mips16SPAliasReg)
|
|
.addReg(Mips::SP);
|
|
}
|
|
|
|
|
|
bool MipsDAGToDAGISel::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 MipsDAGToDAGISel::ProcessFunctionAfterISel(MachineFunction &MF) {
|
|
InitGlobalBaseReg(MF);
|
|
InitMips16SPAliasReg(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)
|
|
ReplaceUsesWithZeroReg(MRI, *I);
|
|
}
|
|
|
|
bool MipsDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
|
|
bool Ret = SelectionDAGISel::runOnMachineFunction(MF);
|
|
|
|
ProcessFunctionAfterISel(MF);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
/// getGlobalBaseReg - Output the instructions required to put the
|
|
/// GOT address into a register.
|
|
SDNode *MipsDAGToDAGISel::getGlobalBaseReg() {
|
|
unsigned GlobalBaseReg = MF->getInfo<MipsFunctionInfo>()->getGlobalBaseReg();
|
|
return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
|
|
}
|
|
|
|
/// getMips16SPAliasReg - Output the instructions required to put the
|
|
/// SP into a Mips16 accessible aliased register.
|
|
SDValue MipsDAGToDAGISel::getMips16SPAliasReg() {
|
|
unsigned Mips16SPAliasReg =
|
|
MF->getInfo<MipsFunctionInfo>()->getMips16SPAliasReg();
|
|
return CurDAG->getRegister(Mips16SPAliasReg, TLI.getPointerTy());
|
|
}
|
|
|
|
/// ComplexPattern used on MipsInstrInfo
|
|
/// Used on Mips Load/Store instructions
|
|
bool MipsDAGToDAGISel::
|
|
SelectAddr(SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
// If an indexed floating point load/store can be emitted, return false.
|
|
const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent);
|
|
|
|
if (LS &&
|
|
(LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) &&
|
|
Subtarget.hasFPIdx())
|
|
return false;
|
|
}
|
|
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, ValTy);
|
|
return true;
|
|
}
|
|
|
|
void MipsDAGToDAGISel::getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg) {
|
|
SDValue AliasFPReg = CurDAG->getRegister(Mips::S0, TLI.getPointerTy());
|
|
if (Parent) {
|
|
switch (Parent->getOpcode()) {
|
|
case ISD::LOAD: {
|
|
LoadSDNode *SD = dyn_cast<LoadSDNode>(Parent);
|
|
switch (SD->getMemoryVT().getSizeInBits()) {
|
|
case 8:
|
|
case 16:
|
|
AliasReg = TM.getFrameLowering()->hasFP(*MF)?
|
|
AliasFPReg: getMips16SPAliasReg();
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case ISD::STORE: {
|
|
StoreSDNode *SD = dyn_cast<StoreSDNode>(Parent);
|
|
switch (SD->getMemoryVT().getSizeInBits()) {
|
|
case 8:
|
|
case 16:
|
|
AliasReg = TM.getFrameLowering()->hasFP(*MF)?
|
|
AliasFPReg: getMips16SPAliasReg();
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
AliasReg = CurDAG->getRegister(Mips::SP, TLI.getPointerTy());
|
|
return;
|
|
|
|
}
|
|
bool MipsDAGToDAGISel::SelectAddr16(
|
|
SDNode *Parent, SDValue Addr, SDValue &Base, SDValue &Offset,
|
|
SDValue &Alias) {
|
|
EVT ValTy = Addr.getValueType();
|
|
|
|
Alias = CurDAG->getTargetConstant(0, ValTy);
|
|
|
|
// 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);
|
|
getMips16SPRefReg(Parent, Alias);
|
|
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);
|
|
getMips16SPRefReg(Parent, Alias);
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
// If an indexed floating point load/store can be emitted, return false.
|
|
const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent);
|
|
|
|
if (LS &&
|
|
(LS->getMemoryVT() == MVT::f32 || LS->getMemoryVT() == MVT::f64) &&
|
|
Subtarget.hasFPIdx())
|
|
return false;
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, ValTy);
|
|
return true;
|
|
}
|
|
|
|
/// Select multiply instructions.
|
|
std::pair<SDNode*, SDNode*>
|
|
MipsDAGToDAGISel::SelectMULT(SDNode *N, unsigned Opc, DebugLoc dl, EVT Ty,
|
|
bool HasLo, bool HasHi) {
|
|
SDNode *Lo = 0, *Hi = 0;
|
|
SDNode *Mul = CurDAG->getMachineNode(Opc, dl, MVT::Glue, N->getOperand(0),
|
|
N->getOperand(1));
|
|
SDValue InFlag = SDValue(Mul, 0);
|
|
|
|
if (HasLo) {
|
|
unsigned Opcode = Subtarget.inMips16Mode() ? Mips::Mflo16 :
|
|
(Ty == MVT::i32 ? Mips::MFLO : Mips::MFLO64);
|
|
Lo = CurDAG->getMachineNode(Opcode, dl, Ty, MVT::Glue, InFlag);
|
|
InFlag = SDValue(Lo, 1);
|
|
}
|
|
if (HasHi) {
|
|
unsigned Opcode = Subtarget.inMips16Mode() ? Mips::Mfhi16 :
|
|
(Ty == MVT::i32 ? Mips::MFHI : Mips::MFHI64);
|
|
Hi = CurDAG->getMachineNode(Opcode, dl, Ty, InFlag);
|
|
}
|
|
return std::make_pair(Lo, Hi);
|
|
}
|
|
|
|
|
|
/// Select instructions not customized! Used for
|
|
/// expanded, promoted and normal instructions
|
|
SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
|
|
unsigned Opcode = Node->getOpcode();
|
|
DebugLoc dl = Node->getDebugLoc();
|
|
|
|
// Dump information about the Node being selected
|
|
DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n");
|
|
|
|
// If we have a custom node, we already have selected!
|
|
if (Node->isMachineOpcode()) {
|
|
DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");
|
|
return NULL;
|
|
}
|
|
|
|
///
|
|
// Instruction Selection not handled by the auto-generated
|
|
// tablegen selection should be handled here.
|
|
///
|
|
EVT NodeTy = Node->getValueType(0);
|
|
unsigned MultOpc;
|
|
|
|
switch(Opcode) {
|
|
default: break;
|
|
|
|
case ISD::SUBE:
|
|
case ISD::ADDE: {
|
|
bool inMips16Mode = Subtarget.inMips16Mode();
|
|
SDValue InFlag = Node->getOperand(2), CmpLHS;
|
|
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");
|
|
|
|
unsigned MOp;
|
|
if (Opcode == ISD::ADDE) {
|
|
CmpLHS = InFlag.getValue(0);
|
|
if (inMips16Mode)
|
|
MOp = Mips::AdduRxRyRz16;
|
|
else
|
|
MOp = Mips::ADDu;
|
|
} else {
|
|
CmpLHS = InFlag.getOperand(0);
|
|
if (inMips16Mode)
|
|
MOp = Mips::SubuRxRyRz16;
|
|
else
|
|
MOp = Mips::SUBu;
|
|
}
|
|
|
|
SDValue Ops[] = { CmpLHS, InFlag.getOperand(1) };
|
|
|
|
SDValue LHS = Node->getOperand(0);
|
|
SDValue RHS = Node->getOperand(1);
|
|
|
|
EVT VT = LHS.getValueType();
|
|
|
|
unsigned Sltu_op = inMips16Mode? Mips::SltuRxRyRz16: Mips::SLTu;
|
|
SDNode *Carry = CurDAG->getMachineNode(Sltu_op, dl, VT, Ops, 2);
|
|
unsigned Addu_op = inMips16Mode? Mips::AdduRxRyRz16 : Mips::ADDu;
|
|
SDNode *AddCarry = CurDAG->getMachineNode(Addu_op, dl, VT,
|
|
SDValue(Carry,0), RHS);
|
|
|
|
return CurDAG->SelectNodeTo(Node, MOp, VT, MVT::Glue,
|
|
LHS, SDValue(AddCarry,0));
|
|
}
|
|
|
|
/// Mul with two results
|
|
case ISD::SMUL_LOHI:
|
|
case ISD::UMUL_LOHI: {
|
|
if (NodeTy == MVT::i32) {
|
|
if (Subtarget.inMips16Mode())
|
|
MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MultuRxRy16 :
|
|
Mips::MultRxRy16);
|
|
else
|
|
MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MULTu : Mips::MULT);
|
|
}
|
|
else
|
|
MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::DMULTu : Mips::DMULT);
|
|
|
|
std::pair<SDNode*, SDNode*> LoHi = SelectMULT(Node, MultOpc, dl, NodeTy,
|
|
true, true);
|
|
|
|
if (!SDValue(Node, 0).use_empty())
|
|
ReplaceUses(SDValue(Node, 0), SDValue(LoHi.first, 0));
|
|
|
|
if (!SDValue(Node, 1).use_empty())
|
|
ReplaceUses(SDValue(Node, 1), SDValue(LoHi.second, 0));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/// Special Muls
|
|
case ISD::MUL: {
|
|
// Mips32 has a 32-bit three operand mul instruction.
|
|
if (Subtarget.hasMips32() && NodeTy == MVT::i32)
|
|
break;
|
|
return SelectMULT(Node, NodeTy == MVT::i32 ? Mips::MULT : Mips::DMULT,
|
|
dl, NodeTy, true, false).first;
|
|
}
|
|
case ISD::MULHS:
|
|
case ISD::MULHU: {
|
|
if (NodeTy == MVT::i32) {
|
|
if (Subtarget.inMips16Mode())
|
|
MultOpc = (Opcode == ISD::MULHU ?
|
|
Mips::MultuRxRy16 : Mips::MultRxRy16);
|
|
else
|
|
MultOpc = (Opcode == ISD::MULHU ? Mips::MULTu : Mips::MULT);
|
|
}
|
|
else
|
|
MultOpc = (Opcode == ISD::MULHU ? Mips::DMULTu : Mips::DMULT);
|
|
|
|
return SelectMULT(Node, MultOpc, dl, NodeTy, false, true).second;
|
|
}
|
|
|
|
// Get target GOT address.
|
|
case ISD::GLOBAL_OFFSET_TABLE:
|
|
return getGlobalBaseReg();
|
|
|
|
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);
|
|
return CurDAG->getMachineNode(Mips::DMTC1, dl, MVT::f64, Zero);
|
|
}
|
|
|
|
SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), dl,
|
|
Mips::ZERO, MVT::i32);
|
|
return CurDAG->getMachineNode(Mips::BuildPairF64, dl, MVT::f64, Zero,
|
|
Zero);
|
|
}
|
|
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();
|
|
DebugLoc DL = CN->getDebugLoc();
|
|
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 RegOpnd;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
case ISD::LOAD:
|
|
case ISD::STORE:
|
|
assert(cast<MemSDNode>(Node)->getMemoryVT().getSizeInBits() / 8 <=
|
|
cast<MemSDNode>(Node)->getAlignment() &&
|
|
"Unexpected unaligned loads/stores.");
|
|
break;
|
|
#endif
|
|
|
|
case MipsISD::ThreadPointer: {
|
|
EVT PtrVT = TLI.getPointerTy();
|
|
unsigned RdhwrOpc, SrcReg, DestReg;
|
|
|
|
if (PtrVT == MVT::i32) {
|
|
RdhwrOpc = Mips::RDHWR;
|
|
SrcReg = Mips::HWR29;
|
|
DestReg = Mips::V1;
|
|
} else {
|
|
RdhwrOpc = Mips::RDHWR64;
|
|
SrcReg = Mips::HWR29_64;
|
|
DestReg = Mips::V1_64;
|
|
}
|
|
|
|
SDNode *Rdhwr =
|
|
CurDAG->getMachineNode(RdhwrOpc, Node->getDebugLoc(),
|
|
Node->getValueType(0),
|
|
CurDAG->getRegister(SrcReg, PtrVT));
|
|
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 ResNode.getNode();
|
|
}
|
|
}
|
|
|
|
// Select the default instruction
|
|
SDNode *ResNode = SelectCode(Node);
|
|
|
|
DEBUG(errs() << "=> ");
|
|
if (ResNode == NULL || ResNode == Node)
|
|
DEBUG(Node->dump(CurDAG));
|
|
else
|
|
DEBUG(ResNode->dump(CurDAG));
|
|
DEBUG(errs() << "\n");
|
|
return ResNode;
|
|
}
|
|
|
|
bool MipsDAGToDAGISel::
|
|
SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
|
|
std::vector<SDValue> &OutOps) {
|
|
assert(ConstraintCode == 'm' && "unexpected asm memory constraint");
|
|
OutOps.push_back(Op);
|
|
return false;
|
|
}
|
|
|
|
/// createMipsISelDag - This pass converts a legalized DAG into a
|
|
/// MIPS-specific DAG, ready for instruction scheduling.
|
|
FunctionPass *llvm::createMipsISelDag(MipsTargetMachine &TM) {
|
|
return new MipsDAGToDAGISel(TM);
|
|
}
|