344 lines · cpp
1//===- ImageOps.cpp - MLIR SPIR-V Image Ops ------------------------------===//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 image operations in the SPIR-V dialect.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"14 15using namespace mlir;16 17//===----------------------------------------------------------------------===//18// Common utility functions19//===----------------------------------------------------------------------===//20 21// TODO: In the future we should model image operands better, so we can move22// some verification into ODS.23static LogicalResult verifyImageOperands(Operation *imageOp,24 spirv::ImageOperandsAttr attr,25 Operation::operand_range operands) {26 if (!attr) {27 if (operands.empty())28 return success();29 30 return imageOp->emitError("the Image Operands should encode what operands "31 "follow, as per Image Operands");32 }33 34 if (spirv::bitEnumContainsAll(attr.getValue(),35 spirv::ImageOperands::Lod |36 spirv::ImageOperands::Grad))37 return imageOp->emitError(38 "it is invalid to set both the Lod and Grad bits");39 40 size_t index = 0;41 42 // The order we process operands is important. In case of multiple argument43 // taking operands, the arguments are ordered starting with operands having44 // smaller-numbered bits first.45 if (spirv::bitEnumContainsAny(attr.getValue(), spirv::ImageOperands::Bias)) {46 if (!isa<spirv::ImplicitLodOpInterface>(imageOp))47 return imageOp->emitError(48 "Bias is only valid with implicit-lod instructions");49 50 if (index + 1 > operands.size())51 return imageOp->emitError("Bias operand requires 1 argument");52 53 if (!isa<FloatType>(operands[index].getType()))54 return imageOp->emitError("Bias must be a floating-point type scalar");55 56 auto samplingOp = cast<spirv::SamplingOpInterface>(imageOp);57 auto sampledImageType =58 cast<spirv::SampledImageType>(samplingOp.getSampledImage().getType());59 auto imageType = cast<spirv::ImageType>(sampledImageType.getImageType());60 61 if (!llvm::is_contained({spirv::Dim::Dim1D, spirv::Dim::Dim2D,62 spirv::Dim::Dim3D, spirv::Dim::Cube},63 imageType.getDim()))64 return imageOp->emitError(65 "Bias must only be used with an image type that has "66 "a dim operand of 1D, 2D, 3D, or Cube");67 68 if (imageType.getSamplingInfo() != spirv::ImageSamplingInfo::SingleSampled)69 return imageOp->emitError("Bias must only be used with an image type "70 "that has a MS operand of 0");71 72 ++index;73 }74 75 if (spirv::bitEnumContainsAny(attr.getValue(), spirv::ImageOperands::Lod)) {76 if (!isa<spirv::ExplicitLodOpInterface>(imageOp) &&77 !isa<spirv::FetchOpInterface>(imageOp))78 return imageOp->emitError(79 "Lod is only valid with explicit-lod and fetch instructions");80 81 if (index + 1 > operands.size())82 return imageOp->emitError("Lod operand requires 1 argument");83 84 spirv::ImageType imageType;85 86 if (isa<spirv::SamplingOpInterface>(imageOp)) {87 if (!isa<mlir::FloatType>(operands[index].getType()))88 return imageOp->emitError("for sampling operations, Lod must be a "89 "floating-point type scalar");90 91 auto samplingOp = cast<spirv::SamplingOpInterface>(imageOp);92 auto sampledImageType = llvm::cast<spirv::SampledImageType>(93 samplingOp.getSampledImage().getType());94 imageType = cast<spirv::ImageType>(sampledImageType.getImageType());95 } else {96 if (!isa<mlir::IntegerType>(operands[index].getType()))97 return imageOp->emitError(98 "for fetch operations, Lod must be an integer type scalar");99 100 auto fetchOp = cast<spirv::FetchOpInterface>(imageOp);101 imageType = cast<spirv::ImageType>(fetchOp.getImage().getType());102 }103 104 if (!llvm::is_contained({spirv::Dim::Dim1D, spirv::Dim::Dim2D,105 spirv::Dim::Dim3D, spirv::Dim::Cube},106 imageType.getDim()))107 return imageOp->emitError(108 "Lod must only be used with an image type that has "109 "a dim operand of 1D, 2D, 3D, or Cube");110 111 if (imageType.getSamplingInfo() != spirv::ImageSamplingInfo::SingleSampled)112 return imageOp->emitError("Lod must only be used with an image type that "113 "has a MS operand of 0");114 115 ++index;116 }117 118 if (spirv::bitEnumContainsAny(attr.getValue(), spirv::ImageOperands::Grad)) {119 if (!isa<spirv::ExplicitLodOpInterface>(imageOp))120 return imageOp->emitError(121 "Grad is only valid with explicit-lod instructions");122 123 if (index + 2 > operands.size())124 return imageOp->emitError(125 "Grad operand requires 2 arguments (scalars or vectors)");126 127 auto samplingOp = cast<spirv::SamplingOpInterface>(imageOp);128 auto sampledImageType =129 cast<spirv::SampledImageType>(samplingOp.getSampledImage().getType());130 auto imageType = cast<spirv::ImageType>(sampledImageType.getImageType());131 132 if (imageType.getSamplingInfo() != spirv::ImageSamplingInfo::SingleSampled)133 return imageOp->emitError("Grad must only be used with an image type "134 "that has a MS operand of 0");135 136 int64_t numberOfComponents = 0;137 138 auto coordVector =139 dyn_cast<mlir::VectorType>(samplingOp.getCoordinate().getType());140 if (coordVector) {141 numberOfComponents = coordVector.getNumElements();142 if (imageType.getArrayedInfo() == spirv::ImageArrayedInfo::Arrayed)143 numberOfComponents -= 1;144 } else {145 numberOfComponents = 1;146 }147 148 assert(numberOfComponents > 0);149 150 auto dXVector = dyn_cast<mlir::VectorType>(operands[index].getType());151 auto dYVector = dyn_cast<mlir::VectorType>(operands[index + 1].getType());152 if (dXVector && dYVector) {153 if (dXVector.getNumElements() != dYVector.getNumElements() ||154 dXVector.getNumElements() != numberOfComponents)155 return imageOp->emitError(156 "number of components of each Grad argument must equal the number "157 "of components in coordinate, minus the array layer component, if "158 "present");159 160 if (!isa<mlir::FloatType>(dXVector.getElementType()) ||161 !isa<mlir::FloatType>(dYVector.getElementType()))162 return imageOp->emitError(163 "Grad arguments must be a vector of floating-point type");164 } else if (isa<mlir::FloatType>(operands[index].getType()) &&165 isa<mlir::FloatType>(operands[index + 1].getType())) {166 if (numberOfComponents != 1)167 return imageOp->emitError(168 "number of components of each Grad argument must equal the number "169 "of components in coordinate, minus the array layer component, if "170 "present");171 } else {172 return imageOp->emitError(173 "Grad arguments must be a scalar or vector of floating-point type");174 }175 176 index += 2;177 }178 179 // TODO: Add the validation rules for the following Image Operands.180 spirv::ImageOperands noSupportOperands =181 spirv::ImageOperands::ConstOffset | spirv::ImageOperands::Offset |182 spirv::ImageOperands::ConstOffsets | spirv::ImageOperands::Sample |183 spirv::ImageOperands::MinLod | spirv::ImageOperands::MakeTexelAvailable |184 spirv::ImageOperands::MakeTexelVisible |185 spirv::ImageOperands::SignExtend | spirv::ImageOperands::ZeroExtend;186 187 assert(!spirv::bitEnumContainsAny(attr.getValue(), noSupportOperands) &&188 "unimplemented operands of Image Operands");189 (void)noSupportOperands;190 191 if (index < operands.size())192 return imageOp->emitError(193 "too many image operand arguments have been provided");194 195 return success();196}197 198//===----------------------------------------------------------------------===//199// spirv.ImageDrefGather200//===----------------------------------------------------------------------===//201 202LogicalResult spirv::ImageDrefGatherOp::verify() {203 return verifyImageOperands(getOperation(), getImageOperandsAttr(),204 getOperandArguments());205}206 207//===----------------------------------------------------------------------===//208// spirv.ImageReadOp209//===----------------------------------------------------------------------===//210 211LogicalResult spirv::ImageReadOp::verify() {212 // TODO: Do we need check for: "If the Arrayed operand is 1, then additional213 // capabilities may be required; e.g., ImageCubeArray, or ImageMSArray."?214 215 // TODO: Ideally it should be somewhere verified that "If the Image Dim216 // operand is not SubpassData, the Image Format must not be Unknown, unless217 // the StorageImageReadWithoutFormat Capability was declared." This function218 // however may not be the suitable place for such verification.219 220 return verifyImageOperands(getOperation(), getImageOperandsAttr(),221 getOperandArguments());222}223 224//===----------------------------------------------------------------------===//225// spirv.ImageWriteOp226//===----------------------------------------------------------------------===//227 228LogicalResult spirv::ImageWriteOp::verify() {229 // TODO: Do we need check for: "If the Arrayed operand is 1, then additional230 // capabilities may be required; e.g., ImageCubeArray, or ImageMSArray."?231 232 // TODO: Ideally it should be somewhere verified that "The Image Format must233 // not be Unknown, unless the StorageImageWriteWithoutFormat Capability was234 // declared." This function however may not be the suitable place for such235 // verification.236 237 return verifyImageOperands(getOperation(), getImageOperandsAttr(),238 getOperandArguments());239}240 241//===----------------------------------------------------------------------===//242// spirv.ImageQuerySize243//===----------------------------------------------------------------------===//244 245LogicalResult spirv::ImageQuerySizeOp::verify() {246 spirv::ImageType imageType =247 llvm::cast<spirv::ImageType>(getImage().getType());248 Type resultType = getResult().getType();249 250 spirv::Dim dim = imageType.getDim();251 spirv::ImageSamplingInfo samplingInfo = imageType.getSamplingInfo();252 spirv::ImageSamplerUseInfo samplerInfo = imageType.getSamplerUseInfo();253 switch (dim) {254 case spirv::Dim::Dim1D:255 case spirv::Dim::Dim2D:256 case spirv::Dim::Dim3D:257 case spirv::Dim::Cube:258 if (samplingInfo != spirv::ImageSamplingInfo::MultiSampled &&259 samplerInfo != spirv::ImageSamplerUseInfo::SamplerUnknown &&260 samplerInfo != spirv::ImageSamplerUseInfo::NoSampler)261 return emitError(262 "if Dim is 1D, 2D, 3D, or Cube, "263 "it must also have either an MS of 1 or a Sampled of 0 or 2");264 break;265 case spirv::Dim::Buffer:266 case spirv::Dim::Rect:267 break;268 default:269 return emitError("the Dim operand of the image type must "270 "be 1D, 2D, 3D, Buffer, Cube, or Rect");271 }272 273 unsigned componentNumber = 0;274 switch (dim) {275 case spirv::Dim::Dim1D:276 case spirv::Dim::Buffer:277 componentNumber = 1;278 break;279 case spirv::Dim::Dim2D:280 case spirv::Dim::Cube:281 case spirv::Dim::Rect:282 componentNumber = 2;283 break;284 case spirv::Dim::Dim3D:285 componentNumber = 3;286 break;287 default:288 break;289 }290 291 if (imageType.getArrayedInfo() == spirv::ImageArrayedInfo::Arrayed)292 componentNumber += 1;293 294 unsigned resultComponentNumber = 1;295 if (auto resultVectorType = llvm::dyn_cast<VectorType>(resultType))296 resultComponentNumber = resultVectorType.getNumElements();297 298 if (componentNumber != resultComponentNumber)299 return emitError("expected the result to have ")300 << componentNumber << " component(s), but found "301 << resultComponentNumber << " component(s)";302 303 return success();304}305 306//===----------------------------------------------------------------------===//307// spirv.ImageSampleImplicitLod308//===----------------------------------------------------------------------===//309 310LogicalResult spirv::ImageSampleImplicitLodOp::verify() {311 return verifyImageOperands(getOperation(), getImageOperandsAttr(),312 getOperandArguments());313}314 315//===----------------------------------------------------------------------===//316// spirv.ImageSampleExplicitLod317//===----------------------------------------------------------------------===//318 319LogicalResult spirv::ImageSampleExplicitLodOp::verify() {320 // TODO: It should be verified somewhere that: "Unless the Kernel capability321 // is declared, it [Coordinate] must be floating point."322 323 return verifyImageOperands(getOperation(), getImageOperandsAttr(),324 getOperandArguments());325}326 327//===----------------------------------------------------------------------===//328// spirv.ImageSampleProjDrefImplicitLod329//===----------------------------------------------------------------------===//330 331LogicalResult spirv::ImageSampleProjDrefImplicitLodOp::verify() {332 return verifyImageOperands(getOperation(), getImageOperandsAttr(),333 getOperandArguments());334}335 336//===----------------------------------------------------------------------===//337// spirv.ImageFetchOp338//===----------------------------------------------------------------------===//339 340LogicalResult spirv::ImageFetchOp::verify() {341 return verifyImageOperands(getOperation(), getImageOperandsAttr(),342 getOperandArguments());343}344