//===-- 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>(); }