mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
1707a88a2c
DoInstructionSelection. Inline "SelectRoot" into it from DAGISelHeader. Sink some other stuff out of DAGISelHeader into SDISel. Eliminate the various 'Indent' stuff from various targets, which dates to when isel was recursive. 17 files changed, 114 insertions(+), 430 deletions(-) llvm-svn: 97555
217 lines
7.4 KiB
C++
217 lines
7.4 KiB
C++
//===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
|
|
//
|
|
// 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 SPARC target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SparcISelLowering.h"
|
|
#include "SparcTargetMachine.h"
|
|
#include "llvm/Intrinsics.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Selector Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
|
|
/// instructions for SelectionDAG operations.
|
|
///
|
|
namespace {
|
|
class SparcDAGToDAGISel : public SelectionDAGISel {
|
|
/// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
|
|
/// make the right decision when generating code for different targets.
|
|
const SparcSubtarget &Subtarget;
|
|
SparcTargetMachine& TM;
|
|
public:
|
|
explicit SparcDAGToDAGISel(SparcTargetMachine &tm)
|
|
: SelectionDAGISel(tm),
|
|
Subtarget(tm.getSubtarget<SparcSubtarget>()),
|
|
TM(tm) {
|
|
}
|
|
|
|
SDNode *Select(SDNode *N);
|
|
|
|
// Complex Pattern Selectors.
|
|
bool SelectADDRrr(SDNode *Op, SDValue N, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRri(SDNode *Op, SDValue N, SDValue &Base,
|
|
SDValue &Offset);
|
|
|
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
|
/// inline asm expressions.
|
|
virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
|
|
char ConstraintCode,
|
|
std::vector<SDValue> &OutOps);
|
|
|
|
virtual const char *getPassName() const {
|
|
return "SPARC DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
// Include the pieces autogenerated from the target description.
|
|
#include "SparcGenDAGISel.inc"
|
|
|
|
private:
|
|
SDNode* getGlobalBaseReg();
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
|
|
MachineFunction *MF = BB->getParent();
|
|
unsigned GlobalBaseReg = TM.getInstrInfo()->getGlobalBaseReg(MF);
|
|
return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
|
|
}
|
|
|
|
bool SparcDAGToDAGISel::SelectADDRri(SDNode *Op, SDValue Addr,
|
|
SDValue &Base, SDValue &Offset) {
|
|
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // direct calls.
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
|
|
if (Predicate_simm13(CN)) {
|
|
if (FrameIndexSDNode *FIN =
|
|
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
|
|
// Constant offset from frame ref.
|
|
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
|
|
} else {
|
|
Base = Addr.getOperand(0);
|
|
}
|
|
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32);
|
|
return true;
|
|
}
|
|
}
|
|
if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
|
|
Base = Addr.getOperand(1);
|
|
Offset = Addr.getOperand(0).getOperand(0);
|
|
return true;
|
|
}
|
|
if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
|
|
Base = Addr.getOperand(0);
|
|
Offset = Addr.getOperand(1).getOperand(0);
|
|
return true;
|
|
}
|
|
}
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, MVT::i32);
|
|
return true;
|
|
}
|
|
|
|
bool SparcDAGToDAGISel::SelectADDRrr(SDNode *Op, SDValue Addr,
|
|
SDValue &R1, SDValue &R2) {
|
|
if (Addr.getOpcode() == ISD::FrameIndex) return false;
|
|
if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
|
Addr.getOpcode() == ISD::TargetGlobalAddress)
|
|
return false; // direct calls.
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
if (isa<ConstantSDNode>(Addr.getOperand(1)) &&
|
|
Predicate_simm13(Addr.getOperand(1).getNode()))
|
|
return false; // Let the reg+imm pattern catch this!
|
|
if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
|
|
Addr.getOperand(1).getOpcode() == SPISD::Lo)
|
|
return false; // Let the reg+imm pattern catch this!
|
|
R1 = Addr.getOperand(0);
|
|
R2 = Addr.getOperand(1);
|
|
return true;
|
|
}
|
|
|
|
R1 = Addr;
|
|
R2 = CurDAG->getRegister(SP::G0, MVT::i32);
|
|
return true;
|
|
}
|
|
|
|
SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
|
|
DebugLoc dl = N->getDebugLoc();
|
|
if (N->isMachineOpcode())
|
|
return NULL; // Already selected.
|
|
|
|
switch (N->getOpcode()) {
|
|
default: break;
|
|
case SPISD::GLOBAL_BASE_REG:
|
|
return getGlobalBaseReg();
|
|
|
|
case ISD::SDIV:
|
|
case ISD::UDIV: {
|
|
// FIXME: should use a custom expander to expose the SRA to the dag.
|
|
SDValue DivLHS = N->getOperand(0);
|
|
SDValue DivRHS = N->getOperand(1);
|
|
|
|
// Set the Y register to the high-part.
|
|
SDValue TopPart;
|
|
if (N->getOpcode() == ISD::SDIV) {
|
|
TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
|
|
CurDAG->getTargetConstant(31, MVT::i32)), 0);
|
|
} else {
|
|
TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
|
|
}
|
|
TopPart = SDValue(CurDAG->getMachineNode(SP::WRYrr, dl, MVT::Flag, TopPart,
|
|
CurDAG->getRegister(SP::G0, MVT::i32)), 0);
|
|
|
|
// FIXME: Handle div by immediate.
|
|
unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
|
|
return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS,
|
|
TopPart);
|
|
}
|
|
case ISD::MULHU:
|
|
case ISD::MULHS: {
|
|
// FIXME: Handle mul by immediate.
|
|
SDValue MulLHS = N->getOperand(0);
|
|
SDValue MulRHS = N->getOperand(1);
|
|
unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
|
|
SDNode *Mul = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Flag,
|
|
MulLHS, MulRHS);
|
|
// The high part is in the Y register.
|
|
return CurDAG->SelectNodeTo(N, SP::RDY, MVT::i32, SDValue(Mul, 1));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return SelectCode(N);
|
|
}
|
|
|
|
|
|
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
|
|
/// inline asm expressions.
|
|
bool
|
|
SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
|
|
char ConstraintCode,
|
|
std::vector<SDValue> &OutOps) {
|
|
SDValue Op0, Op1;
|
|
switch (ConstraintCode) {
|
|
default: return true;
|
|
case 'm': // memory
|
|
if (!SelectADDRrr(Op.getNode(), Op, Op0, Op1))
|
|
SelectADDRri(Op.getNode(), Op, Op0, Op1);
|
|
break;
|
|
}
|
|
|
|
OutOps.push_back(Op0);
|
|
OutOps.push_back(Op1);
|
|
return false;
|
|
}
|
|
|
|
/// createSparcISelDag - This pass converts a legalized DAG into a
|
|
/// SPARC-specific DAG, ready for instruction scheduling.
|
|
///
|
|
FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
|
|
return new SparcDAGToDAGISel(TM);
|
|
}
|