//===-- 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/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define GET_INSTRUCTION_NAME
#include "PTXGenAsmWriter.inc"
PTXInstPrinter::PTXInstPrinter(const MCAsmInfo &MAI,
const MCSubtargetInfo &STI) :
MCInstPrinter(MAI) {
// Initialize the set of available features.
setAvailableFeatures(STI.getFeatureBits());
}
StringRef PTXInstPrinter::getOpcodeName(unsigned Opcode) const {
return getInstructionName(Opcode);
}
void PTXInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
OS << getRegisterName(RegNo);
}
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 << "), ";
}
O << *(MI->getOperand(Index++).getExpr()) << ", (";
unsigned NumArgs = MI->getOperand(Index++).getImm();
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 {
assert(Op.isExpr() && "unknown operand kind in printOperand");
const MCExpr *Expr = Op.getExpr();
if (const MCSymbolRefExpr *SymRefExpr = dyn_cast<MCSymbolRefExpr>(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!");
break;
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;
}
}