[Mlir-commits] [mlir] d0373ba - [mlir][SPIR-V] Add GL NMin, NMax and NClamp ops (#203878)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Jun 25 09:24:22 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-06-25T18:24:17+02:00
New Revision: d0373ba8b57bb2355cfed09ad4c15c315a36af8c

URL: https://github.com/llvm/llvm-project/commit/d0373ba8b57bb2355cfed09ad4c15c315a36af8c
DIFF: https://github.com/llvm/llvm-project/commit/d0373ba8b57bb2355cfed09ad4c15c315a36af8c.diff

LOG: [mlir][SPIR-V] Add GL NMin, NMax and NClamp ops (#203878)

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
    mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
    mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
    mlir/test/Target/SPIRV/gl-ops.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
index dca21b6eedba0..e0b85e73cad99 100644
--- a/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
+++ b/mlir/include/mlir/Dialect/SPIRV/IR/SPIRVGLOps.td
@@ -1081,6 +1081,83 @@ def SPIRV_GLSClampOp : SPIRV_GLTernaryArithmeticOp<"SClamp", 45, SPIRV_Integer>
 
 // -----
 
+def SPIRV_GLNMaxOp : SPIRV_GLBinaryArithmeticOp<"NMax", 80, SPIRV_Float, [AlwaysSpeculatable]> {
+  let summary = "Return maximum of two floating-point operands, NaN-aware";
+
+  let description = [{
+    Result is y if x < y; otherwise result is x, where x and y are interpreted
+    as floating-point. NMax considers a NaN argument as missing, so if one
+    operand is a NaN the result is the other operand. If both operands are NaNs,
+    the result is a NaN.
+
+    The operands must all be a scalar or vector whose component type is
+    floating-point.
+
+    Result Type and the type of all operands must be the same type. Results are
+    computed per component.
+
+    #### Example:
+
+    ```mlir
+    %2 = spirv.GL.NMax %0, %1 : f32
+    %3 = spirv.GL.NMax %0, %1 : vector<3xf16>
+    ```
+  }];
+}
+
+// -----
+
+def SPIRV_GLNMinOp : SPIRV_GLBinaryArithmeticOp<"NMin", 79, SPIRV_Float, [AlwaysSpeculatable]> {
+  let summary = "Return minimum of two floating-point operands, NaN-aware";
+
+  let description = [{
+    Result is y if y < x; otherwise result is x, where x and y are interpreted
+    as floating-point. NMin considers a NaN argument as missing, so if one
+    operand is a NaN the result is the other operand. If both operands are NaNs,
+    the result is a NaN.
+
+    The operands must all be a scalar or vector whose component type is
+    floating-point.
+
+    Result Type and the type of all operands must be the same type. Results are
+    computed per component.
+
+    #### Example:
+
+    ```mlir
+    %2 = spirv.GL.NMin %0, %1 : f32
+    %3 = spirv.GL.NMin %0, %1 : vector<3xf16>
+    ```
+  }];
+}
+
+// -----
+
+def SPIRV_GLNClampOp : SPIRV_GLTernaryArithmeticOp<"NClamp", 81, SPIRV_Float> {
+  let summary = "Clamp x between min and max values, NaN-aware";
+
+  let description = [{
+    Result is min(max(x, minVal), maxVal). The resulting value is poison if
+    minVal > maxVal. The semantics used by min() and max() are those of NMin
+    and NMax, so NaN arguments are considered missing.
+
+    The operands must all be a scalar or vector whose component type is
+    floating-point.
+
+    Result Type and the type of all operands must be the same type. Results are
+    computed per component.
+
+    #### Example:
+
+    ```mlir
+    %2 = spirv.GL.NClamp %x, %min, %max : f32
+    %3 = spirv.GL.NClamp %x, %min, %max : vector<3xf16>
+    ```
+  }];
+}
+
+// -----
+
 def SPIRV_GLFmaOp : SPIRV_GLTernaryArithmeticOp<"Fma", 50, SPIRV_Float, [AlwaysSpeculatable]> {
   let summary = "Computes a * b + c.";
 

diff  --git a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
index 4cb6e6bbf6579..f699055b5502f 100644
--- a/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
+++ b/mlir/lib/Dialect/SPIRV/IR/SPIRVOps.cpp
@@ -1284,6 +1284,16 @@ ParseResult spirv::GLSClampOp::parse(OpAsmParser &parser,
 }
 void spirv::GLSClampOp::print(OpAsmPrinter &p) { printOneResultOp(*this, p); }
 
+//===----------------------------------------------------------------------===//
+// spirv.GLNClampOp
+//===----------------------------------------------------------------------===//
+
+ParseResult spirv::GLNClampOp::parse(OpAsmParser &parser,
+                                     OperationState &result) {
+  return parseOneResultSameOperandTypeOp(parser, result);
+}
+void spirv::GLNClampOp::print(OpAsmPrinter &p) { printOneResultOp(*this, p); }
+
 //===----------------------------------------------------------------------===//
 // spirv.GLFmaOp
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir b/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
index e8f15e30ba4ee..5665ae158d2e4 100644
--- a/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
+++ b/mlir/test/Dialect/SPIRV/IR/gl-ops.mlir
@@ -1266,3 +1266,57 @@ func.func @degrees(%arg0 : i32) -> () {
   %2 = spirv.GL.Degrees %arg0 : i32
   return
 }
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spirv.GL.NMax
+//===----------------------------------------------------------------------===//
+
+func.func @nmax(%arg0 : f32, %arg1 : f32) {
+  // CHECK: spirv.GL.NMax {{%.*}}, {{%.*}} : f32
+  %0 = spirv.GL.NMax %arg0, %arg1 : f32
+  return
+}
+
+func.func @nmaxvec(%arg0 : vector<3xf16>, %arg1 : vector<3xf16>) {
+  // CHECK: spirv.GL.NMax {{%.*}}, {{%.*}} : vector<3xf16>
+  %0 = spirv.GL.NMax %arg0, %arg1 : vector<3xf16>
+  return
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spirv.GL.NMin
+//===----------------------------------------------------------------------===//
+
+func.func @nmin(%arg0 : f32, %arg1 : f32) {
+  // CHECK: spirv.GL.NMin {{%.*}}, {{%.*}} : f32
+  %0 = spirv.GL.NMin %arg0, %arg1 : f32
+  return
+}
+
+func.func @nminvec(%arg0 : vector<3xf16>, %arg1 : vector<3xf16>) {
+  // CHECK: spirv.GL.NMin {{%.*}}, {{%.*}} : vector<3xf16>
+  %0 = spirv.GL.NMin %arg0, %arg1 : vector<3xf16>
+  return
+}
+
+// -----
+
+//===----------------------------------------------------------------------===//
+// spirv.GL.NClamp
+//===----------------------------------------------------------------------===//
+
+func.func @nclamp(%arg0 : f32, %min : f32, %max : f32) -> () {
+  // CHECK: spirv.GL.NClamp {{%[^,]*}}, {{%[^,]*}}, {{%[^,]*}} : f32
+  %2 = spirv.GL.NClamp %arg0, %min, %max : f32
+  return
+}
+
+func.func @nclampvec(%arg0 : vector<3xf32>, %min : vector<3xf32>, %max : vector<3xf32>) -> () {
+  // CHECK: spirv.GL.NClamp {{%[^,]*}}, {{%[^,]*}}, {{%[^,]*}} : vector<3xf32>
+  %2 = spirv.GL.NClamp %arg0, %min, %max : vector<3xf32>
+  return
+}

diff  --git a/mlir/test/Target/SPIRV/gl-ops.mlir b/mlir/test/Target/SPIRV/gl-ops.mlir
index eac859ecf158e..bc17ff82cc441 100644
--- a/mlir/test/Target/SPIRV/gl-ops.mlir
+++ b/mlir/test/Target/SPIRV/gl-ops.mlir
@@ -76,6 +76,11 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
     %5 = spirv.GL.SMin %arg2, %arg3 : i32
     // CHECK: {{%.*}} = spirv.GL.UMin {{%.*}}, {{%.*}} : i32
     %6 = spirv.GL.UMin %arg2, %arg3 : i32
+
+    // CHECK: {{%.*}} = spirv.GL.NMax {{%.*}}, {{%.*}} : f32
+    %7 = spirv.GL.NMax %arg0, %arg1 : f32
+    // CHECK: {{%.*}} = spirv.GL.NMin {{%.*}}, {{%.*}} : f32
+    %8 = spirv.GL.NMin %arg0, %arg1 : f32
     spirv.Return
   }
 
@@ -85,6 +90,12 @@ spirv.module Logical GLSL450 requires #spirv.vce<v1.0, [Shader, Linkage], []> {
     spirv.Return
   }
 
+  spirv.func @nclamp(%arg0 : f32, %arg1 : f32, %arg2 : f32) "None" {
+    // CHECK: spirv.GL.NClamp {{%[^,]*}}, {{%[^,]*}}, {{%[^,]*}} : f32
+    %13 = spirv.GL.NClamp %arg0, %arg1, %arg2 : f32
+    spirv.Return
+  }
+
   spirv.func @uclamp(%arg0 : ui32, %arg1 : ui32, %arg2 : ui32) "None" {
     // CHECK: spirv.GL.UClamp {{%[^,]*}}, {{%[^,]*}}, {{%[^,]*}} : i32
     %13 = spirv.GL.UClamp %arg0, %arg1, %arg2 : ui32


        


More information about the Mlir-commits mailing list