188d5c4c2SKareemErgawy-TomTom //===- SerializeOps.cpp - MLIR SPIR-V Serialization (Ops) -----------------===// 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 serialization methods for MLIR SPIR-V module ops. 1088d5c4c2SKareemErgawy-TomTom // 1188d5c4c2SKareemErgawy-TomTom //===----------------------------------------------------------------------===// 1288d5c4c2SKareemErgawy-TomTom 1388d5c4c2SKareemErgawy-TomTom #include "Serializer.h" 1488d5c4c2SKareemErgawy-TomTom 1588d5c4c2SKareemErgawy-TomTom #include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h" 16a29fffc4SLei Zhang #include "mlir/Dialect/SPIRV/IR/SPIRVEnums.h" 1788d5c4c2SKareemErgawy-TomTom #include "mlir/IR/RegionGraphTraits.h" 1888d5c4c2SKareemErgawy-TomTom #include "mlir/Target/SPIRV/SPIRVBinaryUtils.h" 1988d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/DepthFirstIterator.h" 206d578669SMd Abdullah Shahneous Bari #include "llvm/ADT/StringExtras.h" 2188d5c4c2SKareemErgawy-TomTom #include "llvm/Support/Debug.h" 2288d5c4c2SKareemErgawy-TomTom 2388d5c4c2SKareemErgawy-TomTom #define DEBUG_TYPE "spirv-serialization" 2488d5c4c2SKareemErgawy-TomTom 2588d5c4c2SKareemErgawy-TomTom using namespace mlir; 2688d5c4c2SKareemErgawy-TomTom 2788d5c4c2SKareemErgawy-TomTom /// A pre-order depth-first visitor function for processing basic blocks. 2888d5c4c2SKareemErgawy-TomTom /// 2988d5c4c2SKareemErgawy-TomTom /// Visits the basic blocks starting from the given `headerBlock` in pre-order 3088d5c4c2SKareemErgawy-TomTom /// depth-first manner and calls `blockHandler` on each block. Skips handling 3188d5c4c2SKareemErgawy-TomTom /// blocks in the `skipBlocks` list. If `skipHeader` is true, `blockHandler` 3288d5c4c2SKareemErgawy-TomTom /// will not be invoked in `headerBlock` but still handles all `headerBlock`'s 3388d5c4c2SKareemErgawy-TomTom /// successors. 3488d5c4c2SKareemErgawy-TomTom /// 3588d5c4c2SKareemErgawy-TomTom /// SPIR-V spec "2.16.1. Universal Validation Rules" requires that "the order 3688d5c4c2SKareemErgawy-TomTom /// of blocks in a function must satisfy the rule that blocks appear before 3788d5c4c2SKareemErgawy-TomTom /// all blocks they dominate." This can be achieved by a pre-order CFG 3888d5c4c2SKareemErgawy-TomTom /// traversal algorithm. To make the serialization output more logical and 3988d5c4c2SKareemErgawy-TomTom /// readable to human, we perform depth-first CFG traversal and delay the 4088d5c4c2SKareemErgawy-TomTom /// serialization of the merge block and the continue block, if exists, until 4188d5c4c2SKareemErgawy-TomTom /// after all other blocks have been processed. 4288d5c4c2SKareemErgawy-TomTom static LogicalResult 4388d5c4c2SKareemErgawy-TomTom visitInPrettyBlockOrder(Block *headerBlock, 4488d5c4c2SKareemErgawy-TomTom function_ref<LogicalResult(Block *)> blockHandler, 4588d5c4c2SKareemErgawy-TomTom bool skipHeader = false, BlockRange skipBlocks = {}) { 4688d5c4c2SKareemErgawy-TomTom llvm::df_iterator_default_set<Block *, 4> doneBlocks; 4788d5c4c2SKareemErgawy-TomTom doneBlocks.insert(skipBlocks.begin(), skipBlocks.end()); 4888d5c4c2SKareemErgawy-TomTom 4988d5c4c2SKareemErgawy-TomTom for (Block *block : llvm::depth_first_ext(headerBlock, doneBlocks)) { 5088d5c4c2SKareemErgawy-TomTom if (skipHeader && block == headerBlock) 5188d5c4c2SKareemErgawy-TomTom continue; 5288d5c4c2SKareemErgawy-TomTom if (failed(blockHandler(block))) 5388d5c4c2SKareemErgawy-TomTom return failure(); 5488d5c4c2SKareemErgawy-TomTom } 5588d5c4c2SKareemErgawy-TomTom return success(); 5688d5c4c2SKareemErgawy-TomTom } 5788d5c4c2SKareemErgawy-TomTom 5888d5c4c2SKareemErgawy-TomTom namespace mlir { 5988d5c4c2SKareemErgawy-TomTom namespace spirv { 6088d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processConstantOp(spirv::ConstantOp op) { 6190a1632dSJakub Kuderski if (auto resultID = 6290a1632dSJakub Kuderski prepareConstant(op.getLoc(), op.getType(), op.getValue())) { 6388d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = resultID; 6488d5c4c2SKareemErgawy-TomTom return success(); 6588d5c4c2SKareemErgawy-TomTom } 6688d5c4c2SKareemErgawy-TomTom return failure(); 6788d5c4c2SKareemErgawy-TomTom } 6888d5c4c2SKareemErgawy-TomTom 6988d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) { 7090a1632dSJakub Kuderski if (auto resultID = prepareConstantScalar(op.getLoc(), op.getDefaultValue(), 7188d5c4c2SKareemErgawy-TomTom /*isSpec=*/true)) { 7288d5c4c2SKareemErgawy-TomTom // Emit the OpDecorate instruction for SpecId. 7388d5c4c2SKareemErgawy-TomTom if (auto specID = op->getAttrOfType<IntegerAttr>("spec_id")) { 7488d5c4c2SKareemErgawy-TomTom auto val = static_cast<uint32_t>(specID.getInt()); 753ed47bccSLei Zhang if (failed(emitDecoration(resultID, spirv::Decoration::SpecId, {val}))) 763ed47bccSLei Zhang return failure(); 7788d5c4c2SKareemErgawy-TomTom } 7888d5c4c2SKareemErgawy-TomTom 7990a1632dSJakub Kuderski specConstIDMap[op.getSymName()] = resultID; 8090a1632dSJakub Kuderski return processName(resultID, op.getSymName()); 8188d5c4c2SKareemErgawy-TomTom } 8288d5c4c2SKareemErgawy-TomTom return failure(); 8388d5c4c2SKareemErgawy-TomTom } 8488d5c4c2SKareemErgawy-TomTom 8588d5c4c2SKareemErgawy-TomTom LogicalResult 8688d5c4c2SKareemErgawy-TomTom Serializer::processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op) { 8788d5c4c2SKareemErgawy-TomTom uint32_t typeID = 0; 8890a1632dSJakub Kuderski if (failed(processType(op.getLoc(), op.getType(), typeID))) { 8988d5c4c2SKareemErgawy-TomTom return failure(); 9088d5c4c2SKareemErgawy-TomTom } 9188d5c4c2SKareemErgawy-TomTom 9288d5c4c2SKareemErgawy-TomTom auto resultID = getNextID(); 9388d5c4c2SKareemErgawy-TomTom 9488d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 8> operands; 9588d5c4c2SKareemErgawy-TomTom operands.push_back(typeID); 9688d5c4c2SKareemErgawy-TomTom operands.push_back(resultID); 9788d5c4c2SKareemErgawy-TomTom 9890a1632dSJakub Kuderski auto constituents = op.getConstituents(); 9988d5c4c2SKareemErgawy-TomTom 10088d5c4c2SKareemErgawy-TomTom for (auto index : llvm::seq<uint32_t>(0, constituents.size())) { 1015550c821STres Popp auto constituent = dyn_cast<FlatSymbolRefAttr>(constituents[index]); 10288d5c4c2SKareemErgawy-TomTom 10388d5c4c2SKareemErgawy-TomTom auto constituentName = constituent.getValue(); 10488d5c4c2SKareemErgawy-TomTom auto constituentID = getSpecConstID(constituentName); 10588d5c4c2SKareemErgawy-TomTom 10688d5c4c2SKareemErgawy-TomTom if (!constituentID) { 10788d5c4c2SKareemErgawy-TomTom return op.emitError("unknown result <id> for specialization constant ") 10888d5c4c2SKareemErgawy-TomTom << constituentName; 10988d5c4c2SKareemErgawy-TomTom } 11088d5c4c2SKareemErgawy-TomTom 11188d5c4c2SKareemErgawy-TomTom operands.push_back(constituentID); 11288d5c4c2SKareemErgawy-TomTom } 11388d5c4c2SKareemErgawy-TomTom 1143ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, 11588d5c4c2SKareemErgawy-TomTom spirv::Opcode::OpSpecConstantComposite, operands); 11690a1632dSJakub Kuderski specConstIDMap[op.getSymName()] = resultID; 11788d5c4c2SKareemErgawy-TomTom 11890a1632dSJakub Kuderski return processName(resultID, op.getSymName()); 11988d5c4c2SKareemErgawy-TomTom } 12088d5c4c2SKareemErgawy-TomTom 12188d5c4c2SKareemErgawy-TomTom LogicalResult 12288d5c4c2SKareemErgawy-TomTom Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) { 12388d5c4c2SKareemErgawy-TomTom uint32_t typeID = 0; 12488d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), op.getType(), typeID))) { 12588d5c4c2SKareemErgawy-TomTom return failure(); 12688d5c4c2SKareemErgawy-TomTom } 12788d5c4c2SKareemErgawy-TomTom 12888d5c4c2SKareemErgawy-TomTom auto resultID = getNextID(); 12988d5c4c2SKareemErgawy-TomTom 13088d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 8> operands; 13188d5c4c2SKareemErgawy-TomTom operands.push_back(typeID); 13288d5c4c2SKareemErgawy-TomTom operands.push_back(resultID); 13388d5c4c2SKareemErgawy-TomTom 13488d5c4c2SKareemErgawy-TomTom Block &block = op.getRegion().getBlocks().front(); 13588d5c4c2SKareemErgawy-TomTom Operation &enclosedOp = block.getOperations().front(); 13688d5c4c2SKareemErgawy-TomTom 13788d5c4c2SKareemErgawy-TomTom std::string enclosedOpName; 13888d5c4c2SKareemErgawy-TomTom llvm::raw_string_ostream rss(enclosedOpName); 13988d5c4c2SKareemErgawy-TomTom rss << "Op" << enclosedOp.getName().stripDialect(); 140*095b41c6SJOE1994 auto enclosedOpcode = spirv::symbolizeOpcode(enclosedOpName); 14188d5c4c2SKareemErgawy-TomTom 14288d5c4c2SKareemErgawy-TomTom if (!enclosedOpcode) { 14388d5c4c2SKareemErgawy-TomTom op.emitError("Couldn't find op code for op ") 14488d5c4c2SKareemErgawy-TomTom << enclosedOp.getName().getStringRef(); 14588d5c4c2SKareemErgawy-TomTom return failure(); 14688d5c4c2SKareemErgawy-TomTom } 14788d5c4c2SKareemErgawy-TomTom 1486d5fc1e3SKazu Hirata operands.push_back(static_cast<uint32_t>(*enclosedOpcode)); 14988d5c4c2SKareemErgawy-TomTom 15088d5c4c2SKareemErgawy-TomTom // Append operands to the enclosed op to the list of operands. 15188d5c4c2SKareemErgawy-TomTom for (Value operand : enclosedOp.getOperands()) { 15288d5c4c2SKareemErgawy-TomTom uint32_t id = getValueID(operand); 15388d5c4c2SKareemErgawy-TomTom assert(id && "use before def!"); 15488d5c4c2SKareemErgawy-TomTom operands.push_back(id); 15588d5c4c2SKareemErgawy-TomTom } 15688d5c4c2SKareemErgawy-TomTom 1573ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpSpecConstantOp, 1583ed47bccSLei Zhang operands); 15988d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = resultID; 16088d5c4c2SKareemErgawy-TomTom 16188d5c4c2SKareemErgawy-TomTom return success(); 16288d5c4c2SKareemErgawy-TomTom } 16388d5c4c2SKareemErgawy-TomTom 16488d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processUndefOp(spirv::UndefOp op) { 16588d5c4c2SKareemErgawy-TomTom auto undefType = op.getType(); 16688d5c4c2SKareemErgawy-TomTom auto &id = undefValIDMap[undefType]; 16788d5c4c2SKareemErgawy-TomTom if (!id) { 16888d5c4c2SKareemErgawy-TomTom id = getNextID(); 16988d5c4c2SKareemErgawy-TomTom uint32_t typeID = 0; 1703ed47bccSLei Zhang if (failed(processType(op.getLoc(), undefType, typeID))) 17188d5c4c2SKareemErgawy-TomTom return failure(); 1723ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpUndef, 1733ed47bccSLei Zhang {typeID, id}); 17488d5c4c2SKareemErgawy-TomTom } 17588d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = id; 17688d5c4c2SKareemErgawy-TomTom return success(); 17788d5c4c2SKareemErgawy-TomTom } 17888d5c4c2SKareemErgawy-TomTom 179747d8fb0SKohei Yamaguchi LogicalResult Serializer::processFuncParameter(spirv::FuncOp op) { 180747d8fb0SKohei Yamaguchi for (auto [idx, arg] : llvm::enumerate(op.getArguments())) { 181747d8fb0SKohei Yamaguchi uint32_t argTypeID = 0; 182747d8fb0SKohei Yamaguchi if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) { 183747d8fb0SKohei Yamaguchi return failure(); 184747d8fb0SKohei Yamaguchi } 185747d8fb0SKohei Yamaguchi auto argValueID = getNextID(); 186747d8fb0SKohei Yamaguchi 187747d8fb0SKohei Yamaguchi // Process decoration attributes of arguments. 188747d8fb0SKohei Yamaguchi auto funcOp = cast<FunctionOpInterface>(*op); 189747d8fb0SKohei Yamaguchi for (auto argAttr : funcOp.getArgAttrs(idx)) { 190747d8fb0SKohei Yamaguchi if (argAttr.getName() != DecorationAttr::name) 191747d8fb0SKohei Yamaguchi continue; 192747d8fb0SKohei Yamaguchi 193747d8fb0SKohei Yamaguchi if (auto decAttr = dyn_cast<DecorationAttr>(argAttr.getValue())) { 194747d8fb0SKohei Yamaguchi if (failed(processDecorationAttr(op->getLoc(), argValueID, 195747d8fb0SKohei Yamaguchi decAttr.getValue(), decAttr))) 196747d8fb0SKohei Yamaguchi return failure(); 197747d8fb0SKohei Yamaguchi } 198747d8fb0SKohei Yamaguchi } 199747d8fb0SKohei Yamaguchi 200747d8fb0SKohei Yamaguchi valueIDMap[arg] = argValueID; 201747d8fb0SKohei Yamaguchi encodeInstructionInto(functionHeader, spirv::Opcode::OpFunctionParameter, 202747d8fb0SKohei Yamaguchi {argTypeID, argValueID}); 203747d8fb0SKohei Yamaguchi } 204747d8fb0SKohei Yamaguchi return success(); 205747d8fb0SKohei Yamaguchi } 206747d8fb0SKohei Yamaguchi 20788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processFuncOp(spirv::FuncOp op) { 20888d5c4c2SKareemErgawy-TomTom LLVM_DEBUG(llvm::dbgs() << "-- start function '" << op.getName() << "' --\n"); 20988d5c4c2SKareemErgawy-TomTom assert(functionHeader.empty() && functionBody.empty()); 21088d5c4c2SKareemErgawy-TomTom 21188d5c4c2SKareemErgawy-TomTom uint32_t fnTypeID = 0; 21288d5c4c2SKareemErgawy-TomTom // Generate type of the function. 2134a3460a7SRiver Riddle if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID))) 2143ed47bccSLei Zhang return failure(); 21588d5c4c2SKareemErgawy-TomTom 21688d5c4c2SKareemErgawy-TomTom // Add the function definition. 21788d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands; 21888d5c4c2SKareemErgawy-TomTom uint32_t resTypeID = 0; 2194a3460a7SRiver Riddle auto resultTypes = op.getFunctionType().getResults(); 22088d5c4c2SKareemErgawy-TomTom if (resultTypes.size() > 1) { 22188d5c4c2SKareemErgawy-TomTom return op.emitError("cannot serialize function with multiple return types"); 22288d5c4c2SKareemErgawy-TomTom } 22388d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), 22488d5c4c2SKareemErgawy-TomTom (resultTypes.empty() ? getVoidType() : resultTypes[0]), 22588d5c4c2SKareemErgawy-TomTom resTypeID))) { 22688d5c4c2SKareemErgawy-TomTom return failure(); 22788d5c4c2SKareemErgawy-TomTom } 22888d5c4c2SKareemErgawy-TomTom operands.push_back(resTypeID); 22988d5c4c2SKareemErgawy-TomTom auto funcID = getOrCreateFunctionID(op.getName()); 23088d5c4c2SKareemErgawy-TomTom operands.push_back(funcID); 23190a1632dSJakub Kuderski operands.push_back(static_cast<uint32_t>(op.getFunctionControl())); 23288d5c4c2SKareemErgawy-TomTom operands.push_back(fnTypeID); 2333ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpFunction, operands); 23488d5c4c2SKareemErgawy-TomTom 23588d5c4c2SKareemErgawy-TomTom // Add function name. 23688d5c4c2SKareemErgawy-TomTom if (failed(processName(funcID, op.getName()))) { 23788d5c4c2SKareemErgawy-TomTom return failure(); 23888d5c4c2SKareemErgawy-TomTom } 2396d578669SMd Abdullah Shahneous Bari // Handle external functions with linkage_attributes(LinkageAttributes) 2406d578669SMd Abdullah Shahneous Bari // differently. 2416d578669SMd Abdullah Shahneous Bari auto linkageAttr = op.getLinkageAttributes(); 2426d578669SMd Abdullah Shahneous Bari auto hasImportLinkage = 2436d578669SMd Abdullah Shahneous Bari linkageAttr && (linkageAttr.value().getLinkageType().getValue() == 2446d578669SMd Abdullah Shahneous Bari spirv::LinkageType::Import); 2456d578669SMd Abdullah Shahneous Bari if (op.isExternal() && !hasImportLinkage) { 2466d578669SMd Abdullah Shahneous Bari return op.emitError( 2476d578669SMd Abdullah Shahneous Bari "'spirv.module' cannot contain external functions " 2486d578669SMd Abdullah Shahneous Bari "without 'Import' linkage_attributes (LinkageAttributes)"); 249eb0c8de1SMehdi Amini } 250eb0c8de1SMehdi Amini if (op.isExternal() && hasImportLinkage) { 2516d578669SMd Abdullah Shahneous Bari // Add an entry block to set up the block arguments 2526d578669SMd Abdullah Shahneous Bari // to match the signature of the function. 2536d578669SMd Abdullah Shahneous Bari // This is to generate OpFunctionParameter for functions with 2546d578669SMd Abdullah Shahneous Bari // LinkageAttributes. 2556d578669SMd Abdullah Shahneous Bari // WARNING: This operation has side-effect, it essentially adds a body 2566d578669SMd Abdullah Shahneous Bari // to the func. Hence, making it not external anymore (isExternal() 2576d578669SMd Abdullah Shahneous Bari // is going to return false for this function from now on) 2586d578669SMd Abdullah Shahneous Bari // Hence, we'll remove the body once we are done with the serialization. 2596d578669SMd Abdullah Shahneous Bari op.addEntryBlock(); 260747d8fb0SKohei Yamaguchi if (failed(processFuncParameter(op))) 2616d578669SMd Abdullah Shahneous Bari return failure(); 2626d578669SMd Abdullah Shahneous Bari // Don't need to process the added block, there is nothing to process, 2636d578669SMd Abdullah Shahneous Bari // the fake body was added just to get the arguments, remove the body, 2646d578669SMd Abdullah Shahneous Bari // since it's use is done. 2656d578669SMd Abdullah Shahneous Bari op.eraseBody(); 2666d578669SMd Abdullah Shahneous Bari } else { 267747d8fb0SKohei Yamaguchi if (failed(processFuncParameter(op))) 26888d5c4c2SKareemErgawy-TomTom return failure(); 26988d5c4c2SKareemErgawy-TomTom 27088d5c4c2SKareemErgawy-TomTom // Some instructions (e.g., OpVariable) in a function must be in the first 2716d578669SMd Abdullah Shahneous Bari // block in the function. These instructions will be put in 2726d578669SMd Abdullah Shahneous Bari // functionHeader. Thus, we put the label in functionHeader first, and 2736d578669SMd Abdullah Shahneous Bari // omit it from the first block. OpLabel only needs to be added for 2746d578669SMd Abdullah Shahneous Bari // functions with body (including empty body). Since, we added a fake body 2756d578669SMd Abdullah Shahneous Bari // for functions with 'Import' Linkage attributes, these functions are 2766d578669SMd Abdullah Shahneous Bari // essentially function delcaration, so they should not have OpLabel and a 2776d578669SMd Abdullah Shahneous Bari // terminating instruction. That's why we skipped it for those functions. 2783ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpLabel, 27988d5c4c2SKareemErgawy-TomTom {getOrCreateBlockID(&op.front())}); 2803ed47bccSLei Zhang if (failed(processBlock(&op.front(), /*omitLabel=*/true))) 2813ed47bccSLei Zhang return failure(); 28288d5c4c2SKareemErgawy-TomTom if (failed(visitInPrettyBlockOrder( 28388d5c4c2SKareemErgawy-TomTom &op.front(), [&](Block *block) { return processBlock(block); }, 28488d5c4c2SKareemErgawy-TomTom /*skipHeader=*/true))) { 28588d5c4c2SKareemErgawy-TomTom return failure(); 28688d5c4c2SKareemErgawy-TomTom } 28788d5c4c2SKareemErgawy-TomTom 2886d578669SMd Abdullah Shahneous Bari // There might be OpPhi instructions who have value references needing to 2896d578669SMd Abdullah Shahneous Bari // fix. 2903ed47bccSLei Zhang for (const auto &deferredValue : deferredPhiValues) { 29188d5c4c2SKareemErgawy-TomTom Value value = deferredValue.first; 29288d5c4c2SKareemErgawy-TomTom uint32_t id = getValueID(value); 29388d5c4c2SKareemErgawy-TomTom LLVM_DEBUG(llvm::dbgs() << "[phi] fix reference of value " << value 29488d5c4c2SKareemErgawy-TomTom << " to id = " << id << '\n'); 29588d5c4c2SKareemErgawy-TomTom assert(id && "OpPhi references undefined value!"); 29688d5c4c2SKareemErgawy-TomTom for (size_t offset : deferredValue.second) 29788d5c4c2SKareemErgawy-TomTom functionBody[offset] = id; 29888d5c4c2SKareemErgawy-TomTom } 29988d5c4c2SKareemErgawy-TomTom deferredPhiValues.clear(); 3006d578669SMd Abdullah Shahneous Bari } 30188d5c4c2SKareemErgawy-TomTom LLVM_DEBUG(llvm::dbgs() << "-- completed function '" << op.getName() 30288d5c4c2SKareemErgawy-TomTom << "' --\n"); 3036d578669SMd Abdullah Shahneous Bari // Insert Decorations based on Function Attributes. 3046d578669SMd Abdullah Shahneous Bari // Only attributes we should be considering for decoration are the 3056d578669SMd Abdullah Shahneous Bari // ::mlir::spirv::Decoration attributes. 3066d578669SMd Abdullah Shahneous Bari 3076d578669SMd Abdullah Shahneous Bari for (auto attr : op->getAttrs()) { 3086d578669SMd Abdullah Shahneous Bari // Only generate OpDecorate op for spirv::Decoration attributes. 3096d578669SMd Abdullah Shahneous Bari auto isValidDecoration = mlir::spirv::symbolizeEnum<spirv::Decoration>( 3106d578669SMd Abdullah Shahneous Bari llvm::convertToCamelFromSnakeCase(attr.getName().strref(), 3116d578669SMd Abdullah Shahneous Bari /*capitalizeFirst=*/true)); 3126d578669SMd Abdullah Shahneous Bari if (isValidDecoration != std::nullopt) { 3136d578669SMd Abdullah Shahneous Bari if (failed(processDecoration(op.getLoc(), funcID, attr))) { 3146d578669SMd Abdullah Shahneous Bari return failure(); 3156d578669SMd Abdullah Shahneous Bari } 3166d578669SMd Abdullah Shahneous Bari } 3176d578669SMd Abdullah Shahneous Bari } 31888d5c4c2SKareemErgawy-TomTom // Insert OpFunctionEnd. 3193ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpFunctionEnd, {}); 32088d5c4c2SKareemErgawy-TomTom 32188d5c4c2SKareemErgawy-TomTom functions.append(functionHeader.begin(), functionHeader.end()); 32288d5c4c2SKareemErgawy-TomTom functions.append(functionBody.begin(), functionBody.end()); 32388d5c4c2SKareemErgawy-TomTom functionHeader.clear(); 32488d5c4c2SKareemErgawy-TomTom functionBody.clear(); 32588d5c4c2SKareemErgawy-TomTom 32688d5c4c2SKareemErgawy-TomTom return success(); 32788d5c4c2SKareemErgawy-TomTom } 32888d5c4c2SKareemErgawy-TomTom 32988d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processVariableOp(spirv::VariableOp op) { 33088d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands; 33188d5c4c2SKareemErgawy-TomTom SmallVector<StringRef, 2> elidedAttrs; 33288d5c4c2SKareemErgawy-TomTom uint32_t resultID = 0; 33388d5c4c2SKareemErgawy-TomTom uint32_t resultTypeID = 0; 33488d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), op.getType(), resultTypeID))) { 33588d5c4c2SKareemErgawy-TomTom return failure(); 33688d5c4c2SKareemErgawy-TomTom } 33788d5c4c2SKareemErgawy-TomTom operands.push_back(resultTypeID); 33888d5c4c2SKareemErgawy-TomTom resultID = getNextID(); 33988d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = resultID; 34088d5c4c2SKareemErgawy-TomTom operands.push_back(resultID); 34188d5c4c2SKareemErgawy-TomTom auto attr = op->getAttr(spirv::attributeName<spirv::StorageClass>()); 34288d5c4c2SKareemErgawy-TomTom if (attr) { 343a29fffc4SLei Zhang operands.push_back( 3445550c821STres Popp static_cast<uint32_t>(cast<spirv::StorageClassAttr>(attr).getValue())); 34588d5c4c2SKareemErgawy-TomTom } 34688d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>()); 34788d5c4c2SKareemErgawy-TomTom for (auto arg : op.getODSOperands(0)) { 34888d5c4c2SKareemErgawy-TomTom auto argID = getValueID(arg); 34988d5c4c2SKareemErgawy-TomTom if (!argID) { 35088d5c4c2SKareemErgawy-TomTom return emitError(op.getLoc(), "operand 0 has a use before def"); 35188d5c4c2SKareemErgawy-TomTom } 35288d5c4c2SKareemErgawy-TomTom operands.push_back(argID); 35388d5c4c2SKareemErgawy-TomTom } 3543ed47bccSLei Zhang if (failed(emitDebugLine(functionHeader, op.getLoc()))) 3553ed47bccSLei Zhang return failure(); 3563ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpVariable, operands); 35788d5c4c2SKareemErgawy-TomTom for (auto attr : op->getAttrs()) { 3580c7890c8SRiver Riddle if (llvm::any_of(elidedAttrs, [&](StringRef elided) { 3590c7890c8SRiver Riddle return attr.getName() == elided; 3600c7890c8SRiver Riddle })) { 36188d5c4c2SKareemErgawy-TomTom continue; 36288d5c4c2SKareemErgawy-TomTom } 36388d5c4c2SKareemErgawy-TomTom if (failed(processDecoration(op.getLoc(), resultID, attr))) { 36488d5c4c2SKareemErgawy-TomTom return failure(); 36588d5c4c2SKareemErgawy-TomTom } 36688d5c4c2SKareemErgawy-TomTom } 36788d5c4c2SKareemErgawy-TomTom return success(); 36888d5c4c2SKareemErgawy-TomTom } 36988d5c4c2SKareemErgawy-TomTom 37088d5c4c2SKareemErgawy-TomTom LogicalResult 37188d5c4c2SKareemErgawy-TomTom Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) { 37288d5c4c2SKareemErgawy-TomTom // Get TypeID. 37388d5c4c2SKareemErgawy-TomTom uint32_t resultTypeID = 0; 37488d5c4c2SKareemErgawy-TomTom SmallVector<StringRef, 4> elidedAttrs; 37590a1632dSJakub Kuderski if (failed(processType(varOp.getLoc(), varOp.getType(), resultTypeID))) { 37688d5c4c2SKareemErgawy-TomTom return failure(); 37788d5c4c2SKareemErgawy-TomTom } 37888d5c4c2SKareemErgawy-TomTom 37988d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("type"); 38088d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands; 38188d5c4c2SKareemErgawy-TomTom operands.push_back(resultTypeID); 38288d5c4c2SKareemErgawy-TomTom auto resultID = getNextID(); 38388d5c4c2SKareemErgawy-TomTom 38488d5c4c2SKareemErgawy-TomTom // Encode the name. 38590a1632dSJakub Kuderski auto varName = varOp.getSymName(); 38688d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back(SymbolTable::getSymbolAttrName()); 38788d5c4c2SKareemErgawy-TomTom if (failed(processName(resultID, varName))) { 38888d5c4c2SKareemErgawy-TomTom return failure(); 38988d5c4c2SKareemErgawy-TomTom } 39088d5c4c2SKareemErgawy-TomTom globalVarIDMap[varName] = resultID; 39188d5c4c2SKareemErgawy-TomTom operands.push_back(resultID); 39288d5c4c2SKareemErgawy-TomTom 39388d5c4c2SKareemErgawy-TomTom // Encode StorageClass. 39488d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(varOp.storageClass())); 39588d5c4c2SKareemErgawy-TomTom 39688d5c4c2SKareemErgawy-TomTom // Encode initialization. 3975e54319bSDimple Prajapati StringRef initAttrName = varOp.getInitializerAttrName().getValue(); 3985e54319bSDimple Prajapati if (std::optional<StringRef> initSymbolName = varOp.getInitializer()) { 3995e54319bSDimple Prajapati uint32_t initializerID = 0; 4005e54319bSDimple Prajapati auto initRef = varOp->getAttrOfType<FlatSymbolRefAttr>(initAttrName); 4015e54319bSDimple Prajapati Operation *initOp = SymbolTable::lookupNearestSymbolFrom( 4025e54319bSDimple Prajapati varOp->getParentOp(), initRef.getAttr()); 4035e54319bSDimple Prajapati 4045e54319bSDimple Prajapati // Check if initializer is GlobalVariable or SpecConstant* cases. 4055e54319bSDimple Prajapati if (isa<spirv::GlobalVariableOp>(initOp)) 4065e54319bSDimple Prajapati initializerID = getVariableID(*initSymbolName); 4075e54319bSDimple Prajapati else 4085e54319bSDimple Prajapati initializerID = getSpecConstID(*initSymbolName); 4095e54319bSDimple Prajapati 4105e54319bSDimple Prajapati if (!initializerID) 41188d5c4c2SKareemErgawy-TomTom return emitError(varOp.getLoc(), 41288d5c4c2SKareemErgawy-TomTom "invalid usage of undefined variable as initializer"); 4135e54319bSDimple Prajapati 41488d5c4c2SKareemErgawy-TomTom operands.push_back(initializerID); 4155e54319bSDimple Prajapati elidedAttrs.push_back(initAttrName); 41688d5c4c2SKareemErgawy-TomTom } 41788d5c4c2SKareemErgawy-TomTom 4183ed47bccSLei Zhang if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc()))) 41988d5c4c2SKareemErgawy-TomTom return failure(); 4203ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpVariable, operands); 4215e54319bSDimple Prajapati elidedAttrs.push_back(initAttrName); 42288d5c4c2SKareemErgawy-TomTom 42388d5c4c2SKareemErgawy-TomTom // Encode decorations. 42488d5c4c2SKareemErgawy-TomTom for (auto attr : varOp->getAttrs()) { 4250c7890c8SRiver Riddle if (llvm::any_of(elidedAttrs, [&](StringRef elided) { 4260c7890c8SRiver Riddle return attr.getName() == elided; 4270c7890c8SRiver Riddle })) { 42888d5c4c2SKareemErgawy-TomTom continue; 42988d5c4c2SKareemErgawy-TomTom } 43088d5c4c2SKareemErgawy-TomTom if (failed(processDecoration(varOp.getLoc(), resultID, attr))) { 43188d5c4c2SKareemErgawy-TomTom return failure(); 43288d5c4c2SKareemErgawy-TomTom } 43388d5c4c2SKareemErgawy-TomTom } 43488d5c4c2SKareemErgawy-TomTom return success(); 43588d5c4c2SKareemErgawy-TomTom } 43688d5c4c2SKareemErgawy-TomTom 43788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) { 43888d5c4c2SKareemErgawy-TomTom // Assign <id>s to all blocks so that branches inside the SelectionOp can 43988d5c4c2SKareemErgawy-TomTom // resolve properly. 44090a1632dSJakub Kuderski auto &body = selectionOp.getBody(); 44188d5c4c2SKareemErgawy-TomTom for (Block &block : body) 44288d5c4c2SKareemErgawy-TomTom getOrCreateBlockID(&block); 44388d5c4c2SKareemErgawy-TomTom 44488d5c4c2SKareemErgawy-TomTom auto *headerBlock = selectionOp.getHeaderBlock(); 44588d5c4c2SKareemErgawy-TomTom auto *mergeBlock = selectionOp.getMergeBlock(); 4465e55a201SLei Zhang auto headerID = getBlockID(headerBlock); 44788d5c4c2SKareemErgawy-TomTom auto mergeID = getBlockID(mergeBlock); 44888d5c4c2SKareemErgawy-TomTom auto loc = selectionOp.getLoc(); 44988d5c4c2SKareemErgawy-TomTom 4505e55a201SLei Zhang // This SelectionOp is in some MLIR block with preceding and following ops. In 4515e55a201SLei Zhang // the binary format, it should reside in separate SPIR-V blocks from its 4525e55a201SLei Zhang // preceding and following ops. So we need to emit unconditional branches to 4535e55a201SLei Zhang // jump to this SelectionOp's SPIR-V blocks and jumping back to the normal 4545e55a201SLei Zhang // flow afterwards. 4555e55a201SLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranch, {headerID}); 4565e55a201SLei Zhang 45788d5c4c2SKareemErgawy-TomTom // Emit the selection header block, which dominates all other blocks, first. 45888d5c4c2SKareemErgawy-TomTom // We need to emit an OpSelectionMerge instruction before the selection header 45988d5c4c2SKareemErgawy-TomTom // block's terminator. 46088d5c4c2SKareemErgawy-TomTom auto emitSelectionMerge = [&]() { 4613ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, loc))) 4623ed47bccSLei Zhang return failure(); 46388d5c4c2SKareemErgawy-TomTom lastProcessedWasMergeInst = true; 4643ed47bccSLei Zhang encodeInstructionInto( 46588d5c4c2SKareemErgawy-TomTom functionBody, spirv::Opcode::OpSelectionMerge, 46690a1632dSJakub Kuderski {mergeID, static_cast<uint32_t>(selectionOp.getSelectionControl())}); 4673ed47bccSLei Zhang return success(); 46888d5c4c2SKareemErgawy-TomTom }; 4695e55a201SLei Zhang if (failed( 4705e55a201SLei Zhang processBlock(headerBlock, /*omitLabel=*/false, emitSelectionMerge))) 47188d5c4c2SKareemErgawy-TomTom return failure(); 47288d5c4c2SKareemErgawy-TomTom 47388d5c4c2SKareemErgawy-TomTom // Process all blocks with a depth-first visitor starting from the header 47488d5c4c2SKareemErgawy-TomTom // block. The selection header block and merge block are skipped by this 47588d5c4c2SKareemErgawy-TomTom // visitor. 47688d5c4c2SKareemErgawy-TomTom if (failed(visitInPrettyBlockOrder( 47788d5c4c2SKareemErgawy-TomTom headerBlock, [&](Block *block) { return processBlock(block); }, 47888d5c4c2SKareemErgawy-TomTom /*skipHeader=*/true, /*skipBlocks=*/{mergeBlock}))) 47988d5c4c2SKareemErgawy-TomTom return failure(); 48088d5c4c2SKareemErgawy-TomTom 48188d5c4c2SKareemErgawy-TomTom // There is nothing to do for the merge block in the selection, which just 4825ab6ef75SJakub Kuderski // contains a spirv.mlir.merge op, itself. But we need to have an OpLabel 48388d5c4c2SKareemErgawy-TomTom // instruction to start a new SPIR-V block for ops following this SelectionOp. 48488d5c4c2SKareemErgawy-TomTom // The block should use the <id> for the merge block. 4853ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpLabel, {mergeID}); 486731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "done merge "); 487731676b1SLei Zhang LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs())); 488731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "\n"); 4893ed47bccSLei Zhang return success(); 49088d5c4c2SKareemErgawy-TomTom } 49188d5c4c2SKareemErgawy-TomTom 49288d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processLoopOp(spirv::LoopOp loopOp) { 49388d5c4c2SKareemErgawy-TomTom // Assign <id>s to all blocks so that branches inside the LoopOp can resolve 49488d5c4c2SKareemErgawy-TomTom // properly. We don't need to assign for the entry block, which is just for 49588d5c4c2SKareemErgawy-TomTom // satisfying MLIR region's structural requirement. 49690a1632dSJakub Kuderski auto &body = loopOp.getBody(); 4975605a1eeSKazu Hirata for (Block &block : llvm::drop_begin(body)) 49888d5c4c2SKareemErgawy-TomTom getOrCreateBlockID(&block); 499731676b1SLei Zhang 50088d5c4c2SKareemErgawy-TomTom auto *headerBlock = loopOp.getHeaderBlock(); 50188d5c4c2SKareemErgawy-TomTom auto *continueBlock = loopOp.getContinueBlock(); 50288d5c4c2SKareemErgawy-TomTom auto *mergeBlock = loopOp.getMergeBlock(); 50388d5c4c2SKareemErgawy-TomTom auto headerID = getBlockID(headerBlock); 50488d5c4c2SKareemErgawy-TomTom auto continueID = getBlockID(continueBlock); 50588d5c4c2SKareemErgawy-TomTom auto mergeID = getBlockID(mergeBlock); 50688d5c4c2SKareemErgawy-TomTom auto loc = loopOp.getLoc(); 50788d5c4c2SKareemErgawy-TomTom 50888d5c4c2SKareemErgawy-TomTom // This LoopOp is in some MLIR block with preceding and following ops. In the 50988d5c4c2SKareemErgawy-TomTom // binary format, it should reside in separate SPIR-V blocks from its 51088d5c4c2SKareemErgawy-TomTom // preceding and following ops. So we need to emit unconditional branches to 51188d5c4c2SKareemErgawy-TomTom // jump to this LoopOp's SPIR-V blocks and jumping back to the normal flow 51288d5c4c2SKareemErgawy-TomTom // afterwards. 5133ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranch, {headerID}); 51488d5c4c2SKareemErgawy-TomTom 51588d5c4c2SKareemErgawy-TomTom // LoopOp's entry block is just there for satisfying MLIR's structural 51688d5c4c2SKareemErgawy-TomTom // requirements so we omit it and start serialization from the loop header 51788d5c4c2SKareemErgawy-TomTom // block. 51888d5c4c2SKareemErgawy-TomTom 51988d5c4c2SKareemErgawy-TomTom // Emit the loop header block, which dominates all other blocks, first. We 52088d5c4c2SKareemErgawy-TomTom // need to emit an OpLoopMerge instruction before the loop header block's 52188d5c4c2SKareemErgawy-TomTom // terminator. 52288d5c4c2SKareemErgawy-TomTom auto emitLoopMerge = [&]() { 5233ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, loc))) 5243ed47bccSLei Zhang return failure(); 52588d5c4c2SKareemErgawy-TomTom lastProcessedWasMergeInst = true; 5263ed47bccSLei Zhang encodeInstructionInto( 52788d5c4c2SKareemErgawy-TomTom functionBody, spirv::Opcode::OpLoopMerge, 52890a1632dSJakub Kuderski {mergeID, continueID, static_cast<uint32_t>(loopOp.getLoopControl())}); 5293ed47bccSLei Zhang return success(); 53088d5c4c2SKareemErgawy-TomTom }; 53188d5c4c2SKareemErgawy-TomTom if (failed(processBlock(headerBlock, /*omitLabel=*/false, emitLoopMerge))) 53288d5c4c2SKareemErgawy-TomTom return failure(); 53388d5c4c2SKareemErgawy-TomTom 53488d5c4c2SKareemErgawy-TomTom // Process all blocks with a depth-first visitor starting from the header 53588d5c4c2SKareemErgawy-TomTom // block. The loop header block, loop continue block, and loop merge block are 53688d5c4c2SKareemErgawy-TomTom // skipped by this visitor and handled later in this function. 53788d5c4c2SKareemErgawy-TomTom if (failed(visitInPrettyBlockOrder( 53888d5c4c2SKareemErgawy-TomTom headerBlock, [&](Block *block) { return processBlock(block); }, 53988d5c4c2SKareemErgawy-TomTom /*skipHeader=*/true, /*skipBlocks=*/{continueBlock, mergeBlock}))) 54088d5c4c2SKareemErgawy-TomTom return failure(); 54188d5c4c2SKareemErgawy-TomTom 54288d5c4c2SKareemErgawy-TomTom // We have handled all other blocks. Now get to the loop continue block. 54388d5c4c2SKareemErgawy-TomTom if (failed(processBlock(continueBlock))) 54488d5c4c2SKareemErgawy-TomTom return failure(); 54588d5c4c2SKareemErgawy-TomTom 54688d5c4c2SKareemErgawy-TomTom // There is nothing to do for the merge block in the loop, which just contains 5475ab6ef75SJakub Kuderski // a spirv.mlir.merge op, itself. But we need to have an OpLabel instruction 5485ab6ef75SJakub Kuderski // to start a new SPIR-V block for ops following this LoopOp. The block should 54988d5c4c2SKareemErgawy-TomTom // use the <id> for the merge block. 5503ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpLabel, {mergeID}); 551731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "done merge "); 552731676b1SLei Zhang LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs())); 553731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "\n"); 5543ed47bccSLei Zhang return success(); 55588d5c4c2SKareemErgawy-TomTom } 55688d5c4c2SKareemErgawy-TomTom 55788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processBranchConditionalOp( 55888d5c4c2SKareemErgawy-TomTom spirv::BranchConditionalOp condBranchOp) { 55990a1632dSJakub Kuderski auto conditionID = getValueID(condBranchOp.getCondition()); 56088d5c4c2SKareemErgawy-TomTom auto trueLabelID = getOrCreateBlockID(condBranchOp.getTrueBlock()); 56188d5c4c2SKareemErgawy-TomTom auto falseLabelID = getOrCreateBlockID(condBranchOp.getFalseBlock()); 56288d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 5> arguments{conditionID, trueLabelID, falseLabelID}; 56388d5c4c2SKareemErgawy-TomTom 56490a1632dSJakub Kuderski if (auto weights = condBranchOp.getBranchWeights()) { 56588d5c4c2SKareemErgawy-TomTom for (auto val : weights->getValue()) 5665550c821STres Popp arguments.push_back(cast<IntegerAttr>(val).getInt()); 56788d5c4c2SKareemErgawy-TomTom } 56888d5c4c2SKareemErgawy-TomTom 5693ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, condBranchOp.getLoc()))) 5703ed47bccSLei Zhang return failure(); 5713ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranchConditional, 57288d5c4c2SKareemErgawy-TomTom arguments); 5733ed47bccSLei Zhang return success(); 57488d5c4c2SKareemErgawy-TomTom } 57588d5c4c2SKareemErgawy-TomTom 57688d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processBranchOp(spirv::BranchOp branchOp) { 5773ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, branchOp.getLoc()))) 5783ed47bccSLei Zhang return failure(); 5793ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranch, 58088d5c4c2SKareemErgawy-TomTom {getOrCreateBlockID(branchOp.getTarget())}); 5813ed47bccSLei Zhang return success(); 58288d5c4c2SKareemErgawy-TomTom } 58388d5c4c2SKareemErgawy-TomTom 58488d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processAddressOfOp(spirv::AddressOfOp addressOfOp) { 58590a1632dSJakub Kuderski auto varName = addressOfOp.getVariable(); 58688d5c4c2SKareemErgawy-TomTom auto variableID = getVariableID(varName); 58788d5c4c2SKareemErgawy-TomTom if (!variableID) { 58888d5c4c2SKareemErgawy-TomTom return addressOfOp.emitError("unknown result <id> for variable ") 58988d5c4c2SKareemErgawy-TomTom << varName; 59088d5c4c2SKareemErgawy-TomTom } 59190a1632dSJakub Kuderski valueIDMap[addressOfOp.getPointer()] = variableID; 59288d5c4c2SKareemErgawy-TomTom return success(); 59388d5c4c2SKareemErgawy-TomTom } 59488d5c4c2SKareemErgawy-TomTom 59588d5c4c2SKareemErgawy-TomTom LogicalResult 59688d5c4c2SKareemErgawy-TomTom Serializer::processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp) { 59790a1632dSJakub Kuderski auto constName = referenceOfOp.getSpecConst(); 59888d5c4c2SKareemErgawy-TomTom auto constID = getSpecConstID(constName); 59988d5c4c2SKareemErgawy-TomTom if (!constID) { 60088d5c4c2SKareemErgawy-TomTom return referenceOfOp.emitError( 60188d5c4c2SKareemErgawy-TomTom "unknown result <id> for specialization constant ") 60288d5c4c2SKareemErgawy-TomTom << constName; 60388d5c4c2SKareemErgawy-TomTom } 60490a1632dSJakub Kuderski valueIDMap[referenceOfOp.getReference()] = constID; 60588d5c4c2SKareemErgawy-TomTom return success(); 60688d5c4c2SKareemErgawy-TomTom } 60788d5c4c2SKareemErgawy-TomTom 60888d5c4c2SKareemErgawy-TomTom template <> 60988d5c4c2SKareemErgawy-TomTom LogicalResult 61088d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::EntryPointOp>(spirv::EntryPointOp op) { 61188d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands; 61288d5c4c2SKareemErgawy-TomTom // Add the ExecutionModel. 61390a1632dSJakub Kuderski operands.push_back(static_cast<uint32_t>(op.getExecutionModel())); 61488d5c4c2SKareemErgawy-TomTom // Add the function <id>. 61590a1632dSJakub Kuderski auto funcID = getFunctionID(op.getFn()); 61688d5c4c2SKareemErgawy-TomTom if (!funcID) { 61788d5c4c2SKareemErgawy-TomTom return op.emitError("missing <id> for function ") 61890a1632dSJakub Kuderski << op.getFn() 6195ab6ef75SJakub Kuderski << "; function needs to be defined before spirv.EntryPoint is " 62088d5c4c2SKareemErgawy-TomTom "serialized"; 62188d5c4c2SKareemErgawy-TomTom } 62288d5c4c2SKareemErgawy-TomTom operands.push_back(funcID); 62388d5c4c2SKareemErgawy-TomTom // Add the name of the function. 62490a1632dSJakub Kuderski spirv::encodeStringLiteralInto(operands, op.getFn()); 62588d5c4c2SKareemErgawy-TomTom 62688d5c4c2SKareemErgawy-TomTom // Add the interface values. 62790a1632dSJakub Kuderski if (auto interface = op.getInterface()) { 62888d5c4c2SKareemErgawy-TomTom for (auto var : interface.getValue()) { 6295550c821STres Popp auto id = getVariableID(cast<FlatSymbolRefAttr>(var).getValue()); 63088d5c4c2SKareemErgawy-TomTom if (!id) { 6315ab6ef75SJakub Kuderski return op.emitError( 6325ab6ef75SJakub Kuderski "referencing undefined global variable." 6335ab6ef75SJakub Kuderski "spirv.EntryPoint is at the end of spirv.module. All " 63488d5c4c2SKareemErgawy-TomTom "referenced variables should already be defined"); 63588d5c4c2SKareemErgawy-TomTom } 63688d5c4c2SKareemErgawy-TomTom operands.push_back(id); 63788d5c4c2SKareemErgawy-TomTom } 63888d5c4c2SKareemErgawy-TomTom } 6393ed47bccSLei Zhang encodeInstructionInto(entryPoints, spirv::Opcode::OpEntryPoint, operands); 6403ed47bccSLei Zhang return success(); 64188d5c4c2SKareemErgawy-TomTom } 64288d5c4c2SKareemErgawy-TomTom 64388d5c4c2SKareemErgawy-TomTom template <> 64488d5c4c2SKareemErgawy-TomTom LogicalResult 64588d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::ExecutionModeOp>(spirv::ExecutionModeOp op) { 64688d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands; 64788d5c4c2SKareemErgawy-TomTom // Add the function <id>. 64890a1632dSJakub Kuderski auto funcID = getFunctionID(op.getFn()); 64988d5c4c2SKareemErgawy-TomTom if (!funcID) { 65088d5c4c2SKareemErgawy-TomTom return op.emitError("missing <id> for function ") 65190a1632dSJakub Kuderski << op.getFn() 65288d5c4c2SKareemErgawy-TomTom << "; function needs to be serialized before ExecutionModeOp is " 65388d5c4c2SKareemErgawy-TomTom "serialized"; 65488d5c4c2SKareemErgawy-TomTom } 65588d5c4c2SKareemErgawy-TomTom operands.push_back(funcID); 65688d5c4c2SKareemErgawy-TomTom // Add the ExecutionMode. 65790a1632dSJakub Kuderski operands.push_back(static_cast<uint32_t>(op.getExecutionMode())); 65888d5c4c2SKareemErgawy-TomTom 65988d5c4c2SKareemErgawy-TomTom // Serialize values if any. 66090a1632dSJakub Kuderski auto values = op.getValues(); 66188d5c4c2SKareemErgawy-TomTom if (values) { 66288d5c4c2SKareemErgawy-TomTom for (auto &intVal : values.getValue()) { 66388d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>( 66468f58812STres Popp llvm::cast<IntegerAttr>(intVal).getValue().getZExtValue())); 66588d5c4c2SKareemErgawy-TomTom } 66688d5c4c2SKareemErgawy-TomTom } 6673ed47bccSLei Zhang encodeInstructionInto(executionModes, spirv::Opcode::OpExecutionMode, 66888d5c4c2SKareemErgawy-TomTom operands); 6693ed47bccSLei Zhang return success(); 67088d5c4c2SKareemErgawy-TomTom } 67188d5c4c2SKareemErgawy-TomTom 67288d5c4c2SKareemErgawy-TomTom template <> 67388d5c4c2SKareemErgawy-TomTom LogicalResult 67488d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::FunctionCallOp>(spirv::FunctionCallOp op) { 67590a1632dSJakub Kuderski auto funcName = op.getCallee(); 67688d5c4c2SKareemErgawy-TomTom uint32_t resTypeID = 0; 67788d5c4c2SKareemErgawy-TomTom 67888d5c4c2SKareemErgawy-TomTom Type resultTy = op.getNumResults() ? *op.result_type_begin() : getVoidType(); 67988d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), resultTy, resTypeID))) 68088d5c4c2SKareemErgawy-TomTom return failure(); 68188d5c4c2SKareemErgawy-TomTom 68288d5c4c2SKareemErgawy-TomTom auto funcID = getOrCreateFunctionID(funcName); 68388d5c4c2SKareemErgawy-TomTom auto funcCallID = getNextID(); 68488d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 8> operands{resTypeID, funcCallID, funcID}; 68588d5c4c2SKareemErgawy-TomTom 68690a1632dSJakub Kuderski for (auto value : op.getArguments()) { 68788d5c4c2SKareemErgawy-TomTom auto valueID = getValueID(value); 6885ab6ef75SJakub Kuderski assert(valueID && "cannot find a value for spirv.FunctionCall"); 68988d5c4c2SKareemErgawy-TomTom operands.push_back(valueID); 69088d5c4c2SKareemErgawy-TomTom } 69188d5c4c2SKareemErgawy-TomTom 6925550c821STres Popp if (!isa<NoneType>(resultTy)) 69388d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult(0)] = funcCallID; 69488d5c4c2SKareemErgawy-TomTom 6953ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpFunctionCall, operands); 6963ed47bccSLei Zhang return success(); 69788d5c4c2SKareemErgawy-TomTom } 69888d5c4c2SKareemErgawy-TomTom 69988d5c4c2SKareemErgawy-TomTom template <> 70088d5c4c2SKareemErgawy-TomTom LogicalResult 70188d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::CopyMemoryOp>(spirv::CopyMemoryOp op) { 70288d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands; 70388d5c4c2SKareemErgawy-TomTom SmallVector<StringRef, 2> elidedAttrs; 70488d5c4c2SKareemErgawy-TomTom 70588d5c4c2SKareemErgawy-TomTom for (Value operand : op->getOperands()) { 70688d5c4c2SKareemErgawy-TomTom auto id = getValueID(operand); 70788d5c4c2SKareemErgawy-TomTom assert(id && "use before def!"); 70888d5c4c2SKareemErgawy-TomTom operands.push_back(id); 70988d5c4c2SKareemErgawy-TomTom } 71088d5c4c2SKareemErgawy-TomTom 711ead0a977SSahilPatidar StringAttr memoryAccess = op.getMemoryAccessAttrName(); 712ead0a977SSahilPatidar if (auto attr = op->getAttr(memoryAccess)) { 713a29fffc4SLei Zhang operands.push_back( 7145550c821STres Popp static_cast<uint32_t>(cast<spirv::MemoryAccessAttr>(attr).getValue())); 71588d5c4c2SKareemErgawy-TomTom } 71688d5c4c2SKareemErgawy-TomTom 717ead0a977SSahilPatidar elidedAttrs.push_back(memoryAccess.strref()); 71888d5c4c2SKareemErgawy-TomTom 719ead0a977SSahilPatidar StringAttr alignment = op.getAlignmentAttrName(); 720ead0a977SSahilPatidar if (auto attr = op->getAttr(alignment)) { 72188d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>( 7225550c821STres Popp cast<IntegerAttr>(attr).getValue().getZExtValue())); 72388d5c4c2SKareemErgawy-TomTom } 72488d5c4c2SKareemErgawy-TomTom 725ead0a977SSahilPatidar elidedAttrs.push_back(alignment.strref()); 72688d5c4c2SKareemErgawy-TomTom 727ead0a977SSahilPatidar StringAttr sourceMemoryAccess = op.getSourceMemoryAccessAttrName(); 728ead0a977SSahilPatidar if (auto attr = op->getAttr(sourceMemoryAccess)) { 729a29fffc4SLei Zhang operands.push_back( 7305550c821STres Popp static_cast<uint32_t>(cast<spirv::MemoryAccessAttr>(attr).getValue())); 73188d5c4c2SKareemErgawy-TomTom } 73288d5c4c2SKareemErgawy-TomTom 733ead0a977SSahilPatidar elidedAttrs.push_back(sourceMemoryAccess.strref()); 73488d5c4c2SKareemErgawy-TomTom 735ead0a977SSahilPatidar StringAttr sourceAlignment = op.getSourceAlignmentAttrName(); 736ead0a977SSahilPatidar if (auto attr = op->getAttr(sourceAlignment)) { 73788d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>( 7385550c821STres Popp cast<IntegerAttr>(attr).getValue().getZExtValue())); 73988d5c4c2SKareemErgawy-TomTom } 74088d5c4c2SKareemErgawy-TomTom 741ead0a977SSahilPatidar elidedAttrs.push_back(sourceAlignment.strref()); 7423ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, op.getLoc()))) 7433ed47bccSLei Zhang return failure(); 7443ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpCopyMemory, operands); 74588d5c4c2SKareemErgawy-TomTom 74688d5c4c2SKareemErgawy-TomTom return success(); 74788d5c4c2SKareemErgawy-TomTom } 7487f19e59aSNirvedh Meshram template <> 7497f19e59aSNirvedh Meshram LogicalResult Serializer::processOp<spirv::GenericCastToPtrExplicitOp>( 7507f19e59aSNirvedh Meshram spirv::GenericCastToPtrExplicitOp op) { 7517f19e59aSNirvedh Meshram SmallVector<uint32_t, 4> operands; 7527f19e59aSNirvedh Meshram Type resultTy; 7537f19e59aSNirvedh Meshram Location loc = op->getLoc(); 7547f19e59aSNirvedh Meshram uint32_t resultTypeID = 0; 7557f19e59aSNirvedh Meshram uint32_t resultID = 0; 7567f19e59aSNirvedh Meshram resultTy = op->getResult(0).getType(); 7577f19e59aSNirvedh Meshram if (failed(processType(loc, resultTy, resultTypeID))) 7587f19e59aSNirvedh Meshram return failure(); 7597f19e59aSNirvedh Meshram operands.push_back(resultTypeID); 7607f19e59aSNirvedh Meshram 7617f19e59aSNirvedh Meshram resultID = getNextID(); 7627f19e59aSNirvedh Meshram operands.push_back(resultID); 7637f19e59aSNirvedh Meshram valueIDMap[op->getResult(0)] = resultID; 7647f19e59aSNirvedh Meshram 7657f19e59aSNirvedh Meshram for (Value operand : op->getOperands()) 7667f19e59aSNirvedh Meshram operands.push_back(getValueID(operand)); 7677f19e59aSNirvedh Meshram spirv::StorageClass resultStorage = 7685550c821STres Popp cast<spirv::PointerType>(resultTy).getStorageClass(); 7697f19e59aSNirvedh Meshram operands.push_back(static_cast<uint32_t>(resultStorage)); 7707f19e59aSNirvedh Meshram encodeInstructionInto(functionBody, spirv::Opcode::OpGenericCastToPtrExplicit, 7717f19e59aSNirvedh Meshram operands); 7727f19e59aSNirvedh Meshram return success(); 7737f19e59aSNirvedh Meshram } 77488d5c4c2SKareemErgawy-TomTom 77588d5c4c2SKareemErgawy-TomTom // Pull in auto-generated Serializer::dispatchToAutogenSerialization() and 77688d5c4c2SKareemErgawy-TomTom // various Serializer::processOp<...>() specializations. 77788d5c4c2SKareemErgawy-TomTom #define GET_SERIALIZATION_FNS 77888d5c4c2SKareemErgawy-TomTom #include "mlir/Dialect/SPIRV/IR/SPIRVSerialization.inc" 77988d5c4c2SKareemErgawy-TomTom 78088d5c4c2SKareemErgawy-TomTom } // namespace spirv 78188d5c4c2SKareemErgawy-TomTom } // namespace mlir 782