1 //===- Deserializer.cpp - MLIR SPIR-V Deserializer ------------------------===//
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 SPIR-V binary to MLIR SPIR-V module deserializer.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Deserializer.h"
14 
15 #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
16 #include "mlir/Dialect/SPIRV/IR/SPIRVEnums.h"
17 #include "mlir/Dialect/SPIRV/IR/SPIRVModule.h"
18 #include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
19 #include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"
20 #include "mlir/IR/BlockAndValueMapping.h"
21 #include "mlir/IR/Builders.h"
22 #include "mlir/IR/Location.h"
23 #include "mlir/Support/LogicalResult.h"
24 #include "mlir/Target/SPIRV/SPIRVBinaryUtils.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/Sequence.h"
27 #include "llvm/ADT/SmallVector.h"
28 #include "llvm/ADT/StringExtras.h"
29 #include "llvm/ADT/bit.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/SaveAndRestore.h"
32 #include "llvm/Support/raw_ostream.h"
33 
34 using namespace mlir;
35 
36 #define DEBUG_TYPE "spirv-deserialization"
37 
38 //===----------------------------------------------------------------------===//
39 // Utility Functions
40 //===----------------------------------------------------------------------===//
41 
42 /// Returns true if the given `block` is a function entry block.
43 static inline bool isFnEntryBlock(Block *block) {
44   return block->isEntryBlock() &&
45          isa_and_nonnull<spirv::FuncOp>(block->getParentOp());
46 }
47 
48 //===----------------------------------------------------------------------===//
49 // Deserializer Method Definitions
50 //===----------------------------------------------------------------------===//
51 
52 spirv::Deserializer::Deserializer(ArrayRef<uint32_t> binary,
53                                   MLIRContext *context)
54     : binary(binary), context(context), unknownLoc(UnknownLoc::get(context)),
55       module(createModuleOp()), opBuilder(module->body()) {}
56 
57 LogicalResult spirv::Deserializer::deserialize() {
58   LLVM_DEBUG(llvm::dbgs() << "+++ starting deserialization +++\n");
59 
60   if (failed(processHeader()))
61     return failure();
62 
63   spirv::Opcode opcode = spirv::Opcode::OpNop;
64   ArrayRef<uint32_t> operands;
65   auto binarySize = binary.size();
66   while (curOffset < binarySize) {
67     // Slice the next instruction out and populate `opcode` and `operands`.
68     // Internally this also updates `curOffset`.
69     if (failed(sliceInstruction(opcode, operands)))
70       return failure();
71 
72     if (failed(processInstruction(opcode, operands)))
73       return failure();
74   }
75 
76   assert(curOffset == binarySize &&
77          "deserializer should never index beyond the binary end");
78 
79   for (auto &deferred : deferredInstructions) {
80     if (failed(processInstruction(deferred.first, deferred.second, false))) {
81       return failure();
82     }
83   }
84 
85   attachVCETriple();
86 
87   LLVM_DEBUG(llvm::dbgs() << "+++ completed deserialization +++\n");
88   return success();
89 }
90 
91 spirv::OwningSPIRVModuleRef spirv::Deserializer::collect() {
92   return std::move(module);
93 }
94 
95 //===----------------------------------------------------------------------===//
96 // Module structure
97 //===----------------------------------------------------------------------===//
98 
99 spirv::OwningSPIRVModuleRef spirv::Deserializer::createModuleOp() {
100   OpBuilder builder(context);
101   OperationState state(unknownLoc, spirv::ModuleOp::getOperationName());
102   spirv::ModuleOp::build(builder, state);
103   return cast<spirv::ModuleOp>(Operation::create(state));
104 }
105 
106 LogicalResult spirv::Deserializer::processHeader() {
107   if (binary.size() < spirv::kHeaderWordCount)
108     return emitError(unknownLoc,
109                      "SPIR-V binary module must have a 5-word header");
110 
111   if (binary[0] != spirv::kMagicNumber)
112     return emitError(unknownLoc, "incorrect magic number");
113 
114   // Version number bytes: 0 | major number | minor number | 0
115   uint32_t majorVersion = (binary[1] << 8) >> 24;
116   uint32_t minorVersion = (binary[1] << 16) >> 24;
117   if (majorVersion == 1) {
118     switch (minorVersion) {
119 #define MIN_VERSION_CASE(v)                                                    \
120   case v:                                                                      \
121     version = spirv::Version::V_1_##v;                                         \
122     break
123 
124       MIN_VERSION_CASE(0);
125       MIN_VERSION_CASE(1);
126       MIN_VERSION_CASE(2);
127       MIN_VERSION_CASE(3);
128       MIN_VERSION_CASE(4);
129       MIN_VERSION_CASE(5);
130 #undef MIN_VERSION_CASE
131     default:
132       return emitError(unknownLoc, "unsupported SPIR-V minor version: ")
133              << minorVersion;
134     }
135   } else {
136     return emitError(unknownLoc, "unsupported SPIR-V major version: ")
137            << majorVersion;
138   }
139 
140   // TODO: generator number, bound, schema
141   curOffset = spirv::kHeaderWordCount;
142   return success();
143 }
144 
145 LogicalResult
146 spirv::Deserializer::processCapability(ArrayRef<uint32_t> operands) {
147   if (operands.size() != 1)
148     return emitError(unknownLoc, "OpMemoryModel must have one parameter");
149 
150   auto cap = spirv::symbolizeCapability(operands[0]);
151   if (!cap)
152     return emitError(unknownLoc, "unknown capability: ") << operands[0];
153 
154   capabilities.insert(*cap);
155   return success();
156 }
157 
158 LogicalResult spirv::Deserializer::processExtension(ArrayRef<uint32_t> words) {
159   if (words.empty()) {
160     return emitError(
161         unknownLoc,
162         "OpExtension must have a literal string for the extension name");
163   }
164 
165   unsigned wordIndex = 0;
166   StringRef extName = decodeStringLiteral(words, wordIndex);
167   if (wordIndex != words.size())
168     return emitError(unknownLoc,
169                      "unexpected trailing words in OpExtension instruction");
170   auto ext = spirv::symbolizeExtension(extName);
171   if (!ext)
172     return emitError(unknownLoc, "unknown extension: ") << extName;
173 
174   extensions.insert(*ext);
175   return success();
176 }
177 
178 LogicalResult
179 spirv::Deserializer::processExtInstImport(ArrayRef<uint32_t> words) {
180   if (words.size() < 2) {
181     return emitError(unknownLoc,
182                      "OpExtInstImport must have a result <id> and a literal "
183                      "string for the extended instruction set name");
184   }
185 
186   unsigned wordIndex = 1;
187   extendedInstSets[words[0]] = decodeStringLiteral(words, wordIndex);
188   if (wordIndex != words.size()) {
189     return emitError(unknownLoc,
190                      "unexpected trailing words in OpExtInstImport");
191   }
192   return success();
193 }
194 
195 void spirv::Deserializer::attachVCETriple() {
196   (*module)->setAttr(
197       spirv::ModuleOp::getVCETripleAttrName(),
198       spirv::VerCapExtAttr::get(version, capabilities.getArrayRef(),
199                                 extensions.getArrayRef(), context));
200 }
201 
202 LogicalResult
203 spirv::Deserializer::processMemoryModel(ArrayRef<uint32_t> operands) {
204   if (operands.size() != 2)
205     return emitError(unknownLoc, "OpMemoryModel must have two operands");
206 
207   (*module)->setAttr(
208       "addressing_model",
209       opBuilder.getI32IntegerAttr(llvm::bit_cast<int32_t>(operands.front())));
210   (*module)->setAttr(
211       "memory_model",
212       opBuilder.getI32IntegerAttr(llvm::bit_cast<int32_t>(operands.back())));
213 
214   return success();
215 }
216 
217 LogicalResult spirv::Deserializer::processDecoration(ArrayRef<uint32_t> words) {
218   // TODO: This function should also be auto-generated. For now, since only a
219   // few decorations are processed/handled in a meaningful manner, going with a
220   // manual implementation.
221   if (words.size() < 2) {
222     return emitError(
223         unknownLoc, "OpDecorate must have at least result <id> and Decoration");
224   }
225   auto decorationName =
226       stringifyDecoration(static_cast<spirv::Decoration>(words[1]));
227   if (decorationName.empty()) {
228     return emitError(unknownLoc, "invalid Decoration code : ") << words[1];
229   }
230   auto attrName = llvm::convertToSnakeFromCamelCase(decorationName);
231   auto symbol = opBuilder.getIdentifier(attrName);
232   switch (static_cast<spirv::Decoration>(words[1])) {
233   case spirv::Decoration::DescriptorSet:
234   case spirv::Decoration::Binding:
235     if (words.size() != 3) {
236       return emitError(unknownLoc, "OpDecorate with ")
237              << decorationName << " needs a single integer literal";
238     }
239     decorations[words[0]].set(
240         symbol, opBuilder.getI32IntegerAttr(static_cast<int32_t>(words[2])));
241     break;
242   case spirv::Decoration::BuiltIn:
243     if (words.size() != 3) {
244       return emitError(unknownLoc, "OpDecorate with ")
245              << decorationName << " needs a single integer literal";
246     }
247     decorations[words[0]].set(
248         symbol, opBuilder.getStringAttr(
249                     stringifyBuiltIn(static_cast<spirv::BuiltIn>(words[2]))));
250     break;
251   case spirv::Decoration::ArrayStride:
252     if (words.size() != 3) {
253       return emitError(unknownLoc, "OpDecorate with ")
254              << decorationName << " needs a single integer literal";
255     }
256     typeDecorations[words[0]] = words[2];
257     break;
258   case spirv::Decoration::Aliased:
259   case spirv::Decoration::Block:
260   case spirv::Decoration::BufferBlock:
261   case spirv::Decoration::Flat:
262   case spirv::Decoration::NonReadable:
263   case spirv::Decoration::NonWritable:
264   case spirv::Decoration::NoPerspective:
265   case spirv::Decoration::Restrict:
266     if (words.size() != 2) {
267       return emitError(unknownLoc, "OpDecoration with ")
268              << decorationName << "needs a single target <id>";
269     }
270     // Block decoration does not affect spv.struct type, but is still stored for
271     // verification.
272     // TODO: Update StructType to contain this information since
273     // it is needed for many validation rules.
274     decorations[words[0]].set(symbol, opBuilder.getUnitAttr());
275     break;
276   case spirv::Decoration::Location:
277   case spirv::Decoration::SpecId:
278     if (words.size() != 3) {
279       return emitError(unknownLoc, "OpDecoration with ")
280              << decorationName << "needs a single integer literal";
281     }
282     decorations[words[0]].set(
283         symbol, opBuilder.getI32IntegerAttr(static_cast<int32_t>(words[2])));
284     break;
285   default:
286     return emitError(unknownLoc, "unhandled Decoration : '") << decorationName;
287   }
288   return success();
289 }
290 
291 LogicalResult
292 spirv::Deserializer::processMemberDecoration(ArrayRef<uint32_t> words) {
293   // The binary layout of OpMemberDecorate is different comparing to OpDecorate
294   if (words.size() < 3) {
295     return emitError(unknownLoc,
296                      "OpMemberDecorate must have at least 3 operands");
297   }
298 
299   auto decoration = static_cast<spirv::Decoration>(words[2]);
300   if (decoration == spirv::Decoration::Offset && words.size() != 4) {
301     return emitError(unknownLoc,
302                      " missing offset specification in OpMemberDecorate with "
303                      "Offset decoration");
304   }
305   ArrayRef<uint32_t> decorationOperands;
306   if (words.size() > 3) {
307     decorationOperands = words.slice(3);
308   }
309   memberDecorationMap[words[0]][words[1]][decoration] = decorationOperands;
310   return success();
311 }
312 
313 LogicalResult spirv::Deserializer::processMemberName(ArrayRef<uint32_t> words) {
314   if (words.size() < 3) {
315     return emitError(unknownLoc, "OpMemberName must have at least 3 operands");
316   }
317   unsigned wordIndex = 2;
318   auto name = decodeStringLiteral(words, wordIndex);
319   if (wordIndex != words.size()) {
320     return emitError(unknownLoc,
321                      "unexpected trailing words in OpMemberName instruction");
322   }
323   memberNameMap[words[0]][words[1]] = name;
324   return success();
325 }
326 
327 LogicalResult
328 spirv::Deserializer::processFunction(ArrayRef<uint32_t> operands) {
329   if (curFunction) {
330     return emitError(unknownLoc, "found function inside function");
331   }
332 
333   // Get the result type
334   if (operands.size() != 4) {
335     return emitError(unknownLoc, "OpFunction must have 4 parameters");
336   }
337   Type resultType = getType(operands[0]);
338   if (!resultType) {
339     return emitError(unknownLoc, "undefined result type from <id> ")
340            << operands[0];
341   }
342 
343   if (funcMap.count(operands[1])) {
344     return emitError(unknownLoc, "duplicate function definition/declaration");
345   }
346 
347   auto fnControl = spirv::symbolizeFunctionControl(operands[2]);
348   if (!fnControl) {
349     return emitError(unknownLoc, "unknown Function Control: ") << operands[2];
350   }
351 
352   Type fnType = getType(operands[3]);
353   if (!fnType || !fnType.isa<FunctionType>()) {
354     return emitError(unknownLoc, "unknown function type from <id> ")
355            << operands[3];
356   }
357   auto functionType = fnType.cast<FunctionType>();
358 
359   if ((isVoidType(resultType) && functionType.getNumResults() != 0) ||
360       (functionType.getNumResults() == 1 &&
361        functionType.getResult(0) != resultType)) {
362     return emitError(unknownLoc, "mismatch in function type ")
363            << functionType << " and return type " << resultType << " specified";
364   }
365 
366   std::string fnName = getFunctionSymbol(operands[1]);
367   auto funcOp = opBuilder.create<spirv::FuncOp>(
368       unknownLoc, fnName, functionType, fnControl.getValue());
369   curFunction = funcMap[operands[1]] = funcOp;
370   LLVM_DEBUG(llvm::dbgs() << "-- start function " << fnName << " (type = "
371                           << fnType << ", id = " << operands[1] << ") --\n");
372   auto *entryBlock = funcOp.addEntryBlock();
373   LLVM_DEBUG(llvm::dbgs() << "[block] created entry block " << entryBlock
374                           << "\n");
375 
376   // Parse the op argument instructions
377   if (functionType.getNumInputs()) {
378     for (size_t i = 0, e = functionType.getNumInputs(); i != e; ++i) {
379       auto argType = functionType.getInput(i);
380       spirv::Opcode opcode = spirv::Opcode::OpNop;
381       ArrayRef<uint32_t> operands;
382       if (failed(sliceInstruction(opcode, operands,
383                                   spirv::Opcode::OpFunctionParameter))) {
384         return failure();
385       }
386       if (opcode != spirv::Opcode::OpFunctionParameter) {
387         return emitError(
388                    unknownLoc,
389                    "missing OpFunctionParameter instruction for argument ")
390                << i;
391       }
392       if (operands.size() != 2) {
393         return emitError(
394             unknownLoc,
395             "expected result type and result <id> for OpFunctionParameter");
396       }
397       auto argDefinedType = getType(operands[0]);
398       if (!argDefinedType || argDefinedType != argType) {
399         return emitError(unknownLoc,
400                          "mismatch in argument type between function type "
401                          "definition ")
402                << functionType << " and argument type definition "
403                << argDefinedType << " at argument " << i;
404       }
405       if (getValue(operands[1])) {
406         return emitError(unknownLoc, "duplicate definition of result <id> '")
407                << operands[1];
408       }
409       auto argValue = funcOp.getArgument(i);
410       valueMap[operands[1]] = argValue;
411     }
412   }
413 
414   // RAII guard to reset the insertion point to the module's region after
415   // deserializing the body of this function.
416   OpBuilder::InsertionGuard moduleInsertionGuard(opBuilder);
417 
418   spirv::Opcode opcode = spirv::Opcode::OpNop;
419   ArrayRef<uint32_t> instOperands;
420 
421   // Special handling for the entry block. We need to make sure it starts with
422   // an OpLabel instruction. The entry block takes the same parameters as the
423   // function. All other blocks do not take any parameter. We have already
424   // created the entry block, here we need to register it to the correct label
425   // <id>.
426   if (failed(sliceInstruction(opcode, instOperands,
427                               spirv::Opcode::OpFunctionEnd))) {
428     return failure();
429   }
430   if (opcode == spirv::Opcode::OpFunctionEnd) {
431     LLVM_DEBUG(llvm::dbgs()
432                << "-- completed function '" << fnName << "' (type = " << fnType
433                << ", id = " << operands[1] << ") --\n");
434     return processFunctionEnd(instOperands);
435   }
436   if (opcode != spirv::Opcode::OpLabel) {
437     return emitError(unknownLoc, "a basic block must start with OpLabel");
438   }
439   if (instOperands.size() != 1) {
440     return emitError(unknownLoc, "OpLabel should only have result <id>");
441   }
442   blockMap[instOperands[0]] = entryBlock;
443   if (failed(processLabel(instOperands))) {
444     return failure();
445   }
446 
447   // Then process all the other instructions in the function until we hit
448   // OpFunctionEnd.
449   while (succeeded(sliceInstruction(opcode, instOperands,
450                                     spirv::Opcode::OpFunctionEnd)) &&
451          opcode != spirv::Opcode::OpFunctionEnd) {
452     if (failed(processInstruction(opcode, instOperands))) {
453       return failure();
454     }
455   }
456   if (opcode != spirv::Opcode::OpFunctionEnd) {
457     return failure();
458   }
459 
460   LLVM_DEBUG(llvm::dbgs() << "-- completed function '" << fnName << "' (type = "
461                           << fnType << ", id = " << operands[1] << ") --\n");
462   return processFunctionEnd(instOperands);
463 }
464 
465 LogicalResult
466 spirv::Deserializer::processFunctionEnd(ArrayRef<uint32_t> operands) {
467   // Process OpFunctionEnd.
468   if (!operands.empty()) {
469     return emitError(unknownLoc, "unexpected operands for OpFunctionEnd");
470   }
471 
472   // Wire up block arguments from OpPhi instructions.
473   // Put all structured control flow in spv.selection/spv.loop ops.
474   if (failed(wireUpBlockArgument()) || failed(structurizeControlFlow())) {
475     return failure();
476   }
477 
478   curBlock = nullptr;
479   curFunction = llvm::None;
480 
481   return success();
482 }
483 
484 Optional<std::pair<Attribute, Type>>
485 spirv::Deserializer::getConstant(uint32_t id) {
486   auto constIt = constantMap.find(id);
487   if (constIt == constantMap.end())
488     return llvm::None;
489   return constIt->getSecond();
490 }
491 
492 Optional<spirv::SpecConstOperationMaterializationInfo>
493 spirv::Deserializer::getSpecConstantOperation(uint32_t id) {
494   auto constIt = specConstOperationMap.find(id);
495   if (constIt == specConstOperationMap.end())
496     return llvm::None;
497   return constIt->getSecond();
498 }
499 
500 std::string spirv::Deserializer::getFunctionSymbol(uint32_t id) {
501   auto funcName = nameMap.lookup(id).str();
502   if (funcName.empty()) {
503     funcName = "spirv_fn_" + std::to_string(id);
504   }
505   return funcName;
506 }
507 
508 std::string spirv::Deserializer::getSpecConstantSymbol(uint32_t id) {
509   auto constName = nameMap.lookup(id).str();
510   if (constName.empty()) {
511     constName = "spirv_spec_const_" + std::to_string(id);
512   }
513   return constName;
514 }
515 
516 spirv::SpecConstantOp
517 spirv::Deserializer::createSpecConstant(Location loc, uint32_t resultID,
518                                         Attribute defaultValue) {
519   auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
520   auto op = opBuilder.create<spirv::SpecConstantOp>(unknownLoc, symName,
521                                                     defaultValue);
522   if (decorations.count(resultID)) {
523     for (auto attr : decorations[resultID].getAttrs())
524       op->setAttr(attr.first, attr.second);
525   }
526   specConstMap[resultID] = op;
527   return op;
528 }
529 
530 LogicalResult
531 spirv::Deserializer::processGlobalVariable(ArrayRef<uint32_t> operands) {
532   unsigned wordIndex = 0;
533   if (operands.size() < 3) {
534     return emitError(
535         unknownLoc,
536         "OpVariable needs at least 3 operands, type, <id> and storage class");
537   }
538 
539   // Result Type.
540   auto type = getType(operands[wordIndex]);
541   if (!type) {
542     return emitError(unknownLoc, "unknown result type <id> : ")
543            << operands[wordIndex];
544   }
545   auto ptrType = type.dyn_cast<spirv::PointerType>();
546   if (!ptrType) {
547     return emitError(unknownLoc,
548                      "expected a result type <id> to be a spv.ptr, found : ")
549            << type;
550   }
551   wordIndex++;
552 
553   // Result <id>.
554   auto variableID = operands[wordIndex];
555   auto variableName = nameMap.lookup(variableID).str();
556   if (variableName.empty()) {
557     variableName = "spirv_var_" + std::to_string(variableID);
558   }
559   wordIndex++;
560 
561   // Storage class.
562   auto storageClass = static_cast<spirv::StorageClass>(operands[wordIndex]);
563   if (ptrType.getStorageClass() != storageClass) {
564     return emitError(unknownLoc, "mismatch in storage class of pointer type ")
565            << type << " and that specified in OpVariable instruction  : "
566            << stringifyStorageClass(storageClass);
567   }
568   wordIndex++;
569 
570   // Initializer.
571   FlatSymbolRefAttr initializer = nullptr;
572   if (wordIndex < operands.size()) {
573     auto initializerOp = getGlobalVariable(operands[wordIndex]);
574     if (!initializerOp) {
575       return emitError(unknownLoc, "unknown <id> ")
576              << operands[wordIndex] << "used as initializer";
577     }
578     wordIndex++;
579     initializer = opBuilder.getSymbolRefAttr(initializerOp.getOperation());
580   }
581   if (wordIndex != operands.size()) {
582     return emitError(unknownLoc,
583                      "found more operands than expected when deserializing "
584                      "OpVariable instruction, only ")
585            << wordIndex << " of " << operands.size() << " processed";
586   }
587   auto loc = createFileLineColLoc(opBuilder);
588   auto varOp = opBuilder.create<spirv::GlobalVariableOp>(
589       loc, TypeAttr::get(type), opBuilder.getStringAttr(variableName),
590       initializer);
591 
592   // Decorations.
593   if (decorations.count(variableID)) {
594     for (auto attr : decorations[variableID].getAttrs()) {
595       varOp->setAttr(attr.first, attr.second);
596     }
597   }
598   globalVariableMap[variableID] = varOp;
599   return success();
600 }
601 
602 IntegerAttr spirv::Deserializer::getConstantInt(uint32_t id) {
603   auto constInfo = getConstant(id);
604   if (!constInfo) {
605     return nullptr;
606   }
607   return constInfo->first.dyn_cast<IntegerAttr>();
608 }
609 
610 LogicalResult spirv::Deserializer::processName(ArrayRef<uint32_t> operands) {
611   if (operands.size() < 2) {
612     return emitError(unknownLoc, "OpName needs at least 2 operands");
613   }
614   if (!nameMap.lookup(operands[0]).empty()) {
615     return emitError(unknownLoc, "duplicate name found for result <id> ")
616            << operands[0];
617   }
618   unsigned wordIndex = 1;
619   StringRef name = decodeStringLiteral(operands, wordIndex);
620   if (wordIndex != operands.size()) {
621     return emitError(unknownLoc,
622                      "unexpected trailing words in OpName instruction");
623   }
624   nameMap[operands[0]] = name;
625   return success();
626 }
627 
628 //===----------------------------------------------------------------------===//
629 // Type
630 //===----------------------------------------------------------------------===//
631 
632 LogicalResult spirv::Deserializer::processType(spirv::Opcode opcode,
633                                                ArrayRef<uint32_t> operands) {
634   if (operands.empty()) {
635     return emitError(unknownLoc, "type instruction with opcode ")
636            << spirv::stringifyOpcode(opcode) << " needs at least one <id>";
637   }
638 
639   /// TODO: Types might be forward declared in some instructions and need to be
640   /// handled appropriately.
641   if (typeMap.count(operands[0])) {
642     return emitError(unknownLoc, "duplicate definition for result <id> ")
643            << operands[0];
644   }
645 
646   switch (opcode) {
647   case spirv::Opcode::OpTypeVoid:
648     if (operands.size() != 1)
649       return emitError(unknownLoc, "OpTypeVoid must have no parameters");
650     typeMap[operands[0]] = opBuilder.getNoneType();
651     break;
652   case spirv::Opcode::OpTypeBool:
653     if (operands.size() != 1)
654       return emitError(unknownLoc, "OpTypeBool must have no parameters");
655     typeMap[operands[0]] = opBuilder.getI1Type();
656     break;
657   case spirv::Opcode::OpTypeInt: {
658     if (operands.size() != 3)
659       return emitError(
660           unknownLoc, "OpTypeInt must have bitwidth and signedness parameters");
661 
662     // SPIR-V OpTypeInt "Signedness specifies whether there are signed semantics
663     // to preserve or validate.
664     // 0 indicates unsigned, or no signedness semantics
665     // 1 indicates signed semantics."
666     //
667     // So we cannot differentiate signless and unsigned integers; always use
668     // signless semantics for such cases.
669     auto sign = operands[2] == 1 ? IntegerType::SignednessSemantics::Signed
670                                  : IntegerType::SignednessSemantics::Signless;
671     typeMap[operands[0]] = IntegerType::get(context, operands[1], sign);
672   } break;
673   case spirv::Opcode::OpTypeFloat: {
674     if (operands.size() != 2)
675       return emitError(unknownLoc, "OpTypeFloat must have bitwidth parameter");
676 
677     Type floatTy;
678     switch (operands[1]) {
679     case 16:
680       floatTy = opBuilder.getF16Type();
681       break;
682     case 32:
683       floatTy = opBuilder.getF32Type();
684       break;
685     case 64:
686       floatTy = opBuilder.getF64Type();
687       break;
688     default:
689       return emitError(unknownLoc, "unsupported OpTypeFloat bitwidth: ")
690              << operands[1];
691     }
692     typeMap[operands[0]] = floatTy;
693   } break;
694   case spirv::Opcode::OpTypeVector: {
695     if (operands.size() != 3) {
696       return emitError(
697           unknownLoc,
698           "OpTypeVector must have element type and count parameters");
699     }
700     Type elementTy = getType(operands[1]);
701     if (!elementTy) {
702       return emitError(unknownLoc, "OpTypeVector references undefined <id> ")
703              << operands[1];
704     }
705     typeMap[operands[0]] = VectorType::get({operands[2]}, elementTy);
706   } break;
707   case spirv::Opcode::OpTypePointer: {
708     return processOpTypePointer(operands);
709   } break;
710   case spirv::Opcode::OpTypeArray:
711     return processArrayType(operands);
712   case spirv::Opcode::OpTypeCooperativeMatrixNV:
713     return processCooperativeMatrixType(operands);
714   case spirv::Opcode::OpTypeFunction:
715     return processFunctionType(operands);
716   case spirv::Opcode::OpTypeRuntimeArray:
717     return processRuntimeArrayType(operands);
718   case spirv::Opcode::OpTypeStruct:
719     return processStructType(operands);
720   case spirv::Opcode::OpTypeMatrix:
721     return processMatrixType(operands);
722   default:
723     return emitError(unknownLoc, "unhandled type instruction");
724   }
725   return success();
726 }
727 
728 LogicalResult
729 spirv::Deserializer::processOpTypePointer(ArrayRef<uint32_t> operands) {
730   if (operands.size() != 3)
731     return emitError(unknownLoc, "OpTypePointer must have two parameters");
732 
733   auto pointeeType = getType(operands[2]);
734   if (!pointeeType)
735     return emitError(unknownLoc, "unknown OpTypePointer pointee type <id> ")
736            << operands[2];
737 
738   uint32_t typePointerID = operands[0];
739   auto storageClass = static_cast<spirv::StorageClass>(operands[1]);
740   typeMap[typePointerID] = spirv::PointerType::get(pointeeType, storageClass);
741 
742   for (auto *deferredStructIt = std::begin(deferredStructTypesInfos);
743        deferredStructIt != std::end(deferredStructTypesInfos);) {
744     for (auto *unresolvedMemberIt =
745              std::begin(deferredStructIt->unresolvedMemberTypes);
746          unresolvedMemberIt !=
747          std::end(deferredStructIt->unresolvedMemberTypes);) {
748       if (unresolvedMemberIt->first == typePointerID) {
749         // The newly constructed pointer type can resolve one of the
750         // deferred struct type members; update the memberTypes list and
751         // clean the unresolvedMemberTypes list accordingly.
752         deferredStructIt->memberTypes[unresolvedMemberIt->second] =
753             typeMap[typePointerID];
754         unresolvedMemberIt =
755             deferredStructIt->unresolvedMemberTypes.erase(unresolvedMemberIt);
756       } else {
757         ++unresolvedMemberIt;
758       }
759     }
760 
761     if (deferredStructIt->unresolvedMemberTypes.empty()) {
762       // All deferred struct type members are now resolved, set the struct body.
763       auto structType = deferredStructIt->deferredStructType;
764 
765       assert(structType && "expected a spirv::StructType");
766       assert(structType.isIdentified() && "expected an indentified struct");
767 
768       if (failed(structType.trySetBody(
769               deferredStructIt->memberTypes, deferredStructIt->offsetInfo,
770               deferredStructIt->memberDecorationsInfo)))
771         return failure();
772 
773       deferredStructIt = deferredStructTypesInfos.erase(deferredStructIt);
774     } else {
775       ++deferredStructIt;
776     }
777   }
778 
779   return success();
780 }
781 
782 LogicalResult
783 spirv::Deserializer::processArrayType(ArrayRef<uint32_t> operands) {
784   if (operands.size() != 3) {
785     return emitError(unknownLoc,
786                      "OpTypeArray must have element type and count parameters");
787   }
788 
789   Type elementTy = getType(operands[1]);
790   if (!elementTy) {
791     return emitError(unknownLoc, "OpTypeArray references undefined <id> ")
792            << operands[1];
793   }
794 
795   unsigned count = 0;
796   // TODO: The count can also come frome a specialization constant.
797   auto countInfo = getConstant(operands[2]);
798   if (!countInfo) {
799     return emitError(unknownLoc, "OpTypeArray count <id> ")
800            << operands[2] << "can only come from normal constant right now";
801   }
802 
803   if (auto intVal = countInfo->first.dyn_cast<IntegerAttr>()) {
804     count = intVal.getValue().getZExtValue();
805   } else {
806     return emitError(unknownLoc, "OpTypeArray count must come from a "
807                                  "scalar integer constant instruction");
808   }
809 
810   typeMap[operands[0]] = spirv::ArrayType::get(
811       elementTy, count, typeDecorations.lookup(operands[0]));
812   return success();
813 }
814 
815 LogicalResult
816 spirv::Deserializer::processFunctionType(ArrayRef<uint32_t> operands) {
817   assert(!operands.empty() && "No operands for processing function type");
818   if (operands.size() == 1) {
819     return emitError(unknownLoc, "missing return type for OpTypeFunction");
820   }
821   auto returnType = getType(operands[1]);
822   if (!returnType) {
823     return emitError(unknownLoc, "unknown return type in OpTypeFunction");
824   }
825   SmallVector<Type, 1> argTypes;
826   for (size_t i = 2, e = operands.size(); i < e; ++i) {
827     auto ty = getType(operands[i]);
828     if (!ty) {
829       return emitError(unknownLoc, "unknown argument type in OpTypeFunction");
830     }
831     argTypes.push_back(ty);
832   }
833   ArrayRef<Type> returnTypes;
834   if (!isVoidType(returnType)) {
835     returnTypes = llvm::makeArrayRef(returnType);
836   }
837   typeMap[operands[0]] = FunctionType::get(context, argTypes, returnTypes);
838   return success();
839 }
840 
841 LogicalResult
842 spirv::Deserializer::processCooperativeMatrixType(ArrayRef<uint32_t> operands) {
843   if (operands.size() != 5) {
844     return emitError(unknownLoc, "OpTypeCooperativeMatrix must have element "
845                                  "type and row x column parameters");
846   }
847 
848   Type elementTy = getType(operands[1]);
849   if (!elementTy) {
850     return emitError(unknownLoc,
851                      "OpTypeCooperativeMatrix references undefined <id> ")
852            << operands[1];
853   }
854 
855   auto scope = spirv::symbolizeScope(getConstantInt(operands[2]).getInt());
856   if (!scope) {
857     return emitError(unknownLoc,
858                      "OpTypeCooperativeMatrix references undefined scope <id> ")
859            << operands[2];
860   }
861 
862   unsigned rows = getConstantInt(operands[3]).getInt();
863   unsigned columns = getConstantInt(operands[4]).getInt();
864 
865   typeMap[operands[0]] = spirv::CooperativeMatrixNVType::get(
866       elementTy, scope.getValue(), rows, columns);
867   return success();
868 }
869 
870 LogicalResult
871 spirv::Deserializer::processRuntimeArrayType(ArrayRef<uint32_t> operands) {
872   if (operands.size() != 2) {
873     return emitError(unknownLoc, "OpTypeRuntimeArray must have two operands");
874   }
875   Type memberType = getType(operands[1]);
876   if (!memberType) {
877     return emitError(unknownLoc,
878                      "OpTypeRuntimeArray references undefined <id> ")
879            << operands[1];
880   }
881   typeMap[operands[0]] = spirv::RuntimeArrayType::get(
882       memberType, typeDecorations.lookup(operands[0]));
883   return success();
884 }
885 
886 LogicalResult
887 spirv::Deserializer::processStructType(ArrayRef<uint32_t> operands) {
888   // TODO: Find a way to handle identified structs when debug info is stripped.
889 
890   if (operands.empty()) {
891     return emitError(unknownLoc, "OpTypeStruct must have at least result <id>");
892   }
893 
894   if (operands.size() == 1) {
895     // Handle empty struct.
896     typeMap[operands[0]] =
897         spirv::StructType::getEmpty(context, nameMap.lookup(operands[0]).str());
898     return success();
899   }
900 
901   // First element is operand ID, second element is member index in the struct.
902   SmallVector<std::pair<uint32_t, unsigned>, 0> unresolvedMemberTypes;
903   SmallVector<Type, 4> memberTypes;
904 
905   for (auto op : llvm::drop_begin(operands, 1)) {
906     Type memberType = getType(op);
907     bool typeForwardPtr = (typeForwardPointerIDs.count(op) != 0);
908 
909     if (!memberType && !typeForwardPtr)
910       return emitError(unknownLoc, "OpTypeStruct references undefined <id> ")
911              << op;
912 
913     if (!memberType)
914       unresolvedMemberTypes.emplace_back(op, memberTypes.size());
915 
916     memberTypes.push_back(memberType);
917   }
918 
919   SmallVector<spirv::StructType::OffsetInfo, 0> offsetInfo;
920   SmallVector<spirv::StructType::MemberDecorationInfo, 0> memberDecorationsInfo;
921   if (memberDecorationMap.count(operands[0])) {
922     auto &allMemberDecorations = memberDecorationMap[operands[0]];
923     for (auto memberIndex : llvm::seq<uint32_t>(0, memberTypes.size())) {
924       if (allMemberDecorations.count(memberIndex)) {
925         for (auto &memberDecoration : allMemberDecorations[memberIndex]) {
926           // Check for offset.
927           if (memberDecoration.first == spirv::Decoration::Offset) {
928             // If offset info is empty, resize to the number of members;
929             if (offsetInfo.empty()) {
930               offsetInfo.resize(memberTypes.size());
931             }
932             offsetInfo[memberIndex] = memberDecoration.second[0];
933           } else {
934             if (!memberDecoration.second.empty()) {
935               memberDecorationsInfo.emplace_back(memberIndex, /*hasValue=*/1,
936                                                  memberDecoration.first,
937                                                  memberDecoration.second[0]);
938             } else {
939               memberDecorationsInfo.emplace_back(memberIndex, /*hasValue=*/0,
940                                                  memberDecoration.first, 0);
941             }
942           }
943         }
944       }
945     }
946   }
947 
948   uint32_t structID = operands[0];
949   std::string structIdentifier = nameMap.lookup(structID).str();
950 
951   if (structIdentifier.empty()) {
952     assert(unresolvedMemberTypes.empty() &&
953            "didn't expect unresolved member types");
954     typeMap[structID] =
955         spirv::StructType::get(memberTypes, offsetInfo, memberDecorationsInfo);
956   } else {
957     auto structTy = spirv::StructType::getIdentified(context, structIdentifier);
958     typeMap[structID] = structTy;
959 
960     if (!unresolvedMemberTypes.empty())
961       deferredStructTypesInfos.push_back({structTy, unresolvedMemberTypes,
962                                           memberTypes, offsetInfo,
963                                           memberDecorationsInfo});
964     else if (failed(structTy.trySetBody(memberTypes, offsetInfo,
965                                         memberDecorationsInfo)))
966       return failure();
967   }
968 
969   // TODO: Update StructType to have member name as attribute as
970   // well.
971   return success();
972 }
973 
974 LogicalResult
975 spirv::Deserializer::processMatrixType(ArrayRef<uint32_t> operands) {
976   if (operands.size() != 3) {
977     // Three operands are needed: result_id, column_type, and column_count
978     return emitError(unknownLoc, "OpTypeMatrix must have 3 operands"
979                                  " (result_id, column_type, and column_count)");
980   }
981   // Matrix columns must be of vector type
982   Type elementTy = getType(operands[1]);
983   if (!elementTy) {
984     return emitError(unknownLoc,
985                      "OpTypeMatrix references undefined column type.")
986            << operands[1];
987   }
988 
989   uint32_t colsCount = operands[2];
990   typeMap[operands[0]] = spirv::MatrixType::get(elementTy, colsCount);
991   return success();
992 }
993 
994 LogicalResult
995 spirv::Deserializer::processTypeForwardPointer(ArrayRef<uint32_t> operands) {
996   if (operands.size() != 2)
997     return emitError(unknownLoc,
998                      "OpTypeForwardPointer instruction must have two operands");
999 
1000   typeForwardPointerIDs.insert(operands[0]);
1001   // TODO: Use the 2nd operand (Storage Class) to validate the OpTypePointer
1002   // instruction that defines the actual type.
1003 
1004   return success();
1005 }
1006 
1007 //===----------------------------------------------------------------------===//
1008 // Constant
1009 //===----------------------------------------------------------------------===//
1010 
1011 LogicalResult spirv::Deserializer::processConstant(ArrayRef<uint32_t> operands,
1012                                                    bool isSpec) {
1013   StringRef opname = isSpec ? "OpSpecConstant" : "OpConstant";
1014 
1015   if (operands.size() < 2) {
1016     return emitError(unknownLoc)
1017            << opname << " must have type <id> and result <id>";
1018   }
1019   if (operands.size() < 3) {
1020     return emitError(unknownLoc)
1021            << opname << " must have at least 1 more parameter";
1022   }
1023 
1024   Type resultType = getType(operands[0]);
1025   if (!resultType) {
1026     return emitError(unknownLoc, "undefined result type from <id> ")
1027            << operands[0];
1028   }
1029 
1030   auto checkOperandSizeForBitwidth = [&](unsigned bitwidth) -> LogicalResult {
1031     if (bitwidth == 64) {
1032       if (operands.size() == 4) {
1033         return success();
1034       }
1035       return emitError(unknownLoc)
1036              << opname << " should have 2 parameters for 64-bit values";
1037     }
1038     if (bitwidth <= 32) {
1039       if (operands.size() == 3) {
1040         return success();
1041       }
1042 
1043       return emitError(unknownLoc)
1044              << opname
1045              << " should have 1 parameter for values with no more than 32 bits";
1046     }
1047     return emitError(unknownLoc, "unsupported OpConstant bitwidth: ")
1048            << bitwidth;
1049   };
1050 
1051   auto resultID = operands[1];
1052 
1053   if (auto intType = resultType.dyn_cast<IntegerType>()) {
1054     auto bitwidth = intType.getWidth();
1055     if (failed(checkOperandSizeForBitwidth(bitwidth))) {
1056       return failure();
1057     }
1058 
1059     APInt value;
1060     if (bitwidth == 64) {
1061       // 64-bit integers are represented with two SPIR-V words. According to
1062       // SPIR-V spec: "When the type’s bit width is larger than one word, the
1063       // literal’s low-order words appear first."
1064       struct DoubleWord {
1065         uint32_t word1;
1066         uint32_t word2;
1067       } words = {operands[2], operands[3]};
1068       value = APInt(64, llvm::bit_cast<uint64_t>(words), /*isSigned=*/true);
1069     } else if (bitwidth <= 32) {
1070       value = APInt(bitwidth, operands[2], /*isSigned=*/true);
1071     }
1072 
1073     auto attr = opBuilder.getIntegerAttr(intType, value);
1074 
1075     if (isSpec) {
1076       createSpecConstant(unknownLoc, resultID, attr);
1077     } else {
1078       // For normal constants, we just record the attribute (and its type) for
1079       // later materialization at use sites.
1080       constantMap.try_emplace(resultID, attr, intType);
1081     }
1082 
1083     return success();
1084   }
1085 
1086   if (auto floatType = resultType.dyn_cast<FloatType>()) {
1087     auto bitwidth = floatType.getWidth();
1088     if (failed(checkOperandSizeForBitwidth(bitwidth))) {
1089       return failure();
1090     }
1091 
1092     APFloat value(0.f);
1093     if (floatType.isF64()) {
1094       // Double values are represented with two SPIR-V words. According to
1095       // SPIR-V spec: "When the type’s bit width is larger than one word, the
1096       // literal’s low-order words appear first."
1097       struct DoubleWord {
1098         uint32_t word1;
1099         uint32_t word2;
1100       } words = {operands[2], operands[3]};
1101       value = APFloat(llvm::bit_cast<double>(words));
1102     } else if (floatType.isF32()) {
1103       value = APFloat(llvm::bit_cast<float>(operands[2]));
1104     } else if (floatType.isF16()) {
1105       APInt data(16, operands[2]);
1106       value = APFloat(APFloat::IEEEhalf(), data);
1107     }
1108 
1109     auto attr = opBuilder.getFloatAttr(floatType, value);
1110     if (isSpec) {
1111       createSpecConstant(unknownLoc, resultID, attr);
1112     } else {
1113       // For normal constants, we just record the attribute (and its type) for
1114       // later materialization at use sites.
1115       constantMap.try_emplace(resultID, attr, floatType);
1116     }
1117 
1118     return success();
1119   }
1120 
1121   return emitError(unknownLoc, "OpConstant can only generate values of "
1122                                "scalar integer or floating-point type");
1123 }
1124 
1125 LogicalResult spirv::Deserializer::processConstantBool(
1126     bool isTrue, ArrayRef<uint32_t> operands, bool isSpec) {
1127   if (operands.size() != 2) {
1128     return emitError(unknownLoc, "Op")
1129            << (isSpec ? "Spec" : "") << "Constant"
1130            << (isTrue ? "True" : "False")
1131            << " must have type <id> and result <id>";
1132   }
1133 
1134   auto attr = opBuilder.getBoolAttr(isTrue);
1135   auto resultID = operands[1];
1136   if (isSpec) {
1137     createSpecConstant(unknownLoc, resultID, attr);
1138   } else {
1139     // For normal constants, we just record the attribute (and its type) for
1140     // later materialization at use sites.
1141     constantMap.try_emplace(resultID, attr, opBuilder.getI1Type());
1142   }
1143 
1144   return success();
1145 }
1146 
1147 LogicalResult
1148 spirv::Deserializer::processConstantComposite(ArrayRef<uint32_t> operands) {
1149   if (operands.size() < 2) {
1150     return emitError(unknownLoc,
1151                      "OpConstantComposite must have type <id> and result <id>");
1152   }
1153   if (operands.size() < 3) {
1154     return emitError(unknownLoc,
1155                      "OpConstantComposite must have at least 1 parameter");
1156   }
1157 
1158   Type resultType = getType(operands[0]);
1159   if (!resultType) {
1160     return emitError(unknownLoc, "undefined result type from <id> ")
1161            << operands[0];
1162   }
1163 
1164   SmallVector<Attribute, 4> elements;
1165   elements.reserve(operands.size() - 2);
1166   for (unsigned i = 2, e = operands.size(); i < e; ++i) {
1167     auto elementInfo = getConstant(operands[i]);
1168     if (!elementInfo) {
1169       return emitError(unknownLoc, "OpConstantComposite component <id> ")
1170              << operands[i] << " must come from a normal constant";
1171     }
1172     elements.push_back(elementInfo->first);
1173   }
1174 
1175   auto resultID = operands[1];
1176   if (auto vectorType = resultType.dyn_cast<VectorType>()) {
1177     auto attr = DenseElementsAttr::get(vectorType, elements);
1178     // For normal constants, we just record the attribute (and its type) for
1179     // later materialization at use sites.
1180     constantMap.try_emplace(resultID, attr, resultType);
1181   } else if (auto arrayType = resultType.dyn_cast<spirv::ArrayType>()) {
1182     auto attr = opBuilder.getArrayAttr(elements);
1183     constantMap.try_emplace(resultID, attr, resultType);
1184   } else {
1185     return emitError(unknownLoc, "unsupported OpConstantComposite type: ")
1186            << resultType;
1187   }
1188 
1189   return success();
1190 }
1191 
1192 LogicalResult
1193 spirv::Deserializer::processSpecConstantComposite(ArrayRef<uint32_t> operands) {
1194   if (operands.size() < 2) {
1195     return emitError(unknownLoc,
1196                      "OpConstantComposite must have type <id> and result <id>");
1197   }
1198   if (operands.size() < 3) {
1199     return emitError(unknownLoc,
1200                      "OpConstantComposite must have at least 1 parameter");
1201   }
1202 
1203   Type resultType = getType(operands[0]);
1204   if (!resultType) {
1205     return emitError(unknownLoc, "undefined result type from <id> ")
1206            << operands[0];
1207   }
1208 
1209   auto resultID = operands[1];
1210   auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
1211 
1212   SmallVector<Attribute, 4> elements;
1213   elements.reserve(operands.size() - 2);
1214   for (unsigned i = 2, e = operands.size(); i < e; ++i) {
1215     auto elementInfo = getSpecConstant(operands[i]);
1216     elements.push_back(opBuilder.getSymbolRefAttr(elementInfo));
1217   }
1218 
1219   auto op = opBuilder.create<spirv::SpecConstantCompositeOp>(
1220       unknownLoc, TypeAttr::get(resultType), symName,
1221       opBuilder.getArrayAttr(elements));
1222   specConstCompositeMap[resultID] = op;
1223 
1224   return success();
1225 }
1226 
1227 LogicalResult
1228 spirv::Deserializer::processSpecConstantOperation(ArrayRef<uint32_t> operands) {
1229   if (operands.size() < 3)
1230     return emitError(unknownLoc, "OpConstantOperation must have type <id>, "
1231                                  "result <id>, and operand opcode");
1232 
1233   uint32_t resultTypeID = operands[0];
1234 
1235   if (!getType(resultTypeID))
1236     return emitError(unknownLoc, "undefined result type from <id> ")
1237            << resultTypeID;
1238 
1239   uint32_t resultID = operands[1];
1240   spirv::Opcode enclosedOpcode = static_cast<spirv::Opcode>(operands[2]);
1241   auto emplaceResult = specConstOperationMap.try_emplace(
1242       resultID,
1243       SpecConstOperationMaterializationInfo{
1244           enclosedOpcode, resultTypeID,
1245           SmallVector<uint32_t>{operands.begin() + 3, operands.end()}});
1246 
1247   if (!emplaceResult.second)
1248     return emitError(unknownLoc, "value with <id>: ")
1249            << resultID << " is probably defined before.";
1250 
1251   return success();
1252 }
1253 
1254 Value spirv::Deserializer::materializeSpecConstantOperation(
1255     uint32_t resultID, spirv::Opcode enclosedOpcode, uint32_t resultTypeID,
1256     ArrayRef<uint32_t> enclosedOpOperands) {
1257 
1258   Type resultType = getType(resultTypeID);
1259 
1260   // Instructions wrapped by OpSpecConstantOp need an ID for their
1261   // Deserializer::processOp<op_name>(...) to emit the corresponding SPIR-V
1262   // dialect wrapped op. For that purpose, a new value map is created and "fake"
1263   // ID in that map is assigned to the result of the enclosed instruction. Note
1264   // that there is no need to update this fake ID since we only need to
1265   // reference the created Value for the enclosed op from the spv::YieldOp
1266   // created later in this method (both of which are the only values in their
1267   // region: the SpecConstantOperation's region). If we encounter another
1268   // SpecConstantOperation in the module, we simply re-use the fake ID since the
1269   // previous Value assigned to it isn't visible in the current scope anyway.
1270   DenseMap<uint32_t, Value> newValueMap;
1271   llvm::SaveAndRestore<DenseMap<uint32_t, Value>> valueMapGuard(valueMap,
1272                                                                 newValueMap);
1273   constexpr uint32_t fakeID = static_cast<uint32_t>(-3);
1274 
1275   SmallVector<uint32_t, 4> enclosedOpResultTypeAndOperands;
1276   enclosedOpResultTypeAndOperands.push_back(resultTypeID);
1277   enclosedOpResultTypeAndOperands.push_back(fakeID);
1278   enclosedOpResultTypeAndOperands.append(enclosedOpOperands.begin(),
1279                                          enclosedOpOperands.end());
1280 
1281   // Process enclosed instruction before creating the enclosing
1282   // specConstantOperation (and its region). This way, references to constants,
1283   // global variables, and spec constants will be materialized outside the new
1284   // op's region. For more info, see Deserializer::getValue's implementation.
1285   if (failed(
1286           processInstruction(enclosedOpcode, enclosedOpResultTypeAndOperands)))
1287     return Value();
1288 
1289   // Since the enclosed op is emitted in the current block, split it in a
1290   // separate new block.
1291   Block *enclosedBlock = curBlock->splitBlock(&curBlock->back());
1292 
1293   auto loc = createFileLineColLoc(opBuilder);
1294   auto specConstOperationOp =
1295       opBuilder.create<spirv::SpecConstantOperationOp>(loc, resultType);
1296 
1297   Region &body = specConstOperationOp.body();
1298   // Move the new block into SpecConstantOperation's body.
1299   body.getBlocks().splice(body.end(), curBlock->getParent()->getBlocks(),
1300                           Region::iterator(enclosedBlock));
1301   Block &block = body.back();
1302 
1303   // RAII guard to reset the insertion point to the module's region after
1304   // deserializing the body of the specConstantOperation.
1305   OpBuilder::InsertionGuard moduleInsertionGuard(opBuilder);
1306   opBuilder.setInsertionPointToEnd(&block);
1307 
1308   opBuilder.create<spirv::YieldOp>(loc, block.front().getResult(0));
1309   return specConstOperationOp.getResult();
1310 }
1311 
1312 LogicalResult
1313 spirv::Deserializer::processConstantNull(ArrayRef<uint32_t> operands) {
1314   if (operands.size() != 2) {
1315     return emitError(unknownLoc,
1316                      "OpConstantNull must have type <id> and result <id>");
1317   }
1318 
1319   Type resultType = getType(operands[0]);
1320   if (!resultType) {
1321     return emitError(unknownLoc, "undefined result type from <id> ")
1322            << operands[0];
1323   }
1324 
1325   auto resultID = operands[1];
1326   if (resultType.isIntOrFloat() || resultType.isa<VectorType>()) {
1327     auto attr = opBuilder.getZeroAttr(resultType);
1328     // For normal constants, we just record the attribute (and its type) for
1329     // later materialization at use sites.
1330     constantMap.try_emplace(resultID, attr, resultType);
1331     return success();
1332   }
1333 
1334   return emitError(unknownLoc, "unsupported OpConstantNull type: ")
1335          << resultType;
1336 }
1337 
1338 //===----------------------------------------------------------------------===//
1339 // Control flow
1340 //===----------------------------------------------------------------------===//
1341 
1342 Block *spirv::Deserializer::getOrCreateBlock(uint32_t id) {
1343   if (auto *block = getBlock(id)) {
1344     LLVM_DEBUG(llvm::dbgs() << "[block] got exiting block for id = " << id
1345                             << " @ " << block << "\n");
1346     return block;
1347   }
1348 
1349   // We don't know where this block will be placed finally (in a spv.selection
1350   // or spv.loop or function). Create it into the function for now and sort
1351   // out the proper place later.
1352   auto *block = curFunction->addBlock();
1353   LLVM_DEBUG(llvm::dbgs() << "[block] created block for id = " << id << " @ "
1354                           << block << "\n");
1355   return blockMap[id] = block;
1356 }
1357 
1358 LogicalResult spirv::Deserializer::processBranch(ArrayRef<uint32_t> operands) {
1359   if (!curBlock) {
1360     return emitError(unknownLoc, "OpBranch must appear inside a block");
1361   }
1362 
1363   if (operands.size() != 1) {
1364     return emitError(unknownLoc, "OpBranch must take exactly one target label");
1365   }
1366 
1367   auto *target = getOrCreateBlock(operands[0]);
1368   auto loc = createFileLineColLoc(opBuilder);
1369   // The preceding instruction for the OpBranch instruction could be an
1370   // OpLoopMerge or an OpSelectionMerge instruction, in this case they will have
1371   // the same OpLine information.
1372   opBuilder.create<spirv::BranchOp>(loc, target);
1373 
1374   clearDebugLine();
1375   return success();
1376 }
1377 
1378 LogicalResult
1379 spirv::Deserializer::processBranchConditional(ArrayRef<uint32_t> operands) {
1380   if (!curBlock) {
1381     return emitError(unknownLoc,
1382                      "OpBranchConditional must appear inside a block");
1383   }
1384 
1385   if (operands.size() != 3 && operands.size() != 5) {
1386     return emitError(unknownLoc,
1387                      "OpBranchConditional must have condition, true label, "
1388                      "false label, and optionally two branch weights");
1389   }
1390 
1391   auto condition = getValue(operands[0]);
1392   auto *trueBlock = getOrCreateBlock(operands[1]);
1393   auto *falseBlock = getOrCreateBlock(operands[2]);
1394 
1395   Optional<std::pair<uint32_t, uint32_t>> weights;
1396   if (operands.size() == 5) {
1397     weights = std::make_pair(operands[3], operands[4]);
1398   }
1399   // The preceding instruction for the OpBranchConditional instruction could be
1400   // an OpSelectionMerge instruction, in this case they will have the same
1401   // OpLine information.
1402   auto loc = createFileLineColLoc(opBuilder);
1403   opBuilder.create<spirv::BranchConditionalOp>(
1404       loc, condition, trueBlock,
1405       /*trueArguments=*/ArrayRef<Value>(), falseBlock,
1406       /*falseArguments=*/ArrayRef<Value>(), weights);
1407 
1408   clearDebugLine();
1409   return success();
1410 }
1411 
1412 LogicalResult spirv::Deserializer::processLabel(ArrayRef<uint32_t> operands) {
1413   if (!curFunction) {
1414     return emitError(unknownLoc, "OpLabel must appear inside a function");
1415   }
1416 
1417   if (operands.size() != 1) {
1418     return emitError(unknownLoc, "OpLabel should only have result <id>");
1419   }
1420 
1421   auto labelID = operands[0];
1422   // We may have forward declared this block.
1423   auto *block = getOrCreateBlock(labelID);
1424   LLVM_DEBUG(llvm::dbgs() << "[block] populating block " << block << "\n");
1425   // If we have seen this block, make sure it was just a forward declaration.
1426   assert(block->empty() && "re-deserialize the same block!");
1427 
1428   opBuilder.setInsertionPointToStart(block);
1429   blockMap[labelID] = curBlock = block;
1430 
1431   return success();
1432 }
1433 
1434 LogicalResult
1435 spirv::Deserializer::processSelectionMerge(ArrayRef<uint32_t> operands) {
1436   if (!curBlock) {
1437     return emitError(unknownLoc, "OpSelectionMerge must appear in a block");
1438   }
1439 
1440   if (operands.size() < 2) {
1441     return emitError(
1442         unknownLoc,
1443         "OpSelectionMerge must specify merge target and selection control");
1444   }
1445 
1446   auto *mergeBlock = getOrCreateBlock(operands[0]);
1447   auto loc = createFileLineColLoc(opBuilder);
1448   auto selectionControl = operands[1];
1449 
1450   if (!blockMergeInfo.try_emplace(curBlock, loc, selectionControl, mergeBlock)
1451            .second) {
1452     return emitError(
1453         unknownLoc,
1454         "a block cannot have more than one OpSelectionMerge instruction");
1455   }
1456 
1457   return success();
1458 }
1459 
1460 LogicalResult
1461 spirv::Deserializer::processLoopMerge(ArrayRef<uint32_t> operands) {
1462   if (!curBlock) {
1463     return emitError(unknownLoc, "OpLoopMerge must appear in a block");
1464   }
1465 
1466   if (operands.size() < 3) {
1467     return emitError(unknownLoc, "OpLoopMerge must specify merge target, "
1468                                  "continue target and loop control");
1469   }
1470 
1471   auto *mergeBlock = getOrCreateBlock(operands[0]);
1472   auto *continueBlock = getOrCreateBlock(operands[1]);
1473   auto loc = createFileLineColLoc(opBuilder);
1474   uint32_t loopControl = operands[2];
1475 
1476   if (!blockMergeInfo
1477            .try_emplace(curBlock, loc, loopControl, mergeBlock, continueBlock)
1478            .second) {
1479     return emitError(
1480         unknownLoc,
1481         "a block cannot have more than one OpLoopMerge instruction");
1482   }
1483 
1484   return success();
1485 }
1486 
1487 LogicalResult spirv::Deserializer::processPhi(ArrayRef<uint32_t> operands) {
1488   if (!curBlock) {
1489     return emitError(unknownLoc, "OpPhi must appear in a block");
1490   }
1491 
1492   if (operands.size() < 4) {
1493     return emitError(unknownLoc, "OpPhi must specify result type, result <id>, "
1494                                  "and variable-parent pairs");
1495   }
1496 
1497   // Create a block argument for this OpPhi instruction.
1498   Type blockArgType = getType(operands[0]);
1499   BlockArgument blockArg = curBlock->addArgument(blockArgType);
1500   valueMap[operands[1]] = blockArg;
1501   LLVM_DEBUG(llvm::dbgs() << "[phi] created block argument " << blockArg
1502                           << " id = " << operands[1] << " of type "
1503                           << blockArgType << '\n');
1504 
1505   // For each (value, predecessor) pair, insert the value to the predecessor's
1506   // blockPhiInfo entry so later we can fix the block argument there.
1507   for (unsigned i = 2, e = operands.size(); i < e; i += 2) {
1508     uint32_t value = operands[i];
1509     Block *predecessor = getOrCreateBlock(operands[i + 1]);
1510     blockPhiInfo[predecessor].push_back(value);
1511     LLVM_DEBUG(llvm::dbgs() << "[phi] predecessor @ " << predecessor
1512                             << " with arg id = " << value << '\n');
1513   }
1514 
1515   return success();
1516 }
1517 
1518 namespace {
1519 /// A class for putting all blocks in a structured selection/loop in a
1520 /// spv.selection/spv.loop op.
1521 class ControlFlowStructurizer {
1522 public:
1523   /// Structurizes the loop at the given `headerBlock`.
1524   ///
1525   /// This method will create an spv.loop op in the `mergeBlock` and move all
1526   /// blocks in the structured loop into the spv.loop's region. All branches to
1527   /// the `headerBlock` will be redirected to the `mergeBlock`.
1528   /// This method will also update `mergeInfo` by remapping all blocks inside to
1529   /// the newly cloned ones inside structured control flow op's regions.
1530   static LogicalResult structurize(Location loc, uint32_t control,
1531                                    spirv::BlockMergeInfoMap &mergeInfo,
1532                                    Block *headerBlock, Block *mergeBlock,
1533                                    Block *continueBlock) {
1534     return ControlFlowStructurizer(loc, control, mergeInfo, headerBlock,
1535                                    mergeBlock, continueBlock)
1536         .structurizeImpl();
1537   }
1538 
1539 private:
1540   ControlFlowStructurizer(Location loc, uint32_t control,
1541                           spirv::BlockMergeInfoMap &mergeInfo, Block *header,
1542                           Block *merge, Block *cont)
1543       : location(loc), control(control), blockMergeInfo(mergeInfo),
1544         headerBlock(header), mergeBlock(merge), continueBlock(cont) {}
1545 
1546   /// Creates a new spv.selection op at the beginning of the `mergeBlock`.
1547   spirv::SelectionOp createSelectionOp(uint32_t selectionControl);
1548 
1549   /// Creates a new spv.loop op at the beginning of the `mergeBlock`.
1550   spirv::LoopOp createLoopOp(uint32_t loopControl);
1551 
1552   /// Collects all blocks reachable from `headerBlock` except `mergeBlock`.
1553   void collectBlocksInConstruct();
1554 
1555   LogicalResult structurizeImpl();
1556 
1557   Location location;
1558   uint32_t control;
1559 
1560   spirv::BlockMergeInfoMap &blockMergeInfo;
1561 
1562   Block *headerBlock;
1563   Block *mergeBlock;
1564   Block *continueBlock; // nullptr for spv.selection
1565 
1566   llvm::SetVector<Block *> constructBlocks;
1567 };
1568 } // namespace
1569 
1570 spirv::SelectionOp
1571 ControlFlowStructurizer::createSelectionOp(uint32_t selectionControl) {
1572   // Create a builder and set the insertion point to the beginning of the
1573   // merge block so that the newly created SelectionOp will be inserted there.
1574   OpBuilder builder(&mergeBlock->front());
1575 
1576   auto control = builder.getI32IntegerAttr(selectionControl);
1577   auto selectionOp = builder.create<spirv::SelectionOp>(location, control);
1578   selectionOp.addMergeBlock();
1579 
1580   return selectionOp;
1581 }
1582 
1583 spirv::LoopOp ControlFlowStructurizer::createLoopOp(uint32_t loopControl) {
1584   // Create a builder and set the insertion point to the beginning of the
1585   // merge block so that the newly created LoopOp will be inserted there.
1586   OpBuilder builder(&mergeBlock->front());
1587 
1588   auto control = builder.getI32IntegerAttr(loopControl);
1589   auto loopOp = builder.create<spirv::LoopOp>(location, control);
1590   loopOp.addEntryAndMergeBlock();
1591 
1592   return loopOp;
1593 }
1594 
1595 void ControlFlowStructurizer::collectBlocksInConstruct() {
1596   assert(constructBlocks.empty() && "expected empty constructBlocks");
1597 
1598   // Put the header block in the work list first.
1599   constructBlocks.insert(headerBlock);
1600 
1601   // For each item in the work list, add its successors excluding the merge
1602   // block.
1603   for (unsigned i = 0; i < constructBlocks.size(); ++i) {
1604     for (auto *successor : constructBlocks[i]->getSuccessors())
1605       if (successor != mergeBlock)
1606         constructBlocks.insert(successor);
1607   }
1608 }
1609 
1610 LogicalResult ControlFlowStructurizer::structurizeImpl() {
1611   Operation *op = nullptr;
1612   bool isLoop = continueBlock != nullptr;
1613   if (isLoop) {
1614     if (auto loopOp = createLoopOp(control))
1615       op = loopOp.getOperation();
1616   } else {
1617     if (auto selectionOp = createSelectionOp(control))
1618       op = selectionOp.getOperation();
1619   }
1620   if (!op)
1621     return failure();
1622   Region &body = op->getRegion(0);
1623 
1624   BlockAndValueMapping mapper;
1625   // All references to the old merge block should be directed to the
1626   // selection/loop merge block in the SelectionOp/LoopOp's region.
1627   mapper.map(mergeBlock, &body.back());
1628 
1629   collectBlocksInConstruct();
1630 
1631   // We've identified all blocks belonging to the selection/loop's region. Now
1632   // need to "move" them into the selection/loop. Instead of really moving the
1633   // blocks, in the following we copy them and remap all values and branches.
1634   // This is because:
1635   // * Inserting a block into a region requires the block not in any region
1636   //   before. But selections/loops can nest so we can create selection/loop ops
1637   //   in a nested manner, which means some blocks may already be in a
1638   //   selection/loop region when to be moved again.
1639   // * It's much trickier to fix up the branches into and out of the loop's
1640   //   region: we need to treat not-moved blocks and moved blocks differently:
1641   //   Not-moved blocks jumping to the loop header block need to jump to the
1642   //   merge point containing the new loop op but not the loop continue block's
1643   //   back edge. Moved blocks jumping out of the loop need to jump to the
1644   //   merge block inside the loop region but not other not-moved blocks.
1645   //   We cannot use replaceAllUsesWith clearly and it's harder to follow the
1646   //   logic.
1647 
1648   // Create a corresponding block in the SelectionOp/LoopOp's region for each
1649   // block in this loop construct.
1650   OpBuilder builder(body);
1651   for (auto *block : constructBlocks) {
1652     // Create a block and insert it before the selection/loop merge block in the
1653     // SelectionOp/LoopOp's region.
1654     auto *newBlock = builder.createBlock(&body.back());
1655     mapper.map(block, newBlock);
1656     LLVM_DEBUG(llvm::dbgs() << "[cf] cloned block " << newBlock
1657                             << " from block " << block << "\n");
1658     if (!isFnEntryBlock(block)) {
1659       for (BlockArgument blockArg : block->getArguments()) {
1660         auto newArg = newBlock->addArgument(blockArg.getType());
1661         mapper.map(blockArg, newArg);
1662         LLVM_DEBUG(llvm::dbgs() << "[cf] remapped block argument " << blockArg
1663                                 << " to " << newArg << '\n');
1664       }
1665     } else {
1666       LLVM_DEBUG(llvm::dbgs()
1667                  << "[cf] block " << block << " is a function entry block\n");
1668     }
1669     for (auto &op : *block)
1670       newBlock->push_back(op.clone(mapper));
1671   }
1672 
1673   // Go through all ops and remap the operands.
1674   auto remapOperands = [&](Operation *op) {
1675     for (auto &operand : op->getOpOperands())
1676       if (Value mappedOp = mapper.lookupOrNull(operand.get()))
1677         operand.set(mappedOp);
1678     for (auto &succOp : op->getBlockOperands())
1679       if (Block *mappedOp = mapper.lookupOrNull(succOp.get()))
1680         succOp.set(mappedOp);
1681   };
1682   for (auto &block : body) {
1683     block.walk(remapOperands);
1684   }
1685 
1686   // We have created the SelectionOp/LoopOp and "moved" all blocks belonging to
1687   // the selection/loop construct into its region. Next we need to fix the
1688   // connections between this new SelectionOp/LoopOp with existing blocks.
1689 
1690   // All existing incoming branches should go to the merge block, where the
1691   // SelectionOp/LoopOp resides right now.
1692   headerBlock->replaceAllUsesWith(mergeBlock);
1693 
1694   if (isLoop) {
1695     // The loop selection/loop header block may have block arguments. Since now
1696     // we place the selection/loop op inside the old merge block, we need to
1697     // make sure the old merge block has the same block argument list.
1698     assert(mergeBlock->args_empty() && "OpPhi in loop merge block unsupported");
1699     for (BlockArgument blockArg : headerBlock->getArguments()) {
1700       mergeBlock->addArgument(blockArg.getType());
1701     }
1702 
1703     // If the loop header block has block arguments, make sure the spv.branch op
1704     // matches.
1705     SmallVector<Value, 4> blockArgs;
1706     if (!headerBlock->args_empty())
1707       blockArgs = {mergeBlock->args_begin(), mergeBlock->args_end()};
1708 
1709     // The loop entry block should have a unconditional branch jumping to the
1710     // loop header block.
1711     builder.setInsertionPointToEnd(&body.front());
1712     builder.create<spirv::BranchOp>(location, mapper.lookupOrNull(headerBlock),
1713                                     ArrayRef<Value>(blockArgs));
1714   }
1715 
1716   // All the blocks cloned into the SelectionOp/LoopOp's region can now be
1717   // cleaned up.
1718   LLVM_DEBUG(llvm::dbgs() << "[cf] cleaning up blocks after clone\n");
1719   // First we need to drop all operands' references inside all blocks. This is
1720   // needed because we can have blocks referencing SSA values from one another.
1721   for (auto *block : constructBlocks)
1722     block->dropAllReferences();
1723 
1724   // Then erase all old blocks.
1725   for (auto *block : constructBlocks) {
1726     // We've cloned all blocks belonging to this construct into the structured
1727     // control flow op's region. Among these blocks, some may compose another
1728     // selection/loop. If so, they will be recorded within blockMergeInfo.
1729     // We need to update the pointers there to the newly remapped ones so we can
1730     // continue structurizing them later.
1731     // TODO: The asserts in the following assumes input SPIR-V blob
1732     // forms correctly nested selection/loop constructs. We should relax this
1733     // and support error cases better.
1734     auto it = blockMergeInfo.find(block);
1735     if (it != blockMergeInfo.end()) {
1736       Block *newHeader = mapper.lookupOrNull(block);
1737       assert(newHeader && "nested loop header block should be remapped!");
1738 
1739       Block *newContinue = it->second.continueBlock;
1740       if (newContinue) {
1741         newContinue = mapper.lookupOrNull(newContinue);
1742         assert(newContinue && "nested loop continue block should be remapped!");
1743       }
1744 
1745       Block *newMerge = it->second.mergeBlock;
1746       if (Block *mappedTo = mapper.lookupOrNull(newMerge))
1747         newMerge = mappedTo;
1748 
1749       // Keep original location for nested selection/loop ops.
1750       Location loc = it->second.loc;
1751       // The iterator should be erased before adding a new entry into
1752       // blockMergeInfo to avoid iterator invalidation.
1753       blockMergeInfo.erase(it);
1754       blockMergeInfo.try_emplace(newHeader, loc, it->second.control, newMerge,
1755                                  newContinue);
1756     }
1757 
1758     // The structured selection/loop's entry block does not have arguments.
1759     // If the function's header block is also part of the structured control
1760     // flow, we cannot just simply erase it because it may contain arguments
1761     // matching the function signature and used by the cloned blocks.
1762     if (isFnEntryBlock(block)) {
1763       LLVM_DEBUG(llvm::dbgs() << "[cf] changing entry block " << block
1764                               << " to only contain a spv.Branch op\n");
1765       // Still keep the function entry block for the potential block arguments,
1766       // but replace all ops inside with a branch to the merge block.
1767       block->clear();
1768       builder.setInsertionPointToEnd(block);
1769       builder.create<spirv::BranchOp>(location, mergeBlock);
1770     } else {
1771       LLVM_DEBUG(llvm::dbgs() << "[cf] erasing block " << block << "\n");
1772       block->erase();
1773     }
1774   }
1775 
1776   LLVM_DEBUG(
1777       llvm::dbgs() << "[cf] after structurizing construct with header block "
1778                    << headerBlock << ":\n"
1779                    << *op << '\n');
1780 
1781   return success();
1782 }
1783 
1784 LogicalResult spirv::Deserializer::wireUpBlockArgument() {
1785   LLVM_DEBUG(llvm::dbgs() << "[phi] start wiring up block arguments\n");
1786 
1787   OpBuilder::InsertionGuard guard(opBuilder);
1788 
1789   for (const auto &info : blockPhiInfo) {
1790     Block *block = info.first;
1791     const BlockPhiInfo &phiInfo = info.second;
1792     LLVM_DEBUG(llvm::dbgs() << "[phi] block " << block << "\n");
1793     LLVM_DEBUG(llvm::dbgs() << "[phi] before creating block argument:\n");
1794     LLVM_DEBUG(block->getParentOp()->print(llvm::dbgs()));
1795     LLVM_DEBUG(llvm::dbgs() << '\n');
1796 
1797     // Set insertion point to before this block's terminator early because we
1798     // may materialize ops via getValue() call.
1799     auto *op = block->getTerminator();
1800     opBuilder.setInsertionPoint(op);
1801 
1802     SmallVector<Value, 4> blockArgs;
1803     blockArgs.reserve(phiInfo.size());
1804     for (uint32_t valueId : phiInfo) {
1805       if (Value value = getValue(valueId)) {
1806         blockArgs.push_back(value);
1807         LLVM_DEBUG(llvm::dbgs() << "[phi] block argument " << value
1808                                 << " id = " << valueId << '\n');
1809       } else {
1810         return emitError(unknownLoc, "OpPhi references undefined value!");
1811       }
1812     }
1813 
1814     if (auto branchOp = dyn_cast<spirv::BranchOp>(op)) {
1815       // Replace the previous branch op with a new one with block arguments.
1816       opBuilder.create<spirv::BranchOp>(branchOp.getLoc(), branchOp.getTarget(),
1817                                         blockArgs);
1818       branchOp.erase();
1819     } else {
1820       return emitError(unknownLoc, "unimplemented terminator for Phi creation");
1821     }
1822 
1823     LLVM_DEBUG(llvm::dbgs() << "[phi] after creating block argument:\n");
1824     LLVM_DEBUG(block->getParentOp()->print(llvm::dbgs()));
1825     LLVM_DEBUG(llvm::dbgs() << '\n');
1826   }
1827   blockPhiInfo.clear();
1828 
1829   LLVM_DEBUG(llvm::dbgs() << "[phi] completed wiring up block arguments\n");
1830   return success();
1831 }
1832 
1833 LogicalResult spirv::Deserializer::structurizeControlFlow() {
1834   LLVM_DEBUG(llvm::dbgs() << "[cf] start structurizing control flow\n");
1835 
1836   while (!blockMergeInfo.empty()) {
1837     Block *headerBlock = blockMergeInfo.begin()->first;
1838     BlockMergeInfo mergeInfo = blockMergeInfo.begin()->second;
1839 
1840     LLVM_DEBUG(llvm::dbgs() << "[cf] header block " << headerBlock << ":\n");
1841     LLVM_DEBUG(headerBlock->print(llvm::dbgs()));
1842 
1843     auto *mergeBlock = mergeInfo.mergeBlock;
1844     assert(mergeBlock && "merge block cannot be nullptr");
1845     if (!mergeBlock->args_empty())
1846       return emitError(unknownLoc, "OpPhi in loop merge block unimplemented");
1847     LLVM_DEBUG(llvm::dbgs() << "[cf] merge block " << mergeBlock << ":\n");
1848     LLVM_DEBUG(mergeBlock->print(llvm::dbgs()));
1849 
1850     auto *continueBlock = mergeInfo.continueBlock;
1851     if (continueBlock) {
1852       LLVM_DEBUG(llvm::dbgs()
1853                  << "[cf] continue block " << continueBlock << ":\n");
1854       LLVM_DEBUG(continueBlock->print(llvm::dbgs()));
1855     }
1856     // Erase this case before calling into structurizer, who will update
1857     // blockMergeInfo.
1858     blockMergeInfo.erase(blockMergeInfo.begin());
1859     if (failed(ControlFlowStructurizer::structurize(
1860             mergeInfo.loc, mergeInfo.control, blockMergeInfo, headerBlock,
1861             mergeBlock, continueBlock)))
1862       return failure();
1863   }
1864 
1865   LLVM_DEBUG(llvm::dbgs() << "[cf] completed structurizing control flow\n");
1866   return success();
1867 }
1868 
1869 //===----------------------------------------------------------------------===//
1870 // Debug
1871 //===----------------------------------------------------------------------===//
1872 
1873 Location spirv::Deserializer::createFileLineColLoc(OpBuilder opBuilder) {
1874   if (!debugLine)
1875     return unknownLoc;
1876 
1877   auto fileName = debugInfoMap.lookup(debugLine->fileID).str();
1878   if (fileName.empty())
1879     fileName = "<unknown>";
1880   return opBuilder.getFileLineColLoc(opBuilder.getIdentifier(fileName),
1881                                      debugLine->line, debugLine->col);
1882 }
1883 
1884 LogicalResult
1885 spirv::Deserializer::processDebugLine(ArrayRef<uint32_t> operands) {
1886   // According to SPIR-V spec:
1887   // "This location information applies to the instructions physically
1888   // following this instruction, up to the first occurrence of any of the
1889   // following: the next end of block, the next OpLine instruction, or the next
1890   // OpNoLine instruction."
1891   if (operands.size() != 3)
1892     return emitError(unknownLoc, "OpLine must have 3 operands");
1893   debugLine = DebugLine(operands[0], operands[1], operands[2]);
1894   return success();
1895 }
1896 
1897 LogicalResult spirv::Deserializer::clearDebugLine() {
1898   debugLine = llvm::None;
1899   return success();
1900 }
1901 
1902 LogicalResult
1903 spirv::Deserializer::processDebugString(ArrayRef<uint32_t> operands) {
1904   if (operands.size() < 2)
1905     return emitError(unknownLoc, "OpString needs at least 2 operands");
1906 
1907   if (!debugInfoMap.lookup(operands[0]).empty())
1908     return emitError(unknownLoc,
1909                      "duplicate debug string found for result <id> ")
1910            << operands[0];
1911 
1912   unsigned wordIndex = 1;
1913   StringRef debugString = decodeStringLiteral(operands, wordIndex);
1914   if (wordIndex != operands.size())
1915     return emitError(unknownLoc,
1916                      "unexpected trailing words in OpString instruction");
1917 
1918   debugInfoMap[operands[0]] = debugString;
1919   return success();
1920 }
1921