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