[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