-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[mlir][spirv] Refactor image operations #128552
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-mlir-spirv Author: Igor Wodiany (IgWod-IMG) ChangesThis patch makes multiple changes to images ops:
This change is made in preparation for adding more Image ops. Change to the assembly format was previously mentioned in #124124. Patch is 37.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128552.diff 6 Files Affected:
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td
index b7d6ec70ce141..a4fe29536e60a 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
//
// This file contains image ops for the SPIR-V dialect. It corresponds
-// to "3.37.10. Image Instructions" of the SPIR-V specification.
+// to "3.56.10. Image Instructions" of the SPIR-V specification.
//
//===----------------------------------------------------------------------===//
@@ -19,12 +19,56 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
// -----
-def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
+class SPIRV_ValuesAreContained<string operand, list<string> values, string transform, string type, string getter> :
+ CPred<"::llvm::is_contained("
+ "{::mlir::spirv::" # type # "::" # !interleave(values, ", ::mlir::spirv::" # type # "::") # "},"
+ "::llvm::cast<::mlir::spirv::ImageType>(" # !subst("$_self", "$" # operand # ".getType()", transform) # ")." # getter # "()"
+ ")"
+>;
+
+class SPIRV_SampledOperandIs<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the sampled operand of the underlying image must be " # !interleave(values, " or "),
+ SPIRV_ValuesAreContained<operand, values, transform, "ImageSamplerUseInfo", "getSamplerUseInfo">
+>;
+
+class SPIRV_MSOperandIs<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the MS operand of the underlying image type must be " # !interleave(values, " or "),
+ SPIRV_ValuesAreContained<operand, values, transform, "ImageSamplingInfo", "getSamplingInfo">
+>;
+
+class SPIRV_DimIs<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the Dim operand of the underlying image must be " # !interleave(values, " or "),
+ SPIRV_ValuesAreContained<operand, values, transform, "Dim", "getDim">
+>;
+
+class SPIRV_DimIsNot<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the Dim operand of the underlying image must not be " # !interleave(values, " or "),
+ Neg<SPIRV_ValuesAreContained<operand, values, transform, "Dim", "getDim">>
+>;
+
+class SPIRV_NoneOrElementMatchImage<string operand, string image, string transform="$_self"> : PredOpTrait<
+ "the " # operand # " component type must match the image sampled type",
+ CPred<"::llvm::isa<NoneType>(cast<ImageType>(" # !subst("$_self", "$" # image # ".getType()", transform) # ").getElementType()) ||"
+ "(getElementTypeOrSelf($" # operand # ")"
+ "=="
+ "cast<ImageType>(" # !subst("$_self", "$" # image # ".getType()", transform) # ").getElementType())"
+ >
+>;
+
+def SPIRV_SampledImageTransform : StrFunc<"llvm::cast<spirv::SampledImageType>($_self).getImageType()">;
+
+// -----
+
+def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather",
+ [Pure,
+ SPIRV_DimIs<"sampled_image", ["Dim2D", "Cube", "Rect"], SPIRV_SampledImageTransform.result>,
+ SPIRV_MSOperandIs<"sampled_image", ["SingleSampled"], SPIRV_SampledImageTransform.result>,
+ SPIRV_NoneOrElementMatchImage<"result", "sampled_image", SPIRV_SampledImageTransform.result>]>{
let summary = "Gathers the requested depth-comparison from four texels.";
let description = [{
Result Type must be a vector of four components of floating-point type
- or integer type. Its components must be the same as Sampled Type of the
+ or integer type. Its components must be the same as Sampled Type of the
underlying OpTypeImage (unless that underlying Sampled Type is
OpTypeVoid). It has one component per gathered texel.
@@ -32,8 +76,8 @@ def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
OpTypeImage must have a Dim of 2D, Cube, or Rect. The MS operand of the
underlying OpTypeImage must be 0.
- Coordinate must be a scalar or vector of floating-point type. It
- contains (u[, v] … [, array layer]) as needed by the definition of
+ Coordinate must be a scalar or vector of floating-point type. It
+ contains (u[, v] ... [, array layer]) as needed by the definition of
Sampled Image.
Dref is the depth-comparison reference value. It must be a 32-bit
@@ -44,8 +88,8 @@ def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
#### Example:
```mlir
- %0 = spirv.ImageDrefGather %1 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, %2 : vector<4xf32>, %3 : f32 -> vector<4xi32>
- %0 = spirv.ImageDrefGather %1 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, %2 : vector<4xf32>, %3 : f32 ["NonPrivateTexel"] : f32, f32 -> vector<4xi32>
+ %0 = spirv.ImageDrefGather %1, %2, %3 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, vector<4xf32>, f32 -> vector<4xi32>
+ %0 = spirv.ImageDrefGather %1, %2, %3 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, vector<4xf32>, f32 ["NonPrivateTexel"] -> vector<4xi32>
```
}];
@@ -57,23 +101,24 @@ def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
];
let arguments = (ins
- SPIRV_AnySampledImage:$sampledimage,
+ SPIRV_AnySampledImage:$sampled_image,
SPIRV_ScalarOrVectorOf<SPIRV_Float>:$coordinate,
- SPIRV_Float:$dref,
- OptionalAttr<SPIRV_ImageOperandsAttr>:$imageoperands,
+ SPIRV_Float32:$dref,
+ OptionalAttr<SPIRV_ImageOperandsAttr>:$image_operands,
Variadic<SPIRV_Type>:$operand_arguments
);
let results = (outs
- SPIRV_Vector:$result
+ AnyTypeOf<[SPIRV_Vec4<SPIRV_Integer>, SPIRV_Vec4<SPIRV_Float>]>:$result
);
- let assemblyFormat = [{$sampledimage `:` type($sampledimage) `,`
- $coordinate `:` type($coordinate) `,` $dref `:` type($dref)
- custom<ImageOperands>($imageoperands)
- ( `(` $operand_arguments^ `:` type($operand_arguments) `)`)?
- attr-dict
- `->` type($result)}];
+
+ let assemblyFormat = [{
+ $sampled_image `,` $coordinate `,` $dref custom<ImageOperands>($image_operands) ( `(` $operand_arguments^ `)` )? attr-dict
+ `:` type($sampled_image) `,` type($coordinate) `,` type($dref) ( `(` type($operand_arguments)^ `)` )?
+ `->` type($result)
+ }];
+
}
// -----
@@ -82,7 +127,7 @@ def SPIRV_ImageQuerySizeOp : SPIRV_Op<"ImageQuerySize", [Pure]> {
let summary = "Query the dimensions of Image, with no level of detail.";
let description = [{
- Result Type must be an integer type scalar or vector. The number of
+ Result Type must be an integer type scalar or vector. The number of
components must be:
1 for the 1D and Buffer dimensionalities,
@@ -130,12 +175,15 @@ def SPIRV_ImageQuerySizeOp : SPIRV_Op<"ImageQuerySize", [Pure]> {
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$result
);
- let assemblyFormat = "attr-dict $image `:` type($image) `->` type($result)";
+ let assemblyFormat = "$image attr-dict `:` type($image) `->` type($result)";
}
// -----
-def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite", []> {
+def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite",
+ [SPIRV_SampledOperandIs<"image", ["SamplerUnknown", "NoSampler"]>,
+ SPIRV_DimIsNot<"image", ["SubpassData"]>,
+ SPIRV_NoneOrElementMatchImage<"texel", "image">]> {
let summary = "Write a texel to an image without a sampler.";
let description = [{
@@ -163,7 +211,7 @@ def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite", []> {
#### Example:
```mlir
- spirv.ImageWrite %0 : !spirv.image<f32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Rgba16>, %1 : vector<2xsi32>, %2 : vector<4xf32>
+ spirv.ImageWrite %0, %1, %2 : !spirv.image<f32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Rgba16>, vector<2xsi32>, vector<4xf32>
```
}];
@@ -177,20 +225,18 @@ def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite", []> {
let results = (outs);
- let assemblyFormat = [{$image `:` type($image) `,`
- $coordinate `:` type($coordinate) `,`
- $texel `:` type($texel)
- custom<ImageOperands>($image_operands)
- ( `(` $operand_arguments^ `:` type($operand_arguments) `)`)?
- attr-dict}];
+ let assemblyFormat = [{
+ $image `,` $coordinate `,` $texel custom<ImageOperands>($image_operands) ( `(` $operand_arguments^ `)`)? attr-dict
+ `:` type($image) `,` type($coordinate) `,` type($texel) ( `(` type($operand_arguments)^ `)`)?
+ }];
}
// -----
def SPIRV_ImageOp : SPIRV_Op<"Image",
[Pure,
- TypesMatchWith<"type of 'result' matches image type of 'sampledimage'",
- "sampledimage", "result",
+ TypesMatchWith<"type of 'result' matches image type of 'sampled_image'",
+ "sampled_image", "result",
"::llvm::cast<spirv::SampledImageType>($_self).getImageType()">]> {
let summary = "Extract the image from a sampled image.";
@@ -210,14 +256,14 @@ def SPIRV_ImageOp : SPIRV_Op<"Image",
}];
let arguments = (ins
- SPIRV_AnySampledImage:$sampledimage
+ SPIRV_AnySampledImage:$sampled_image
);
let results = (outs
SPIRV_AnyImage:$result
);
- let assemblyFormat = "attr-dict $sampledimage `:` type($sampledimage)";
+ let assemblyFormat = "$sampled_image attr-dict `:` type($sampled_image)";
let hasVerifier = 0;
}
diff --git a/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt b/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt
index ae8ad5a491ff2..235beb0b6a097 100644
--- a/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt
+++ b/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt
@@ -8,6 +8,7 @@ add_mlir_dialect_library(MLIRSPIRVDialect
ControlFlowOps.cpp
CooperativeMatrixOps.cpp
GroupOps.cpp
+ ImageOps.cpp
IntegerDotProductOps.cpp
MemoryOps.cpp
MeshOps.cpp
diff --git a/mlir/lib/Dialect/SPIRV/IR/ImageOps.cpp b/mlir/lib/Dialect/SPIRV/IR/ImageOps.cpp
new file mode 100644
index 0000000000000..9513a9c74634e
--- /dev/null
+++ b/mlir/lib/Dialect/SPIRV/IR/ImageOps.cpp
@@ -0,0 +1,138 @@
+//===- ImageOps.cpp - MLIR SPIR-V Image Ops ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the image operations in the SPIR-V dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
+
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+// Common utility functions
+//===----------------------------------------------------------------------===//
+
+template <typename Op>
+static LogicalResult verifyImageOperands(Op imageOp,
+ spirv::ImageOperandsAttr attr,
+ Operation::operand_range operands) {
+ if (!attr) {
+ if (operands.empty())
+ return success();
+
+ return imageOp.emitError("the Image Operands should encode what operands "
+ "follow, as per Image Operands");
+ }
+
+ // TODO: Add the validation rules for the following Image Operands.
+ spirv::ImageOperands noSupportOperands =
+ spirv::ImageOperands::Bias | spirv::ImageOperands::Lod |
+ spirv::ImageOperands::Grad | spirv::ImageOperands::ConstOffset |
+ spirv::ImageOperands::Offset | spirv::ImageOperands::ConstOffsets |
+ spirv::ImageOperands::Sample | spirv::ImageOperands::MinLod |
+ spirv::ImageOperands::MakeTexelAvailable |
+ spirv::ImageOperands::MakeTexelVisible |
+ spirv::ImageOperands::SignExtend | spirv::ImageOperands::ZeroExtend;
+
+ if (spirv::bitEnumContainsAny(attr.getValue(), noSupportOperands))
+ llvm_unreachable("unimplemented operands of Image Operands");
+
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.ImageDrefGather
+//===----------------------------------------------------------------------===//
+
+LogicalResult spirv::ImageDrefGatherOp::verify() {
+ return verifyImageOperands(*this, getImageOperandsAttr(),
+ getOperandArguments());
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.ImageWriteOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult spirv::ImageWriteOp::verify() {
+ // TODO: Do we need check for: "If the Arrayed operand is 1, then additional
+ // capabilities may be required; e.g., ImageCubeArray, or ImageMSArray."?
+
+ // TODO: Ideally it should be somewhere verified that "The Image Format must
+ // not be Unknown, unless the StorageImageWriteWithoutFormat Capability was
+ // declared." This function however may not be the suitable place for such
+ // verification.
+
+ return verifyImageOperands(*this, getImageOperandsAttr(),
+ getOperandArguments());
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.ImageQuerySize
+//===----------------------------------------------------------------------===//
+
+LogicalResult spirv::ImageQuerySizeOp::verify() {
+ spirv::ImageType imageType =
+ llvm::cast<spirv::ImageType>(getImage().getType());
+ Type resultType = getResult().getType();
+
+ spirv::Dim dim = imageType.getDim();
+ spirv::ImageSamplingInfo samplingInfo = imageType.getSamplingInfo();
+ spirv::ImageSamplerUseInfo samplerInfo = imageType.getSamplerUseInfo();
+ switch (dim) {
+ case spirv::Dim::Dim1D:
+ case spirv::Dim::Dim2D:
+ case spirv::Dim::Dim3D:
+ case spirv::Dim::Cube:
+ if (samplingInfo != spirv::ImageSamplingInfo::MultiSampled &&
+ samplerInfo != spirv::ImageSamplerUseInfo::SamplerUnknown &&
+ samplerInfo != spirv::ImageSamplerUseInfo::NoSampler)
+ return emitError(
+ "if Dim is 1D, 2D, 3D, or Cube, "
+ "it must also have either an MS of 1 or a Sampled of 0 or 2");
+ break;
+ case spirv::Dim::Buffer:
+ case spirv::Dim::Rect:
+ break;
+ default:
+ return emitError("the Dim operand of the image type must "
+ "be 1D, 2D, 3D, Buffer, Cube, or Rect");
+ }
+
+ unsigned componentNumber = 0;
+ switch (dim) {
+ case spirv::Dim::Dim1D:
+ case spirv::Dim::Buffer:
+ componentNumber = 1;
+ break;
+ case spirv::Dim::Dim2D:
+ case spirv::Dim::Cube:
+ case spirv::Dim::Rect:
+ componentNumber = 2;
+ break;
+ case spirv::Dim::Dim3D:
+ componentNumber = 3;
+ break;
+ default:
+ break;
+ }
+
+ if (imageType.getArrayedInfo() == spirv::ImageArrayedInfo::Arrayed)
+ componentNumber += 1;
+
+ unsigned resultComponentNumber = 1;
+ if (auto resultVectorType = llvm::dyn_cast<VectorType>(resultType))
+ resultComponentNumber = resultVectorType.getNumElements();
+
+ if (componentNumber != resultComponentNumber)
+ return emitError("expected the result to have ")
+ << componentNumber << " component(s), but found "
+ << resultComponentNumber << " component(s)";
+
+ return success();
+}
diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
index dc414339ae7b8..da9855b02860d 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
@@ -166,34 +166,6 @@ static void printOneResultOp(Operation *op, OpAsmPrinter &p) {
p << " : " << resultType;
}
-template <typename Op>
-static LogicalResult verifyImageOperands(Op imageOp,
- spirv::ImageOperandsAttr attr,
- Operation::operand_range operands) {
- if (!attr) {
- if (operands.empty())
- return success();
-
- return imageOp.emitError("the Image Operands should encode what operands "
- "follow, as per Image Operands");
- }
-
- // TODO: Add the validation rules for the following Image Operands.
- spirv::ImageOperands noSupportOperands =
- spirv::ImageOperands::Bias | spirv::ImageOperands::Lod |
- spirv::ImageOperands::Grad | spirv::ImageOperands::ConstOffset |
- spirv::ImageOperands::Offset | spirv::ImageOperands::ConstOffsets |
- spirv::ImageOperands::Sample | spirv::ImageOperands::MinLod |
- spirv::ImageOperands::MakeTexelAvailable |
- spirv::ImageOperands::MakeTexelVisible |
- spirv::ImageOperands::SignExtend | spirv::ImageOperands::ZeroExtend;
-
- if (spirv::bitEnumContainsAll(attr.getValue(), noSupportOperands))
- llvm_unreachable("unimplemented operands of Image Operands");
-
- return success();
-}
-
template <typename BlockReadWriteOpTy>
static LogicalResult verifyBlockReadWritePtrAndValTypes(BlockReadWriteOpTy op,
Value ptr, Value val) {
@@ -2002,85 +1974,6 @@ LogicalResult spirv::GLLdexpOp::verify() {
return success();
}
-//===----------------------------------------------------------------------===//
-// spirv.ImageDrefGather
-//===----------------------------------------------------------------------===//
-
-LogicalResult spirv::ImageDrefGatherOp::verify() {
- VectorType resultType = llvm::cast<VectorType>(getResult().getType());
- auto sampledImageType =
- llvm::cast<spirv::SampledImageType>(getSampledimage().getType());
- auto imageType =
- llvm::cast<spirv::ImageType>(sampledImageType.getImageType());
-
- if (resultType.getNumElements() != 4)
- return emitOpError("result type must be a vector of four components");
-
- Type elementType = resultType.getElementType();
- Type sampledElementType = imageType.getElementType();
- if (!llvm::isa<NoneType>(sampledElementType) &&
- elementType != sampledElementType)
- return emitOpError(
- "the component type of result must be the same as sampled type of the "
- "underlying image type");
-
- spirv::Dim imageDim = imageType.getDim();
- spirv::ImageSamplingInfo imageMS = imageType.getSamplingInfo();
-
- if (imageDim != spirv::Dim::Dim2D && imageDim != spirv::Dim::Cube &&
- imageDim != spirv::Dim::Rect)
- return emitOpError(
- "the Dim operand of the underlying image type must be 2D, Cube, or "
- "Rect");
-
- if (imageMS != spirv::ImageSamplingInfo::SingleSampled)
- return emitOpError("the MS operand of the underlying image type must be 0");
-
- spirv::ImageOperandsAttr attr = getImageoperandsAttr();
- auto operandArguments = getOperandArguments();
-
- return verifyImageOperands(*this, attr, operandArguments);
-}
-
-//===----------------------------------------------------------------------===//
-// spirv.ImageWriteOp
-//===----------------------------------------------------------------------===//
-
-LogicalResult spirv::ImageWriteOp::verify() {
- ImageType imageType = cast<ImageType>(getImage().getType());
- Type sampledType = imageType.getElementType();
- ImageSamplerUseInfo samplerInfo = imageType.getSamplerUseInfo();
-
- if (!llvm::is_contained({spirv::ImageSamplerUseInfo::SamplerUnknown,
- spirv::ImageSamplerUseInfo::NoSampler},
- samplerInfo)) {
- return emitOpError(
- "the sampled operand of the underlying image must be 0 or 2");
- }
-
- // TODO: Do we need check for: "If the Arrayed operand is 1, then additional
- // capabilities may be required; e.g., ImageCubeArray, or ImageMSArray."?
-
- if (imageType.getDim() == spirv::Dim::SubpassData) {
- return emitOpError(
- "the Dim operand of the underlying image must not be SubpassData");
- }
-
- Type texelType = getElementTypeOrSelf(getTexel());
- if (!isa<NoneType>(sampledType) && texelType != sampledType) {
- return emitOpError(
- "the texel component type must match the image sampled type");
- }
-
- // TODO: Ideally it should be somewhere verified that ...
[truncated]
|
@llvm/pr-subscribers-mlir Author: Igor Wodiany (IgWod-IMG) ChangesThis patch makes multiple changes to images ops:
This change is made in preparation for adding more Image ops. Change to the assembly format was previously mentioned in #124124. Patch is 37.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/128552.diff 6 Files Affected:
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td
index b7d6ec70ce141..a4fe29536e60a 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVImageOps.td
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
//
// This file contains image ops for the SPIR-V dialect. It corresponds
-// to "3.37.10. Image Instructions" of the SPIR-V specification.
+// to "3.56.10. Image Instructions" of the SPIR-V specification.
//
//===----------------------------------------------------------------------===//
@@ -19,12 +19,56 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
// -----
-def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
+class SPIRV_ValuesAreContained<string operand, list<string> values, string transform, string type, string getter> :
+ CPred<"::llvm::is_contained("
+ "{::mlir::spirv::" # type # "::" # !interleave(values, ", ::mlir::spirv::" # type # "::") # "},"
+ "::llvm::cast<::mlir::spirv::ImageType>(" # !subst("$_self", "$" # operand # ".getType()", transform) # ")." # getter # "()"
+ ")"
+>;
+
+class SPIRV_SampledOperandIs<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the sampled operand of the underlying image must be " # !interleave(values, " or "),
+ SPIRV_ValuesAreContained<operand, values, transform, "ImageSamplerUseInfo", "getSamplerUseInfo">
+>;
+
+class SPIRV_MSOperandIs<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the MS operand of the underlying image type must be " # !interleave(values, " or "),
+ SPIRV_ValuesAreContained<operand, values, transform, "ImageSamplingInfo", "getSamplingInfo">
+>;
+
+class SPIRV_DimIs<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the Dim operand of the underlying image must be " # !interleave(values, " or "),
+ SPIRV_ValuesAreContained<operand, values, transform, "Dim", "getDim">
+>;
+
+class SPIRV_DimIsNot<string operand, list<string> values, string transform="$_self"> : PredOpTrait<
+ "the Dim operand of the underlying image must not be " # !interleave(values, " or "),
+ Neg<SPIRV_ValuesAreContained<operand, values, transform, "Dim", "getDim">>
+>;
+
+class SPIRV_NoneOrElementMatchImage<string operand, string image, string transform="$_self"> : PredOpTrait<
+ "the " # operand # " component type must match the image sampled type",
+ CPred<"::llvm::isa<NoneType>(cast<ImageType>(" # !subst("$_self", "$" # image # ".getType()", transform) # ").getElementType()) ||"
+ "(getElementTypeOrSelf($" # operand # ")"
+ "=="
+ "cast<ImageType>(" # !subst("$_self", "$" # image # ".getType()", transform) # ").getElementType())"
+ >
+>;
+
+def SPIRV_SampledImageTransform : StrFunc<"llvm::cast<spirv::SampledImageType>($_self).getImageType()">;
+
+// -----
+
+def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather",
+ [Pure,
+ SPIRV_DimIs<"sampled_image", ["Dim2D", "Cube", "Rect"], SPIRV_SampledImageTransform.result>,
+ SPIRV_MSOperandIs<"sampled_image", ["SingleSampled"], SPIRV_SampledImageTransform.result>,
+ SPIRV_NoneOrElementMatchImage<"result", "sampled_image", SPIRV_SampledImageTransform.result>]>{
let summary = "Gathers the requested depth-comparison from four texels.";
let description = [{
Result Type must be a vector of four components of floating-point type
- or integer type. Its components must be the same as Sampled Type of the
+ or integer type. Its components must be the same as Sampled Type of the
underlying OpTypeImage (unless that underlying Sampled Type is
OpTypeVoid). It has one component per gathered texel.
@@ -32,8 +76,8 @@ def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
OpTypeImage must have a Dim of 2D, Cube, or Rect. The MS operand of the
underlying OpTypeImage must be 0.
- Coordinate must be a scalar or vector of floating-point type. It
- contains (u[, v] … [, array layer]) as needed by the definition of
+ Coordinate must be a scalar or vector of floating-point type. It
+ contains (u[, v] ... [, array layer]) as needed by the definition of
Sampled Image.
Dref is the depth-comparison reference value. It must be a 32-bit
@@ -44,8 +88,8 @@ def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
#### Example:
```mlir
- %0 = spirv.ImageDrefGather %1 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, %2 : vector<4xf32>, %3 : f32 -> vector<4xi32>
- %0 = spirv.ImageDrefGather %1 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, %2 : vector<4xf32>, %3 : f32 ["NonPrivateTexel"] : f32, f32 -> vector<4xi32>
+ %0 = spirv.ImageDrefGather %1, %2, %3 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, vector<4xf32>, f32 -> vector<4xi32>
+ %0 = spirv.ImageDrefGather %1, %2, %3 : !spirv.sampled_image<!spirv.image<i32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Unknown>>, vector<4xf32>, f32 ["NonPrivateTexel"] -> vector<4xi32>
```
}];
@@ -57,23 +101,24 @@ def SPIRV_ImageDrefGatherOp : SPIRV_Op<"ImageDrefGather", [Pure]> {
];
let arguments = (ins
- SPIRV_AnySampledImage:$sampledimage,
+ SPIRV_AnySampledImage:$sampled_image,
SPIRV_ScalarOrVectorOf<SPIRV_Float>:$coordinate,
- SPIRV_Float:$dref,
- OptionalAttr<SPIRV_ImageOperandsAttr>:$imageoperands,
+ SPIRV_Float32:$dref,
+ OptionalAttr<SPIRV_ImageOperandsAttr>:$image_operands,
Variadic<SPIRV_Type>:$operand_arguments
);
let results = (outs
- SPIRV_Vector:$result
+ AnyTypeOf<[SPIRV_Vec4<SPIRV_Integer>, SPIRV_Vec4<SPIRV_Float>]>:$result
);
- let assemblyFormat = [{$sampledimage `:` type($sampledimage) `,`
- $coordinate `:` type($coordinate) `,` $dref `:` type($dref)
- custom<ImageOperands>($imageoperands)
- ( `(` $operand_arguments^ `:` type($operand_arguments) `)`)?
- attr-dict
- `->` type($result)}];
+
+ let assemblyFormat = [{
+ $sampled_image `,` $coordinate `,` $dref custom<ImageOperands>($image_operands) ( `(` $operand_arguments^ `)` )? attr-dict
+ `:` type($sampled_image) `,` type($coordinate) `,` type($dref) ( `(` type($operand_arguments)^ `)` )?
+ `->` type($result)
+ }];
+
}
// -----
@@ -82,7 +127,7 @@ def SPIRV_ImageQuerySizeOp : SPIRV_Op<"ImageQuerySize", [Pure]> {
let summary = "Query the dimensions of Image, with no level of detail.";
let description = [{
- Result Type must be an integer type scalar or vector. The number of
+ Result Type must be an integer type scalar or vector. The number of
components must be:
1 for the 1D and Buffer dimensionalities,
@@ -130,12 +175,15 @@ def SPIRV_ImageQuerySizeOp : SPIRV_Op<"ImageQuerySize", [Pure]> {
SPIRV_ScalarOrVectorOf<SPIRV_Integer>:$result
);
- let assemblyFormat = "attr-dict $image `:` type($image) `->` type($result)";
+ let assemblyFormat = "$image attr-dict `:` type($image) `->` type($result)";
}
// -----
-def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite", []> {
+def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite",
+ [SPIRV_SampledOperandIs<"image", ["SamplerUnknown", "NoSampler"]>,
+ SPIRV_DimIsNot<"image", ["SubpassData"]>,
+ SPIRV_NoneOrElementMatchImage<"texel", "image">]> {
let summary = "Write a texel to an image without a sampler.";
let description = [{
@@ -163,7 +211,7 @@ def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite", []> {
#### Example:
```mlir
- spirv.ImageWrite %0 : !spirv.image<f32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Rgba16>, %1 : vector<2xsi32>, %2 : vector<4xf32>
+ spirv.ImageWrite %0, %1, %2 : !spirv.image<f32, Dim2D, NoDepth, NonArrayed, SingleSampled, NoSampler, Rgba16>, vector<2xsi32>, vector<4xf32>
```
}];
@@ -177,20 +225,18 @@ def SPIRV_ImageWriteOp : SPIRV_Op<"ImageWrite", []> {
let results = (outs);
- let assemblyFormat = [{$image `:` type($image) `,`
- $coordinate `:` type($coordinate) `,`
- $texel `:` type($texel)
- custom<ImageOperands>($image_operands)
- ( `(` $operand_arguments^ `:` type($operand_arguments) `)`)?
- attr-dict}];
+ let assemblyFormat = [{
+ $image `,` $coordinate `,` $texel custom<ImageOperands>($image_operands) ( `(` $operand_arguments^ `)`)? attr-dict
+ `:` type($image) `,` type($coordinate) `,` type($texel) ( `(` type($operand_arguments)^ `)`)?
+ }];
}
// -----
def SPIRV_ImageOp : SPIRV_Op<"Image",
[Pure,
- TypesMatchWith<"type of 'result' matches image type of 'sampledimage'",
- "sampledimage", "result",
+ TypesMatchWith<"type of 'result' matches image type of 'sampled_image'",
+ "sampled_image", "result",
"::llvm::cast<spirv::SampledImageType>($_self).getImageType()">]> {
let summary = "Extract the image from a sampled image.";
@@ -210,14 +256,14 @@ def SPIRV_ImageOp : SPIRV_Op<"Image",
}];
let arguments = (ins
- SPIRV_AnySampledImage:$sampledimage
+ SPIRV_AnySampledImage:$sampled_image
);
let results = (outs
SPIRV_AnyImage:$result
);
- let assemblyFormat = "attr-dict $sampledimage `:` type($sampledimage)";
+ let assemblyFormat = "$sampled_image attr-dict `:` type($sampled_image)";
let hasVerifier = 0;
}
diff --git a/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt b/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt
index ae8ad5a491ff2..235beb0b6a097 100644
--- a/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt
+++ b/mlir/lib/Dialect/SPIRV/IR/CMakeLists.txt
@@ -8,6 +8,7 @@ add_mlir_dialect_library(MLIRSPIRVDialect
ControlFlowOps.cpp
CooperativeMatrixOps.cpp
GroupOps.cpp
+ ImageOps.cpp
IntegerDotProductOps.cpp
MemoryOps.cpp
MeshOps.cpp
diff --git a/mlir/lib/Dialect/SPIRV/IR/ImageOps.cpp b/mlir/lib/Dialect/SPIRV/IR/ImageOps.cpp
new file mode 100644
index 0000000000000..9513a9c74634e
--- /dev/null
+++ b/mlir/lib/Dialect/SPIRV/IR/ImageOps.cpp
@@ -0,0 +1,138 @@
+//===- ImageOps.cpp - MLIR SPIR-V Image Ops ------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the image operations in the SPIR-V dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/SPIRV/IR/SPIRVOps.h"
+
+using namespace mlir;
+
+//===----------------------------------------------------------------------===//
+// Common utility functions
+//===----------------------------------------------------------------------===//
+
+template <typename Op>
+static LogicalResult verifyImageOperands(Op imageOp,
+ spirv::ImageOperandsAttr attr,
+ Operation::operand_range operands) {
+ if (!attr) {
+ if (operands.empty())
+ return success();
+
+ return imageOp.emitError("the Image Operands should encode what operands "
+ "follow, as per Image Operands");
+ }
+
+ // TODO: Add the validation rules for the following Image Operands.
+ spirv::ImageOperands noSupportOperands =
+ spirv::ImageOperands::Bias | spirv::ImageOperands::Lod |
+ spirv::ImageOperands::Grad | spirv::ImageOperands::ConstOffset |
+ spirv::ImageOperands::Offset | spirv::ImageOperands::ConstOffsets |
+ spirv::ImageOperands::Sample | spirv::ImageOperands::MinLod |
+ spirv::ImageOperands::MakeTexelAvailable |
+ spirv::ImageOperands::MakeTexelVisible |
+ spirv::ImageOperands::SignExtend | spirv::ImageOperands::ZeroExtend;
+
+ if (spirv::bitEnumContainsAny(attr.getValue(), noSupportOperands))
+ llvm_unreachable("unimplemented operands of Image Operands");
+
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.ImageDrefGather
+//===----------------------------------------------------------------------===//
+
+LogicalResult spirv::ImageDrefGatherOp::verify() {
+ return verifyImageOperands(*this, getImageOperandsAttr(),
+ getOperandArguments());
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.ImageWriteOp
+//===----------------------------------------------------------------------===//
+
+LogicalResult spirv::ImageWriteOp::verify() {
+ // TODO: Do we need check for: "If the Arrayed operand is 1, then additional
+ // capabilities may be required; e.g., ImageCubeArray, or ImageMSArray."?
+
+ // TODO: Ideally it should be somewhere verified that "The Image Format must
+ // not be Unknown, unless the StorageImageWriteWithoutFormat Capability was
+ // declared." This function however may not be the suitable place for such
+ // verification.
+
+ return verifyImageOperands(*this, getImageOperandsAttr(),
+ getOperandArguments());
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.ImageQuerySize
+//===----------------------------------------------------------------------===//
+
+LogicalResult spirv::ImageQuerySizeOp::verify() {
+ spirv::ImageType imageType =
+ llvm::cast<spirv::ImageType>(getImage().getType());
+ Type resultType = getResult().getType();
+
+ spirv::Dim dim = imageType.getDim();
+ spirv::ImageSamplingInfo samplingInfo = imageType.getSamplingInfo();
+ spirv::ImageSamplerUseInfo samplerInfo = imageType.getSamplerUseInfo();
+ switch (dim) {
+ case spirv::Dim::Dim1D:
+ case spirv::Dim::Dim2D:
+ case spirv::Dim::Dim3D:
+ case spirv::Dim::Cube:
+ if (samplingInfo != spirv::ImageSamplingInfo::MultiSampled &&
+ samplerInfo != spirv::ImageSamplerUseInfo::SamplerUnknown &&
+ samplerInfo != spirv::ImageSamplerUseInfo::NoSampler)
+ return emitError(
+ "if Dim is 1D, 2D, 3D, or Cube, "
+ "it must also have either an MS of 1 or a Sampled of 0 or 2");
+ break;
+ case spirv::Dim::Buffer:
+ case spirv::Dim::Rect:
+ break;
+ default:
+ return emitError("the Dim operand of the image type must "
+ "be 1D, 2D, 3D, Buffer, Cube, or Rect");
+ }
+
+ unsigned componentNumber = 0;
+ switch (dim) {
+ case spirv::Dim::Dim1D:
+ case spirv::Dim::Buffer:
+ componentNumber = 1;
+ break;
+ case spirv::Dim::Dim2D:
+ case spirv::Dim::Cube:
+ case spirv::Dim::Rect:
+ componentNumber = 2;
+ break;
+ case spirv::Dim::Dim3D:
+ componentNumber = 3;
+ break;
+ default:
+ break;
+ }
+
+ if (imageType.getArrayedInfo() == spirv::ImageArrayedInfo::Arrayed)
+ componentNumber += 1;
+
+ unsigned resultComponentNumber = 1;
+ if (auto resultVectorType = llvm::dyn_cast<VectorType>(resultType))
+ resultComponentNumber = resultVectorType.getNumElements();
+
+ if (componentNumber != resultComponentNumber)
+ return emitError("expected the result to have ")
+ << componentNumber << " component(s), but found "
+ << resultComponentNumber << " component(s)";
+
+ return success();
+}
diff --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
index dc414339ae7b8..da9855b02860d 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
@@ -166,34 +166,6 @@ static void printOneResultOp(Operation *op, OpAsmPrinter &p) {
p << " : " << resultType;
}
-template <typename Op>
-static LogicalResult verifyImageOperands(Op imageOp,
- spirv::ImageOperandsAttr attr,
- Operation::operand_range operands) {
- if (!attr) {
- if (operands.empty())
- return success();
-
- return imageOp.emitError("the Image Operands should encode what operands "
- "follow, as per Image Operands");
- }
-
- // TODO: Add the validation rules for the following Image Operands.
- spirv::ImageOperands noSupportOperands =
- spirv::ImageOperands::Bias | spirv::ImageOperands::Lod |
- spirv::ImageOperands::Grad | spirv::ImageOperands::ConstOffset |
- spirv::ImageOperands::Offset | spirv::ImageOperands::ConstOffsets |
- spirv::ImageOperands::Sample | spirv::ImageOperands::MinLod |
- spirv::ImageOperands::MakeTexelAvailable |
- spirv::ImageOperands::MakeTexelVisible |
- spirv::ImageOperands::SignExtend | spirv::ImageOperands::ZeroExtend;
-
- if (spirv::bitEnumContainsAll(attr.getValue(), noSupportOperands))
- llvm_unreachable("unimplemented operands of Image Operands");
-
- return success();
-}
-
template <typename BlockReadWriteOpTy>
static LogicalResult verifyBlockReadWritePtrAndValTypes(BlockReadWriteOpTy op,
Value ptr, Value val) {
@@ -2002,85 +1974,6 @@ LogicalResult spirv::GLLdexpOp::verify() {
return success();
}
-//===----------------------------------------------------------------------===//
-// spirv.ImageDrefGather
-//===----------------------------------------------------------------------===//
-
-LogicalResult spirv::ImageDrefGatherOp::verify() {
- VectorType resultType = llvm::cast<VectorType>(getResult().getType());
- auto sampledImageType =
- llvm::cast<spirv::SampledImageType>(getSampledimage().getType());
- auto imageType =
- llvm::cast<spirv::ImageType>(sampledImageType.getImageType());
-
- if (resultType.getNumElements() != 4)
- return emitOpError("result type must be a vector of four components");
-
- Type elementType = resultType.getElementType();
- Type sampledElementType = imageType.getElementType();
- if (!llvm::isa<NoneType>(sampledElementType) &&
- elementType != sampledElementType)
- return emitOpError(
- "the component type of result must be the same as sampled type of the "
- "underlying image type");
-
- spirv::Dim imageDim = imageType.getDim();
- spirv::ImageSamplingInfo imageMS = imageType.getSamplingInfo();
-
- if (imageDim != spirv::Dim::Dim2D && imageDim != spirv::Dim::Cube &&
- imageDim != spirv::Dim::Rect)
- return emitOpError(
- "the Dim operand of the underlying image type must be 2D, Cube, or "
- "Rect");
-
- if (imageMS != spirv::ImageSamplingInfo::SingleSampled)
- return emitOpError("the MS operand of the underlying image type must be 0");
-
- spirv::ImageOperandsAttr attr = getImageoperandsAttr();
- auto operandArguments = getOperandArguments();
-
- return verifyImageOperands(*this, attr, operandArguments);
-}
-
-//===----------------------------------------------------------------------===//
-// spirv.ImageWriteOp
-//===----------------------------------------------------------------------===//
-
-LogicalResult spirv::ImageWriteOp::verify() {
- ImageType imageType = cast<ImageType>(getImage().getType());
- Type sampledType = imageType.getElementType();
- ImageSamplerUseInfo samplerInfo = imageType.getSamplerUseInfo();
-
- if (!llvm::is_contained({spirv::ImageSamplerUseInfo::SamplerUnknown,
- spirv::ImageSamplerUseInfo::NoSampler},
- samplerInfo)) {
- return emitOpError(
- "the sampled operand of the underlying image must be 0 or 2");
- }
-
- // TODO: Do we need check for: "If the Arrayed operand is 1, then additional
- // capabilities may be required; e.g., ImageCubeArray, or ImageMSArray."?
-
- if (imageType.getDim() == spirv::Dim::SubpassData) {
- return emitOpError(
- "the Dim operand of the underlying image must not be SubpassData");
- }
-
- Type texelType = getElementTypeOrSelf(getTexel());
- if (!isa<NoneType>(sampledType) && texelType != sampledType) {
- return emitOpError(
- "the texel component type must match the image sampled type");
- }
-
- // TODO: Ideally it should be somewhere verified that ...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks for cleaning this up!
This patch makes multiple changes to images ops: 1) The assembly format is unified with the rest of the dialect to use `%0 = spirv.op %1, %2, %3 : f32, f32, f32` rather than having each type directly attached to each argument. 2) The verification is moved from `SPIRVOps.cpp` to a new file so the ops can be easier maintained. 3) Majority of C++ verification is removed and moved into ODS. Verification of `ImageQuerySizeOp` is left in C++ due to the complexity of rules. 4) `spirv::bitEnumContainsAll` is replaced by `spirv::bitEnumContainsAny` in `verifyImageOperands`. In this context `...Any` seems to be the correct function, as we want to check whether unsupported operand is being used - in opposite to checking if all unsupported operands are being used. 5) Simplify target tests by removing entry points and adding `Linkage` capability to the modules.
1918f96
to
a4a35bf
Compare
I have made the requested changes and pushed the update. |
@IgWod-IMG I've landed 99207ae to fix an unused variable warning. Thanks! |
@kazutakahirata Thank you :) |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/17/builds/6068 Here is the relevant piece of the build log for the reference
|
This patch makes multiple changes to images ops:
%0 = spirv.op %1, %2, %3 : f32, f32, f32
rather than having each type directly attached to each argument.SPIRVOps.cpp
to a new file so the ops can be easier maintained.ImageQuerySizeOp
is left in C++ due to the complexity of rules.spirv::bitEnumContainsAll
is replaced byspirv::bitEnumContainsAny
inverifyImageOperands
. In this context...Any
seems to be the correct function, as we want to check whether unsupported operand is being used - in opposite to checking if all unsupported operands are being used.Linkage
capability to the modules.This change is made in preparation for adding more Image ops. Change to the assembly format was previously mentioned in #124124.