[Mlir-commits] [mlir] 86a9a1b - [mlir][SPIR-V] Let FConvert cast between same width types (#225349)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Sep 22 06:28:57 PDT 2026
Author: Arseniy Obolenskiy
Date: 2026-09-22T15:28:50+02:00
New Revision: 86a9a1bd8bcc53762454b7d0aadd17820bbc56d7
URL: https://github.com/llvm/llvm-project/commit/86a9a1bd8bcc53762454b7d0aadd17820bbc56d7
DIFF: https://github.com/llvm/llvm-project/commit/86a9a1bd8bcc53762454b7d0aadd17820bbc56d7.diff
LOG: [mlir][SPIR-V] Let FConvert cast between same width types (#225349)
The spec requires the component type to differ, not the width, so casts
like f16 to bf16 are legal
Prerequisite for https://github.com/llvm/llvm-project/pull/212817
Added:
Modified:
mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td
mlir/lib/Dialect/SPIRV/IR/CastOps.cpp
mlir/test/Dialect/SPIRV/IR/cast-ops.mlir
mlir/test/Target/SPIRV/cast-ops.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td
index a434764750a56..7a85a386900f0 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVCastOps.td
@@ -204,8 +204,8 @@ def SPIRV_FConvertOp : SPIRV_CastOp<"FConvert",
Result Type must be a scalar or vector of floating-point type.
Float Value must be a scalar or vector of floating-point type. It must
- have the same number of components as Result Type. The component width
- cannot equal the component width in Result Type.
+ have the same number of components as Result Type. The component type
+ must not equal the component type in Result Type.
Results are computed per component.
diff --git a/mlir/lib/Dialect/SPIRV/IR/CastOps.cpp b/mlir/lib/Dialect/SPIRV/IR/CastOps.cpp
index e8bbb8016baf6..5884afca0fe77 100644
--- a/mlir/lib/Dialect/SPIRV/IR/CastOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/CastOps.cpp
@@ -21,13 +21,8 @@ using namespace mlir::spirv::AttrNames;
namespace mlir::spirv {
-static LogicalResult verifyCastOp(Operation *op,
- bool requireSameBitWidth = true,
- bool skipBitWidthCheck = false) {
- // Some CastOps have no limit on bit widths for result and operand type.
- if (skipBitWidthCheck)
- return success();
-
+static FailureOr<std::pair<Type, Type>>
+getCastOpOperandAndResultElementType(Operation *op) {
Type operandType = op->getOperand(0).getType();
Type resultType = op->getResult(0).getType();
@@ -49,8 +44,26 @@ static LogicalResult verifyCastOp(Operation *op,
return {operandType, resultType};
});
- if (!operandElemTy || !resultElemTy)
- return op->emitOpError("incompatible operand and result types");
+ if (!operandElemTy || !resultElemTy) {
+ op->emitOpError("incompatible operand and result types");
+ return failure();
+ }
+
+ return TypePair{operandElemTy, resultElemTy};
+}
+
+static LogicalResult verifyCastOp(Operation *op,
+ bool requireSameBitWidth = true,
+ bool skipBitWidthCheck = false) {
+ // Some CastOps have no limit on bit widths for result and operand type.
+ if (skipBitWidthCheck)
+ return success();
+
+ FailureOr<std::pair<Type, Type>> elemTypes =
+ getCastOpOperandAndResultElementType(op);
+ if (failed(elemTypes))
+ return failure();
+ auto [operandElemTy, resultElemTy] = *elemTypes;
unsigned operandTypeBitWidth = operandElemTy.getIntOrFloatBitWidth();
unsigned resultTypeBitWidth = resultElemTy.getIntOrFloatBitWidth();
@@ -304,7 +317,22 @@ LogicalResult ConvertUToFOp::verify() {
//===----------------------------------------------------------------------===//
LogicalResult spirv::FConvertOp::verify() {
- return verifyCastOp(*this, /*requireSameBitWidth=*/false);
+ // The SPIR-V spec requires the component type to
diff er, not the bit
+ // width: "The component type must not equal the component type in Result
+ // Type." (OpFConvert, section 3.42.11). This allows converting between
+ // same-width encodings such as f16 and bf16.
+ FailureOr<std::pair<Type, Type>> elemTypes =
+ getCastOpOperandAndResultElementType(*this);
+ if (failed(elemTypes))
+ return failure();
+ auto [operandElemTy, resultElemTy] = *elemTypes;
+
+ if (operandElemTy == resultElemTy) {
+ return emitOpError("expected
diff erent component types for operand type "
+ "and result type, but provided ")
+ << operandElemTy << " and " << resultElemTy;
+ }
+ return success();
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir b/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir
index 2bd992979e2ab..e5ea675a1f243 100644
--- a/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/cast-ops.mlir
@@ -309,7 +309,7 @@ func.func @f_convert_coop_matrix(%arg0 : !spirv.coopmatrix<8x16xf32, Subgroup, M
// -----
func.func @f_convert_vector(%arg0 : f32) -> f32 {
- // expected-error @+1 {{expected the
diff erent bit widths for operand type and result type, but provided 'f32' and 'f32'}}
+ // expected-error @+1 {{expected
diff erent component types for operand type and result type, but provided 'f32' and 'f32'}}
%0 = spirv.FConvert %arg0 : f32 to f32
spirv.ReturnValue %0 : f32
}
@@ -324,6 +324,14 @@ func.func @f_convert_bf16_to_f32_scalar(%arg0 : bf16) -> f32 {
// -----
+func.func @f_convert_f16_to_bf16_scalar(%arg0 : f16) -> bf16 {
+ // CHECK: {{%.*}} = spirv.FConvert {{%.*}} : f16 to bf16
+ %0 = spirv.FConvert %arg0 : f16 to bf16
+ spirv.ReturnValue %0 : bf16
+}
+
+// -----
+
func.func @f_convert_f32_to_bf16_vector(%arg0 : vector<3xf32>) -> vector<3xbf16> {
// CHECK: {{%.*}} = spirv.FConvert {{%.*}} : vector<3xf32> to vector<3xbf16>
%0 = spirv.FConvert %arg0 : vector<3xf32> to vector<3xbf16>
diff --git a/mlir/test/Target/SPIRV/cast-ops.mlir b/mlir/test/Target/SPIRV/cast-ops.mlir
index 317264d37b8c8..b058c2cebda2f 100644
--- a/mlir/test/Target/SPIRV/cast-ops.mlir
+++ b/mlir/test/Target/SPIRV/cast-ops.mlir
@@ -29,7 +29,7 @@ spirv.module Logical Vulkan requires #spirv.vce<v1.6, [Shader, Linkage, Cooperat
// -----
-spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage, BFloat16TypeKHR, Float64, Int64], [SPV_KHR_bfloat16]> {
+spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage, BFloat16TypeKHR, Float16, Float64, Int64], [SPV_KHR_bfloat16]> {
spirv.func @convert_f_to_s(%arg0 : f32) -> i32 "None" {
// CHECK: {{%.*}} = spirv.ConvertFToS {{%.*}} : f32 to i32
%0 = spirv.ConvertFToS %arg0 : f32 to i32
@@ -105,6 +105,11 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage, BFloat1
%0 = spirv.FConvert %arg0 : bf16 to f32
spirv.ReturnValue %0 : f32
}
+ spirv.func @convert_f16_to_bf16(%arg0 : f16) -> bf16 "None" {
+ // CHECK: {{%.*}} = spirv.FConvert {{%.*}} : f16 to bf16
+ %0 = spirv.FConvert %arg0 : f16 to bf16
+ spirv.ReturnValue %0 : bf16
+ }
spirv.func @s_convert(%arg0 : i32) -> i64 "None" {
// CHECK: {{%.*}} = spirv.SConvert {{%.*}} : i32 to i64
%0 = spirv.SConvert %arg0 : i32 to i64
More information about the Mlir-commits
mailing list