| //===-- R600InstPrinter.cpp - AMDGPU MC Inst -> ASM ---------------------===// | |
| // | |
| // 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 | |
| // | |
| // \file | |
| //===----------------------------------------------------------------------===// | |
| #include "R600InstPrinter.h" | |
| #include "AMDGPUInstPrinter.h" | |
| #include "R600MCTargetDesc.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstrInfo.h" | |
| #include "llvm/MC/MCSubtargetInfo.h" | |
| #include "llvm/Support/CommandLine.h" | |
| using namespace llvm; | |
| void R600InstPrinter::printInst(const MCInst *MI, uint64_t Address, | |
| StringRef Annot, const MCSubtargetInfo &STI, | |
| raw_ostream &O) { | |
| O.flush(); | |
| printInstruction(MI, Address, O); | |
| printAnnotation(O, Annot); | |
| } | |
| void R600InstPrinter::printAbs(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, '|'); | |
| } | |
| void R600InstPrinter::printBankSwizzle(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| int BankSwizzle = MI->getOperand(OpNo).getImm(); | |
| switch (BankSwizzle) { | |
| case 1: | |
| O << "BS:VEC_021/SCL_122"; | |
| break; | |
| case 2: | |
| O << "BS:VEC_120/SCL_212"; | |
| break; | |
| case 3: | |
| O << "BS:VEC_102/SCL_221"; | |
| break; | |
| case 4: | |
| O << "BS:VEC_201"; | |
| break; | |
| case 5: | |
| O << "BS:VEC_210"; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void R600InstPrinter::printClamp(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, "_SAT"); | |
| } | |
| void R600InstPrinter::printCT(const MCInst *MI, unsigned OpNo, raw_ostream &O) { | |
| unsigned CT = MI->getOperand(OpNo).getImm(); | |
| switch (CT) { | |
| case 0: | |
| O << 'U'; | |
| break; | |
| case 1: | |
| O << 'N'; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void R600InstPrinter::printKCache(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| int KCacheMode = MI->getOperand(OpNo).getImm(); | |
| if (KCacheMode > 0) { | |
| int KCacheBank = MI->getOperand(OpNo - 2).getImm(); | |
| O << "CB" << KCacheBank << ':'; | |
| int KCacheAddr = MI->getOperand(OpNo + 2).getImm(); | |
| int LineSize = (KCacheMode == 1) ? 16 : 32; | |
| O << KCacheAddr * 16 << '-' << KCacheAddr * 16 + LineSize; | |
| } | |
| } | |
| void R600InstPrinter::printLast(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, "*", " "); | |
| } | |
| void R600InstPrinter::printLiteral(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| const MCOperand &Op = MI->getOperand(OpNo); | |
| assert(Op.isImm() || Op.isExpr()); | |
| if (Op.isImm()) { | |
| int64_t Imm = Op.getImm(); | |
| O << Imm << '(' << BitsToFloat(Imm) << ')'; | |
| } | |
| if (Op.isExpr()) { | |
| Op.getExpr()->print(O << '@', &MAI); | |
| } | |
| } | |
| void R600InstPrinter::printNeg(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, '-'); | |
| } | |
| void R600InstPrinter::printOMOD(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| switch (MI->getOperand(OpNo).getImm()) { | |
| default: | |
| break; | |
| case 1: | |
| O << " * 2.0"; | |
| break; | |
| case 2: | |
| O << " * 4.0"; | |
| break; | |
| case 3: | |
| O << " / 2.0"; | |
| break; | |
| } | |
| } | |
| void R600InstPrinter::printMemOperand(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| printOperand(MI, OpNo, O); | |
| O << ", "; | |
| printOperand(MI, OpNo + 1, O); | |
| } | |
| void R600InstPrinter::printOperand(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| if (OpNo >= MI->getNumOperands()) { | |
| O << "/*Missing OP" << OpNo << "*/"; | |
| return; | |
| } | |
| const MCOperand &Op = MI->getOperand(OpNo); | |
| if (Op.isReg()) { | |
| switch (Op.getReg()) { | |
| // This is the default predicate state, so we don't need to print it. | |
| case R600::PRED_SEL_OFF: | |
| break; | |
| default: | |
| O << getRegisterName(Op.getReg()); | |
| break; | |
| } | |
| } else if (Op.isImm()) { | |
| O << Op.getImm(); | |
| } else if (Op.isDFPImm()) { | |
| // We special case 0.0 because otherwise it will be printed as an integer. | |
| if (Op.getDFPImm() == 0.0) | |
| O << "0.0"; | |
| else { | |
| O << bit_cast<double>(Op.getDFPImm()); | |
| } | |
| } else if (Op.isExpr()) { | |
| const MCExpr *Exp = Op.getExpr(); | |
| Exp->print(O, &MAI); | |
| } else { | |
| O << "/*INV_OP*/"; | |
| } | |
| } | |
| void R600InstPrinter::printRel(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, '+'); | |
| } | |
| void R600InstPrinter::printRSel(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| unsigned Sel = MI->getOperand(OpNo).getImm(); | |
| switch (Sel) { | |
| case 0: | |
| O << 'X'; | |
| break; | |
| case 1: | |
| O << 'Y'; | |
| break; | |
| case 2: | |
| O << 'Z'; | |
| break; | |
| case 3: | |
| O << 'W'; | |
| break; | |
| case 4: | |
| O << '0'; | |
| break; | |
| case 5: | |
| O << '1'; | |
| break; | |
| case 7: | |
| O << '_'; | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| void R600InstPrinter::printUpdateExecMask(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, "ExecMask,"); | |
| } | |
| void R600InstPrinter::printUpdatePred(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| AMDGPUInstPrinter::printIfSet(MI, OpNo, O, "Pred,"); | |
| } | |
| void R600InstPrinter::printWrite(const MCInst *MI, unsigned OpNo, | |
| raw_ostream &O) { | |
| const MCOperand &Op = MI->getOperand(OpNo); | |
| if (Op.getImm() == 0) { | |
| O << " (MASKED)"; | |
| } | |
| } | |
| #include "R600GenAsmWriter.inc" |