166 lines · cpp
1//===- SPIRVOpDefinition.cpp - MLIR SPIR-V Op Definition Implementation ---===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Defines the TableGen'erated SPIR-V op implementation in the SPIR-V dialect.10// These are placed in a separate file to reduce the total amount of code in11// SPIRVOps.cpp and make that file faster to recompile.12//13//===----------------------------------------------------------------------===//14 15#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"16 17#include "SPIRVParsingUtils.h"18 19#include "mlir/IR/TypeUtilities.h"20 21namespace mlir::spirv {22/// Returns true if the given op is a function-like op or nested in a23/// function-like op without a module-like op in the middle.24static bool isNestedInFunctionOpInterface(Operation *op) {25 if (!op)26 return false;27 if (op->hasTrait<OpTrait::SymbolTable>())28 return false;29 if (isa<FunctionOpInterface>(op))30 return true;31 return isNestedInFunctionOpInterface(op->getParentOp());32}33 34/// Returns true if the given op is a GraphARM op or nested in a35/// GraphARM op without a module-like op in the middle.36static bool isNestedInGraphARMOpInterface(Operation *op) {37 if (!op)38 return false;39 if (op->hasTrait<OpTrait::SymbolTable>())40 return false;41 if (isa<spirv::GraphARMOp>(op))42 return true;43 return isNestedInGraphARMOpInterface(op->getParentOp());44}45 46/// Returns true if the given op is an module-like op that maintains a symbol47/// table.48static bool isDirectInModuleLikeOp(Operation *op) {49 return op && op->hasTrait<OpTrait::SymbolTable>();50}51 52/// Result of a logical op must be a scalar or vector of boolean type.53static Type getUnaryOpResultType(Type operandType) {54 Builder builder(operandType.getContext());55 Type resultType = builder.getIntegerType(1);56 if (auto vecType = llvm::dyn_cast<VectorType>(operandType))57 return VectorType::get(vecType.getNumElements(), resultType);58 return resultType;59}60 61static ParseResult parseImageOperands(OpAsmParser &parser,62 spirv::ImageOperandsAttr &attr) {63 // Expect image operands64 if (parser.parseOptionalLSquare())65 return success();66 67 spirv::ImageOperands imageOperands;68 if (parseEnumStrAttr(imageOperands, parser))69 return failure();70 71 attr = spirv::ImageOperandsAttr::get(parser.getContext(), imageOperands);72 73 return parser.parseRSquare();74}75 76static void printImageOperands(OpAsmPrinter &printer, Operation *imageOp,77 spirv::ImageOperandsAttr attr) {78 if (attr) {79 auto strImageOperands = stringifyImageOperands(attr.getValue());80 printer << "[\"" << strImageOperands << "\"]";81 }82}83 84/// Adapted from the cf.switch implementation.85/// <cases> ::= `default` `:` bb-id (`(` ssa-use-and-type-list `)`)?86/// ( `,` integer `:` bb-id (`(` ssa-use-and-type-list `)`)? )*87static ParseResult parseSwitchOpCases(88 OpAsmParser &parser, Type &selectorType, Block *&defaultTarget,89 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &defaultOperands,90 SmallVectorImpl<Type> &defaultOperandTypes, DenseIntElementsAttr &literals,91 SmallVectorImpl<Block *> &targets,92 SmallVectorImpl<SmallVector<OpAsmParser::UnresolvedOperand>>93 &targetOperands,94 SmallVectorImpl<SmallVector<Type>> &targetOperandTypes) {95 if (parser.parseKeyword("default") || parser.parseColon() ||96 parser.parseSuccessor(defaultTarget))97 return failure();98 if (succeeded(parser.parseOptionalLParen())) {99 if (parser.parseOperandList(defaultOperands, OpAsmParser::Delimiter::None,100 /*allowResultNumber=*/false) ||101 parser.parseColonTypeList(defaultOperandTypes) || parser.parseRParen())102 return failure();103 }104 105 SmallVector<APInt> values;106 unsigned bitWidth = selectorType.getIntOrFloatBitWidth();107 while (succeeded(parser.parseOptionalComma())) {108 int64_t value = 0;109 if (failed(parser.parseInteger(value)))110 return failure();111 values.push_back(APInt(bitWidth, value, /*isSigned=*/true));112 113 Block *target;114 SmallVector<OpAsmParser::UnresolvedOperand> operands;115 SmallVector<Type> operandTypes;116 if (failed(parser.parseColon()) || failed(parser.parseSuccessor(target)))117 return failure();118 if (succeeded(parser.parseOptionalLParen())) {119 if (failed(parser.parseOperandList(operands,120 OpAsmParser::Delimiter::None)) ||121 failed(parser.parseColonTypeList(operandTypes)) ||122 failed(parser.parseRParen()))123 return failure();124 }125 targets.push_back(target);126 targetOperands.emplace_back(operands);127 targetOperandTypes.emplace_back(operandTypes);128 }129 130 if (!values.empty()) {131 ShapedType literalType =132 VectorType::get(static_cast<int64_t>(values.size()), selectorType);133 literals = DenseIntElementsAttr::get(literalType, values);134 }135 return success();136}137 138static void139printSwitchOpCases(OpAsmPrinter &p, SwitchOp op, Type selectorType,140 Block *defaultTarget, OperandRange defaultOperands,141 TypeRange defaultOperandTypes, DenseIntElementsAttr literals,142 SuccessorRange targets, OperandRangeRange targetOperands,143 const TypeRangeRange &targetOperandTypes) {144 p << " default: ";145 p.printSuccessorAndUseList(defaultTarget, defaultOperands);146 147 if (!literals)148 return;149 150 for (auto [index, literal] : llvm::enumerate(literals.getValues<APInt>())) {151 p << ',';152 p.printNewline();153 p << " ";154 p << literal.getLimitedValue();155 p << ": ";156 p.printSuccessorAndUseList(targets[index], targetOperands[index]);157 }158 p.printNewline();159}160 161} // namespace mlir::spirv162 163// TablenGen'erated operation definitions.164#define GET_OP_CLASSES165#include "mlir/Dialect/SPIRV/IR/SPIRVOps.cpp.inc"166