to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
296 lines
7.8 KiB
C++
296 lines
7.8 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::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();
|
|
}
|