188d5c4c2SKareemErgawy-TomTom //===- Serializer.cpp - MLIR SPIR-V Serializer ----------------------------===//
288d5c4c2SKareemErgawy-TomTom //
388d5c4c2SKareemErgawy-TomTom // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
488d5c4c2SKareemErgawy-TomTom // See https://llvm.org/LICENSE.txt for license information.
588d5c4c2SKareemErgawy-TomTom // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
688d5c4c2SKareemErgawy-TomTom //
788d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
888d5c4c2SKareemErgawy-TomTom //
988d5c4c2SKareemErgawy-TomTom // This file defines the MLIR SPIR-V module to SPIR-V binary serializer.
1088d5c4c2SKareemErgawy-TomTom //
1188d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
1288d5c4c2SKareemErgawy-TomTom 
1388d5c4c2SKareemErgawy-TomTom #include "Serializer.h"
1488d5c4c2SKareemErgawy-TomTom 
1588d5c4c2SKareemErgawy-TomTom #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"
1688d5c4c2SKareemErgawy-TomTom #include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
1788d5c4c2SKareemErgawy-TomTom #include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"
1888d5c4c2SKareemErgawy-TomTom #include "mlir/Support/LogicalResult.h"
1988d5c4c2SKareemErgawy-TomTom #include "mlir/Target/SPIRV/SPIRVBinaryUtils.h"
2088d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/Sequence.h"
2188d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/SmallPtrSet.h"
2288d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/StringExtras.h"
2388d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/TypeSwitch.h"
2488d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/bit.h"
2588d5c4c2SKareemErgawy-TomTom #include "llvm/Support/Debug.h"
2688d5c4c2SKareemErgawy-TomTom 
2788d5c4c2SKareemErgawy-TomTom #define DEBUG_TYPE "spirv-serialization"
2888d5c4c2SKareemErgawy-TomTom 
2988d5c4c2SKareemErgawy-TomTom using namespace mlir;
3088d5c4c2SKareemErgawy-TomTom 
3188d5c4c2SKareemErgawy-TomTom /// Returns the merge block if the given `op` is a structured control flow op.
3288d5c4c2SKareemErgawy-TomTom /// Otherwise returns nullptr.
getStructuredControlFlowOpMergeBlock(Operation * op)3388d5c4c2SKareemErgawy-TomTom static Block *getStructuredControlFlowOpMergeBlock(Operation *op) {
3488d5c4c2SKareemErgawy-TomTom   if (auto selectionOp = dyn_cast<spirv::SelectionOp>(op))
3588d5c4c2SKareemErgawy-TomTom     return selectionOp.getMergeBlock();
3688d5c4c2SKareemErgawy-TomTom   if (auto loopOp = dyn_cast<spirv::LoopOp>(op))
3788d5c4c2SKareemErgawy-TomTom     return loopOp.getMergeBlock();
3888d5c4c2SKareemErgawy-TomTom   return nullptr;
3988d5c4c2SKareemErgawy-TomTom }
4088d5c4c2SKareemErgawy-TomTom 
4188d5c4c2SKareemErgawy-TomTom /// Given a predecessor `block` for a block with arguments, returns the block
4288d5c4c2SKareemErgawy-TomTom /// that should be used as the parent block for SPIR-V OpPhi instructions
4388d5c4c2SKareemErgawy-TomTom /// corresponding to the block arguments.
getPhiIncomingBlock(Block * block)4488d5c4c2SKareemErgawy-TomTom static Block *getPhiIncomingBlock(Block *block) {
4529812a61SKareemErgawy-TomTom   // If the predecessor block in question is the entry block for a
4629812a61SKareemErgawy-TomTom   // spv.mlir.loop, we jump to this spv.mlir.loop from its enclosing block.
4788d5c4c2SKareemErgawy-TomTom   if (block->isEntryBlock()) {
4888d5c4c2SKareemErgawy-TomTom     if (auto loopOp = dyn_cast<spirv::LoopOp>(block->getParentOp())) {
4988d5c4c2SKareemErgawy-TomTom       // Then the incoming parent block for OpPhi should be the merge block of
5088d5c4c2SKareemErgawy-TomTom       // the structured control flow op before this loop.
5188d5c4c2SKareemErgawy-TomTom       Operation *op = loopOp.getOperation();
5288d5c4c2SKareemErgawy-TomTom       while ((op = op->getPrevNode()) != nullptr)
5388d5c4c2SKareemErgawy-TomTom         if (Block *incomingBlock = getStructuredControlFlowOpMergeBlock(op))
5488d5c4c2SKareemErgawy-TomTom           return incomingBlock;
5588d5c4c2SKareemErgawy-TomTom       // Or the enclosing block itself if no structured control flow ops
5688d5c4c2SKareemErgawy-TomTom       // exists before this loop.
5788d5c4c2SKareemErgawy-TomTom       return loopOp->getBlock();
5888d5c4c2SKareemErgawy-TomTom     }
5988d5c4c2SKareemErgawy-TomTom   }
6088d5c4c2SKareemErgawy-TomTom 
6188d5c4c2SKareemErgawy-TomTom   // Otherwise, we jump from the given predecessor block. Try to see if there is
6288d5c4c2SKareemErgawy-TomTom   // a structured control flow op inside it.
6388d5c4c2SKareemErgawy-TomTom   for (Operation &op : llvm::reverse(block->getOperations())) {
6488d5c4c2SKareemErgawy-TomTom     if (Block *incomingBlock = getStructuredControlFlowOpMergeBlock(&op))
6588d5c4c2SKareemErgawy-TomTom       return incomingBlock;
6688d5c4c2SKareemErgawy-TomTom   }
6788d5c4c2SKareemErgawy-TomTom   return block;
6888d5c4c2SKareemErgawy-TomTom }
6988d5c4c2SKareemErgawy-TomTom 
7088d5c4c2SKareemErgawy-TomTom namespace mlir {
7188d5c4c2SKareemErgawy-TomTom namespace spirv {
7288d5c4c2SKareemErgawy-TomTom 
7388d5c4c2SKareemErgawy-TomTom /// Encodes an SPIR-V instruction with the given `opcode` and `operands` into
7488d5c4c2SKareemErgawy-TomTom /// the given `binary` vector.
encodeInstructionInto(SmallVectorImpl<uint32_t> & binary,spirv::Opcode op,ArrayRef<uint32_t> operands)753ed47bccSLei Zhang void encodeInstructionInto(SmallVectorImpl<uint32_t> &binary, spirv::Opcode op,
7688d5c4c2SKareemErgawy-TomTom                            ArrayRef<uint32_t> operands) {
7788d5c4c2SKareemErgawy-TomTom   uint32_t wordCount = 1 + operands.size();
7888d5c4c2SKareemErgawy-TomTom   binary.push_back(spirv::getPrefixedOpcode(wordCount, op));
7988d5c4c2SKareemErgawy-TomTom   binary.append(operands.begin(), operands.end());
8088d5c4c2SKareemErgawy-TomTom }
8188d5c4c2SKareemErgawy-TomTom 
Serializer(spirv::ModuleOp module,const SerializationOptions & options)82b289266cSLei Zhang Serializer::Serializer(spirv::ModuleOp module,
83b289266cSLei Zhang                        const SerializationOptions &options)
84b289266cSLei Zhang     : module(module), mlirBuilder(module.getContext()), options(options) {}
8588d5c4c2SKareemErgawy-TomTom 
serialize()8688d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::serialize() {
8788d5c4c2SKareemErgawy-TomTom   LLVM_DEBUG(llvm::dbgs() << "+++ starting serialization +++\n");
8888d5c4c2SKareemErgawy-TomTom 
8942e5f1d9SRiver Riddle   if (failed(module.verifyInvariants()))
9088d5c4c2SKareemErgawy-TomTom     return failure();
9188d5c4c2SKareemErgawy-TomTom 
9288d5c4c2SKareemErgawy-TomTom   // TODO: handle the other sections
9388d5c4c2SKareemErgawy-TomTom   processCapability();
9488d5c4c2SKareemErgawy-TomTom   processExtension();
9588d5c4c2SKareemErgawy-TomTom   processMemoryModel();
9688d5c4c2SKareemErgawy-TomTom   processDebugInfo();
9788d5c4c2SKareemErgawy-TomTom 
9888d5c4c2SKareemErgawy-TomTom   // Iterate over the module body to serialize it. Assumptions are that there is
9988d5c4c2SKareemErgawy-TomTom   // only one basic block in the moduleOp
10056f60a1cSLei Zhang   for (auto &op : *module.getBody()) {
10188d5c4c2SKareemErgawy-TomTom     if (failed(processOperation(&op))) {
10288d5c4c2SKareemErgawy-TomTom       return failure();
10388d5c4c2SKareemErgawy-TomTom     }
10488d5c4c2SKareemErgawy-TomTom   }
10588d5c4c2SKareemErgawy-TomTom 
10688d5c4c2SKareemErgawy-TomTom   LLVM_DEBUG(llvm::dbgs() << "+++ completed serialization +++\n");
10788d5c4c2SKareemErgawy-TomTom   return success();
10888d5c4c2SKareemErgawy-TomTom }
10988d5c4c2SKareemErgawy-TomTom 
collect(SmallVectorImpl<uint32_t> & binary)11088d5c4c2SKareemErgawy-TomTom void Serializer::collect(SmallVectorImpl<uint32_t> &binary) {
11188d5c4c2SKareemErgawy-TomTom   auto moduleSize = spirv::kHeaderWordCount + capabilities.size() +
11288d5c4c2SKareemErgawy-TomTom                     extensions.size() + extendedSets.size() +
11388d5c4c2SKareemErgawy-TomTom                     memoryModel.size() + entryPoints.size() +
11488d5c4c2SKareemErgawy-TomTom                     executionModes.size() + decorations.size() +
11588d5c4c2SKareemErgawy-TomTom                     typesGlobalValues.size() + functions.size();
11688d5c4c2SKareemErgawy-TomTom 
11788d5c4c2SKareemErgawy-TomTom   binary.clear();
11888d5c4c2SKareemErgawy-TomTom   binary.reserve(moduleSize);
11988d5c4c2SKareemErgawy-TomTom 
12088d5c4c2SKareemErgawy-TomTom   spirv::appendModuleHeader(binary, module.vce_triple()->getVersion(), nextID);
12188d5c4c2SKareemErgawy-TomTom   binary.append(capabilities.begin(), capabilities.end());
12288d5c4c2SKareemErgawy-TomTom   binary.append(extensions.begin(), extensions.end());
12388d5c4c2SKareemErgawy-TomTom   binary.append(extendedSets.begin(), extendedSets.end());
12488d5c4c2SKareemErgawy-TomTom   binary.append(memoryModel.begin(), memoryModel.end());
12588d5c4c2SKareemErgawy-TomTom   binary.append(entryPoints.begin(), entryPoints.end());
12688d5c4c2SKareemErgawy-TomTom   binary.append(executionModes.begin(), executionModes.end());
12788d5c4c2SKareemErgawy-TomTom   binary.append(debug.begin(), debug.end());
12888d5c4c2SKareemErgawy-TomTom   binary.append(names.begin(), names.end());
12988d5c4c2SKareemErgawy-TomTom   binary.append(decorations.begin(), decorations.end());
13088d5c4c2SKareemErgawy-TomTom   binary.append(typesGlobalValues.begin(), typesGlobalValues.end());
13188d5c4c2SKareemErgawy-TomTom   binary.append(functions.begin(), functions.end());
13288d5c4c2SKareemErgawy-TomTom }
13388d5c4c2SKareemErgawy-TomTom 
13488d5c4c2SKareemErgawy-TomTom #ifndef NDEBUG
printValueIDMap(raw_ostream & os)13588d5c4c2SKareemErgawy-TomTom void Serializer::printValueIDMap(raw_ostream &os) {
13688d5c4c2SKareemErgawy-TomTom   os << "\n= Value <id> Map =\n\n";
13788d5c4c2SKareemErgawy-TomTom   for (auto valueIDPair : valueIDMap) {
13888d5c4c2SKareemErgawy-TomTom     Value val = valueIDPair.first;
13988d5c4c2SKareemErgawy-TomTom     os << "  " << val << " "
14088d5c4c2SKareemErgawy-TomTom        << "id = " << valueIDPair.second << ' ';
14188d5c4c2SKareemErgawy-TomTom     if (auto *op = val.getDefiningOp()) {
14288d5c4c2SKareemErgawy-TomTom       os << "from op '" << op->getName() << "'";
14388d5c4c2SKareemErgawy-TomTom     } else if (auto arg = val.dyn_cast<BlockArgument>()) {
14488d5c4c2SKareemErgawy-TomTom       Block *block = arg.getOwner();
14588d5c4c2SKareemErgawy-TomTom       os << "from argument of block " << block << ' ';
14688d5c4c2SKareemErgawy-TomTom       os << " in op '" << block->getParentOp()->getName() << "'";
14788d5c4c2SKareemErgawy-TomTom     }
14888d5c4c2SKareemErgawy-TomTom     os << '\n';
14988d5c4c2SKareemErgawy-TomTom   }
15088d5c4c2SKareemErgawy-TomTom }
15188d5c4c2SKareemErgawy-TomTom #endif
15288d5c4c2SKareemErgawy-TomTom 
15388d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
15488d5c4c2SKareemErgawy-TomTom // Module structure
15588d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
15688d5c4c2SKareemErgawy-TomTom 
getOrCreateFunctionID(StringRef fnName)15788d5c4c2SKareemErgawy-TomTom uint32_t Serializer::getOrCreateFunctionID(StringRef fnName) {
15888d5c4c2SKareemErgawy-TomTom   auto funcID = funcIDMap.lookup(fnName);
15988d5c4c2SKareemErgawy-TomTom   if (!funcID) {
16088d5c4c2SKareemErgawy-TomTom     funcID = getNextID();
16188d5c4c2SKareemErgawy-TomTom     funcIDMap[fnName] = funcID;
16288d5c4c2SKareemErgawy-TomTom   }
16388d5c4c2SKareemErgawy-TomTom   return funcID;
16488d5c4c2SKareemErgawy-TomTom }
16588d5c4c2SKareemErgawy-TomTom 
processCapability()16688d5c4c2SKareemErgawy-TomTom void Serializer::processCapability() {
16788d5c4c2SKareemErgawy-TomTom   for (auto cap : module.vce_triple()->getCapabilities())
1683ed47bccSLei Zhang     encodeInstructionInto(capabilities, spirv::Opcode::OpCapability,
16988d5c4c2SKareemErgawy-TomTom                           {static_cast<uint32_t>(cap)});
17088d5c4c2SKareemErgawy-TomTom }
17188d5c4c2SKareemErgawy-TomTom 
processDebugInfo()17288d5c4c2SKareemErgawy-TomTom void Serializer::processDebugInfo() {
173b289266cSLei Zhang   if (!options.emitDebugInfo)
17488d5c4c2SKareemErgawy-TomTom     return;
17588d5c4c2SKareemErgawy-TomTom   auto fileLoc = module.getLoc().dyn_cast<FileLineColLoc>();
176a4bb667dSRiver Riddle   auto fileName = fileLoc ? fileLoc.getFilename().strref() : "<unknown>";
17788d5c4c2SKareemErgawy-TomTom   fileID = getNextID();
17888d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 16> operands;
17988d5c4c2SKareemErgawy-TomTom   operands.push_back(fileID);
1803ed47bccSLei Zhang   spirv::encodeStringLiteralInto(operands, fileName);
1813ed47bccSLei Zhang   encodeInstructionInto(debug, spirv::Opcode::OpString, operands);
18288d5c4c2SKareemErgawy-TomTom   // TODO: Encode more debug instructions.
18388d5c4c2SKareemErgawy-TomTom }
18488d5c4c2SKareemErgawy-TomTom 
processExtension()18588d5c4c2SKareemErgawy-TomTom void Serializer::processExtension() {
18688d5c4c2SKareemErgawy-TomTom   llvm::SmallVector<uint32_t, 16> extName;
18788d5c4c2SKareemErgawy-TomTom   for (spirv::Extension ext : module.vce_triple()->getExtensions()) {
18888d5c4c2SKareemErgawy-TomTom     extName.clear();
1893ed47bccSLei Zhang     spirv::encodeStringLiteralInto(extName, spirv::stringifyExtension(ext));
1903ed47bccSLei Zhang     encodeInstructionInto(extensions, spirv::Opcode::OpExtension, extName);
19188d5c4c2SKareemErgawy-TomTom   }
19288d5c4c2SKareemErgawy-TomTom }
19388d5c4c2SKareemErgawy-TomTom 
processMemoryModel()19488d5c4c2SKareemErgawy-TomTom void Serializer::processMemoryModel() {
19588d5c4c2SKareemErgawy-TomTom   uint32_t mm = module->getAttrOfType<IntegerAttr>("memory_model").getInt();
19688d5c4c2SKareemErgawy-TomTom   uint32_t am = module->getAttrOfType<IntegerAttr>("addressing_model").getInt();
19788d5c4c2SKareemErgawy-TomTom 
1983ed47bccSLei Zhang   encodeInstructionInto(memoryModel, spirv::Opcode::OpMemoryModel, {am, mm});
19988d5c4c2SKareemErgawy-TomTom }
20088d5c4c2SKareemErgawy-TomTom 
processDecoration(Location loc,uint32_t resultID,NamedAttribute attr)20188d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processDecoration(Location loc, uint32_t resultID,
20288d5c4c2SKareemErgawy-TomTom                                             NamedAttribute attr) {
2030c7890c8SRiver Riddle   auto attrName = attr.getName().strref();
20488d5c4c2SKareemErgawy-TomTom   auto decorationName = llvm::convertToCamelFromSnakeCase(attrName, true);
20588d5c4c2SKareemErgawy-TomTom   auto decoration = spirv::symbolizeDecoration(decorationName);
20688d5c4c2SKareemErgawy-TomTom   if (!decoration) {
20788d5c4c2SKareemErgawy-TomTom     return emitError(
20888d5c4c2SKareemErgawy-TomTom                loc, "non-argument attributes expected to have snake-case-ified "
20988d5c4c2SKareemErgawy-TomTom                     "decoration name, unhandled attribute with name : ")
21088d5c4c2SKareemErgawy-TomTom            << attrName;
21188d5c4c2SKareemErgawy-TomTom   }
21288d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 1> args;
213*6d5fc1e3SKazu Hirata   switch (*decoration) {
21488d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::Binding:
21588d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::DescriptorSet:
21688d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::Location:
2170c7890c8SRiver Riddle     if (auto intAttr = attr.getValue().dyn_cast<IntegerAttr>()) {
21888d5c4c2SKareemErgawy-TomTom       args.push_back(intAttr.getValue().getZExtValue());
21988d5c4c2SKareemErgawy-TomTom       break;
22088d5c4c2SKareemErgawy-TomTom     }
22188d5c4c2SKareemErgawy-TomTom     return emitError(loc, "expected integer attribute for ") << attrName;
22288d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::BuiltIn:
2230c7890c8SRiver Riddle     if (auto strAttr = attr.getValue().dyn_cast<StringAttr>()) {
22488d5c4c2SKareemErgawy-TomTom       auto enumVal = spirv::symbolizeBuiltIn(strAttr.getValue());
22588d5c4c2SKareemErgawy-TomTom       if (enumVal) {
226*6d5fc1e3SKazu Hirata         args.push_back(static_cast<uint32_t>(*enumVal));
22788d5c4c2SKareemErgawy-TomTom         break;
22888d5c4c2SKareemErgawy-TomTom       }
22988d5c4c2SKareemErgawy-TomTom       return emitError(loc, "invalid ")
23088d5c4c2SKareemErgawy-TomTom              << attrName << " attribute " << strAttr.getValue();
23188d5c4c2SKareemErgawy-TomTom     }
23288d5c4c2SKareemErgawy-TomTom     return emitError(loc, "expected string attribute for ") << attrName;
23388d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::Aliased:
23488d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::Flat:
23588d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::NonReadable:
23688d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::NonWritable:
23788d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::NoPerspective:
23888d5c4c2SKareemErgawy-TomTom   case spirv::Decoration::Restrict:
2391e4cfe5eSWeiwei Li   case spirv::Decoration::RelaxedPrecision:
24088d5c4c2SKareemErgawy-TomTom     // For unit attributes, the args list has no values so we do nothing
2410c7890c8SRiver Riddle     if (auto unitAttr = attr.getValue().dyn_cast<UnitAttr>())
24288d5c4c2SKareemErgawy-TomTom       break;
24388d5c4c2SKareemErgawy-TomTom     return emitError(loc, "expected unit attribute for ") << attrName;
24488d5c4c2SKareemErgawy-TomTom   default:
24588d5c4c2SKareemErgawy-TomTom     return emitError(loc, "unhandled decoration ") << decorationName;
24688d5c4c2SKareemErgawy-TomTom   }
247*6d5fc1e3SKazu Hirata   return emitDecoration(resultID, *decoration, args);
24888d5c4c2SKareemErgawy-TomTom }
24988d5c4c2SKareemErgawy-TomTom 
processName(uint32_t resultID,StringRef name)25088d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processName(uint32_t resultID, StringRef name) {
25188d5c4c2SKareemErgawy-TomTom   assert(!name.empty() && "unexpected empty string for OpName");
252b289266cSLei Zhang   if (!options.emitSymbolName)
253b289266cSLei Zhang     return success();
25488d5c4c2SKareemErgawy-TomTom 
25588d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 4> nameOperands;
25688d5c4c2SKareemErgawy-TomTom   nameOperands.push_back(resultID);
2573ed47bccSLei Zhang   spirv::encodeStringLiteralInto(nameOperands, name);
2583ed47bccSLei Zhang   encodeInstructionInto(names, spirv::Opcode::OpName, nameOperands);
2593ed47bccSLei Zhang   return success();
26088d5c4c2SKareemErgawy-TomTom }
26188d5c4c2SKareemErgawy-TomTom 
26288d5c4c2SKareemErgawy-TomTom template <>
processTypeDecoration(Location loc,spirv::ArrayType type,uint32_t resultID)26388d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processTypeDecoration<spirv::ArrayType>(
26488d5c4c2SKareemErgawy-TomTom     Location loc, spirv::ArrayType type, uint32_t resultID) {
26588d5c4c2SKareemErgawy-TomTom   if (unsigned stride = type.getArrayStride()) {
26688d5c4c2SKareemErgawy-TomTom     // OpDecorate %arrayTypeSSA ArrayStride strideLiteral
26788d5c4c2SKareemErgawy-TomTom     return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
26888d5c4c2SKareemErgawy-TomTom   }
26988d5c4c2SKareemErgawy-TomTom   return success();
27088d5c4c2SKareemErgawy-TomTom }
27188d5c4c2SKareemErgawy-TomTom 
27288d5c4c2SKareemErgawy-TomTom template <>
processTypeDecoration(Location loc,spirv::RuntimeArrayType type,uint32_t resultID)27388d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processTypeDecoration<spirv::RuntimeArrayType>(
27488d5c4c2SKareemErgawy-TomTom     Location loc, spirv::RuntimeArrayType type, uint32_t resultID) {
27588d5c4c2SKareemErgawy-TomTom   if (unsigned stride = type.getArrayStride()) {
27688d5c4c2SKareemErgawy-TomTom     // OpDecorate %arrayTypeSSA ArrayStride strideLiteral
27788d5c4c2SKareemErgawy-TomTom     return emitDecoration(resultID, spirv::Decoration::ArrayStride, {stride});
27888d5c4c2SKareemErgawy-TomTom   }
27988d5c4c2SKareemErgawy-TomTom   return success();
28088d5c4c2SKareemErgawy-TomTom }
28188d5c4c2SKareemErgawy-TomTom 
processMemberDecoration(uint32_t structID,const spirv::StructType::MemberDecorationInfo & memberDecoration)28288d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processMemberDecoration(
28388d5c4c2SKareemErgawy-TomTom     uint32_t structID,
28488d5c4c2SKareemErgawy-TomTom     const spirv::StructType::MemberDecorationInfo &memberDecoration) {
28588d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 4> args(
28688d5c4c2SKareemErgawy-TomTom       {structID, memberDecoration.memberIndex,
28788d5c4c2SKareemErgawy-TomTom        static_cast<uint32_t>(memberDecoration.decoration)});
28888d5c4c2SKareemErgawy-TomTom   if (memberDecoration.hasValue) {
28988d5c4c2SKareemErgawy-TomTom     args.push_back(memberDecoration.decorationValue);
29088d5c4c2SKareemErgawy-TomTom   }
2913ed47bccSLei Zhang   encodeInstructionInto(decorations, spirv::Opcode::OpMemberDecorate, args);
2923ed47bccSLei Zhang   return success();
29388d5c4c2SKareemErgawy-TomTom }
29488d5c4c2SKareemErgawy-TomTom 
29588d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
29688d5c4c2SKareemErgawy-TomTom // Type
29788d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
29888d5c4c2SKareemErgawy-TomTom 
29988d5c4c2SKareemErgawy-TomTom // According to the SPIR-V spec "Validation Rules for Shader Capabilities":
30088d5c4c2SKareemErgawy-TomTom // "Composite objects in the StorageBuffer, PhysicalStorageBuffer, Uniform, and
30188d5c4c2SKareemErgawy-TomTom // PushConstant Storage Classes must be explicitly laid out."
isInterfaceStructPtrType(Type type) const30288d5c4c2SKareemErgawy-TomTom bool Serializer::isInterfaceStructPtrType(Type type) const {
30388d5c4c2SKareemErgawy-TomTom   if (auto ptrType = type.dyn_cast<spirv::PointerType>()) {
30488d5c4c2SKareemErgawy-TomTom     switch (ptrType.getStorageClass()) {
30588d5c4c2SKareemErgawy-TomTom     case spirv::StorageClass::PhysicalStorageBuffer:
30688d5c4c2SKareemErgawy-TomTom     case spirv::StorageClass::PushConstant:
30788d5c4c2SKareemErgawy-TomTom     case spirv::StorageClass::StorageBuffer:
30888d5c4c2SKareemErgawy-TomTom     case spirv::StorageClass::Uniform:
30988d5c4c2SKareemErgawy-TomTom       return ptrType.getPointeeType().isa<spirv::StructType>();
31088d5c4c2SKareemErgawy-TomTom     default:
31188d5c4c2SKareemErgawy-TomTom       break;
31288d5c4c2SKareemErgawy-TomTom     }
31388d5c4c2SKareemErgawy-TomTom   }
31488d5c4c2SKareemErgawy-TomTom   return false;
31588d5c4c2SKareemErgawy-TomTom }
31688d5c4c2SKareemErgawy-TomTom 
processType(Location loc,Type type,uint32_t & typeID)31788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processType(Location loc, Type type,
31888d5c4c2SKareemErgawy-TomTom                                       uint32_t &typeID) {
31988d5c4c2SKareemErgawy-TomTom   // Maintains a set of names for nested identified struct types. This is used
32088d5c4c2SKareemErgawy-TomTom   // to properly serialize recursive references.
3214efb7754SRiver Riddle   SetVector<StringRef> serializationCtx;
32288d5c4c2SKareemErgawy-TomTom   return processTypeImpl(loc, type, typeID, serializationCtx);
32388d5c4c2SKareemErgawy-TomTom }
32488d5c4c2SKareemErgawy-TomTom 
32588d5c4c2SKareemErgawy-TomTom LogicalResult
processTypeImpl(Location loc,Type type,uint32_t & typeID,SetVector<StringRef> & serializationCtx)32688d5c4c2SKareemErgawy-TomTom Serializer::processTypeImpl(Location loc, Type type, uint32_t &typeID,
3274efb7754SRiver Riddle                             SetVector<StringRef> &serializationCtx) {
32888d5c4c2SKareemErgawy-TomTom   typeID = getTypeID(type);
329222d7fc7SLei Zhang   if (typeID)
33088d5c4c2SKareemErgawy-TomTom     return success();
331222d7fc7SLei Zhang 
33288d5c4c2SKareemErgawy-TomTom   typeID = getNextID();
33388d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 4> operands;
33488d5c4c2SKareemErgawy-TomTom 
33588d5c4c2SKareemErgawy-TomTom   operands.push_back(typeID);
33688d5c4c2SKareemErgawy-TomTom   auto typeEnum = spirv::Opcode::OpTypeVoid;
33788d5c4c2SKareemErgawy-TomTom   bool deferSerialization = false;
33888d5c4c2SKareemErgawy-TomTom 
33988d5c4c2SKareemErgawy-TomTom   if ((type.isa<FunctionType>() &&
34088d5c4c2SKareemErgawy-TomTom        succeeded(prepareFunctionType(loc, type.cast<FunctionType>(), typeEnum,
34188d5c4c2SKareemErgawy-TomTom                                      operands))) ||
34288d5c4c2SKareemErgawy-TomTom       succeeded(prepareBasicType(loc, type, typeID, typeEnum, operands,
34388d5c4c2SKareemErgawy-TomTom                                  deferSerialization, serializationCtx))) {
34488d5c4c2SKareemErgawy-TomTom     if (deferSerialization)
34588d5c4c2SKareemErgawy-TomTom       return success();
34688d5c4c2SKareemErgawy-TomTom 
34788d5c4c2SKareemErgawy-TomTom     typeIDMap[type] = typeID;
34888d5c4c2SKareemErgawy-TomTom 
3493ed47bccSLei Zhang     encodeInstructionInto(typesGlobalValues, typeEnum, operands);
35088d5c4c2SKareemErgawy-TomTom 
35188d5c4c2SKareemErgawy-TomTom     if (recursiveStructInfos.count(type) != 0) {
35288d5c4c2SKareemErgawy-TomTom       // This recursive struct type is emitted already, now the OpTypePointer
35388d5c4c2SKareemErgawy-TomTom       // instructions referring to recursive references are emitted as well.
35488d5c4c2SKareemErgawy-TomTom       for (auto &ptrInfo : recursiveStructInfos[type]) {
35588d5c4c2SKareemErgawy-TomTom         // TODO: This might not work if more than 1 recursive reference is
35688d5c4c2SKareemErgawy-TomTom         // present in the struct.
35788d5c4c2SKareemErgawy-TomTom         SmallVector<uint32_t, 4> ptrOperands;
35888d5c4c2SKareemErgawy-TomTom         ptrOperands.push_back(ptrInfo.pointerTypeID);
35988d5c4c2SKareemErgawy-TomTom         ptrOperands.push_back(static_cast<uint32_t>(ptrInfo.storageClass));
36088d5c4c2SKareemErgawy-TomTom         ptrOperands.push_back(typeIDMap[type]);
36188d5c4c2SKareemErgawy-TomTom 
3623ed47bccSLei Zhang         encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpTypePointer,
3633ed47bccSLei Zhang                               ptrOperands);
36488d5c4c2SKareemErgawy-TomTom       }
36588d5c4c2SKareemErgawy-TomTom 
36688d5c4c2SKareemErgawy-TomTom       recursiveStructInfos[type].clear();
36788d5c4c2SKareemErgawy-TomTom     }
36888d5c4c2SKareemErgawy-TomTom 
36988d5c4c2SKareemErgawy-TomTom     return success();
37088d5c4c2SKareemErgawy-TomTom   }
37188d5c4c2SKareemErgawy-TomTom 
37288d5c4c2SKareemErgawy-TomTom   return failure();
37388d5c4c2SKareemErgawy-TomTom }
37488d5c4c2SKareemErgawy-TomTom 
prepareBasicType(Location loc,Type type,uint32_t resultID,spirv::Opcode & typeEnum,SmallVectorImpl<uint32_t> & operands,bool & deferSerialization,SetVector<StringRef> & serializationCtx)37588d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::prepareBasicType(
37688d5c4c2SKareemErgawy-TomTom     Location loc, Type type, uint32_t resultID, spirv::Opcode &typeEnum,
37788d5c4c2SKareemErgawy-TomTom     SmallVectorImpl<uint32_t> &operands, bool &deferSerialization,
3784efb7754SRiver Riddle     SetVector<StringRef> &serializationCtx) {
37988d5c4c2SKareemErgawy-TomTom   deferSerialization = false;
38088d5c4c2SKareemErgawy-TomTom 
38188d5c4c2SKareemErgawy-TomTom   if (isVoidType(type)) {
38288d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeVoid;
38388d5c4c2SKareemErgawy-TomTom     return success();
38488d5c4c2SKareemErgawy-TomTom   }
38588d5c4c2SKareemErgawy-TomTom 
38688d5c4c2SKareemErgawy-TomTom   if (auto intType = type.dyn_cast<IntegerType>()) {
38788d5c4c2SKareemErgawy-TomTom     if (intType.getWidth() == 1) {
38888d5c4c2SKareemErgawy-TomTom       typeEnum = spirv::Opcode::OpTypeBool;
38988d5c4c2SKareemErgawy-TomTom       return success();
39088d5c4c2SKareemErgawy-TomTom     }
39188d5c4c2SKareemErgawy-TomTom 
39288d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeInt;
39388d5c4c2SKareemErgawy-TomTom     operands.push_back(intType.getWidth());
39488d5c4c2SKareemErgawy-TomTom     // SPIR-V OpTypeInt "Signedness specifies whether there are signed semantics
39588d5c4c2SKareemErgawy-TomTom     // to preserve or validate.
39688d5c4c2SKareemErgawy-TomTom     // 0 indicates unsigned, or no signedness semantics
39788d5c4c2SKareemErgawy-TomTom     // 1 indicates signed semantics."
39888d5c4c2SKareemErgawy-TomTom     operands.push_back(intType.isSigned() ? 1 : 0);
39988d5c4c2SKareemErgawy-TomTom     return success();
40088d5c4c2SKareemErgawy-TomTom   }
40188d5c4c2SKareemErgawy-TomTom 
40288d5c4c2SKareemErgawy-TomTom   if (auto floatType = type.dyn_cast<FloatType>()) {
40388d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeFloat;
40488d5c4c2SKareemErgawy-TomTom     operands.push_back(floatType.getWidth());
40588d5c4c2SKareemErgawy-TomTom     return success();
40688d5c4c2SKareemErgawy-TomTom   }
40788d5c4c2SKareemErgawy-TomTom 
40888d5c4c2SKareemErgawy-TomTom   if (auto vectorType = type.dyn_cast<VectorType>()) {
40988d5c4c2SKareemErgawy-TomTom     uint32_t elementTypeID = 0;
41088d5c4c2SKareemErgawy-TomTom     if (failed(processTypeImpl(loc, vectorType.getElementType(), elementTypeID,
41188d5c4c2SKareemErgawy-TomTom                                serializationCtx))) {
41288d5c4c2SKareemErgawy-TomTom       return failure();
41388d5c4c2SKareemErgawy-TomTom     }
41488d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeVector;
41588d5c4c2SKareemErgawy-TomTom     operands.push_back(elementTypeID);
41688d5c4c2SKareemErgawy-TomTom     operands.push_back(vectorType.getNumElements());
41788d5c4c2SKareemErgawy-TomTom     return success();
41888d5c4c2SKareemErgawy-TomTom   }
41988d5c4c2SKareemErgawy-TomTom 
42088d5c4c2SKareemErgawy-TomTom   if (auto imageType = type.dyn_cast<spirv::ImageType>()) {
42188d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeImage;
42288d5c4c2SKareemErgawy-TomTom     uint32_t sampledTypeID = 0;
42388d5c4c2SKareemErgawy-TomTom     if (failed(processType(loc, imageType.getElementType(), sampledTypeID)))
42488d5c4c2SKareemErgawy-TomTom       return failure();
42588d5c4c2SKareemErgawy-TomTom 
42688d5c4c2SKareemErgawy-TomTom     operands.push_back(sampledTypeID);
42788d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(imageType.getDim()));
42888d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(imageType.getDepthInfo()));
42988d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(imageType.getArrayedInfo()));
43088d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(imageType.getSamplingInfo()));
43188d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(imageType.getSamplerUseInfo()));
43288d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(imageType.getImageFormat()));
43388d5c4c2SKareemErgawy-TomTom     return success();
43488d5c4c2SKareemErgawy-TomTom   }
43588d5c4c2SKareemErgawy-TomTom 
43688d5c4c2SKareemErgawy-TomTom   if (auto arrayType = type.dyn_cast<spirv::ArrayType>()) {
43788d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeArray;
43888d5c4c2SKareemErgawy-TomTom     uint32_t elementTypeID = 0;
43988d5c4c2SKareemErgawy-TomTom     if (failed(processTypeImpl(loc, arrayType.getElementType(), elementTypeID,
44088d5c4c2SKareemErgawy-TomTom                                serializationCtx))) {
44188d5c4c2SKareemErgawy-TomTom       return failure();
44288d5c4c2SKareemErgawy-TomTom     }
44388d5c4c2SKareemErgawy-TomTom     operands.push_back(elementTypeID);
44488d5c4c2SKareemErgawy-TomTom     if (auto elementCountID = prepareConstantInt(
44588d5c4c2SKareemErgawy-TomTom             loc, mlirBuilder.getI32IntegerAttr(arrayType.getNumElements()))) {
44688d5c4c2SKareemErgawy-TomTom       operands.push_back(elementCountID);
44788d5c4c2SKareemErgawy-TomTom     }
44888d5c4c2SKareemErgawy-TomTom     return processTypeDecoration(loc, arrayType, resultID);
44988d5c4c2SKareemErgawy-TomTom   }
45088d5c4c2SKareemErgawy-TomTom 
45188d5c4c2SKareemErgawy-TomTom   if (auto ptrType = type.dyn_cast<spirv::PointerType>()) {
45288d5c4c2SKareemErgawy-TomTom     uint32_t pointeeTypeID = 0;
45388d5c4c2SKareemErgawy-TomTom     spirv::StructType pointeeStruct =
45488d5c4c2SKareemErgawy-TomTom         ptrType.getPointeeType().dyn_cast<spirv::StructType>();
45588d5c4c2SKareemErgawy-TomTom 
45688d5c4c2SKareemErgawy-TomTom     if (pointeeStruct && pointeeStruct.isIdentified() &&
45788d5c4c2SKareemErgawy-TomTom         serializationCtx.count(pointeeStruct.getIdentifier()) != 0) {
45888d5c4c2SKareemErgawy-TomTom       // A recursive reference to an enclosing struct is found.
45988d5c4c2SKareemErgawy-TomTom       //
46088d5c4c2SKareemErgawy-TomTom       // 1. Prepare an OpTypeForwardPointer with resultID and the ptr storage
46188d5c4c2SKareemErgawy-TomTom       // class as operands.
46288d5c4c2SKareemErgawy-TomTom       SmallVector<uint32_t, 2> forwardPtrOperands;
46388d5c4c2SKareemErgawy-TomTom       forwardPtrOperands.push_back(resultID);
46488d5c4c2SKareemErgawy-TomTom       forwardPtrOperands.push_back(
46588d5c4c2SKareemErgawy-TomTom           static_cast<uint32_t>(ptrType.getStorageClass()));
46688d5c4c2SKareemErgawy-TomTom 
4673ed47bccSLei Zhang       encodeInstructionInto(typesGlobalValues,
46888d5c4c2SKareemErgawy-TomTom                             spirv::Opcode::OpTypeForwardPointer,
46988d5c4c2SKareemErgawy-TomTom                             forwardPtrOperands);
47088d5c4c2SKareemErgawy-TomTom 
47188d5c4c2SKareemErgawy-TomTom       // 2. Find the pointee (enclosing) struct.
47288d5c4c2SKareemErgawy-TomTom       auto structType = spirv::StructType::getIdentified(
47388d5c4c2SKareemErgawy-TomTom           module.getContext(), pointeeStruct.getIdentifier());
47488d5c4c2SKareemErgawy-TomTom 
47588d5c4c2SKareemErgawy-TomTom       if (!structType)
47688d5c4c2SKareemErgawy-TomTom         return failure();
47788d5c4c2SKareemErgawy-TomTom 
47888d5c4c2SKareemErgawy-TomTom       // 3. Mark the OpTypePointer that is supposed to be emitted by this call
47988d5c4c2SKareemErgawy-TomTom       // as deferred.
48088d5c4c2SKareemErgawy-TomTom       deferSerialization = true;
48188d5c4c2SKareemErgawy-TomTom 
48288d5c4c2SKareemErgawy-TomTom       // 4. Record the info needed to emit the deferred OpTypePointer
48388d5c4c2SKareemErgawy-TomTom       // instruction when the enclosing struct is completely serialized.
48488d5c4c2SKareemErgawy-TomTom       recursiveStructInfos[structType].push_back(
48588d5c4c2SKareemErgawy-TomTom           {resultID, ptrType.getStorageClass()});
48688d5c4c2SKareemErgawy-TomTom     } else {
48788d5c4c2SKareemErgawy-TomTom       if (failed(processTypeImpl(loc, ptrType.getPointeeType(), pointeeTypeID,
48888d5c4c2SKareemErgawy-TomTom                                  serializationCtx)))
48988d5c4c2SKareemErgawy-TomTom         return failure();
49088d5c4c2SKareemErgawy-TomTom     }
49188d5c4c2SKareemErgawy-TomTom 
49288d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypePointer;
49388d5c4c2SKareemErgawy-TomTom     operands.push_back(static_cast<uint32_t>(ptrType.getStorageClass()));
49488d5c4c2SKareemErgawy-TomTom     operands.push_back(pointeeTypeID);
495222d7fc7SLei Zhang 
496222d7fc7SLei Zhang     if (isInterfaceStructPtrType(ptrType)) {
497222d7fc7SLei Zhang       if (failed(emitDecoration(getTypeID(pointeeStruct),
498222d7fc7SLei Zhang                                 spirv::Decoration::Block)))
499222d7fc7SLei Zhang         return emitError(loc, "cannot decorate ")
500222d7fc7SLei Zhang                << pointeeStruct << " with Block decoration";
501222d7fc7SLei Zhang     }
502222d7fc7SLei Zhang 
50388d5c4c2SKareemErgawy-TomTom     return success();
50488d5c4c2SKareemErgawy-TomTom   }
50588d5c4c2SKareemErgawy-TomTom 
50688d5c4c2SKareemErgawy-TomTom   if (auto runtimeArrayType = type.dyn_cast<spirv::RuntimeArrayType>()) {
50788d5c4c2SKareemErgawy-TomTom     uint32_t elementTypeID = 0;
50888d5c4c2SKareemErgawy-TomTom     if (failed(processTypeImpl(loc, runtimeArrayType.getElementType(),
50988d5c4c2SKareemErgawy-TomTom                                elementTypeID, serializationCtx))) {
51088d5c4c2SKareemErgawy-TomTom       return failure();
51188d5c4c2SKareemErgawy-TomTom     }
51288d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeRuntimeArray;
51388d5c4c2SKareemErgawy-TomTom     operands.push_back(elementTypeID);
51488d5c4c2SKareemErgawy-TomTom     return processTypeDecoration(loc, runtimeArrayType, resultID);
51588d5c4c2SKareemErgawy-TomTom   }
51688d5c4c2SKareemErgawy-TomTom 
5172ef24139SWeiwei Li   if (auto sampledImageType = type.dyn_cast<spirv::SampledImageType>()) {
5182ef24139SWeiwei Li     typeEnum = spirv::Opcode::OpTypeSampledImage;
5192ef24139SWeiwei Li     uint32_t imageTypeID = 0;
5202ef24139SWeiwei Li     if (failed(
5212ef24139SWeiwei Li             processType(loc, sampledImageType.getImageType(), imageTypeID))) {
5222ef24139SWeiwei Li       return failure();
5232ef24139SWeiwei Li     }
5242ef24139SWeiwei Li     operands.push_back(imageTypeID);
5252ef24139SWeiwei Li     return success();
5262ef24139SWeiwei Li   }
5272ef24139SWeiwei Li 
52888d5c4c2SKareemErgawy-TomTom   if (auto structType = type.dyn_cast<spirv::StructType>()) {
52988d5c4c2SKareemErgawy-TomTom     if (structType.isIdentified()) {
5303ed47bccSLei Zhang       if (failed(processName(resultID, structType.getIdentifier())))
5313ed47bccSLei Zhang         return failure();
53288d5c4c2SKareemErgawy-TomTom       serializationCtx.insert(structType.getIdentifier());
53388d5c4c2SKareemErgawy-TomTom     }
53488d5c4c2SKareemErgawy-TomTom 
53588d5c4c2SKareemErgawy-TomTom     bool hasOffset = structType.hasOffset();
53688d5c4c2SKareemErgawy-TomTom     for (auto elementIndex :
53788d5c4c2SKareemErgawy-TomTom          llvm::seq<uint32_t>(0, structType.getNumElements())) {
53888d5c4c2SKareemErgawy-TomTom       uint32_t elementTypeID = 0;
53988d5c4c2SKareemErgawy-TomTom       if (failed(processTypeImpl(loc, structType.getElementType(elementIndex),
54088d5c4c2SKareemErgawy-TomTom                                  elementTypeID, serializationCtx))) {
54188d5c4c2SKareemErgawy-TomTom         return failure();
54288d5c4c2SKareemErgawy-TomTom       }
54388d5c4c2SKareemErgawy-TomTom       operands.push_back(elementTypeID);
54488d5c4c2SKareemErgawy-TomTom       if (hasOffset) {
54588d5c4c2SKareemErgawy-TomTom         // Decorate each struct member with an offset
54688d5c4c2SKareemErgawy-TomTom         spirv::StructType::MemberDecorationInfo offsetDecoration{
54788d5c4c2SKareemErgawy-TomTom             elementIndex, /*hasValue=*/1, spirv::Decoration::Offset,
54888d5c4c2SKareemErgawy-TomTom             static_cast<uint32_t>(structType.getMemberOffset(elementIndex))};
54988d5c4c2SKareemErgawy-TomTom         if (failed(processMemberDecoration(resultID, offsetDecoration))) {
55088d5c4c2SKareemErgawy-TomTom           return emitError(loc, "cannot decorate ")
55188d5c4c2SKareemErgawy-TomTom                  << elementIndex << "-th member of " << structType
55288d5c4c2SKareemErgawy-TomTom                  << " with its offset";
55388d5c4c2SKareemErgawy-TomTom         }
55488d5c4c2SKareemErgawy-TomTom       }
55588d5c4c2SKareemErgawy-TomTom     }
55688d5c4c2SKareemErgawy-TomTom     SmallVector<spirv::StructType::MemberDecorationInfo, 4> memberDecorations;
55788d5c4c2SKareemErgawy-TomTom     structType.getMemberDecorations(memberDecorations);
55888d5c4c2SKareemErgawy-TomTom 
55988d5c4c2SKareemErgawy-TomTom     for (auto &memberDecoration : memberDecorations) {
56088d5c4c2SKareemErgawy-TomTom       if (failed(processMemberDecoration(resultID, memberDecoration))) {
56188d5c4c2SKareemErgawy-TomTom         return emitError(loc, "cannot decorate ")
56288d5c4c2SKareemErgawy-TomTom                << static_cast<uint32_t>(memberDecoration.memberIndex)
56388d5c4c2SKareemErgawy-TomTom                << "-th member of " << structType << " with "
56488d5c4c2SKareemErgawy-TomTom                << stringifyDecoration(memberDecoration.decoration);
56588d5c4c2SKareemErgawy-TomTom       }
56688d5c4c2SKareemErgawy-TomTom     }
56788d5c4c2SKareemErgawy-TomTom 
56888d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeStruct;
56988d5c4c2SKareemErgawy-TomTom 
57088d5c4c2SKareemErgawy-TomTom     if (structType.isIdentified())
57188d5c4c2SKareemErgawy-TomTom       serializationCtx.remove(structType.getIdentifier());
57288d5c4c2SKareemErgawy-TomTom 
57388d5c4c2SKareemErgawy-TomTom     return success();
57488d5c4c2SKareemErgawy-TomTom   }
57588d5c4c2SKareemErgawy-TomTom 
57688d5c4c2SKareemErgawy-TomTom   if (auto cooperativeMatrixType =
57788d5c4c2SKareemErgawy-TomTom           type.dyn_cast<spirv::CooperativeMatrixNVType>()) {
57888d5c4c2SKareemErgawy-TomTom     uint32_t elementTypeID = 0;
57988d5c4c2SKareemErgawy-TomTom     if (failed(processTypeImpl(loc, cooperativeMatrixType.getElementType(),
58088d5c4c2SKareemErgawy-TomTom                                elementTypeID, serializationCtx))) {
58188d5c4c2SKareemErgawy-TomTom       return failure();
58288d5c4c2SKareemErgawy-TomTom     }
58388d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeCooperativeMatrixNV;
58488d5c4c2SKareemErgawy-TomTom     auto getConstantOp = [&](uint32_t id) {
58588d5c4c2SKareemErgawy-TomTom       auto attr = IntegerAttr::get(IntegerType::get(type.getContext(), 32), id);
58688d5c4c2SKareemErgawy-TomTom       return prepareConstantInt(loc, attr);
58788d5c4c2SKareemErgawy-TomTom     };
58888d5c4c2SKareemErgawy-TomTom     operands.push_back(elementTypeID);
58988d5c4c2SKareemErgawy-TomTom     operands.push_back(
59088d5c4c2SKareemErgawy-TomTom         getConstantOp(static_cast<uint32_t>(cooperativeMatrixType.getScope())));
59188d5c4c2SKareemErgawy-TomTom     operands.push_back(getConstantOp(cooperativeMatrixType.getRows()));
59288d5c4c2SKareemErgawy-TomTom     operands.push_back(getConstantOp(cooperativeMatrixType.getColumns()));
59388d5c4c2SKareemErgawy-TomTom     return success();
59488d5c4c2SKareemErgawy-TomTom   }
59588d5c4c2SKareemErgawy-TomTom 
59688d5c4c2SKareemErgawy-TomTom   if (auto matrixType = type.dyn_cast<spirv::MatrixType>()) {
59788d5c4c2SKareemErgawy-TomTom     uint32_t elementTypeID = 0;
59888d5c4c2SKareemErgawy-TomTom     if (failed(processTypeImpl(loc, matrixType.getColumnType(), elementTypeID,
59988d5c4c2SKareemErgawy-TomTom                                serializationCtx))) {
60088d5c4c2SKareemErgawy-TomTom       return failure();
60188d5c4c2SKareemErgawy-TomTom     }
60288d5c4c2SKareemErgawy-TomTom     typeEnum = spirv::Opcode::OpTypeMatrix;
60388d5c4c2SKareemErgawy-TomTom     operands.push_back(elementTypeID);
60488d5c4c2SKareemErgawy-TomTom     operands.push_back(matrixType.getNumColumns());
60588d5c4c2SKareemErgawy-TomTom     return success();
60688d5c4c2SKareemErgawy-TomTom   }
60788d5c4c2SKareemErgawy-TomTom 
60888d5c4c2SKareemErgawy-TomTom   // TODO: Handle other types.
60988d5c4c2SKareemErgawy-TomTom   return emitError(loc, "unhandled type in serialization: ") << type;
61088d5c4c2SKareemErgawy-TomTom }
61188d5c4c2SKareemErgawy-TomTom 
61288d5c4c2SKareemErgawy-TomTom LogicalResult
prepareFunctionType(Location loc,FunctionType type,spirv::Opcode & typeEnum,SmallVectorImpl<uint32_t> & operands)61388d5c4c2SKareemErgawy-TomTom Serializer::prepareFunctionType(Location loc, FunctionType type,
61488d5c4c2SKareemErgawy-TomTom                                 spirv::Opcode &typeEnum,
61588d5c4c2SKareemErgawy-TomTom                                 SmallVectorImpl<uint32_t> &operands) {
61688d5c4c2SKareemErgawy-TomTom   typeEnum = spirv::Opcode::OpTypeFunction;
61788d5c4c2SKareemErgawy-TomTom   assert(type.getNumResults() <= 1 &&
61888d5c4c2SKareemErgawy-TomTom          "serialization supports only a single return value");
61988d5c4c2SKareemErgawy-TomTom   uint32_t resultID = 0;
62088d5c4c2SKareemErgawy-TomTom   if (failed(processType(
62188d5c4c2SKareemErgawy-TomTom           loc, type.getNumResults() == 1 ? type.getResult(0) : getVoidType(),
62288d5c4c2SKareemErgawy-TomTom           resultID))) {
62388d5c4c2SKareemErgawy-TomTom     return failure();
62488d5c4c2SKareemErgawy-TomTom   }
62588d5c4c2SKareemErgawy-TomTom   operands.push_back(resultID);
62688d5c4c2SKareemErgawy-TomTom   for (auto &res : type.getInputs()) {
62788d5c4c2SKareemErgawy-TomTom     uint32_t argTypeID = 0;
62888d5c4c2SKareemErgawy-TomTom     if (failed(processType(loc, res, argTypeID))) {
62988d5c4c2SKareemErgawy-TomTom       return failure();
63088d5c4c2SKareemErgawy-TomTom     }
63188d5c4c2SKareemErgawy-TomTom     operands.push_back(argTypeID);
63288d5c4c2SKareemErgawy-TomTom   }
63388d5c4c2SKareemErgawy-TomTom   return success();
63488d5c4c2SKareemErgawy-TomTom }
63588d5c4c2SKareemErgawy-TomTom 
63688d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
63788d5c4c2SKareemErgawy-TomTom // Constant
63888d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
63988d5c4c2SKareemErgawy-TomTom 
prepareConstant(Location loc,Type constType,Attribute valueAttr)64088d5c4c2SKareemErgawy-TomTom uint32_t Serializer::prepareConstant(Location loc, Type constType,
64188d5c4c2SKareemErgawy-TomTom                                      Attribute valueAttr) {
64288d5c4c2SKareemErgawy-TomTom   if (auto id = prepareConstantScalar(loc, valueAttr)) {
64388d5c4c2SKareemErgawy-TomTom     return id;
64488d5c4c2SKareemErgawy-TomTom   }
64588d5c4c2SKareemErgawy-TomTom 
64688d5c4c2SKareemErgawy-TomTom   // This is a composite literal. We need to handle each component separately
64788d5c4c2SKareemErgawy-TomTom   // and then emit an OpConstantComposite for the whole.
64888d5c4c2SKareemErgawy-TomTom 
64988d5c4c2SKareemErgawy-TomTom   if (auto id = getConstantID(valueAttr)) {
65088d5c4c2SKareemErgawy-TomTom     return id;
65188d5c4c2SKareemErgawy-TomTom   }
65288d5c4c2SKareemErgawy-TomTom 
65388d5c4c2SKareemErgawy-TomTom   uint32_t typeID = 0;
65488d5c4c2SKareemErgawy-TomTom   if (failed(processType(loc, constType, typeID))) {
65588d5c4c2SKareemErgawy-TomTom     return 0;
65688d5c4c2SKareemErgawy-TomTom   }
65788d5c4c2SKareemErgawy-TomTom 
65888d5c4c2SKareemErgawy-TomTom   uint32_t resultID = 0;
65988d5c4c2SKareemErgawy-TomTom   if (auto attr = valueAttr.dyn_cast<DenseElementsAttr>()) {
66088d5c4c2SKareemErgawy-TomTom     int rank = attr.getType().dyn_cast<ShapedType>().getRank();
66188d5c4c2SKareemErgawy-TomTom     SmallVector<uint64_t, 4> index(rank);
66288d5c4c2SKareemErgawy-TomTom     resultID = prepareDenseElementsConstant(loc, constType, attr,
66388d5c4c2SKareemErgawy-TomTom                                             /*dim=*/0, index);
66488d5c4c2SKareemErgawy-TomTom   } else if (auto arrayAttr = valueAttr.dyn_cast<ArrayAttr>()) {
66588d5c4c2SKareemErgawy-TomTom     resultID = prepareArrayConstant(loc, constType, arrayAttr);
66688d5c4c2SKareemErgawy-TomTom   }
66788d5c4c2SKareemErgawy-TomTom 
66888d5c4c2SKareemErgawy-TomTom   if (resultID == 0) {
66988d5c4c2SKareemErgawy-TomTom     emitError(loc, "cannot serialize attribute: ") << valueAttr;
67088d5c4c2SKareemErgawy-TomTom     return 0;
67188d5c4c2SKareemErgawy-TomTom   }
67288d5c4c2SKareemErgawy-TomTom 
67388d5c4c2SKareemErgawy-TomTom   constIDMap[valueAttr] = resultID;
67488d5c4c2SKareemErgawy-TomTom   return resultID;
67588d5c4c2SKareemErgawy-TomTom }
67688d5c4c2SKareemErgawy-TomTom 
prepareArrayConstant(Location loc,Type constType,ArrayAttr attr)67788d5c4c2SKareemErgawy-TomTom uint32_t Serializer::prepareArrayConstant(Location loc, Type constType,
67888d5c4c2SKareemErgawy-TomTom                                           ArrayAttr attr) {
67988d5c4c2SKareemErgawy-TomTom   uint32_t typeID = 0;
68088d5c4c2SKareemErgawy-TomTom   if (failed(processType(loc, constType, typeID))) {
68188d5c4c2SKareemErgawy-TomTom     return 0;
68288d5c4c2SKareemErgawy-TomTom   }
68388d5c4c2SKareemErgawy-TomTom 
68488d5c4c2SKareemErgawy-TomTom   uint32_t resultID = getNextID();
68588d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 4> operands = {typeID, resultID};
68688d5c4c2SKareemErgawy-TomTom   operands.reserve(attr.size() + 2);
68788d5c4c2SKareemErgawy-TomTom   auto elementType = constType.cast<spirv::ArrayType>().getElementType();
68888d5c4c2SKareemErgawy-TomTom   for (Attribute elementAttr : attr) {
68988d5c4c2SKareemErgawy-TomTom     if (auto elementID = prepareConstant(loc, elementType, elementAttr)) {
69088d5c4c2SKareemErgawy-TomTom       operands.push_back(elementID);
69188d5c4c2SKareemErgawy-TomTom     } else {
69288d5c4c2SKareemErgawy-TomTom       return 0;
69388d5c4c2SKareemErgawy-TomTom     }
69488d5c4c2SKareemErgawy-TomTom   }
69588d5c4c2SKareemErgawy-TomTom   spirv::Opcode opcode = spirv::Opcode::OpConstantComposite;
6963ed47bccSLei Zhang   encodeInstructionInto(typesGlobalValues, opcode, operands);
69788d5c4c2SKareemErgawy-TomTom 
69888d5c4c2SKareemErgawy-TomTom   return resultID;
69988d5c4c2SKareemErgawy-TomTom }
70088d5c4c2SKareemErgawy-TomTom 
70188d5c4c2SKareemErgawy-TomTom // TODO: Turn the below function into iterative function, instead of
70288d5c4c2SKareemErgawy-TomTom // recursive function.
70388d5c4c2SKareemErgawy-TomTom uint32_t
prepareDenseElementsConstant(Location loc,Type constType,DenseElementsAttr valueAttr,int dim,MutableArrayRef<uint64_t> index)70488d5c4c2SKareemErgawy-TomTom Serializer::prepareDenseElementsConstant(Location loc, Type constType,
70588d5c4c2SKareemErgawy-TomTom                                          DenseElementsAttr valueAttr, int dim,
70688d5c4c2SKareemErgawy-TomTom                                          MutableArrayRef<uint64_t> index) {
70788d5c4c2SKareemErgawy-TomTom   auto shapedType = valueAttr.getType().dyn_cast<ShapedType>();
70888d5c4c2SKareemErgawy-TomTom   assert(dim <= shapedType.getRank());
70988d5c4c2SKareemErgawy-TomTom   if (shapedType.getRank() == dim) {
71088d5c4c2SKareemErgawy-TomTom     if (auto attr = valueAttr.dyn_cast<DenseIntElementsAttr>()) {
71188d5c4c2SKareemErgawy-TomTom       return attr.getType().getElementType().isInteger(1)
712ae40d625SRiver Riddle                  ? prepareConstantBool(loc, attr.getValues<BoolAttr>()[index])
713ae40d625SRiver Riddle                  : prepareConstantInt(loc,
714ae40d625SRiver Riddle                                       attr.getValues<IntegerAttr>()[index]);
71588d5c4c2SKareemErgawy-TomTom     }
71688d5c4c2SKareemErgawy-TomTom     if (auto attr = valueAttr.dyn_cast<DenseFPElementsAttr>()) {
717ae40d625SRiver Riddle       return prepareConstantFp(loc, attr.getValues<FloatAttr>()[index]);
71888d5c4c2SKareemErgawy-TomTom     }
71988d5c4c2SKareemErgawy-TomTom     return 0;
72088d5c4c2SKareemErgawy-TomTom   }
72188d5c4c2SKareemErgawy-TomTom 
72288d5c4c2SKareemErgawy-TomTom   uint32_t typeID = 0;
72388d5c4c2SKareemErgawy-TomTom   if (failed(processType(loc, constType, typeID))) {
72488d5c4c2SKareemErgawy-TomTom     return 0;
72588d5c4c2SKareemErgawy-TomTom   }
72688d5c4c2SKareemErgawy-TomTom 
72788d5c4c2SKareemErgawy-TomTom   uint32_t resultID = getNextID();
72888d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 4> operands = {typeID, resultID};
72988d5c4c2SKareemErgawy-TomTom   operands.reserve(shapedType.getDimSize(dim) + 2);
73088d5c4c2SKareemErgawy-TomTom   auto elementType = constType.cast<spirv::CompositeType>().getElementType(0);
73188d5c4c2SKareemErgawy-TomTom   for (int i = 0; i < shapedType.getDimSize(dim); ++i) {
73288d5c4c2SKareemErgawy-TomTom     index[dim] = i;
73388d5c4c2SKareemErgawy-TomTom     if (auto elementID = prepareDenseElementsConstant(
73488d5c4c2SKareemErgawy-TomTom             loc, elementType, valueAttr, dim + 1, index)) {
73588d5c4c2SKareemErgawy-TomTom       operands.push_back(elementID);
73688d5c4c2SKareemErgawy-TomTom     } else {
73788d5c4c2SKareemErgawy-TomTom       return 0;
73888d5c4c2SKareemErgawy-TomTom     }
73988d5c4c2SKareemErgawy-TomTom   }
74088d5c4c2SKareemErgawy-TomTom   spirv::Opcode opcode = spirv::Opcode::OpConstantComposite;
7413ed47bccSLei Zhang   encodeInstructionInto(typesGlobalValues, opcode, operands);
74288d5c4c2SKareemErgawy-TomTom 
74388d5c4c2SKareemErgawy-TomTom   return resultID;
74488d5c4c2SKareemErgawy-TomTom }
74588d5c4c2SKareemErgawy-TomTom 
prepareConstantScalar(Location loc,Attribute valueAttr,bool isSpec)74688d5c4c2SKareemErgawy-TomTom uint32_t Serializer::prepareConstantScalar(Location loc, Attribute valueAttr,
74788d5c4c2SKareemErgawy-TomTom                                            bool isSpec) {
74888d5c4c2SKareemErgawy-TomTom   if (auto floatAttr = valueAttr.dyn_cast<FloatAttr>()) {
74988d5c4c2SKareemErgawy-TomTom     return prepareConstantFp(loc, floatAttr, isSpec);
75088d5c4c2SKareemErgawy-TomTom   }
75188d5c4c2SKareemErgawy-TomTom   if (auto boolAttr = valueAttr.dyn_cast<BoolAttr>()) {
75288d5c4c2SKareemErgawy-TomTom     return prepareConstantBool(loc, boolAttr, isSpec);
75388d5c4c2SKareemErgawy-TomTom   }
75488d5c4c2SKareemErgawy-TomTom   if (auto intAttr = valueAttr.dyn_cast<IntegerAttr>()) {
75588d5c4c2SKareemErgawy-TomTom     return prepareConstantInt(loc, intAttr, isSpec);
75688d5c4c2SKareemErgawy-TomTom   }
75788d5c4c2SKareemErgawy-TomTom 
75888d5c4c2SKareemErgawy-TomTom   return 0;
75988d5c4c2SKareemErgawy-TomTom }
76088d5c4c2SKareemErgawy-TomTom 
prepareConstantBool(Location loc,BoolAttr boolAttr,bool isSpec)76188d5c4c2SKareemErgawy-TomTom uint32_t Serializer::prepareConstantBool(Location loc, BoolAttr boolAttr,
76288d5c4c2SKareemErgawy-TomTom                                          bool isSpec) {
76388d5c4c2SKareemErgawy-TomTom   if (!isSpec) {
76488d5c4c2SKareemErgawy-TomTom     // We can de-duplicate normal constants, but not specialization constants.
76588d5c4c2SKareemErgawy-TomTom     if (auto id = getConstantID(boolAttr)) {
76688d5c4c2SKareemErgawy-TomTom       return id;
76788d5c4c2SKareemErgawy-TomTom     }
76888d5c4c2SKareemErgawy-TomTom   }
76988d5c4c2SKareemErgawy-TomTom 
77088d5c4c2SKareemErgawy-TomTom   // Process the type for this bool literal
77188d5c4c2SKareemErgawy-TomTom   uint32_t typeID = 0;
77288d5c4c2SKareemErgawy-TomTom   if (failed(processType(loc, boolAttr.getType(), typeID))) {
77388d5c4c2SKareemErgawy-TomTom     return 0;
77488d5c4c2SKareemErgawy-TomTom   }
77588d5c4c2SKareemErgawy-TomTom 
77688d5c4c2SKareemErgawy-TomTom   auto resultID = getNextID();
77788d5c4c2SKareemErgawy-TomTom   auto opcode = boolAttr.getValue()
77888d5c4c2SKareemErgawy-TomTom                     ? (isSpec ? spirv::Opcode::OpSpecConstantTrue
77988d5c4c2SKareemErgawy-TomTom                               : spirv::Opcode::OpConstantTrue)
78088d5c4c2SKareemErgawy-TomTom                     : (isSpec ? spirv::Opcode::OpSpecConstantFalse
78188d5c4c2SKareemErgawy-TomTom                               : spirv::Opcode::OpConstantFalse);
7823ed47bccSLei Zhang   encodeInstructionInto(typesGlobalValues, opcode, {typeID, resultID});
78388d5c4c2SKareemErgawy-TomTom 
78488d5c4c2SKareemErgawy-TomTom   if (!isSpec) {
78588d5c4c2SKareemErgawy-TomTom     constIDMap[boolAttr] = resultID;
78688d5c4c2SKareemErgawy-TomTom   }
78788d5c4c2SKareemErgawy-TomTom   return resultID;
78888d5c4c2SKareemErgawy-TomTom }
78988d5c4c2SKareemErgawy-TomTom 
prepareConstantInt(Location loc,IntegerAttr intAttr,bool isSpec)79088d5c4c2SKareemErgawy-TomTom uint32_t Serializer::prepareConstantInt(Location loc, IntegerAttr intAttr,
79188d5c4c2SKareemErgawy-TomTom                                         bool isSpec) {
79288d5c4c2SKareemErgawy-TomTom   if (!isSpec) {
79388d5c4c2SKareemErgawy-TomTom     // We can de-duplicate normal constants, but not specialization constants.
79488d5c4c2SKareemErgawy-TomTom     if (auto id = getConstantID(intAttr)) {
79588d5c4c2SKareemErgawy-TomTom       return id;
79688d5c4c2SKareemErgawy-TomTom     }
79788d5c4c2SKareemErgawy-TomTom   }
79888d5c4c2SKareemErgawy-TomTom 
79988d5c4c2SKareemErgawy-TomTom   // Process the type for this integer literal
80088d5c4c2SKareemErgawy-TomTom   uint32_t typeID = 0;
80188d5c4c2SKareemErgawy-TomTom   if (failed(processType(loc, intAttr.getType(), typeID))) {
80288d5c4c2SKareemErgawy-TomTom     return 0;
80388d5c4c2SKareemErgawy-TomTom   }
80488d5c4c2SKareemErgawy-TomTom 
80588d5c4c2SKareemErgawy-TomTom   auto resultID = getNextID();
80688d5c4c2SKareemErgawy-TomTom   APInt value = intAttr.getValue();
80788d5c4c2SKareemErgawy-TomTom   unsigned bitwidth = value.getBitWidth();
80888d5c4c2SKareemErgawy-TomTom   bool isSigned = value.isSignedIntN(bitwidth);
80988d5c4c2SKareemErgawy-TomTom 
81088d5c4c2SKareemErgawy-TomTom   auto opcode =
81188d5c4c2SKareemErgawy-TomTom       isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
81288d5c4c2SKareemErgawy-TomTom 
813233a3a75SLei Zhang   switch (bitwidth) {
814233a3a75SLei Zhang     // According to SPIR-V spec, "When the type's bit width is less than
815233a3a75SLei Zhang     // 32-bits, the literal's value appears in the low-order bits of the word,
816233a3a75SLei Zhang     // and the high-order bits must be 0 for a floating-point type, or 0 for an
817233a3a75SLei Zhang     // integer type with Signedness of 0, or sign extended when Signedness
818233a3a75SLei Zhang     // is 1."
819233a3a75SLei Zhang   case 32:
820233a3a75SLei Zhang   case 16:
821233a3a75SLei Zhang   case 8: {
82288d5c4c2SKareemErgawy-TomTom     uint32_t word = 0;
82388d5c4c2SKareemErgawy-TomTom     if (isSigned) {
82488d5c4c2SKareemErgawy-TomTom       word = static_cast<int32_t>(value.getSExtValue());
82588d5c4c2SKareemErgawy-TomTom     } else {
82688d5c4c2SKareemErgawy-TomTom       word = static_cast<uint32_t>(value.getZExtValue());
82788d5c4c2SKareemErgawy-TomTom     }
8283ed47bccSLei Zhang     encodeInstructionInto(typesGlobalValues, opcode, {typeID, resultID, word});
829233a3a75SLei Zhang   } break;
83088d5c4c2SKareemErgawy-TomTom     // According to SPIR-V spec: "When the type's bit width is larger than one
83188d5c4c2SKareemErgawy-TomTom     // word, the literal’s low-order words appear first."
832233a3a75SLei Zhang   case 64: {
83388d5c4c2SKareemErgawy-TomTom     struct DoubleWord {
83488d5c4c2SKareemErgawy-TomTom       uint32_t word1;
83588d5c4c2SKareemErgawy-TomTom       uint32_t word2;
83688d5c4c2SKareemErgawy-TomTom     } words;
83788d5c4c2SKareemErgawy-TomTom     if (isSigned) {
83888d5c4c2SKareemErgawy-TomTom       words = llvm::bit_cast<DoubleWord>(value.getSExtValue());
83988d5c4c2SKareemErgawy-TomTom     } else {
84088d5c4c2SKareemErgawy-TomTom       words = llvm::bit_cast<DoubleWord>(value.getZExtValue());
84188d5c4c2SKareemErgawy-TomTom     }
8423ed47bccSLei Zhang     encodeInstructionInto(typesGlobalValues, opcode,
84388d5c4c2SKareemErgawy-TomTom                           {typeID, resultID, words.word1, words.word2});
844233a3a75SLei Zhang   } break;
845233a3a75SLei Zhang   default: {
84688d5c4c2SKareemErgawy-TomTom     std::string valueStr;
84788d5c4c2SKareemErgawy-TomTom     llvm::raw_string_ostream rss(valueStr);
84888d5c4c2SKareemErgawy-TomTom     value.print(rss, /*isSigned=*/false);
84988d5c4c2SKareemErgawy-TomTom 
85088d5c4c2SKareemErgawy-TomTom     emitError(loc, "cannot serialize ")
85188d5c4c2SKareemErgawy-TomTom         << bitwidth << "-bit integer literal: " << rss.str();
85288d5c4c2SKareemErgawy-TomTom     return 0;
85388d5c4c2SKareemErgawy-TomTom   }
854233a3a75SLei Zhang   }
85588d5c4c2SKareemErgawy-TomTom 
85688d5c4c2SKareemErgawy-TomTom   if (!isSpec) {
85788d5c4c2SKareemErgawy-TomTom     constIDMap[intAttr] = resultID;
85888d5c4c2SKareemErgawy-TomTom   }
85988d5c4c2SKareemErgawy-TomTom   return resultID;
86088d5c4c2SKareemErgawy-TomTom }
86188d5c4c2SKareemErgawy-TomTom 
prepareConstantFp(Location loc,FloatAttr floatAttr,bool isSpec)86288d5c4c2SKareemErgawy-TomTom uint32_t Serializer::prepareConstantFp(Location loc, FloatAttr floatAttr,
86388d5c4c2SKareemErgawy-TomTom                                        bool isSpec) {
86488d5c4c2SKareemErgawy-TomTom   if (!isSpec) {
86588d5c4c2SKareemErgawy-TomTom     // We can de-duplicate normal constants, but not specialization constants.
86688d5c4c2SKareemErgawy-TomTom     if (auto id = getConstantID(floatAttr)) {
86788d5c4c2SKareemErgawy-TomTom       return id;
86888d5c4c2SKareemErgawy-TomTom     }
86988d5c4c2SKareemErgawy-TomTom   }
87088d5c4c2SKareemErgawy-TomTom 
87188d5c4c2SKareemErgawy-TomTom   // Process the type for this float literal
87288d5c4c2SKareemErgawy-TomTom   uint32_t typeID = 0;
87388d5c4c2SKareemErgawy-TomTom   if (failed(processType(loc, floatAttr.getType(), typeID))) {
87488d5c4c2SKareemErgawy-TomTom     return 0;
87588d5c4c2SKareemErgawy-TomTom   }
87688d5c4c2SKareemErgawy-TomTom 
87788d5c4c2SKareemErgawy-TomTom   auto resultID = getNextID();
87888d5c4c2SKareemErgawy-TomTom   APFloat value = floatAttr.getValue();
87988d5c4c2SKareemErgawy-TomTom   APInt intValue = value.bitcastToAPInt();
88088d5c4c2SKareemErgawy-TomTom 
88188d5c4c2SKareemErgawy-TomTom   auto opcode =
88288d5c4c2SKareemErgawy-TomTom       isSpec ? spirv::Opcode::OpSpecConstant : spirv::Opcode::OpConstant;
88388d5c4c2SKareemErgawy-TomTom 
88488d5c4c2SKareemErgawy-TomTom   if (&value.getSemantics() == &APFloat::IEEEsingle()) {
88588d5c4c2SKareemErgawy-TomTom     uint32_t word = llvm::bit_cast<uint32_t>(value.convertToFloat());
8863ed47bccSLei Zhang     encodeInstructionInto(typesGlobalValues, opcode, {typeID, resultID, word});
88788d5c4c2SKareemErgawy-TomTom   } else if (&value.getSemantics() == &APFloat::IEEEdouble()) {
88888d5c4c2SKareemErgawy-TomTom     struct DoubleWord {
88988d5c4c2SKareemErgawy-TomTom       uint32_t word1;
89088d5c4c2SKareemErgawy-TomTom       uint32_t word2;
89188d5c4c2SKareemErgawy-TomTom     } words = llvm::bit_cast<DoubleWord>(value.convertToDouble());
8923ed47bccSLei Zhang     encodeInstructionInto(typesGlobalValues, opcode,
89388d5c4c2SKareemErgawy-TomTom                           {typeID, resultID, words.word1, words.word2});
89488d5c4c2SKareemErgawy-TomTom   } else if (&value.getSemantics() == &APFloat::IEEEhalf()) {
89588d5c4c2SKareemErgawy-TomTom     uint32_t word =
89688d5c4c2SKareemErgawy-TomTom         static_cast<uint32_t>(value.bitcastToAPInt().getZExtValue());
8973ed47bccSLei Zhang     encodeInstructionInto(typesGlobalValues, opcode, {typeID, resultID, word});
89888d5c4c2SKareemErgawy-TomTom   } else {
89988d5c4c2SKareemErgawy-TomTom     std::string valueStr;
90088d5c4c2SKareemErgawy-TomTom     llvm::raw_string_ostream rss(valueStr);
90188d5c4c2SKareemErgawy-TomTom     value.print(rss);
90288d5c4c2SKareemErgawy-TomTom 
90388d5c4c2SKareemErgawy-TomTom     emitError(loc, "cannot serialize ")
90488d5c4c2SKareemErgawy-TomTom         << floatAttr.getType() << "-typed float literal: " << rss.str();
90588d5c4c2SKareemErgawy-TomTom     return 0;
90688d5c4c2SKareemErgawy-TomTom   }
90788d5c4c2SKareemErgawy-TomTom 
90888d5c4c2SKareemErgawy-TomTom   if (!isSpec) {
90988d5c4c2SKareemErgawy-TomTom     constIDMap[floatAttr] = resultID;
91088d5c4c2SKareemErgawy-TomTom   }
91188d5c4c2SKareemErgawy-TomTom   return resultID;
91288d5c4c2SKareemErgawy-TomTom }
91388d5c4c2SKareemErgawy-TomTom 
91488d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
91588d5c4c2SKareemErgawy-TomTom // Control flow
91688d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
91788d5c4c2SKareemErgawy-TomTom 
getOrCreateBlockID(Block * block)91888d5c4c2SKareemErgawy-TomTom uint32_t Serializer::getOrCreateBlockID(Block *block) {
91988d5c4c2SKareemErgawy-TomTom   if (uint32_t id = getBlockID(block))
92088d5c4c2SKareemErgawy-TomTom     return id;
92188d5c4c2SKareemErgawy-TomTom   return blockIDMap[block] = getNextID();
92288d5c4c2SKareemErgawy-TomTom }
92388d5c4c2SKareemErgawy-TomTom 
924731676b1SLei Zhang #ifndef NDEBUG
printBlock(Block * block,raw_ostream & os)925731676b1SLei Zhang void Serializer::printBlock(Block *block, raw_ostream &os) {
926731676b1SLei Zhang   os << "block " << block << " (id = ";
927731676b1SLei Zhang   if (uint32_t id = getBlockID(block))
928731676b1SLei Zhang     os << id;
929731676b1SLei Zhang   else
930731676b1SLei Zhang     os << "unknown";
931731676b1SLei Zhang   os << ")\n";
932731676b1SLei Zhang }
933731676b1SLei Zhang #endif
934731676b1SLei Zhang 
93588d5c4c2SKareemErgawy-TomTom LogicalResult
processBlock(Block * block,bool omitLabel,function_ref<LogicalResult ()> emitMerge)93688d5c4c2SKareemErgawy-TomTom Serializer::processBlock(Block *block, bool omitLabel,
937731676b1SLei Zhang                          function_ref<LogicalResult()> emitMerge) {
93888d5c4c2SKareemErgawy-TomTom   LLVM_DEBUG(llvm::dbgs() << "processing block " << block << ":\n");
93988d5c4c2SKareemErgawy-TomTom   LLVM_DEBUG(block->print(llvm::dbgs()));
94088d5c4c2SKareemErgawy-TomTom   LLVM_DEBUG(llvm::dbgs() << '\n');
94188d5c4c2SKareemErgawy-TomTom   if (!omitLabel) {
94288d5c4c2SKareemErgawy-TomTom     uint32_t blockID = getOrCreateBlockID(block);
943731676b1SLei Zhang     LLVM_DEBUG(printBlock(block, llvm::dbgs()));
94488d5c4c2SKareemErgawy-TomTom 
94588d5c4c2SKareemErgawy-TomTom     // Emit OpLabel for this block.
9463ed47bccSLei Zhang     encodeInstructionInto(functionBody, spirv::Opcode::OpLabel, {blockID});
94788d5c4c2SKareemErgawy-TomTom   }
94888d5c4c2SKareemErgawy-TomTom 
94988d5c4c2SKareemErgawy-TomTom   // Emit OpPhi instructions for block arguments, if any.
95088d5c4c2SKareemErgawy-TomTom   if (failed(emitPhiForBlockArguments(block)))
95188d5c4c2SKareemErgawy-TomTom     return failure();
95288d5c4c2SKareemErgawy-TomTom 
953731676b1SLei Zhang   // If we need to emit merge instructions, it must happen in this block. Check
954731676b1SLei Zhang   // whether we have other structured control flow ops, which will be expanded
955731676b1SLei Zhang   // into multiple basic blocks. If that's the case, we need to emit the merge
956731676b1SLei Zhang   // right now and then create new blocks for further serialization of the ops
957731676b1SLei Zhang   // in this block.
958731676b1SLei Zhang   if (emitMerge && llvm::any_of(block->getOperations(), [](Operation &op) {
959731676b1SLei Zhang         return isa<spirv::LoopOp, spirv::SelectionOp>(op);
960731676b1SLei Zhang       })) {
961731676b1SLei Zhang     if (failed(emitMerge()))
962731676b1SLei Zhang       return failure();
963731676b1SLei Zhang     emitMerge = nullptr;
964731676b1SLei Zhang 
965731676b1SLei Zhang     // Start a new block for further serialization.
966731676b1SLei Zhang     uint32_t blockID = getNextID();
967731676b1SLei Zhang     encodeInstructionInto(functionBody, spirv::Opcode::OpBranch, {blockID});
968731676b1SLei Zhang     encodeInstructionInto(functionBody, spirv::Opcode::OpLabel, {blockID});
969731676b1SLei Zhang   }
970731676b1SLei Zhang 
97188d5c4c2SKareemErgawy-TomTom   // Process each op in this block except the terminator.
97288d5c4c2SKareemErgawy-TomTom   for (auto &op : llvm::make_range(block->begin(), std::prev(block->end()))) {
97388d5c4c2SKareemErgawy-TomTom     if (failed(processOperation(&op)))
97488d5c4c2SKareemErgawy-TomTom       return failure();
97588d5c4c2SKareemErgawy-TomTom   }
97688d5c4c2SKareemErgawy-TomTom 
97788d5c4c2SKareemErgawy-TomTom   // Process the terminator.
978731676b1SLei Zhang   if (emitMerge)
979731676b1SLei Zhang     if (failed(emitMerge()))
9803ed47bccSLei Zhang       return failure();
98188d5c4c2SKareemErgawy-TomTom   if (failed(processOperation(&block->back())))
98288d5c4c2SKareemErgawy-TomTom     return failure();
98388d5c4c2SKareemErgawy-TomTom 
98488d5c4c2SKareemErgawy-TomTom   return success();
98588d5c4c2SKareemErgawy-TomTom }
98688d5c4c2SKareemErgawy-TomTom 
emitPhiForBlockArguments(Block * block)98788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::emitPhiForBlockArguments(Block *block) {
98888d5c4c2SKareemErgawy-TomTom   // Nothing to do if this block has no arguments or it's the entry block, which
98988d5c4c2SKareemErgawy-TomTom   // always has the same arguments as the function signature.
99088d5c4c2SKareemErgawy-TomTom   if (block->args_empty() || block->isEntryBlock())
99188d5c4c2SKareemErgawy-TomTom     return success();
99288d5c4c2SKareemErgawy-TomTom 
993731676b1SLei Zhang   LLVM_DEBUG(llvm::dbgs() << "emitting phi instructions..\n");
994731676b1SLei Zhang 
99588d5c4c2SKareemErgawy-TomTom   // If the block has arguments, we need to create SPIR-V OpPhi instructions.
99688d5c4c2SKareemErgawy-TomTom   // A SPIR-V OpPhi instruction is of the syntax:
99788d5c4c2SKareemErgawy-TomTom   //   OpPhi | result type | result <id> | (value <id>, parent block <id>) pair
99888d5c4c2SKareemErgawy-TomTom   // So we need to collect all predecessor blocks and the arguments they send
99988d5c4c2SKareemErgawy-TomTom   // to this block.
1000e4dee7e7SKareemErgawy-TomTom   SmallVector<std::pair<Block *, OperandRange>, 4> predecessors;
1001731676b1SLei Zhang   for (Block *mlirPredecessor : block->getPredecessors()) {
1002731676b1SLei Zhang     auto *terminator = mlirPredecessor->getTerminator();
1003731676b1SLei Zhang     LLVM_DEBUG(llvm::dbgs() << "  mlir predecessor ");
1004731676b1SLei Zhang     LLVM_DEBUG(printBlock(mlirPredecessor, llvm::dbgs()));
1005731676b1SLei Zhang     LLVM_DEBUG(llvm::dbgs() << "    terminator: " << *terminator << "\n");
100688d5c4c2SKareemErgawy-TomTom     // The predecessor here is the immediate one according to MLIR's IR
100788d5c4c2SKareemErgawy-TomTom     // structure. It does not directly map to the incoming parent block for the
100888d5c4c2SKareemErgawy-TomTom     // OpPhi instructions at SPIR-V binary level. This is because structured
100988d5c4c2SKareemErgawy-TomTom     // control flow ops are serialized to multiple SPIR-V blocks. If there is a
10103fb384d5SKareemErgawy-TomTom     // spv.mlir.selection/spv.mlir.loop op in the MLIR predecessor block, the
10113fb384d5SKareemErgawy-TomTom     // branch op jumping to the OpPhi's block then resides in the previous
10123fb384d5SKareemErgawy-TomTom     // structured control flow op's merge block.
1013731676b1SLei Zhang     Block *spirvPredecessor = getPhiIncomingBlock(mlirPredecessor);
1014731676b1SLei Zhang     LLVM_DEBUG(llvm::dbgs() << "  spirv predecessor ");
1015731676b1SLei Zhang     LLVM_DEBUG(printBlock(spirvPredecessor, llvm::dbgs()));
101688d5c4c2SKareemErgawy-TomTom     if (auto branchOp = dyn_cast<spirv::BranchOp>(terminator)) {
1017731676b1SLei Zhang       predecessors.emplace_back(spirvPredecessor, branchOp.getOperands());
1018e4dee7e7SKareemErgawy-TomTom     } else if (auto branchCondOp =
1019e4dee7e7SKareemErgawy-TomTom                    dyn_cast<spirv::BranchConditionalOp>(terminator)) {
1020e4dee7e7SKareemErgawy-TomTom       Optional<OperandRange> blockOperands;
1021731676b1SLei Zhang       if (branchCondOp.trueTarget() == block) {
1022731676b1SLei Zhang         blockOperands = branchCondOp.trueTargetOperands();
1023731676b1SLei Zhang       } else {
1024731676b1SLei Zhang         assert(branchCondOp.falseTarget() == block);
1025731676b1SLei Zhang         blockOperands = branchCondOp.falseTargetOperands();
1026e4dee7e7SKareemErgawy-TomTom       }
1027e4dee7e7SKareemErgawy-TomTom 
1028731676b1SLei Zhang       assert(!blockOperands->empty() &&
1029e4dee7e7SKareemErgawy-TomTom              "expected non-empty block operand range");
1030731676b1SLei Zhang       predecessors.emplace_back(spirvPredecessor, *blockOperands);
103188d5c4c2SKareemErgawy-TomTom     } else {
103288d5c4c2SKareemErgawy-TomTom       return terminator->emitError("unimplemented terminator for Phi creation");
103388d5c4c2SKareemErgawy-TomTom     }
1034731676b1SLei Zhang     LLVM_DEBUG({
1035731676b1SLei Zhang       llvm::dbgs() << "    block arguments:\n";
1036731676b1SLei Zhang       for (Value v : predecessors.back().second)
1037731676b1SLei Zhang         llvm::dbgs() << "      " << v << "\n";
1038731676b1SLei Zhang     });
103988d5c4c2SKareemErgawy-TomTom   }
104088d5c4c2SKareemErgawy-TomTom 
104188d5c4c2SKareemErgawy-TomTom   // Then create OpPhi instruction for each of the block argument.
104288d5c4c2SKareemErgawy-TomTom   for (auto argIndex : llvm::seq<unsigned>(0, block->getNumArguments())) {
104388d5c4c2SKareemErgawy-TomTom     BlockArgument arg = block->getArgument(argIndex);
104488d5c4c2SKareemErgawy-TomTom 
104588d5c4c2SKareemErgawy-TomTom     // Get the type <id> and result <id> for this OpPhi instruction.
104688d5c4c2SKareemErgawy-TomTom     uint32_t phiTypeID = 0;
104788d5c4c2SKareemErgawy-TomTom     if (failed(processType(arg.getLoc(), arg.getType(), phiTypeID)))
104888d5c4c2SKareemErgawy-TomTom       return failure();
104988d5c4c2SKareemErgawy-TomTom     uint32_t phiID = getNextID();
105088d5c4c2SKareemErgawy-TomTom 
105188d5c4c2SKareemErgawy-TomTom     LLVM_DEBUG(llvm::dbgs() << "[phi] for block argument #" << argIndex << ' '
105288d5c4c2SKareemErgawy-TomTom                             << arg << " (id = " << phiID << ")\n");
105388d5c4c2SKareemErgawy-TomTom 
105488d5c4c2SKareemErgawy-TomTom     // Prepare the (value <id>, parent block <id>) pairs.
105588d5c4c2SKareemErgawy-TomTom     SmallVector<uint32_t, 8> phiArgs;
105688d5c4c2SKareemErgawy-TomTom     phiArgs.push_back(phiTypeID);
105788d5c4c2SKareemErgawy-TomTom     phiArgs.push_back(phiID);
105888d5c4c2SKareemErgawy-TomTom 
105988d5c4c2SKareemErgawy-TomTom     for (auto predIndex : llvm::seq<unsigned>(0, predecessors.size())) {
1060e4dee7e7SKareemErgawy-TomTom       Value value = predecessors[predIndex].second[argIndex];
106188d5c4c2SKareemErgawy-TomTom       uint32_t predBlockId = getOrCreateBlockID(predecessors[predIndex].first);
106288d5c4c2SKareemErgawy-TomTom       LLVM_DEBUG(llvm::dbgs() << "[phi] use predecessor (id = " << predBlockId
106388d5c4c2SKareemErgawy-TomTom                               << ") value " << value << ' ');
106488d5c4c2SKareemErgawy-TomTom       // Each pair is a value <id> ...
106588d5c4c2SKareemErgawy-TomTom       uint32_t valueId = getValueID(value);
106688d5c4c2SKareemErgawy-TomTom       if (valueId == 0) {
106788d5c4c2SKareemErgawy-TomTom         // The op generating this value hasn't been visited yet so we don't have
106888d5c4c2SKareemErgawy-TomTom         // an <id> assigned yet. Record this to fix up later.
106988d5c4c2SKareemErgawy-TomTom         LLVM_DEBUG(llvm::dbgs() << "(need to fix)\n");
107088d5c4c2SKareemErgawy-TomTom         deferredPhiValues[value].push_back(functionBody.size() + 1 +
107188d5c4c2SKareemErgawy-TomTom                                            phiArgs.size());
107288d5c4c2SKareemErgawy-TomTom       } else {
107388d5c4c2SKareemErgawy-TomTom         LLVM_DEBUG(llvm::dbgs() << "(id = " << valueId << ")\n");
107488d5c4c2SKareemErgawy-TomTom       }
107588d5c4c2SKareemErgawy-TomTom       phiArgs.push_back(valueId);
107688d5c4c2SKareemErgawy-TomTom       // ... and a parent block <id>.
107788d5c4c2SKareemErgawy-TomTom       phiArgs.push_back(predBlockId);
107888d5c4c2SKareemErgawy-TomTom     }
107988d5c4c2SKareemErgawy-TomTom 
10803ed47bccSLei Zhang     encodeInstructionInto(functionBody, spirv::Opcode::OpPhi, phiArgs);
108188d5c4c2SKareemErgawy-TomTom     valueIDMap[arg] = phiID;
108288d5c4c2SKareemErgawy-TomTom   }
108388d5c4c2SKareemErgawy-TomTom 
108488d5c4c2SKareemErgawy-TomTom   return success();
108588d5c4c2SKareemErgawy-TomTom }
108688d5c4c2SKareemErgawy-TomTom 
108788d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
108888d5c4c2SKareemErgawy-TomTom // Operation
108988d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===//
109088d5c4c2SKareemErgawy-TomTom 
encodeExtensionInstruction(Operation * op,StringRef extensionSetName,uint32_t extensionOpcode,ArrayRef<uint32_t> operands)109188d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::encodeExtensionInstruction(
109288d5c4c2SKareemErgawy-TomTom     Operation *op, StringRef extensionSetName, uint32_t extensionOpcode,
109388d5c4c2SKareemErgawy-TomTom     ArrayRef<uint32_t> operands) {
109488d5c4c2SKareemErgawy-TomTom   // Check if the extension has been imported.
109588d5c4c2SKareemErgawy-TomTom   auto &setID = extendedInstSetIDMap[extensionSetName];
109688d5c4c2SKareemErgawy-TomTom   if (!setID) {
109788d5c4c2SKareemErgawy-TomTom     setID = getNextID();
109888d5c4c2SKareemErgawy-TomTom     SmallVector<uint32_t, 16> importOperands;
109988d5c4c2SKareemErgawy-TomTom     importOperands.push_back(setID);
11003ed47bccSLei Zhang     spirv::encodeStringLiteralInto(importOperands, extensionSetName);
11013ed47bccSLei Zhang     encodeInstructionInto(extendedSets, spirv::Opcode::OpExtInstImport,
11023ed47bccSLei Zhang                           importOperands);
110388d5c4c2SKareemErgawy-TomTom   }
110488d5c4c2SKareemErgawy-TomTom 
110588d5c4c2SKareemErgawy-TomTom   // The first two operands are the result type <id> and result <id>. The set
110688d5c4c2SKareemErgawy-TomTom   // <id> and the opcode need to be insert after this.
110788d5c4c2SKareemErgawy-TomTom   if (operands.size() < 2) {
110888d5c4c2SKareemErgawy-TomTom     return op->emitError("extended instructions must have a result encoding");
110988d5c4c2SKareemErgawy-TomTom   }
111088d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 8> extInstOperands;
111188d5c4c2SKareemErgawy-TomTom   extInstOperands.reserve(operands.size() + 2);
111288d5c4c2SKareemErgawy-TomTom   extInstOperands.append(operands.begin(), std::next(operands.begin(), 2));
111388d5c4c2SKareemErgawy-TomTom   extInstOperands.push_back(setID);
111488d5c4c2SKareemErgawy-TomTom   extInstOperands.push_back(extensionOpcode);
111588d5c4c2SKareemErgawy-TomTom   extInstOperands.append(std::next(operands.begin(), 2), operands.end());
11163ed47bccSLei Zhang   encodeInstructionInto(functionBody, spirv::Opcode::OpExtInst,
111788d5c4c2SKareemErgawy-TomTom                         extInstOperands);
11183ed47bccSLei Zhang   return success();
111988d5c4c2SKareemErgawy-TomTom }
112088d5c4c2SKareemErgawy-TomTom 
processOperation(Operation * opInst)112188d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processOperation(Operation *opInst) {
112288d5c4c2SKareemErgawy-TomTom   LLVM_DEBUG(llvm::dbgs() << "[op] '" << opInst->getName() << "'\n");
112388d5c4c2SKareemErgawy-TomTom 
112488d5c4c2SKareemErgawy-TomTom   // First dispatch the ops that do not directly mirror an instruction from
112588d5c4c2SKareemErgawy-TomTom   // the SPIR-V spec.
112688d5c4c2SKareemErgawy-TomTom   return TypeSwitch<Operation *, LogicalResult>(opInst)
112788d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::AddressOfOp op) { return processAddressOfOp(op); })
112888d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::BranchOp op) { return processBranchOp(op); })
112988d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::BranchConditionalOp op) {
113088d5c4c2SKareemErgawy-TomTom         return processBranchConditionalOp(op);
113188d5c4c2SKareemErgawy-TomTom       })
113288d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::ConstantOp op) { return processConstantOp(op); })
113388d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::FuncOp op) { return processFuncOp(op); })
113488d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::GlobalVariableOp op) {
113588d5c4c2SKareemErgawy-TomTom         return processGlobalVariableOp(op);
113688d5c4c2SKareemErgawy-TomTom       })
113788d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::LoopOp op) { return processLoopOp(op); })
113888d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::ReferenceOfOp op) { return processReferenceOfOp(op); })
113988d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::SelectionOp op) { return processSelectionOp(op); })
114088d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::SpecConstantOp op) { return processSpecConstantOp(op); })
114188d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::SpecConstantCompositeOp op) {
114288d5c4c2SKareemErgawy-TomTom         return processSpecConstantCompositeOp(op);
114388d5c4c2SKareemErgawy-TomTom       })
114488d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::SpecConstantOperationOp op) {
114588d5c4c2SKareemErgawy-TomTom         return processSpecConstantOperationOp(op);
114688d5c4c2SKareemErgawy-TomTom       })
114788d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::UndefOp op) { return processUndefOp(op); })
114888d5c4c2SKareemErgawy-TomTom       .Case([&](spirv::VariableOp op) { return processVariableOp(op); })
114988d5c4c2SKareemErgawy-TomTom 
115088d5c4c2SKareemErgawy-TomTom       // Then handle all the ops that directly mirror SPIR-V instructions with
115188d5c4c2SKareemErgawy-TomTom       // auto-generated methods.
115288d5c4c2SKareemErgawy-TomTom       .Default(
115388d5c4c2SKareemErgawy-TomTom           [&](Operation *op) { return dispatchToAutogenSerialization(op); });
115488d5c4c2SKareemErgawy-TomTom }
115588d5c4c2SKareemErgawy-TomTom 
processOpWithoutGrammarAttr(Operation * op,StringRef extInstSet,uint32_t opcode)115688d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processOpWithoutGrammarAttr(Operation *op,
115788d5c4c2SKareemErgawy-TomTom                                                       StringRef extInstSet,
115888d5c4c2SKareemErgawy-TomTom                                                       uint32_t opcode) {
115988d5c4c2SKareemErgawy-TomTom   SmallVector<uint32_t, 4> operands;
116088d5c4c2SKareemErgawy-TomTom   Location loc = op->getLoc();
116188d5c4c2SKareemErgawy-TomTom 
116288d5c4c2SKareemErgawy-TomTom   uint32_t resultID = 0;
116388d5c4c2SKareemErgawy-TomTom   if (op->getNumResults() != 0) {
116488d5c4c2SKareemErgawy-TomTom     uint32_t resultTypeID = 0;
116588d5c4c2SKareemErgawy-TomTom     if (failed(processType(loc, op->getResult(0).getType(), resultTypeID)))
116688d5c4c2SKareemErgawy-TomTom       return failure();
116788d5c4c2SKareemErgawy-TomTom     operands.push_back(resultTypeID);
116888d5c4c2SKareemErgawy-TomTom 
116988d5c4c2SKareemErgawy-TomTom     resultID = getNextID();
117088d5c4c2SKareemErgawy-TomTom     operands.push_back(resultID);
117188d5c4c2SKareemErgawy-TomTom     valueIDMap[op->getResult(0)] = resultID;
117288d5c4c2SKareemErgawy-TomTom   };
117388d5c4c2SKareemErgawy-TomTom 
117488d5c4c2SKareemErgawy-TomTom   for (Value operand : op->getOperands())
117588d5c4c2SKareemErgawy-TomTom     operands.push_back(getValueID(operand));
117688d5c4c2SKareemErgawy-TomTom 
11773ed47bccSLei Zhang   if (failed(emitDebugLine(functionBody, loc)))
11783ed47bccSLei Zhang     return failure();
117988d5c4c2SKareemErgawy-TomTom 
118088d5c4c2SKareemErgawy-TomTom   if (extInstSet.empty()) {
11813ed47bccSLei Zhang     encodeInstructionInto(functionBody, static_cast<spirv::Opcode>(opcode),
11823ed47bccSLei Zhang                           operands);
118388d5c4c2SKareemErgawy-TomTom   } else {
11843ed47bccSLei Zhang     if (failed(encodeExtensionInstruction(op, extInstSet, opcode, operands)))
11853ed47bccSLei Zhang       return failure();
118688d5c4c2SKareemErgawy-TomTom   }
118788d5c4c2SKareemErgawy-TomTom 
118888d5c4c2SKareemErgawy-TomTom   if (op->getNumResults() != 0) {
118988d5c4c2SKareemErgawy-TomTom     for (auto attr : op->getAttrs()) {
119088d5c4c2SKareemErgawy-TomTom       if (failed(processDecoration(loc, resultID, attr)))
119188d5c4c2SKareemErgawy-TomTom         return failure();
119288d5c4c2SKareemErgawy-TomTom     }
119388d5c4c2SKareemErgawy-TomTom   }
119488d5c4c2SKareemErgawy-TomTom 
119588d5c4c2SKareemErgawy-TomTom   return success();
119688d5c4c2SKareemErgawy-TomTom }
119788d5c4c2SKareemErgawy-TomTom 
emitDecoration(uint32_t target,spirv::Decoration decoration,ArrayRef<uint32_t> params)119888d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::emitDecoration(uint32_t target,
119988d5c4c2SKareemErgawy-TomTom                                          spirv::Decoration decoration,
120088d5c4c2SKareemErgawy-TomTom                                          ArrayRef<uint32_t> params) {
120188d5c4c2SKareemErgawy-TomTom   uint32_t wordCount = 3 + params.size();
120288d5c4c2SKareemErgawy-TomTom   decorations.push_back(
120388d5c4c2SKareemErgawy-TomTom       spirv::getPrefixedOpcode(wordCount, spirv::Opcode::OpDecorate));
120488d5c4c2SKareemErgawy-TomTom   decorations.push_back(target);
120588d5c4c2SKareemErgawy-TomTom   decorations.push_back(static_cast<uint32_t>(decoration));
120688d5c4c2SKareemErgawy-TomTom   decorations.append(params.begin(), params.end());
120788d5c4c2SKareemErgawy-TomTom   return success();
120888d5c4c2SKareemErgawy-TomTom }
120988d5c4c2SKareemErgawy-TomTom 
emitDebugLine(SmallVectorImpl<uint32_t> & binary,Location loc)121088d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::emitDebugLine(SmallVectorImpl<uint32_t> &binary,
121188d5c4c2SKareemErgawy-TomTom                                         Location loc) {
1212b289266cSLei Zhang   if (!options.emitDebugInfo)
121388d5c4c2SKareemErgawy-TomTom     return success();
121488d5c4c2SKareemErgawy-TomTom 
121588d5c4c2SKareemErgawy-TomTom   if (lastProcessedWasMergeInst) {
121688d5c4c2SKareemErgawy-TomTom     lastProcessedWasMergeInst = false;
121788d5c4c2SKareemErgawy-TomTom     return success();
121888d5c4c2SKareemErgawy-TomTom   }
121988d5c4c2SKareemErgawy-TomTom 
122088d5c4c2SKareemErgawy-TomTom   auto fileLoc = loc.dyn_cast<FileLineColLoc>();
122188d5c4c2SKareemErgawy-TomTom   if (fileLoc)
12223ed47bccSLei Zhang     encodeInstructionInto(binary, spirv::Opcode::OpLine,
122388d5c4c2SKareemErgawy-TomTom                           {fileID, fileLoc.getLine(), fileLoc.getColumn()});
122488d5c4c2SKareemErgawy-TomTom   return success();
122588d5c4c2SKareemErgawy-TomTom }
122688d5c4c2SKareemErgawy-TomTom } // namespace spirv
122788d5c4c2SKareemErgawy-TomTom } // namespace mlir
1228