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