brintos

brintos / llvm-project-archived public Read only

0
0
Text · 80.3 KiB · 938952e Raw
2146 lines · cpp
1//===- SPIRVOps.cpp - MLIR SPIR-V operations ------------------------------===//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// This file defines the operations in the SPIR-V dialect.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"14 15#include "SPIRVOpUtils.h"16#include "SPIRVParsingUtils.h"17 18#include "mlir/Dialect/SPIRV/IR/SPIRVAttributes.h"19#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"20#include "mlir/Dialect/SPIRV/IR/SPIRVEnums.h"21#include "mlir/Dialect/SPIRV/IR/SPIRVOpTraits.h"22#include "mlir/Dialect/SPIRV/IR/SPIRVTypes.h"23#include "mlir/Dialect/SPIRV/IR/TargetAndABI.h"24#include "mlir/IR/Builders.h"25#include "mlir/IR/BuiltinTypes.h"26#include "mlir/IR/OpDefinition.h"27#include "mlir/IR/OpImplementation.h"28#include "mlir/IR/Operation.h"29#include "mlir/IR/TypeUtilities.h"30#include "mlir/Interfaces/FunctionImplementation.h"31#include "llvm/ADT/APFloat.h"32#include "llvm/ADT/APInt.h"33#include "llvm/ADT/ArrayRef.h"34#include "llvm/ADT/STLExtras.h"35#include "llvm/ADT/StringExtras.h"36#include "llvm/ADT/TypeSwitch.h"37#include "llvm/Support/InterleavedRange.h"38#include <cassert>39#include <numeric>40#include <optional>41 42using namespace mlir;43using namespace mlir::spirv::AttrNames;44 45//===----------------------------------------------------------------------===//46// Common utility functions47//===----------------------------------------------------------------------===//48 49LogicalResult spirv::extractValueFromConstOp(Operation *op, int32_t &value) {50  auto constOp = dyn_cast_or_null<spirv::ConstantOp>(op);51  if (!constOp) {52    return failure();53  }54  auto valueAttr = constOp.getValue();55  auto integerValueAttr = llvm::dyn_cast<IntegerAttr>(valueAttr);56  if (!integerValueAttr) {57    return failure();58  }59 60  if (integerValueAttr.getType().isSignlessInteger())61    value = integerValueAttr.getInt();62  else63    value = integerValueAttr.getSInt();64 65  return success();66}67 68LogicalResult69spirv::verifyMemorySemantics(Operation *op,70                             spirv::MemorySemantics memorySemantics) {71  // According to the SPIR-V specification:72  // "Despite being a mask and allowing multiple bits to be combined, it is73  // invalid for more than one of these four bits to be set: Acquire, Release,74  // AcquireRelease, or SequentiallyConsistent. Requesting both Acquire and75  // Release semantics is done by setting the AcquireRelease bit, not by setting76  // two bits."77  auto atMostOneInSet = spirv::MemorySemantics::Acquire |78                        spirv::MemorySemantics::Release |79                        spirv::MemorySemantics::AcquireRelease |80                        spirv::MemorySemantics::SequentiallyConsistent;81 82  auto bitCount =83      llvm::popcount(static_cast<uint32_t>(memorySemantics & atMostOneInSet));84  if (bitCount > 1) {85    return op->emitError(86        "expected at most one of these four memory constraints "87        "to be set: `Acquire`, `Release`,"88        "`AcquireRelease` or `SequentiallyConsistent`");89  }90  return success();91}92 93void spirv::printVariableDecorations(Operation *op, OpAsmPrinter &printer,94                                     SmallVectorImpl<StringRef> &elidedAttrs) {95  // Print optional descriptor binding96  auto descriptorSetName = llvm::convertToSnakeFromCamelCase(97      stringifyDecoration(spirv::Decoration::DescriptorSet));98  auto bindingName = llvm::convertToSnakeFromCamelCase(99      stringifyDecoration(spirv::Decoration::Binding));100  auto descriptorSet = op->getAttrOfType<IntegerAttr>(descriptorSetName);101  auto binding = op->getAttrOfType<IntegerAttr>(bindingName);102  if (descriptorSet && binding) {103    elidedAttrs.push_back(descriptorSetName);104    elidedAttrs.push_back(bindingName);105    printer << " bind(" << descriptorSet.getInt() << ", " << binding.getInt()106            << ")";107  }108 109  // Print BuiltIn attribute if present110  auto builtInName = llvm::convertToSnakeFromCamelCase(111      stringifyDecoration(spirv::Decoration::BuiltIn));112  if (auto builtin = op->getAttrOfType<StringAttr>(builtInName)) {113    printer << " " << builtInName << "(\"" << builtin.getValue() << "\")";114    elidedAttrs.push_back(builtInName);115  }116 117  printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);118}119 120static ParseResult parseOneResultSameOperandTypeOp(OpAsmParser &parser,121                                                   OperationState &result) {122  SmallVector<OpAsmParser::UnresolvedOperand, 2> ops;123  Type type;124  // If the operand list is in-between parentheses, then we have a generic form.125  // (see the fallback in `printOneResultOp`).126  SMLoc loc = parser.getCurrentLocation();127  if (!parser.parseOptionalLParen()) {128    if (parser.parseOperandList(ops) || parser.parseRParen() ||129        parser.parseOptionalAttrDict(result.attributes) ||130        parser.parseColon() || parser.parseType(type))131      return failure();132    auto fnType = llvm::dyn_cast<FunctionType>(type);133    if (!fnType) {134      parser.emitError(loc, "expected function type");135      return failure();136    }137    if (parser.resolveOperands(ops, fnType.getInputs(), loc, result.operands))138      return failure();139    result.addTypes(fnType.getResults());140    return success();141  }142  return failure(parser.parseOperandList(ops) ||143                 parser.parseOptionalAttrDict(result.attributes) ||144                 parser.parseColonType(type) ||145                 parser.resolveOperands(ops, type, result.operands) ||146                 parser.addTypeToList(type, result.types));147}148 149static void printOneResultOp(Operation *op, OpAsmPrinter &p) {150  assert(op->getNumResults() == 1 && "op should have one result");151 152  // If not all the operand and result types are the same, just use the153  // generic assembly form to avoid omitting information in printing.154  auto resultType = op->getResult(0).getType();155  if (llvm::any_of(op->getOperandTypes(),156                   [&](Type type) { return type != resultType; })) {157    p.printGenericOp(op, /*printOpName=*/false);158    return;159  }160 161  p << ' ';162  p.printOperands(op->getOperands());163  p.printOptionalAttrDict(op->getAttrs());164  // Now we can output only one type for all operands and the result.165  p << " : " << resultType;166}167 168template <typename BlockReadWriteOpTy>169static LogicalResult verifyBlockReadWritePtrAndValTypes(BlockReadWriteOpTy op,170                                                        Value ptr, Value val) {171  auto valType = val.getType();172  if (auto valVecTy = llvm::dyn_cast<VectorType>(valType))173    valType = valVecTy.getElementType();174 175  if (valType !=176      llvm::cast<spirv::PointerType>(ptr.getType()).getPointeeType()) {177    return op.emitOpError("mismatch in result type and pointer type");178  }179  return success();180}181 182/// Walks the given type hierarchy with the given indices, potentially down183/// to component granularity, to select an element type. Returns null type and184/// emits errors with the given loc on failure.185static Type186getElementType(Type type, ArrayRef<int32_t> indices,187               function_ref<InFlightDiagnostic(StringRef)> emitErrorFn) {188  if (indices.empty()) {189    emitErrorFn("expected at least one index for spirv.CompositeExtract");190    return nullptr;191  }192 193  for (auto index : indices) {194    if (auto cType = llvm::dyn_cast<spirv::CompositeType>(type)) {195      if (cType.hasCompileTimeKnownNumElements() &&196          (index < 0 ||197           static_cast<uint64_t>(index) >= cType.getNumElements())) {198        emitErrorFn("index ") << index << " out of bounds for " << type;199        return nullptr;200      }201      type = cType.getElementType(index);202    } else {203      emitErrorFn("cannot extract from non-composite type ")204          << type << " with index " << index;205      return nullptr;206    }207  }208  return type;209}210 211static Type212getElementType(Type type, Attribute indices,213               function_ref<InFlightDiagnostic(StringRef)> emitErrorFn) {214  auto indicesArrayAttr = llvm::dyn_cast<ArrayAttr>(indices);215  if (!indicesArrayAttr) {216    emitErrorFn("expected a 32-bit integer array attribute for 'indices'");217    return nullptr;218  }219  if (indicesArrayAttr.empty()) {220    emitErrorFn("expected at least one index for spirv.CompositeExtract");221    return nullptr;222  }223 224  SmallVector<int32_t, 2> indexVals;225  for (auto indexAttr : indicesArrayAttr) {226    auto indexIntAttr = llvm::dyn_cast<IntegerAttr>(indexAttr);227    if (!indexIntAttr) {228      emitErrorFn("expected an 32-bit integer for index, but found '")229          << indexAttr << "'";230      return nullptr;231    }232    indexVals.push_back(indexIntAttr.getInt());233  }234  return getElementType(type, indexVals, emitErrorFn);235}236 237static Type getElementType(Type type, Attribute indices, Location loc) {238  auto errorFn = [&](StringRef err) -> InFlightDiagnostic {239    return ::mlir::emitError(loc, err);240  };241  return getElementType(type, indices, errorFn);242}243 244static Type getElementType(Type type, Attribute indices, OpAsmParser &parser,245                           SMLoc loc) {246  auto errorFn = [&](StringRef err) -> InFlightDiagnostic {247    return parser.emitError(loc, err);248  };249  return getElementType(type, indices, errorFn);250}251 252template <typename ExtendedBinaryOp>253static LogicalResult verifyArithmeticExtendedBinaryOp(ExtendedBinaryOp op) {254  auto resultType = llvm::cast<spirv::StructType>(op.getType());255  if (resultType.getNumElements() != 2)256    return op.emitOpError("expected result struct type containing two members");257 258  if (!llvm::all_equal({op.getOperand1().getType(), op.getOperand2().getType(),259                        resultType.getElementType(0),260                        resultType.getElementType(1)}))261    return op.emitOpError(262        "expected all operand types and struct member types are the same");263 264  return success();265}266 267static ParseResult parseArithmeticExtendedBinaryOp(OpAsmParser &parser,268                                                   OperationState &result) {269  SmallVector<OpAsmParser::UnresolvedOperand, 2> operands;270  if (parser.parseOptionalAttrDict(result.attributes) ||271      parser.parseOperandList(operands) || parser.parseColon())272    return failure();273 274  Type resultType;275  SMLoc loc = parser.getCurrentLocation();276  if (parser.parseType(resultType))277    return failure();278 279  auto structType = llvm::dyn_cast<spirv::StructType>(resultType);280  if (!structType || structType.getNumElements() != 2)281    return parser.emitError(loc, "expected spirv.struct type with two members");282 283  SmallVector<Type, 2> operandTypes(2, structType.getElementType(0));284  if (parser.resolveOperands(operands, operandTypes, loc, result.operands))285    return failure();286 287  result.addTypes(resultType);288  return success();289}290 291static void printArithmeticExtendedBinaryOp(Operation *op,292                                            OpAsmPrinter &printer) {293  printer << ' ';294  printer.printOptionalAttrDict(op->getAttrs());295  printer.printOperands(op->getOperands());296  printer << " : " << op->getResultTypes().front();297}298 299static LogicalResult verifyShiftOp(Operation *op) {300  if (op->getOperand(0).getType() != op->getResult(0).getType()) {301    return op->emitError("expected the same type for the first operand and "302                         "result, but provided ")303           << op->getOperand(0).getType() << " and "304           << op->getResult(0).getType();305  }306  return success();307}308 309//===----------------------------------------------------------------------===//310// spirv.mlir.addressof311//===----------------------------------------------------------------------===//312 313void spirv::AddressOfOp::build(OpBuilder &builder, OperationState &state,314                               spirv::GlobalVariableOp var) {315  build(builder, state, var.getType(), SymbolRefAttr::get(var));316}317 318LogicalResult spirv::AddressOfOp::verify() {319  auto varOp = dyn_cast_or_null<spirv::GlobalVariableOp>(320      SymbolTable::lookupNearestSymbolFrom((*this)->getParentOp(),321                                           getVariableAttr()));322  if (!varOp) {323    return emitOpError("expected spirv.GlobalVariable symbol");324  }325  if (getPointer().getType() != varOp.getType()) {326    return emitOpError(327        "result type mismatch with the referenced global variable's type");328  }329  return success();330}331 332//===----------------------------------------------------------------------===//333// spirv.CompositeConstruct334//===----------------------------------------------------------------------===//335 336LogicalResult spirv::CompositeConstructOp::verify() {337  operand_range constituents = this->getConstituents();338 339  // There are 4 cases with varying verification rules:340  // 1. Cooperative Matrices (1 constituent)341  // 2. Structs (1 constituent for each member)342  // 3. Arrays (1 constituent for each array element)343  // 4. Vectors (1 constituent (sub-)element for each vector element)344 345  auto coopElementType =346      llvm::TypeSwitch<Type, Type>(getType())347          .Case<spirv::CooperativeMatrixType>(348              [](auto coopType) { return coopType.getElementType(); })349          .Default(nullptr);350 351  // Case 1. -- matrices.352  if (coopElementType) {353    if (constituents.size() != 1)354      return emitOpError("has incorrect number of operands: expected ")355             << "1, but provided " << constituents.size();356    if (coopElementType != constituents.front().getType())357      return emitOpError("operand type mismatch: expected operand type ")358             << coopElementType << ", but provided "359             << constituents.front().getType();360    return success();361  }362 363  // Case 2./3./4. -- number of constituents matches the number of elements.364  auto cType = llvm::cast<spirv::CompositeType>(getType());365  if (constituents.size() == cType.getNumElements()) {366    for (auto index : llvm::seq<uint32_t>(0, constituents.size())) {367      if (constituents[index].getType() != cType.getElementType(index)) {368        return emitOpError("operand type mismatch: expected operand type ")369               << cType.getElementType(index) << ", but provided "370               << constituents[index].getType();371      }372    }373    return success();374  }375 376  // Case 4. -- check that all constituents add up tp the expected vector type.377  auto resultType = llvm::dyn_cast<VectorType>(cType);378  if (!resultType)379    return emitOpError(380        "expected to return a vector or cooperative matrix when the number of "381        "constituents is less than what the result needs");382 383  SmallVector<unsigned> sizes;384  for (Value component : constituents) {385    if (!llvm::isa<VectorType>(component.getType()) &&386        !component.getType().isIntOrFloat())387      return emitOpError("operand type mismatch: expected operand to have "388                         "a scalar or vector type, but provided ")389             << component.getType();390 391    Type elementType = component.getType();392    if (auto vectorType = llvm::dyn_cast<VectorType>(component.getType())) {393      sizes.push_back(vectorType.getNumElements());394      elementType = vectorType.getElementType();395    } else {396      sizes.push_back(1);397    }398 399    if (elementType != resultType.getElementType())400      return emitOpError("operand element type mismatch: expected to be ")401             << resultType.getElementType() << ", but provided " << elementType;402  }403  unsigned totalCount = llvm::sum_of(sizes);404  if (totalCount != cType.getNumElements())405    return emitOpError("has incorrect number of operands: expected ")406           << cType.getNumElements() << ", but provided " << totalCount;407  return success();408}409 410//===----------------------------------------------------------------------===//411// spirv.CompositeExtractOp412//===----------------------------------------------------------------------===//413 414void spirv::CompositeExtractOp::build(OpBuilder &builder, OperationState &state,415                                      Value composite,416                                      ArrayRef<int32_t> indices) {417  auto indexAttr = builder.getI32ArrayAttr(indices);418  auto elementType =419      getElementType(composite.getType(), indexAttr, state.location);420  if (!elementType) {421    return;422  }423  build(builder, state, elementType, composite, indexAttr);424}425 426ParseResult spirv::CompositeExtractOp::parse(OpAsmParser &parser,427                                             OperationState &result) {428  OpAsmParser::UnresolvedOperand compositeInfo;429  Attribute indicesAttr;430  StringRef indicesAttrName =431      spirv::CompositeExtractOp::getIndicesAttrName(result.name);432  Type compositeType;433  SMLoc attrLocation;434 435  if (parser.parseOperand(compositeInfo) ||436      parser.getCurrentLocation(&attrLocation) ||437      parser.parseAttribute(indicesAttr, indicesAttrName, result.attributes) ||438      parser.parseColonType(compositeType) ||439      parser.resolveOperand(compositeInfo, compositeType, result.operands)) {440    return failure();441  }442 443  Type resultType =444      getElementType(compositeType, indicesAttr, parser, attrLocation);445  if (!resultType) {446    return failure();447  }448  result.addTypes(resultType);449  return success();450}451 452void spirv::CompositeExtractOp::print(OpAsmPrinter &printer) {453  printer << ' ' << getComposite() << getIndices() << " : "454          << getComposite().getType();455}456 457LogicalResult spirv::CompositeExtractOp::verify() {458  auto indicesArrayAttr = llvm::dyn_cast<ArrayAttr>(getIndices());459  auto resultType =460      getElementType(getComposite().getType(), indicesArrayAttr, getLoc());461  if (!resultType)462    return failure();463 464  if (resultType != getType()) {465    return emitOpError("invalid result type: expected ")466           << resultType << " but provided " << getType();467  }468 469  return success();470}471 472//===----------------------------------------------------------------------===//473// spirv.CompositeInsert474//===----------------------------------------------------------------------===//475 476void spirv::CompositeInsertOp::build(OpBuilder &builder, OperationState &state,477                                     Value object, Value composite,478                                     ArrayRef<int32_t> indices) {479  auto indexAttr = builder.getI32ArrayAttr(indices);480  build(builder, state, composite.getType(), object, composite, indexAttr);481}482 483ParseResult spirv::CompositeInsertOp::parse(OpAsmParser &parser,484                                            OperationState &result) {485  SmallVector<OpAsmParser::UnresolvedOperand, 2> operands;486  Type objectType, compositeType;487  Attribute indicesAttr;488  StringRef indicesAttrName =489      spirv::CompositeInsertOp::getIndicesAttrName(result.name);490  auto loc = parser.getCurrentLocation();491 492  return failure(493      parser.parseOperandList(operands, 2) ||494      parser.parseAttribute(indicesAttr, indicesAttrName, result.attributes) ||495      parser.parseColonType(objectType) ||496      parser.parseKeywordType("into", compositeType) ||497      parser.resolveOperands(operands, {objectType, compositeType}, loc,498                             result.operands) ||499      parser.addTypesToList(compositeType, result.types));500}501 502LogicalResult spirv::CompositeInsertOp::verify() {503  auto indicesArrayAttr = llvm::dyn_cast<ArrayAttr>(getIndices());504  auto objectType =505      getElementType(getComposite().getType(), indicesArrayAttr, getLoc());506  if (!objectType)507    return failure();508 509  if (objectType != getObject().getType()) {510    return emitOpError("object operand type should be ")511           << objectType << ", but found " << getObject().getType();512  }513 514  if (getComposite().getType() != getType()) {515    return emitOpError("result type should be the same as "516                       "the composite type, but found ")517           << getComposite().getType() << " vs " << getType();518  }519 520  return success();521}522 523void spirv::CompositeInsertOp::print(OpAsmPrinter &printer) {524  printer << " " << getObject() << ", " << getComposite() << getIndices()525          << " : " << getObject().getType() << " into "526          << getComposite().getType();527}528 529//===----------------------------------------------------------------------===//530// spirv.Constant531//===----------------------------------------------------------------------===//532 533ParseResult spirv::ConstantOp::parse(OpAsmParser &parser,534                                     OperationState &result) {535  Attribute value;536  StringRef valueAttrName = spirv::ConstantOp::getValueAttrName(result.name);537  if (parser.parseAttribute(value, valueAttrName, result.attributes))538    return failure();539 540  Type type = NoneType::get(parser.getContext());541  if (auto typedAttr = llvm::dyn_cast<TypedAttr>(value))542    type = typedAttr.getType();543  if (llvm::isa<NoneType, TensorType>(type)) {544    if (parser.parseColonType(type))545      return failure();546  }547 548  if (llvm::isa<TensorArmType>(type)) {549    if (parser.parseOptionalColon().succeeded())550      if (parser.parseType(type))551        return failure();552  }553 554  return parser.addTypeToList(type, result.types);555}556 557void spirv::ConstantOp::print(OpAsmPrinter &printer) {558  printer << ' ' << getValue();559  if (llvm::isa<spirv::ArrayType>(getType()))560    printer << " : " << getType();561}562 563static LogicalResult verifyConstantType(spirv::ConstantOp op, Attribute value,564                                        Type opType) {565  if (isa<spirv::CooperativeMatrixType>(opType)) {566    auto denseAttr = dyn_cast<DenseElementsAttr>(value);567    if (!denseAttr || !denseAttr.isSplat())568      return op.emitOpError("expected a splat dense attribute for cooperative "569                            "matrix constant, but found ")570             << denseAttr;571  }572  if (llvm::isa<IntegerAttr, FloatAttr>(value)) {573    auto valueType = llvm::cast<TypedAttr>(value).getType();574    if (valueType != opType)575      return op.emitOpError("result type (")576             << opType << ") does not match value type (" << valueType << ")";577    return success();578  }579  if (llvm::isa<DenseIntOrFPElementsAttr, SparseElementsAttr>(value)) {580    auto valueType = llvm::cast<TypedAttr>(value).getType();581    if (valueType == opType)582      return success();583    auto arrayType = llvm::dyn_cast<spirv::ArrayType>(opType);584    auto shapedType = llvm::dyn_cast<ShapedType>(valueType);585    if (!arrayType)586      return op.emitOpError("result or element type (")587             << opType << ") does not match value type (" << valueType588             << "), must be the same or spirv.array";589 590    int numElements = arrayType.getNumElements();591    auto opElemType = arrayType.getElementType();592    while (auto t = llvm::dyn_cast<spirv::ArrayType>(opElemType)) {593      numElements *= t.getNumElements();594      opElemType = t.getElementType();595    }596    if (!opElemType.isIntOrFloat())597      return op.emitOpError("only support nested array result type");598 599    auto valueElemType = shapedType.getElementType();600    if (valueElemType != opElemType) {601      return op.emitOpError("result element type (")602             << opElemType << ") does not match value element type ("603             << valueElemType << ")";604    }605 606    if (numElements != shapedType.getNumElements()) {607      return op.emitOpError("result number of elements (")608             << numElements << ") does not match value number of elements ("609             << shapedType.getNumElements() << ")";610    }611    return success();612  }613  if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(value)) {614    auto arrayType = llvm::dyn_cast<spirv::ArrayType>(opType);615    if (!arrayType)616      return op.emitOpError(617          "must have spirv.array result type for array value");618    Type elemType = arrayType.getElementType();619    for (Attribute element : arrayAttr.getValue()) {620      // Verify array elements recursively.621      if (failed(verifyConstantType(op, element, elemType)))622        return failure();623    }624    return success();625  }626  return op.emitOpError("cannot have attribute: ") << value;627}628 629LogicalResult spirv::ConstantOp::verify() {630  // ODS already generates checks to make sure the result type is valid. We just631  // need to additionally check that the value's attribute type is consistent632  // with the result type.633  return verifyConstantType(*this, getValueAttr(), getType());634}635 636bool spirv::ConstantOp::isBuildableWith(Type type) {637  // Must be valid SPIR-V type first.638  if (!llvm::isa<spirv::SPIRVType>(type))639    return false;640 641  if (isa<SPIRVDialect>(type.getDialect())) {642    // TODO: support constant struct643    return llvm::isa<spirv::ArrayType>(type);644  }645 646  return true;647}648 649spirv::ConstantOp spirv::ConstantOp::getZero(Type type, Location loc,650                                             OpBuilder &builder) {651  if (auto intType = llvm::dyn_cast<IntegerType>(type)) {652    unsigned width = intType.getWidth();653    if (width == 1)654      return spirv::ConstantOp::create(builder, loc, type,655                                       builder.getBoolAttr(false));656    return spirv::ConstantOp::create(657        builder, loc, type, builder.getIntegerAttr(type, APInt(width, 0)));658  }659  if (auto floatType = llvm::dyn_cast<FloatType>(type)) {660    return spirv::ConstantOp::create(builder, loc, type,661                                     builder.getFloatAttr(floatType, 0.0));662  }663  if (auto vectorType = llvm::dyn_cast<VectorType>(type)) {664    Type elemType = vectorType.getElementType();665    if (llvm::isa<IntegerType>(elemType)) {666      return spirv::ConstantOp::create(667          builder, loc, type,668          DenseElementsAttr::get(vectorType,669                                 IntegerAttr::get(elemType, 0).getValue()));670    }671    if (llvm::isa<FloatType>(elemType)) {672      return spirv::ConstantOp::create(673          builder, loc, type,674          DenseFPElementsAttr::get(vectorType,675                                   FloatAttr::get(elemType, 0.0).getValue()));676    }677  }678 679  llvm_unreachable("unimplemented types for ConstantOp::getZero()");680}681 682spirv::ConstantOp spirv::ConstantOp::getOne(Type type, Location loc,683                                            OpBuilder &builder) {684  if (auto intType = llvm::dyn_cast<IntegerType>(type)) {685    unsigned width = intType.getWidth();686    if (width == 1)687      return spirv::ConstantOp::create(builder, loc, type,688                                       builder.getBoolAttr(true));689    return spirv::ConstantOp::create(690        builder, loc, type, builder.getIntegerAttr(type, APInt(width, 1)));691  }692  if (auto floatType = llvm::dyn_cast<FloatType>(type)) {693    return spirv::ConstantOp::create(builder, loc, type,694                                     builder.getFloatAttr(floatType, 1.0));695  }696  if (auto vectorType = llvm::dyn_cast<VectorType>(type)) {697    Type elemType = vectorType.getElementType();698    if (llvm::isa<IntegerType>(elemType)) {699      return spirv::ConstantOp::create(700          builder, loc, type,701          DenseElementsAttr::get(vectorType,702                                 IntegerAttr::get(elemType, 1).getValue()));703    }704    if (llvm::isa<FloatType>(elemType)) {705      return spirv::ConstantOp::create(706          builder, loc, type,707          DenseFPElementsAttr::get(vectorType,708                                   FloatAttr::get(elemType, 1.0).getValue()));709    }710  }711 712  llvm_unreachable("unimplemented types for ConstantOp::getOne()");713}714 715void mlir::spirv::ConstantOp::getAsmResultNames(716    llvm::function_ref<void(mlir::Value, llvm::StringRef)> setNameFn) {717  Type type = getType();718 719  SmallString<32> specialNameBuffer;720  llvm::raw_svector_ostream specialName(specialNameBuffer);721  specialName << "cst";722 723  IntegerType intTy = llvm::dyn_cast<IntegerType>(type);724 725  if (IntegerAttr intCst = llvm::dyn_cast<IntegerAttr>(getValue())) {726    assert(intTy);727 728    if (intTy.getWidth() == 1) {729      return setNameFn(getResult(), (intCst.getInt() ? "true" : "false"));730    }731 732    if (intTy.isSignless()) {733      specialName << intCst.getInt();734    } else if (intTy.isUnsigned()) {735      specialName << intCst.getUInt();736    } else {737      specialName << intCst.getSInt();738    }739  }740 741  if (intTy || llvm::isa<FloatType>(type)) {742    specialName << '_' << type;743  }744 745  if (auto vecType = llvm::dyn_cast<VectorType>(type)) {746    specialName << "_vec_";747    specialName << vecType.getDimSize(0);748 749    Type elementType = vecType.getElementType();750 751    if (llvm::isa<IntegerType>(elementType) ||752        llvm::isa<FloatType>(elementType)) {753      specialName << "x" << elementType;754    }755  }756 757  setNameFn(getResult(), specialName.str());758}759 760void mlir::spirv::AddressOfOp::getAsmResultNames(761    llvm::function_ref<void(mlir::Value, llvm::StringRef)> setNameFn) {762  SmallString<32> specialNameBuffer;763  llvm::raw_svector_ostream specialName(specialNameBuffer);764  specialName << getVariable() << "_addr";765  setNameFn(getResult(), specialName.str());766}767 768//===----------------------------------------------------------------------===//769// spirv.EXTConstantCompositeReplicate770//===----------------------------------------------------------------------===//771 772// Returns type of attribute. In case of a TypedAttr this will simply return773// the type. But for an ArrayAttr which is untyped and can be multidimensional774// it creates the ArrayType recursively.775static Type getValueType(Attribute attr) {776  if (auto typedAttr = dyn_cast<TypedAttr>(attr)) {777    return typedAttr.getType();778  }779 780  if (auto arrayAttr = dyn_cast<ArrayAttr>(attr)) {781    return spirv::ArrayType::get(getValueType(arrayAttr[0]), arrayAttr.size());782  }783 784  return nullptr;785}786 787LogicalResult spirv::EXTConstantCompositeReplicateOp::verify() {788  Type valueType = getValueType(getValue());789  if (!valueType)790    return emitError("unknown value attribute type");791 792  auto compositeType = dyn_cast<spirv::CompositeType>(getType());793  if (!compositeType)794    return emitError("result type is not a composite type");795 796  Type compositeElementType = compositeType.getElementType(0);797 798  SmallVector<Type, 3> possibleTypes = {compositeElementType};799  while (auto type = dyn_cast<spirv::CompositeType>(compositeElementType)) {800    compositeElementType = type.getElementType(0);801    possibleTypes.push_back(compositeElementType);802  }803 804  if (!is_contained(possibleTypes, valueType)) {805    return emitError("expected value attribute type ")806           << interleaved(possibleTypes, " or ") << ", but got: " << valueType;807  }808 809  return success();810}811 812//===----------------------------------------------------------------------===//813// spirv.ControlBarrierOp814//===----------------------------------------------------------------------===//815 816LogicalResult spirv::ControlBarrierOp::verify() {817  return verifyMemorySemantics(getOperation(), getMemorySemantics());818}819 820//===----------------------------------------------------------------------===//821// spirv.EntryPoint822//===----------------------------------------------------------------------===//823 824void spirv::EntryPointOp::build(OpBuilder &builder, OperationState &state,825                                spirv::ExecutionModel executionModel,826                                spirv::FuncOp function,827                                ArrayRef<Attribute> interfaceVars) {828  build(builder, state,829        spirv::ExecutionModelAttr::get(builder.getContext(), executionModel),830        SymbolRefAttr::get(function), builder.getArrayAttr(interfaceVars));831}832 833ParseResult spirv::EntryPointOp::parse(OpAsmParser &parser,834                                       OperationState &result) {835  spirv::ExecutionModel execModel;836  SmallVector<Attribute, 4> interfaceVars;837 838  FlatSymbolRefAttr fn;839  if (parseEnumStrAttr<spirv::ExecutionModelAttr>(execModel, parser, result) ||840      parser.parseAttribute(fn, Type(), kFnNameAttrName, result.attributes)) {841    return failure();842  }843 844  if (!parser.parseOptionalComma()) {845    // Parse the interface variables846    if (parser.parseCommaSeparatedList([&]() -> ParseResult {847          // The name of the interface variable attribute isnt important848          FlatSymbolRefAttr var;849          NamedAttrList attrs;850          if (parser.parseAttribute(var, Type(), "var_symbol", attrs))851            return failure();852          interfaceVars.push_back(var);853          return success();854        }))855      return failure();856  }857  result.addAttribute(spirv::EntryPointOp::getInterfaceAttrName(result.name),858                      parser.getBuilder().getArrayAttr(interfaceVars));859  return success();860}861 862void spirv::EntryPointOp::print(OpAsmPrinter &printer) {863  printer << " \"" << stringifyExecutionModel(getExecutionModel()) << "\" ";864  printer.printSymbolName(getFn());865  auto interfaceVars = getInterface().getValue();866  if (!interfaceVars.empty())867    printer << ", " << llvm::interleaved(interfaceVars);868}869 870LogicalResult spirv::EntryPointOp::verify() {871  // Checks for fn and interface symbol reference are done in spirv::ModuleOp872  // verification.873  return success();874}875 876//===----------------------------------------------------------------------===//877// spirv.ExecutionMode878//===----------------------------------------------------------------------===//879 880void spirv::ExecutionModeOp::build(OpBuilder &builder, OperationState &state,881                                   spirv::FuncOp function,882                                   spirv::ExecutionMode executionMode,883                                   ArrayRef<int32_t> params) {884  build(builder, state, SymbolRefAttr::get(function),885        spirv::ExecutionModeAttr::get(builder.getContext(), executionMode),886        builder.getI32ArrayAttr(params));887}888 889ParseResult spirv::ExecutionModeOp::parse(OpAsmParser &parser,890                                          OperationState &result) {891  spirv::ExecutionMode execMode;892  Attribute fn;893  if (parser.parseAttribute(fn, kFnNameAttrName, result.attributes) ||894      parseEnumStrAttr<spirv::ExecutionModeAttr>(execMode, parser, result)) {895    return failure();896  }897 898  SmallVector<int32_t, 4> values;899  Type i32Type = parser.getBuilder().getIntegerType(32);900  while (!parser.parseOptionalComma()) {901    NamedAttrList attr;902    Attribute value;903    if (parser.parseAttribute(value, i32Type, "value", attr)) {904      return failure();905    }906    values.push_back(llvm::cast<IntegerAttr>(value).getInt());907  }908  StringRef valuesAttrName =909      spirv::ExecutionModeOp::getValuesAttrName(result.name);910  result.addAttribute(valuesAttrName,911                      parser.getBuilder().getI32ArrayAttr(values));912  return success();913}914 915void spirv::ExecutionModeOp::print(OpAsmPrinter &printer) {916  printer << " ";917  printer.printSymbolName(getFn());918  printer << " \"" << stringifyExecutionMode(getExecutionMode()) << "\"";919  ArrayAttr values = this->getValues();920  if (!values.empty())921    printer << ", " << llvm::interleaved(values.getAsValueRange<IntegerAttr>());922}923 924//===----------------------------------------------------------------------===//925// spirv.func926//===----------------------------------------------------------------------===//927 928ParseResult spirv::FuncOp::parse(OpAsmParser &parser, OperationState &result) {929  SmallVector<OpAsmParser::Argument> entryArgs;930  SmallVector<DictionaryAttr> resultAttrs;931  SmallVector<Type> resultTypes;932  auto &builder = parser.getBuilder();933 934  // Parse the name as a symbol.935  StringAttr nameAttr;936  if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),937                             result.attributes))938    return failure();939 940  // Parse the function signature.941  bool isVariadic = false;942  if (function_interface_impl::parseFunctionSignatureWithArguments(943          parser, /*allowVariadic=*/false, entryArgs, isVariadic, resultTypes,944          resultAttrs))945    return failure();946 947  SmallVector<Type> argTypes;948  for (auto &arg : entryArgs)949    argTypes.push_back(arg.type);950  auto fnType = builder.getFunctionType(argTypes, resultTypes);951  result.addAttribute(getFunctionTypeAttrName(result.name),952                      TypeAttr::get(fnType));953 954  // Parse the optional function control keyword.955  spirv::FunctionControl fnControl;956  if (parseEnumStrAttr<spirv::FunctionControlAttr>(fnControl, parser, result))957    return failure();958 959  // If additional attributes are present, parse them.960  if (parser.parseOptionalAttrDictWithKeyword(result.attributes))961    return failure();962 963  // Add the attributes to the function arguments.964  assert(resultAttrs.size() == resultTypes.size());965  call_interface_impl::addArgAndResultAttrs(966      builder, result, entryArgs, resultAttrs, getArgAttrsAttrName(result.name),967      getResAttrsAttrName(result.name));968 969  // Parse the optional function body.970  auto *body = result.addRegion();971  OptionalParseResult parseResult =972      parser.parseOptionalRegion(*body, entryArgs);973  return failure(parseResult.has_value() && failed(*parseResult));974}975 976void spirv::FuncOp::print(OpAsmPrinter &printer) {977  // Print function name, signature, and control.978  printer << " ";979  printer.printSymbolName(getSymName());980  auto fnType = getFunctionType();981  function_interface_impl::printFunctionSignature(982      printer, *this, fnType.getInputs(),983      /*isVariadic=*/false, fnType.getResults());984  printer << " \"" << spirv::stringifyFunctionControl(getFunctionControl())985          << "\"";986  function_interface_impl::printFunctionAttributes(987      printer, *this,988      {spirv::attributeName<spirv::FunctionControl>(),989       getFunctionTypeAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(),990       getFunctionControlAttrName()});991 992  // Print the body if this is not an external function.993  Region &body = this->getBody();994  if (!body.empty()) {995    printer << ' ';996    printer.printRegion(body, /*printEntryBlockArgs=*/false,997                        /*printBlockTerminators=*/true);998  }999}1000 1001LogicalResult spirv::FuncOp::verifyType() {1002  FunctionType fnType = getFunctionType();1003  if (fnType.getNumResults() > 1)1004    return emitOpError("cannot have more than one result");1005 1006  auto hasDecorationAttr = [&](spirv::Decoration decoration,1007                               unsigned argIndex) {1008    auto func = llvm::cast<FunctionOpInterface>(getOperation());1009    for (auto argAttr : cast<FunctionOpInterface>(func).getArgAttrs(argIndex)) {1010      if (argAttr.getName() != spirv::DecorationAttr::name)1011        continue;1012      if (auto decAttr = dyn_cast<spirv::DecorationAttr>(argAttr.getValue()))1013        return decAttr.getValue() == decoration;1014    }1015    return false;1016  };1017 1018  for (unsigned i = 0, e = this->getNumArguments(); i != e; ++i) {1019    Type param = fnType.getInputs()[i];1020    auto inputPtrType = dyn_cast<spirv::PointerType>(param);1021    if (!inputPtrType)1022      continue;1023 1024    auto pointeePtrType =1025        dyn_cast<spirv::PointerType>(inputPtrType.getPointeeType());1026    if (pointeePtrType) {1027      // SPIR-V spec, from SPV_KHR_physical_storage_buffer:1028      // > If an OpFunctionParameter is a pointer (or contains a pointer)1029      // > and the type it points to is a pointer in the PhysicalStorageBuffer1030      // > storage class, the function parameter must be decorated with exactly1031      // > one of AliasedPointer or RestrictPointer.1032      if (pointeePtrType.getStorageClass() !=1033          spirv::StorageClass::PhysicalStorageBuffer)1034        continue;1035 1036      bool hasAliasedPtr =1037          hasDecorationAttr(spirv::Decoration::AliasedPointer, i);1038      bool hasRestrictPtr =1039          hasDecorationAttr(spirv::Decoration::RestrictPointer, i);1040      if (!hasAliasedPtr && !hasRestrictPtr)1041        return emitOpError()1042               << "with a pointer points to a physical buffer pointer must "1043                  "be decorated either 'AliasedPointer' or 'RestrictPointer'";1044      continue;1045    }1046    // SPIR-V spec, from SPV_KHR_physical_storage_buffer:1047    // > If an OpFunctionParameter is a pointer (or contains a pointer) in1048    // > the PhysicalStorageBuffer storage class, the function parameter must1049    // > be decorated with exactly one of Aliased or Restrict.1050    if (auto pointeeArrayType =1051            dyn_cast<spirv::ArrayType>(inputPtrType.getPointeeType())) {1052      pointeePtrType =1053          dyn_cast<spirv::PointerType>(pointeeArrayType.getElementType());1054    } else {1055      pointeePtrType = inputPtrType;1056    }1057 1058    if (!pointeePtrType || pointeePtrType.getStorageClass() !=1059                               spirv::StorageClass::PhysicalStorageBuffer)1060      continue;1061 1062    bool hasAliased = hasDecorationAttr(spirv::Decoration::Aliased, i);1063    bool hasRestrict = hasDecorationAttr(spirv::Decoration::Restrict, i);1064    if (!hasAliased && !hasRestrict)1065      return emitOpError() << "with physical buffer pointer must be decorated "1066                              "either 'Aliased' or 'Restrict'";1067  }1068 1069  return success();1070}1071 1072LogicalResult spirv::FuncOp::verifyBody() {1073  FunctionType fnType = getFunctionType();1074  if (!isExternal()) {1075    Block &entryBlock = front();1076 1077    unsigned numArguments = this->getNumArguments();1078    if (entryBlock.getNumArguments() != numArguments)1079      return emitOpError("entry block must have ")1080             << numArguments << " arguments to match function signature";1081 1082    for (auto [index, fnArgType, blockArgType] :1083         llvm::enumerate(getArgumentTypes(), entryBlock.getArgumentTypes())) {1084      if (blockArgType != fnArgType) {1085        return emitOpError("type of entry block argument #")1086               << index << '(' << blockArgType1087               << ") must match the type of the corresponding argument in "1088               << "function signature(" << fnArgType << ')';1089      }1090    }1091  }1092 1093  auto walkResult = walk([fnType](Operation *op) -> WalkResult {1094    if (auto retOp = dyn_cast<spirv::ReturnOp>(op)) {1095      if (fnType.getNumResults() != 0)1096        return retOp.emitOpError("cannot be used in functions returning value");1097    } else if (auto retOp = dyn_cast<spirv::ReturnValueOp>(op)) {1098      if (fnType.getNumResults() != 1)1099        return retOp.emitOpError(1100                   "returns 1 value but enclosing function requires ")1101               << fnType.getNumResults() << " results";1102 1103      auto retOperandType = retOp.getValue().getType();1104      auto fnResultType = fnType.getResult(0);1105      if (retOperandType != fnResultType)1106        return retOp.emitOpError(" return value's type (")1107               << retOperandType << ") mismatch with function's result type ("1108               << fnResultType << ")";1109    }1110    return WalkResult::advance();1111  });1112 1113  // TODO: verify other bits like linkage type.1114 1115  return failure(walkResult.wasInterrupted());1116}1117 1118void spirv::FuncOp::build(OpBuilder &builder, OperationState &state,1119                          StringRef name, FunctionType type,1120                          spirv::FunctionControl control,1121                          ArrayRef<NamedAttribute> attrs) {1122  state.addAttribute(SymbolTable::getSymbolAttrName(),1123                     builder.getStringAttr(name));1124  state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));1125  state.addAttribute(spirv::attributeName<spirv::FunctionControl>(),1126                     builder.getAttr<spirv::FunctionControlAttr>(control));1127  state.attributes.append(attrs.begin(), attrs.end());1128  state.addRegion();1129}1130 1131//===----------------------------------------------------------------------===//1132// spirv.GLFClampOp1133//===----------------------------------------------------------------------===//1134 1135ParseResult spirv::GLFClampOp::parse(OpAsmParser &parser,1136                                     OperationState &result) {1137  return parseOneResultSameOperandTypeOp(parser, result);1138}1139void spirv::GLFClampOp::print(OpAsmPrinter &p) { printOneResultOp(*this, p); }1140 1141//===----------------------------------------------------------------------===//1142// spirv.GLUClampOp1143//===----------------------------------------------------------------------===//1144 1145ParseResult spirv::GLUClampOp::parse(OpAsmParser &parser,1146                                     OperationState &result) {1147  return parseOneResultSameOperandTypeOp(parser, result);1148}1149void spirv::GLUClampOp::print(OpAsmPrinter &p) { printOneResultOp(*this, p); }1150 1151//===----------------------------------------------------------------------===//1152// spirv.GLSClampOp1153//===----------------------------------------------------------------------===//1154 1155ParseResult spirv::GLSClampOp::parse(OpAsmParser &parser,1156                                     OperationState &result) {1157  return parseOneResultSameOperandTypeOp(parser, result);1158}1159void spirv::GLSClampOp::print(OpAsmPrinter &p) { printOneResultOp(*this, p); }1160 1161//===----------------------------------------------------------------------===//1162// spirv.GLFmaOp1163//===----------------------------------------------------------------------===//1164 1165ParseResult spirv::GLFmaOp::parse(OpAsmParser &parser, OperationState &result) {1166  return parseOneResultSameOperandTypeOp(parser, result);1167}1168void spirv::GLFmaOp::print(OpAsmPrinter &p) { printOneResultOp(*this, p); }1169 1170//===----------------------------------------------------------------------===//1171// spirv.GlobalVariable1172//===----------------------------------------------------------------------===//1173 1174void spirv::GlobalVariableOp::build(OpBuilder &builder, OperationState &state,1175                                    Type type, StringRef name,1176                                    unsigned descriptorSet, unsigned binding) {1177  build(builder, state, TypeAttr::get(type), builder.getStringAttr(name));1178  state.addAttribute(1179      spirv::SPIRVDialect::getAttributeName(spirv::Decoration::DescriptorSet),1180      builder.getI32IntegerAttr(descriptorSet));1181  state.addAttribute(1182      spirv::SPIRVDialect::getAttributeName(spirv::Decoration::Binding),1183      builder.getI32IntegerAttr(binding));1184}1185 1186void spirv::GlobalVariableOp::build(OpBuilder &builder, OperationState &state,1187                                    Type type, StringRef name,1188                                    spirv::BuiltIn builtin) {1189  build(builder, state, TypeAttr::get(type), builder.getStringAttr(name));1190  state.addAttribute(1191      spirv::SPIRVDialect::getAttributeName(spirv::Decoration::BuiltIn),1192      builder.getStringAttr(spirv::stringifyBuiltIn(builtin)));1193}1194 1195ParseResult spirv::GlobalVariableOp::parse(OpAsmParser &parser,1196                                           OperationState &result) {1197  // Parse variable name.1198  StringAttr nameAttr;1199  StringRef initializerAttrName =1200      spirv::GlobalVariableOp::getInitializerAttrName(result.name);1201  if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),1202                             result.attributes)) {1203    return failure();1204  }1205 1206  // Parse optional initializer1207  if (succeeded(parser.parseOptionalKeyword(initializerAttrName))) {1208    FlatSymbolRefAttr initSymbol;1209    if (parser.parseLParen() ||1210        parser.parseAttribute(initSymbol, Type(), initializerAttrName,1211                              result.attributes) ||1212        parser.parseRParen())1213      return failure();1214  }1215 1216  if (parseVariableDecorations(parser, result)) {1217    return failure();1218  }1219 1220  Type type;1221  StringRef typeAttrName =1222      spirv::GlobalVariableOp::getTypeAttrName(result.name);1223  auto loc = parser.getCurrentLocation();1224  if (parser.parseColonType(type)) {1225    return failure();1226  }1227  if (!llvm::isa<spirv::PointerType>(type)) {1228    return parser.emitError(loc, "expected spirv.ptr type");1229  }1230  result.addAttribute(typeAttrName, TypeAttr::get(type));1231 1232  return success();1233}1234 1235void spirv::GlobalVariableOp::print(OpAsmPrinter &printer) {1236  SmallVector<StringRef, 4> elidedAttrs{1237      spirv::attributeName<spirv::StorageClass>()};1238 1239  // Print variable name.1240  printer << ' ';1241  printer.printSymbolName(getSymName());1242  elidedAttrs.push_back(SymbolTable::getSymbolAttrName());1243 1244  StringRef initializerAttrName = this->getInitializerAttrName();1245  // Print optional initializer1246  if (auto initializer = this->getInitializer()) {1247    printer << " " << initializerAttrName << '(';1248    printer.printSymbolName(*initializer);1249    printer << ')';1250    elidedAttrs.push_back(initializerAttrName);1251  }1252 1253  StringRef typeAttrName = this->getTypeAttrName();1254  elidedAttrs.push_back(typeAttrName);1255  spirv::printVariableDecorations(*this, printer, elidedAttrs);1256  printer << " : " << getType();1257}1258 1259LogicalResult spirv::GlobalVariableOp::verify() {1260  if (!llvm::isa<spirv::PointerType>(getType()))1261    return emitOpError("result must be of a !spv.ptr type");1262 1263  // SPIR-V spec: "Storage Class is the Storage Class of the memory holding the1264  // object. It cannot be Generic. It must be the same as the Storage Class1265  // operand of the Result Type."1266  // Also, Function storage class is reserved by spirv.Variable.1267  auto storageClass = this->storageClass();1268  if (storageClass == spirv::StorageClass::Generic ||1269      storageClass == spirv::StorageClass::Function) {1270    return emitOpError("storage class cannot be '")1271           << stringifyStorageClass(storageClass) << "'";1272  }1273 1274  if (auto init = (*this)->getAttrOfType<FlatSymbolRefAttr>(1275          this->getInitializerAttrName())) {1276    Operation *initOp = SymbolTable::lookupNearestSymbolFrom(1277        (*this)->getParentOp(), init.getAttr());1278    // TODO: Currently only variable initialization with specialization1279    // constants is supported. There could be normal constants in the module1280    // scope as well.1281    //1282    // In the current setup we also cannot initialize one global variable with1283    // another. The problem is that if we try to initialize pointer of type X1284    // with another pointer type, the validator fails because it expects the1285    // variable to be initialized to be type X, not pointer to X. Now1286    // `spirv.GlobalVariable` only allows pointer type, so in the current design1287    // we cannot initialize one `spirv.GlobalVariable` with another.1288    if (!initOp ||1289        !isa<spirv::SpecConstantOp, spirv::SpecConstantCompositeOp>(initOp)) {1290      return emitOpError("initializer must be result of a "1291                         "spirv.SpecConstant or "1292                         "spirv.SpecConstantCompositeOp op");1293    }1294  }1295 1296  return success();1297}1298 1299//===----------------------------------------------------------------------===//1300// spirv.INTEL.SubgroupBlockRead1301//===----------------------------------------------------------------------===//1302 1303LogicalResult spirv::INTELSubgroupBlockReadOp::verify() {1304  if (failed(verifyBlockReadWritePtrAndValTypes(*this, getPtr(), getValue())))1305    return failure();1306 1307  return success();1308}1309 1310//===----------------------------------------------------------------------===//1311// spirv.INTEL.SubgroupBlockWrite1312//===----------------------------------------------------------------------===//1313 1314ParseResult spirv::INTELSubgroupBlockWriteOp::parse(OpAsmParser &parser,1315                                                    OperationState &result) {1316  // Parse the storage class specification1317  spirv::StorageClass storageClass;1318  SmallVector<OpAsmParser::UnresolvedOperand, 2> operandInfo;1319  auto loc = parser.getCurrentLocation();1320  Type elementType;1321  if (parseEnumStrAttr(storageClass, parser) ||1322      parser.parseOperandList(operandInfo, 2) || parser.parseColon() ||1323      parser.parseType(elementType)) {1324    return failure();1325  }1326 1327  auto ptrType = spirv::PointerType::get(elementType, storageClass);1328  if (auto valVecTy = llvm::dyn_cast<VectorType>(elementType))1329    ptrType = spirv::PointerType::get(valVecTy.getElementType(), storageClass);1330 1331  if (parser.resolveOperands(operandInfo, {ptrType, elementType}, loc,1332                             result.operands)) {1333    return failure();1334  }1335  return success();1336}1337 1338void spirv::INTELSubgroupBlockWriteOp::print(OpAsmPrinter &printer) {1339  printer << " " << getPtr() << ", " << getValue() << " : "1340          << getValue().getType();1341}1342 1343LogicalResult spirv::INTELSubgroupBlockWriteOp::verify() {1344  if (failed(verifyBlockReadWritePtrAndValTypes(*this, getPtr(), getValue())))1345    return failure();1346 1347  return success();1348}1349 1350//===----------------------------------------------------------------------===//1351// spirv.IAddCarryOp1352//===----------------------------------------------------------------------===//1353 1354LogicalResult spirv::IAddCarryOp::verify() {1355  return ::verifyArithmeticExtendedBinaryOp(*this);1356}1357 1358ParseResult spirv::IAddCarryOp::parse(OpAsmParser &parser,1359                                      OperationState &result) {1360  return ::parseArithmeticExtendedBinaryOp(parser, result);1361}1362 1363void spirv::IAddCarryOp::print(OpAsmPrinter &printer) {1364  ::printArithmeticExtendedBinaryOp(*this, printer);1365}1366 1367//===----------------------------------------------------------------------===//1368// spirv.ISubBorrowOp1369//===----------------------------------------------------------------------===//1370 1371LogicalResult spirv::ISubBorrowOp::verify() {1372  return ::verifyArithmeticExtendedBinaryOp(*this);1373}1374 1375ParseResult spirv::ISubBorrowOp::parse(OpAsmParser &parser,1376                                       OperationState &result) {1377  return ::parseArithmeticExtendedBinaryOp(parser, result);1378}1379 1380void spirv::ISubBorrowOp::print(OpAsmPrinter &printer) {1381  ::printArithmeticExtendedBinaryOp(*this, printer);1382}1383 1384//===----------------------------------------------------------------------===//1385// spirv.SMulExtended1386//===----------------------------------------------------------------------===//1387 1388LogicalResult spirv::SMulExtendedOp::verify() {1389  return ::verifyArithmeticExtendedBinaryOp(*this);1390}1391 1392ParseResult spirv::SMulExtendedOp::parse(OpAsmParser &parser,1393                                         OperationState &result) {1394  return ::parseArithmeticExtendedBinaryOp(parser, result);1395}1396 1397void spirv::SMulExtendedOp::print(OpAsmPrinter &printer) {1398  ::printArithmeticExtendedBinaryOp(*this, printer);1399}1400 1401//===----------------------------------------------------------------------===//1402// spirv.UMulExtended1403//===----------------------------------------------------------------------===//1404 1405LogicalResult spirv::UMulExtendedOp::verify() {1406  return ::verifyArithmeticExtendedBinaryOp(*this);1407}1408 1409ParseResult spirv::UMulExtendedOp::parse(OpAsmParser &parser,1410                                         OperationState &result) {1411  return ::parseArithmeticExtendedBinaryOp(parser, result);1412}1413 1414void spirv::UMulExtendedOp::print(OpAsmPrinter &printer) {1415  ::printArithmeticExtendedBinaryOp(*this, printer);1416}1417 1418//===----------------------------------------------------------------------===//1419// spirv.MemoryBarrierOp1420//===----------------------------------------------------------------------===//1421 1422LogicalResult spirv::MemoryBarrierOp::verify() {1423  return verifyMemorySemantics(getOperation(), getMemorySemantics());1424}1425 1426//===----------------------------------------------------------------------===//1427// spirv.module1428//===----------------------------------------------------------------------===//1429 1430void spirv::ModuleOp::build(OpBuilder &builder, OperationState &state,1431                            std::optional<StringRef> name) {1432  OpBuilder::InsertionGuard guard(builder);1433  builder.createBlock(state.addRegion());1434  if (name) {1435    state.attributes.append(mlir::SymbolTable::getSymbolAttrName(),1436                            builder.getStringAttr(*name));1437  }1438}1439 1440void spirv::ModuleOp::build(OpBuilder &builder, OperationState &state,1441                            spirv::AddressingModel addressingModel,1442                            spirv::MemoryModel memoryModel,1443                            std::optional<VerCapExtAttr> vceTriple,1444                            std::optional<StringRef> name) {1445  state.addAttribute(1446      "addressing_model",1447      builder.getAttr<spirv::AddressingModelAttr>(addressingModel));1448  state.addAttribute("memory_model",1449                     builder.getAttr<spirv::MemoryModelAttr>(memoryModel));1450  OpBuilder::InsertionGuard guard(builder);1451  builder.createBlock(state.addRegion());1452  if (vceTriple)1453    state.addAttribute(getVCETripleAttrName(), *vceTriple);1454  if (name)1455    state.addAttribute(mlir::SymbolTable::getSymbolAttrName(),1456                       builder.getStringAttr(*name));1457}1458 1459ParseResult spirv::ModuleOp::parse(OpAsmParser &parser,1460                                   OperationState &result) {1461  Region *body = result.addRegion();1462 1463  // If the name is present, parse it.1464  StringAttr nameAttr;1465  (void)parser.parseOptionalSymbolName(1466      nameAttr, mlir::SymbolTable::getSymbolAttrName(), result.attributes);1467 1468  // Parse attributes1469  spirv::AddressingModel addrModel;1470  spirv::MemoryModel memoryModel;1471  if (spirv::parseEnumKeywordAttr<spirv::AddressingModelAttr>(addrModel, parser,1472                                                              result) ||1473      spirv::parseEnumKeywordAttr<spirv::MemoryModelAttr>(memoryModel, parser,1474                                                          result))1475    return failure();1476 1477  if (succeeded(parser.parseOptionalKeyword("requires"))) {1478    spirv::VerCapExtAttr vceTriple;1479    if (parser.parseAttribute(vceTriple,1480                              spirv::ModuleOp::getVCETripleAttrName(),1481                              result.attributes))1482      return failure();1483  }1484 1485  if (parser.parseOptionalAttrDictWithKeyword(result.attributes) ||1486      parser.parseRegion(*body, /*arguments=*/{}))1487    return failure();1488 1489  // Make sure we have at least one block.1490  if (body->empty())1491    body->push_back(new Block());1492 1493  return success();1494}1495 1496void spirv::ModuleOp::print(OpAsmPrinter &printer) {1497  if (std::optional<StringRef> name = getName()) {1498    printer << ' ';1499    printer.printSymbolName(*name);1500  }1501 1502  SmallVector<StringRef, 2> elidedAttrs;1503 1504  printer << " " << spirv::stringifyAddressingModel(getAddressingModel()) << " "1505          << spirv::stringifyMemoryModel(getMemoryModel());1506  auto addressingModelAttrName = spirv::attributeName<spirv::AddressingModel>();1507  auto memoryModelAttrName = spirv::attributeName<spirv::MemoryModel>();1508  elidedAttrs.assign({addressingModelAttrName, memoryModelAttrName,1509                      mlir::SymbolTable::getSymbolAttrName()});1510 1511  if (std::optional<spirv::VerCapExtAttr> triple = getVceTriple()) {1512    printer << " requires " << *triple;1513    elidedAttrs.push_back(spirv::ModuleOp::getVCETripleAttrName());1514  }1515 1516  printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);1517  printer << ' ';1518  printer.printRegion(getRegion());1519}1520 1521LogicalResult spirv::ModuleOp::verifyRegions() {1522  Dialect *dialect = (*this)->getDialect();1523  DenseMap<std::pair<spirv::FuncOp, spirv::ExecutionModel>, spirv::EntryPointOp>1524      entryPoints;1525  mlir::SymbolTable table(*this);1526 1527  for (auto &op : *getBody()) {1528    if (op.getDialect() != dialect)1529      return op.emitError("'spirv.module' can only contain spirv.* ops");1530 1531    // For EntryPoint op, check that the function and execution model is not1532    // duplicated in EntryPointOps. Also verify that the interface specified1533    // comes from globalVariables here to make this check cheaper.1534    if (auto entryPointOp = dyn_cast<spirv::EntryPointOp>(op)) {1535      auto funcOp = table.lookup<spirv::FuncOp>(entryPointOp.getFn());1536      if (!funcOp) {1537        return entryPointOp.emitError("function '")1538               << entryPointOp.getFn() << "' not found in 'spirv.module'";1539      }1540      if (auto interface = entryPointOp.getInterface()) {1541        for (Attribute varRef : interface) {1542          auto varSymRef = llvm::dyn_cast<FlatSymbolRefAttr>(varRef);1543          if (!varSymRef) {1544            return entryPointOp.emitError(1545                       "expected symbol reference for interface "1546                       "specification instead of '")1547                   << varRef;1548          }1549          auto variableOp =1550              table.lookup<spirv::GlobalVariableOp>(varSymRef.getValue());1551          if (!variableOp) {1552            return entryPointOp.emitError("expected spirv.GlobalVariable "1553                                          "symbol reference instead of'")1554                   << varSymRef << "'";1555          }1556        }1557      }1558 1559      auto key = std::pair<spirv::FuncOp, spirv::ExecutionModel>(1560          funcOp, entryPointOp.getExecutionModel());1561      if (!entryPoints.try_emplace(key, entryPointOp).second)1562        return entryPointOp.emitError("duplicate of a previous EntryPointOp");1563    } else if (auto funcOp = dyn_cast<spirv::FuncOp>(op)) {1564      // If the function is external and does not have 'Import'1565      // linkage_attributes(LinkageAttributes), throw an error. 'Import'1566      // LinkageAttributes is used to import external functions.1567      auto linkageAttr = funcOp.getLinkageAttributes();1568      auto hasImportLinkage =1569          linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==1570                          spirv::LinkageType::Import);1571      if (funcOp.isExternal() && !hasImportLinkage)1572        return op.emitError(1573            "'spirv.module' cannot contain external functions "1574            "without 'Import' linkage_attributes (LinkageAttributes)");1575 1576      // TODO: move this check to spirv.func.1577      for (auto &block : funcOp)1578        for (auto &op : block) {1579          if (op.getDialect() != dialect)1580            return op.emitError(1581                "functions in 'spirv.module' can only contain spirv.* ops");1582        }1583    }1584  }1585 1586  return success();1587}1588 1589//===----------------------------------------------------------------------===//1590// spirv.mlir.referenceof1591//===----------------------------------------------------------------------===//1592 1593LogicalResult spirv::ReferenceOfOp::verify() {1594  auto *specConstSym = SymbolTable::lookupNearestSymbolFrom(1595      (*this)->getParentOp(), getSpecConstAttr());1596  Type constType;1597 1598  auto specConstOp = dyn_cast_or_null<spirv::SpecConstantOp>(specConstSym);1599  if (specConstOp)1600    constType = specConstOp.getDefaultValue().getType();1601 1602  auto specConstCompositeOp =1603      dyn_cast_or_null<spirv::SpecConstantCompositeOp>(specConstSym);1604  if (specConstCompositeOp)1605    constType = specConstCompositeOp.getType();1606 1607  if (!specConstOp && !specConstCompositeOp)1608    return emitOpError(1609        "expected spirv.SpecConstant or spirv.SpecConstantComposite symbol");1610 1611  if (getReference().getType() != constType)1612    return emitOpError("result type mismatch with the referenced "1613                       "specialization constant's type");1614 1615  return success();1616}1617 1618//===----------------------------------------------------------------------===//1619// spirv.SpecConstant1620//===----------------------------------------------------------------------===//1621 1622ParseResult spirv::SpecConstantOp::parse(OpAsmParser &parser,1623                                         OperationState &result) {1624  StringAttr nameAttr;1625  Attribute valueAttr;1626  StringRef defaultValueAttrName =1627      spirv::SpecConstantOp::getDefaultValueAttrName(result.name);1628 1629  if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),1630                             result.attributes))1631    return failure();1632 1633  // Parse optional spec_id.1634  if (succeeded(parser.parseOptionalKeyword(kSpecIdAttrName))) {1635    IntegerAttr specIdAttr;1636    if (parser.parseLParen() ||1637        parser.parseAttribute(specIdAttr, kSpecIdAttrName, result.attributes) ||1638        parser.parseRParen())1639      return failure();1640  }1641 1642  if (parser.parseEqual() ||1643      parser.parseAttribute(valueAttr, defaultValueAttrName, result.attributes))1644    return failure();1645 1646  return success();1647}1648 1649void spirv::SpecConstantOp::print(OpAsmPrinter &printer) {1650  printer << ' ';1651  printer.printSymbolName(getSymName());1652  if (auto specID = (*this)->getAttrOfType<IntegerAttr>(kSpecIdAttrName))1653    printer << ' ' << kSpecIdAttrName << '(' << specID.getInt() << ')';1654  printer << " = " << getDefaultValue();1655}1656 1657LogicalResult spirv::SpecConstantOp::verify() {1658  if (auto specID = (*this)->getAttrOfType<IntegerAttr>(kSpecIdAttrName))1659    if (specID.getValue().isNegative())1660      return emitOpError("SpecId cannot be negative");1661 1662  auto value = getDefaultValue();1663  if (llvm::isa<IntegerAttr, FloatAttr>(value)) {1664    // Make sure bitwidth is allowed.1665    if (!llvm::isa<spirv::SPIRVType>(value.getType()))1666      return emitOpError("default value bitwidth disallowed");1667    return success();1668  }1669  return emitOpError(1670      "default value can only be a bool, integer, or float scalar");1671}1672 1673//===----------------------------------------------------------------------===//1674// spirv.VectorShuffle1675//===----------------------------------------------------------------------===//1676 1677LogicalResult spirv::VectorShuffleOp::verify() {1678  VectorType resultType = llvm::cast<VectorType>(getType());1679 1680  size_t numResultElements = resultType.getNumElements();1681  if (numResultElements != getComponents().size())1682    return emitOpError("result type element count (")1683           << numResultElements1684           << ") mismatch with the number of component selectors ("1685           << getComponents().size() << ")";1686 1687  size_t totalSrcElements =1688      llvm::cast<VectorType>(getVector1().getType()).getNumElements() +1689      llvm::cast<VectorType>(getVector2().getType()).getNumElements();1690 1691  for (const auto &selector : getComponents().getAsValueRange<IntegerAttr>()) {1692    uint32_t index = selector.getZExtValue();1693    if (index >= totalSrcElements &&1694        index != std::numeric_limits<uint32_t>().max())1695      return emitOpError("component selector ")1696             << index << " out of range: expected to be in [0, "1697             << totalSrcElements << ") or 0xffffffff";1698  }1699  return success();1700}1701 1702//===----------------------------------------------------------------------===//1703// spirv.MatrixTimesScalar1704//===----------------------------------------------------------------------===//1705 1706LogicalResult spirv::MatrixTimesScalarOp::verify() {1707  Type elementType =1708      llvm::TypeSwitch<Type, Type>(getMatrix().getType())1709          .Case<spirv::CooperativeMatrixType, spirv::MatrixType>(1710              [](auto matrixType) { return matrixType.getElementType(); })1711          .Default(nullptr);1712 1713  assert(elementType && "Unhandled type");1714 1715  // Check that the scalar type is the same as the matrix element type.1716  if (getScalar().getType() != elementType)1717    return emitOpError("input matrix components' type and scaling value must "1718                       "have the same type");1719 1720  return success();1721}1722 1723//===----------------------------------------------------------------------===//1724// spirv.Transpose1725//===----------------------------------------------------------------------===//1726 1727LogicalResult spirv::TransposeOp::verify() {1728  auto inputMatrix = llvm::cast<spirv::MatrixType>(getMatrix().getType());1729  auto resultMatrix = llvm::cast<spirv::MatrixType>(getResult().getType());1730 1731  // Verify that the input and output matrices have correct shapes.1732  if (inputMatrix.getNumRows() != resultMatrix.getNumColumns())1733    return emitError("input matrix rows count must be equal to "1734                     "output matrix columns count");1735 1736  if (inputMatrix.getNumColumns() != resultMatrix.getNumRows())1737    return emitError("input matrix columns count must be equal to "1738                     "output matrix rows count");1739 1740  // Verify that the input and output matrices have the same component type1741  if (inputMatrix.getElementType() != resultMatrix.getElementType())1742    return emitError("input and output matrices must have the same "1743                     "component type");1744 1745  return success();1746}1747 1748//===----------------------------------------------------------------------===//1749// spirv.MatrixTimesVector1750//===----------------------------------------------------------------------===//1751 1752LogicalResult spirv::MatrixTimesVectorOp::verify() {1753  auto matrixType = llvm::cast<spirv::MatrixType>(getMatrix().getType());1754  auto vectorType = llvm::cast<VectorType>(getVector().getType());1755  auto resultType = llvm::cast<VectorType>(getType());1756 1757  if (matrixType.getNumColumns() != vectorType.getNumElements())1758    return emitOpError("matrix columns (")1759           << matrixType.getNumColumns() << ") must match vector operand size ("1760           << vectorType.getNumElements() << ")";1761 1762  if (resultType.getNumElements() != matrixType.getNumRows())1763    return emitOpError("result size (")1764           << resultType.getNumElements() << ") must match the matrix rows ("1765           << matrixType.getNumRows() << ")";1766 1767  if (matrixType.getElementType() != resultType.getElementType())1768    return emitOpError("matrix and result element types must match");1769 1770  return success();1771}1772 1773//===----------------------------------------------------------------------===//1774// spirv.VectorTimesMatrix1775//===----------------------------------------------------------------------===//1776 1777LogicalResult spirv::VectorTimesMatrixOp::verify() {1778  auto vectorType = llvm::cast<VectorType>(getVector().getType());1779  auto matrixType = llvm::cast<spirv::MatrixType>(getMatrix().getType());1780  auto resultType = llvm::cast<VectorType>(getType());1781 1782  if (matrixType.getNumRows() != vectorType.getNumElements())1783    return emitOpError("number of components in vector must equal the number "1784                       "of components in each column in matrix");1785 1786  if (resultType.getNumElements() != matrixType.getNumColumns())1787    return emitOpError("number of columns in matrix must equal the number of "1788                       "components in result");1789 1790  if (matrixType.getElementType() != resultType.getElementType())1791    return emitOpError("matrix must be a matrix with the same component type "1792                       "as the component type in result");1793 1794  return success();1795}1796 1797//===----------------------------------------------------------------------===//1798// spirv.MatrixTimesMatrix1799//===----------------------------------------------------------------------===//1800 1801LogicalResult spirv::MatrixTimesMatrixOp::verify() {1802  auto leftMatrix = llvm::cast<spirv::MatrixType>(getLeftmatrix().getType());1803  auto rightMatrix = llvm::cast<spirv::MatrixType>(getRightmatrix().getType());1804  auto resultMatrix = llvm::cast<spirv::MatrixType>(getResult().getType());1805 1806  // left matrix columns' count and right matrix rows' count must be equal1807  if (leftMatrix.getNumColumns() != rightMatrix.getNumRows())1808    return emitError("left matrix columns' count must be equal to "1809                     "the right matrix rows' count");1810 1811  // right and result matrices columns' count must be the same1812  if (rightMatrix.getNumColumns() != resultMatrix.getNumColumns())1813    return emitError(1814        "right and result matrices must have equal columns' count");1815 1816  // right and result matrices component type must be the same1817  if (rightMatrix.getElementType() != resultMatrix.getElementType())1818    return emitError("right and result matrices' component type must"1819                     " be the same");1820 1821  // left and result matrices component type must be the same1822  if (leftMatrix.getElementType() != resultMatrix.getElementType())1823    return emitError("left and result matrices' component type"1824                     " must be the same");1825 1826  // left and result matrices rows count must be the same1827  if (leftMatrix.getNumRows() != resultMatrix.getNumRows())1828    return emitError("left and result matrices must have equal rows' count");1829 1830  return success();1831}1832 1833//===----------------------------------------------------------------------===//1834// spirv.SpecConstantComposite1835//===----------------------------------------------------------------------===//1836 1837ParseResult spirv::SpecConstantCompositeOp::parse(OpAsmParser &parser,1838                                                  OperationState &result) {1839 1840  StringAttr compositeName;1841  if (parser.parseSymbolName(compositeName, SymbolTable::getSymbolAttrName(),1842                             result.attributes))1843    return failure();1844 1845  if (parser.parseLParen())1846    return failure();1847 1848  SmallVector<Attribute, 4> constituents;1849 1850  do {1851    // The name of the constituent attribute isn't important1852    const char *attrName = "spec_const";1853    FlatSymbolRefAttr specConstRef;1854    NamedAttrList attrs;1855 1856    if (parser.parseAttribute(specConstRef, Type(), attrName, attrs))1857      return failure();1858 1859    constituents.push_back(specConstRef);1860  } while (!parser.parseOptionalComma());1861 1862  if (parser.parseRParen())1863    return failure();1864 1865  StringAttr compositeSpecConstituentsName =1866      spirv::SpecConstantCompositeOp::getConstituentsAttrName(result.name);1867  result.addAttribute(compositeSpecConstituentsName,1868                      parser.getBuilder().getArrayAttr(constituents));1869 1870  Type type;1871  if (parser.parseColonType(type))1872    return failure();1873 1874  StringAttr typeAttrName =1875      spirv::SpecConstantCompositeOp::getTypeAttrName(result.name);1876  result.addAttribute(typeAttrName, TypeAttr::get(type));1877 1878  return success();1879}1880 1881void spirv::SpecConstantCompositeOp::print(OpAsmPrinter &printer) {1882  printer << " ";1883  printer.printSymbolName(getSymName());1884  printer << " (" << llvm::interleaved(this->getConstituents().getValue())1885          << ") : " << getType();1886}1887 1888LogicalResult spirv::SpecConstantCompositeOp::verify() {1889  auto cType = llvm::dyn_cast<spirv::CompositeType>(getType());1890  auto constituents = this->getConstituents().getValue();1891 1892  if (!cType)1893    return emitError("result type must be a composite type, but provided ")1894           << getType();1895 1896  if (llvm::isa<spirv::CooperativeMatrixType>(cType))1897    return emitError("unsupported composite type  ") << cType;1898  if (constituents.size() != cType.getNumElements())1899    return emitError("has incorrect number of operands: expected ")1900           << cType.getNumElements() << ", but provided "1901           << constituents.size();1902 1903  for (auto index : llvm::seq<uint32_t>(0, constituents.size())) {1904    auto constituent = llvm::cast<FlatSymbolRefAttr>(constituents[index]);1905 1906    auto constituentSpecConstOp =1907        dyn_cast<spirv::SpecConstantOp>(SymbolTable::lookupNearestSymbolFrom(1908            (*this)->getParentOp(), constituent.getAttr()));1909 1910    if (constituentSpecConstOp.getDefaultValue().getType() !=1911        cType.getElementType(index))1912      return emitError("has incorrect types of operands: expected ")1913             << cType.getElementType(index) << ", but provided "1914             << constituentSpecConstOp.getDefaultValue().getType();1915  }1916 1917  return success();1918}1919 1920//===----------------------------------------------------------------------===//1921// spirv.EXTSpecConstantCompositeReplicateOp1922//===----------------------------------------------------------------------===//1923 1924ParseResult1925spirv::EXTSpecConstantCompositeReplicateOp::parse(OpAsmParser &parser,1926                                                  OperationState &result) {1927  StringAttr compositeName;1928  FlatSymbolRefAttr specConstRef;1929  const char *attrName = "spec_const";1930  NamedAttrList attrs;1931  Type type;1932 1933  if (parser.parseSymbolName(compositeName, SymbolTable::getSymbolAttrName(),1934                             result.attributes) ||1935      parser.parseLParen() ||1936      parser.parseAttribute(specConstRef, Type(), attrName, attrs) ||1937      parser.parseRParen() || parser.parseColonType(type))1938    return failure();1939 1940  StringAttr compositeSpecConstituentName =1941      spirv::EXTSpecConstantCompositeReplicateOp::getConstituentAttrName(1942          result.name);1943  result.addAttribute(compositeSpecConstituentName, specConstRef);1944 1945  StringAttr typeAttrName =1946      spirv::EXTSpecConstantCompositeReplicateOp::getTypeAttrName(result.name);1947  result.addAttribute(typeAttrName, TypeAttr::get(type));1948 1949  return success();1950}1951 1952void spirv::EXTSpecConstantCompositeReplicateOp::print(OpAsmPrinter &printer) {1953  printer << " ";1954  printer.printSymbolName(getSymName());1955  printer << " (" << this->getConstituent() << ") : " << getType();1956}1957 1958LogicalResult spirv::EXTSpecConstantCompositeReplicateOp::verify() {1959  auto compositeType = dyn_cast<spirv::CompositeType>(getType());1960  if (!compositeType)1961    return emitError("result type must be a composite type, but provided ")1962           << getType();1963 1964  Operation *constituentOp = SymbolTable::lookupNearestSymbolFrom(1965      (*this)->getParentOp(), this->getConstituent());1966  if (!constituentOp)1967    return emitError(1968        "splat spec constant reference defining constituent not found");1969 1970  auto constituentSpecConstOp = dyn_cast<spirv::SpecConstantOp>(constituentOp);1971  if (!constituentSpecConstOp)1972    return emitError("constituent is not a spec constant");1973 1974  Type constituentType = constituentSpecConstOp.getDefaultValue().getType();1975  Type compositeElementType = compositeType.getElementType(0);1976  if (constituentType != compositeElementType)1977    return emitError("constituent has incorrect type: expected ")1978           << compositeElementType << ", but provided " << constituentType;1979 1980  return success();1981}1982 1983//===----------------------------------------------------------------------===//1984// spirv.SpecConstantOperation1985//===----------------------------------------------------------------------===//1986 1987ParseResult spirv::SpecConstantOperationOp::parse(OpAsmParser &parser,1988                                                  OperationState &result) {1989  Region *body = result.addRegion();1990 1991  if (parser.parseKeyword("wraps"))1992    return failure();1993 1994  body->push_back(new Block);1995  Block &block = body->back();1996  Operation *wrappedOp = parser.parseGenericOperation(&block, block.begin());1997 1998  if (!wrappedOp)1999    return failure();2000 2001  OpBuilder builder(parser.getContext());2002  builder.setInsertionPointToEnd(&block);2003  spirv::YieldOp::create(builder, wrappedOp->getLoc(), wrappedOp->getResult(0));2004  result.location = wrappedOp->getLoc();2005 2006  result.addTypes(wrappedOp->getResult(0).getType());2007 2008  if (parser.parseOptionalAttrDict(result.attributes))2009    return failure();2010 2011  return success();2012}2013 2014void spirv::SpecConstantOperationOp::print(OpAsmPrinter &printer) {2015  printer << " wraps ";2016  printer.printGenericOp(&getBody().front().front());2017}2018 2019LogicalResult spirv::SpecConstantOperationOp::verifyRegions() {2020  Block &block = getRegion().getBlocks().front();2021 2022  if (block.getOperations().size() != 2)2023    return emitOpError("expected exactly 2 nested ops");2024 2025  Operation &enclosedOp = block.getOperations().front();2026 2027  if (!enclosedOp.hasTrait<OpTrait::spirv::UsableInSpecConstantOp>())2028    return emitOpError("invalid enclosed op");2029 2030  for (auto operand : enclosedOp.getOperands())2031    if (!isa<spirv::ConstantOp, spirv::ReferenceOfOp,2032             spirv::SpecConstantOperationOp>(operand.getDefiningOp()))2033      return emitOpError(2034          "invalid operand, must be defined by a constant operation");2035 2036  return success();2037}2038 2039//===----------------------------------------------------------------------===//2040// spirv.GL.FrexpStruct2041//===----------------------------------------------------------------------===//2042 2043LogicalResult spirv::GLFrexpStructOp::verify() {2044  spirv::StructType structTy =2045      llvm::dyn_cast<spirv::StructType>(getResult().getType());2046 2047  if (structTy.getNumElements() != 2)2048    return emitError("result type must be a struct type with two memebers");2049 2050  Type significandTy = structTy.getElementType(0);2051  Type exponentTy = structTy.getElementType(1);2052  VectorType exponentVecTy = llvm::dyn_cast<VectorType>(exponentTy);2053  IntegerType exponentIntTy = llvm::dyn_cast<IntegerType>(exponentTy);2054 2055  Type operandTy = getOperand().getType();2056  VectorType operandVecTy = llvm::dyn_cast<VectorType>(operandTy);2057  FloatType operandFTy = llvm::dyn_cast<FloatType>(operandTy);2058 2059  if (significandTy != operandTy)2060    return emitError("member zero of the resulting struct type must be the "2061                     "same type as the operand");2062 2063  if (exponentVecTy) {2064    IntegerType componentIntTy =2065        llvm::dyn_cast<IntegerType>(exponentVecTy.getElementType());2066    if (!componentIntTy || componentIntTy.getWidth() != 32)2067      return emitError("member one of the resulting struct type must"2068                       "be a scalar or vector of 32 bit integer type");2069  } else if (!exponentIntTy || exponentIntTy.getWidth() != 32) {2070    return emitError("member one of the resulting struct type "2071                     "must be a scalar or vector of 32 bit integer type");2072  }2073 2074  // Check that the two member types have the same number of components2075  if (operandVecTy && exponentVecTy &&2076      (exponentVecTy.getNumElements() == operandVecTy.getNumElements()))2077    return success();2078 2079  if (operandFTy && exponentIntTy)2080    return success();2081 2082  return emitError("member one of the resulting struct type must have the same "2083                   "number of components as the operand type");2084}2085 2086//===----------------------------------------------------------------------===//2087// spirv.GL.Ldexp2088//===----------------------------------------------------------------------===//2089 2090LogicalResult spirv::GLLdexpOp::verify() {2091  Type significandType = getX().getType();2092  Type exponentType = getExp().getType();2093 2094  if (llvm::isa<FloatType>(significandType) !=2095      llvm::isa<IntegerType>(exponentType))2096    return emitOpError("operands must both be scalars or vectors");2097 2098  auto getNumElements = [](Type type) -> unsigned {2099    if (auto vectorType = llvm::dyn_cast<VectorType>(type))2100      return vectorType.getNumElements();2101    return 1;2102  };2103 2104  if (getNumElements(significandType) != getNumElements(exponentType))2105    return emitOpError("operands must have the same number of elements");2106 2107  return success();2108}2109 2110//===----------------------------------------------------------------------===//2111// spirv.ShiftLeftLogicalOp2112//===----------------------------------------------------------------------===//2113 2114LogicalResult spirv::ShiftLeftLogicalOp::verify() {2115  return verifyShiftOp(*this);2116}2117 2118//===----------------------------------------------------------------------===//2119// spirv.ShiftRightArithmeticOp2120//===----------------------------------------------------------------------===//2121 2122LogicalResult spirv::ShiftRightArithmeticOp::verify() {2123  return verifyShiftOp(*this);2124}2125 2126//===----------------------------------------------------------------------===//2127// spirv.ShiftRightLogicalOp2128//===----------------------------------------------------------------------===//2129 2130LogicalResult spirv::ShiftRightLogicalOp::verify() {2131  return verifyShiftOp(*this);2132}2133 2134//===----------------------------------------------------------------------===//2135// spirv.VectorTimesScalarOp2136//===----------------------------------------------------------------------===//2137 2138LogicalResult spirv::VectorTimesScalarOp::verify() {2139  if (getVector().getType() != getType())2140    return emitOpError("vector operand and result type mismatch");2141  auto scalarType = llvm::cast<VectorType>(getType()).getElementType();2142  if (getScalar().getType() != scalarType)2143    return emitOpError("scalar operand and result element type match");2144  return success();2145}2146