PTX 6.3 requires using ".aligned" in the MMA instruction names. In order to generate correct name, now we pass current PTX version to each instruction as an extra constant operand and InstPrinter adjusts its output accordingly. Differential Revision: https://reviews.llvm.org/D59393 llvm-svn: 359246
310 lines
8.4 KiB
C++
310 lines
8.4 KiB
C++
//===-- NVPTXInstPrinter.cpp - PTX assembly instruction printing ----------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Print MCInst instructions to .ptx format.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "InstPrinter/NVPTXInstPrinter.h"
|
|
#include "MCTargetDesc/NVPTXBaseInfo.h"
|
|
#include "NVPTX.h"
|
|
#include "llvm/MC/MCExpr.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/Support/FormattedStream.h"
|
|
#include <cctype>
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "asm-printer"
|
|
|
|
#include "NVPTXGenAsmWriter.inc"
|
|
|
|
NVPTXInstPrinter::NVPTXInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
|
|
const MCRegisterInfo &MRI)
|
|
: MCInstPrinter(MAI, MII, MRI) {}
|
|
|
|
void NVPTXInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
|
|
// Decode the virtual register
|
|
// Must be kept in sync with NVPTXAsmPrinter::encodeVirtualRegister
|
|
unsigned RCId = (RegNo >> 28);
|
|
switch (RCId) {
|
|
default: report_fatal_error("Bad virtual register encoding");
|
|
case 0:
|
|
// This is actually a physical register, so defer to the autogenerated
|
|
// register printer
|
|
OS << getRegisterName(RegNo);
|
|
return;
|
|
case 1:
|
|
OS << "%p";
|
|
break;
|
|
case 2:
|
|
OS << "%rs";
|
|
break;
|
|
case 3:
|
|
OS << "%r";
|
|
break;
|
|
case 4:
|
|
OS << "%rd";
|
|
break;
|
|
case 5:
|
|
OS << "%f";
|
|
break;
|
|
case 6:
|
|
OS << "%fd";
|
|
break;
|
|
case 7:
|
|
OS << "%h";
|
|
break;
|
|
case 8:
|
|
OS << "%hh";
|
|
break;
|
|
}
|
|
|
|
unsigned VReg = RegNo & 0x0FFFFFFF;
|
|
OS << VReg;
|
|
}
|
|
|
|
void NVPTXInstPrinter::printInst(const MCInst *MI, raw_ostream &OS,
|
|
StringRef Annot, const MCSubtargetInfo &STI) {
|
|
printInstruction(MI, OS);
|
|
|
|
// Next always print the annotation.
|
|
printAnnotation(OS, Annot);
|
|
}
|
|
|
|
void NVPTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
|
|
raw_ostream &O) {
|
|
const MCOperand &Op = MI->getOperand(OpNo);
|
|
if (Op.isReg()) {
|
|
unsigned Reg = Op.getReg();
|
|
printRegName(O, Reg);
|
|
} else if (Op.isImm()) {
|
|
O << markup("<imm:") << formatImm(Op.getImm()) << markup(">");
|
|
} else {
|
|
assert(Op.isExpr() && "Unknown operand kind in printOperand");
|
|
Op.getExpr()->print(O, &MAI);
|
|
}
|
|
}
|
|
|
|
void NVPTXInstPrinter::printCvtMode(const MCInst *MI, int OpNum, raw_ostream &O,
|
|
const char *Modifier) {
|
|
const MCOperand &MO = MI->getOperand(OpNum);
|
|
int64_t Imm = MO.getImm();
|
|
|
|
if (strcmp(Modifier, "ftz") == 0) {
|
|
// FTZ flag
|
|
if (Imm & NVPTX::PTXCvtMode::FTZ_FLAG)
|
|
O << ".ftz";
|
|
} else if (strcmp(Modifier, "sat") == 0) {
|
|
// SAT flag
|
|
if (Imm & NVPTX::PTXCvtMode::SAT_FLAG)
|
|
O << ".sat";
|
|
} else if (strcmp(Modifier, "base") == 0) {
|
|
// Default operand
|
|
switch (Imm & NVPTX::PTXCvtMode::BASE_MASK) {
|
|
default:
|
|
return;
|
|
case NVPTX::PTXCvtMode::NONE:
|
|
break;
|
|
case NVPTX::PTXCvtMode::RNI:
|
|
O << ".rni";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RZI:
|
|
O << ".rzi";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RMI:
|
|
O << ".rmi";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RPI:
|
|
O << ".rpi";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RN:
|
|
O << ".rn";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RZ:
|
|
O << ".rz";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RM:
|
|
O << ".rm";
|
|
break;
|
|
case NVPTX::PTXCvtMode::RP:
|
|
O << ".rp";
|
|
break;
|
|
}
|
|
} else {
|
|
llvm_unreachable("Invalid conversion modifier");
|
|
}
|
|
}
|
|
|
|
void NVPTXInstPrinter::printCmpMode(const MCInst *MI, int OpNum, raw_ostream &O,
|
|
const char *Modifier) {
|
|
const MCOperand &MO = MI->getOperand(OpNum);
|
|
int64_t Imm = MO.getImm();
|
|
|
|
if (strcmp(Modifier, "ftz") == 0) {
|
|
// FTZ flag
|
|
if (Imm & NVPTX::PTXCmpMode::FTZ_FLAG)
|
|
O << ".ftz";
|
|
} else if (strcmp(Modifier, "base") == 0) {
|
|
switch (Imm & NVPTX::PTXCmpMode::BASE_MASK) {
|
|
default:
|
|
return;
|
|
case NVPTX::PTXCmpMode::EQ:
|
|
O << ".eq";
|
|
break;
|
|
case NVPTX::PTXCmpMode::NE:
|
|
O << ".ne";
|
|
break;
|
|
case NVPTX::PTXCmpMode::LT:
|
|
O << ".lt";
|
|
break;
|
|
case NVPTX::PTXCmpMode::LE:
|
|
O << ".le";
|
|
break;
|
|
case NVPTX::PTXCmpMode::GT:
|
|
O << ".gt";
|
|
break;
|
|
case NVPTX::PTXCmpMode::GE:
|
|
O << ".ge";
|
|
break;
|
|
case NVPTX::PTXCmpMode::LO:
|
|
O << ".lo";
|
|
break;
|
|
case NVPTX::PTXCmpMode::LS:
|
|
O << ".ls";
|
|
break;
|
|
case NVPTX::PTXCmpMode::HI:
|
|
O << ".hi";
|
|
break;
|
|
case NVPTX::PTXCmpMode::HS:
|
|
O << ".hs";
|
|
break;
|
|
case NVPTX::PTXCmpMode::EQU:
|
|
O << ".equ";
|
|
break;
|
|
case NVPTX::PTXCmpMode::NEU:
|
|
O << ".neu";
|
|
break;
|
|
case NVPTX::PTXCmpMode::LTU:
|
|
O << ".ltu";
|
|
break;
|
|
case NVPTX::PTXCmpMode::LEU:
|
|
O << ".leu";
|
|
break;
|
|
case NVPTX::PTXCmpMode::GTU:
|
|
O << ".gtu";
|
|
break;
|
|
case NVPTX::PTXCmpMode::GEU:
|
|
O << ".geu";
|
|
break;
|
|
case NVPTX::PTXCmpMode::NUM:
|
|
O << ".num";
|
|
break;
|
|
case NVPTX::PTXCmpMode::NotANumber:
|
|
O << ".nan";
|
|
break;
|
|
}
|
|
} else {
|
|
llvm_unreachable("Empty Modifier");
|
|
}
|
|
}
|
|
|
|
void NVPTXInstPrinter::printLdStCode(const MCInst *MI, int OpNum,
|
|
raw_ostream &O, const char *Modifier) {
|
|
if (Modifier) {
|
|
const MCOperand &MO = MI->getOperand(OpNum);
|
|
int Imm = (int) MO.getImm();
|
|
if (!strcmp(Modifier, "volatile")) {
|
|
if (Imm)
|
|
O << ".volatile";
|
|
} else if (!strcmp(Modifier, "addsp")) {
|
|
switch (Imm) {
|
|
case NVPTX::PTXLdStInstCode::GLOBAL:
|
|
O << ".global";
|
|
break;
|
|
case NVPTX::PTXLdStInstCode::SHARED:
|
|
O << ".shared";
|
|
break;
|
|
case NVPTX::PTXLdStInstCode::LOCAL:
|
|
O << ".local";
|
|
break;
|
|
case NVPTX::PTXLdStInstCode::PARAM:
|
|
O << ".param";
|
|
break;
|
|
case NVPTX::PTXLdStInstCode::CONSTANT:
|
|
O << ".const";
|
|
break;
|
|
case NVPTX::PTXLdStInstCode::GENERIC:
|
|
break;
|
|
default:
|
|
llvm_unreachable("Wrong Address Space");
|
|
}
|
|
} else if (!strcmp(Modifier, "sign")) {
|
|
if (Imm == NVPTX::PTXLdStInstCode::Signed)
|
|
O << "s";
|
|
else if (Imm == NVPTX::PTXLdStInstCode::Unsigned)
|
|
O << "u";
|
|
else if (Imm == NVPTX::PTXLdStInstCode::Untyped)
|
|
O << "b";
|
|
else if (Imm == NVPTX::PTXLdStInstCode::Float)
|
|
O << "f";
|
|
else
|
|
llvm_unreachable("Unknown register type");
|
|
} else if (!strcmp(Modifier, "vec")) {
|
|
if (Imm == NVPTX::PTXLdStInstCode::V2)
|
|
O << ".v2";
|
|
else if (Imm == NVPTX::PTXLdStInstCode::V4)
|
|
O << ".v4";
|
|
} else
|
|
llvm_unreachable("Unknown Modifier");
|
|
} else
|
|
llvm_unreachable("Empty Modifier");
|
|
}
|
|
|
|
void NVPTXInstPrinter::printMmaCode(const MCInst *MI, int OpNum, raw_ostream &O,
|
|
const char *Modifier) {
|
|
const MCOperand &MO = MI->getOperand(OpNum);
|
|
int Imm = (int)MO.getImm();
|
|
if (Modifier == nullptr || strcmp(Modifier, "version") == 0) {
|
|
O << Imm; // Just print out PTX version
|
|
} else if (strcmp(Modifier, "aligned") == 0) {
|
|
// PTX63 requires '.aligned' in the name of the instruction.
|
|
if (Imm >= 63)
|
|
O << ".aligned";
|
|
} else
|
|
llvm_unreachable("Unknown Modifier");
|
|
}
|
|
|
|
void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum,
|
|
raw_ostream &O, const char *Modifier) {
|
|
printOperand(MI, OpNum, O);
|
|
|
|
if (Modifier && !strcmp(Modifier, "add")) {
|
|
O << ", ";
|
|
printOperand(MI, OpNum + 1, O);
|
|
} else {
|
|
if (MI->getOperand(OpNum + 1).isImm() &&
|
|
MI->getOperand(OpNum + 1).getImm() == 0)
|
|
return; // don't print ',0' or '+0'
|
|
O << "+";
|
|
printOperand(MI, OpNum + 1, O);
|
|
}
|
|
}
|
|
|
|
void NVPTXInstPrinter::printProtoIdent(const MCInst *MI, int OpNum,
|
|
raw_ostream &O, const char *Modifier) {
|
|
const MCOperand &Op = MI->getOperand(OpNum);
|
|
assert(Op.isExpr() && "Call prototype is not an MCExpr?");
|
|
const MCExpr *Expr = Op.getExpr();
|
|
const MCSymbol &Sym = cast<MCSymbolRefExpr>(Expr)->getSymbol();
|
|
O << Sym.getName();
|
|
}
|