LLVM  16.0.0git
SPIRVInstPrinter.cpp
Go to the documentation of this file.
1 //===-- SPIRVInstPrinter.cpp - Output SPIR-V MCInsts as ASM -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This class prints a SPIR-V MCInst to a .s file.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "SPIRVInstPrinter.h"
14 #include "SPIRV.h"
15 #include "SPIRVBaseInfo.h"
16 #include "llvm/CodeGen/Register.h"
17 #include "llvm/MC/MCAsmInfo.h"
18 #include "llvm/MC/MCExpr.h"
19 #include "llvm/MC/MCInst.h"
20 #include "llvm/MC/MCInstrInfo.h"
21 #include "llvm/MC/MCSymbol.h"
22 #include "llvm/Support/Casting.h"
25 
26 using namespace llvm;
27 using namespace llvm::SPIRV;
28 
29 #define DEBUG_TYPE "asm-printer"
30 
31 // Include the auto-generated portion of the assembly writer.
32 #include "SPIRVGenAsmWriter.inc"
33 
35  unsigned StartIndex,
36  raw_ostream &O,
37  bool SkipFirstSpace,
38  bool SkipImmediates) {
39  const unsigned NumOps = MI->getNumOperands();
40  for (unsigned i = StartIndex; i < NumOps; ++i) {
41  if (!SkipImmediates || !MI->getOperand(i).isImm()) {
42  if (!SkipFirstSpace || i != StartIndex)
43  O << ' ';
44  printOperand(MI, i, O);
45  }
46  }
47 }
48 
50  unsigned StartIndex,
51  raw_ostream &O) {
52  O << ' ';
53  if (MI->getNumOperands() - StartIndex == 2) { // Handle 64 bit literals.
54  uint64_t Imm = MI->getOperand(StartIndex).getImm();
55  Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32);
56  O << Imm;
57  } else {
58  printRemainingVariableOps(MI, StartIndex, O, true, false);
59  }
60 }
61 
62 void SPIRVInstPrinter::recordOpExtInstImport(const MCInst *MI) {
63  // TODO: insert {Reg, Set} into ExtInstSetIDs map.
64 }
65 
67  StringRef Annot, const MCSubtargetInfo &STI,
68  raw_ostream &OS) {
69  const unsigned OpCode = MI->getOpcode();
70  printInstruction(MI, Address, OS);
71 
72  if (OpCode == SPIRV::OpDecorate) {
73  printOpDecorate(MI, OS);
74  } else if (OpCode == SPIRV::OpExtInstImport) {
75  recordOpExtInstImport(MI);
76  } else if (OpCode == SPIRV::OpExtInst) {
77  printOpExtInst(MI, OS);
78  } else {
79  // Print any extra operands for variadic instructions.
80  MCInstrDesc MCDesc = MII.get(OpCode);
81  if (MCDesc.isVariadic()) {
82  const unsigned NumFixedOps = MCDesc.getNumOperands();
83  const unsigned LastFixedIndex = NumFixedOps - 1;
84  const int FirstVariableIndex = NumFixedOps;
85  if (NumFixedOps > 0 &&
86  MCDesc.OpInfo[LastFixedIndex].OperandType == MCOI::OPERAND_UNKNOWN) {
87  // For instructions where a custom type (not reg or immediate) comes as
88  // the last operand before the variable_ops. This is usually a StringImm
89  // operand, but there are a few other cases.
90  switch (OpCode) {
91  case SPIRV::OpTypeImage:
92  OS << ' ';
93  printSymbolicOperand<OperandCategory::AccessQualifierOperand>(
94  MI, FirstVariableIndex, OS);
95  break;
96  case SPIRV::OpVariable:
97  OS << ' ';
98  printOperand(MI, FirstVariableIndex, OS);
99  break;
100  case SPIRV::OpEntryPoint: {
101  // Print the interface ID operands, skipping the name's string
102  // literal.
103  printRemainingVariableOps(MI, NumFixedOps, OS, false, true);
104  break;
105  }
106  case SPIRV::OpExecutionMode:
107  case SPIRV::OpExecutionModeId:
108  case SPIRV::OpLoopMerge: {
109  // Print any literals after the OPERAND_UNKNOWN argument normally.
110  printRemainingVariableOps(MI, NumFixedOps, OS);
111  break;
112  }
113  default:
114  break; // printStringImm has already been handled.
115  }
116  } else {
117  // For instructions with no fixed ops or a reg/immediate as the final
118  // fixed operand, we can usually print the rest with "printOperand", but
119  // check for a few cases with custom types first.
120  switch (OpCode) {
121  case SPIRV::OpLoad:
122  case SPIRV::OpStore:
123  OS << ' ';
124  printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
125  MI, FirstVariableIndex, OS);
126  printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
127  break;
128  case SPIRV::OpImageSampleImplicitLod:
129  case SPIRV::OpImageSampleDrefImplicitLod:
130  case SPIRV::OpImageSampleProjImplicitLod:
131  case SPIRV::OpImageSampleProjDrefImplicitLod:
132  case SPIRV::OpImageFetch:
133  case SPIRV::OpImageGather:
134  case SPIRV::OpImageDrefGather:
135  case SPIRV::OpImageRead:
136  case SPIRV::OpImageWrite:
137  case SPIRV::OpImageSparseSampleImplicitLod:
138  case SPIRV::OpImageSparseSampleDrefImplicitLod:
139  case SPIRV::OpImageSparseSampleProjImplicitLod:
140  case SPIRV::OpImageSparseSampleProjDrefImplicitLod:
141  case SPIRV::OpImageSparseFetch:
142  case SPIRV::OpImageSparseGather:
143  case SPIRV::OpImageSparseDrefGather:
144  case SPIRV::OpImageSparseRead:
145  case SPIRV::OpImageSampleFootprintNV:
146  OS << ' ';
147  printSymbolicOperand<OperandCategory::ImageOperandOperand>(
148  MI, FirstVariableIndex, OS);
149  printRemainingVariableOps(MI, NumFixedOps + 1, OS);
150  break;
151  case SPIRV::OpCopyMemory:
152  case SPIRV::OpCopyMemorySized: {
153  const unsigned NumOps = MI->getNumOperands();
154  for (unsigned i = NumFixedOps; i < NumOps; ++i) {
155  OS << ' ';
156  printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, i,
157  OS);
158  if (MI->getOperand(i).getImm() & MemoryOperand::Aligned) {
159  assert(i + 1 < NumOps && "Missing alignment operand");
160  OS << ' ';
161  printOperand(MI, i + 1, OS);
162  i += 1;
163  }
164  }
165  break;
166  }
167  case SPIRV::OpConstantI:
168  case SPIRV::OpConstantF:
169  printOpConstantVarOps(MI, NumFixedOps, OS);
170  break;
171  default:
172  printRemainingVariableOps(MI, NumFixedOps, OS);
173  break;
174  }
175  }
176  }
177  }
178 
179  printAnnotation(OS, Annot);
180 }
181 
183  // The fixed operands have already been printed, so just need to decide what
184  // type of ExtInst operands to print based on the instruction set and number.
185  MCInstrDesc MCDesc = MII.get(MI->getOpcode());
186  unsigned NumFixedOps = MCDesc.getNumOperands();
187  const auto NumOps = MI->getNumOperands();
188  if (NumOps == NumFixedOps)
189  return;
190 
191  O << ' ';
192 
193  // TODO: implement special printing for OpenCLExtInst::vstor*.
194  printRemainingVariableOps(MI, NumFixedOps, O, true);
195 }
196 
198  // The fixed operands have already been printed, so just need to decide what
199  // type of decoration operands to print based on the Decoration type.
200  MCInstrDesc MCDesc = MII.get(MI->getOpcode());
201  unsigned NumFixedOps = MCDesc.getNumOperands();
202 
203  if (NumFixedOps != MI->getNumOperands()) {
204  auto DecOp = MI->getOperand(NumFixedOps - 1);
205  auto Dec = static_cast<Decoration::Decoration>(DecOp.getImm());
206 
207  O << ' ';
208 
209  switch (Dec) {
210  case Decoration::BuiltIn:
211  printSymbolicOperand<OperandCategory::BuiltInOperand>(MI, NumFixedOps, O);
212  break;
213  case Decoration::UniformId:
214  printSymbolicOperand<OperandCategory::ScopeOperand>(MI, NumFixedOps, O);
215  break;
216  case Decoration::FuncParamAttr:
217  printSymbolicOperand<OperandCategory::FunctionParameterAttributeOperand>(
218  MI, NumFixedOps, O);
219  break;
220  case Decoration::FPRoundingMode:
221  printSymbolicOperand<OperandCategory::FPRoundingModeOperand>(
222  MI, NumFixedOps, O);
223  break;
224  case Decoration::FPFastMathMode:
225  printSymbolicOperand<OperandCategory::FPFastMathModeOperand>(
226  MI, NumFixedOps, O);
227  break;
228  case Decoration::LinkageAttributes:
229  case Decoration::UserSemantic:
230  printStringImm(MI, NumFixedOps, O);
231  break;
232  default:
233  printRemainingVariableOps(MI, NumFixedOps, O, true);
234  break;
235  }
236  }
237 }
238 
239 static void printExpr(const MCExpr *Expr, raw_ostream &O) {
240 #ifndef NDEBUG
241  const MCSymbolRefExpr *SRE;
242 
243  if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
244  SRE = cast<MCSymbolRefExpr>(BE->getLHS());
245  else
246  SRE = cast<MCSymbolRefExpr>(Expr);
247 
249 
251 #endif
252  O << *Expr;
253 }
254 
255 void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
256  raw_ostream &O, const char *Modifier) {
257  assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
258  if (OpNo < MI->getNumOperands()) {
259  const MCOperand &Op = MI->getOperand(OpNo);
260  if (Op.isReg())
261  O << '%' << (Register::virtReg2Index(Op.getReg()) + 1);
262  else if (Op.isImm())
263  O << formatImm((int64_t)Op.getImm());
264  else if (Op.isDFPImm())
265  O << formatImm((double)Op.getDFPImm());
266  else if (Op.isExpr())
267  printExpr(Op.getExpr(), O);
268  else
269  llvm_unreachable("Unexpected operand type");
270  }
271 }
272 
273 void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo,
274  raw_ostream &O) {
275  const unsigned NumOps = MI->getNumOperands();
276  unsigned StrStartIndex = OpNo;
277  while (StrStartIndex < NumOps) {
278  if (MI->getOperand(StrStartIndex).isReg())
279  break;
280 
281  std::string Str = getSPIRVStringOperand(*MI, OpNo);
282  if (StrStartIndex != OpNo)
283  O << ' '; // Add a space if we're starting a new string/argument.
284  O << '"';
285  for (char c : Str) {
286  if (c == '"')
287  O.write('\\'); // Escape " characters (might break for complex UTF-8).
288  O.write(c);
289  }
290  O << '"';
291 
292  unsigned numOpsInString = (Str.size() / 4) + 1;
293  StrStartIndex += numOpsInString;
294 
295  // Check for final Op of "OpDecorate %x %stringImm %linkageAttribute".
296  if (MI->getOpcode() == SPIRV::OpDecorate &&
297  MI->getOperand(1).getImm() ==
298  static_cast<unsigned>(Decoration::LinkageAttributes)) {
299  O << ' ';
300  printSymbolicOperand<OperandCategory::LinkageTypeOperand>(
301  MI, StrStartIndex, O);
302  break;
303  }
304  }
305 }
306 
307 void SPIRVInstPrinter::printExtension(const MCInst *MI, unsigned OpNo,
308  raw_ostream &O) {
309  llvm_unreachable("Unimplemented printExtension");
310 }
311 
312 template <OperandCategory::OperandCategory category>
314  raw_ostream &O) {
315  if (OpNo < MI->getNumOperands()) {
316  O << getSymbolicOperandMnemonic(category, MI->getOperand(OpNo).getImm());
317  }
318 }
llvm::MCSymbolRefExpr::getKind
VariantKind getKind() const
Definition: MCExpr.h:401
i
i
Definition: README.txt:29
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:105
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::SPIRVInstPrinter::printOpConstantVarOps
void printOpConstantVarOps(const MCInst *MI, unsigned StartIndex, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:49
ErrorHandling.h
printOperand
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
Definition: SelectionDAGDumper.cpp:958
llvm::MCInst
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:184
llvm::MCBinaryExpr
Binary assembler expressions.
Definition: MCExpr.h:481
llvm::SPIRVInstPrinter::printInst
void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &OS) override
Print the specified MCInst to the specified raw_ostream.
Definition: SPIRVInstPrinter.cpp:66
FormattedStream.h
SPIRVBaseInfo.h
MCInstrInfo.h
MCSymbol.h
SPIRVInstPrinter.h
llvm::SPIRVInstPrinter::printOperand
void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, const char *Modifier=nullptr)
Definition: SPIRVInstPrinter.cpp:255
llvm::SPIRVInstPrinter::printOpDecorate
void printOpDecorate(const MCInst *MI, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:197
MCInst.h
llvm::MCInstrDesc
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:197
printExpr
static void printExpr(const MCExpr *Expr, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:239
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
c
the resulting code requires compare and branches when and if the revised code is with conditional branches instead of More there is a byte word extend before each where there should be only and the condition codes are not remembered when the same two values are compared twice More LSR enhancements i8 and i32 load store addressing modes are identical int int c
Definition: README.txt:418
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
llvm::SPIRVInstPrinter::printOpExtInst
void printOpExtInst(const MCInst *MI, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:182
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:240
llvm::MCSymbolRefExpr::VariantKind
VariantKind
Definition: MCExpr.h:194
uint64_t
llvm::MCOperandInfo::OperandType
uint8_t OperandType
Information about the type of the operand.
Definition: MCInstrDesc.h:96
SPIRV.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MCInstrDesc::OpInfo
const MCOperandInfo * OpInfo
Definition: MCInstrDesc.h:208
llvm::MCSymbolRefExpr
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:192
MCAsmInfo.h
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
llvm::SPIRVInstPrinter::printRemainingVariableOps
void printRemainingVariableOps(const MCInst *MI, unsigned StartIndex, raw_ostream &O, bool SkipFirstSpace=false, bool SkipImmediates=false)
Definition: SPIRVInstPrinter.cpp:34
llvm::SPIRVInstPrinter::printSymbolicOperand
void printSymbolicOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:313
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:348
Casting.h
llvm::SPIRVInstPrinter::printExtension
void printExtension(const MCInst *MI, unsigned OpNo, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:307
llvm::MCInstrDesc::isVariadic
bool isVariadic() const
Return true if this instruction can have a variable number of operands.
Definition: MCInstrDesc.h:258
llvm::SPIRVInstPrinter::printStringImm
void printStringImm(const MCInst *MI, unsigned OpNo, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:273
llvm::getSymbolicOperandMnemonic
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
Definition: SPIRVBaseInfo.cpp:69
llvm::RISCVMatInt::Imm
@ Imm
Definition: RISCVMatInt.h:23
llvm::MCOI::OPERAND_UNKNOWN
@ OPERAND_UNKNOWN
Definition: MCInstrDesc.h:58
llvm::SPIRV
Definition: SPIRVBaseInfo.cpp:20
llvm::MCOperand
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:36
Register.h
llvm::MCSymbolRefExpr::VK_None
@ VK_None
Definition: MCExpr.h:195
llvm::Register::virtReg2Index
static unsigned virtReg2Index(Register Reg)
Convert a virtual register number to a 0-based index.
Definition: Register.h:77
llvm::getSPIRVStringOperand
std::string getSPIRVStringOperand(const InstType &MI, unsigned StartIndex)
Definition: SPIRVBaseInfo.h:232
MCExpr.h
llvm::MCSubtargetInfo
Generic base class for all target subtargets.
Definition: MCSubtargetInfo.h:76
llvm::MCInstrDesc::getNumOperands
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
Definition: MCInstrDesc.h:230
llvm::MCExpr
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35