| //===- PTXInstrInfo.cpp - PTX Instruction Information ---------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file contains the PTX implementation of the TargetInstrInfo class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #define DEBUG_TYPE "ptx-instrinfo" |
| |
| #include "PTX.h" |
| #include "PTXInstrInfo.h" |
| #include "llvm/CodeGen/MachineInstrBuilder.h" |
| #include "llvm/CodeGen/MachineRegisterInfo.h" |
| #include "llvm/CodeGen/SelectionDAG.h" |
| #include "llvm/CodeGen/SelectionDAGNodes.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/TargetRegistry.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| #define GET_INSTRINFO_CTOR |
| #include "PTXGenInstrInfo.inc" |
| |
| using namespace llvm; |
| |
| PTXInstrInfo::PTXInstrInfo(PTXTargetMachine &_TM) |
| : PTXGenInstrInfo(), |
| RI(_TM, *this), TM(_TM) {} |
| |
| static const struct map_entry { |
| const TargetRegisterClass *cls; |
| const int opcode; |
| } map[] = { |
| { &PTX::RegI16RegClass, PTX::MOVU16rr }, |
| { &PTX::RegI32RegClass, PTX::MOVU32rr }, |
| { &PTX::RegI64RegClass, PTX::MOVU64rr }, |
| { &PTX::RegF32RegClass, PTX::MOVF32rr }, |
| { &PTX::RegF64RegClass, PTX::MOVF64rr }, |
| { &PTX::RegPredRegClass, PTX::MOVPREDrr } |
| }; |
| |
| void PTXInstrInfo::copyPhysReg(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator I, DebugLoc DL, |
| unsigned DstReg, unsigned SrcReg, |
| bool KillSrc) const { |
| |
| const MachineRegisterInfo& MRI = MBB.getParent()->getRegInfo(); |
| //assert(MRI.getRegClass(SrcReg) == MRI.getRegClass(DstReg) && |
| // "Invalid register copy between two register classes"); |
| |
| for (int i = 0, e = sizeof(map)/sizeof(map[0]); i != e; ++i) { |
| if (map[i].cls == MRI.getRegClass(DstReg)) { |
| const MCInstrDesc &MCID = get(map[i].opcode); |
| MachineInstr *MI = BuildMI(MBB, I, DL, MCID, DstReg). |
| addReg(SrcReg, getKillRegState(KillSrc)); |
| AddDefaultPredicate(MI); |
| return; |
| } |
| } |
| |
| llvm_unreachable("Impossible reg-to-reg copy"); |
| } |
| |
| bool PTXInstrInfo::copyRegToReg(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator I, |
| unsigned DstReg, unsigned SrcReg, |
| const TargetRegisterClass *DstRC, |
| const TargetRegisterClass *SrcRC, |
| DebugLoc DL) const { |
| if (DstRC != SrcRC) |
| return false; |
| |
| for (int i = 0, e = sizeof(map)/sizeof(map[0]); i != e; ++ i) |
| if (DstRC == map[i].cls) { |
| const MCInstrDesc &MCID = get(map[i].opcode); |
| MachineInstr *MI = BuildMI(MBB, I, DL, MCID, DstReg).addReg(SrcReg); |
| AddDefaultPredicate(MI); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool PTXInstrInfo::isMoveInstr(const MachineInstr& MI, |
| unsigned &SrcReg, unsigned &DstReg, |
| unsigned &SrcSubIdx, unsigned &DstSubIdx) const { |
| switch (MI.getOpcode()) { |
| default: |
| return false; |
| case PTX::MOVU16rr: |
| case PTX::MOVU32rr: |
| case PTX::MOVU64rr: |
| case PTX::MOVF32rr: |
| case PTX::MOVF64rr: |
| case PTX::MOVPREDrr: |
| assert(MI.getNumOperands() >= 2 && |
| MI.getOperand(0).isReg() && MI.getOperand(1).isReg() && |
| "Invalid register-register move instruction"); |
| SrcSubIdx = DstSubIdx = 0; // No sub-registers |
| DstReg = MI.getOperand(0).getReg(); |
| SrcReg = MI.getOperand(1).getReg(); |
| return true; |
| } |
| } |
| |
| // predicate support |
| |
| bool PTXInstrInfo::isPredicated(const MachineInstr *MI) const { |
| int i = MI->findFirstPredOperandIdx(); |
| return i != -1 && MI->getOperand(i).getReg() != PTX::NoRegister; |
| } |
| |
| bool PTXInstrInfo::isUnpredicatedTerminator(const MachineInstr *MI) const { |
| return !isPredicated(MI) && get(MI->getOpcode()).isTerminator(); |
| } |
| |
| bool PTXInstrInfo:: |
| PredicateInstruction(MachineInstr *MI, |
| const SmallVectorImpl<MachineOperand> &Pred) const { |
| if (Pred.size() < 2) |
| llvm_unreachable("lesser than 2 predicate operands are provided"); |
| |
| int i = MI->findFirstPredOperandIdx(); |
| if (i == -1) |
| llvm_unreachable("missing predicate operand"); |
| |
| MI->getOperand(i).setReg(Pred[0].getReg()); |
| MI->getOperand(i+1).setImm(Pred[1].getImm()); |
| |
| return true; |
| } |
| |
| bool PTXInstrInfo:: |
| SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1, |
| const SmallVectorImpl<MachineOperand> &Pred2) const { |
| const MachineOperand &PredReg1 = Pred1[0]; |
| const MachineOperand &PredReg2 = Pred2[0]; |
| if (PredReg1.getReg() != PredReg2.getReg()) |
| return false; |
| |
| const MachineOperand &PredOp1 = Pred1[1]; |
| const MachineOperand &PredOp2 = Pred2[1]; |
| if (PredOp1.getImm() != PredOp2.getImm()) |
| return false; |
| |
| return true; |
| } |
| |
| bool PTXInstrInfo:: |
| DefinesPredicate(MachineInstr *MI, |
| std::vector<MachineOperand> &Pred) const { |
| // If an instruction sets a predicate register, it defines a predicate. |
| |
| // TODO supprot 5-operand format of setp instruction |
| |
| if (MI->getNumOperands() < 1) |
| return false; |
| |
| const MachineOperand &MO = MI->getOperand(0); |
| |
| if (!MO.isReg() || RI.getRegClass(MO.getReg()) != &PTX::RegPredRegClass) |
| return false; |
| |
| Pred.push_back(MO); |
| Pred.push_back(MachineOperand::CreateImm(PTXPredicate::None)); |
| return true; |
| } |
| |
| // branch support |
| |
| bool PTXInstrInfo:: |
| AnalyzeBranch(MachineBasicBlock &MBB, |
| MachineBasicBlock *&TBB, |
| MachineBasicBlock *&FBB, |
| SmallVectorImpl<MachineOperand> &Cond, |
| bool AllowModify) const { |
| // TODO implement cases when AllowModify is true |
| |
| if (MBB.empty()) |
| return true; |
| |
| MachineBasicBlock::const_iterator iter = MBB.end(); |
| const MachineInstr& instLast1 = *--iter; |
| const MCInstrDesc &desc1 = instLast1.getDesc(); |
| // for special case that MBB has only 1 instruction |
| const bool IsSizeOne = MBB.size() == 1; |
| // if IsSizeOne is true, *--iter and instLast2 are invalid |
| // we put a dummy value in instLast2 and desc2 since they are used |
| const MachineInstr& instLast2 = IsSizeOne ? instLast1 : *--iter; |
| const MCInstrDesc &desc2 = IsSizeOne ? desc1 : instLast2.getDesc(); |
| |
| DEBUG(dbgs() << "\n"); |
| DEBUG(dbgs() << "AnalyzeBranch: opcode: " << instLast1.getOpcode() << "\n"); |
| DEBUG(dbgs() << "AnalyzeBranch: MBB: " << MBB.getName().str() << "\n"); |
| DEBUG(dbgs() << "AnalyzeBranch: TBB: " << TBB << "\n"); |
| DEBUG(dbgs() << "AnalyzeBranch: FBB: " << FBB << "\n"); |
| |
| // this block ends with no branches |
| if (!IsAnyKindOfBranch(instLast1)) { |
| DEBUG(dbgs() << "AnalyzeBranch: ends with no branch\n"); |
| return false; |
| } |
| |
| // this block ends with only an unconditional branch |
| if (desc1.isUnconditionalBranch() && |
| // when IsSizeOne is true, it "absorbs" the evaluation of instLast2 |
| (IsSizeOne || !IsAnyKindOfBranch(instLast2))) { |
| DEBUG(dbgs() << "AnalyzeBranch: ends with only uncond branch\n"); |
| TBB = GetBranchTarget(instLast1); |
| return false; |
| } |
| |
| // this block ends with a conditional branch and |
| // it falls through to a successor block |
| if (desc1.isConditionalBranch() && |
| IsAnySuccessorAlsoLayoutSuccessor(MBB)) { |
| DEBUG(dbgs() << "AnalyzeBranch: ends with cond branch and fall through\n"); |
| TBB = GetBranchTarget(instLast1); |
| int i = instLast1.findFirstPredOperandIdx(); |
| Cond.push_back(instLast1.getOperand(i)); |
| Cond.push_back(instLast1.getOperand(i+1)); |
| return false; |
| } |
| |
| // when IsSizeOne is true, we are done |
| if (IsSizeOne) |
| return true; |
| |
| // this block ends with a conditional branch |
| // followed by an unconditional branch |
| if (desc2.isConditionalBranch() && |
| desc1.isUnconditionalBranch()) { |
| DEBUG(dbgs() << "AnalyzeBranch: ends with cond and uncond branch\n"); |
| TBB = GetBranchTarget(instLast2); |
| FBB = GetBranchTarget(instLast1); |
| int i = instLast2.findFirstPredOperandIdx(); |
| Cond.push_back(instLast2.getOperand(i)); |
| Cond.push_back(instLast2.getOperand(i+1)); |
| return false; |
| } |
| |
| // branch cannot be understood |
| DEBUG(dbgs() << "AnalyzeBranch: cannot be understood\n"); |
| return true; |
| } |
| |
| unsigned PTXInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const { |
| unsigned count = 0; |
| while (!MBB.empty()) |
| if (IsAnyKindOfBranch(MBB.back())) { |
| MBB.pop_back(); |
| ++count; |
| } else |
| break; |
| DEBUG(dbgs() << "RemoveBranch: MBB: " << MBB.getName().str() << "\n"); |
| DEBUG(dbgs() << "RemoveBranch: remove " << count << " branch inst\n"); |
| return count; |
| } |
| |
| unsigned PTXInstrInfo:: |
| InsertBranch(MachineBasicBlock &MBB, |
| MachineBasicBlock *TBB, |
| MachineBasicBlock *FBB, |
| const SmallVectorImpl<MachineOperand> &Cond, |
| DebugLoc DL) const { |
| DEBUG(dbgs() << "InsertBranch: MBB: " << MBB.getName().str() << "\n"); |
| DEBUG(if (TBB) dbgs() << "InsertBranch: TBB: " << TBB->getName().str() |
| << "\n"; |
| else dbgs() << "InsertBranch: TBB: (NULL)\n"); |
| DEBUG(if (FBB) dbgs() << "InsertBranch: FBB: " << FBB->getName().str() |
| << "\n"; |
| else dbgs() << "InsertBranch: FBB: (NULL)\n"); |
| DEBUG(dbgs() << "InsertBranch: Cond size: " << Cond.size() << "\n"); |
| |
| assert(TBB && "TBB is NULL"); |
| |
| if (FBB) { |
| BuildMI(&MBB, DL, get(PTX::BRAdp)) |
| .addMBB(TBB).addReg(Cond[0].getReg()).addImm(Cond[1].getImm()); |
| BuildMI(&MBB, DL, get(PTX::BRAd)) |
| .addMBB(FBB).addReg(PTX::NoRegister).addImm(PTXPredicate::None); |
| return 2; |
| } else if (Cond.size()) { |
| BuildMI(&MBB, DL, get(PTX::BRAdp)) |
| .addMBB(TBB).addReg(Cond[0].getReg()).addImm(Cond[1].getImm()); |
| return 1; |
| } else { |
| BuildMI(&MBB, DL, get(PTX::BRAd)) |
| .addMBB(TBB).addReg(PTX::NoRegister).addImm(PTXPredicate::None); |
| return 1; |
| } |
| } |
| |
| // Memory operand folding for spills |
| void PTXInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MII, |
| unsigned SrcReg, bool isKill, int FrameIdx, |
| const TargetRegisterClass *RC, |
| const TargetRegisterInfo *TRI) const { |
| assert(false && "storeRegToStackSlot should not be called for PTX"); |
| } |
| |
| void PTXInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, |
| MachineBasicBlock::iterator MII, |
| unsigned DestReg, int FrameIdx, |
| const TargetRegisterClass *RC, |
| const TargetRegisterInfo *TRI) const { |
| assert(false && "loadRegFromStackSlot should not be called for PTX"); |
| } |
| |
| // static helper routines |
| |
| MachineSDNode *PTXInstrInfo:: |
| GetPTXMachineNode(SelectionDAG *DAG, unsigned Opcode, |
| DebugLoc dl, EVT VT, SDValue Op1) { |
| SDValue predReg = DAG->getRegister(PTX::NoRegister, MVT::i1); |
| SDValue predOp = DAG->getTargetConstant(PTXPredicate::None, MVT::i32); |
| SDValue ops[] = { Op1, predReg, predOp }; |
| return DAG->getMachineNode(Opcode, dl, VT, ops, array_lengthof(ops)); |
| } |
| |
| MachineSDNode *PTXInstrInfo:: |
| GetPTXMachineNode(SelectionDAG *DAG, unsigned Opcode, |
| DebugLoc dl, EVT VT, SDValue Op1, SDValue Op2) { |
| SDValue predReg = DAG->getRegister(PTX::NoRegister, MVT::i1); |
| SDValue predOp = DAG->getTargetConstant(PTXPredicate::None, MVT::i32); |
| SDValue ops[] = { Op1, Op2, predReg, predOp }; |
| return DAG->getMachineNode(Opcode, dl, VT, ops, array_lengthof(ops)); |
| } |
| |
| void PTXInstrInfo::AddDefaultPredicate(MachineInstr *MI) { |
| if (MI->findFirstPredOperandIdx() == -1) { |
| MI->addOperand(MachineOperand::CreateReg(PTX::NoRegister, /*IsDef=*/false)); |
| MI->addOperand(MachineOperand::CreateImm(PTXPredicate::None)); |
| } |
| } |
| |
| bool PTXInstrInfo::IsAnyKindOfBranch(const MachineInstr& inst) { |
| const MCInstrDesc &desc = inst.getDesc(); |
| return desc.isTerminator() || desc.isBranch() || desc.isIndirectBranch(); |
| } |
| |
| bool PTXInstrInfo:: |
| IsAnySuccessorAlsoLayoutSuccessor(const MachineBasicBlock& MBB) { |
| for (MachineBasicBlock::const_succ_iterator |
| i = MBB.succ_begin(), e = MBB.succ_end(); i != e; ++i) |
| if (MBB.isLayoutSuccessor((const MachineBasicBlock*) &*i)) |
| return true; |
| return false; |
| } |
| |
| MachineBasicBlock *PTXInstrInfo::GetBranchTarget(const MachineInstr& inst) { |
| // FIXME So far all branch instructions put destination in 1st operand |
| const MachineOperand& target = inst.getOperand(0); |
| assert(target.isMBB() && "FIXME: detect branch target operand"); |
| return target.getMBB(); |
| } |