357 lines
10 KiB
C++
357 lines
10 KiB
C++
//===-- PTXISelDAGToDAG.cpp - A dag to dag inst selector for PTX ----------===//
|
|
//
|
|
// 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 PTX target.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "PTX.h"
|
|
#include "PTXMachineFunctionInfo.h"
|
|
#include "PTXTargetMachine.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/CodeGen/SelectionDAGISel.h"
|
|
#include "llvm/DerivedTypes.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
// PTXDAGToDAGISel - PTX specific code to select PTX machine
|
|
// instructions for SelectionDAG operations.
|
|
class PTXDAGToDAGISel : public SelectionDAGISel {
|
|
public:
|
|
PTXDAGToDAGISel(PTXTargetMachine &TM, CodeGenOpt::Level OptLevel);
|
|
|
|
virtual const char *getPassName() const {
|
|
return "PTX DAG->DAG Pattern Instruction Selection";
|
|
}
|
|
|
|
SDNode *Select(SDNode *Node);
|
|
|
|
// Complex Pattern Selectors.
|
|
bool SelectADDRrr(SDValue &Addr, SDValue &R1, SDValue &R2);
|
|
bool SelectADDRri(SDValue &Addr, SDValue &Base, SDValue &Offset);
|
|
bool SelectADDRii(SDValue &Addr, SDValue &Base, SDValue &Offset);
|
|
bool SelectADDRlocal(SDValue &Addr, SDValue &Base, SDValue &Offset);
|
|
|
|
// Include the pieces auto'gened from the target description
|
|
#include "PTXGenDAGISel.inc"
|
|
|
|
private:
|
|
// We need this only because we can't match intruction BRAdp
|
|
// pattern (PTXbrcond bb:$d, ...) in PTXInstrInfo.td
|
|
SDNode *SelectBRCOND(SDNode *Node);
|
|
|
|
SDNode *SelectREADPARAM(SDNode *Node);
|
|
SDNode *SelectWRITEPARAM(SDNode *Node);
|
|
SDNode *SelectFrameIndex(SDNode *Node);
|
|
|
|
bool isImm(const SDValue &operand);
|
|
bool SelectImm(const SDValue &operand, SDValue &imm);
|
|
|
|
const PTXSubtarget& getSubtarget() const;
|
|
}; // class PTXDAGToDAGISel
|
|
} // namespace
|
|
|
|
// createPTXISelDag - This pass converts a legalized DAG into a
|
|
// PTX-specific DAG, ready for instruction scheduling
|
|
FunctionPass *llvm::createPTXISelDag(PTXTargetMachine &TM,
|
|
CodeGenOpt::Level OptLevel) {
|
|
return new PTXDAGToDAGISel(TM, OptLevel);
|
|
}
|
|
|
|
PTXDAGToDAGISel::PTXDAGToDAGISel(PTXTargetMachine &TM,
|
|
CodeGenOpt::Level OptLevel)
|
|
: SelectionDAGISel(TM, OptLevel) {}
|
|
|
|
SDNode *PTXDAGToDAGISel::Select(SDNode *Node) {
|
|
switch (Node->getOpcode()) {
|
|
case ISD::BRCOND:
|
|
return SelectBRCOND(Node);
|
|
case PTXISD::READ_PARAM:
|
|
return SelectREADPARAM(Node);
|
|
case PTXISD::WRITE_PARAM:
|
|
return SelectWRITEPARAM(Node);
|
|
case ISD::FrameIndex:
|
|
return SelectFrameIndex(Node);
|
|
default:
|
|
return SelectCode(Node);
|
|
}
|
|
}
|
|
|
|
SDNode *PTXDAGToDAGISel::SelectBRCOND(SDNode *Node) {
|
|
assert(Node->getNumOperands() >= 3);
|
|
|
|
SDValue Chain = Node->getOperand(0);
|
|
SDValue Pred = Node->getOperand(1);
|
|
SDValue Target = Node->getOperand(2); // branch target
|
|
SDValue PredOp = CurDAG->getTargetConstant(PTXPredicate::Normal, MVT::i32);
|
|
DebugLoc dl = Node->getDebugLoc();
|
|
|
|
assert(Target.getOpcode() == ISD::BasicBlock);
|
|
assert(Pred.getValueType() == MVT::i1);
|
|
|
|
// Emit BRAdp
|
|
SDValue Ops[] = { Target, Pred, PredOp, Chain };
|
|
return CurDAG->getMachineNode(PTX::BRAdp, dl, MVT::Other, Ops, 4);
|
|
}
|
|
|
|
SDNode *PTXDAGToDAGISel::SelectREADPARAM(SDNode *Node) {
|
|
SDValue Chain = Node->getOperand(0);
|
|
SDValue Index = Node->getOperand(1);
|
|
|
|
int OpCode;
|
|
|
|
// Get the type of parameter we are reading
|
|
EVT VT = Node->getValueType(0);
|
|
assert(VT.isSimple() && "READ_PARAM only implemented for MVT types");
|
|
|
|
MVT Type = VT.getSimpleVT();
|
|
|
|
if (Type == MVT::i1)
|
|
OpCode = PTX::READPARAMPRED;
|
|
else if (Type == MVT::i16)
|
|
OpCode = PTX::READPARAMI16;
|
|
else if (Type == MVT::i32)
|
|
OpCode = PTX::READPARAMI32;
|
|
else if (Type == MVT::i64)
|
|
OpCode = PTX::READPARAMI64;
|
|
else if (Type == MVT::f32)
|
|
OpCode = PTX::READPARAMF32;
|
|
else {
|
|
assert(Type == MVT::f64 && "Unexpected type!");
|
|
OpCode = PTX::READPARAMF64;
|
|
}
|
|
|
|
SDValue Pred = CurDAG->getRegister(PTX::NoRegister, MVT::i1);
|
|
SDValue PredOp = CurDAG->getTargetConstant(PTXPredicate::None, MVT::i32);
|
|
DebugLoc dl = Node->getDebugLoc();
|
|
|
|
SDValue Ops[] = { Index, Pred, PredOp, Chain };
|
|
return CurDAG->getMachineNode(OpCode, dl, VT, Ops, 4);
|
|
}
|
|
|
|
SDNode *PTXDAGToDAGISel::SelectWRITEPARAM(SDNode *Node) {
|
|
|
|
SDValue Chain = Node->getOperand(0);
|
|
SDValue Value = Node->getOperand(1);
|
|
|
|
int OpCode;
|
|
|
|
//Node->dumpr(CurDAG);
|
|
|
|
// Get the type of parameter we are writing
|
|
EVT VT = Value->getValueType(0);
|
|
assert(VT.isSimple() && "WRITE_PARAM only implemented for MVT types");
|
|
|
|
MVT Type = VT.getSimpleVT();
|
|
|
|
if (Type == MVT::i1)
|
|
OpCode = PTX::WRITEPARAMPRED;
|
|
else if (Type == MVT::i16)
|
|
OpCode = PTX::WRITEPARAMI16;
|
|
else if (Type == MVT::i32)
|
|
OpCode = PTX::WRITEPARAMI32;
|
|
else if (Type == MVT::i64)
|
|
OpCode = PTX::WRITEPARAMI64;
|
|
else if (Type == MVT::f32)
|
|
OpCode = PTX::WRITEPARAMF32;
|
|
else if (Type == MVT::f64)
|
|
OpCode = PTX::WRITEPARAMF64;
|
|
else
|
|
llvm_unreachable("Invalid type in SelectWRITEPARAM");
|
|
|
|
SDValue Pred = CurDAG->getRegister(PTX::NoRegister, MVT::i1);
|
|
SDValue PredOp = CurDAG->getTargetConstant(PTXPredicate::None, MVT::i32);
|
|
DebugLoc dl = Node->getDebugLoc();
|
|
|
|
SDValue Ops[] = { Value, Pred, PredOp, Chain };
|
|
SDNode* Ret = CurDAG->getMachineNode(OpCode, dl, MVT::Other, Ops, 4);
|
|
|
|
//dbgs() << "SelectWRITEPARAM produced:\n\t";
|
|
//Ret->dumpr(CurDAG);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
SDNode *PTXDAGToDAGISel::SelectFrameIndex(SDNode *Node) {
|
|
int FI = cast<FrameIndexSDNode>(Node)->getIndex();
|
|
//dbgs() << "Selecting FrameIndex at index " << FI << "\n";
|
|
//SDValue TFI = CurDAG->getTargetFrameIndex(FI, Node->getValueType(0));
|
|
|
|
PTXMachineFunctionInfo *MFI = MF->getInfo<PTXMachineFunctionInfo>();
|
|
|
|
SDValue FrameSymbol = CurDAG->getTargetExternalSymbol(MFI->getFrameSymbol(FI),
|
|
Node->getValueType(0));
|
|
|
|
return FrameSymbol.getNode();
|
|
}
|
|
|
|
// Match memory operand of the form [reg+reg]
|
|
bool PTXDAGToDAGISel::SelectADDRrr(SDValue &Addr, SDValue &R1, SDValue &R2) {
|
|
if (Addr.getOpcode() != ISD::ADD || Addr.getNumOperands() < 2 ||
|
|
isImm(Addr.getOperand(0)) || isImm(Addr.getOperand(1)))
|
|
return false;
|
|
|
|
assert(Addr.getValueType().isSimple() && "Type must be simple");
|
|
|
|
R1 = Addr;
|
|
R2 = CurDAG->getTargetConstant(0, Addr.getValueType().getSimpleVT());
|
|
|
|
return true;
|
|
}
|
|
|
|
// Match memory operand of the form [reg], [imm+reg], and [reg+imm]
|
|
bool PTXDAGToDAGISel::SelectADDRri(SDValue &Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
// FrameIndex addresses are handled separately
|
|
//errs() << "SelectADDRri: ";
|
|
//Addr.getNode()->dumpr();
|
|
if (isa<FrameIndexSDNode>(Addr)) {
|
|
//errs() << "Failure\n";
|
|
return false;
|
|
}
|
|
|
|
if (CurDAG->isBaseWithConstantOffset(Addr)) {
|
|
Base = Addr.getOperand(0);
|
|
if (isa<FrameIndexSDNode>(Base)) {
|
|
//errs() << "Failure\n";
|
|
return false;
|
|
}
|
|
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
|
|
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32);
|
|
//errs() << "Success\n";
|
|
return true;
|
|
}
|
|
|
|
/*if (Addr.getNumOperands() == 1) {
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, Addr.getValueType().getSimpleVT());
|
|
errs() << "Success\n";
|
|
return true;
|
|
}*/
|
|
|
|
//errs() << "SelectADDRri fails on: ";
|
|
//Addr.getNode()->dumpr();
|
|
|
|
if (isImm(Addr)) {
|
|
//errs() << "Failure\n";
|
|
return false;
|
|
}
|
|
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, Addr.getValueType().getSimpleVT());
|
|
|
|
//errs() << "Success\n";
|
|
return true;
|
|
|
|
/*if (Addr.getOpcode() != ISD::ADD) {
|
|
// let SelectADDRii handle the [imm] case
|
|
if (isImm(Addr))
|
|
return false;
|
|
// it is [reg]
|
|
|
|
assert(Addr.getValueType().isSimple() && "Type must be simple");
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, Addr.getValueType().getSimpleVT());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (Addr.getNumOperands() < 2)
|
|
return false;
|
|
|
|
// let SelectADDRii handle the [imm+imm] case
|
|
if (isImm(Addr.getOperand(0)) && isImm(Addr.getOperand(1)))
|
|
return false;
|
|
|
|
// try [reg+imm] and [imm+reg]
|
|
for (int i = 0; i < 2; i ++)
|
|
if (SelectImm(Addr.getOperand(1-i), Offset)) {
|
|
Base = Addr.getOperand(i);
|
|
return true;
|
|
}
|
|
|
|
// neither [reg+imm] nor [imm+reg]
|
|
return false;*/
|
|
}
|
|
|
|
// Match memory operand of the form [imm+imm] and [imm]
|
|
bool PTXDAGToDAGISel::SelectADDRii(SDValue &Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
// is [imm+imm]?
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
return SelectImm(Addr.getOperand(0), Base) &&
|
|
SelectImm(Addr.getOperand(1), Offset);
|
|
}
|
|
|
|
// is [imm]?
|
|
if (SelectImm(Addr, Base)) {
|
|
assert(Addr.getValueType().isSimple() && "Type must be simple");
|
|
|
|
Offset = CurDAG->getTargetConstant(0, Addr.getValueType().getSimpleVT());
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Match memory operand of the form [reg], [imm+reg], and [reg+imm]
|
|
bool PTXDAGToDAGISel::SelectADDRlocal(SDValue &Addr, SDValue &Base,
|
|
SDValue &Offset) {
|
|
//errs() << "SelectADDRlocal: ";
|
|
//Addr.getNode()->dumpr();
|
|
if (isa<FrameIndexSDNode>(Addr)) {
|
|
Base = Addr;
|
|
Offset = CurDAG->getTargetConstant(0, Addr.getValueType().getSimpleVT());
|
|
//errs() << "Success\n";
|
|
return true;
|
|
}
|
|
|
|
if (CurDAG->isBaseWithConstantOffset(Addr)) {
|
|
Base = Addr.getOperand(0);
|
|
if (!isa<FrameIndexSDNode>(Base)) {
|
|
//errs() << "Failure\n";
|
|
return false;
|
|
}
|
|
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
|
|
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32);
|
|
//errs() << "Offset: ";
|
|
//Offset.getNode()->dumpr();
|
|
//errs() << "Success\n";
|
|
return true;
|
|
}
|
|
|
|
//errs() << "Failure\n";
|
|
return false;
|
|
}
|
|
|
|
bool PTXDAGToDAGISel::isImm(const SDValue &operand) {
|
|
return ConstantSDNode::classof(operand.getNode());
|
|
}
|
|
|
|
bool PTXDAGToDAGISel::SelectImm(const SDValue &operand, SDValue &imm) {
|
|
SDNode *node = operand.getNode();
|
|
if (!ConstantSDNode::classof(node))
|
|
return false;
|
|
|
|
ConstantSDNode *CN = cast<ConstantSDNode>(node);
|
|
imm = CurDAG->getTargetConstant(*CN->getConstantIntValue(),
|
|
operand.getValueType());
|
|
return true;
|
|
}
|
|
|
|
const PTXSubtarget& PTXDAGToDAGISel::getSubtarget() const
|
|
{
|
|
return TM.getSubtarget<PTXSubtarget>();
|
|
}
|
|
|