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  Register Reg = MI->getOperand(0).getReg();
64  auto Name = getSPIRVStringOperand(*MI, 1);
65  auto Set = getExtInstSetFromString(Name);
66  ExtInstSetIDs.insert({Reg, Set});
67 }
68 
70  StringRef Annot, const MCSubtargetInfo &STI,
71  raw_ostream &OS) {
72  const unsigned OpCode = MI->getOpcode();
73  printInstruction(MI, Address, OS);
74 
75  if (OpCode == SPIRV::OpDecorate) {
76  printOpDecorate(MI, OS);
77  } else if (OpCode == SPIRV::OpExtInstImport) {
78  recordOpExtInstImport(MI);
79  } else if (OpCode == SPIRV::OpExtInst) {
80  printOpExtInst(MI, OS);
81  } else {
82  // Print any extra operands for variadic instructions.
83  MCInstrDesc MCDesc = MII.get(OpCode);
84  if (MCDesc.isVariadic()) {
85  const unsigned NumFixedOps = MCDesc.getNumOperands();
86  const unsigned LastFixedIndex = NumFixedOps - 1;
87  const int FirstVariableIndex = NumFixedOps;
88  if (NumFixedOps > 0 &&
89  MCDesc.OpInfo[LastFixedIndex].OperandType == MCOI::OPERAND_UNKNOWN) {
90  // For instructions where a custom type (not reg or immediate) comes as
91  // the last operand before the variable_ops. This is usually a StringImm
92  // operand, but there are a few other cases.
93  switch (OpCode) {
94  case SPIRV::OpTypeImage:
95  OS << ' ';
96  printSymbolicOperand<OperandCategory::AccessQualifierOperand>(
97  MI, FirstVariableIndex, OS);
98  break;
99  case SPIRV::OpVariable:
100  OS << ' ';
101  printOperand(MI, FirstVariableIndex, OS);
102  break;
103  case SPIRV::OpEntryPoint: {
104  // Print the interface ID operands, skipping the name's string
105  // literal.
106  printRemainingVariableOps(MI, NumFixedOps, OS, false, true);
107  break;
108  }
109  case SPIRV::OpExecutionMode:
110  case SPIRV::OpExecutionModeId:
111  case SPIRV::OpLoopMerge: {
112  // Print any literals after the OPERAND_UNKNOWN argument normally.
113  printRemainingVariableOps(MI, NumFixedOps, OS);
114  break;
115  }
116  default:
117  break; // printStringImm has already been handled.
118  }
119  } else {
120  // For instructions with no fixed ops or a reg/immediate as the final
121  // fixed operand, we can usually print the rest with "printOperand", but
122  // check for a few cases with custom types first.
123  switch (OpCode) {
124  case SPIRV::OpLoad:
125  case SPIRV::OpStore:
126  OS << ' ';
127  printSymbolicOperand<OperandCategory::MemoryOperandOperand>(
128  MI, FirstVariableIndex, OS);
129  printRemainingVariableOps(MI, FirstVariableIndex + 1, OS);
130  break;
131  case SPIRV::OpImageSampleImplicitLod:
132  case SPIRV::OpImageSampleDrefImplicitLod:
133  case SPIRV::OpImageSampleProjImplicitLod:
134  case SPIRV::OpImageSampleProjDrefImplicitLod:
135  case SPIRV::OpImageFetch:
136  case SPIRV::OpImageGather:
137  case SPIRV::OpImageDrefGather:
138  case SPIRV::OpImageRead:
139  case SPIRV::OpImageWrite:
140  case SPIRV::OpImageSparseSampleImplicitLod:
141  case SPIRV::OpImageSparseSampleDrefImplicitLod:
142  case SPIRV::OpImageSparseSampleProjImplicitLod:
143  case SPIRV::OpImageSparseSampleProjDrefImplicitLod:
144  case SPIRV::OpImageSparseFetch:
145  case SPIRV::OpImageSparseGather:
146  case SPIRV::OpImageSparseDrefGather:
147  case SPIRV::OpImageSparseRead:
148  case SPIRV::OpImageSampleFootprintNV:
149  OS << ' ';
150  printSymbolicOperand<OperandCategory::ImageOperandOperand>(
151  MI, FirstVariableIndex, OS);
152  printRemainingVariableOps(MI, NumFixedOps + 1, OS);
153  break;
154  case SPIRV::OpCopyMemory:
155  case SPIRV::OpCopyMemorySized: {
156  const unsigned NumOps = MI->getNumOperands();
157  for (unsigned i = NumFixedOps; i < NumOps; ++i) {
158  OS << ' ';
159  printSymbolicOperand<OperandCategory::MemoryOperandOperand>(MI, i,
160  OS);
161  if (MI->getOperand(i).getImm() & MemoryOperand::Aligned) {
162  assert(i + 1 < NumOps && "Missing alignment operand");
163  OS << ' ';
164  printOperand(MI, i + 1, OS);
165  i += 1;
166  }
167  }
168  break;
169  }
170  case SPIRV::OpConstantI:
171  case SPIRV::OpConstantF:
172  printOpConstantVarOps(MI, NumFixedOps, OS);
173  break;
174  default:
175  printRemainingVariableOps(MI, NumFixedOps, OS);
176  break;
177  }
178  }
179  }
180  }
181 
182  printAnnotation(OS, Annot);
183 }
184 
186  // The fixed operands have already been printed, so just need to decide what
187  // type of ExtInst operands to print based on the instruction set and number.
188  MCInstrDesc MCDesc = MII.get(MI->getOpcode());
189  unsigned NumFixedOps = MCDesc.getNumOperands();
190  const auto NumOps = MI->getNumOperands();
191  if (NumOps == NumFixedOps)
192  return;
193 
194  O << ' ';
195 
196  // TODO: implement special printing for OpenCLExtInst::vstor*.
197  printRemainingVariableOps(MI, NumFixedOps, O, true);
198 }
199 
201  // The fixed operands have already been printed, so just need to decide what
202  // type of decoration operands to print based on the Decoration type.
203  MCInstrDesc MCDesc = MII.get(MI->getOpcode());
204  unsigned NumFixedOps = MCDesc.getNumOperands();
205 
206  if (NumFixedOps != MI->getNumOperands()) {
207  auto DecOp = MI->getOperand(NumFixedOps - 1);
208  auto Dec = static_cast<Decoration::Decoration>(DecOp.getImm());
209 
210  O << ' ';
211 
212  switch (Dec) {
213  case Decoration::BuiltIn:
214  printSymbolicOperand<OperandCategory::BuiltInOperand>(MI, NumFixedOps, O);
215  break;
216  case Decoration::UniformId:
217  printSymbolicOperand<OperandCategory::ScopeOperand>(MI, NumFixedOps, O);
218  break;
219  case Decoration::FuncParamAttr:
220  printSymbolicOperand<OperandCategory::FunctionParameterAttributeOperand>(
221  MI, NumFixedOps, O);
222  break;
223  case Decoration::FPRoundingMode:
224  printSymbolicOperand<OperandCategory::FPRoundingModeOperand>(
225  MI, NumFixedOps, O);
226  break;
227  case Decoration::FPFastMathMode:
228  printSymbolicOperand<OperandCategory::FPFastMathModeOperand>(
229  MI, NumFixedOps, O);
230  break;
231  case Decoration::LinkageAttributes:
232  case Decoration::UserSemantic:
233  printStringImm(MI, NumFixedOps, O);
234  break;
235  default:
236  printRemainingVariableOps(MI, NumFixedOps, O, true);
237  break;
238  }
239  }
240 }
241 
242 static void printExpr(const MCExpr *Expr, raw_ostream &O) {
243 #ifndef NDEBUG
244  const MCSymbolRefExpr *SRE;
245 
246  if (const MCBinaryExpr *BE = dyn_cast<MCBinaryExpr>(Expr))
247  SRE = cast<MCSymbolRefExpr>(BE->getLHS());
248  else
249  SRE = cast<MCSymbolRefExpr>(Expr);
250 
252 
254 #endif
255  O << *Expr;
256 }
257 
258 void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
259  raw_ostream &O, const char *Modifier) {
260  assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
261  if (OpNo < MI->getNumOperands()) {
262  const MCOperand &Op = MI->getOperand(OpNo);
263  if (Op.isReg())
264  O << '%' << (Register::virtReg2Index(Op.getReg()) + 1);
265  else if (Op.isImm())
266  O << formatImm((int64_t)Op.getImm());
267  else if (Op.isDFPImm())
268  O << formatImm((double)Op.getDFPImm());
269  else if (Op.isExpr())
270  printExpr(Op.getExpr(), O);
271  else
272  llvm_unreachable("Unexpected operand type");
273  }
274 }
275 
276 void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo,
277  raw_ostream &O) {
278  const unsigned NumOps = MI->getNumOperands();
279  unsigned StrStartIndex = OpNo;
280  while (StrStartIndex < NumOps) {
281  if (MI->getOperand(StrStartIndex).isReg())
282  break;
283 
284  std::string Str = getSPIRVStringOperand(*MI, OpNo);
285  if (StrStartIndex != OpNo)
286  O << ' '; // Add a space if we're starting a new string/argument.
287  O << '"';
288  for (char c : Str) {
289  if (c == '"')
290  O.write('\\'); // Escape " characters (might break for complex UTF-8).
291  O.write(c);
292  }
293  O << '"';
294 
295  unsigned numOpsInString = (Str.size() / 4) + 1;
296  StrStartIndex += numOpsInString;
297 
298  // Check for final Op of "OpDecorate %x %stringImm %linkageAttribute".
299  if (MI->getOpcode() == SPIRV::OpDecorate &&
300  MI->getOperand(1).getImm() ==
301  static_cast<unsigned>(Decoration::LinkageAttributes)) {
302  O << ' ';
303  printSymbolicOperand<OperandCategory::LinkageTypeOperand>(
304  MI, StrStartIndex, O);
305  break;
306  }
307  }
308 }
309 
310 void SPIRVInstPrinter::printExtension(const MCInst *MI, unsigned OpNo,
311  raw_ostream &O) {
312  auto SetReg = MI->getOperand(2).getReg();
313  auto Set = ExtInstSetIDs[SetReg];
314  auto Op = MI->getOperand(OpNo).getImm();
315  O << getExtInstName(Set, Op);
316 }
317 
318 template <OperandCategory::OperandCategory category>
320  raw_ostream &O) {
321  if (OpNo < MI->getNumOperands()) {
322  O << getSymbolicOperandMnemonic(category, MI->getOperand(OpNo).getImm());
323  }
324 }
llvm::MCSymbolRefExpr::getKind
VariantKind getKind() const
Definition: MCExpr.h:401
i
i
Definition: README.txt:29
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:109
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
llvm::X86Disassembler::Reg
Reg
All possible values of the reg field in the ModR/M byte.
Definition: X86DisassemblerDecoder.h:462
printOperand
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
Definition: SelectionDAGDumper.cpp:958
llvm::getExtInstSetFromString
SPIRV::InstructionSet::InstructionSet getExtInstSetFromString(std::string SetName)
Definition: SPIRVBaseInfo.cpp:190
llvm::getExtInstName
std::string getExtInstName(SPIRV::InstructionSet::InstructionSet Set, uint32_t InstructionNumber)
Definition: SPIRVBaseInfo.cpp:199
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:69
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:258
llvm::SPIRVInstPrinter::printOpDecorate
void printOpDecorate(const MCInst *MI, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:200
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:242
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::SPIRVInstPrinter::printOpExtInst
void printOpExtInst(const MCInst *MI, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:185
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:264
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::Register
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
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:319
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:351
Casting.h
llvm::SPIRVInstPrinter::printExtension
void printExtension(const MCInst *MI, unsigned OpNo, raw_ostream &O)
Definition: SPIRVInstPrinter.cpp:310
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:276
llvm::getSymbolicOperandMnemonic
std::string getSymbolicOperandMnemonic(SPIRV::OperandCategory::OperandCategory Category, int32_t Value)
Definition: SPIRVBaseInfo.cpp:57
llvm::RISCVMatInt::Imm
@ Imm
Definition: RISCVMatInt.h:23
llvm::MCOI::OPERAND_UNKNOWN
@ OPERAND_UNKNOWN
Definition: MCInstrDesc.h:58
llvm::SPIRV
Lowers a builtin funtion call using the provided DemangledCall skeleton and external instruction Set.
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:242
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