|  | //===-- NVPTXInstPrinter.cpp - PTX assembly instruction printing ----------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // 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(); | 
|  | } |