text: //===-- 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 "MCTargetDesc/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, uint64_t Address,
                                   StringRef Annot, const MCSubtargetInfo &STI,
                                   raw_ostream &OS) {
    printInstruction(MI, Address, 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();
  }
  