250 lines
6.5 KiB
C++
250 lines
6.5 KiB
C++
|
//===-- 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<MCSymbolRefExpr>(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<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!");
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|