//===-- PTXInstPrinter.cpp - Convert PTX MCInst to assembly syntax --------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class prints a PTX MCInst to a .ptx file. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "asm-printer" #include "PTXInstPrinter.h" #include "MCTargetDesc/PTXBaseInfo.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; #include "PTXGenAsmWriter.inc" PTXInstPrinter::PTXInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI, const MCSubtargetInfo &STI) : MCInstPrinter(MAI, MII, MRI) { // Initialize the set of available features. setAvailableFeatures(STI.getFeatureBits()); } void PTXInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { // Decode the register number into type and offset unsigned RegSpace = RegNo & 0x7; unsigned RegType = (RegNo >> 3) & 0x7; unsigned RegOffset = RegNo >> 6; // Print the register OS << "%"; switch (RegSpace) { default: llvm_unreachable("Unknown register space!"); case PTXRegisterSpace::Reg: switch (RegType) { default: llvm_unreachable("Unknown register type!"); case PTXRegisterType::Pred: OS << "p"; break; case PTXRegisterType::B16: OS << "rh"; break; case PTXRegisterType::B32: OS << "r"; break; case PTXRegisterType::B64: OS << "rd"; break; case PTXRegisterType::F32: OS << "f"; break; case PTXRegisterType::F64: OS << "fd"; break; } break; case PTXRegisterSpace::Return: OS << "ret"; break; case PTXRegisterSpace::Argument: OS << "arg"; break; } OS << RegOffset; } void PTXInstPrinter::printInst(const MCInst *MI, raw_ostream &O, StringRef Annot) { printPredicate(MI, O); switch (MI->getOpcode()) { default: printInstruction(MI, O); break; case PTX::CALL: printCall(MI, O); } O << ";"; printAnnotation(O, Annot); } void PTXInstPrinter::printPredicate(const MCInst *MI, raw_ostream &O) { // The last two operands are the predicate operands int RegIndex; int OpIndex; if (MI->getOpcode() == PTX::CALL) { RegIndex = 0; OpIndex = 1; } else { RegIndex = MI->getNumOperands()-2; OpIndex = MI->getNumOperands()-1; } int PredOp = MI->getOperand(OpIndex).getImm(); if (PredOp == PTXPredicate::None) return; if (PredOp == PTXPredicate::Negate) O << '!'; else O << '@'; printOperand(MI, RegIndex, O); } void PTXInstPrinter::printCall(const MCInst *MI, raw_ostream &O) { O << "\tcall.uni\t"; // The first two operands are the predicate slot unsigned Index = 2; unsigned NumRets = MI->getOperand(Index++).getImm(); if (NumRets > 0) { O << "("; printOperand(MI, Index++, O); for (unsigned i = 1; i < NumRets; ++i) { O << ", "; printOperand(MI, Index++, O); } O << "), "; } const MCExpr* Expr = MI->getOperand(Index++).getExpr(); unsigned NumArgs = MI->getOperand(Index++).getImm(); // if the function call is to printf or puts, change to vprintf if (const MCSymbolRefExpr *SymRefExpr = dyn_cast(Expr)) { const MCSymbol &Sym = SymRefExpr->getSymbol(); if (Sym.getName() == "printf" || Sym.getName() == "puts") { O << "vprintf"; } else { O << Sym.getName(); } } else { O << *Expr; } O << ", ("; if (NumArgs > 0) { printOperand(MI, Index++, O); for (unsigned i = 1; i < NumArgs; ++i) { O << ", "; printOperand(MI, Index++, O); } } O << ")"; } void PTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNo); if (Op.isImm()) { O << Op.getImm(); } else if (Op.isFPImm()) { double Imm = Op.getFPImm(); APFloat FPImm(Imm); APInt FPIntImm = FPImm.bitcastToAPInt(); O << "0D"; // PTX requires us to output the full 64 bits, even if the number is zero if (FPIntImm.getZExtValue() > 0) { O << FPIntImm.toString(16, false); } else { O << "0000000000000000"; } } else if (Op.isReg()) { printRegName(O, Op.getReg()); } else { assert(Op.isExpr() && "unknown operand kind in printOperand"); const MCExpr *Expr = Op.getExpr(); if (const MCSymbolRefExpr *SymRefExpr = dyn_cast(Expr)) { const MCSymbol &Sym = SymRefExpr->getSymbol(); O << Sym.getName(); } else { O << *Op.getExpr(); } } } void PTXInstPrinter::printMemOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { // By definition, operand OpNo+1 is an i32imm const MCOperand &Op2 = MI->getOperand(OpNo+1); printOperand(MI, OpNo, O); if (Op2.getImm() == 0) return; // don't print "+0" O << "+" << Op2.getImm(); } void PTXInstPrinter::printRoundingMode(const MCInst *MI, unsigned OpNo, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNo); assert (Op.isImm() && "Rounding modes must be immediate values"); switch (Op.getImm()) { default: llvm_unreachable("Unknown rounding mode!"); case PTXRoundingMode::RndDefault: llvm_unreachable("FP rounding-mode pass did not handle instruction!"); case PTXRoundingMode::RndNone: // Do not print anything. break; case PTXRoundingMode::RndNearestEven: O << ".rn"; break; case PTXRoundingMode::RndTowardsZero: O << ".rz"; break; case PTXRoundingMode::RndNegInf: O << ".rm"; break; case PTXRoundingMode::RndPosInf: O << ".rp"; break; case PTXRoundingMode::RndApprox: O << ".approx"; break; case PTXRoundingMode::RndNearestEvenInt: O << ".rni"; break; case PTXRoundingMode::RndTowardsZeroInt: O << ".rzi"; break; case PTXRoundingMode::RndNegInfInt: O << ".rmi"; break; case PTXRoundingMode::RndPosInfInt: O << ".rpi"; break; } }