[Mlir-commits] [mlir] [mlir][SPIR-V] Add SPIRVToLLVM conversion for GL.FClamp/SClamp/UClamp (PR #203831)
Arseniy Obolenskiy
llvmlistbot at llvm.org
Mon Jul 6 02:18:14 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/203831
>From 80a6849c7d7da987f19ca9e401d00b1aebbc6d01 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Mon, 15 Jun 2026 08:07:27 +0200
Subject: [PATCH 1/2] [mlir][SPIR-V] Add SPIRVToLLVM conversion for
GL.FClamp/SClamp/UClamp
Lower the GLSL clamp ops as nested min/max following `min(max(x, y), z)`
---
.../Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp | 26 ++++++++++++++
.../SPIRVToLLVM/gl-ops-to-llvm.mlir | 36 +++++++++++++++++++
2 files changed, 62 insertions(+)
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
index c43415b27b1b3..bc1d690061a91 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
@@ -921,6 +921,29 @@ class InverseSqrtPattern
}
};
+/// Converts the GLSL clamp ops (FClamp, SClamp, UClamp) into a nested
+/// min/max sequence, following the op semantics `min(max(x, minVal), maxVal)`.
+template <typename SPIRVOp, typename LLVMMinOp, typename LLVMMaxOp>
+class ClampPattern : public SPIRVToLLVMConversion<SPIRVOp> {
+public:
+ using SPIRVToLLVMConversion<SPIRVOp>::SPIRVToLLVMConversion;
+
+ LogicalResult
+ matchAndRewrite(SPIRVOp op, typename SPIRVOp::Adaptor adaptor,
+ ConversionPatternRewriter &rewriter) const override {
+ auto dstType = this->getTypeConverter()->convertType(op.getType());
+ if (!dstType)
+ return rewriter.notifyMatchFailure(op, "type conversion failed");
+
+ Location loc = op.getLoc();
+ Value max = LLVMMaxOp::create(rewriter, loc, dstType, adaptor.getX(),
+ adaptor.getY());
+ rewriter.template replaceOpWithNewOp<LLVMMinOp>(op, dstType, max,
+ adaptor.getZ());
+ return success();
+ }
+};
+
/// Converts `spirv.Load` and `spirv.Store` to LLVM dialect.
template <typename SPIRVOp>
class LoadStorePattern : public SPIRVToLLVMConversion<SPIRVOp> {
@@ -1897,6 +1920,9 @@ void mlir::populateSPIRVToLLVMConversionPatterns(
DirectConversionPattern<spirv::GLFAbsOp, LLVM::FAbsOp>,
DirectConversionPattern<spirv::GLFloorOp, LLVM::FFloorOp>,
DirectConversionPattern<spirv::GLFmaOp, LLVM::FMAOp>,
+ ClampPattern<spirv::GLFClampOp, LLVM::MinNumOp, LLVM::MaxNumOp>,
+ ClampPattern<spirv::GLSClampOp, LLVM::SMinOp, LLVM::SMaxOp>,
+ ClampPattern<spirv::GLUClampOp, LLVM::UMinOp, LLVM::UMaxOp>,
DirectConversionPattern<spirv::GLFMaxOp, LLVM::MaxNumOp>,
DirectConversionPattern<spirv::GLFMinOp, LLVM::MinNumOp>,
DirectConversionPattern<spirv::GLLogOp, LLVM::LogOp>,
diff --git a/mlir/test/Conversion/SPIRVToLLVM/gl-ops-to-llvm.mlir b/mlir/test/Conversion/SPIRVToLLVM/gl-ops-to-llvm.mlir
index ffa47efbf9213..c23b33c1625cd 100644
--- a/mlir/test/Conversion/SPIRVToLLVM/gl-ops-to-llvm.mlir
+++ b/mlir/test/Conversion/SPIRVToLLVM/gl-ops-to-llvm.mlir
@@ -91,6 +91,18 @@ spirv.func @fmin(%arg0: f32, %arg1: vector<3xf16>) "None" {
spirv.Return
}
+//===----------------------------------------------------------------------===//
+// spirv.GL.FClamp
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @fclamp
+spirv.func @fclamp(%arg0: f32, %arg1: f32, %arg2: f32) "None" {
+ // CHECK: %[[MAX:.*]] = llvm.intr.maxnum(%{{.*}}, %{{.*}}) : (f32, f32) -> f32
+ // CHECK: llvm.intr.minnum(%[[MAX]], %{{.*}}) : (f32, f32) -> f32
+ %0 = spirv.GL.FClamp %arg0, %arg1, %arg2 : f32
+ spirv.Return
+}
+
//===----------------------------------------------------------------------===//
// spirv.GL.Log
//===----------------------------------------------------------------------===//
@@ -208,6 +220,30 @@ spirv.func @umin(%arg0: i16, %arg1: vector<3xi32>) "None" {
spirv.Return
}
+//===----------------------------------------------------------------------===//
+// spirv.GL.SClamp
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @sclamp
+spirv.func @sclamp(%arg0: i16, %arg1: i16, %arg2: i16) "None" {
+ // CHECK: %[[MAX:.*]] = llvm.intr.smax(%{{.*}}, %{{.*}}) : (i16, i16) -> i16
+ // CHECK: llvm.intr.smin(%[[MAX]], %{{.*}}) : (i16, i16) -> i16
+ %0 = spirv.GL.SClamp %arg0, %arg1, %arg2 : i16
+ spirv.Return
+}
+
+//===----------------------------------------------------------------------===//
+// spirv.GL.UClamp
+//===----------------------------------------------------------------------===//
+
+// CHECK-LABEL: @uclamp
+spirv.func @uclamp(%arg0: i32, %arg1: i32, %arg2: i32) "None" {
+ // CHECK: %[[MAX:.*]] = llvm.intr.umax(%{{.*}}, %{{.*}}) : (i32, i32) -> i32
+ // CHECK: llvm.intr.umin(%[[MAX]], %{{.*}}) : (i32, i32) -> i32
+ %0 = spirv.GL.UClamp %arg0, %arg1, %arg2 : i32
+ spirv.Return
+}
+
//===----------------------------------------------------------------------===//
// spirv.GL.Sqrt
//===----------------------------------------------------------------------===//
>From 030c2466aa092e7183e755f53aeaa2f1f045f07d Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <gooddoog at student.su>
Date: Mon, 6 Jul 2026 11:18:06 +0200
Subject: [PATCH 2/2] Update mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
Co-authored-by: Igor Wodiany <dev at wodiany.com>
---
mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
index bc1d690061a91..a81922e739232 100644
--- a/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
+++ b/mlir/lib/Conversion/SPIRVToLLVM/SPIRVToLLVM.cpp
@@ -931,7 +931,7 @@ class ClampPattern : public SPIRVToLLVMConversion<SPIRVOp> {
LogicalResult
matchAndRewrite(SPIRVOp op, typename SPIRVOp::Adaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
- auto dstType = this->getTypeConverter()->convertType(op.getType());
+ Type dstType = this->getTypeConverter()->convertType(op.getType());
if (!dstType)
return rewriter.notifyMatchFailure(op, "type conversion failed");
More information about the Mlir-commits
mailing list