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"
1688d5c4c2SKareemErgawy-TomTom #include "mlir/IR/RegionGraphTraits.h"
1788d5c4c2SKareemErgawy-TomTom #include "mlir/Support/LogicalResult.h"
1888d5c4c2SKareemErgawy-TomTom #include "mlir/Target/SPIRV/SPIRVBinaryUtils.h"
1988d5c4c2SKareemErgawy-TomTom #include "llvm/ADT/DepthFirstIterator.h"
2088d5c4c2SKareemErgawy-TomTom #include "llvm/Support/Debug.h"
2188d5c4c2SKareemErgawy-TomTom
2288d5c4c2SKareemErgawy-TomTom #define DEBUG_TYPE "spirv-serialization"
2388d5c4c2SKareemErgawy-TomTom
2488d5c4c2SKareemErgawy-TomTom using namespace mlir;
2588d5c4c2SKareemErgawy-TomTom
2688d5c4c2SKareemErgawy-TomTom /// A pre-order depth-first visitor function for processing basic blocks.
2788d5c4c2SKareemErgawy-TomTom ///
2888d5c4c2SKareemErgawy-TomTom /// Visits the basic blocks starting from the given `headerBlock` in pre-order
2988d5c4c2SKareemErgawy-TomTom /// depth-first manner and calls `blockHandler` on each block. Skips handling
3088d5c4c2SKareemErgawy-TomTom /// blocks in the `skipBlocks` list. If `skipHeader` is true, `blockHandler`
3188d5c4c2SKareemErgawy-TomTom /// will not be invoked in `headerBlock` but still handles all `headerBlock`'s
3288d5c4c2SKareemErgawy-TomTom /// successors.
3388d5c4c2SKareemErgawy-TomTom ///
3488d5c4c2SKareemErgawy-TomTom /// SPIR-V spec "2.16.1. Universal Validation Rules" requires that "the order
3588d5c4c2SKareemErgawy-TomTom /// of blocks in a function must satisfy the rule that blocks appear before
3688d5c4c2SKareemErgawy-TomTom /// all blocks they dominate." This can be achieved by a pre-order CFG
3788d5c4c2SKareemErgawy-TomTom /// traversal algorithm. To make the serialization output more logical and
3888d5c4c2SKareemErgawy-TomTom /// readable to human, we perform depth-first CFG traversal and delay the
3988d5c4c2SKareemErgawy-TomTom /// serialization of the merge block and the continue block, if exists, until
4088d5c4c2SKareemErgawy-TomTom /// after all other blocks have been processed.
4188d5c4c2SKareemErgawy-TomTom static LogicalResult
visitInPrettyBlockOrder(Block * headerBlock,function_ref<LogicalResult (Block *)> blockHandler,bool skipHeader=false,BlockRange skipBlocks={})4288d5c4c2SKareemErgawy-TomTom visitInPrettyBlockOrder(Block *headerBlock,
4388d5c4c2SKareemErgawy-TomTom function_ref<LogicalResult(Block *)> blockHandler,
4488d5c4c2SKareemErgawy-TomTom bool skipHeader = false, BlockRange skipBlocks = {}) {
4588d5c4c2SKareemErgawy-TomTom llvm::df_iterator_default_set<Block *, 4> doneBlocks;
4688d5c4c2SKareemErgawy-TomTom doneBlocks.insert(skipBlocks.begin(), skipBlocks.end());
4788d5c4c2SKareemErgawy-TomTom
4888d5c4c2SKareemErgawy-TomTom for (Block *block : llvm::depth_first_ext(headerBlock, doneBlocks)) {
4988d5c4c2SKareemErgawy-TomTom if (skipHeader && block == headerBlock)
5088d5c4c2SKareemErgawy-TomTom continue;
5188d5c4c2SKareemErgawy-TomTom if (failed(blockHandler(block)))
5288d5c4c2SKareemErgawy-TomTom return failure();
5388d5c4c2SKareemErgawy-TomTom }
5488d5c4c2SKareemErgawy-TomTom return success();
5588d5c4c2SKareemErgawy-TomTom }
5688d5c4c2SKareemErgawy-TomTom
5788d5c4c2SKareemErgawy-TomTom namespace mlir {
5888d5c4c2SKareemErgawy-TomTom namespace spirv {
processConstantOp(spirv::ConstantOp op)5988d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processConstantOp(spirv::ConstantOp op) {
6088d5c4c2SKareemErgawy-TomTom if (auto resultID = prepareConstant(op.getLoc(), op.getType(), op.value())) {
6188d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = resultID;
6288d5c4c2SKareemErgawy-TomTom return success();
6388d5c4c2SKareemErgawy-TomTom }
6488d5c4c2SKareemErgawy-TomTom return failure();
6588d5c4c2SKareemErgawy-TomTom }
6688d5c4c2SKareemErgawy-TomTom
processSpecConstantOp(spirv::SpecConstantOp op)6788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processSpecConstantOp(spirv::SpecConstantOp op) {
6888d5c4c2SKareemErgawy-TomTom if (auto resultID = prepareConstantScalar(op.getLoc(), op.default_value(),
6988d5c4c2SKareemErgawy-TomTom /*isSpec=*/true)) {
7088d5c4c2SKareemErgawy-TomTom // Emit the OpDecorate instruction for SpecId.
7188d5c4c2SKareemErgawy-TomTom if (auto specID = op->getAttrOfType<IntegerAttr>("spec_id")) {
7288d5c4c2SKareemErgawy-TomTom auto val = static_cast<uint32_t>(specID.getInt());
733ed47bccSLei Zhang if (failed(emitDecoration(resultID, spirv::Decoration::SpecId, {val})))
743ed47bccSLei Zhang return failure();
7588d5c4c2SKareemErgawy-TomTom }
7688d5c4c2SKareemErgawy-TomTom
7788d5c4c2SKareemErgawy-TomTom specConstIDMap[op.sym_name()] = resultID;
7888d5c4c2SKareemErgawy-TomTom return processName(resultID, op.sym_name());
7988d5c4c2SKareemErgawy-TomTom }
8088d5c4c2SKareemErgawy-TomTom return failure();
8188d5c4c2SKareemErgawy-TomTom }
8288d5c4c2SKareemErgawy-TomTom
8388d5c4c2SKareemErgawy-TomTom LogicalResult
processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op)8488d5c4c2SKareemErgawy-TomTom Serializer::processSpecConstantCompositeOp(spirv::SpecConstantCompositeOp op) {
8588d5c4c2SKareemErgawy-TomTom uint32_t typeID = 0;
8688d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), op.type(), typeID))) {
8788d5c4c2SKareemErgawy-TomTom return failure();
8888d5c4c2SKareemErgawy-TomTom }
8988d5c4c2SKareemErgawy-TomTom
9088d5c4c2SKareemErgawy-TomTom auto resultID = getNextID();
9188d5c4c2SKareemErgawy-TomTom
9288d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 8> operands;
9388d5c4c2SKareemErgawy-TomTom operands.push_back(typeID);
9488d5c4c2SKareemErgawy-TomTom operands.push_back(resultID);
9588d5c4c2SKareemErgawy-TomTom
9688d5c4c2SKareemErgawy-TomTom auto constituents = op.constituents();
9788d5c4c2SKareemErgawy-TomTom
9888d5c4c2SKareemErgawy-TomTom for (auto index : llvm::seq<uint32_t>(0, constituents.size())) {
9988d5c4c2SKareemErgawy-TomTom auto constituent = constituents[index].dyn_cast<FlatSymbolRefAttr>();
10088d5c4c2SKareemErgawy-TomTom
10188d5c4c2SKareemErgawy-TomTom auto constituentName = constituent.getValue();
10288d5c4c2SKareemErgawy-TomTom auto constituentID = getSpecConstID(constituentName);
10388d5c4c2SKareemErgawy-TomTom
10488d5c4c2SKareemErgawy-TomTom if (!constituentID) {
10588d5c4c2SKareemErgawy-TomTom return op.emitError("unknown result <id> for specialization constant ")
10688d5c4c2SKareemErgawy-TomTom << constituentName;
10788d5c4c2SKareemErgawy-TomTom }
10888d5c4c2SKareemErgawy-TomTom
10988d5c4c2SKareemErgawy-TomTom operands.push_back(constituentID);
11088d5c4c2SKareemErgawy-TomTom }
11188d5c4c2SKareemErgawy-TomTom
1123ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues,
11388d5c4c2SKareemErgawy-TomTom spirv::Opcode::OpSpecConstantComposite, operands);
11488d5c4c2SKareemErgawy-TomTom specConstIDMap[op.sym_name()] = resultID;
11588d5c4c2SKareemErgawy-TomTom
11688d5c4c2SKareemErgawy-TomTom return processName(resultID, op.sym_name());
11788d5c4c2SKareemErgawy-TomTom }
11888d5c4c2SKareemErgawy-TomTom
11988d5c4c2SKareemErgawy-TomTom LogicalResult
processSpecConstantOperationOp(spirv::SpecConstantOperationOp op)12088d5c4c2SKareemErgawy-TomTom Serializer::processSpecConstantOperationOp(spirv::SpecConstantOperationOp op) {
12188d5c4c2SKareemErgawy-TomTom uint32_t typeID = 0;
12288d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), op.getType(), typeID))) {
12388d5c4c2SKareemErgawy-TomTom return failure();
12488d5c4c2SKareemErgawy-TomTom }
12588d5c4c2SKareemErgawy-TomTom
12688d5c4c2SKareemErgawy-TomTom auto resultID = getNextID();
12788d5c4c2SKareemErgawy-TomTom
12888d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 8> operands;
12988d5c4c2SKareemErgawy-TomTom operands.push_back(typeID);
13088d5c4c2SKareemErgawy-TomTom operands.push_back(resultID);
13188d5c4c2SKareemErgawy-TomTom
13288d5c4c2SKareemErgawy-TomTom Block &block = op.getRegion().getBlocks().front();
13388d5c4c2SKareemErgawy-TomTom Operation &enclosedOp = block.getOperations().front();
13488d5c4c2SKareemErgawy-TomTom
13588d5c4c2SKareemErgawy-TomTom std::string enclosedOpName;
13688d5c4c2SKareemErgawy-TomTom llvm::raw_string_ostream rss(enclosedOpName);
13788d5c4c2SKareemErgawy-TomTom rss << "Op" << enclosedOp.getName().stripDialect();
13888d5c4c2SKareemErgawy-TomTom auto enclosedOpcode = spirv::symbolizeOpcode(rss.str());
13988d5c4c2SKareemErgawy-TomTom
14088d5c4c2SKareemErgawy-TomTom if (!enclosedOpcode) {
14188d5c4c2SKareemErgawy-TomTom op.emitError("Couldn't find op code for op ")
14288d5c4c2SKareemErgawy-TomTom << enclosedOp.getName().getStringRef();
14388d5c4c2SKareemErgawy-TomTom return failure();
14488d5c4c2SKareemErgawy-TomTom }
14588d5c4c2SKareemErgawy-TomTom
1466d5fc1e3SKazu Hirata operands.push_back(static_cast<uint32_t>(*enclosedOpcode));
14788d5c4c2SKareemErgawy-TomTom
14888d5c4c2SKareemErgawy-TomTom // Append operands to the enclosed op to the list of operands.
14988d5c4c2SKareemErgawy-TomTom for (Value operand : enclosedOp.getOperands()) {
15088d5c4c2SKareemErgawy-TomTom uint32_t id = getValueID(operand);
15188d5c4c2SKareemErgawy-TomTom assert(id && "use before def!");
15288d5c4c2SKareemErgawy-TomTom operands.push_back(id);
15388d5c4c2SKareemErgawy-TomTom }
15488d5c4c2SKareemErgawy-TomTom
1553ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpSpecConstantOp,
1563ed47bccSLei Zhang operands);
15788d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = resultID;
15888d5c4c2SKareemErgawy-TomTom
15988d5c4c2SKareemErgawy-TomTom return success();
16088d5c4c2SKareemErgawy-TomTom }
16188d5c4c2SKareemErgawy-TomTom
processUndefOp(spirv::UndefOp op)16288d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processUndefOp(spirv::UndefOp op) {
16388d5c4c2SKareemErgawy-TomTom auto undefType = op.getType();
16488d5c4c2SKareemErgawy-TomTom auto &id = undefValIDMap[undefType];
16588d5c4c2SKareemErgawy-TomTom if (!id) {
16688d5c4c2SKareemErgawy-TomTom id = getNextID();
16788d5c4c2SKareemErgawy-TomTom uint32_t typeID = 0;
1683ed47bccSLei Zhang if (failed(processType(op.getLoc(), undefType, typeID)))
16988d5c4c2SKareemErgawy-TomTom return failure();
1703ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpUndef,
1713ed47bccSLei Zhang {typeID, id});
17288d5c4c2SKareemErgawy-TomTom }
17388d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = id;
17488d5c4c2SKareemErgawy-TomTom return success();
17588d5c4c2SKareemErgawy-TomTom }
17688d5c4c2SKareemErgawy-TomTom
processFuncOp(spirv::FuncOp op)17788d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processFuncOp(spirv::FuncOp op) {
17888d5c4c2SKareemErgawy-TomTom LLVM_DEBUG(llvm::dbgs() << "-- start function '" << op.getName() << "' --\n");
17988d5c4c2SKareemErgawy-TomTom assert(functionHeader.empty() && functionBody.empty());
18088d5c4c2SKareemErgawy-TomTom
18188d5c4c2SKareemErgawy-TomTom uint32_t fnTypeID = 0;
18288d5c4c2SKareemErgawy-TomTom // Generate type of the function.
1834a3460a7SRiver Riddle if (failed(processType(op.getLoc(), op.getFunctionType(), fnTypeID)))
1843ed47bccSLei Zhang return failure();
18588d5c4c2SKareemErgawy-TomTom
18688d5c4c2SKareemErgawy-TomTom // Add the function definition.
18788d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands;
18888d5c4c2SKareemErgawy-TomTom uint32_t resTypeID = 0;
1894a3460a7SRiver Riddle auto resultTypes = op.getFunctionType().getResults();
19088d5c4c2SKareemErgawy-TomTom if (resultTypes.size() > 1) {
19188d5c4c2SKareemErgawy-TomTom return op.emitError("cannot serialize function with multiple return types");
19288d5c4c2SKareemErgawy-TomTom }
19388d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(),
19488d5c4c2SKareemErgawy-TomTom (resultTypes.empty() ? getVoidType() : resultTypes[0]),
19588d5c4c2SKareemErgawy-TomTom resTypeID))) {
19688d5c4c2SKareemErgawy-TomTom return failure();
19788d5c4c2SKareemErgawy-TomTom }
19888d5c4c2SKareemErgawy-TomTom operands.push_back(resTypeID);
19988d5c4c2SKareemErgawy-TomTom auto funcID = getOrCreateFunctionID(op.getName());
20088d5c4c2SKareemErgawy-TomTom operands.push_back(funcID);
20188d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(op.function_control()));
20288d5c4c2SKareemErgawy-TomTom operands.push_back(fnTypeID);
2033ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpFunction, operands);
20488d5c4c2SKareemErgawy-TomTom
20588d5c4c2SKareemErgawy-TomTom // Add function name.
20688d5c4c2SKareemErgawy-TomTom if (failed(processName(funcID, op.getName()))) {
20788d5c4c2SKareemErgawy-TomTom return failure();
20888d5c4c2SKareemErgawy-TomTom }
20988d5c4c2SKareemErgawy-TomTom
21088d5c4c2SKareemErgawy-TomTom // Declare the parameters.
21188d5c4c2SKareemErgawy-TomTom for (auto arg : op.getArguments()) {
21288d5c4c2SKareemErgawy-TomTom uint32_t argTypeID = 0;
21388d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), arg.getType(), argTypeID))) {
21488d5c4c2SKareemErgawy-TomTom return failure();
21588d5c4c2SKareemErgawy-TomTom }
21688d5c4c2SKareemErgawy-TomTom auto argValueID = getNextID();
21788d5c4c2SKareemErgawy-TomTom valueIDMap[arg] = argValueID;
2183ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpFunctionParameter,
21988d5c4c2SKareemErgawy-TomTom {argTypeID, argValueID});
22088d5c4c2SKareemErgawy-TomTom }
22188d5c4c2SKareemErgawy-TomTom
22288d5c4c2SKareemErgawy-TomTom // Process the body.
22388d5c4c2SKareemErgawy-TomTom if (op.isExternal()) {
22488d5c4c2SKareemErgawy-TomTom return op.emitError("external function is unhandled");
22588d5c4c2SKareemErgawy-TomTom }
22688d5c4c2SKareemErgawy-TomTom
22788d5c4c2SKareemErgawy-TomTom // Some instructions (e.g., OpVariable) in a function must be in the first
22888d5c4c2SKareemErgawy-TomTom // block in the function. These instructions will be put in functionHeader.
22988d5c4c2SKareemErgawy-TomTom // Thus, we put the label in functionHeader first, and omit it from the first
23088d5c4c2SKareemErgawy-TomTom // block.
2313ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpLabel,
23288d5c4c2SKareemErgawy-TomTom {getOrCreateBlockID(&op.front())});
2333ed47bccSLei Zhang if (failed(processBlock(&op.front(), /*omitLabel=*/true)))
2343ed47bccSLei Zhang return failure();
23588d5c4c2SKareemErgawy-TomTom if (failed(visitInPrettyBlockOrder(
23688d5c4c2SKareemErgawy-TomTom &op.front(), [&](Block *block) { return processBlock(block); },
23788d5c4c2SKareemErgawy-TomTom /*skipHeader=*/true))) {
23888d5c4c2SKareemErgawy-TomTom return failure();
23988d5c4c2SKareemErgawy-TomTom }
24088d5c4c2SKareemErgawy-TomTom
24188d5c4c2SKareemErgawy-TomTom // There might be OpPhi instructions who have value references needing to fix.
2423ed47bccSLei Zhang for (const auto &deferredValue : deferredPhiValues) {
24388d5c4c2SKareemErgawy-TomTom Value value = deferredValue.first;
24488d5c4c2SKareemErgawy-TomTom uint32_t id = getValueID(value);
24588d5c4c2SKareemErgawy-TomTom LLVM_DEBUG(llvm::dbgs() << "[phi] fix reference of value " << value
24688d5c4c2SKareemErgawy-TomTom << " to id = " << id << '\n');
24788d5c4c2SKareemErgawy-TomTom assert(id && "OpPhi references undefined value!");
24888d5c4c2SKareemErgawy-TomTom for (size_t offset : deferredValue.second)
24988d5c4c2SKareemErgawy-TomTom functionBody[offset] = id;
25088d5c4c2SKareemErgawy-TomTom }
25188d5c4c2SKareemErgawy-TomTom deferredPhiValues.clear();
25288d5c4c2SKareemErgawy-TomTom
25388d5c4c2SKareemErgawy-TomTom LLVM_DEBUG(llvm::dbgs() << "-- completed function '" << op.getName()
25488d5c4c2SKareemErgawy-TomTom << "' --\n");
25588d5c4c2SKareemErgawy-TomTom // Insert OpFunctionEnd.
2563ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpFunctionEnd, {});
25788d5c4c2SKareemErgawy-TomTom
25888d5c4c2SKareemErgawy-TomTom functions.append(functionHeader.begin(), functionHeader.end());
25988d5c4c2SKareemErgawy-TomTom functions.append(functionBody.begin(), functionBody.end());
26088d5c4c2SKareemErgawy-TomTom functionHeader.clear();
26188d5c4c2SKareemErgawy-TomTom functionBody.clear();
26288d5c4c2SKareemErgawy-TomTom
26388d5c4c2SKareemErgawy-TomTom return success();
26488d5c4c2SKareemErgawy-TomTom }
26588d5c4c2SKareemErgawy-TomTom
processVariableOp(spirv::VariableOp op)26688d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processVariableOp(spirv::VariableOp op) {
26788d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands;
26888d5c4c2SKareemErgawy-TomTom SmallVector<StringRef, 2> elidedAttrs;
26988d5c4c2SKareemErgawy-TomTom uint32_t resultID = 0;
27088d5c4c2SKareemErgawy-TomTom uint32_t resultTypeID = 0;
27188d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), op.getType(), resultTypeID))) {
27288d5c4c2SKareemErgawy-TomTom return failure();
27388d5c4c2SKareemErgawy-TomTom }
27488d5c4c2SKareemErgawy-TomTom operands.push_back(resultTypeID);
27588d5c4c2SKareemErgawy-TomTom resultID = getNextID();
27688d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult()] = resultID;
27788d5c4c2SKareemErgawy-TomTom operands.push_back(resultID);
27888d5c4c2SKareemErgawy-TomTom auto attr = op->getAttr(spirv::attributeName<spirv::StorageClass>());
27988d5c4c2SKareemErgawy-TomTom if (attr) {
28088d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(
28188d5c4c2SKareemErgawy-TomTom attr.cast<IntegerAttr>().getValue().getZExtValue()));
28288d5c4c2SKareemErgawy-TomTom }
28388d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>());
28488d5c4c2SKareemErgawy-TomTom for (auto arg : op.getODSOperands(0)) {
28588d5c4c2SKareemErgawy-TomTom auto argID = getValueID(arg);
28688d5c4c2SKareemErgawy-TomTom if (!argID) {
28788d5c4c2SKareemErgawy-TomTom return emitError(op.getLoc(), "operand 0 has a use before def");
28888d5c4c2SKareemErgawy-TomTom }
28988d5c4c2SKareemErgawy-TomTom operands.push_back(argID);
29088d5c4c2SKareemErgawy-TomTom }
2913ed47bccSLei Zhang if (failed(emitDebugLine(functionHeader, op.getLoc())))
2923ed47bccSLei Zhang return failure();
2933ed47bccSLei Zhang encodeInstructionInto(functionHeader, spirv::Opcode::OpVariable, operands);
29488d5c4c2SKareemErgawy-TomTom for (auto attr : op->getAttrs()) {
2950c7890c8SRiver Riddle if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
2960c7890c8SRiver Riddle return attr.getName() == elided;
2970c7890c8SRiver Riddle })) {
29888d5c4c2SKareemErgawy-TomTom continue;
29988d5c4c2SKareemErgawy-TomTom }
30088d5c4c2SKareemErgawy-TomTom if (failed(processDecoration(op.getLoc(), resultID, attr))) {
30188d5c4c2SKareemErgawy-TomTom return failure();
30288d5c4c2SKareemErgawy-TomTom }
30388d5c4c2SKareemErgawy-TomTom }
30488d5c4c2SKareemErgawy-TomTom return success();
30588d5c4c2SKareemErgawy-TomTom }
30688d5c4c2SKareemErgawy-TomTom
30788d5c4c2SKareemErgawy-TomTom LogicalResult
processGlobalVariableOp(spirv::GlobalVariableOp varOp)30888d5c4c2SKareemErgawy-TomTom Serializer::processGlobalVariableOp(spirv::GlobalVariableOp varOp) {
30988d5c4c2SKareemErgawy-TomTom // Get TypeID.
31088d5c4c2SKareemErgawy-TomTom uint32_t resultTypeID = 0;
31188d5c4c2SKareemErgawy-TomTom SmallVector<StringRef, 4> elidedAttrs;
31288d5c4c2SKareemErgawy-TomTom if (failed(processType(varOp.getLoc(), varOp.type(), resultTypeID))) {
31388d5c4c2SKareemErgawy-TomTom return failure();
31488d5c4c2SKareemErgawy-TomTom }
31588d5c4c2SKareemErgawy-TomTom
31688d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("type");
31788d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands;
31888d5c4c2SKareemErgawy-TomTom operands.push_back(resultTypeID);
31988d5c4c2SKareemErgawy-TomTom auto resultID = getNextID();
32088d5c4c2SKareemErgawy-TomTom
32188d5c4c2SKareemErgawy-TomTom // Encode the name.
32288d5c4c2SKareemErgawy-TomTom auto varName = varOp.sym_name();
32388d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back(SymbolTable::getSymbolAttrName());
32488d5c4c2SKareemErgawy-TomTom if (failed(processName(resultID, varName))) {
32588d5c4c2SKareemErgawy-TomTom return failure();
32688d5c4c2SKareemErgawy-TomTom }
32788d5c4c2SKareemErgawy-TomTom globalVarIDMap[varName] = resultID;
32888d5c4c2SKareemErgawy-TomTom operands.push_back(resultID);
32988d5c4c2SKareemErgawy-TomTom
33088d5c4c2SKareemErgawy-TomTom // Encode StorageClass.
33188d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(varOp.storageClass()));
33288d5c4c2SKareemErgawy-TomTom
33388d5c4c2SKareemErgawy-TomTom // Encode initialization.
33488d5c4c2SKareemErgawy-TomTom if (auto initializer = varOp.initializer()) {
3356d5fc1e3SKazu Hirata auto initializerID = getVariableID(*initializer);
33688d5c4c2SKareemErgawy-TomTom if (!initializerID) {
33788d5c4c2SKareemErgawy-TomTom return emitError(varOp.getLoc(),
33888d5c4c2SKareemErgawy-TomTom "invalid usage of undefined variable as initializer");
33988d5c4c2SKareemErgawy-TomTom }
34088d5c4c2SKareemErgawy-TomTom operands.push_back(initializerID);
34188d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("initializer");
34288d5c4c2SKareemErgawy-TomTom }
34388d5c4c2SKareemErgawy-TomTom
3443ed47bccSLei Zhang if (failed(emitDebugLine(typesGlobalValues, varOp.getLoc())))
34588d5c4c2SKareemErgawy-TomTom return failure();
3463ed47bccSLei Zhang encodeInstructionInto(typesGlobalValues, spirv::Opcode::OpVariable, operands);
3473ed47bccSLei Zhang elidedAttrs.push_back("initializer");
34888d5c4c2SKareemErgawy-TomTom
34988d5c4c2SKareemErgawy-TomTom // Encode decorations.
35088d5c4c2SKareemErgawy-TomTom for (auto attr : varOp->getAttrs()) {
3510c7890c8SRiver Riddle if (llvm::any_of(elidedAttrs, [&](StringRef elided) {
3520c7890c8SRiver Riddle return attr.getName() == elided;
3530c7890c8SRiver Riddle })) {
35488d5c4c2SKareemErgawy-TomTom continue;
35588d5c4c2SKareemErgawy-TomTom }
35688d5c4c2SKareemErgawy-TomTom if (failed(processDecoration(varOp.getLoc(), resultID, attr))) {
35788d5c4c2SKareemErgawy-TomTom return failure();
35888d5c4c2SKareemErgawy-TomTom }
35988d5c4c2SKareemErgawy-TomTom }
36088d5c4c2SKareemErgawy-TomTom return success();
36188d5c4c2SKareemErgawy-TomTom }
36288d5c4c2SKareemErgawy-TomTom
processSelectionOp(spirv::SelectionOp selectionOp)36388d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processSelectionOp(spirv::SelectionOp selectionOp) {
36488d5c4c2SKareemErgawy-TomTom // Assign <id>s to all blocks so that branches inside the SelectionOp can
36588d5c4c2SKareemErgawy-TomTom // resolve properly.
36688d5c4c2SKareemErgawy-TomTom auto &body = selectionOp.body();
36788d5c4c2SKareemErgawy-TomTom for (Block &block : body)
36888d5c4c2SKareemErgawy-TomTom getOrCreateBlockID(&block);
36988d5c4c2SKareemErgawy-TomTom
37088d5c4c2SKareemErgawy-TomTom auto *headerBlock = selectionOp.getHeaderBlock();
37188d5c4c2SKareemErgawy-TomTom auto *mergeBlock = selectionOp.getMergeBlock();
3725e55a201SLei Zhang auto headerID = getBlockID(headerBlock);
37388d5c4c2SKareemErgawy-TomTom auto mergeID = getBlockID(mergeBlock);
37488d5c4c2SKareemErgawy-TomTom auto loc = selectionOp.getLoc();
37588d5c4c2SKareemErgawy-TomTom
3765e55a201SLei Zhang // This SelectionOp is in some MLIR block with preceding and following ops. In
3775e55a201SLei Zhang // the binary format, it should reside in separate SPIR-V blocks from its
3785e55a201SLei Zhang // preceding and following ops. So we need to emit unconditional branches to
3795e55a201SLei Zhang // jump to this SelectionOp's SPIR-V blocks and jumping back to the normal
3805e55a201SLei Zhang // flow afterwards.
3815e55a201SLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranch, {headerID});
3825e55a201SLei Zhang
38388d5c4c2SKareemErgawy-TomTom // Emit the selection header block, which dominates all other blocks, first.
38488d5c4c2SKareemErgawy-TomTom // We need to emit an OpSelectionMerge instruction before the selection header
38588d5c4c2SKareemErgawy-TomTom // block's terminator.
38688d5c4c2SKareemErgawy-TomTom auto emitSelectionMerge = [&]() {
3873ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, loc)))
3883ed47bccSLei Zhang return failure();
38988d5c4c2SKareemErgawy-TomTom lastProcessedWasMergeInst = true;
3903ed47bccSLei Zhang encodeInstructionInto(
39188d5c4c2SKareemErgawy-TomTom functionBody, spirv::Opcode::OpSelectionMerge,
39288d5c4c2SKareemErgawy-TomTom {mergeID, static_cast<uint32_t>(selectionOp.selection_control())});
3933ed47bccSLei Zhang return success();
39488d5c4c2SKareemErgawy-TomTom };
3955e55a201SLei Zhang if (failed(
3965e55a201SLei Zhang processBlock(headerBlock, /*omitLabel=*/false, emitSelectionMerge)))
39788d5c4c2SKareemErgawy-TomTom return failure();
39888d5c4c2SKareemErgawy-TomTom
39988d5c4c2SKareemErgawy-TomTom // Process all blocks with a depth-first visitor starting from the header
40088d5c4c2SKareemErgawy-TomTom // block. The selection header block and merge block are skipped by this
40188d5c4c2SKareemErgawy-TomTom // visitor.
40288d5c4c2SKareemErgawy-TomTom if (failed(visitInPrettyBlockOrder(
40388d5c4c2SKareemErgawy-TomTom headerBlock, [&](Block *block) { return processBlock(block); },
40488d5c4c2SKareemErgawy-TomTom /*skipHeader=*/true, /*skipBlocks=*/{mergeBlock})))
40588d5c4c2SKareemErgawy-TomTom return failure();
40688d5c4c2SKareemErgawy-TomTom
40788d5c4c2SKareemErgawy-TomTom // There is nothing to do for the merge block in the selection, which just
40888d5c4c2SKareemErgawy-TomTom // contains a spv.mlir.merge op, itself. But we need to have an OpLabel
40988d5c4c2SKareemErgawy-TomTom // instruction to start a new SPIR-V block for ops following this SelectionOp.
41088d5c4c2SKareemErgawy-TomTom // The block should use the <id> for the merge block.
4113ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpLabel, {mergeID});
412731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "done merge ");
413731676b1SLei Zhang LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs()));
414731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "\n");
4153ed47bccSLei Zhang return success();
41688d5c4c2SKareemErgawy-TomTom }
41788d5c4c2SKareemErgawy-TomTom
processLoopOp(spirv::LoopOp loopOp)41888d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processLoopOp(spirv::LoopOp loopOp) {
41988d5c4c2SKareemErgawy-TomTom // Assign <id>s to all blocks so that branches inside the LoopOp can resolve
42088d5c4c2SKareemErgawy-TomTom // properly. We don't need to assign for the entry block, which is just for
42188d5c4c2SKareemErgawy-TomTom // satisfying MLIR region's structural requirement.
42288d5c4c2SKareemErgawy-TomTom auto &body = loopOp.body();
423*5605a1eeSKazu Hirata for (Block &block : llvm::drop_begin(body))
42488d5c4c2SKareemErgawy-TomTom getOrCreateBlockID(&block);
425731676b1SLei Zhang
42688d5c4c2SKareemErgawy-TomTom auto *headerBlock = loopOp.getHeaderBlock();
42788d5c4c2SKareemErgawy-TomTom auto *continueBlock = loopOp.getContinueBlock();
42888d5c4c2SKareemErgawy-TomTom auto *mergeBlock = loopOp.getMergeBlock();
42988d5c4c2SKareemErgawy-TomTom auto headerID = getBlockID(headerBlock);
43088d5c4c2SKareemErgawy-TomTom auto continueID = getBlockID(continueBlock);
43188d5c4c2SKareemErgawy-TomTom auto mergeID = getBlockID(mergeBlock);
43288d5c4c2SKareemErgawy-TomTom auto loc = loopOp.getLoc();
43388d5c4c2SKareemErgawy-TomTom
43488d5c4c2SKareemErgawy-TomTom // This LoopOp is in some MLIR block with preceding and following ops. In the
43588d5c4c2SKareemErgawy-TomTom // binary format, it should reside in separate SPIR-V blocks from its
43688d5c4c2SKareemErgawy-TomTom // preceding and following ops. So we need to emit unconditional branches to
43788d5c4c2SKareemErgawy-TomTom // jump to this LoopOp's SPIR-V blocks and jumping back to the normal flow
43888d5c4c2SKareemErgawy-TomTom // afterwards.
4393ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranch, {headerID});
44088d5c4c2SKareemErgawy-TomTom
44188d5c4c2SKareemErgawy-TomTom // LoopOp's entry block is just there for satisfying MLIR's structural
44288d5c4c2SKareemErgawy-TomTom // requirements so we omit it and start serialization from the loop header
44388d5c4c2SKareemErgawy-TomTom // block.
44488d5c4c2SKareemErgawy-TomTom
44588d5c4c2SKareemErgawy-TomTom // Emit the loop header block, which dominates all other blocks, first. We
44688d5c4c2SKareemErgawy-TomTom // need to emit an OpLoopMerge instruction before the loop header block's
44788d5c4c2SKareemErgawy-TomTom // terminator.
44888d5c4c2SKareemErgawy-TomTom auto emitLoopMerge = [&]() {
4493ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, loc)))
4503ed47bccSLei Zhang return failure();
45188d5c4c2SKareemErgawy-TomTom lastProcessedWasMergeInst = true;
4523ed47bccSLei Zhang encodeInstructionInto(
45388d5c4c2SKareemErgawy-TomTom functionBody, spirv::Opcode::OpLoopMerge,
45488d5c4c2SKareemErgawy-TomTom {mergeID, continueID, static_cast<uint32_t>(loopOp.loop_control())});
4553ed47bccSLei Zhang return success();
45688d5c4c2SKareemErgawy-TomTom };
45788d5c4c2SKareemErgawy-TomTom if (failed(processBlock(headerBlock, /*omitLabel=*/false, emitLoopMerge)))
45888d5c4c2SKareemErgawy-TomTom return failure();
45988d5c4c2SKareemErgawy-TomTom
46088d5c4c2SKareemErgawy-TomTom // Process all blocks with a depth-first visitor starting from the header
46188d5c4c2SKareemErgawy-TomTom // block. The loop header block, loop continue block, and loop merge block are
46288d5c4c2SKareemErgawy-TomTom // skipped by this visitor and handled later in this function.
46388d5c4c2SKareemErgawy-TomTom if (failed(visitInPrettyBlockOrder(
46488d5c4c2SKareemErgawy-TomTom headerBlock, [&](Block *block) { return processBlock(block); },
46588d5c4c2SKareemErgawy-TomTom /*skipHeader=*/true, /*skipBlocks=*/{continueBlock, mergeBlock})))
46688d5c4c2SKareemErgawy-TomTom return failure();
46788d5c4c2SKareemErgawy-TomTom
46888d5c4c2SKareemErgawy-TomTom // We have handled all other blocks. Now get to the loop continue block.
46988d5c4c2SKareemErgawy-TomTom if (failed(processBlock(continueBlock)))
47088d5c4c2SKareemErgawy-TomTom return failure();
47188d5c4c2SKareemErgawy-TomTom
47288d5c4c2SKareemErgawy-TomTom // There is nothing to do for the merge block in the loop, which just contains
47388d5c4c2SKareemErgawy-TomTom // a spv.mlir.merge op, itself. But we need to have an OpLabel instruction to
47488d5c4c2SKareemErgawy-TomTom // start a new SPIR-V block for ops following this LoopOp. The block should
47588d5c4c2SKareemErgawy-TomTom // use the <id> for the merge block.
4763ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpLabel, {mergeID});
477731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "done merge ");
478731676b1SLei Zhang LLVM_DEBUG(printBlock(mergeBlock, llvm::dbgs()));
479731676b1SLei Zhang LLVM_DEBUG(llvm::dbgs() << "\n");
4803ed47bccSLei Zhang return success();
48188d5c4c2SKareemErgawy-TomTom }
48288d5c4c2SKareemErgawy-TomTom
processBranchConditionalOp(spirv::BranchConditionalOp condBranchOp)48388d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processBranchConditionalOp(
48488d5c4c2SKareemErgawy-TomTom spirv::BranchConditionalOp condBranchOp) {
48588d5c4c2SKareemErgawy-TomTom auto conditionID = getValueID(condBranchOp.condition());
48688d5c4c2SKareemErgawy-TomTom auto trueLabelID = getOrCreateBlockID(condBranchOp.getTrueBlock());
48788d5c4c2SKareemErgawy-TomTom auto falseLabelID = getOrCreateBlockID(condBranchOp.getFalseBlock());
48888d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 5> arguments{conditionID, trueLabelID, falseLabelID};
48988d5c4c2SKareemErgawy-TomTom
49088d5c4c2SKareemErgawy-TomTom if (auto weights = condBranchOp.branch_weights()) {
49188d5c4c2SKareemErgawy-TomTom for (auto val : weights->getValue())
49288d5c4c2SKareemErgawy-TomTom arguments.push_back(val.cast<IntegerAttr>().getInt());
49388d5c4c2SKareemErgawy-TomTom }
49488d5c4c2SKareemErgawy-TomTom
4953ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, condBranchOp.getLoc())))
4963ed47bccSLei Zhang return failure();
4973ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranchConditional,
49888d5c4c2SKareemErgawy-TomTom arguments);
4993ed47bccSLei Zhang return success();
50088d5c4c2SKareemErgawy-TomTom }
50188d5c4c2SKareemErgawy-TomTom
processBranchOp(spirv::BranchOp branchOp)50288d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processBranchOp(spirv::BranchOp branchOp) {
5033ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, branchOp.getLoc())))
5043ed47bccSLei Zhang return failure();
5053ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpBranch,
50688d5c4c2SKareemErgawy-TomTom {getOrCreateBlockID(branchOp.getTarget())});
5073ed47bccSLei Zhang return success();
50888d5c4c2SKareemErgawy-TomTom }
50988d5c4c2SKareemErgawy-TomTom
processAddressOfOp(spirv::AddressOfOp addressOfOp)51088d5c4c2SKareemErgawy-TomTom LogicalResult Serializer::processAddressOfOp(spirv::AddressOfOp addressOfOp) {
51188d5c4c2SKareemErgawy-TomTom auto varName = addressOfOp.variable();
51288d5c4c2SKareemErgawy-TomTom auto variableID = getVariableID(varName);
51388d5c4c2SKareemErgawy-TomTom if (!variableID) {
51488d5c4c2SKareemErgawy-TomTom return addressOfOp.emitError("unknown result <id> for variable ")
51588d5c4c2SKareemErgawy-TomTom << varName;
51688d5c4c2SKareemErgawy-TomTom }
51788d5c4c2SKareemErgawy-TomTom valueIDMap[addressOfOp.pointer()] = variableID;
51888d5c4c2SKareemErgawy-TomTom return success();
51988d5c4c2SKareemErgawy-TomTom }
52088d5c4c2SKareemErgawy-TomTom
52188d5c4c2SKareemErgawy-TomTom LogicalResult
processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp)52288d5c4c2SKareemErgawy-TomTom Serializer::processReferenceOfOp(spirv::ReferenceOfOp referenceOfOp) {
52388d5c4c2SKareemErgawy-TomTom auto constName = referenceOfOp.spec_const();
52488d5c4c2SKareemErgawy-TomTom auto constID = getSpecConstID(constName);
52588d5c4c2SKareemErgawy-TomTom if (!constID) {
52688d5c4c2SKareemErgawy-TomTom return referenceOfOp.emitError(
52788d5c4c2SKareemErgawy-TomTom "unknown result <id> for specialization constant ")
52888d5c4c2SKareemErgawy-TomTom << constName;
52988d5c4c2SKareemErgawy-TomTom }
53088d5c4c2SKareemErgawy-TomTom valueIDMap[referenceOfOp.reference()] = constID;
53188d5c4c2SKareemErgawy-TomTom return success();
53288d5c4c2SKareemErgawy-TomTom }
53388d5c4c2SKareemErgawy-TomTom
53488d5c4c2SKareemErgawy-TomTom template <>
53588d5c4c2SKareemErgawy-TomTom LogicalResult
processOp(spirv::EntryPointOp op)53688d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::EntryPointOp>(spirv::EntryPointOp op) {
53788d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands;
53888d5c4c2SKareemErgawy-TomTom // Add the ExecutionModel.
53988d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(op.execution_model()));
54088d5c4c2SKareemErgawy-TomTom // Add the function <id>.
54188d5c4c2SKareemErgawy-TomTom auto funcID = getFunctionID(op.fn());
54288d5c4c2SKareemErgawy-TomTom if (!funcID) {
54388d5c4c2SKareemErgawy-TomTom return op.emitError("missing <id> for function ")
54488d5c4c2SKareemErgawy-TomTom << op.fn()
54588d5c4c2SKareemErgawy-TomTom << "; function needs to be defined before spv.EntryPoint is "
54688d5c4c2SKareemErgawy-TomTom "serialized";
54788d5c4c2SKareemErgawy-TomTom }
54888d5c4c2SKareemErgawy-TomTom operands.push_back(funcID);
54988d5c4c2SKareemErgawy-TomTom // Add the name of the function.
5503ed47bccSLei Zhang spirv::encodeStringLiteralInto(operands, op.fn());
55188d5c4c2SKareemErgawy-TomTom
55288d5c4c2SKareemErgawy-TomTom // Add the interface values.
55388d5c4c2SKareemErgawy-TomTom if (auto interface = op.interface()) {
55488d5c4c2SKareemErgawy-TomTom for (auto var : interface.getValue()) {
55588d5c4c2SKareemErgawy-TomTom auto id = getVariableID(var.cast<FlatSymbolRefAttr>().getValue());
55688d5c4c2SKareemErgawy-TomTom if (!id) {
55788d5c4c2SKareemErgawy-TomTom return op.emitError("referencing undefined global variable."
55888d5c4c2SKareemErgawy-TomTom "spv.EntryPoint is at the end of spv.module. All "
55988d5c4c2SKareemErgawy-TomTom "referenced variables should already be defined");
56088d5c4c2SKareemErgawy-TomTom }
56188d5c4c2SKareemErgawy-TomTom operands.push_back(id);
56288d5c4c2SKareemErgawy-TomTom }
56388d5c4c2SKareemErgawy-TomTom }
5643ed47bccSLei Zhang encodeInstructionInto(entryPoints, spirv::Opcode::OpEntryPoint, operands);
5653ed47bccSLei Zhang return success();
56688d5c4c2SKareemErgawy-TomTom }
56788d5c4c2SKareemErgawy-TomTom
56888d5c4c2SKareemErgawy-TomTom template <>
56988d5c4c2SKareemErgawy-TomTom LogicalResult
processOp(spirv::ControlBarrierOp op)57088d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::ControlBarrierOp>(spirv::ControlBarrierOp op) {
57188d5c4c2SKareemErgawy-TomTom StringRef argNames[] = {"execution_scope", "memory_scope",
57288d5c4c2SKareemErgawy-TomTom "memory_semantics"};
57388d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 3> operands;
57488d5c4c2SKareemErgawy-TomTom
57588d5c4c2SKareemErgawy-TomTom for (auto argName : argNames) {
57688d5c4c2SKareemErgawy-TomTom auto argIntAttr = op->getAttrOfType<IntegerAttr>(argName);
57788d5c4c2SKareemErgawy-TomTom auto operand = prepareConstantInt(op.getLoc(), argIntAttr);
57888d5c4c2SKareemErgawy-TomTom if (!operand) {
57988d5c4c2SKareemErgawy-TomTom return failure();
58088d5c4c2SKareemErgawy-TomTom }
58188d5c4c2SKareemErgawy-TomTom operands.push_back(operand);
58288d5c4c2SKareemErgawy-TomTom }
58388d5c4c2SKareemErgawy-TomTom
5843ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpControlBarrier,
58588d5c4c2SKareemErgawy-TomTom operands);
5863ed47bccSLei Zhang return success();
58788d5c4c2SKareemErgawy-TomTom }
58888d5c4c2SKareemErgawy-TomTom
58988d5c4c2SKareemErgawy-TomTom template <>
59088d5c4c2SKareemErgawy-TomTom LogicalResult
processOp(spirv::ExecutionModeOp op)59188d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::ExecutionModeOp>(spirv::ExecutionModeOp op) {
59288d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands;
59388d5c4c2SKareemErgawy-TomTom // Add the function <id>.
59488d5c4c2SKareemErgawy-TomTom auto funcID = getFunctionID(op.fn());
59588d5c4c2SKareemErgawy-TomTom if (!funcID) {
59688d5c4c2SKareemErgawy-TomTom return op.emitError("missing <id> for function ")
59788d5c4c2SKareemErgawy-TomTom << op.fn()
59888d5c4c2SKareemErgawy-TomTom << "; function needs to be serialized before ExecutionModeOp is "
59988d5c4c2SKareemErgawy-TomTom "serialized";
60088d5c4c2SKareemErgawy-TomTom }
60188d5c4c2SKareemErgawy-TomTom operands.push_back(funcID);
60288d5c4c2SKareemErgawy-TomTom // Add the ExecutionMode.
60388d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(op.execution_mode()));
60488d5c4c2SKareemErgawy-TomTom
60588d5c4c2SKareemErgawy-TomTom // Serialize values if any.
60688d5c4c2SKareemErgawy-TomTom auto values = op.values();
60788d5c4c2SKareemErgawy-TomTom if (values) {
60888d5c4c2SKareemErgawy-TomTom for (auto &intVal : values.getValue()) {
60988d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(
61088d5c4c2SKareemErgawy-TomTom intVal.cast<IntegerAttr>().getValue().getZExtValue()));
61188d5c4c2SKareemErgawy-TomTom }
61288d5c4c2SKareemErgawy-TomTom }
6133ed47bccSLei Zhang encodeInstructionInto(executionModes, spirv::Opcode::OpExecutionMode,
61488d5c4c2SKareemErgawy-TomTom operands);
6153ed47bccSLei Zhang return success();
61688d5c4c2SKareemErgawy-TomTom }
61788d5c4c2SKareemErgawy-TomTom
61888d5c4c2SKareemErgawy-TomTom template <>
61988d5c4c2SKareemErgawy-TomTom LogicalResult
processOp(spirv::MemoryBarrierOp op)62088d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::MemoryBarrierOp>(spirv::MemoryBarrierOp op) {
62188d5c4c2SKareemErgawy-TomTom StringRef argNames[] = {"memory_scope", "memory_semantics"};
62288d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 2> operands;
62388d5c4c2SKareemErgawy-TomTom
62488d5c4c2SKareemErgawy-TomTom for (auto argName : argNames) {
62588d5c4c2SKareemErgawy-TomTom auto argIntAttr = op->getAttrOfType<IntegerAttr>(argName);
62688d5c4c2SKareemErgawy-TomTom auto operand = prepareConstantInt(op.getLoc(), argIntAttr);
62788d5c4c2SKareemErgawy-TomTom if (!operand) {
62888d5c4c2SKareemErgawy-TomTom return failure();
62988d5c4c2SKareemErgawy-TomTom }
63088d5c4c2SKareemErgawy-TomTom operands.push_back(operand);
63188d5c4c2SKareemErgawy-TomTom }
63288d5c4c2SKareemErgawy-TomTom
6333ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpMemoryBarrier, operands);
6343ed47bccSLei Zhang return success();
63588d5c4c2SKareemErgawy-TomTom }
63688d5c4c2SKareemErgawy-TomTom
63788d5c4c2SKareemErgawy-TomTom template <>
63888d5c4c2SKareemErgawy-TomTom LogicalResult
processOp(spirv::FunctionCallOp op)63988d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::FunctionCallOp>(spirv::FunctionCallOp op) {
64088d5c4c2SKareemErgawy-TomTom auto funcName = op.callee();
64188d5c4c2SKareemErgawy-TomTom uint32_t resTypeID = 0;
64288d5c4c2SKareemErgawy-TomTom
64388d5c4c2SKareemErgawy-TomTom Type resultTy = op.getNumResults() ? *op.result_type_begin() : getVoidType();
64488d5c4c2SKareemErgawy-TomTom if (failed(processType(op.getLoc(), resultTy, resTypeID)))
64588d5c4c2SKareemErgawy-TomTom return failure();
64688d5c4c2SKareemErgawy-TomTom
64788d5c4c2SKareemErgawy-TomTom auto funcID = getOrCreateFunctionID(funcName);
64888d5c4c2SKareemErgawy-TomTom auto funcCallID = getNextID();
64988d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 8> operands{resTypeID, funcCallID, funcID};
65088d5c4c2SKareemErgawy-TomTom
65188d5c4c2SKareemErgawy-TomTom for (auto value : op.arguments()) {
65288d5c4c2SKareemErgawy-TomTom auto valueID = getValueID(value);
65388d5c4c2SKareemErgawy-TomTom assert(valueID && "cannot find a value for spv.FunctionCall");
65488d5c4c2SKareemErgawy-TomTom operands.push_back(valueID);
65588d5c4c2SKareemErgawy-TomTom }
65688d5c4c2SKareemErgawy-TomTom
65788d5c4c2SKareemErgawy-TomTom if (!resultTy.isa<NoneType>())
65888d5c4c2SKareemErgawy-TomTom valueIDMap[op.getResult(0)] = funcCallID;
65988d5c4c2SKareemErgawy-TomTom
6603ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpFunctionCall, operands);
6613ed47bccSLei Zhang return success();
66288d5c4c2SKareemErgawy-TomTom }
66388d5c4c2SKareemErgawy-TomTom
66488d5c4c2SKareemErgawy-TomTom template <>
66588d5c4c2SKareemErgawy-TomTom LogicalResult
processOp(spirv::CopyMemoryOp op)66688d5c4c2SKareemErgawy-TomTom Serializer::processOp<spirv::CopyMemoryOp>(spirv::CopyMemoryOp op) {
66788d5c4c2SKareemErgawy-TomTom SmallVector<uint32_t, 4> operands;
66888d5c4c2SKareemErgawy-TomTom SmallVector<StringRef, 2> elidedAttrs;
66988d5c4c2SKareemErgawy-TomTom
67088d5c4c2SKareemErgawy-TomTom for (Value operand : op->getOperands()) {
67188d5c4c2SKareemErgawy-TomTom auto id = getValueID(operand);
67288d5c4c2SKareemErgawy-TomTom assert(id && "use before def!");
67388d5c4c2SKareemErgawy-TomTom operands.push_back(id);
67488d5c4c2SKareemErgawy-TomTom }
67588d5c4c2SKareemErgawy-TomTom
67688d5c4c2SKareemErgawy-TomTom if (auto attr = op->getAttr("memory_access")) {
67788d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(
67888d5c4c2SKareemErgawy-TomTom attr.cast<IntegerAttr>().getValue().getZExtValue()));
67988d5c4c2SKareemErgawy-TomTom }
68088d5c4c2SKareemErgawy-TomTom
68188d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("memory_access");
68288d5c4c2SKareemErgawy-TomTom
68388d5c4c2SKareemErgawy-TomTom if (auto attr = op->getAttr("alignment")) {
68488d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(
68588d5c4c2SKareemErgawy-TomTom attr.cast<IntegerAttr>().getValue().getZExtValue()));
68688d5c4c2SKareemErgawy-TomTom }
68788d5c4c2SKareemErgawy-TomTom
68888d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("alignment");
68988d5c4c2SKareemErgawy-TomTom
69088d5c4c2SKareemErgawy-TomTom if (auto attr = op->getAttr("source_memory_access")) {
69188d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(
69288d5c4c2SKareemErgawy-TomTom attr.cast<IntegerAttr>().getValue().getZExtValue()));
69388d5c4c2SKareemErgawy-TomTom }
69488d5c4c2SKareemErgawy-TomTom
69588d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("source_memory_access");
69688d5c4c2SKareemErgawy-TomTom
69788d5c4c2SKareemErgawy-TomTom if (auto attr = op->getAttr("source_alignment")) {
69888d5c4c2SKareemErgawy-TomTom operands.push_back(static_cast<uint32_t>(
69988d5c4c2SKareemErgawy-TomTom attr.cast<IntegerAttr>().getValue().getZExtValue()));
70088d5c4c2SKareemErgawy-TomTom }
70188d5c4c2SKareemErgawy-TomTom
70288d5c4c2SKareemErgawy-TomTom elidedAttrs.push_back("source_alignment");
7033ed47bccSLei Zhang if (failed(emitDebugLine(functionBody, op.getLoc())))
7043ed47bccSLei Zhang return failure();
7053ed47bccSLei Zhang encodeInstructionInto(functionBody, spirv::Opcode::OpCopyMemory, operands);
70688d5c4c2SKareemErgawy-TomTom
70788d5c4c2SKareemErgawy-TomTom return success();
70888d5c4c2SKareemErgawy-TomTom }
70988d5c4c2SKareemErgawy-TomTom
71088d5c4c2SKareemErgawy-TomTom // Pull in auto-generated Serializer::dispatchToAutogenSerialization() and
71188d5c4c2SKareemErgawy-TomTom // various Serializer::processOp<...>() specializations.
71288d5c4c2SKareemErgawy-TomTom #define GET_SERIALIZATION_FNS
71388d5c4c2SKareemErgawy-TomTom #include "mlir/Dialect/SPIRV/IR/SPIRVSerialization.inc"
71488d5c4c2SKareemErgawy-TomTom
71588d5c4c2SKareemErgawy-TomTom } // namespace spirv
71688d5c4c2SKareemErgawy-TomTom } // namespace mlir
717