#include "SPIRVInstPrinter.h"
#include "SPIRV.h"
#include "SPIRVBaseInfo.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
#define DEBUG_TYPE "asm-printer"
#include "SPIRVGenAsmWriter.inc"
void SPIRVInstPrinter::printRemainingVariableOps(const MCInst *MI,
unsigned StartIndex,
raw_ostream &O,
bool SkipFirstSpace,
bool SkipImmediates) {
const unsigned NumOps = MI->getNumOperands();
for (unsigned i = StartIndex; i < NumOps; ++i) {
if (!SkipImmediates || !MI->getOperand(i).isImm()) {
if (!SkipFirstSpace || i != StartIndex)
O << ' ';
printOperand(MI, i, O);
}
}
}
void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI,
unsigned StartIndex,
raw_ostream &O) {
O << ' ';
if (MI->getNumOperands() - StartIndex == 2) { uint64_t Imm = MI->getOperand(StartIndex).getImm();
Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
O << Imm;
} else {
printRemainingVariableOps(MI, StartIndex, O, true, false);
}
}
void SPIRVInstPrinter::recordOpExtInstImport(const MCInst *MI) {
}
void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address,
StringRef Annot, const MCSubtargetInfo &STI,
raw_ostream &OS) {
const unsigned OpCode = MI->getOpcode();
printInstruction(MI, Address, OS);
if (OpCode == SPIRV::OpDecorate) {
printOpDecorate(MI, OS);
} else if (OpCode == SPIRV::OpExtInstImport) {
recordOpExtInstImport(MI);
} else if (OpCode == SPIRV::OpExtInst) {
printOpExtInst(MI, OS);
} else {
MCInstrDesc MCDesc = MII.get(OpCode);
if (MCDesc.isVariadic()) {
const unsigned NumFixedOps = MCDesc.getNumOperands();
const unsigned LastFixedIndex = NumFixedOps - 1;
const int FirstVariableIndex = NumFixedOps;
if (NumFixedOps > 0 &&
MCDesc.OpInfo[LastFixedIndex].OperandType == MCOI::OPERAND_UNKNOWN) {
switch (OpCode) {
case SPIRV::OpTypeImage:
OS << ' ';
printAccessQualifier(MI, FirstVariableIndex, OS);
break;
case SPIRV::OpVariable:
OS << ' ';
printOperand(MI, FirstVariableIndex, OS);
break;
case SPIRV::OpEntryPoint: {
printRemainingVariableOps(MI, NumFixedOps, OS, false, true);
break;
}
case SPIRV::OpExecutionMode:
case SPIRV::OpExecutionModeId:
case SPIRV::OpLoopMerge: {
printRemainingVariableOps(MI, NumFixedOps, OS);
break;
}
default:
break; }
} else {
switch (OpCode) {
case SPIRV::OpLoad:
case SPIRV::OpStore:
OS << ' ';
printMemoryOperand(MI, FirstVariableIndex, OS);
printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
break;
case SPIRV::OpImageSampleImplicitLod:
case SPIRV::OpImageSampleDrefImplicitLod:
case SPIRV::OpImageSampleProjImplicitLod:
case SPIRV::OpImageSampleProjDrefImplicitLod:
case SPIRV::OpImageFetch:
case SPIRV::OpImageGather:
case SPIRV::OpImageDrefGather:
case SPIRV::OpImageRead:
case SPIRV::OpImageWrite:
case SPIRV::OpImageSparseSampleImplicitLod:
case SPIRV::OpImageSparseSampleDrefImplicitLod:
case SPIRV::OpImageSparseSampleProjImplicitLod:
case SPIRV::OpImageSparseSampleProjDrefImplicitLod:
case SPIRV::OpImageSparseFetch:
case SPIRV::OpImageSparseGather:
case SPIRV::OpImageSparseDrefGather:
case SPIRV::OpImageSparseRead:
case SPIRV::OpImageSampleFootprintNV:
OS << ' ';
printImageOperand(MI, FirstVariableIndex, OS);
printRemainingVariableOps(MI, NumFixedOps + 1, OS);
break;
case SPIRV::OpCopyMemory:
case SPIRV::OpCopyMemorySized: {
const unsigned NumOps = MI->getNumOperands();
for (unsigned i = NumFixedOps; i < NumOps; ++i) {
OS << ' ';
printMemoryOperand(MI, i, OS);
if (MI->getOperand(i).getImm() &
static_cast<unsigned>(SPIRV::MemoryOperand::Aligned)) {
assert(i + 1 < NumOps && "Missing alignment operand");
OS << ' ';
printOperand(MI, i + 1, OS);
i += 1;
}
}
break;
}
case SPIRV::OpConstantI:
case SPIRV::OpConstantF:
printOpConstantVarOps(MI, NumFixedOps, OS);
break;
default:
printRemainingVariableOps(MI, NumFixedOps, OS);
break;
}
}
}
}
printAnnotation(OS, Annot);
}
void SPIRVInstPrinter::printOpExtInst(const MCInst *MI, raw_ostream &O) {
MCInstrDesc MCDesc = MII.get(MI->getOpcode());
unsigned NumFixedOps = MCDesc.getNumOperands();
const auto NumOps = MI->getNumOperands();
if (NumOps == NumFixedOps)
return;
O << ' ';
printRemainingVariableOps(MI, NumFixedOps, O, true);
}
void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) {
MCInstrDesc MCDesc = MII.get(MI->getOpcode());
unsigned NumFixedOps = MCDesc.getNumOperands();
if (NumFixedOps != MI->getNumOperands()) {
auto DecOp = MI->getOperand(NumFixedOps - 1);
auto Dec = static_cast<SPIRV::Decoration>(DecOp.getImm());
O << ' ';
switch (Dec) {
case SPIRV::Decoration::BuiltIn:
printBuiltIn(MI, NumFixedOps, O);
break;
case SPIRV::Decoration::UniformId:
printScope(MI, NumFixedOps, O);
break;
case SPIRV::Decoration::FuncParamAttr:
printFunctionParameterAttribute(MI, NumFixedOps, O);
break;
case SPIRV::Decoration::FPRoundingMode:
printFPRoundingMode(MI, NumFixedOps, O);
break;
case SPIRV::Decoration::FPFastMathMode:
printFPFastMathMode(MI, NumFixedOps, O);
break;
case SPIRV::Decoration::LinkageAttributes:
case SPIRV::Decoration::UserSemantic:
printStringImm(MI, NumFixedOps, O);
break;
default:
printRemainingVariableOps(MI, NumFixedOps, O, true);
break;
}
}
}
static void printExpr(const MCExpr *Expr, raw_ostream &O) {
#ifndef NDEBUG
const MCSymbolRefExpr *SRE;
if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
SRE = cast<MCSymbolRefExpr>(BE->getLHS());
else
SRE = cast<MCSymbolRefExpr>(Expr);
MCSymbolRefExpr::VariantKind Kind = SRE->getKind();
assert(Kind == MCSymbolRefExpr::VK_None);
#endif
O << *Expr;
}
void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O, const char *Modifier) {
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
if (OpNo < MI->getNumOperands()) {
const MCOperand &Op = MI->getOperand(OpNo);
if (Op.isReg())
O << '%' << (Register::virtReg2Index(Op.getReg()) + 1);
else if (Op.isImm())
O << formatImm((int64_t)Op.getImm());
else if (Op.isDFPImm())
O << formatImm((double)Op.getDFPImm());
else if (Op.isExpr())
printExpr(Op.getExpr(), O);
else
llvm_unreachable("Unexpected operand type");
}
}
void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
const unsigned NumOps = MI->getNumOperands();
unsigned StrStartIndex = OpNo;
while (StrStartIndex < NumOps) {
if (MI->getOperand(StrStartIndex).isReg())
break;
std::string Str = getSPIRVStringOperand(*MI, OpNo);
if (StrStartIndex != OpNo)
O << ' '; O << '"';
for (char c : Str) {
if (c == '"')
O.write('\\'); O.write(c);
}
O << '"';
unsigned numOpsInString = (Str.size() / 4) + 1;
StrStartIndex += numOpsInString;
if (MI->getOpcode() == SPIRV::OpDecorate &&
MI->getOperand(1).getImm() ==
static_cast<unsigned>(SPIRV::Decoration::LinkageAttributes)) {
O << ' ';
printLinkageType(MI, StrStartIndex, O);
break;
}
}
}
void SPIRVInstPrinter::printExtInst(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
llvm_unreachable("Unimplemented printExtInst");
}
void SPIRVInstPrinter::printCapability(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::Capability e =
static_cast<SPIRV::Capability>(MI->getOperand(OpNo).getImm());
O << SPIRV::getCapabilityName(e);
}
}
void SPIRVInstPrinter::printSourceLanguage(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::SourceLanguage e =
static_cast<SPIRV::SourceLanguage>(MI->getOperand(OpNo).getImm());
O << SPIRV::getSourceLanguageName(e);
}
}
void SPIRVInstPrinter::printExecutionModel(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::ExecutionModel e =
static_cast<SPIRV::ExecutionModel>(MI->getOperand(OpNo).getImm());
O << SPIRV::getExecutionModelName(e);
}
}
void SPIRVInstPrinter::printAddressingModel(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::AddressingModel e =
static_cast<SPIRV::AddressingModel>(MI->getOperand(OpNo).getImm());
O << SPIRV::getAddressingModelName(e);
}
}
void SPIRVInstPrinter::printMemoryModel(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::MemoryModel e =
static_cast<SPIRV::MemoryModel>(MI->getOperand(OpNo).getImm());
O << SPIRV::getMemoryModelName(e);
}
}
void SPIRVInstPrinter::printExecutionMode(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::ExecutionMode e =
static_cast<SPIRV::ExecutionMode>(MI->getOperand(OpNo).getImm());
O << SPIRV::getExecutionModeName(e);
}
}
void SPIRVInstPrinter::printStorageClass(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::StorageClass e =
static_cast<SPIRV::StorageClass>(MI->getOperand(OpNo).getImm());
O << SPIRV::getStorageClassName(e);
}
}
void SPIRVInstPrinter::printDim(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::Dim e = static_cast<SPIRV::Dim>(MI->getOperand(OpNo).getImm());
O << SPIRV::getDimName(e);
}
}
void SPIRVInstPrinter::printSamplerAddressingMode(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::SamplerAddressingMode e = static_cast<SPIRV::SamplerAddressingMode>(
MI->getOperand(OpNo).getImm());
O << SPIRV::getSamplerAddressingModeName(e);
}
}
void SPIRVInstPrinter::printSamplerFilterMode(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::SamplerFilterMode e =
static_cast<SPIRV::SamplerFilterMode>(MI->getOperand(OpNo).getImm());
O << SPIRV::getSamplerFilterModeName(e);
}
}
void SPIRVInstPrinter::printImageFormat(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::ImageFormat e =
static_cast<SPIRV::ImageFormat>(MI->getOperand(OpNo).getImm());
O << SPIRV::getImageFormatName(e);
}
}
void SPIRVInstPrinter::printImageChannelOrder(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::ImageChannelOrder e =
static_cast<SPIRV::ImageChannelOrder>(MI->getOperand(OpNo).getImm());
O << SPIRV::getImageChannelOrderName(e);
}
}
void SPIRVInstPrinter::printImageChannelDataType(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::ImageChannelDataType e =
static_cast<SPIRV::ImageChannelDataType>(MI->getOperand(OpNo).getImm());
O << SPIRV::getImageChannelDataTypeName(e);
}
}
void SPIRVInstPrinter::printImageOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getImageOperandName(e);
}
}
void SPIRVInstPrinter::printFPFastMathMode(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getFPFastMathModeName(e);
}
}
void SPIRVInstPrinter::printFPRoundingMode(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::FPRoundingMode e =
static_cast<SPIRV::FPRoundingMode>(MI->getOperand(OpNo).getImm());
O << SPIRV::getFPRoundingModeName(e);
}
}
void SPIRVInstPrinter::printLinkageType(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::LinkageType e =
static_cast<SPIRV::LinkageType>(MI->getOperand(OpNo).getImm());
O << SPIRV::getLinkageTypeName(e);
}
}
void SPIRVInstPrinter::printAccessQualifier(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::AccessQualifier e =
static_cast<SPIRV::AccessQualifier>(MI->getOperand(OpNo).getImm());
O << SPIRV::getAccessQualifierName(e);
}
}
void SPIRVInstPrinter::printFunctionParameterAttribute(const MCInst *MI,
unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::FunctionParameterAttribute e =
static_cast<SPIRV::FunctionParameterAttribute>(
MI->getOperand(OpNo).getImm());
O << SPIRV::getFunctionParameterAttributeName(e);
}
}
void SPIRVInstPrinter::printDecoration(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::Decoration e =
static_cast<SPIRV::Decoration>(MI->getOperand(OpNo).getImm());
O << SPIRV::getDecorationName(e);
}
}
void SPIRVInstPrinter::printBuiltIn(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::BuiltIn e =
static_cast<SPIRV::BuiltIn>(MI->getOperand(OpNo).getImm());
O << SPIRV::getBuiltInName(e);
}
}
void SPIRVInstPrinter::printSelectionControl(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getSelectionControlName(e);
}
}
void SPIRVInstPrinter::printLoopControl(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getLoopControlName(e);
}
}
void SPIRVInstPrinter::printFunctionControl(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getFunctionControlName(e);
}
}
void SPIRVInstPrinter::printMemorySemantics(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getMemorySemanticsName(e);
}
}
void SPIRVInstPrinter::printMemoryOperand(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
unsigned e = static_cast<unsigned>(MI->getOperand(OpNo).getImm());
O << SPIRV::getMemoryOperandName(e);
}
}
void SPIRVInstPrinter::printScope(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::Scope e = static_cast<SPIRV::Scope>(MI->getOperand(OpNo).getImm());
O << SPIRV::getScopeName(e);
}
}
void SPIRVInstPrinter::printGroupOperation(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::GroupOperation e =
static_cast<SPIRV::GroupOperation>(MI->getOperand(OpNo).getImm());
O << SPIRV::getGroupOperationName(e);
}
}
void SPIRVInstPrinter::printKernelEnqueueFlags(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::KernelEnqueueFlags e =
static_cast<SPIRV::KernelEnqueueFlags>(MI->getOperand(OpNo).getImm());
O << SPIRV::getKernelEnqueueFlagsName(e);
}
}
void SPIRVInstPrinter::printKernelProfilingInfo(const MCInst *MI, unsigned OpNo,
raw_ostream &O) {
if (OpNo < MI->getNumOperands()) {
SPIRV::KernelProfilingInfo e =
static_cast<SPIRV::KernelProfilingInfo>(MI->getOperand(OpNo).getImm());
O << SPIRV::getKernelProfilingInfoName(e);
}
}