1 //===- SPIRVOps.cpp - MLIR SPIR-V operations ------------------------------===//
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 file defines the operations in the SPIR-V dialect.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
14 
15 #include "mlir/Dialect/SPIRV/IR/ParserUtils.h"
16 #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
17 #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
18 #include "mlir/Dialect/SPIRV/IR/SPIRVOpTraits.h"
19 #include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"
20 #include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"
21 #include "mlir/IR/Builders.h"
22 #include "mlir/IR/BuiltinOps.h"
23 #include "mlir/IR/BuiltinTypes.h"
24 #include "mlir/IR/FunctionImplementation.h"
25 #include "mlir/IR/OpDefinition.h"
26 #include "mlir/IR/OpImplementation.h"
27 #include "mlir/IR/TypeUtilities.h"
28 #include "mlir/Interfaces/CallInterfaces.h"
29 #include "llvm/ADT/APFloat.h"
30 #include "llvm/ADT/APInt.h"
31 #include "llvm/ADT/StringExtras.h"
32 #include "llvm/ADT/bit.h"
33 
34 using namespace mlir;
35 
36 // TODO: generate these strings using ODS.
37 static constexpr const char kMemoryAccessAttrName[] = "memory_access";
38 static constexpr const char kSourceMemoryAccessAttrName[] =
39     "source_memory_access";
40 static constexpr const char kAlignmentAttrName[] = "alignment";
41 static constexpr const char kSourceAlignmentAttrName[] = "source_alignment";
42 static constexpr const char kBranchWeightAttrName[] = "branch_weights";
43 static constexpr const char kCallee[] = "callee";
44 static constexpr const char kClusterSize[] = "cluster_size";
45 static constexpr const char kControl[] = "control";
46 static constexpr const char kDefaultValueAttrName[] = "default_value";
47 static constexpr const char kExecutionScopeAttrName[] = "execution_scope";
48 static constexpr const char kEqualSemanticsAttrName[] = "equal_semantics";
49 static constexpr const char kFnNameAttrName[] = "fn";
50 static constexpr const char kGroupOperationAttrName[] = "group_operation";
51 static constexpr const char kIndicesAttrName[] = "indices";
52 static constexpr const char kInitializerAttrName[] = "initializer";
53 static constexpr const char kInterfaceAttrName[] = "interface";
54 static constexpr const char kMemoryScopeAttrName[] = "memory_scope";
55 static constexpr const char kSemanticsAttrName[] = "semantics";
56 static constexpr const char kSpecIdAttrName[] = "spec_id";
57 static constexpr const char kTypeAttrName[] = "type";
58 static constexpr const char kUnequalSemanticsAttrName[] = "unequal_semantics";
59 static constexpr const char kValueAttrName[] = "value";
60 static constexpr const char kValuesAttrName[] = "values";
61 static constexpr const char kCompositeSpecConstituentsName[] = "constituents";
62 
63 //===----------------------------------------------------------------------===//
64 // Common utility functions
65 //===----------------------------------------------------------------------===//
66 
67 /// Returns true if the given op is a function-like op or nested in a
68 /// function-like op without a module-like op in the middle.
69 static bool isNestedInFunctionLikeOp(Operation *op) {
70   if (!op)
71     return false;
72   if (op->hasTrait<OpTrait::SymbolTable>())
73     return false;
74   if (op->hasTrait<OpTrait::FunctionLike>())
75     return true;
76   return isNestedInFunctionLikeOp(op->getParentOp());
77 }
78 
79 /// Returns true if the given op is an module-like op that maintains a symbol
80 /// table.
81 static bool isDirectInModuleLikeOp(Operation *op) {
82   return op && op->hasTrait<OpTrait::SymbolTable>();
83 }
84 
85 static LogicalResult extractValueFromConstOp(Operation *op, int32_t &value) {
86   auto constOp = dyn_cast_or_null<spirv::ConstantOp>(op);
87   if (!constOp) {
88     return failure();
89   }
90   auto valueAttr = constOp.value();
91   auto integerValueAttr = valueAttr.dyn_cast<IntegerAttr>();
92   if (!integerValueAttr) {
93     return failure();
94   }
95   value = integerValueAttr.getInt();
96   return success();
97 }
98 
99 template <typename Ty>
100 static ArrayAttr
101 getStrArrayAttrForEnumList(Builder &builder, ArrayRef<Ty> enumValues,
102                            function_ref<StringRef(Ty)> stringifyFn) {
103   if (enumValues.empty()) {
104     return nullptr;
105   }
106   SmallVector<StringRef, 1> enumValStrs;
107   enumValStrs.reserve(enumValues.size());
108   for (auto val : enumValues) {
109     enumValStrs.emplace_back(stringifyFn(val));
110   }
111   return builder.getStrArrayAttr(enumValStrs);
112 }
113 
114 /// Parses the next string attribute in `parser` as an enumerant of the given
115 /// `EnumClass`.
116 template <typename EnumClass>
117 static ParseResult
118 parseEnumStrAttr(EnumClass &value, OpAsmParser &parser,
119                  StringRef attrName = spirv::attributeName<EnumClass>()) {
120   Attribute attrVal;
121   NamedAttrList attr;
122   auto loc = parser.getCurrentLocation();
123   if (parser.parseAttribute(attrVal, parser.getBuilder().getNoneType(),
124                             attrName, attr)) {
125     return failure();
126   }
127   if (!attrVal.isa<StringAttr>()) {
128     return parser.emitError(loc, "expected ")
129            << attrName << " attribute specified as string";
130   }
131   auto attrOptional =
132       spirv::symbolizeEnum<EnumClass>(attrVal.cast<StringAttr>().getValue());
133   if (!attrOptional) {
134     return parser.emitError(loc, "invalid ")
135            << attrName << " attribute specification: " << attrVal;
136   }
137   value = attrOptional.getValue();
138   return success();
139 }
140 
141 /// Parses the next string attribute in `parser` as an enumerant of the given
142 /// `EnumClass` and inserts the enumerant into `state` as an 32-bit integer
143 /// attribute with the enum class's name as attribute name.
144 template <typename EnumClass>
145 static ParseResult
146 parseEnumStrAttr(EnumClass &value, OpAsmParser &parser, OperationState &state,
147                  StringRef attrName = spirv::attributeName<EnumClass>()) {
148   if (parseEnumStrAttr(value, parser)) {
149     return failure();
150   }
151   state.addAttribute(attrName, parser.getBuilder().getI32IntegerAttr(
152                                    llvm::bit_cast<int32_t>(value)));
153   return success();
154 }
155 
156 /// Parses the next keyword in `parser` as an enumerant of the given `EnumClass`
157 /// and inserts the enumerant into `state` as an 32-bit integer attribute with
158 /// the enum class's name as attribute name.
159 template <typename EnumClass>
160 static ParseResult
161 parseEnumKeywordAttr(EnumClass &value, OpAsmParser &parser,
162                      OperationState &state,
163                      StringRef attrName = spirv::attributeName<EnumClass>()) {
164   if (parseEnumKeywordAttr(value, parser)) {
165     return failure();
166   }
167   state.addAttribute(attrName, parser.getBuilder().getI32IntegerAttr(
168                                    llvm::bit_cast<int32_t>(value)));
169   return success();
170 }
171 
172 /// Parses Function, Selection and Loop control attributes. If no control is
173 /// specified, "None" is used as a default.
174 template <typename EnumClass>
175 static ParseResult
176 parseControlAttribute(OpAsmParser &parser, OperationState &state,
177                       StringRef attrName = spirv::attributeName<EnumClass>()) {
178   if (succeeded(parser.parseOptionalKeyword(kControl))) {
179     EnumClass control;
180     if (parser.parseLParen() || parseEnumKeywordAttr(control, parser, state) ||
181         parser.parseRParen())
182       return failure();
183     return success();
184   }
185   // Set control to "None" otherwise.
186   Builder builder = parser.getBuilder();
187   state.addAttribute(attrName, builder.getI32IntegerAttr(0));
188   return success();
189 }
190 
191 /// Parses optional memory access attributes attached to a memory access
192 /// operand/pointer. Specifically, parses the following syntax:
193 ///     (`[` memory-access `]`)?
194 /// where:
195 ///     memory-access ::= `"None"` | `"Volatile"` | `"Aligned", `
196 ///         integer-literal | `"NonTemporal"`
197 static ParseResult parseMemoryAccessAttributes(OpAsmParser &parser,
198                                                OperationState &state) {
199   // Parse an optional list of attributes staring with '['
200   if (parser.parseOptionalLSquare()) {
201     // Nothing to do
202     return success();
203   }
204 
205   spirv::MemoryAccess memoryAccessAttr;
206   if (parseEnumStrAttr(memoryAccessAttr, parser, state,
207                        kMemoryAccessAttrName)) {
208     return failure();
209   }
210 
211   if (spirv::bitEnumContains(memoryAccessAttr, spirv::MemoryAccess::Aligned)) {
212     // Parse integer attribute for alignment.
213     Attribute alignmentAttr;
214     Type i32Type = parser.getBuilder().getIntegerType(32);
215     if (parser.parseComma() ||
216         parser.parseAttribute(alignmentAttr, i32Type, kAlignmentAttrName,
217                               state.attributes)) {
218       return failure();
219     }
220   }
221   return parser.parseRSquare();
222 }
223 
224 // TODO Make sure to merge this and the previous function into one template
225 // parameterized by memory access attribute name and alignment. Doing so now
226 // results in VS2017 in producing an internal error (at the call site) that's
227 // not detailed enough to understand what is happening.
228 static ParseResult parseSourceMemoryAccessAttributes(OpAsmParser &parser,
229                                                      OperationState &state) {
230   // Parse an optional list of attributes staring with '['
231   if (parser.parseOptionalLSquare()) {
232     // Nothing to do
233     return success();
234   }
235 
236   spirv::MemoryAccess memoryAccessAttr;
237   if (parseEnumStrAttr(memoryAccessAttr, parser, state,
238                        kSourceMemoryAccessAttrName)) {
239     return failure();
240   }
241 
242   if (spirv::bitEnumContains(memoryAccessAttr, spirv::MemoryAccess::Aligned)) {
243     // Parse integer attribute for alignment.
244     Attribute alignmentAttr;
245     Type i32Type = parser.getBuilder().getIntegerType(32);
246     if (parser.parseComma() ||
247         parser.parseAttribute(alignmentAttr, i32Type, kSourceAlignmentAttrName,
248                               state.attributes)) {
249       return failure();
250     }
251   }
252   return parser.parseRSquare();
253 }
254 
255 template <typename MemoryOpTy>
256 static void printMemoryAccessAttribute(
257     MemoryOpTy memoryOp, OpAsmPrinter &printer,
258     SmallVectorImpl<StringRef> &elidedAttrs,
259     Optional<spirv::MemoryAccess> memoryAccessAtrrValue = None,
260     Optional<uint32_t> alignmentAttrValue = None) {
261   // Print optional memory access attribute.
262   if (auto memAccess = (memoryAccessAtrrValue ? memoryAccessAtrrValue
263                                               : memoryOp.memory_access())) {
264     elidedAttrs.push_back(kMemoryAccessAttrName);
265 
266     printer << " [\"" << stringifyMemoryAccess(*memAccess) << "\"";
267 
268     if (spirv::bitEnumContains(*memAccess, spirv::MemoryAccess::Aligned)) {
269       // Print integer alignment attribute.
270       if (auto alignment = (alignmentAttrValue ? alignmentAttrValue
271                                                : memoryOp.alignment())) {
272         elidedAttrs.push_back(kAlignmentAttrName);
273         printer << ", " << alignment;
274       }
275     }
276     printer << "]";
277   }
278   elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>());
279 }
280 
281 // TODO Make sure to merge this and the previous function into one template
282 // parameterized by memory access attribute name and alignment. Doing so now
283 // results in VS2017 in producing an internal error (at the call site) that's
284 // not detailed enough to understand what is happening.
285 template <typename MemoryOpTy>
286 static void printSourceMemoryAccessAttribute(
287     MemoryOpTy memoryOp, OpAsmPrinter &printer,
288     SmallVectorImpl<StringRef> &elidedAttrs,
289     Optional<spirv::MemoryAccess> memoryAccessAtrrValue = None,
290     Optional<uint32_t> alignmentAttrValue = None) {
291 
292   printer << ", ";
293 
294   // Print optional memory access attribute.
295   if (auto memAccess = (memoryAccessAtrrValue ? memoryAccessAtrrValue
296                                               : memoryOp.memory_access())) {
297     elidedAttrs.push_back(kSourceMemoryAccessAttrName);
298 
299     printer << " [\"" << stringifyMemoryAccess(*memAccess) << "\"";
300 
301     if (spirv::bitEnumContains(*memAccess, spirv::MemoryAccess::Aligned)) {
302       // Print integer alignment attribute.
303       if (auto alignment = (alignmentAttrValue ? alignmentAttrValue
304                                                : memoryOp.alignment())) {
305         elidedAttrs.push_back(kSourceAlignmentAttrName);
306         printer << ", " << alignment;
307       }
308     }
309     printer << "]";
310   }
311   elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>());
312 }
313 
314 static ParseResult parseImageOperands(OpAsmParser &parser,
315                                       spirv::ImageOperandsAttr &attr) {
316   // Expect image operands
317   if (parser.parseOptionalLSquare())
318     return success();
319 
320   spirv::ImageOperands imageOperands;
321   if (parseEnumStrAttr(imageOperands, parser))
322     return failure();
323 
324   attr = spirv::ImageOperandsAttr::get(parser.getBuilder().getContext(),
325                                        imageOperands);
326 
327   return parser.parseRSquare();
328 }
329 
330 static void printImageOperands(OpAsmPrinter &printer, Operation *imageOp,
331                                spirv::ImageOperandsAttr attr) {
332   if (attr) {
333     auto strImageOperands = stringifyImageOperands(attr.getValue());
334     printer << "[\"" << strImageOperands << "\"]";
335   }
336 }
337 
338 template <typename Op>
339 static LogicalResult verifyImageOperands(Op imageOp,
340                                          spirv::ImageOperandsAttr attr,
341                                          Operation::operand_range operands) {
342   if (!attr) {
343     if (operands.empty())
344       return success();
345 
346     return imageOp.emitError("the Image Operands should encode what operands "
347                              "follow, as per Image Operands");
348   }
349 
350   // TODO: Add the validation rules for the following Image Operands.
351   spirv::ImageOperands noSupportOperands =
352       spirv::ImageOperands::Bias | spirv::ImageOperands::Lod |
353       spirv::ImageOperands::Grad | spirv::ImageOperands::ConstOffset |
354       spirv::ImageOperands::Offset | spirv::ImageOperands::ConstOffsets |
355       spirv::ImageOperands::Sample | spirv::ImageOperands::MinLod |
356       spirv::ImageOperands::MakeTexelAvailable |
357       spirv::ImageOperands::MakeTexelVisible |
358       spirv::ImageOperands::SignExtend | spirv::ImageOperands::ZeroExtend;
359 
360   if (spirv::bitEnumContains(attr.getValue(), noSupportOperands))
361     llvm_unreachable("unimplemented operands of Image Operands");
362 
363   return success();
364 }
365 
366 static LogicalResult verifyCastOp(Operation *op,
367                                   bool requireSameBitWidth = true,
368                                   bool skipBitWidthCheck = false) {
369   // Some CastOps have no limit on bit widths for result and operand type.
370   if (skipBitWidthCheck)
371     return success();
372 
373   Type operandType = op->getOperand(0).getType();
374   Type resultType = op->getResult(0).getType();
375 
376   // ODS checks that result type and operand type have the same shape.
377   if (auto vectorType = operandType.dyn_cast<VectorType>()) {
378     operandType = vectorType.getElementType();
379     resultType = resultType.cast<VectorType>().getElementType();
380   }
381 
382   if (auto coopMatrixType =
383           operandType.dyn_cast<spirv::CooperativeMatrixNVType>()) {
384     operandType = coopMatrixType.getElementType();
385     resultType =
386         resultType.cast<spirv::CooperativeMatrixNVType>().getElementType();
387   }
388 
389   auto operandTypeBitWidth = operandType.getIntOrFloatBitWidth();
390   auto resultTypeBitWidth = resultType.getIntOrFloatBitWidth();
391   auto isSameBitWidth = operandTypeBitWidth == resultTypeBitWidth;
392 
393   if (requireSameBitWidth) {
394     if (!isSameBitWidth) {
395       return op->emitOpError(
396                  "expected the same bit widths for operand type and result "
397                  "type, but provided ")
398              << operandType << " and " << resultType;
399     }
400     return success();
401   }
402 
403   if (isSameBitWidth) {
404     return op->emitOpError(
405                "expected the different bit widths for operand type and result "
406                "type, but provided ")
407            << operandType << " and " << resultType;
408   }
409   return success();
410 }
411 
412 template <typename MemoryOpTy>
413 static LogicalResult verifyMemoryAccessAttribute(MemoryOpTy memoryOp) {
414   // ODS checks for attributes values. Just need to verify that if the
415   // memory-access attribute is Aligned, then the alignment attribute must be
416   // present.
417   auto *op = memoryOp.getOperation();
418   auto memAccessAttr = op->getAttr(kMemoryAccessAttrName);
419   if (!memAccessAttr) {
420     // Alignment attribute shouldn't be present if memory access attribute is
421     // not present.
422     if (op->getAttr(kAlignmentAttrName)) {
423       return memoryOp.emitOpError(
424           "invalid alignment specification without aligned memory access "
425           "specification");
426     }
427     return success();
428   }
429 
430   auto memAccessVal = memAccessAttr.template cast<IntegerAttr>();
431   auto memAccess = spirv::symbolizeMemoryAccess(memAccessVal.getInt());
432 
433   if (!memAccess) {
434     return memoryOp.emitOpError("invalid memory access specifier: ")
435            << memAccessVal;
436   }
437 
438   if (spirv::bitEnumContains(*memAccess, spirv::MemoryAccess::Aligned)) {
439     if (!op->getAttr(kAlignmentAttrName)) {
440       return memoryOp.emitOpError("missing alignment value");
441     }
442   } else {
443     if (op->getAttr(kAlignmentAttrName)) {
444       return memoryOp.emitOpError(
445           "invalid alignment specification with non-aligned memory access "
446           "specification");
447     }
448   }
449   return success();
450 }
451 
452 // TODO Make sure to merge this and the previous function into one template
453 // parameterized by memory access attribute name and alignment. Doing so now
454 // results in VS2017 in producing an internal error (at the call site) that's
455 // not detailed enough to understand what is happening.
456 template <typename MemoryOpTy>
457 static LogicalResult verifySourceMemoryAccessAttribute(MemoryOpTy memoryOp) {
458   // ODS checks for attributes values. Just need to verify that if the
459   // memory-access attribute is Aligned, then the alignment attribute must be
460   // present.
461   auto *op = memoryOp.getOperation();
462   auto memAccessAttr = op->getAttr(kSourceMemoryAccessAttrName);
463   if (!memAccessAttr) {
464     // Alignment attribute shouldn't be present if memory access attribute is
465     // not present.
466     if (op->getAttr(kSourceAlignmentAttrName)) {
467       return memoryOp.emitOpError(
468           "invalid alignment specification without aligned memory access "
469           "specification");
470     }
471     return success();
472   }
473 
474   auto memAccessVal = memAccessAttr.template cast<IntegerAttr>();
475   auto memAccess = spirv::symbolizeMemoryAccess(memAccessVal.getInt());
476 
477   if (!memAccess) {
478     return memoryOp.emitOpError("invalid memory access specifier: ")
479            << memAccessVal;
480   }
481 
482   if (spirv::bitEnumContains(*memAccess, spirv::MemoryAccess::Aligned)) {
483     if (!op->getAttr(kSourceAlignmentAttrName)) {
484       return memoryOp.emitOpError("missing alignment value");
485     }
486   } else {
487     if (op->getAttr(kSourceAlignmentAttrName)) {
488       return memoryOp.emitOpError(
489           "invalid alignment specification with non-aligned memory access "
490           "specification");
491     }
492   }
493   return success();
494 }
495 
496 template <typename BarrierOp>
497 static LogicalResult verifyMemorySemantics(BarrierOp op) {
498   // According to the SPIR-V specification:
499   // "Despite being a mask and allowing multiple bits to be combined, it is
500   // invalid for more than one of these four bits to be set: Acquire, Release,
501   // AcquireRelease, or SequentiallyConsistent. Requesting both Acquire and
502   // Release semantics is done by setting the AcquireRelease bit, not by setting
503   // two bits."
504   auto memorySemantics = op.memory_semantics();
505   auto atMostOneInSet = spirv::MemorySemantics::Acquire |
506                         spirv::MemorySemantics::Release |
507                         spirv::MemorySemantics::AcquireRelease |
508                         spirv::MemorySemantics::SequentiallyConsistent;
509 
510   auto bitCount = llvm::countPopulation(
511       static_cast<uint32_t>(memorySemantics & atMostOneInSet));
512   if (bitCount > 1) {
513     return op.emitError("expected at most one of these four memory constraints "
514                         "to be set: `Acquire`, `Release`,"
515                         "`AcquireRelease` or `SequentiallyConsistent`");
516   }
517   return success();
518 }
519 
520 template <typename LoadStoreOpTy>
521 static LogicalResult verifyLoadStorePtrAndValTypes(LoadStoreOpTy op, Value ptr,
522                                                    Value val) {
523   // ODS already checks ptr is spirv::PointerType. Just check that the pointee
524   // type of the pointer and the type of the value are the same
525   //
526   // TODO: Check that the value type satisfies restrictions of
527   // SPIR-V OpLoad/OpStore operations
528   if (val.getType() !=
529       ptr.getType().cast<spirv::PointerType>().getPointeeType()) {
530     return op.emitOpError("mismatch in result type and pointer type");
531   }
532   return success();
533 }
534 
535 template <typename BlockReadWriteOpTy>
536 static LogicalResult verifyBlockReadWritePtrAndValTypes(BlockReadWriteOpTy op,
537                                                         Value ptr, Value val) {
538   auto valType = val.getType();
539   if (auto valVecTy = valType.dyn_cast<VectorType>())
540     valType = valVecTy.getElementType();
541 
542   if (valType != ptr.getType().cast<spirv::PointerType>().getPointeeType()) {
543     return op.emitOpError("mismatch in result type and pointer type");
544   }
545   return success();
546 }
547 
548 static ParseResult parseVariableDecorations(OpAsmParser &parser,
549                                             OperationState &state) {
550   auto builtInName = llvm::convertToSnakeFromCamelCase(
551       stringifyDecoration(spirv::Decoration::BuiltIn));
552   if (succeeded(parser.parseOptionalKeyword("bind"))) {
553     Attribute set, binding;
554     // Parse optional descriptor binding
555     auto descriptorSetName = llvm::convertToSnakeFromCamelCase(
556         stringifyDecoration(spirv::Decoration::DescriptorSet));
557     auto bindingName = llvm::convertToSnakeFromCamelCase(
558         stringifyDecoration(spirv::Decoration::Binding));
559     Type i32Type = parser.getBuilder().getIntegerType(32);
560     if (parser.parseLParen() ||
561         parser.parseAttribute(set, i32Type, descriptorSetName,
562                               state.attributes) ||
563         parser.parseComma() ||
564         parser.parseAttribute(binding, i32Type, bindingName,
565                               state.attributes) ||
566         parser.parseRParen()) {
567       return failure();
568     }
569   } else if (succeeded(parser.parseOptionalKeyword(builtInName))) {
570     StringAttr builtIn;
571     if (parser.parseLParen() ||
572         parser.parseAttribute(builtIn, builtInName, state.attributes) ||
573         parser.parseRParen()) {
574       return failure();
575     }
576   }
577 
578   // Parse other attributes
579   if (parser.parseOptionalAttrDict(state.attributes))
580     return failure();
581 
582   return success();
583 }
584 
585 static void printVariableDecorations(Operation *op, OpAsmPrinter &printer,
586                                      SmallVectorImpl<StringRef> &elidedAttrs) {
587   // Print optional descriptor binding
588   auto descriptorSetName = llvm::convertToSnakeFromCamelCase(
589       stringifyDecoration(spirv::Decoration::DescriptorSet));
590   auto bindingName = llvm::convertToSnakeFromCamelCase(
591       stringifyDecoration(spirv::Decoration::Binding));
592   auto descriptorSet = op->getAttrOfType<IntegerAttr>(descriptorSetName);
593   auto binding = op->getAttrOfType<IntegerAttr>(bindingName);
594   if (descriptorSet && binding) {
595     elidedAttrs.push_back(descriptorSetName);
596     elidedAttrs.push_back(bindingName);
597     printer << " bind(" << descriptorSet.getInt() << ", " << binding.getInt()
598             << ")";
599   }
600 
601   // Print BuiltIn attribute if present
602   auto builtInName = llvm::convertToSnakeFromCamelCase(
603       stringifyDecoration(spirv::Decoration::BuiltIn));
604   if (auto builtin = op->getAttrOfType<StringAttr>(builtInName)) {
605     printer << " " << builtInName << "(\"" << builtin.getValue() << "\")";
606     elidedAttrs.push_back(builtInName);
607   }
608 
609   printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
610 }
611 
612 // Get bit width of types.
613 static unsigned getBitWidth(Type type) {
614   if (type.isa<spirv::PointerType>()) {
615     // Just return 64 bits for pointer types for now.
616     // TODO: Make sure not caller relies on the actual pointer width value.
617     return 64;
618   }
619 
620   if (type.isIntOrFloat())
621     return type.getIntOrFloatBitWidth();
622 
623   if (auto vectorType = type.dyn_cast<VectorType>()) {
624     assert(vectorType.getElementType().isIntOrFloat());
625     return vectorType.getNumElements() *
626            vectorType.getElementType().getIntOrFloatBitWidth();
627   }
628   llvm_unreachable("unhandled bit width computation for type");
629 }
630 
631 /// Walks the given type hierarchy with the given indices, potentially down
632 /// to component granularity, to select an element type. Returns null type and
633 /// emits errors with the given loc on failure.
634 static Type
635 getElementType(Type type, ArrayRef<int32_t> indices,
636                function_ref<InFlightDiagnostic(StringRef)> emitErrorFn) {
637   if (indices.empty()) {
638     emitErrorFn("expected at least one index for spv.CompositeExtract");
639     return nullptr;
640   }
641 
642   for (auto index : indices) {
643     if (auto cType = type.dyn_cast<spirv::CompositeType>()) {
644       if (cType.hasCompileTimeKnownNumElements() &&
645           (index < 0 ||
646            static_cast<uint64_t>(index) >= cType.getNumElements())) {
647         emitErrorFn("index ") << index << " out of bounds for " << type;
648         return nullptr;
649       }
650       type = cType.getElementType(index);
651     } else {
652       emitErrorFn("cannot extract from non-composite type ")
653           << type << " with index " << index;
654       return nullptr;
655     }
656   }
657   return type;
658 }
659 
660 static Type
661 getElementType(Type type, Attribute indices,
662                function_ref<InFlightDiagnostic(StringRef)> emitErrorFn) {
663   auto indicesArrayAttr = indices.dyn_cast<ArrayAttr>();
664   if (!indicesArrayAttr) {
665     emitErrorFn("expected a 32-bit integer array attribute for 'indices'");
666     return nullptr;
667   }
668   if (!indicesArrayAttr.size()) {
669     emitErrorFn("expected at least one index for spv.CompositeExtract");
670     return nullptr;
671   }
672 
673   SmallVector<int32_t, 2> indexVals;
674   for (auto indexAttr : indicesArrayAttr) {
675     auto indexIntAttr = indexAttr.dyn_cast<IntegerAttr>();
676     if (!indexIntAttr) {
677       emitErrorFn("expected an 32-bit integer for index, but found '")
678           << indexAttr << "'";
679       return nullptr;
680     }
681     indexVals.push_back(indexIntAttr.getInt());
682   }
683   return getElementType(type, indexVals, emitErrorFn);
684 }
685 
686 static Type getElementType(Type type, Attribute indices, Location loc) {
687   auto errorFn = [&](StringRef err) -> InFlightDiagnostic {
688     return ::mlir::emitError(loc, err);
689   };
690   return getElementType(type, indices, errorFn);
691 }
692 
693 static Type getElementType(Type type, Attribute indices, OpAsmParser &parser,
694                            llvm::SMLoc loc) {
695   auto errorFn = [&](StringRef err) -> InFlightDiagnostic {
696     return parser.emitError(loc, err);
697   };
698   return getElementType(type, indices, errorFn);
699 }
700 
701 /// Returns true if the given `block` only contains one `spv.mlir.merge` op.
702 static inline bool isMergeBlock(Block &block) {
703   return !block.empty() && std::next(block.begin()) == block.end() &&
704          isa<spirv::MergeOp>(block.front());
705 }
706 
707 //===----------------------------------------------------------------------===//
708 // Common parsers and printers
709 //===----------------------------------------------------------------------===//
710 
711 // Parses an atomic update op. If the update op does not take a value (like
712 // AtomicIIncrement) `hasValue` must be false.
713 static ParseResult parseAtomicUpdateOp(OpAsmParser &parser,
714                                        OperationState &state, bool hasValue) {
715   spirv::Scope scope;
716   spirv::MemorySemantics memoryScope;
717   SmallVector<OpAsmParser::OperandType, 2> operandInfo;
718   OpAsmParser::OperandType ptrInfo, valueInfo;
719   Type type;
720   llvm::SMLoc loc;
721   if (parseEnumStrAttr(scope, parser, state, kMemoryScopeAttrName) ||
722       parseEnumStrAttr(memoryScope, parser, state, kSemanticsAttrName) ||
723       parser.parseOperandList(operandInfo, (hasValue ? 2 : 1)) ||
724       parser.getCurrentLocation(&loc) || parser.parseColonType(type))
725     return failure();
726 
727   auto ptrType = type.dyn_cast<spirv::PointerType>();
728   if (!ptrType)
729     return parser.emitError(loc, "expected pointer type");
730 
731   SmallVector<Type, 2> operandTypes;
732   operandTypes.push_back(ptrType);
733   if (hasValue)
734     operandTypes.push_back(ptrType.getPointeeType());
735   if (parser.resolveOperands(operandInfo, operandTypes, parser.getNameLoc(),
736                              state.operands))
737     return failure();
738   return parser.addTypeToList(ptrType.getPointeeType(), state.types);
739 }
740 
741 // Prints an atomic update op.
742 static void printAtomicUpdateOp(Operation *op, OpAsmPrinter &printer) {
743   printer << " \"";
744   auto scopeAttr = op->getAttrOfType<IntegerAttr>(kMemoryScopeAttrName);
745   printer << spirv::stringifyScope(
746                  static_cast<spirv::Scope>(scopeAttr.getInt()))
747           << "\" \"";
748   auto memorySemanticsAttr = op->getAttrOfType<IntegerAttr>(kSemanticsAttrName);
749   printer << spirv::stringifyMemorySemantics(
750                  static_cast<spirv::MemorySemantics>(
751                      memorySemanticsAttr.getInt()))
752           << "\" " << op->getOperands() << " : " << op->getOperand(0).getType();
753 }
754 
755 // Verifies an atomic update op.
756 static LogicalResult verifyAtomicUpdateOp(Operation *op) {
757   auto ptrType = op->getOperand(0).getType().cast<spirv::PointerType>();
758   auto elementType = ptrType.getPointeeType();
759   if (!elementType.isa<IntegerType>())
760     return op->emitOpError(
761                "pointer operand must point to an integer value, found ")
762            << elementType;
763 
764   if (op->getNumOperands() > 1) {
765     auto valueType = op->getOperand(1).getType();
766     if (valueType != elementType)
767       return op->emitOpError("expected value to have the same type as the "
768                              "pointer operand's pointee type ")
769              << elementType << ", but found " << valueType;
770   }
771   return success();
772 }
773 
774 static ParseResult parseGroupNonUniformArithmeticOp(OpAsmParser &parser,
775                                                     OperationState &state) {
776   spirv::Scope executionScope;
777   spirv::GroupOperation groupOperation;
778   OpAsmParser::OperandType valueInfo;
779   if (parseEnumStrAttr(executionScope, parser, state,
780                        kExecutionScopeAttrName) ||
781       parseEnumStrAttr(groupOperation, parser, state,
782                        kGroupOperationAttrName) ||
783       parser.parseOperand(valueInfo))
784     return failure();
785 
786   Optional<OpAsmParser::OperandType> clusterSizeInfo;
787   if (succeeded(parser.parseOptionalKeyword(kClusterSize))) {
788     clusterSizeInfo = OpAsmParser::OperandType();
789     if (parser.parseLParen() || parser.parseOperand(*clusterSizeInfo) ||
790         parser.parseRParen())
791       return failure();
792   }
793 
794   Type resultType;
795   if (parser.parseColonType(resultType))
796     return failure();
797 
798   if (parser.resolveOperand(valueInfo, resultType, state.operands))
799     return failure();
800 
801   if (clusterSizeInfo.hasValue()) {
802     Type i32Type = parser.getBuilder().getIntegerType(32);
803     if (parser.resolveOperand(*clusterSizeInfo, i32Type, state.operands))
804       return failure();
805   }
806 
807   return parser.addTypeToList(resultType, state.types);
808 }
809 
810 static void printGroupNonUniformArithmeticOp(Operation *groupOp,
811                                              OpAsmPrinter &printer) {
812   printer << " \""
813           << stringifyScope(static_cast<spirv::Scope>(
814                  groupOp->getAttrOfType<IntegerAttr>(kExecutionScopeAttrName)
815                      .getInt()))
816           << "\" \""
817           << stringifyGroupOperation(static_cast<spirv::GroupOperation>(
818                  groupOp->getAttrOfType<IntegerAttr>(kGroupOperationAttrName)
819                      .getInt()))
820           << "\" " << groupOp->getOperand(0);
821 
822   if (groupOp->getNumOperands() > 1)
823     printer << " " << kClusterSize << '(' << groupOp->getOperand(1) << ')';
824   printer << " : " << groupOp->getResult(0).getType();
825 }
826 
827 static LogicalResult verifyGroupNonUniformArithmeticOp(Operation *groupOp) {
828   spirv::Scope scope = static_cast<spirv::Scope>(
829       groupOp->getAttrOfType<IntegerAttr>(kExecutionScopeAttrName).getInt());
830   if (scope != spirv::Scope::Workgroup && scope != spirv::Scope::Subgroup)
831     return groupOp->emitOpError(
832         "execution scope must be 'Workgroup' or 'Subgroup'");
833 
834   spirv::GroupOperation operation = static_cast<spirv::GroupOperation>(
835       groupOp->getAttrOfType<IntegerAttr>(kGroupOperationAttrName).getInt());
836   if (operation == spirv::GroupOperation::ClusteredReduce &&
837       groupOp->getNumOperands() == 1)
838     return groupOp->emitOpError("cluster size operand must be provided for "
839                                 "'ClusteredReduce' group operation");
840   if (groupOp->getNumOperands() > 1) {
841     Operation *sizeOp = groupOp->getOperand(1).getDefiningOp();
842     int32_t clusterSize = 0;
843 
844     // TODO: support specialization constant here.
845     if (failed(extractValueFromConstOp(sizeOp, clusterSize)))
846       return groupOp->emitOpError(
847           "cluster size operand must come from a constant op");
848 
849     if (!llvm::isPowerOf2_32(clusterSize))
850       return groupOp->emitOpError(
851           "cluster size operand must be a power of two");
852   }
853   return success();
854 }
855 
856 static ParseResult parseUnaryOp(OpAsmParser &parser, OperationState &state) {
857   OpAsmParser::OperandType operandInfo;
858   Type type;
859   if (parser.parseOperand(operandInfo) || parser.parseColonType(type) ||
860       parser.resolveOperands(operandInfo, type, state.operands)) {
861     return failure();
862   }
863   state.addTypes(type);
864   return success();
865 }
866 
867 static void printUnaryOp(Operation *unaryOp, OpAsmPrinter &printer) {
868   printer << ' ' << unaryOp->getOperand(0) << " : "
869           << unaryOp->getOperand(0).getType();
870 }
871 
872 /// Result of a logical op must be a scalar or vector of boolean type.
873 static Type getUnaryOpResultType(Builder &builder, Type operandType) {
874   Type resultType = builder.getIntegerType(1);
875   if (auto vecType = operandType.dyn_cast<VectorType>()) {
876     return VectorType::get(vecType.getNumElements(), resultType);
877   }
878   return resultType;
879 }
880 
881 static ParseResult parseLogicalUnaryOp(OpAsmParser &parser,
882                                        OperationState &state) {
883   OpAsmParser::OperandType operandInfo;
884   Type type;
885   if (parser.parseOperand(operandInfo) || parser.parseColonType(type) ||
886       parser.resolveOperand(operandInfo, type, state.operands)) {
887     return failure();
888   }
889   state.addTypes(getUnaryOpResultType(parser.getBuilder(), type));
890   return success();
891 }
892 
893 static ParseResult parseLogicalBinaryOp(OpAsmParser &parser,
894                                         OperationState &result) {
895   SmallVector<OpAsmParser::OperandType, 2> ops;
896   Type type;
897   if (parser.parseOperandList(ops, 2) || parser.parseColonType(type) ||
898       parser.resolveOperands(ops, type, result.operands)) {
899     return failure();
900   }
901   result.addTypes(getUnaryOpResultType(parser.getBuilder(), type));
902   return success();
903 }
904 
905 static void printLogicalOp(Operation *logicalOp, OpAsmPrinter &printer) {
906   printer << ' ' << logicalOp->getOperands() << " : "
907           << logicalOp->getOperand(0).getType();
908 }
909 
910 static ParseResult parseShiftOp(OpAsmParser &parser, OperationState &state) {
911   SmallVector<OpAsmParser::OperandType, 2> operandInfo;
912   Type baseType;
913   Type shiftType;
914   auto loc = parser.getCurrentLocation();
915 
916   if (parser.parseOperandList(operandInfo, 2) || parser.parseColon() ||
917       parser.parseType(baseType) || parser.parseComma() ||
918       parser.parseType(shiftType) ||
919       parser.resolveOperands(operandInfo, {baseType, shiftType}, loc,
920                              state.operands)) {
921     return failure();
922   }
923   state.addTypes(baseType);
924   return success();
925 }
926 
927 static void printShiftOp(Operation *op, OpAsmPrinter &printer) {
928   Value base = op->getOperand(0);
929   Value shift = op->getOperand(1);
930   printer << ' ' << base << ", " << shift << " : " << base.getType() << ", "
931           << shift.getType();
932 }
933 
934 static LogicalResult verifyShiftOp(Operation *op) {
935   if (op->getOperand(0).getType() != op->getResult(0).getType()) {
936     return op->emitError("expected the same type for the first operand and "
937                          "result, but provided ")
938            << op->getOperand(0).getType() << " and "
939            << op->getResult(0).getType();
940   }
941   return success();
942 }
943 
944 static void buildLogicalBinaryOp(OpBuilder &builder, OperationState &state,
945                                  Value lhs, Value rhs) {
946   assert(lhs.getType() == rhs.getType());
947 
948   Type boolType = builder.getI1Type();
949   if (auto vecType = lhs.getType().dyn_cast<VectorType>())
950     boolType = VectorType::get(vecType.getShape(), boolType);
951   state.addTypes(boolType);
952 
953   state.addOperands({lhs, rhs});
954 }
955 
956 static void buildLogicalUnaryOp(OpBuilder &builder, OperationState &state,
957                                 Value value) {
958   Type boolType = builder.getI1Type();
959   if (auto vecType = value.getType().dyn_cast<VectorType>())
960     boolType = VectorType::get(vecType.getShape(), boolType);
961   state.addTypes(boolType);
962 
963   state.addOperands(value);
964 }
965 
966 //===----------------------------------------------------------------------===//
967 // spv.AccessChainOp
968 //===----------------------------------------------------------------------===//
969 
970 static Type getElementPtrType(Type type, ValueRange indices, Location baseLoc) {
971   auto ptrType = type.dyn_cast<spirv::PointerType>();
972   if (!ptrType) {
973     emitError(baseLoc, "'spv.AccessChain' op expected a pointer "
974                        "to composite type, but provided ")
975         << type;
976     return nullptr;
977   }
978 
979   auto resultType = ptrType.getPointeeType();
980   auto resultStorageClass = ptrType.getStorageClass();
981   int32_t index = 0;
982 
983   for (auto indexSSA : indices) {
984     auto cType = resultType.dyn_cast<spirv::CompositeType>();
985     if (!cType) {
986       emitError(baseLoc,
987                 "'spv.AccessChain' op cannot extract from non-composite type ")
988           << resultType << " with index " << index;
989       return nullptr;
990     }
991     index = 0;
992     if (resultType.isa<spirv::StructType>()) {
993       Operation *op = indexSSA.getDefiningOp();
994       if (!op) {
995         emitError(baseLoc, "'spv.AccessChain' op index must be an "
996                            "integer spv.Constant to access "
997                            "element of spv.struct");
998         return nullptr;
999       }
1000 
1001       // TODO: this should be relaxed to allow
1002       // integer literals of other bitwidths.
1003       if (failed(extractValueFromConstOp(op, index))) {
1004         emitError(baseLoc,
1005                   "'spv.AccessChain' index must be an integer spv.Constant to "
1006                   "access element of spv.struct, but provided ")
1007             << op->getName();
1008         return nullptr;
1009       }
1010       if (index < 0 || static_cast<uint64_t>(index) >= cType.getNumElements()) {
1011         emitError(baseLoc, "'spv.AccessChain' op index ")
1012             << index << " out of bounds for " << resultType;
1013         return nullptr;
1014       }
1015     }
1016     resultType = cType.getElementType(index);
1017   }
1018   return spirv::PointerType::get(resultType, resultStorageClass);
1019 }
1020 
1021 void spirv::AccessChainOp::build(OpBuilder &builder, OperationState &state,
1022                                  Value basePtr, ValueRange indices) {
1023   auto type = getElementPtrType(basePtr.getType(), indices, state.location);
1024   assert(type && "Unable to deduce return type based on basePtr and indices");
1025   build(builder, state, type, basePtr, indices);
1026 }
1027 
1028 static ParseResult parseAccessChainOp(OpAsmParser &parser,
1029                                       OperationState &state) {
1030   OpAsmParser::OperandType ptrInfo;
1031   SmallVector<OpAsmParser::OperandType, 4> indicesInfo;
1032   Type type;
1033   auto loc = parser.getCurrentLocation();
1034   SmallVector<Type, 4> indicesTypes;
1035 
1036   if (parser.parseOperand(ptrInfo) ||
1037       parser.parseOperandList(indicesInfo, OpAsmParser::Delimiter::Square) ||
1038       parser.parseColonType(type) ||
1039       parser.resolveOperand(ptrInfo, type, state.operands)) {
1040     return failure();
1041   }
1042 
1043   // Check that the provided indices list is not empty before parsing their
1044   // type list.
1045   if (indicesInfo.empty()) {
1046     return emitError(state.location, "'spv.AccessChain' op expected at "
1047                                      "least one index ");
1048   }
1049 
1050   if (parser.parseComma() || parser.parseTypeList(indicesTypes))
1051     return failure();
1052 
1053   // Check that the indices types list is not empty and that it has a one-to-one
1054   // mapping to the provided indices.
1055   if (indicesTypes.size() != indicesInfo.size()) {
1056     return emitError(state.location, "'spv.AccessChain' op indices "
1057                                      "types' count must be equal to indices "
1058                                      "info count");
1059   }
1060 
1061   if (parser.resolveOperands(indicesInfo, indicesTypes, loc, state.operands))
1062     return failure();
1063 
1064   auto resultType = getElementPtrType(
1065       type, llvm::makeArrayRef(state.operands).drop_front(), state.location);
1066   if (!resultType) {
1067     return failure();
1068   }
1069 
1070   state.addTypes(resultType);
1071   return success();
1072 }
1073 
1074 template <typename Op>
1075 static void printAccessChain(Op op, ValueRange indices, OpAsmPrinter &printer) {
1076   printer << ' ' << op.base_ptr() << '[' << indices
1077           << "] : " << op.base_ptr().getType() << ", " << indices.getTypes();
1078 }
1079 
1080 static void print(spirv::AccessChainOp op, OpAsmPrinter &printer) {
1081   printAccessChain(op, op.indices(), printer);
1082 }
1083 
1084 template <typename Op>
1085 static LogicalResult verifyAccessChain(Op accessChainOp, ValueRange indices) {
1086   auto resultType = getElementPtrType(accessChainOp.base_ptr().getType(),
1087                                       indices, accessChainOp.getLoc());
1088   if (!resultType)
1089     return failure();
1090 
1091   auto providedResultType =
1092       accessChainOp.getType().template dyn_cast<spirv::PointerType>();
1093   if (!providedResultType)
1094     return accessChainOp.emitOpError(
1095                "result type must be a pointer, but provided")
1096            << providedResultType;
1097 
1098   if (resultType != providedResultType)
1099     return accessChainOp.emitOpError("invalid result type: expected ")
1100            << resultType << ", but provided " << providedResultType;
1101 
1102   return success();
1103 }
1104 
1105 static LogicalResult verify(spirv::AccessChainOp accessChainOp) {
1106   return verifyAccessChain(accessChainOp, accessChainOp.indices());
1107 }
1108 
1109 //===----------------------------------------------------------------------===//
1110 // spv.mlir.addressof
1111 //===----------------------------------------------------------------------===//
1112 
1113 void spirv::AddressOfOp::build(OpBuilder &builder, OperationState &state,
1114                                spirv::GlobalVariableOp var) {
1115   build(builder, state, var.type(), SymbolRefAttr::get(var));
1116 }
1117 
1118 static LogicalResult verify(spirv::AddressOfOp addressOfOp) {
1119   auto varOp = dyn_cast_or_null<spirv::GlobalVariableOp>(
1120       SymbolTable::lookupNearestSymbolFrom(addressOfOp->getParentOp(),
1121                                            addressOfOp.variableAttr()));
1122   if (!varOp) {
1123     return addressOfOp.emitOpError("expected spv.GlobalVariable symbol");
1124   }
1125   if (addressOfOp.pointer().getType() != varOp.type()) {
1126     return addressOfOp.emitOpError(
1127         "result type mismatch with the referenced global variable's type");
1128   }
1129   return success();
1130 }
1131 
1132 //===----------------------------------------------------------------------===//
1133 // spv.AtomicCompareExchangeWeak
1134 //===----------------------------------------------------------------------===//
1135 
1136 static ParseResult parseAtomicCompareExchangeWeakOp(OpAsmParser &parser,
1137                                                     OperationState &state) {
1138   spirv::Scope memoryScope;
1139   spirv::MemorySemantics equalSemantics, unequalSemantics;
1140   SmallVector<OpAsmParser::OperandType, 3> operandInfo;
1141   Type type;
1142   if (parseEnumStrAttr(memoryScope, parser, state, kMemoryScopeAttrName) ||
1143       parseEnumStrAttr(equalSemantics, parser, state,
1144                        kEqualSemanticsAttrName) ||
1145       parseEnumStrAttr(unequalSemantics, parser, state,
1146                        kUnequalSemanticsAttrName) ||
1147       parser.parseOperandList(operandInfo, 3))
1148     return failure();
1149 
1150   auto loc = parser.getCurrentLocation();
1151   if (parser.parseColonType(type))
1152     return failure();
1153 
1154   auto ptrType = type.dyn_cast<spirv::PointerType>();
1155   if (!ptrType)
1156     return parser.emitError(loc, "expected pointer type");
1157 
1158   if (parser.resolveOperands(
1159           operandInfo,
1160           {ptrType, ptrType.getPointeeType(), ptrType.getPointeeType()},
1161           parser.getNameLoc(), state.operands))
1162     return failure();
1163 
1164   return parser.addTypeToList(ptrType.getPointeeType(), state.types);
1165 }
1166 
1167 static void print(spirv::AtomicCompareExchangeWeakOp atomOp,
1168                   OpAsmPrinter &printer) {
1169   printer << " \"" << stringifyScope(atomOp.memory_scope()) << "\" \""
1170           << stringifyMemorySemantics(atomOp.equal_semantics()) << "\" \""
1171           << stringifyMemorySemantics(atomOp.unequal_semantics()) << "\" "
1172           << atomOp.getOperands() << " : " << atomOp.pointer().getType();
1173 }
1174 
1175 static LogicalResult verify(spirv::AtomicCompareExchangeWeakOp atomOp) {
1176   // According to the spec:
1177   // "The type of Value must be the same as Result Type. The type of the value
1178   // pointed to by Pointer must be the same as Result Type. This type must also
1179   // match the type of Comparator."
1180   if (atomOp.getType() != atomOp.value().getType())
1181     return atomOp.emitOpError("value operand must have the same type as the op "
1182                               "result, but found ")
1183            << atomOp.value().getType() << " vs " << atomOp.getType();
1184 
1185   if (atomOp.getType() != atomOp.comparator().getType())
1186     return atomOp.emitOpError(
1187                "comparator operand must have the same type as the op "
1188                "result, but found ")
1189            << atomOp.comparator().getType() << " vs " << atomOp.getType();
1190 
1191   Type pointeeType =
1192       atomOp.pointer().getType().cast<spirv::PointerType>().getPointeeType();
1193   if (atomOp.getType() != pointeeType)
1194     return atomOp.emitOpError(
1195                "pointer operand's pointee type must have the same "
1196                "as the op result type, but found ")
1197            << pointeeType << " vs " << atomOp.getType();
1198 
1199   // TODO: Unequal cannot be set to Release or Acquire and Release.
1200   // In addition, Unequal cannot be set to a stronger memory-order then Equal.
1201 
1202   return success();
1203 }
1204 
1205 //===----------------------------------------------------------------------===//
1206 // spv.BitcastOp
1207 //===----------------------------------------------------------------------===//
1208 
1209 static LogicalResult verify(spirv::BitcastOp bitcastOp) {
1210   // TODO: The SPIR-V spec validation rules are different for different
1211   // versions.
1212   auto operandType = bitcastOp.operand().getType();
1213   auto resultType = bitcastOp.result().getType();
1214   if (operandType == resultType) {
1215     return bitcastOp.emitError(
1216         "result type must be different from operand type");
1217   }
1218   if (operandType.isa<spirv::PointerType>() &&
1219       !resultType.isa<spirv::PointerType>()) {
1220     return bitcastOp.emitError(
1221         "unhandled bit cast conversion from pointer type to non-pointer type");
1222   }
1223   if (!operandType.isa<spirv::PointerType>() &&
1224       resultType.isa<spirv::PointerType>()) {
1225     return bitcastOp.emitError(
1226         "unhandled bit cast conversion from non-pointer type to pointer type");
1227   }
1228   auto operandBitWidth = getBitWidth(operandType);
1229   auto resultBitWidth = getBitWidth(resultType);
1230   if (operandBitWidth != resultBitWidth) {
1231     return bitcastOp.emitOpError("mismatch in result type bitwidth ")
1232            << resultBitWidth << " and operand type bitwidth "
1233            << operandBitWidth;
1234   }
1235   return success();
1236 }
1237 
1238 //===----------------------------------------------------------------------===//
1239 // spv.BranchOp
1240 //===----------------------------------------------------------------------===//
1241 
1242 Optional<MutableOperandRange>
1243 spirv::BranchOp::getMutableSuccessorOperands(unsigned index) {
1244   assert(index == 0 && "invalid successor index");
1245   return targetOperandsMutable();
1246 }
1247 
1248 //===----------------------------------------------------------------------===//
1249 // spv.BranchConditionalOp
1250 //===----------------------------------------------------------------------===//
1251 
1252 Optional<MutableOperandRange>
1253 spirv::BranchConditionalOp::getMutableSuccessorOperands(unsigned index) {
1254   assert(index < 2 && "invalid successor index");
1255   return index == kTrueIndex ? trueTargetOperandsMutable()
1256                              : falseTargetOperandsMutable();
1257 }
1258 
1259 static ParseResult parseBranchConditionalOp(OpAsmParser &parser,
1260                                             OperationState &state) {
1261   auto &builder = parser.getBuilder();
1262   OpAsmParser::OperandType condInfo;
1263   Block *dest;
1264 
1265   // Parse the condition.
1266   Type boolTy = builder.getI1Type();
1267   if (parser.parseOperand(condInfo) ||
1268       parser.resolveOperand(condInfo, boolTy, state.operands))
1269     return failure();
1270 
1271   // Parse the optional branch weights.
1272   if (succeeded(parser.parseOptionalLSquare())) {
1273     IntegerAttr trueWeight, falseWeight;
1274     NamedAttrList weights;
1275 
1276     auto i32Type = builder.getIntegerType(32);
1277     if (parser.parseAttribute(trueWeight, i32Type, "weight", weights) ||
1278         parser.parseComma() ||
1279         parser.parseAttribute(falseWeight, i32Type, "weight", weights) ||
1280         parser.parseRSquare())
1281       return failure();
1282 
1283     state.addAttribute(kBranchWeightAttrName,
1284                        builder.getArrayAttr({trueWeight, falseWeight}));
1285   }
1286 
1287   // Parse the true branch.
1288   SmallVector<Value, 4> trueOperands;
1289   if (parser.parseComma() ||
1290       parser.parseSuccessorAndUseList(dest, trueOperands))
1291     return failure();
1292   state.addSuccessors(dest);
1293   state.addOperands(trueOperands);
1294 
1295   // Parse the false branch.
1296   SmallVector<Value, 4> falseOperands;
1297   if (parser.parseComma() ||
1298       parser.parseSuccessorAndUseList(dest, falseOperands))
1299     return failure();
1300   state.addSuccessors(dest);
1301   state.addOperands(falseOperands);
1302   state.addAttribute(
1303       spirv::BranchConditionalOp::getOperandSegmentSizeAttr(),
1304       builder.getI32VectorAttr({1, static_cast<int32_t>(trueOperands.size()),
1305                                 static_cast<int32_t>(falseOperands.size())}));
1306 
1307   return success();
1308 }
1309 
1310 static void print(spirv::BranchConditionalOp branchOp, OpAsmPrinter &printer) {
1311   printer << ' ' << branchOp.condition();
1312 
1313   if (auto weights = branchOp.branch_weights()) {
1314     printer << " [";
1315     llvm::interleaveComma(weights->getValue(), printer, [&](Attribute a) {
1316       printer << a.cast<IntegerAttr>().getInt();
1317     });
1318     printer << "]";
1319   }
1320 
1321   printer << ", ";
1322   printer.printSuccessorAndUseList(branchOp.getTrueBlock(),
1323                                    branchOp.getTrueBlockArguments());
1324   printer << ", ";
1325   printer.printSuccessorAndUseList(branchOp.getFalseBlock(),
1326                                    branchOp.getFalseBlockArguments());
1327 }
1328 
1329 static LogicalResult verify(spirv::BranchConditionalOp branchOp) {
1330   if (auto weights = branchOp.branch_weights()) {
1331     if (weights->getValue().size() != 2) {
1332       return branchOp.emitOpError("must have exactly two branch weights");
1333     }
1334     if (llvm::all_of(*weights, [](Attribute attr) {
1335           return attr.cast<IntegerAttr>().getValue().isNullValue();
1336         }))
1337       return branchOp.emitOpError("branch weights cannot both be zero");
1338   }
1339 
1340   return success();
1341 }
1342 
1343 //===----------------------------------------------------------------------===//
1344 // spv.CompositeConstruct
1345 //===----------------------------------------------------------------------===//
1346 
1347 static ParseResult parseCompositeConstructOp(OpAsmParser &parser,
1348                                              OperationState &state) {
1349   SmallVector<OpAsmParser::OperandType, 4> operands;
1350   Type type;
1351   auto loc = parser.getCurrentLocation();
1352 
1353   if (parser.parseOperandList(operands) || parser.parseColonType(type)) {
1354     return failure();
1355   }
1356   auto cType = type.dyn_cast<spirv::CompositeType>();
1357   if (!cType) {
1358     return parser.emitError(
1359                loc, "result type must be a composite type, but provided ")
1360            << type;
1361   }
1362 
1363   if (cType.hasCompileTimeKnownNumElements() &&
1364       operands.size() != cType.getNumElements()) {
1365     return parser.emitError(loc, "has incorrect number of operands: expected ")
1366            << cType.getNumElements() << ", but provided " << operands.size();
1367   }
1368   // TODO: Add support for constructing a vector type from the vector operands.
1369   // According to the spec: "for constructing a vector, the operands may
1370   // also be vectors with the same component type as the Result Type component
1371   // type".
1372   SmallVector<Type, 4> elementTypes;
1373   elementTypes.reserve(operands.size());
1374   for (auto index : llvm::seq<uint32_t>(0, operands.size())) {
1375     elementTypes.push_back(cType.getElementType(index));
1376   }
1377   state.addTypes(type);
1378   return parser.resolveOperands(operands, elementTypes, loc, state.operands);
1379 }
1380 
1381 static void print(spirv::CompositeConstructOp compositeConstructOp,
1382                   OpAsmPrinter &printer) {
1383   printer << " " << compositeConstructOp.constituents() << " : "
1384           << compositeConstructOp.getResult().getType();
1385 }
1386 
1387 static LogicalResult verify(spirv::CompositeConstructOp compositeConstructOp) {
1388   auto cType = compositeConstructOp.getType().cast<spirv::CompositeType>();
1389   SmallVector<Value, 4> constituents(compositeConstructOp.constituents());
1390 
1391   if (cType.isa<spirv::CooperativeMatrixNVType>()) {
1392     if (constituents.size() != 1)
1393       return compositeConstructOp.emitError(
1394                  "has incorrect number of operands: expected ")
1395              << "1, but provided " << constituents.size();
1396   } else if (constituents.size() != cType.getNumElements()) {
1397     return compositeConstructOp.emitError(
1398                "has incorrect number of operands: expected ")
1399            << cType.getNumElements() << ", but provided "
1400            << constituents.size();
1401   }
1402 
1403   for (auto index : llvm::seq<uint32_t>(0, constituents.size())) {
1404     if (constituents[index].getType() != cType.getElementType(index)) {
1405       return compositeConstructOp.emitError(
1406                  "operand type mismatch: expected operand type ")
1407              << cType.getElementType(index) << ", but provided "
1408              << constituents[index].getType();
1409     }
1410   }
1411 
1412   return success();
1413 }
1414 
1415 //===----------------------------------------------------------------------===//
1416 // spv.CompositeExtractOp
1417 //===----------------------------------------------------------------------===//
1418 
1419 void spirv::CompositeExtractOp::build(OpBuilder &builder, OperationState &state,
1420                                       Value composite,
1421                                       ArrayRef<int32_t> indices) {
1422   auto indexAttr = builder.getI32ArrayAttr(indices);
1423   auto elementType =
1424       getElementType(composite.getType(), indexAttr, state.location);
1425   if (!elementType) {
1426     return;
1427   }
1428   build(builder, state, elementType, composite, indexAttr);
1429 }
1430 
1431 static ParseResult parseCompositeExtractOp(OpAsmParser &parser,
1432                                            OperationState &state) {
1433   OpAsmParser::OperandType compositeInfo;
1434   Attribute indicesAttr;
1435   Type compositeType;
1436   llvm::SMLoc attrLocation;
1437 
1438   if (parser.parseOperand(compositeInfo) ||
1439       parser.getCurrentLocation(&attrLocation) ||
1440       parser.parseAttribute(indicesAttr, kIndicesAttrName, state.attributes) ||
1441       parser.parseColonType(compositeType) ||
1442       parser.resolveOperand(compositeInfo, compositeType, state.operands)) {
1443     return failure();
1444   }
1445 
1446   Type resultType =
1447       getElementType(compositeType, indicesAttr, parser, attrLocation);
1448   if (!resultType) {
1449     return failure();
1450   }
1451   state.addTypes(resultType);
1452   return success();
1453 }
1454 
1455 static void print(spirv::CompositeExtractOp compositeExtractOp,
1456                   OpAsmPrinter &printer) {
1457   printer << ' ' << compositeExtractOp.composite()
1458           << compositeExtractOp.indices() << " : "
1459           << compositeExtractOp.composite().getType();
1460 }
1461 
1462 static LogicalResult verify(spirv::CompositeExtractOp compExOp) {
1463   auto indicesArrayAttr = compExOp.indices().dyn_cast<ArrayAttr>();
1464   auto resultType = getElementType(compExOp.composite().getType(),
1465                                    indicesArrayAttr, compExOp.getLoc());
1466   if (!resultType)
1467     return failure();
1468 
1469   if (resultType != compExOp.getType()) {
1470     return compExOp.emitOpError("invalid result type: expected ")
1471            << resultType << " but provided " << compExOp.getType();
1472   }
1473 
1474   return success();
1475 }
1476 
1477 //===----------------------------------------------------------------------===//
1478 // spv.CompositeInsert
1479 //===----------------------------------------------------------------------===//
1480 
1481 void spirv::CompositeInsertOp::build(OpBuilder &builder, OperationState &state,
1482                                      Value object, Value composite,
1483                                      ArrayRef<int32_t> indices) {
1484   auto indexAttr = builder.getI32ArrayAttr(indices);
1485   build(builder, state, composite.getType(), object, composite, indexAttr);
1486 }
1487 
1488 static ParseResult parseCompositeInsertOp(OpAsmParser &parser,
1489                                           OperationState &state) {
1490   SmallVector<OpAsmParser::OperandType, 2> operands;
1491   Type objectType, compositeType;
1492   Attribute indicesAttr;
1493   auto loc = parser.getCurrentLocation();
1494 
1495   return failure(
1496       parser.parseOperandList(operands, 2) ||
1497       parser.parseAttribute(indicesAttr, kIndicesAttrName, state.attributes) ||
1498       parser.parseColonType(objectType) ||
1499       parser.parseKeywordType("into", compositeType) ||
1500       parser.resolveOperands(operands, {objectType, compositeType}, loc,
1501                              state.operands) ||
1502       parser.addTypesToList(compositeType, state.types));
1503 }
1504 
1505 static LogicalResult verify(spirv::CompositeInsertOp compositeInsertOp) {
1506   auto indicesArrayAttr = compositeInsertOp.indices().dyn_cast<ArrayAttr>();
1507   auto objectType =
1508       getElementType(compositeInsertOp.composite().getType(), indicesArrayAttr,
1509                      compositeInsertOp.getLoc());
1510   if (!objectType)
1511     return failure();
1512 
1513   if (objectType != compositeInsertOp.object().getType()) {
1514     return compositeInsertOp.emitOpError("object operand type should be ")
1515            << objectType << ", but found "
1516            << compositeInsertOp.object().getType();
1517   }
1518 
1519   if (compositeInsertOp.composite().getType() != compositeInsertOp.getType()) {
1520     return compositeInsertOp.emitOpError("result type should be the same as "
1521                                          "the composite type, but found ")
1522            << compositeInsertOp.composite().getType() << " vs "
1523            << compositeInsertOp.getType();
1524   }
1525 
1526   return success();
1527 }
1528 
1529 static void print(spirv::CompositeInsertOp compositeInsertOp,
1530                   OpAsmPrinter &printer) {
1531   printer << " " << compositeInsertOp.object() << ", "
1532           << compositeInsertOp.composite() << compositeInsertOp.indices()
1533           << " : " << compositeInsertOp.object().getType() << " into "
1534           << compositeInsertOp.composite().getType();
1535 }
1536 
1537 //===----------------------------------------------------------------------===//
1538 // spv.Constant
1539 //===----------------------------------------------------------------------===//
1540 
1541 static ParseResult parseConstantOp(OpAsmParser &parser, OperationState &state) {
1542   Attribute value;
1543   if (parser.parseAttribute(value, kValueAttrName, state.attributes))
1544     return failure();
1545 
1546   Type type = value.getType();
1547   if (type.isa<NoneType, TensorType>()) {
1548     if (parser.parseColonType(type))
1549       return failure();
1550   }
1551 
1552   return parser.addTypeToList(type, state.types);
1553 }
1554 
1555 static void print(spirv::ConstantOp constOp, OpAsmPrinter &printer) {
1556   printer << ' ' << constOp.value();
1557   if (constOp.getType().isa<spirv::ArrayType>())
1558     printer << " : " << constOp.getType();
1559 }
1560 
1561 static LogicalResult verify(spirv::ConstantOp constOp) {
1562   auto opType = constOp.getType();
1563   auto value = constOp.value();
1564   auto valueType = value.getType();
1565 
1566   // ODS already generates checks to make sure the result type is valid. We just
1567   // need to additionally check that the value's attribute type is consistent
1568   // with the result type.
1569   if (value.isa<IntegerAttr, FloatAttr>()) {
1570     if (valueType != opType)
1571       return constOp.emitOpError("result type (")
1572              << opType << ") does not match value type (" << valueType << ")";
1573     return success();
1574   }
1575   if (value.isa<DenseIntOrFPElementsAttr, SparseElementsAttr>()) {
1576     if (valueType == opType)
1577       return success();
1578     auto arrayType = opType.dyn_cast<spirv::ArrayType>();
1579     auto shapedType = valueType.dyn_cast<ShapedType>();
1580     if (!arrayType) {
1581       return constOp.emitOpError(
1582           "must have spv.array result type for array value");
1583     }
1584 
1585     int numElements = arrayType.getNumElements();
1586     auto opElemType = arrayType.getElementType();
1587     while (auto t = opElemType.dyn_cast<spirv::ArrayType>()) {
1588       numElements *= t.getNumElements();
1589       opElemType = t.getElementType();
1590     }
1591     if (!opElemType.isIntOrFloat())
1592       return constOp.emitOpError("only support nested array result type");
1593 
1594     auto valueElemType = shapedType.getElementType();
1595     if (valueElemType != opElemType) {
1596       return constOp.emitOpError("result element type (")
1597              << opElemType << ") does not match value element type ("
1598              << valueElemType << ")";
1599     }
1600 
1601     if (numElements != shapedType.getNumElements()) {
1602       return constOp.emitOpError("result number of elements (")
1603              << numElements << ") does not match value number of elements ("
1604              << shapedType.getNumElements() << ")";
1605     }
1606     return success();
1607   }
1608   if (auto attayAttr = value.dyn_cast<ArrayAttr>()) {
1609     auto arrayType = opType.dyn_cast<spirv::ArrayType>();
1610     if (!arrayType)
1611       return constOp.emitOpError(
1612           "must have spv.array result type for array value");
1613     Type elemType = arrayType.getElementType();
1614     for (Attribute element : attayAttr.getValue()) {
1615       if (element.getType() != elemType)
1616         return constOp.emitOpError("has array element whose type (")
1617                << element.getType()
1618                << ") does not match the result element type (" << elemType
1619                << ')';
1620     }
1621     return success();
1622   }
1623   return constOp.emitOpError("cannot have value of type ") << valueType;
1624 }
1625 
1626 bool spirv::ConstantOp::isBuildableWith(Type type) {
1627   // Must be valid SPIR-V type first.
1628   if (!type.isa<spirv::SPIRVType>())
1629     return false;
1630 
1631   if (isa<SPIRVDialect>(type.getDialect())) {
1632     // TODO: support constant struct
1633     return type.isa<spirv::ArrayType>();
1634   }
1635 
1636   return true;
1637 }
1638 
1639 spirv::ConstantOp spirv::ConstantOp::getZero(Type type, Location loc,
1640                                              OpBuilder &builder) {
1641   if (auto intType = type.dyn_cast<IntegerType>()) {
1642     unsigned width = intType.getWidth();
1643     if (width == 1)
1644       return builder.create<spirv::ConstantOp>(loc, type,
1645                                                builder.getBoolAttr(false));
1646     return builder.create<spirv::ConstantOp>(
1647         loc, type, builder.getIntegerAttr(type, APInt(width, 0)));
1648   }
1649   if (auto floatType = type.dyn_cast<FloatType>()) {
1650     return builder.create<spirv::ConstantOp>(
1651         loc, type, builder.getFloatAttr(floatType, 0.0));
1652   }
1653   if (auto vectorType = type.dyn_cast<VectorType>()) {
1654     Type elemType = vectorType.getElementType();
1655     if (elemType.isa<IntegerType>()) {
1656       return builder.create<spirv::ConstantOp>(
1657           loc, type,
1658           DenseElementsAttr::get(vectorType,
1659                                  IntegerAttr::get(elemType, 0.0).getValue()));
1660     }
1661     if (elemType.isa<FloatType>()) {
1662       return builder.create<spirv::ConstantOp>(
1663           loc, type,
1664           DenseFPElementsAttr::get(vectorType,
1665                                    FloatAttr::get(elemType, 0.0).getValue()));
1666     }
1667   }
1668 
1669   llvm_unreachable("unimplemented types for ConstantOp::getZero()");
1670 }
1671 
1672 spirv::ConstantOp spirv::ConstantOp::getOne(Type type, Location loc,
1673                                             OpBuilder &builder) {
1674   if (auto intType = type.dyn_cast<IntegerType>()) {
1675     unsigned width = intType.getWidth();
1676     if (width == 1)
1677       return builder.create<spirv::ConstantOp>(loc, type,
1678                                                builder.getBoolAttr(true));
1679     return builder.create<spirv::ConstantOp>(
1680         loc, type, builder.getIntegerAttr(type, APInt(width, 1)));
1681   }
1682   if (auto floatType = type.dyn_cast<FloatType>()) {
1683     return builder.create<spirv::ConstantOp>(
1684         loc, type, builder.getFloatAttr(floatType, 1.0));
1685   }
1686   if (auto vectorType = type.dyn_cast<VectorType>()) {
1687     Type elemType = vectorType.getElementType();
1688     if (elemType.isa<IntegerType>()) {
1689       return builder.create<spirv::ConstantOp>(
1690           loc, type,
1691           DenseElementsAttr::get(vectorType,
1692                                  IntegerAttr::get(elemType, 1.0).getValue()));
1693     }
1694     if (elemType.isa<FloatType>()) {
1695       return builder.create<spirv::ConstantOp>(
1696           loc, type,
1697           DenseFPElementsAttr::get(vectorType,
1698                                    FloatAttr::get(elemType, 1.0).getValue()));
1699     }
1700   }
1701 
1702   llvm_unreachable("unimplemented types for ConstantOp::getOne()");
1703 }
1704 
1705 void mlir::spirv::ConstantOp::getAsmResultNames(
1706     llvm::function_ref<void(mlir::Value, llvm::StringRef)> setNameFn) {
1707   Type type = getType();
1708 
1709   SmallString<32> specialNameBuffer;
1710   llvm::raw_svector_ostream specialName(specialNameBuffer);
1711   specialName << "cst";
1712 
1713   IntegerType intTy = type.dyn_cast<IntegerType>();
1714 
1715   if (IntegerAttr intCst = value().dyn_cast<IntegerAttr>()) {
1716     if (intTy && intTy.getWidth() == 1) {
1717       return setNameFn(getResult(), (intCst.getInt() ? "true" : "false"));
1718     }
1719 
1720     if (intTy.isSignless()) {
1721       specialName << intCst.getInt();
1722     } else {
1723       specialName << intCst.getSInt();
1724     }
1725   }
1726 
1727   if (intTy || type.isa<FloatType>()) {
1728     specialName << '_' << type;
1729   }
1730 
1731   if (auto vecType = type.dyn_cast<VectorType>()) {
1732     specialName << "_vec_";
1733     specialName << vecType.getDimSize(0);
1734 
1735     Type elementType = vecType.getElementType();
1736 
1737     if (elementType.isa<IntegerType>() || elementType.isa<FloatType>()) {
1738       specialName << "x" << elementType;
1739     }
1740   }
1741 
1742   setNameFn(getResult(), specialName.str());
1743 }
1744 
1745 void mlir::spirv::AddressOfOp::getAsmResultNames(
1746     llvm::function_ref<void(mlir::Value, llvm::StringRef)> setNameFn) {
1747   SmallString<32> specialNameBuffer;
1748   llvm::raw_svector_ostream specialName(specialNameBuffer);
1749   specialName << variable() << "_addr";
1750   setNameFn(getResult(), specialName.str());
1751 }
1752 
1753 //===----------------------------------------------------------------------===//
1754 // spv.EntryPoint
1755 //===----------------------------------------------------------------------===//
1756 
1757 void spirv::EntryPointOp::build(OpBuilder &builder, OperationState &state,
1758                                 spirv::ExecutionModel executionModel,
1759                                 spirv::FuncOp function,
1760                                 ArrayRef<Attribute> interfaceVars) {
1761   build(builder, state,
1762         spirv::ExecutionModelAttr::get(builder.getContext(), executionModel),
1763         SymbolRefAttr::get(function), builder.getArrayAttr(interfaceVars));
1764 }
1765 
1766 static ParseResult parseEntryPointOp(OpAsmParser &parser,
1767                                      OperationState &state) {
1768   spirv::ExecutionModel execModel;
1769   SmallVector<OpAsmParser::OperandType, 0> identifiers;
1770   SmallVector<Type, 0> idTypes;
1771   SmallVector<Attribute, 4> interfaceVars;
1772 
1773   FlatSymbolRefAttr fn;
1774   if (parseEnumStrAttr(execModel, parser, state) ||
1775       parser.parseAttribute(fn, Type(), kFnNameAttrName, state.attributes)) {
1776     return failure();
1777   }
1778 
1779   if (!parser.parseOptionalComma()) {
1780     // Parse the interface variables
1781     do {
1782       // The name of the interface variable attribute isnt important
1783       auto attrName = "var_symbol";
1784       FlatSymbolRefAttr var;
1785       NamedAttrList attrs;
1786       if (parser.parseAttribute(var, Type(), attrName, attrs)) {
1787         return failure();
1788       }
1789       interfaceVars.push_back(var);
1790     } while (!parser.parseOptionalComma());
1791   }
1792   state.addAttribute(kInterfaceAttrName,
1793                      parser.getBuilder().getArrayAttr(interfaceVars));
1794   return success();
1795 }
1796 
1797 static void print(spirv::EntryPointOp entryPointOp, OpAsmPrinter &printer) {
1798   printer << " \"" << stringifyExecutionModel(entryPointOp.execution_model())
1799           << "\" ";
1800   printer.printSymbolName(entryPointOp.fn());
1801   auto interfaceVars = entryPointOp.interface().getValue();
1802   if (!interfaceVars.empty()) {
1803     printer << ", ";
1804     llvm::interleaveComma(interfaceVars, printer);
1805   }
1806 }
1807 
1808 static LogicalResult verify(spirv::EntryPointOp entryPointOp) {
1809   // Checks for fn and interface symbol reference are done in spirv::ModuleOp
1810   // verification.
1811   return success();
1812 }
1813 
1814 //===----------------------------------------------------------------------===//
1815 // spv.ExecutionMode
1816 //===----------------------------------------------------------------------===//
1817 
1818 void spirv::ExecutionModeOp::build(OpBuilder &builder, OperationState &state,
1819                                    spirv::FuncOp function,
1820                                    spirv::ExecutionMode executionMode,
1821                                    ArrayRef<int32_t> params) {
1822   build(builder, state, SymbolRefAttr::get(function),
1823         spirv::ExecutionModeAttr::get(builder.getContext(), executionMode),
1824         builder.getI32ArrayAttr(params));
1825 }
1826 
1827 static ParseResult parseExecutionModeOp(OpAsmParser &parser,
1828                                         OperationState &state) {
1829   spirv::ExecutionMode execMode;
1830   Attribute fn;
1831   if (parser.parseAttribute(fn, kFnNameAttrName, state.attributes) ||
1832       parseEnumStrAttr(execMode, parser, state)) {
1833     return failure();
1834   }
1835 
1836   SmallVector<int32_t, 4> values;
1837   Type i32Type = parser.getBuilder().getIntegerType(32);
1838   while (!parser.parseOptionalComma()) {
1839     NamedAttrList attr;
1840     Attribute value;
1841     if (parser.parseAttribute(value, i32Type, "value", attr)) {
1842       return failure();
1843     }
1844     values.push_back(value.cast<IntegerAttr>().getInt());
1845   }
1846   state.addAttribute(kValuesAttrName,
1847                      parser.getBuilder().getI32ArrayAttr(values));
1848   return success();
1849 }
1850 
1851 static void print(spirv::ExecutionModeOp execModeOp, OpAsmPrinter &printer) {
1852   printer << " ";
1853   printer.printSymbolName(execModeOp.fn());
1854   printer << " \"" << stringifyExecutionMode(execModeOp.execution_mode())
1855           << "\"";
1856   auto values = execModeOp.values();
1857   if (!values.size())
1858     return;
1859   printer << ", ";
1860   llvm::interleaveComma(values, printer, [&](Attribute a) {
1861     printer << a.cast<IntegerAttr>().getInt();
1862   });
1863 }
1864 
1865 //===----------------------------------------------------------------------===//
1866 // spv.func
1867 //===----------------------------------------------------------------------===//
1868 
1869 static ParseResult parseFuncOp(OpAsmParser &parser, OperationState &state) {
1870   SmallVector<OpAsmParser::OperandType, 4> entryArgs;
1871   SmallVector<NamedAttrList, 4> argAttrs;
1872   SmallVector<NamedAttrList, 4> resultAttrs;
1873   SmallVector<Type, 4> argTypes;
1874   SmallVector<Type, 4> resultTypes;
1875   auto &builder = parser.getBuilder();
1876 
1877   // Parse the name as a symbol.
1878   StringAttr nameAttr;
1879   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
1880                              state.attributes))
1881     return failure();
1882 
1883   // Parse the function signature.
1884   bool isVariadic = false;
1885   if (function_like_impl::parseFunctionSignature(
1886           parser, /*allowVariadic=*/false, entryArgs, argTypes, argAttrs,
1887           isVariadic, resultTypes, resultAttrs))
1888     return failure();
1889 
1890   auto fnType = builder.getFunctionType(argTypes, resultTypes);
1891   state.addAttribute(function_like_impl::getTypeAttrName(),
1892                      TypeAttr::get(fnType));
1893 
1894   // Parse the optional function control keyword.
1895   spirv::FunctionControl fnControl;
1896   if (parseEnumStrAttr(fnControl, parser, state))
1897     return failure();
1898 
1899   // If additional attributes are present, parse them.
1900   if (parser.parseOptionalAttrDictWithKeyword(state.attributes))
1901     return failure();
1902 
1903   // Add the attributes to the function arguments.
1904   assert(argAttrs.size() == argTypes.size());
1905   assert(resultAttrs.size() == resultTypes.size());
1906   function_like_impl::addArgAndResultAttrs(builder, state, argAttrs,
1907                                            resultAttrs);
1908 
1909   // Parse the optional function body.
1910   auto *body = state.addRegion();
1911   OptionalParseResult result = parser.parseOptionalRegion(
1912       *body, entryArgs, entryArgs.empty() ? ArrayRef<Type>() : argTypes);
1913   return failure(result.hasValue() && failed(*result));
1914 }
1915 
1916 static void print(spirv::FuncOp fnOp, OpAsmPrinter &printer) {
1917   // Print function name, signature, and control.
1918   printer << " ";
1919   printer.printSymbolName(fnOp.sym_name());
1920   auto fnType = fnOp.getType();
1921   function_like_impl::printFunctionSignature(printer, fnOp, fnType.getInputs(),
1922                                              /*isVariadic=*/false,
1923                                              fnType.getResults());
1924   printer << " \"" << spirv::stringifyFunctionControl(fnOp.function_control())
1925           << "\"";
1926   function_like_impl::printFunctionAttributes(
1927       printer, fnOp, fnType.getNumInputs(), fnType.getNumResults(),
1928       {spirv::attributeName<spirv::FunctionControl>()});
1929 
1930   // Print the body if this is not an external function.
1931   Region &body = fnOp.body();
1932   if (!body.empty())
1933     printer.printRegion(body, /*printEntryBlockArgs=*/false,
1934                         /*printBlockTerminators=*/true);
1935 }
1936 
1937 LogicalResult spirv::FuncOp::verifyType() {
1938   auto type = getTypeAttr().getValue();
1939   if (!type.isa<FunctionType>())
1940     return emitOpError("requires '" + getTypeAttrName() +
1941                        "' attribute of function type");
1942   if (getType().getNumResults() > 1)
1943     return emitOpError("cannot have more than one result");
1944   return success();
1945 }
1946 
1947 LogicalResult spirv::FuncOp::verifyBody() {
1948   FunctionType fnType = getType();
1949 
1950   auto walkResult = walk([fnType](Operation *op) -> WalkResult {
1951     if (auto retOp = dyn_cast<spirv::ReturnOp>(op)) {
1952       if (fnType.getNumResults() != 0)
1953         return retOp.emitOpError("cannot be used in functions returning value");
1954     } else if (auto retOp = dyn_cast<spirv::ReturnValueOp>(op)) {
1955       if (fnType.getNumResults() != 1)
1956         return retOp.emitOpError(
1957                    "returns 1 value but enclosing function requires ")
1958                << fnType.getNumResults() << " results";
1959 
1960       auto retOperandType = retOp.value().getType();
1961       auto fnResultType = fnType.getResult(0);
1962       if (retOperandType != fnResultType)
1963         return retOp.emitOpError(" return value's type (")
1964                << retOperandType << ") mismatch with function's result type ("
1965                << fnResultType << ")";
1966     }
1967     return WalkResult::advance();
1968   });
1969 
1970   // TODO: verify other bits like linkage type.
1971 
1972   return failure(walkResult.wasInterrupted());
1973 }
1974 
1975 void spirv::FuncOp::build(OpBuilder &builder, OperationState &state,
1976                           StringRef name, FunctionType type,
1977                           spirv::FunctionControl control,
1978                           ArrayRef<NamedAttribute> attrs) {
1979   state.addAttribute(SymbolTable::getSymbolAttrName(),
1980                      builder.getStringAttr(name));
1981   state.addAttribute(getTypeAttrName(), TypeAttr::get(type));
1982   state.addAttribute(spirv::attributeName<spirv::FunctionControl>(),
1983                      builder.getI32IntegerAttr(static_cast<uint32_t>(control)));
1984   state.attributes.append(attrs.begin(), attrs.end());
1985   state.addRegion();
1986 }
1987 
1988 // CallableOpInterface
1989 Region *spirv::FuncOp::getCallableRegion() {
1990   return isExternal() ? nullptr : &body();
1991 }
1992 
1993 // CallableOpInterface
1994 ArrayRef<Type> spirv::FuncOp::getCallableResults() {
1995   return getType().getResults();
1996 }
1997 
1998 //===----------------------------------------------------------------------===//
1999 // spv.FunctionCall
2000 //===----------------------------------------------------------------------===//
2001 
2002 static LogicalResult verify(spirv::FunctionCallOp functionCallOp) {
2003   auto fnName = functionCallOp.calleeAttr();
2004 
2005   auto funcOp =
2006       dyn_cast_or_null<spirv::FuncOp>(SymbolTable::lookupNearestSymbolFrom(
2007           functionCallOp->getParentOp(), fnName));
2008   if (!funcOp) {
2009     return functionCallOp.emitOpError("callee function '")
2010            << fnName.getValue() << "' not found in nearest symbol table";
2011   }
2012 
2013   auto functionType = funcOp.getType();
2014 
2015   if (functionCallOp.getNumResults() > 1) {
2016     return functionCallOp.emitOpError(
2017                "expected callee function to have 0 or 1 result, but provided ")
2018            << functionCallOp.getNumResults();
2019   }
2020 
2021   if (functionType.getNumInputs() != functionCallOp.getNumOperands()) {
2022     return functionCallOp.emitOpError(
2023                "has incorrect number of operands for callee: expected ")
2024            << functionType.getNumInputs() << ", but provided "
2025            << functionCallOp.getNumOperands();
2026   }
2027 
2028   for (uint32_t i = 0, e = functionType.getNumInputs(); i != e; ++i) {
2029     if (functionCallOp.getOperand(i).getType() != functionType.getInput(i)) {
2030       return functionCallOp.emitOpError(
2031                  "operand type mismatch: expected operand type ")
2032              << functionType.getInput(i) << ", but provided "
2033              << functionCallOp.getOperand(i).getType() << " for operand number "
2034              << i;
2035     }
2036   }
2037 
2038   if (functionType.getNumResults() != functionCallOp.getNumResults()) {
2039     return functionCallOp.emitOpError(
2040                "has incorrect number of results has for callee: expected ")
2041            << functionType.getNumResults() << ", but provided "
2042            << functionCallOp.getNumResults();
2043   }
2044 
2045   if (functionCallOp.getNumResults() &&
2046       (functionCallOp.getResult(0).getType() != functionType.getResult(0))) {
2047     return functionCallOp.emitOpError("result type mismatch: expected ")
2048            << functionType.getResult(0) << ", but provided "
2049            << functionCallOp.getResult(0).getType();
2050   }
2051 
2052   return success();
2053 }
2054 
2055 CallInterfaceCallable spirv::FunctionCallOp::getCallableForCallee() {
2056   return (*this)->getAttrOfType<SymbolRefAttr>(kCallee);
2057 }
2058 
2059 Operation::operand_range spirv::FunctionCallOp::getArgOperands() {
2060   return arguments();
2061 }
2062 
2063 //===----------------------------------------------------------------------===//
2064 // spv.GlobalVariable
2065 //===----------------------------------------------------------------------===//
2066 
2067 void spirv::GlobalVariableOp::build(OpBuilder &builder, OperationState &state,
2068                                     Type type, StringRef name,
2069                                     unsigned descriptorSet, unsigned binding) {
2070   build(builder, state, TypeAttr::get(type), builder.getStringAttr(name),
2071         nullptr);
2072   state.addAttribute(
2073       spirv::SPIRVDialect::getAttributeName(spirv::Decoration::DescriptorSet),
2074       builder.getI32IntegerAttr(descriptorSet));
2075   state.addAttribute(
2076       spirv::SPIRVDialect::getAttributeName(spirv::Decoration::Binding),
2077       builder.getI32IntegerAttr(binding));
2078 }
2079 
2080 void spirv::GlobalVariableOp::build(OpBuilder &builder, OperationState &state,
2081                                     Type type, StringRef name,
2082                                     spirv::BuiltIn builtin) {
2083   build(builder, state, TypeAttr::get(type), builder.getStringAttr(name),
2084         nullptr);
2085   state.addAttribute(
2086       spirv::SPIRVDialect::getAttributeName(spirv::Decoration::BuiltIn),
2087       builder.getStringAttr(spirv::stringifyBuiltIn(builtin)));
2088 }
2089 
2090 static ParseResult parseGlobalVariableOp(OpAsmParser &parser,
2091                                          OperationState &state) {
2092   // Parse variable name.
2093   StringAttr nameAttr;
2094   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2095                              state.attributes)) {
2096     return failure();
2097   }
2098 
2099   // Parse optional initializer
2100   if (succeeded(parser.parseOptionalKeyword(kInitializerAttrName))) {
2101     FlatSymbolRefAttr initSymbol;
2102     if (parser.parseLParen() ||
2103         parser.parseAttribute(initSymbol, Type(), kInitializerAttrName,
2104                               state.attributes) ||
2105         parser.parseRParen())
2106       return failure();
2107   }
2108 
2109   if (parseVariableDecorations(parser, state)) {
2110     return failure();
2111   }
2112 
2113   Type type;
2114   auto loc = parser.getCurrentLocation();
2115   if (parser.parseColonType(type)) {
2116     return failure();
2117   }
2118   if (!type.isa<spirv::PointerType>()) {
2119     return parser.emitError(loc, "expected spv.ptr type");
2120   }
2121   state.addAttribute(kTypeAttrName, TypeAttr::get(type));
2122 
2123   return success();
2124 }
2125 
2126 static void print(spirv::GlobalVariableOp varOp, OpAsmPrinter &printer) {
2127   auto *op = varOp.getOperation();
2128   SmallVector<StringRef, 4> elidedAttrs{
2129       spirv::attributeName<spirv::StorageClass>()};
2130 
2131   // Print variable name.
2132   printer << ' ';
2133   printer.printSymbolName(varOp.sym_name());
2134   elidedAttrs.push_back(SymbolTable::getSymbolAttrName());
2135 
2136   // Print optional initializer
2137   if (auto initializer = varOp.initializer()) {
2138     printer << " " << kInitializerAttrName << '(';
2139     printer.printSymbolName(initializer.getValue());
2140     printer << ')';
2141     elidedAttrs.push_back(kInitializerAttrName);
2142   }
2143 
2144   elidedAttrs.push_back(kTypeAttrName);
2145   printVariableDecorations(op, printer, elidedAttrs);
2146   printer << " : " << varOp.type();
2147 }
2148 
2149 static LogicalResult verify(spirv::GlobalVariableOp varOp) {
2150   // SPIR-V spec: "Storage Class is the Storage Class of the memory holding the
2151   // object. It cannot be Generic. It must be the same as the Storage Class
2152   // operand of the Result Type."
2153   // Also, Function storage class is reserved by spv.Variable.
2154   auto storageClass = varOp.storageClass();
2155   if (storageClass == spirv::StorageClass::Generic ||
2156       storageClass == spirv::StorageClass::Function) {
2157     return varOp.emitOpError("storage class cannot be '")
2158            << stringifyStorageClass(storageClass) << "'";
2159   }
2160 
2161   if (auto init =
2162           varOp->getAttrOfType<FlatSymbolRefAttr>(kInitializerAttrName)) {
2163     Operation *initOp = SymbolTable::lookupNearestSymbolFrom(
2164         varOp->getParentOp(), init.getAttr());
2165     // TODO: Currently only variable initialization with specialization
2166     // constants and other variables is supported. They could be normal
2167     // constants in the module scope as well.
2168     if (!initOp ||
2169         !isa<spirv::GlobalVariableOp, spirv::SpecConstantOp>(initOp)) {
2170       return varOp.emitOpError("initializer must be result of a "
2171                                "spv.SpecConstant or spv.GlobalVariable op");
2172     }
2173   }
2174 
2175   return success();
2176 }
2177 
2178 //===----------------------------------------------------------------------===//
2179 // spv.GroupBroadcast
2180 //===----------------------------------------------------------------------===//
2181 
2182 static LogicalResult verify(spirv::GroupBroadcastOp broadcastOp) {
2183   spirv::Scope scope = broadcastOp.execution_scope();
2184   if (scope != spirv::Scope::Workgroup && scope != spirv::Scope::Subgroup)
2185     return broadcastOp.emitOpError(
2186         "execution scope must be 'Workgroup' or 'Subgroup'");
2187 
2188   if (auto localIdTy = broadcastOp.localid().getType().dyn_cast<VectorType>())
2189     if (!(localIdTy.getNumElements() == 2 || localIdTy.getNumElements() == 3))
2190       return broadcastOp.emitOpError("localid is a vector and can be with only "
2191                                      " 2 or 3 components, actual number is ")
2192              << localIdTy.getNumElements();
2193 
2194   return success();
2195 }
2196 
2197 //===----------------------------------------------------------------------===//
2198 // spv.GroupNonUniformBallotOp
2199 //===----------------------------------------------------------------------===//
2200 
2201 static LogicalResult verify(spirv::GroupNonUniformBallotOp ballotOp) {
2202   spirv::Scope scope = ballotOp.execution_scope();
2203   if (scope != spirv::Scope::Workgroup && scope != spirv::Scope::Subgroup)
2204     return ballotOp.emitOpError(
2205         "execution scope must be 'Workgroup' or 'Subgroup'");
2206 
2207   return success();
2208 }
2209 
2210 //===----------------------------------------------------------------------===//
2211 // spv.GroupNonUniformBroadcast
2212 //===----------------------------------------------------------------------===//
2213 
2214 static LogicalResult verify(spirv::GroupNonUniformBroadcastOp broadcastOp) {
2215   spirv::Scope scope = broadcastOp.execution_scope();
2216   if (scope != spirv::Scope::Workgroup && scope != spirv::Scope::Subgroup)
2217     return broadcastOp.emitOpError(
2218         "execution scope must be 'Workgroup' or 'Subgroup'");
2219 
2220   // SPIR-V spec: "Before version 1.5, Id must come from a
2221   // constant instruction.
2222   auto targetEnv = spirv::getDefaultTargetEnv(broadcastOp.getContext());
2223   if (auto spirvModule = broadcastOp->getParentOfType<spirv::ModuleOp>())
2224     targetEnv = spirv::lookupTargetEnvOrDefault(spirvModule);
2225 
2226   if (targetEnv.getVersion() < spirv::Version::V_1_5) {
2227     auto *idOp = broadcastOp.id().getDefiningOp();
2228     if (!idOp || !isa<spirv::ConstantOp,           // for normal constant
2229                       spirv::ReferenceOfOp>(idOp)) // for spec constant
2230       return broadcastOp.emitOpError("id must be the result of a constant op");
2231   }
2232 
2233   return success();
2234 }
2235 
2236 //===----------------------------------------------------------------------===//
2237 // spv.SubgroupBlockReadINTEL
2238 //===----------------------------------------------------------------------===//
2239 
2240 static ParseResult parseSubgroupBlockReadINTELOp(OpAsmParser &parser,
2241                                                  OperationState &state) {
2242   // Parse the storage class specification
2243   spirv::StorageClass storageClass;
2244   OpAsmParser::OperandType ptrInfo;
2245   Type elementType;
2246   if (parseEnumStrAttr(storageClass, parser) || parser.parseOperand(ptrInfo) ||
2247       parser.parseColon() || parser.parseType(elementType)) {
2248     return failure();
2249   }
2250 
2251   auto ptrType = spirv::PointerType::get(elementType, storageClass);
2252   if (auto valVecTy = elementType.dyn_cast<VectorType>())
2253     ptrType = spirv::PointerType::get(valVecTy.getElementType(), storageClass);
2254 
2255   if (parser.resolveOperand(ptrInfo, ptrType, state.operands)) {
2256     return failure();
2257   }
2258 
2259   state.addTypes(elementType);
2260   return success();
2261 }
2262 
2263 static void print(spirv::SubgroupBlockReadINTELOp blockReadOp,
2264                   OpAsmPrinter &printer) {
2265   SmallVector<StringRef, 4> elidedAttrs;
2266   printer << " " << blockReadOp.ptr();
2267   printer << " : " << blockReadOp.getType();
2268 }
2269 
2270 static LogicalResult verify(spirv::SubgroupBlockReadINTELOp blockReadOp) {
2271   if (failed(verifyBlockReadWritePtrAndValTypes(blockReadOp, blockReadOp.ptr(),
2272                                                 blockReadOp.value())))
2273     return failure();
2274 
2275   return success();
2276 }
2277 
2278 //===----------------------------------------------------------------------===//
2279 // spv.SubgroupBlockWriteINTEL
2280 //===----------------------------------------------------------------------===//
2281 
2282 static ParseResult parseSubgroupBlockWriteINTELOp(OpAsmParser &parser,
2283                                                   OperationState &state) {
2284   // Parse the storage class specification
2285   spirv::StorageClass storageClass;
2286   SmallVector<OpAsmParser::OperandType, 2> operandInfo;
2287   auto loc = parser.getCurrentLocation();
2288   Type elementType;
2289   if (parseEnumStrAttr(storageClass, parser) ||
2290       parser.parseOperandList(operandInfo, 2) || parser.parseColon() ||
2291       parser.parseType(elementType)) {
2292     return failure();
2293   }
2294 
2295   auto ptrType = spirv::PointerType::get(elementType, storageClass);
2296   if (auto valVecTy = elementType.dyn_cast<VectorType>())
2297     ptrType = spirv::PointerType::get(valVecTy.getElementType(), storageClass);
2298 
2299   if (parser.resolveOperands(operandInfo, {ptrType, elementType}, loc,
2300                              state.operands)) {
2301     return failure();
2302   }
2303   return success();
2304 }
2305 
2306 static void print(spirv::SubgroupBlockWriteINTELOp blockWriteOp,
2307                   OpAsmPrinter &printer) {
2308   SmallVector<StringRef, 4> elidedAttrs;
2309   printer << " " << blockWriteOp.ptr() << ", " << blockWriteOp.value();
2310   printer << " : " << blockWriteOp.value().getType();
2311 }
2312 
2313 static LogicalResult verify(spirv::SubgroupBlockWriteINTELOp blockWriteOp) {
2314   if (failed(verifyBlockReadWritePtrAndValTypes(
2315           blockWriteOp, blockWriteOp.ptr(), blockWriteOp.value())))
2316     return failure();
2317 
2318   return success();
2319 }
2320 
2321 //===----------------------------------------------------------------------===//
2322 // spv.GroupNonUniformElectOp
2323 //===----------------------------------------------------------------------===//
2324 
2325 void spirv::GroupNonUniformElectOp::build(OpBuilder &builder,
2326                                           OperationState &state,
2327                                           spirv::Scope scope) {
2328   build(builder, state, builder.getI1Type(), scope);
2329 }
2330 
2331 static LogicalResult verify(spirv::GroupNonUniformElectOp groupOp) {
2332   spirv::Scope scope = groupOp.execution_scope();
2333   if (scope != spirv::Scope::Workgroup && scope != spirv::Scope::Subgroup)
2334     return groupOp.emitOpError(
2335         "execution scope must be 'Workgroup' or 'Subgroup'");
2336 
2337   return success();
2338 }
2339 
2340 //===----------------------------------------------------------------------===//
2341 // spv.LoadOp
2342 //===----------------------------------------------------------------------===//
2343 
2344 void spirv::LoadOp::build(OpBuilder &builder, OperationState &state,
2345                           Value basePtr, MemoryAccessAttr memoryAccess,
2346                           IntegerAttr alignment) {
2347   auto ptrType = basePtr.getType().cast<spirv::PointerType>();
2348   build(builder, state, ptrType.getPointeeType(), basePtr, memoryAccess,
2349         alignment);
2350 }
2351 
2352 static ParseResult parseLoadOp(OpAsmParser &parser, OperationState &state) {
2353   // Parse the storage class specification
2354   spirv::StorageClass storageClass;
2355   OpAsmParser::OperandType ptrInfo;
2356   Type elementType;
2357   if (parseEnumStrAttr(storageClass, parser) || parser.parseOperand(ptrInfo) ||
2358       parseMemoryAccessAttributes(parser, state) ||
2359       parser.parseOptionalAttrDict(state.attributes) || parser.parseColon() ||
2360       parser.parseType(elementType)) {
2361     return failure();
2362   }
2363 
2364   auto ptrType = spirv::PointerType::get(elementType, storageClass);
2365   if (parser.resolveOperand(ptrInfo, ptrType, state.operands)) {
2366     return failure();
2367   }
2368 
2369   state.addTypes(elementType);
2370   return success();
2371 }
2372 
2373 static void print(spirv::LoadOp loadOp, OpAsmPrinter &printer) {
2374   auto *op = loadOp.getOperation();
2375   SmallVector<StringRef, 4> elidedAttrs;
2376   StringRef sc = stringifyStorageClass(
2377       loadOp.ptr().getType().cast<spirv::PointerType>().getStorageClass());
2378   printer << " \"" << sc << "\" " << loadOp.ptr();
2379 
2380   printMemoryAccessAttribute(loadOp, printer, elidedAttrs);
2381 
2382   printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
2383   printer << " : " << loadOp.getType();
2384 }
2385 
2386 static LogicalResult verify(spirv::LoadOp loadOp) {
2387   // SPIR-V spec : "Result Type is the type of the loaded object. It must be a
2388   // type with fixed size; i.e., it cannot be, nor include, any
2389   // OpTypeRuntimeArray types."
2390   if (failed(verifyLoadStorePtrAndValTypes(loadOp, loadOp.ptr(),
2391                                            loadOp.value()))) {
2392     return failure();
2393   }
2394   return verifyMemoryAccessAttribute(loadOp);
2395 }
2396 
2397 //===----------------------------------------------------------------------===//
2398 // spv.mlir.loop
2399 //===----------------------------------------------------------------------===//
2400 
2401 void spirv::LoopOp::build(OpBuilder &builder, OperationState &state) {
2402   state.addAttribute("loop_control",
2403                      builder.getI32IntegerAttr(
2404                          static_cast<uint32_t>(spirv::LoopControl::None)));
2405   state.addRegion();
2406 }
2407 
2408 static ParseResult parseLoopOp(OpAsmParser &parser, OperationState &state) {
2409   if (parseControlAttribute<spirv::LoopControl>(parser, state))
2410     return failure();
2411   return parser.parseRegion(*state.addRegion(), /*arguments=*/{},
2412                             /*argTypes=*/{});
2413 }
2414 
2415 static void print(spirv::LoopOp loopOp, OpAsmPrinter &printer) {
2416   auto *op = loopOp.getOperation();
2417 
2418   auto control = loopOp.loop_control();
2419   if (control != spirv::LoopControl::None)
2420     printer << " control(" << spirv::stringifyLoopControl(control) << ")";
2421   printer.printRegion(op->getRegion(0), /*printEntryBlockArgs=*/false,
2422                       /*printBlockTerminators=*/true);
2423 }
2424 
2425 /// Returns true if the given `srcBlock` contains only one `spv.Branch` to the
2426 /// given `dstBlock`.
2427 static inline bool hasOneBranchOpTo(Block &srcBlock, Block &dstBlock) {
2428   // Check that there is only one op in the `srcBlock`.
2429   if (!llvm::hasSingleElement(srcBlock))
2430     return false;
2431 
2432   auto branchOp = dyn_cast<spirv::BranchOp>(srcBlock.back());
2433   return branchOp && branchOp.getSuccessor() == &dstBlock;
2434 }
2435 
2436 static LogicalResult verify(spirv::LoopOp loopOp) {
2437   auto *op = loopOp.getOperation();
2438 
2439   // We need to verify that the blocks follow the following layout:
2440   //
2441   //                     +-------------+
2442   //                     | entry block |
2443   //                     +-------------+
2444   //                            |
2445   //                            v
2446   //                     +-------------+
2447   //                     | loop header | <-----+
2448   //                     +-------------+       |
2449   //                                           |
2450   //                           ...             |
2451   //                          \ | /            |
2452   //                            v              |
2453   //                    +---------------+      |
2454   //                    | loop continue | -----+
2455   //                    +---------------+
2456   //
2457   //                           ...
2458   //                          \ | /
2459   //                            v
2460   //                     +-------------+
2461   //                     | merge block |
2462   //                     +-------------+
2463 
2464   auto &region = op->getRegion(0);
2465   // Allow empty region as a degenerated case, which can come from
2466   // optimizations.
2467   if (region.empty())
2468     return success();
2469 
2470   // The last block is the merge block.
2471   Block &merge = region.back();
2472   if (!isMergeBlock(merge))
2473     return loopOp.emitOpError(
2474         "last block must be the merge block with only one 'spv.mlir.merge' op");
2475 
2476   if (std::next(region.begin()) == region.end())
2477     return loopOp.emitOpError(
2478         "must have an entry block branching to the loop header block");
2479   // The first block is the entry block.
2480   Block &entry = region.front();
2481 
2482   if (std::next(region.begin(), 2) == region.end())
2483     return loopOp.emitOpError(
2484         "must have a loop header block branched from the entry block");
2485   // The second block is the loop header block.
2486   Block &header = *std::next(region.begin(), 1);
2487 
2488   if (!hasOneBranchOpTo(entry, header))
2489     return loopOp.emitOpError(
2490         "entry block must only have one 'spv.Branch' op to the second block");
2491 
2492   if (std::next(region.begin(), 3) == region.end())
2493     return loopOp.emitOpError(
2494         "requires a loop continue block branching to the loop header block");
2495   // The second to last block is the loop continue block.
2496   Block &cont = *std::prev(region.end(), 2);
2497 
2498   // Make sure that we have a branch from the loop continue block to the loop
2499   // header block.
2500   if (llvm::none_of(
2501           llvm::seq<unsigned>(0, cont.getNumSuccessors()),
2502           [&](unsigned index) { return cont.getSuccessor(index) == &header; }))
2503     return loopOp.emitOpError("second to last block must be the loop continue "
2504                               "block that branches to the loop header block");
2505 
2506   // Make sure that no other blocks (except the entry and loop continue block)
2507   // branches to the loop header block.
2508   for (auto &block : llvm::make_range(std::next(region.begin(), 2),
2509                                       std::prev(region.end(), 2))) {
2510     for (auto i : llvm::seq<unsigned>(0, block.getNumSuccessors())) {
2511       if (block.getSuccessor(i) == &header) {
2512         return loopOp.emitOpError("can only have the entry and loop continue "
2513                                   "block branching to the loop header block");
2514       }
2515     }
2516   }
2517 
2518   return success();
2519 }
2520 
2521 Block *spirv::LoopOp::getEntryBlock() {
2522   assert(!body().empty() && "op region should not be empty!");
2523   return &body().front();
2524 }
2525 
2526 Block *spirv::LoopOp::getHeaderBlock() {
2527   assert(!body().empty() && "op region should not be empty!");
2528   // The second block is the loop header block.
2529   return &*std::next(body().begin());
2530 }
2531 
2532 Block *spirv::LoopOp::getContinueBlock() {
2533   assert(!body().empty() && "op region should not be empty!");
2534   // The second to last block is the loop continue block.
2535   return &*std::prev(body().end(), 2);
2536 }
2537 
2538 Block *spirv::LoopOp::getMergeBlock() {
2539   assert(!body().empty() && "op region should not be empty!");
2540   // The last block is the loop merge block.
2541   return &body().back();
2542 }
2543 
2544 void spirv::LoopOp::addEntryAndMergeBlock() {
2545   assert(body().empty() && "entry and merge block already exist");
2546   body().push_back(new Block());
2547   auto *mergeBlock = new Block();
2548   body().push_back(mergeBlock);
2549   OpBuilder builder = OpBuilder::atBlockEnd(mergeBlock);
2550 
2551   // Add a spv.mlir.merge op into the merge block.
2552   builder.create<spirv::MergeOp>(getLoc());
2553 }
2554 
2555 //===----------------------------------------------------------------------===//
2556 // spv.mlir.merge
2557 //===----------------------------------------------------------------------===//
2558 
2559 static LogicalResult verify(spirv::MergeOp mergeOp) {
2560   auto *parentOp = mergeOp->getParentOp();
2561   if (!parentOp || !isa<spirv::SelectionOp, spirv::LoopOp>(parentOp))
2562     return mergeOp.emitOpError(
2563         "expected parent op to be 'spv.mlir.selection' or 'spv.mlir.loop'");
2564 
2565   Block &parentLastBlock = mergeOp->getParentRegion()->back();
2566   if (mergeOp.getOperation() != parentLastBlock.getTerminator())
2567     return mergeOp.emitOpError("can only be used in the last block of "
2568                                "'spv.mlir.selection' or 'spv.mlir.loop'");
2569   return success();
2570 }
2571 
2572 //===----------------------------------------------------------------------===//
2573 // spv.module
2574 //===----------------------------------------------------------------------===//
2575 
2576 void spirv::ModuleOp::build(OpBuilder &builder, OperationState &state,
2577                             Optional<StringRef> name) {
2578   OpBuilder::InsertionGuard guard(builder);
2579   builder.createBlock(state.addRegion());
2580   if (name) {
2581     state.attributes.append(mlir::SymbolTable::getSymbolAttrName(),
2582                             builder.getStringAttr(*name));
2583   }
2584 }
2585 
2586 void spirv::ModuleOp::build(OpBuilder &builder, OperationState &state,
2587                             spirv::AddressingModel addressingModel,
2588                             spirv::MemoryModel memoryModel,
2589                             Optional<VerCapExtAttr> vceTriple,
2590                             Optional<StringRef> name) {
2591   state.addAttribute(
2592       "addressing_model",
2593       builder.getI32IntegerAttr(static_cast<int32_t>(addressingModel)));
2594   state.addAttribute("memory_model", builder.getI32IntegerAttr(
2595                                          static_cast<int32_t>(memoryModel)));
2596   OpBuilder::InsertionGuard guard(builder);
2597   builder.createBlock(state.addRegion());
2598   if (vceTriple)
2599     state.addAttribute(getVCETripleAttrName(), *vceTriple);
2600   if (name)
2601     state.addAttribute(mlir::SymbolTable::getSymbolAttrName(),
2602                        builder.getStringAttr(*name));
2603 }
2604 
2605 static ParseResult parseModuleOp(OpAsmParser &parser, OperationState &state) {
2606   Region *body = state.addRegion();
2607 
2608   // If the name is present, parse it.
2609   StringAttr nameAttr;
2610   parser.parseOptionalSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2611                                  state.attributes);
2612 
2613   // Parse attributes
2614   spirv::AddressingModel addrModel;
2615   spirv::MemoryModel memoryModel;
2616   if (parseEnumKeywordAttr(addrModel, parser, state) ||
2617       parseEnumKeywordAttr(memoryModel, parser, state))
2618     return failure();
2619 
2620   if (succeeded(parser.parseOptionalKeyword("requires"))) {
2621     spirv::VerCapExtAttr vceTriple;
2622     if (parser.parseAttribute(vceTriple,
2623                               spirv::ModuleOp::getVCETripleAttrName(),
2624                               state.attributes))
2625       return failure();
2626   }
2627 
2628   if (parser.parseOptionalAttrDictWithKeyword(state.attributes))
2629     return failure();
2630 
2631   if (parser.parseRegion(*body, /*arguments=*/{}, /*argTypes=*/{}))
2632     return failure();
2633 
2634   // Make sure we have at least one block.
2635   if (body->empty())
2636     body->push_back(new Block());
2637 
2638   return success();
2639 }
2640 
2641 static void print(spirv::ModuleOp moduleOp, OpAsmPrinter &printer) {
2642   if (Optional<StringRef> name = moduleOp.getName()) {
2643     printer << ' ';
2644     printer.printSymbolName(*name);
2645   }
2646 
2647   SmallVector<StringRef, 2> elidedAttrs;
2648 
2649   printer << " " << spirv::stringifyAddressingModel(moduleOp.addressing_model())
2650           << " " << spirv::stringifyMemoryModel(moduleOp.memory_model());
2651   auto addressingModelAttrName = spirv::attributeName<spirv::AddressingModel>();
2652   auto memoryModelAttrName = spirv::attributeName<spirv::MemoryModel>();
2653   elidedAttrs.assign({addressingModelAttrName, memoryModelAttrName,
2654                       SymbolTable::getSymbolAttrName()});
2655 
2656   if (Optional<spirv::VerCapExtAttr> triple = moduleOp.vce_triple()) {
2657     printer << " requires " << *triple;
2658     elidedAttrs.push_back(spirv::ModuleOp::getVCETripleAttrName());
2659   }
2660 
2661   printer.printOptionalAttrDictWithKeyword(moduleOp->getAttrs(), elidedAttrs);
2662   printer.printRegion(moduleOp.getRegion());
2663 }
2664 
2665 static LogicalResult verify(spirv::ModuleOp moduleOp) {
2666   auto &op = *moduleOp.getOperation();
2667   auto *dialect = op.getDialect();
2668   DenseMap<std::pair<spirv::FuncOp, spirv::ExecutionModel>, spirv::EntryPointOp>
2669       entryPoints;
2670   SymbolTable table(moduleOp);
2671 
2672   for (auto &op : *moduleOp.getBody()) {
2673     if (op.getDialect() != dialect)
2674       return op.emitError("'spv.module' can only contain spv.* ops");
2675 
2676     // For EntryPoint op, check that the function and execution model is not
2677     // duplicated in EntryPointOps. Also verify that the interface specified
2678     // comes from globalVariables here to make this check cheaper.
2679     if (auto entryPointOp = dyn_cast<spirv::EntryPointOp>(op)) {
2680       auto funcOp = table.lookup<spirv::FuncOp>(entryPointOp.fn());
2681       if (!funcOp) {
2682         return entryPointOp.emitError("function '")
2683                << entryPointOp.fn() << "' not found in 'spv.module'";
2684       }
2685       if (auto interface = entryPointOp.interface()) {
2686         for (Attribute varRef : interface) {
2687           auto varSymRef = varRef.dyn_cast<FlatSymbolRefAttr>();
2688           if (!varSymRef) {
2689             return entryPointOp.emitError(
2690                        "expected symbol reference for interface "
2691                        "specification instead of '")
2692                    << varRef;
2693           }
2694           auto variableOp =
2695               table.lookup<spirv::GlobalVariableOp>(varSymRef.getValue());
2696           if (!variableOp) {
2697             return entryPointOp.emitError("expected spv.GlobalVariable "
2698                                           "symbol reference instead of'")
2699                    << varSymRef << "'";
2700           }
2701         }
2702       }
2703 
2704       auto key = std::pair<spirv::FuncOp, spirv::ExecutionModel>(
2705           funcOp, entryPointOp.execution_model());
2706       auto entryPtIt = entryPoints.find(key);
2707       if (entryPtIt != entryPoints.end()) {
2708         return entryPointOp.emitError("duplicate of a previous EntryPointOp");
2709       }
2710       entryPoints[key] = entryPointOp;
2711     } else if (auto funcOp = dyn_cast<spirv::FuncOp>(op)) {
2712       if (funcOp.isExternal())
2713         return op.emitError("'spv.module' cannot contain external functions");
2714 
2715       // TODO: move this check to spv.func.
2716       for (auto &block : funcOp)
2717         for (auto &op : block) {
2718           if (op.getDialect() != dialect)
2719             return op.emitError(
2720                 "functions in 'spv.module' can only contain spv.* ops");
2721         }
2722     }
2723   }
2724 
2725   return success();
2726 }
2727 
2728 //===----------------------------------------------------------------------===//
2729 // spv.mlir.referenceof
2730 //===----------------------------------------------------------------------===//
2731 
2732 static LogicalResult verify(spirv::ReferenceOfOp referenceOfOp) {
2733   auto *specConstSym = SymbolTable::lookupNearestSymbolFrom(
2734       referenceOfOp->getParentOp(), referenceOfOp.spec_constAttr());
2735   Type constType;
2736 
2737   auto specConstOp = dyn_cast_or_null<spirv::SpecConstantOp>(specConstSym);
2738   if (specConstOp)
2739     constType = specConstOp.default_value().getType();
2740 
2741   auto specConstCompositeOp =
2742       dyn_cast_or_null<spirv::SpecConstantCompositeOp>(specConstSym);
2743   if (specConstCompositeOp)
2744     constType = specConstCompositeOp.type();
2745 
2746   if (!specConstOp && !specConstCompositeOp)
2747     return referenceOfOp.emitOpError(
2748         "expected spv.SpecConstant or spv.SpecConstantComposite symbol");
2749 
2750   if (referenceOfOp.reference().getType() != constType)
2751     return referenceOfOp.emitOpError("result type mismatch with the referenced "
2752                                      "specialization constant's type");
2753 
2754   return success();
2755 }
2756 
2757 //===----------------------------------------------------------------------===//
2758 // spv.Return
2759 //===----------------------------------------------------------------------===//
2760 
2761 static LogicalResult verify(spirv::ReturnOp returnOp) {
2762   // Verification is performed in spv.func op.
2763   return success();
2764 }
2765 
2766 //===----------------------------------------------------------------------===//
2767 // spv.ReturnValue
2768 //===----------------------------------------------------------------------===//
2769 
2770 static LogicalResult verify(spirv::ReturnValueOp retValOp) {
2771   // Verification is performed in spv.func op.
2772   return success();
2773 }
2774 
2775 //===----------------------------------------------------------------------===//
2776 // spv.Select
2777 //===----------------------------------------------------------------------===//
2778 
2779 void spirv::SelectOp::build(OpBuilder &builder, OperationState &state,
2780                             Value cond, Value trueValue, Value falseValue) {
2781   build(builder, state, trueValue.getType(), cond, trueValue, falseValue);
2782 }
2783 
2784 static LogicalResult verify(spirv::SelectOp op) {
2785   if (auto conditionTy = op.condition().getType().dyn_cast<VectorType>()) {
2786     auto resultVectorTy = op.result().getType().dyn_cast<VectorType>();
2787     if (!resultVectorTy) {
2788       return op.emitOpError("result expected to be of vector type when "
2789                             "condition is of vector type");
2790     }
2791     if (resultVectorTy.getNumElements() != conditionTy.getNumElements()) {
2792       return op.emitOpError("result should have the same number of elements as "
2793                             "the condition when condition is of vector type");
2794     }
2795   }
2796   return success();
2797 }
2798 
2799 //===----------------------------------------------------------------------===//
2800 // spv.mlir.selection
2801 //===----------------------------------------------------------------------===//
2802 
2803 static ParseResult parseSelectionOp(OpAsmParser &parser,
2804                                     OperationState &state) {
2805   if (parseControlAttribute<spirv::SelectionControl>(parser, state))
2806     return failure();
2807   return parser.parseRegion(*state.addRegion(), /*arguments=*/{},
2808                             /*argTypes=*/{});
2809 }
2810 
2811 static void print(spirv::SelectionOp selectionOp, OpAsmPrinter &printer) {
2812   auto *op = selectionOp.getOperation();
2813   auto control = selectionOp.selection_control();
2814   if (control != spirv::SelectionControl::None)
2815     printer << " control(" << spirv::stringifySelectionControl(control) << ")";
2816   printer.printRegion(op->getRegion(0), /*printEntryBlockArgs=*/false,
2817                       /*printBlockTerminators=*/true);
2818 }
2819 
2820 static LogicalResult verify(spirv::SelectionOp selectionOp) {
2821   auto *op = selectionOp.getOperation();
2822 
2823   // We need to verify that the blocks follow the following layout:
2824   //
2825   //                     +--------------+
2826   //                     | header block |
2827   //                     +--------------+
2828   //                          / | \
2829   //                           ...
2830   //
2831   //
2832   //         +---------+   +---------+   +---------+
2833   //         | case #0 |   | case #1 |   | case #2 |  ...
2834   //         +---------+   +---------+   +---------+
2835   //
2836   //
2837   //                           ...
2838   //                          \ | /
2839   //                            v
2840   //                     +-------------+
2841   //                     | merge block |
2842   //                     +-------------+
2843 
2844   auto &region = op->getRegion(0);
2845   // Allow empty region as a degenerated case, which can come from
2846   // optimizations.
2847   if (region.empty())
2848     return success();
2849 
2850   // The last block is the merge block.
2851   if (!isMergeBlock(region.back()))
2852     return selectionOp.emitOpError(
2853         "last block must be the merge block with only one 'spv.mlir.merge' op");
2854 
2855   if (std::next(region.begin()) == region.end())
2856     return selectionOp.emitOpError("must have a selection header block");
2857 
2858   return success();
2859 }
2860 
2861 Block *spirv::SelectionOp::getHeaderBlock() {
2862   assert(!body().empty() && "op region should not be empty!");
2863   // The first block is the loop header block.
2864   return &body().front();
2865 }
2866 
2867 Block *spirv::SelectionOp::getMergeBlock() {
2868   assert(!body().empty() && "op region should not be empty!");
2869   // The last block is the loop merge block.
2870   return &body().back();
2871 }
2872 
2873 void spirv::SelectionOp::addMergeBlock() {
2874   assert(body().empty() && "entry and merge block already exist");
2875   auto *mergeBlock = new Block();
2876   body().push_back(mergeBlock);
2877   OpBuilder builder = OpBuilder::atBlockEnd(mergeBlock);
2878 
2879   // Add a spv.mlir.merge op into the merge block.
2880   builder.create<spirv::MergeOp>(getLoc());
2881 }
2882 
2883 spirv::SelectionOp spirv::SelectionOp::createIfThen(
2884     Location loc, Value condition,
2885     function_ref<void(OpBuilder &builder)> thenBody, OpBuilder &builder) {
2886   auto selectionOp =
2887       builder.create<spirv::SelectionOp>(loc, spirv::SelectionControl::None);
2888 
2889   selectionOp.addMergeBlock();
2890   Block *mergeBlock = selectionOp.getMergeBlock();
2891   Block *thenBlock = nullptr;
2892 
2893   // Build the "then" block.
2894   {
2895     OpBuilder::InsertionGuard guard(builder);
2896     thenBlock = builder.createBlock(mergeBlock);
2897     thenBody(builder);
2898     builder.create<spirv::BranchOp>(loc, mergeBlock);
2899   }
2900 
2901   // Build the header block.
2902   {
2903     OpBuilder::InsertionGuard guard(builder);
2904     builder.createBlock(thenBlock);
2905     builder.create<spirv::BranchConditionalOp>(
2906         loc, condition, thenBlock,
2907         /*trueArguments=*/ArrayRef<Value>(), mergeBlock,
2908         /*falseArguments=*/ArrayRef<Value>());
2909   }
2910 
2911   return selectionOp;
2912 }
2913 
2914 //===----------------------------------------------------------------------===//
2915 // spv.SpecConstant
2916 //===----------------------------------------------------------------------===//
2917 
2918 static ParseResult parseSpecConstantOp(OpAsmParser &parser,
2919                                        OperationState &state) {
2920   StringAttr nameAttr;
2921   Attribute valueAttr;
2922 
2923   if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
2924                              state.attributes))
2925     return failure();
2926 
2927   // Parse optional spec_id.
2928   if (succeeded(parser.parseOptionalKeyword(kSpecIdAttrName))) {
2929     IntegerAttr specIdAttr;
2930     if (parser.parseLParen() ||
2931         parser.parseAttribute(specIdAttr, kSpecIdAttrName, state.attributes) ||
2932         parser.parseRParen())
2933       return failure();
2934   }
2935 
2936   if (parser.parseEqual() ||
2937       parser.parseAttribute(valueAttr, kDefaultValueAttrName, state.attributes))
2938     return failure();
2939 
2940   return success();
2941 }
2942 
2943 static void print(spirv::SpecConstantOp constOp, OpAsmPrinter &printer) {
2944   printer << ' ';
2945   printer.printSymbolName(constOp.sym_name());
2946   if (auto specID = constOp->getAttrOfType<IntegerAttr>(kSpecIdAttrName))
2947     printer << ' ' << kSpecIdAttrName << '(' << specID.getInt() << ')';
2948   printer << " = " << constOp.default_value();
2949 }
2950 
2951 static LogicalResult verify(spirv::SpecConstantOp constOp) {
2952   if (auto specID = constOp->getAttrOfType<IntegerAttr>(kSpecIdAttrName))
2953     if (specID.getValue().isNegative())
2954       return constOp.emitOpError("SpecId cannot be negative");
2955 
2956   auto value = constOp.default_value();
2957   if (value.isa<IntegerAttr, FloatAttr>()) {
2958     // Make sure bitwidth is allowed.
2959     if (!value.getType().isa<spirv::SPIRVType>())
2960       return constOp.emitOpError("default value bitwidth disallowed");
2961     return success();
2962   }
2963   return constOp.emitOpError(
2964       "default value can only be a bool, integer, or float scalar");
2965 }
2966 
2967 //===----------------------------------------------------------------------===//
2968 // spv.StoreOp
2969 //===----------------------------------------------------------------------===//
2970 
2971 static ParseResult parseStoreOp(OpAsmParser &parser, OperationState &state) {
2972   // Parse the storage class specification
2973   spirv::StorageClass storageClass;
2974   SmallVector<OpAsmParser::OperandType, 2> operandInfo;
2975   auto loc = parser.getCurrentLocation();
2976   Type elementType;
2977   if (parseEnumStrAttr(storageClass, parser) ||
2978       parser.parseOperandList(operandInfo, 2) ||
2979       parseMemoryAccessAttributes(parser, state) || parser.parseColon() ||
2980       parser.parseType(elementType)) {
2981     return failure();
2982   }
2983 
2984   auto ptrType = spirv::PointerType::get(elementType, storageClass);
2985   if (parser.resolveOperands(operandInfo, {ptrType, elementType}, loc,
2986                              state.operands)) {
2987     return failure();
2988   }
2989   return success();
2990 }
2991 
2992 static void print(spirv::StoreOp storeOp, OpAsmPrinter &printer) {
2993   auto *op = storeOp.getOperation();
2994   SmallVector<StringRef, 4> elidedAttrs;
2995   StringRef sc = stringifyStorageClass(
2996       storeOp.ptr().getType().cast<spirv::PointerType>().getStorageClass());
2997   printer << " \"" << sc << "\" " << storeOp.ptr() << ", " << storeOp.value();
2998 
2999   printMemoryAccessAttribute(storeOp, printer, elidedAttrs);
3000 
3001   printer << " : " << storeOp.value().getType();
3002   printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
3003 }
3004 
3005 static LogicalResult verify(spirv::StoreOp storeOp) {
3006   // SPIR-V spec : "Pointer is the pointer to store through. Its type must be an
3007   // OpTypePointer whose Type operand is the same as the type of Object."
3008   if (failed(verifyLoadStorePtrAndValTypes(storeOp, storeOp.ptr(),
3009                                            storeOp.value()))) {
3010     return failure();
3011   }
3012   return verifyMemoryAccessAttribute(storeOp);
3013 }
3014 
3015 //===----------------------------------------------------------------------===//
3016 // spv.Unreachable
3017 //===----------------------------------------------------------------------===//
3018 
3019 static LogicalResult verify(spirv::UnreachableOp unreachableOp) {
3020   auto *op = unreachableOp.getOperation();
3021   auto *block = op->getBlock();
3022   // Fast track: if this is in entry block, its invalid. Otherwise, if no
3023   // predecessors, it's valid.
3024   if (block->isEntryBlock())
3025     return unreachableOp.emitOpError("cannot be used in reachable block");
3026   if (block->hasNoPredecessors())
3027     return success();
3028 
3029   // TODO: further verification needs to analyze reachability from
3030   // the entry block.
3031 
3032   return success();
3033 }
3034 
3035 //===----------------------------------------------------------------------===//
3036 // spv.Variable
3037 //===----------------------------------------------------------------------===//
3038 
3039 static ParseResult parseVariableOp(OpAsmParser &parser, OperationState &state) {
3040   // Parse optional initializer
3041   Optional<OpAsmParser::OperandType> initInfo;
3042   if (succeeded(parser.parseOptionalKeyword("init"))) {
3043     initInfo = OpAsmParser::OperandType();
3044     if (parser.parseLParen() || parser.parseOperand(*initInfo) ||
3045         parser.parseRParen())
3046       return failure();
3047   }
3048 
3049   if (parseVariableDecorations(parser, state)) {
3050     return failure();
3051   }
3052 
3053   // Parse result pointer type
3054   Type type;
3055   if (parser.parseColon())
3056     return failure();
3057   auto loc = parser.getCurrentLocation();
3058   if (parser.parseType(type))
3059     return failure();
3060 
3061   auto ptrType = type.dyn_cast<spirv::PointerType>();
3062   if (!ptrType)
3063     return parser.emitError(loc, "expected spv.ptr type");
3064   state.addTypes(ptrType);
3065 
3066   // Resolve the initializer operand
3067   if (initInfo) {
3068     if (parser.resolveOperand(*initInfo, ptrType.getPointeeType(),
3069                               state.operands))
3070       return failure();
3071   }
3072 
3073   auto attr = parser.getBuilder().getI32IntegerAttr(
3074       llvm::bit_cast<int32_t>(ptrType.getStorageClass()));
3075   state.addAttribute(spirv::attributeName<spirv::StorageClass>(), attr);
3076 
3077   return success();
3078 }
3079 
3080 static void print(spirv::VariableOp varOp, OpAsmPrinter &printer) {
3081   SmallVector<StringRef, 4> elidedAttrs{
3082       spirv::attributeName<spirv::StorageClass>()};
3083   // Print optional initializer
3084   if (varOp.getNumOperands() != 0)
3085     printer << " init(" << varOp.initializer() << ")";
3086 
3087   printVariableDecorations(varOp, printer, elidedAttrs);
3088   printer << " : " << varOp.getType();
3089 }
3090 
3091 static LogicalResult verify(spirv::VariableOp varOp) {
3092   // SPIR-V spec: "Storage Class is the Storage Class of the memory holding the
3093   // object. It cannot be Generic. It must be the same as the Storage Class
3094   // operand of the Result Type."
3095   if (varOp.storage_class() != spirv::StorageClass::Function) {
3096     return varOp.emitOpError(
3097         "can only be used to model function-level variables. Use "
3098         "spv.GlobalVariable for module-level variables.");
3099   }
3100 
3101   auto pointerType = varOp.pointer().getType().cast<spirv::PointerType>();
3102   if (varOp.storage_class() != pointerType.getStorageClass())
3103     return varOp.emitOpError(
3104         "storage class must match result pointer's storage class");
3105 
3106   if (varOp.getNumOperands() != 0) {
3107     // SPIR-V spec: "Initializer must be an <id> from a constant instruction or
3108     // a global (module scope) OpVariable instruction".
3109     auto *initOp = varOp.getOperand(0).getDefiningOp();
3110     if (!initOp || !isa<spirv::ConstantOp,    // for normal constant
3111                         spirv::ReferenceOfOp, // for spec constant
3112                         spirv::AddressOfOp>(initOp))
3113       return varOp.emitOpError("initializer must be the result of a "
3114                                "constant or spv.GlobalVariable op");
3115   }
3116 
3117   // TODO: generate these strings using ODS.
3118   auto *op = varOp.getOperation();
3119   auto descriptorSetName = llvm::convertToSnakeFromCamelCase(
3120       stringifyDecoration(spirv::Decoration::DescriptorSet));
3121   auto bindingName = llvm::convertToSnakeFromCamelCase(
3122       stringifyDecoration(spirv::Decoration::Binding));
3123   auto builtInName = llvm::convertToSnakeFromCamelCase(
3124       stringifyDecoration(spirv::Decoration::BuiltIn));
3125 
3126   for (const auto &attr : {descriptorSetName, bindingName, builtInName}) {
3127     if (op->getAttr(attr))
3128       return varOp.emitOpError("cannot have '")
3129              << attr << "' attribute (only allowed in spv.GlobalVariable)";
3130   }
3131 
3132   return success();
3133 }
3134 
3135 //===----------------------------------------------------------------------===//
3136 // spv.VectorShuffle
3137 //===----------------------------------------------------------------------===//
3138 
3139 static LogicalResult verify(spirv::VectorShuffleOp shuffleOp) {
3140   VectorType resultType = shuffleOp.getType().cast<VectorType>();
3141 
3142   size_t numResultElements = resultType.getNumElements();
3143   if (numResultElements != shuffleOp.components().size())
3144     return shuffleOp.emitOpError("result type element count (")
3145            << numResultElements
3146            << ") mismatch with the number of component selectors ("
3147            << shuffleOp.components().size() << ")";
3148 
3149   size_t totalSrcElements =
3150       shuffleOp.vector1().getType().cast<VectorType>().getNumElements() +
3151       shuffleOp.vector2().getType().cast<VectorType>().getNumElements();
3152 
3153   for (const auto &selector :
3154        shuffleOp.components().getAsValueRange<IntegerAttr>()) {
3155     uint32_t index = selector.getZExtValue();
3156     if (index >= totalSrcElements &&
3157         index != std::numeric_limits<uint32_t>().max())
3158       return shuffleOp.emitOpError("component selector ")
3159              << index << " out of range: expected to be in [0, "
3160              << totalSrcElements << ") or 0xffffffff";
3161   }
3162   return success();
3163 }
3164 
3165 //===----------------------------------------------------------------------===//
3166 // spv.CooperativeMatrixLoadNV
3167 //===----------------------------------------------------------------------===//
3168 
3169 static ParseResult parseCooperativeMatrixLoadNVOp(OpAsmParser &parser,
3170                                                   OperationState &state) {
3171   SmallVector<OpAsmParser::OperandType, 3> operandInfo;
3172   Type strideType = parser.getBuilder().getIntegerType(32);
3173   Type columnMajorType = parser.getBuilder().getIntegerType(1);
3174   Type ptrType;
3175   Type elementType;
3176   if (parser.parseOperandList(operandInfo, 3) ||
3177       parseMemoryAccessAttributes(parser, state) || parser.parseColon() ||
3178       parser.parseType(ptrType) || parser.parseKeywordType("as", elementType)) {
3179     return failure();
3180   }
3181   if (parser.resolveOperands(operandInfo,
3182                              {ptrType, strideType, columnMajorType},
3183                              parser.getNameLoc(), state.operands)) {
3184     return failure();
3185   }
3186 
3187   state.addTypes(elementType);
3188   return success();
3189 }
3190 
3191 static void print(spirv::CooperativeMatrixLoadNVOp M, OpAsmPrinter &printer) {
3192   printer << " " << M.pointer() << ", " << M.stride() << ", "
3193           << M.columnmajor();
3194   // Print optional memory access attribute.
3195   if (auto memAccess = M.memory_access())
3196     printer << " [\"" << stringifyMemoryAccess(*memAccess) << "\"]";
3197   printer << " : " << M.pointer().getType() << " as " << M.getType();
3198 }
3199 
3200 static LogicalResult verifyPointerAndCoopMatrixType(Operation *op, Type pointer,
3201                                                     Type coopMatrix) {
3202   Type pointeeType = pointer.cast<spirv::PointerType>().getPointeeType();
3203   if (!pointeeType.isa<spirv::ScalarType>() && !pointeeType.isa<VectorType>())
3204     return op->emitError(
3205                "Pointer must point to a scalar or vector type but provided ")
3206            << pointeeType;
3207   spirv::StorageClass storage =
3208       pointer.cast<spirv::PointerType>().getStorageClass();
3209   if (storage != spirv::StorageClass::Workgroup &&
3210       storage != spirv::StorageClass::StorageBuffer &&
3211       storage != spirv::StorageClass::PhysicalStorageBuffer)
3212     return op->emitError(
3213                "Pointer storage class must be Workgroup, StorageBuffer or "
3214                "PhysicalStorageBufferEXT but provided ")
3215            << stringifyStorageClass(storage);
3216   return success();
3217 }
3218 
3219 //===----------------------------------------------------------------------===//
3220 // spv.CooperativeMatrixStoreNV
3221 //===----------------------------------------------------------------------===//
3222 
3223 static ParseResult parseCooperativeMatrixStoreNVOp(OpAsmParser &parser,
3224                                                    OperationState &state) {
3225   SmallVector<OpAsmParser::OperandType, 4> operandInfo;
3226   Type strideType = parser.getBuilder().getIntegerType(32);
3227   Type columnMajorType = parser.getBuilder().getIntegerType(1);
3228   Type ptrType;
3229   Type elementType;
3230   if (parser.parseOperandList(operandInfo, 4) ||
3231       parseMemoryAccessAttributes(parser, state) || parser.parseColon() ||
3232       parser.parseType(ptrType) || parser.parseComma() ||
3233       parser.parseType(elementType)) {
3234     return failure();
3235   }
3236   if (parser.resolveOperands(
3237           operandInfo, {ptrType, elementType, strideType, columnMajorType},
3238           parser.getNameLoc(), state.operands)) {
3239     return failure();
3240   }
3241 
3242   return success();
3243 }
3244 
3245 static void print(spirv::CooperativeMatrixStoreNVOp coopMatrix,
3246                   OpAsmPrinter &printer) {
3247   printer << " " << coopMatrix.pointer() << ", " << coopMatrix.object() << ", "
3248           << coopMatrix.stride() << ", " << coopMatrix.columnmajor();
3249   // Print optional memory access attribute.
3250   if (auto memAccess = coopMatrix.memory_access())
3251     printer << " [\"" << stringifyMemoryAccess(*memAccess) << "\"]";
3252   printer << " : " << coopMatrix.pointer().getType() << ", "
3253           << coopMatrix.getOperand(1).getType();
3254 }
3255 
3256 //===----------------------------------------------------------------------===//
3257 // spv.CooperativeMatrixMulAddNV
3258 //===----------------------------------------------------------------------===//
3259 
3260 static LogicalResult
3261 verifyCoopMatrixMulAdd(spirv::CooperativeMatrixMulAddNVOp op) {
3262   if (op.c().getType() != op.result().getType())
3263     return op.emitOpError("result and third operand must have the same type");
3264   auto typeA = op.a().getType().cast<spirv::CooperativeMatrixNVType>();
3265   auto typeB = op.b().getType().cast<spirv::CooperativeMatrixNVType>();
3266   auto typeC = op.c().getType().cast<spirv::CooperativeMatrixNVType>();
3267   auto typeR = op.result().getType().cast<spirv::CooperativeMatrixNVType>();
3268   if (typeA.getRows() != typeR.getRows() ||
3269       typeA.getColumns() != typeB.getRows() ||
3270       typeB.getColumns() != typeR.getColumns())
3271     return op.emitOpError("matrix size must match");
3272   if (typeR.getScope() != typeA.getScope() ||
3273       typeR.getScope() != typeB.getScope() ||
3274       typeR.getScope() != typeC.getScope())
3275     return op.emitOpError("matrix scope must match");
3276   if (typeA.getElementType() != typeB.getElementType() ||
3277       typeR.getElementType() != typeC.getElementType())
3278     return op.emitOpError("matrix element type must match");
3279   return success();
3280 }
3281 
3282 //===----------------------------------------------------------------------===//
3283 // spv.MatrixTimesScalar
3284 //===----------------------------------------------------------------------===//
3285 
3286 static LogicalResult verifyMatrixTimesScalar(spirv::MatrixTimesScalarOp op) {
3287   // We already checked that result and matrix are both of matrix type in the
3288   // auto-generated verify method.
3289 
3290   auto inputMatrix = op.matrix().getType().cast<spirv::MatrixType>();
3291   auto resultMatrix = op.result().getType().cast<spirv::MatrixType>();
3292 
3293   // Check that the scalar type is the same as the matrix element type.
3294   if (op.scalar().getType() != inputMatrix.getElementType())
3295     return op.emitError("input matrix components' type and scaling value must "
3296                         "have the same type");
3297 
3298   // Note that the next three checks could be done using the AllTypesMatch
3299   // trait in the Op definition file but it generates a vague error message.
3300 
3301   // Check that the input and result matrices have the same columns' count
3302   if (inputMatrix.getNumColumns() != resultMatrix.getNumColumns())
3303     return op.emitError("input and result matrices must have the same "
3304                         "number of columns");
3305 
3306   // Check that the input and result matrices' have the same rows count
3307   if (inputMatrix.getNumRows() != resultMatrix.getNumRows())
3308     return op.emitError("input and result matrices' columns must have "
3309                         "the same size");
3310 
3311   // Check that the input and result matrices' have the same component type
3312   if (inputMatrix.getElementType() != resultMatrix.getElementType())
3313     return op.emitError("input and result matrices' columns must have "
3314                         "the same component type");
3315 
3316   return success();
3317 }
3318 
3319 //===----------------------------------------------------------------------===//
3320 // spv.CopyMemory
3321 //===----------------------------------------------------------------------===//
3322 
3323 static void print(spirv::CopyMemoryOp copyMemory, OpAsmPrinter &printer) {
3324   auto *op = copyMemory.getOperation();
3325   printer << ' ';
3326 
3327   StringRef targetStorageClass =
3328       stringifyStorageClass(copyMemory.target()
3329                                 .getType()
3330                                 .cast<spirv::PointerType>()
3331                                 .getStorageClass());
3332   printer << " \"" << targetStorageClass << "\" " << copyMemory.target()
3333           << ", ";
3334 
3335   StringRef sourceStorageClass =
3336       stringifyStorageClass(copyMemory.source()
3337                                 .getType()
3338                                 .cast<spirv::PointerType>()
3339                                 .getStorageClass());
3340   printer << " \"" << sourceStorageClass << "\" " << copyMemory.source();
3341 
3342   SmallVector<StringRef, 4> elidedAttrs;
3343   printMemoryAccessAttribute(copyMemory, printer, elidedAttrs);
3344   printSourceMemoryAccessAttribute(copyMemory, printer, elidedAttrs,
3345                                    copyMemory.source_memory_access(),
3346                                    copyMemory.source_alignment());
3347 
3348   printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
3349 
3350   Type pointeeType =
3351       copyMemory.target().getType().cast<spirv::PointerType>().getPointeeType();
3352   printer << " : " << pointeeType;
3353 }
3354 
3355 static ParseResult parseCopyMemoryOp(OpAsmParser &parser,
3356                                      OperationState &state) {
3357   spirv::StorageClass targetStorageClass;
3358   OpAsmParser::OperandType targetPtrInfo;
3359 
3360   spirv::StorageClass sourceStorageClass;
3361   OpAsmParser::OperandType sourcePtrInfo;
3362 
3363   Type elementType;
3364 
3365   if (parseEnumStrAttr(targetStorageClass, parser) ||
3366       parser.parseOperand(targetPtrInfo) || parser.parseComma() ||
3367       parseEnumStrAttr(sourceStorageClass, parser) ||
3368       parser.parseOperand(sourcePtrInfo) ||
3369       parseMemoryAccessAttributes(parser, state)) {
3370     return failure();
3371   }
3372 
3373   if (!parser.parseOptionalComma()) {
3374     // Parse 2nd memory access attributes.
3375     if (parseSourceMemoryAccessAttributes(parser, state)) {
3376       return failure();
3377     }
3378   }
3379 
3380   if (parser.parseColon() || parser.parseType(elementType))
3381     return failure();
3382 
3383   if (parser.parseOptionalAttrDict(state.attributes))
3384     return failure();
3385 
3386   auto targetPtrType = spirv::PointerType::get(elementType, targetStorageClass);
3387   auto sourcePtrType = spirv::PointerType::get(elementType, sourceStorageClass);
3388 
3389   if (parser.resolveOperand(targetPtrInfo, targetPtrType, state.operands) ||
3390       parser.resolveOperand(sourcePtrInfo, sourcePtrType, state.operands)) {
3391     return failure();
3392   }
3393 
3394   return success();
3395 }
3396 
3397 static LogicalResult verifyCopyMemory(spirv::CopyMemoryOp copyMemory) {
3398   Type targetType =
3399       copyMemory.target().getType().cast<spirv::PointerType>().getPointeeType();
3400 
3401   Type sourceType =
3402       copyMemory.source().getType().cast<spirv::PointerType>().getPointeeType();
3403 
3404   if (targetType != sourceType) {
3405     return copyMemory.emitOpError(
3406         "both operands must be pointers to the same type");
3407   }
3408 
3409   if (failed(verifyMemoryAccessAttribute(copyMemory))) {
3410     return failure();
3411   }
3412 
3413   // TODO - According to the spec:
3414   //
3415   // If two masks are present, the first applies to Target and cannot include
3416   // MakePointerVisible, and the second applies to Source and cannot include
3417   // MakePointerAvailable.
3418   //
3419   // Add such verification here.
3420 
3421   return verifySourceMemoryAccessAttribute(copyMemory);
3422 }
3423 
3424 //===----------------------------------------------------------------------===//
3425 // spv.Transpose
3426 //===----------------------------------------------------------------------===//
3427 
3428 static LogicalResult verifyTranspose(spirv::TransposeOp op) {
3429   auto inputMatrix = op.matrix().getType().cast<spirv::MatrixType>();
3430   auto resultMatrix = op.result().getType().cast<spirv::MatrixType>();
3431 
3432   // Verify that the input and output matrices have correct shapes.
3433   if (inputMatrix.getNumRows() != resultMatrix.getNumColumns())
3434     return op.emitError("input matrix rows count must be equal to "
3435                         "output matrix columns count");
3436 
3437   if (inputMatrix.getNumColumns() != resultMatrix.getNumRows())
3438     return op.emitError("input matrix columns count must be equal to "
3439                         "output matrix rows count");
3440 
3441   // Verify that the input and output matrices have the same component type
3442   if (inputMatrix.getElementType() != resultMatrix.getElementType())
3443     return op.emitError("input and output matrices must have the same "
3444                         "component type");
3445 
3446   return success();
3447 }
3448 
3449 //===----------------------------------------------------------------------===//
3450 // spv.MatrixTimesMatrix
3451 //===----------------------------------------------------------------------===//
3452 
3453 static LogicalResult verifyMatrixTimesMatrix(spirv::MatrixTimesMatrixOp op) {
3454   auto leftMatrix = op.leftmatrix().getType().cast<spirv::MatrixType>();
3455   auto rightMatrix = op.rightmatrix().getType().cast<spirv::MatrixType>();
3456   auto resultMatrix = op.result().getType().cast<spirv::MatrixType>();
3457 
3458   // left matrix columns' count and right matrix rows' count must be equal
3459   if (leftMatrix.getNumColumns() != rightMatrix.getNumRows())
3460     return op.emitError("left matrix columns' count must be equal to "
3461                         "the right matrix rows' count");
3462 
3463   // right and result matrices columns' count must be the same
3464   if (rightMatrix.getNumColumns() != resultMatrix.getNumColumns())
3465     return op.emitError(
3466         "right and result matrices must have equal columns' count");
3467 
3468   // right and result matrices component type must be the same
3469   if (rightMatrix.getElementType() != resultMatrix.getElementType())
3470     return op.emitError("right and result matrices' component type must"
3471                         " be the same");
3472 
3473   // left and result matrices component type must be the same
3474   if (leftMatrix.getElementType() != resultMatrix.getElementType())
3475     return op.emitError("left and result matrices' component type"
3476                         " must be the same");
3477 
3478   // left and result matrices rows count must be the same
3479   if (leftMatrix.getNumRows() != resultMatrix.getNumRows())
3480     return op.emitError("left and result matrices must have equal rows'"
3481                         " count");
3482 
3483   return success();
3484 }
3485 
3486 //===----------------------------------------------------------------------===//
3487 // spv.SpecConstantComposite
3488 //===----------------------------------------------------------------------===//
3489 
3490 static ParseResult parseSpecConstantCompositeOp(OpAsmParser &parser,
3491                                                 OperationState &state) {
3492 
3493   StringAttr compositeName;
3494   if (parser.parseSymbolName(compositeName, SymbolTable::getSymbolAttrName(),
3495                              state.attributes))
3496     return failure();
3497 
3498   if (parser.parseLParen())
3499     return failure();
3500 
3501   SmallVector<Attribute, 4> constituents;
3502 
3503   do {
3504     // The name of the constituent attribute isn't important
3505     const char *attrName = "spec_const";
3506     FlatSymbolRefAttr specConstRef;
3507     NamedAttrList attrs;
3508 
3509     if (parser.parseAttribute(specConstRef, Type(), attrName, attrs))
3510       return failure();
3511 
3512     constituents.push_back(specConstRef);
3513   } while (!parser.parseOptionalComma());
3514 
3515   if (parser.parseRParen())
3516     return failure();
3517 
3518   state.addAttribute(kCompositeSpecConstituentsName,
3519                      parser.getBuilder().getArrayAttr(constituents));
3520 
3521   Type type;
3522   if (parser.parseColonType(type))
3523     return failure();
3524 
3525   state.addAttribute(kTypeAttrName, TypeAttr::get(type));
3526 
3527   return success();
3528 }
3529 
3530 static void print(spirv::SpecConstantCompositeOp op, OpAsmPrinter &printer) {
3531   printer << " ";
3532   printer.printSymbolName(op.sym_name());
3533   printer << " (";
3534   auto constituents = op.constituents().getValue();
3535 
3536   if (!constituents.empty())
3537     llvm::interleaveComma(constituents, printer);
3538 
3539   printer << ") : " << op.type();
3540 }
3541 
3542 static LogicalResult verify(spirv::SpecConstantCompositeOp constOp) {
3543   auto cType = constOp.type().dyn_cast<spirv::CompositeType>();
3544   auto constituents = constOp.constituents().getValue();
3545 
3546   if (!cType)
3547     return constOp.emitError(
3548                "result type must be a composite type, but provided ")
3549            << constOp.type();
3550 
3551   if (cType.isa<spirv::CooperativeMatrixNVType>())
3552     return constOp.emitError("unsupported composite type  ") << cType;
3553   if (constituents.size() != cType.getNumElements())
3554     return constOp.emitError("has incorrect number of operands: expected ")
3555            << cType.getNumElements() << ", but provided "
3556            << constituents.size();
3557 
3558   for (auto index : llvm::seq<uint32_t>(0, constituents.size())) {
3559     auto constituent = constituents[index].cast<FlatSymbolRefAttr>();
3560 
3561     auto constituentSpecConstOp =
3562         dyn_cast<spirv::SpecConstantOp>(SymbolTable::lookupNearestSymbolFrom(
3563             constOp->getParentOp(), constituent.getAttr()));
3564 
3565     if (constituentSpecConstOp.default_value().getType() !=
3566         cType.getElementType(index))
3567       return constOp.emitError("has incorrect types of operands: expected ")
3568              << cType.getElementType(index) << ", but provided "
3569              << constituentSpecConstOp.default_value().getType();
3570   }
3571 
3572   return success();
3573 }
3574 
3575 //===----------------------------------------------------------------------===//
3576 // spv.SpecConstantOperation
3577 //===----------------------------------------------------------------------===//
3578 
3579 static ParseResult parseSpecConstantOperationOp(OpAsmParser &parser,
3580                                                 OperationState &state) {
3581   Region *body = state.addRegion();
3582 
3583   if (parser.parseKeyword("wraps"))
3584     return failure();
3585 
3586   body->push_back(new Block);
3587   Block &block = body->back();
3588   Operation *wrappedOp = parser.parseGenericOperation(&block, block.begin());
3589 
3590   if (!wrappedOp)
3591     return failure();
3592 
3593   OpBuilder builder(parser.getBuilder().getContext());
3594   builder.setInsertionPointToEnd(&block);
3595   builder.create<spirv::YieldOp>(wrappedOp->getLoc(), wrappedOp->getResult(0));
3596   state.location = wrappedOp->getLoc();
3597 
3598   state.addTypes(wrappedOp->getResult(0).getType());
3599 
3600   if (parser.parseOptionalAttrDict(state.attributes))
3601     return failure();
3602 
3603   return success();
3604 }
3605 
3606 static void print(spirv::SpecConstantOperationOp op, OpAsmPrinter &printer) {
3607   printer << " wraps ";
3608   printer.printGenericOp(&op.body().front().front());
3609 }
3610 
3611 static LogicalResult verify(spirv::SpecConstantOperationOp constOp) {
3612   Block &block = constOp.getRegion().getBlocks().front();
3613 
3614   if (block.getOperations().size() != 2)
3615     return constOp.emitOpError("expected exactly 2 nested ops");
3616 
3617   Operation &enclosedOp = block.getOperations().front();
3618 
3619   if (!enclosedOp.hasTrait<OpTrait::spirv::UsableInSpecConstantOp>())
3620     return constOp.emitOpError("invalid enclosed op");
3621 
3622   for (auto operand : enclosedOp.getOperands())
3623     if (!isa<spirv::ConstantOp, spirv::ReferenceOfOp,
3624              spirv::SpecConstantOperationOp>(operand.getDefiningOp()))
3625       return constOp.emitOpError(
3626           "invalid operand, must be defined by a constant operation");
3627 
3628   return success();
3629 }
3630 
3631 //===----------------------------------------------------------------------===//
3632 // spv.GLSL.FrexpStruct
3633 //===----------------------------------------------------------------------===//
3634 static LogicalResult
3635 verifyGLSLFrexpStructOp(spirv::GLSLFrexpStructOp frexpStructOp) {
3636   spirv::StructType structTy =
3637       frexpStructOp.result().getType().dyn_cast<spirv::StructType>();
3638 
3639   if (structTy.getNumElements() != 2)
3640     return frexpStructOp.emitError("result type must be a struct  type "
3641                                    "with two memebers");
3642 
3643   Type significandTy = structTy.getElementType(0);
3644   Type exponentTy = structTy.getElementType(1);
3645   VectorType exponentVecTy = exponentTy.dyn_cast<VectorType>();
3646   IntegerType exponentIntTy = exponentTy.dyn_cast<IntegerType>();
3647 
3648   Type operandTy = frexpStructOp.operand().getType();
3649   VectorType operandVecTy = operandTy.dyn_cast<VectorType>();
3650   FloatType operandFTy = operandTy.dyn_cast<FloatType>();
3651 
3652   if (significandTy != operandTy)
3653     return frexpStructOp.emitError("member zero of the resulting struct type "
3654                                    "must be the same type as the operand");
3655 
3656   if (exponentVecTy) {
3657     IntegerType componentIntTy =
3658         exponentVecTy.getElementType().dyn_cast<IntegerType>();
3659     if (!(componentIntTy && componentIntTy.getWidth() == 32))
3660       return frexpStructOp.emitError(
3661           "member one of the resulting struct type must"
3662           "be a scalar or vector of 32 bit integer type");
3663   } else if (!(exponentIntTy && exponentIntTy.getWidth() == 32)) {
3664     return frexpStructOp.emitError(
3665         "member one of the resulting struct type "
3666         "must be a scalar or vector of 32 bit integer type");
3667   }
3668 
3669   // Check that the two member types have the same number of components
3670   if (operandVecTy && exponentVecTy &&
3671       (exponentVecTy.getNumElements() == operandVecTy.getNumElements()))
3672     return success();
3673 
3674   if (operandFTy && exponentIntTy)
3675     return success();
3676 
3677   return frexpStructOp.emitError(
3678       "member one of the resulting struct type "
3679       "must have the same number of components as the operand type");
3680 }
3681 
3682 //===----------------------------------------------------------------------===//
3683 // spv.GLSL.Ldexp
3684 //===----------------------------------------------------------------------===//
3685 
3686 static LogicalResult verify(spirv::GLSLLdexpOp ldexpOp) {
3687   Type significandType = ldexpOp.x().getType();
3688   Type exponentType = ldexpOp.exp().getType();
3689 
3690   if (significandType.isa<FloatType>() != exponentType.isa<IntegerType>())
3691     return ldexpOp.emitOpError("operands must both be scalars or vectors");
3692 
3693   auto getNumElements = [](Type type) -> unsigned {
3694     if (auto vectorType = type.dyn_cast<VectorType>())
3695       return vectorType.getNumElements();
3696     return 1;
3697   };
3698 
3699   if (getNumElements(significandType) != getNumElements(exponentType))
3700     return ldexpOp.emitOpError(
3701         "operands must have the same number of elements");
3702 
3703   return success();
3704 }
3705 
3706 //===----------------------------------------------------------------------===//
3707 // spv.ImageDrefGather
3708 //===----------------------------------------------------------------------===//
3709 
3710 static LogicalResult verify(spirv::ImageDrefGatherOp imageDrefGatherOp) {
3711   VectorType resultType =
3712       imageDrefGatherOp.result().getType().cast<VectorType>();
3713   auto sampledImageType = imageDrefGatherOp.sampledimage()
3714                               .getType()
3715                               .cast<spirv::SampledImageType>();
3716   auto imageType = sampledImageType.getImageType().cast<spirv::ImageType>();
3717 
3718   if (resultType.getNumElements() != 4)
3719     return imageDrefGatherOp.emitOpError(
3720         "result type must be a vector of four components");
3721 
3722   Type elementType = resultType.getElementType();
3723   Type sampledElementType = imageType.getElementType();
3724   if (!sampledElementType.isa<NoneType>() && elementType != sampledElementType)
3725     return imageDrefGatherOp.emitOpError(
3726         "the component type of result must be the same as sampled type of the "
3727         "underlying image type");
3728 
3729   spirv::Dim imageDim = imageType.getDim();
3730   spirv::ImageSamplingInfo imageMS = imageType.getSamplingInfo();
3731 
3732   if (imageDim != spirv::Dim::Dim2D && imageDim != spirv::Dim::Cube &&
3733       imageDim != spirv::Dim::Rect)
3734     return imageDrefGatherOp.emitOpError(
3735         "the Dim operand of the underlying image type must be 2D, Cube, or "
3736         "Rect");
3737 
3738   if (imageMS != spirv::ImageSamplingInfo::SingleSampled)
3739     return imageDrefGatherOp.emitOpError(
3740         "the MS operand of the underlying image type must be 0");
3741 
3742   spirv::ImageOperandsAttr attr = imageDrefGatherOp.imageoperandsAttr();
3743   auto operandArguments = imageDrefGatherOp.operand_arguments();
3744 
3745   return verifyImageOperands(imageDrefGatherOp, attr, operandArguments);
3746 }
3747 
3748 //===----------------------------------------------------------------------===//
3749 // spv.ImageQuerySize
3750 //===----------------------------------------------------------------------===//
3751 
3752 static LogicalResult verify(spirv::ImageQuerySizeOp imageQuerySizeOp) {
3753   spirv::ImageType imageType =
3754       imageQuerySizeOp.image().getType().cast<spirv::ImageType>();
3755   Type resultType = imageQuerySizeOp.result().getType();
3756 
3757   spirv::Dim dim = imageType.getDim();
3758   spirv::ImageSamplingInfo samplingInfo = imageType.getSamplingInfo();
3759   spirv::ImageSamplerUseInfo samplerInfo = imageType.getSamplerUseInfo();
3760   switch (dim) {
3761   case spirv::Dim::Dim1D:
3762   case spirv::Dim::Dim2D:
3763   case spirv::Dim::Dim3D:
3764   case spirv::Dim::Cube:
3765     if (!(samplingInfo == spirv::ImageSamplingInfo::MultiSampled ||
3766           samplerInfo == spirv::ImageSamplerUseInfo::SamplerUnknown ||
3767           samplerInfo == spirv::ImageSamplerUseInfo::NoSampler))
3768       return imageQuerySizeOp.emitError(
3769           "if Dim is 1D, 2D, 3D, or Cube, "
3770           "it must also have either an MS of 1 or a Sampled of 0 or 2");
3771     break;
3772   case spirv::Dim::Buffer:
3773   case spirv::Dim::Rect:
3774     break;
3775   default:
3776     return imageQuerySizeOp.emitError("the Dim operand of the image type must "
3777                                       "be 1D, 2D, 3D, Buffer, Cube, or Rect");
3778   }
3779 
3780   unsigned componentNumber = 0;
3781   switch (dim) {
3782   case spirv::Dim::Dim1D:
3783   case spirv::Dim::Buffer:
3784     componentNumber = 1;
3785     break;
3786   case spirv::Dim::Dim2D:
3787   case spirv::Dim::Cube:
3788   case spirv::Dim::Rect:
3789     componentNumber = 2;
3790     break;
3791   case spirv::Dim::Dim3D:
3792     componentNumber = 3;
3793     break;
3794   default:
3795     break;
3796   }
3797 
3798   if (imageType.getArrayedInfo() == spirv::ImageArrayedInfo::Arrayed)
3799     componentNumber += 1;
3800 
3801   unsigned resultComponentNumber = 1;
3802   if (auto resultVectorType = resultType.dyn_cast<VectorType>())
3803     resultComponentNumber = resultVectorType.getNumElements();
3804 
3805   if (componentNumber != resultComponentNumber)
3806     return imageQuerySizeOp.emitError("expected the result to have ")
3807            << componentNumber << " component(s), but found "
3808            << resultComponentNumber << " component(s)";
3809 
3810   return success();
3811 }
3812 
3813 static ParseResult parsePtrAccessChainOpImpl(StringRef opName,
3814                                              OpAsmParser &parser,
3815                                              OperationState &state) {
3816   OpAsmParser::OperandType ptrInfo;
3817   SmallVector<OpAsmParser::OperandType, 4> indicesInfo;
3818   Type type;
3819   auto loc = parser.getCurrentLocation();
3820   SmallVector<Type, 4> indicesTypes;
3821 
3822   if (parser.parseOperand(ptrInfo) ||
3823       parser.parseOperandList(indicesInfo, OpAsmParser::Delimiter::Square) ||
3824       parser.parseColonType(type) ||
3825       parser.resolveOperand(ptrInfo, type, state.operands))
3826     return failure();
3827 
3828   // Check that the provided indices list is not empty before parsing their
3829   // type list.
3830   if (indicesInfo.empty())
3831     return emitError(state.location) << opName << " expected element";
3832 
3833   if (parser.parseComma() || parser.parseTypeList(indicesTypes))
3834     return failure();
3835 
3836   // Check that the indices types list is not empty and that it has a one-to-one
3837   // mapping to the provided indices.
3838   if (indicesTypes.size() != indicesInfo.size())
3839     return emitError(state.location)
3840            << opName
3841            << " indices types' count must be equal to indices info count";
3842 
3843   if (parser.resolveOperands(indicesInfo, indicesTypes, loc, state.operands))
3844     return failure();
3845 
3846   auto resultType = getElementPtrType(
3847       type, llvm::makeArrayRef(state.operands).drop_front(2), state.location);
3848   if (!resultType)
3849     return failure();
3850 
3851   state.addTypes(resultType);
3852   return success();
3853 }
3854 
3855 template <typename Op>
3856 static auto concatElemAndIndices(Op op) {
3857   SmallVector<Value> ret(op.indices().size() + 1);
3858   ret[0] = op.element();
3859   llvm::copy(op.indices(), ret.begin() + 1);
3860   return ret;
3861 }
3862 
3863 //===----------------------------------------------------------------------===//
3864 // spv.InBoundsPtrAccessChainOp
3865 //===----------------------------------------------------------------------===//
3866 
3867 void spirv::InBoundsPtrAccessChainOp::build(OpBuilder &builder,
3868                                             OperationState &state,
3869                                             Value basePtr, Value element,
3870                                             ValueRange indices) {
3871   auto type = getElementPtrType(basePtr.getType(), indices, state.location);
3872   assert(type && "Unable to deduce return type based on basePtr and indices");
3873   build(builder, state, type, basePtr, element, indices);
3874 }
3875 
3876 static ParseResult parseInBoundsPtrAccessChainOp(OpAsmParser &parser,
3877                                                  OperationState &state) {
3878   return parsePtrAccessChainOpImpl(
3879       spirv::InBoundsPtrAccessChainOp::getOperationName(), parser, state);
3880 }
3881 
3882 static void print(spirv::InBoundsPtrAccessChainOp op, OpAsmPrinter &printer) {
3883   printAccessChain(op, concatElemAndIndices(op), printer);
3884 }
3885 
3886 static LogicalResult verify(spirv::InBoundsPtrAccessChainOp accessChainOp) {
3887   return verifyAccessChain(accessChainOp, accessChainOp.indices());
3888 }
3889 
3890 //===----------------------------------------------------------------------===//
3891 // spv.PtrAccessChainOp
3892 //===----------------------------------------------------------------------===//
3893 
3894 void spirv::PtrAccessChainOp::build(OpBuilder &builder, OperationState &state,
3895                                     Value basePtr, Value element,
3896                                     ValueRange indices) {
3897   auto type = getElementPtrType(basePtr.getType(), indices, state.location);
3898   assert(type && "Unable to deduce return type based on basePtr and indices");
3899   build(builder, state, type, basePtr, element, indices);
3900 }
3901 
3902 static ParseResult parsePtrAccessChainOp(OpAsmParser &parser,
3903                                          OperationState &state) {
3904   return parsePtrAccessChainOpImpl(spirv::PtrAccessChainOp::getOperationName(),
3905                                    parser, state);
3906 }
3907 
3908 static void print(spirv::PtrAccessChainOp op, OpAsmPrinter &printer) {
3909   printAccessChain(op, concatElemAndIndices(op), printer);
3910 }
3911 
3912 static LogicalResult verify(spirv::PtrAccessChainOp accessChainOp) {
3913   return verifyAccessChain(accessChainOp, accessChainOp.indices());
3914 }
3915 
3916 namespace mlir {
3917 namespace spirv {
3918 
3919 // TableGen'erated operation interfaces for querying versions, extensions, and
3920 // capabilities.
3921 #include "mlir/Dialect/SPIRV/IR/SPIRVAvailability.cpp.inc"
3922 } // namespace spirv
3923 } // namespace mlir
3924 
3925 // TablenGen'erated operation definitions.
3926 #define GET_OP_CLASSES
3927 #include "mlir/Dialect/SPIRV/IR/SPIRVOps.cpp.inc"
3928 
3929 namespace mlir {
3930 namespace spirv {
3931 // TableGen'erated operation availability interface implementations.
3932 #include "mlir/Dialect/SPIRV/IR/SPIRVOpAvailabilityImpl.inc"
3933 
3934 } // namespace spirv
3935 } // namespace mlir
3936