[Mlir-commits] [mlir] [mlir][vector] Fix mask neutral value for masked fmaximum/fminimum reductions (PR #222275)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Sep 9 02:14:37 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-llvm

@llvm/pr-subscribers-mlir

Author: lorenzo chelini (chelini)

<details>
<summary>Changes</summary>

Masked maximumf/minimumf reductions were lowered by replacing inactive lanes with a neutral value before applying an unmasked reduction. The maximumf neutral was incorrectly set to the negative subnormal closest to zero, causing it to beat any negative active value. Similarly, minimumf used FLT_MAX, which loses to an active +Inf.
This change adds LLVM dialect support for llvm.vp.reduce.fmaximum/fminimum and lowers masked reductions directly to these predicated intrinsics. Their NaN and signed-zero semantics match vector.reduction <maximumf>/<minimumf>. The start value is ±infinity, or the corresponding finite extreme under ninf.
It also adds execution tests for the previously incorrect cases and conversion coverage for ninf.

---

Patch is 20.99 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/222275.diff


6 Files Affected:

- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td (+2) 
- (modified) mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp (+72-52) 
- (modified) mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir (+64-8) 
- (added) mlir/test/Integration/Dialect/Vector/CPU/reductions-masked-minmax-f32.mlir (+80) 
- (modified) mlir/test/Target/LLVMIR/Import/intrinsic.ll (+6) 
- (modified) mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir (+8) 


``````````diff
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
index f40f3f5ebda93..d494bd7184a16 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
@@ -1702,6 +1702,8 @@ def LLVM_VPReduceFAddOp : LLVM_VPReductionF<"fadd">;
 def LLVM_VPReduceFMulOp : LLVM_VPReductionF<"fmul">;
 def LLVM_VPReduceFMaxOp : LLVM_VPReductionF<"fmax">;
 def LLVM_VPReduceFMinOp : LLVM_VPReductionF<"fmin">;
+def LLVM_VPReduceFMaximumOp : LLVM_VPReductionF<"fmaximum">;
+def LLVM_VPReduceFMinimumOp : LLVM_VPReductionF<"fminimum">;
 
 def LLVM_VPMergeMinOp  : LLVM_VPSelectBase<"merge">;
 
diff --git a/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp b/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp
index 152c45b695cee..be4fdeb9eb174 100644
--- a/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp
+++ b/mlir/lib/Conversion/VectorToLLVM/ConvertVectorToLLVM.cpp
@@ -483,6 +483,10 @@ class ReductionNeutralSIntMax {};
 class ReductionNeutralUIntMax {};
 class ReductionNeutralFPMin {};
 class ReductionNeutralFPMax {};
+class ReductionNeutralFPNegInf {};
+class ReductionNeutralFPPosInf {};
+class ReductionNeutralFPLowestFinite {};
+class ReductionNeutralFPLargestFinite {};
 
 /// Create the reduction neutral zero value.
 static Value createReductionNeutralValue(ReductionNeutralZero neutral,
@@ -582,6 +586,55 @@ static Value createReductionNeutralValue(ReductionNeutralFPMax neutral,
                                            /*Negative=*/true)));
 }
 
+/// Create the reduction neutral negative infinity value.
+static Value createReductionNeutralValue(ReductionNeutralFPNegInf neutral,
+                                         ConversionPatternRewriter &rewriter,
+                                         Location loc, Type llvmType) {
+  auto floatType = cast<FloatType>(llvmType);
+  return LLVM::ConstantOp::create(
+      rewriter, loc, llvmType,
+      rewriter.getFloatAttr(
+          llvmType, llvm::APFloat::getInf(floatType.getFloatSemantics(),
+                                          /*Negative=*/true)));
+}
+
+/// Create the reduction neutral positive infinity value.
+static Value createReductionNeutralValue(ReductionNeutralFPPosInf neutral,
+                                         ConversionPatternRewriter &rewriter,
+                                         Location loc, Type llvmType) {
+  auto floatType = cast<FloatType>(llvmType);
+  return LLVM::ConstantOp::create(
+      rewriter, loc, llvmType,
+      rewriter.getFloatAttr(
+          llvmType, llvm::APFloat::getInf(floatType.getFloatSemantics(),
+                                          /*Negative=*/false)));
+}
+
+/// Create the reduction neutral lowest finite value.
+static Value createReductionNeutralValue(ReductionNeutralFPLowestFinite neutral,
+                                         ConversionPatternRewriter &rewriter,
+                                         Location loc, Type llvmType) {
+  auto floatType = cast<FloatType>(llvmType);
+  return LLVM::ConstantOp::create(
+      rewriter, loc, llvmType,
+      rewriter.getFloatAttr(
+          llvmType, llvm::APFloat::getLargest(floatType.getFloatSemantics(),
+                                              /*Negative=*/true)));
+}
+
+/// Create the reduction neutral largest finite value.
+static Value
+createReductionNeutralValue(ReductionNeutralFPLargestFinite neutral,
+                            ConversionPatternRewriter &rewriter, Location loc,
+                            Type llvmType) {
+  auto floatType = cast<FloatType>(llvmType);
+  return LLVM::ConstantOp::create(
+      rewriter, loc, llvmType,
+      rewriter.getFloatAttr(
+          llvmType, llvm::APFloat::getLargest(floatType.getFloatSemantics(),
+                                              /*Negative=*/false)));
+}
+
 /// Returns `accumulator` if it has a valid value. Otherwise, creates and
 /// returns a new accumulator value using `ReductionNeutral`.
 template <class ReductionNeutral>
@@ -691,52 +744,6 @@ static Value createFPReductionComparisonOpLowering(
   return result;
 }
 
-/// Reduction neutral classes for overloading
-class MaskNeutralFMaximum {};
-class MaskNeutralFMinimum {};
-
-/// Get the mask neutral floating point maximum value
-static llvm::APFloat
-getMaskNeutralValue(MaskNeutralFMaximum,
-                    const llvm::fltSemantics &floatSemantics) {
-  return llvm::APFloat::getSmallest(floatSemantics, /*Negative=*/true);
-}
-/// Get the mask neutral floating point minimum value
-static llvm::APFloat
-getMaskNeutralValue(MaskNeutralFMinimum,
-                    const llvm::fltSemantics &floatSemantics) {
-  return llvm::APFloat::getLargest(floatSemantics, /*Negative=*/false);
-}
-
-/// Create the mask neutral floating point MLIR vector constant
-template <typename MaskNeutral>
-static Value createMaskNeutralValue(ConversionPatternRewriter &rewriter,
-                                    Location loc, Type llvmType,
-                                    Type vectorType) {
-  const auto &floatSemantics = cast<FloatType>(llvmType).getFloatSemantics();
-  auto value = getMaskNeutralValue(MaskNeutral{}, floatSemantics);
-  auto denseValue = DenseElementsAttr::get(cast<ShapedType>(vectorType), value);
-  return LLVM::ConstantOp::create(rewriter, loc, vectorType, denseValue);
-}
-
-/// Lowers masked `fmaximum` and `fminimum` reductions using the non-masked
-/// intrinsics. It is a workaround to overcome the lack of masked intrinsics for
-/// `fmaximum`/`fminimum`.
-/// More information: https://github.com/llvm/llvm-project/issues/64940
-template <class LLVMRedIntrinOp, class MaskNeutral>
-static Value
-lowerMaskedReductionWithRegular(ConversionPatternRewriter &rewriter,
-                                Location loc, Type llvmType,
-                                Value vectorOperand, Value accumulator,
-                                Value mask, LLVM::FastmathFlagsAttr fmf) {
-  const Value vectorMaskNeutral = createMaskNeutralValue<MaskNeutral>(
-      rewriter, loc, llvmType, vectorOperand.getType());
-  const Value selectedVectorByMask = LLVM::SelectOp::create(
-      rewriter, loc, mask, vectorOperand, vectorMaskNeutral);
-  return createFPReductionComparisonOpLowering<LLVMRedIntrinOp>(
-      rewriter, loc, llvmType, selectedVectorByMask, accumulator, fmf);
-}
-
 template <class LLVMRedIntrinOp, class ReductionNeutral>
 static Value
 lowerReductionWithStartValue(ConversionPatternRewriter &rewriter, Location loc,
@@ -974,6 +981,8 @@ class MaskedReductionOpConversion
     LLVM::FastmathFlagsAttr fmf = LLVM::FastmathFlagsAttr::get(
         reductionOp.getContext(),
         convertArithFastMathFlagsToLLVM(fMFAttr.getValue()));
+    const bool noInfs =
+        LLVM::bitEnumContainsAny(fmf.getValue(), LLVM::FastmathFlags::ninf);
 
     Value result;
     switch (kind) {
@@ -1035,14 +1044,25 @@ class MaskedReductionOpConversion
           rewriter, loc, llvmType, operand, acc, maskOp.getMask());
       break;
     case CombiningKind::MAXIMUMF:
-      result = lowerMaskedReductionWithRegular<LLVM::vector_reduce_fmaximum,
-                                               MaskNeutralFMaximum>(
-          rewriter, loc, llvmType, operand, acc, maskOp.getMask(), fmf);
+      // `ninf` promises no infinity reaches the reduction, so the neutral start
+      // value must stay finite.
+      result =
+          noInfs ? lowerPredicatedReductionWithStartValue<
+                       LLVM::VPReduceFMaximumOp, ReductionNeutralFPLowestFinite>(
+                       rewriter, loc, llvmType, operand, acc, maskOp.getMask())
+                 : lowerPredicatedReductionWithStartValue<
+                       LLVM::VPReduceFMaximumOp, ReductionNeutralFPNegInf>(
+                       rewriter, loc, llvmType, operand, acc, maskOp.getMask());
       break;
     case CombiningKind::MINIMUMF:
-      result = lowerMaskedReductionWithRegular<LLVM::vector_reduce_fminimum,
-                                               MaskNeutralFMinimum>(
-          rewriter, loc, llvmType, operand, acc, maskOp.getMask(), fmf);
+      result =
+          noInfs
+              ? lowerPredicatedReductionWithStartValue<
+                    LLVM::VPReduceFMinimumOp, ReductionNeutralFPLargestFinite>(
+                    rewriter, loc, llvmType, operand, acc, maskOp.getMask())
+              : lowerPredicatedReductionWithStartValue<
+                    LLVM::VPReduceFMinimumOp, ReductionNeutralFPPosInf>(
+                    rewriter, loc, llvmType, operand, acc, maskOp.getMask());
       break;
     }
 
diff --git a/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir b/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir
index c7d9e22fb2423..434dd87a7293a 100644
--- a/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir
+++ b/mlir/test/Conversion/VectorToLLVM/vector-reduction-to-llvm.mlir
@@ -169,10 +169,9 @@ func.func @masked_reduce_maximumf_f32(%arg0: vector<16xf32>, %mask : vector<16xi
 // CHECK-LABEL:   func.func @masked_reduce_maximumf_f32(
 // CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
 // CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
-// CHECK:           %[[MASK_NEUTRAL:.*]] = llvm.mlir.constant(dense<-1.401300e-45> : vector<16xf32>) : vector<16xf32>
-// CHECK:           %[[MASKED:.*]] = llvm.select %[[MASK]], %[[INPUT]], %[[MASK_NEUTRAL]] : vector<16xi1>, vector<16xf32>
-// CHECK:           %[[RESULT:.*]] = llvm.intr.vector.reduce.fmaximum(%[[MASKED]])  : (vector<16xf32>) -> f32
-// CHECK:           return %[[RESULT]]
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(0xFF800000 : f32) : f32
+// CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
+// CHECK:           "llvm.intr.vp.reduce.fmaximum"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
 
 // -----
 
@@ -184,10 +183,67 @@ func.func @masked_reduce_minimumf_f32(%arg0: vector<16xf32>, %mask : vector<16xi
 // CHECK-LABEL:   func.func @masked_reduce_minimumf_f32(
 // CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
 // CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
-// CHECK:           %[[MASK_NEUTRAL:.*]] = llvm.mlir.constant(dense<3.40282347E+38> : vector<16xf32>) : vector<16xf32>
-// CHECK:           %[[MASKED:.*]] = llvm.select %[[MASK]], %[[INPUT]], %[[MASK_NEUTRAL]] : vector<16xi1>, vector<16xf32>
-// CHECK:           %[[RESULT:.*]] = llvm.intr.vector.reduce.fminimum(%[[MASKED]])  : (vector<16xf32>) -> f32
-// CHECK:           return %[[RESULT]]
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(0x7F800000 : f32) : f32
+// CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
+// CHECK:           "llvm.intr.vp.reduce.fminimum"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
+
+// -----
+
+func.func @masked_reduce_maximumf_f32_ninf(%arg0: vector<16xf32>, %mask : vector<16xi1>) -> f32 {
+  %0 = vector.mask %mask { vector.reduction <maximumf>, %arg0 fastmath<ninf> : vector<16xf32> into f32 } : vector<16xi1> -> f32
+  return %0 : f32
+}
+
+// CHECK-LABEL:   func.func @masked_reduce_maximumf_f32_ninf(
+// CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
+// CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(-3.40282347E+38 : f32) : f32
+// CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
+// CHECK:           "llvm.intr.vp.reduce.fmaximum"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
+
+// -----
+
+func.func @masked_reduce_minimumf_f32_ninf(%arg0: vector<16xf32>, %mask : vector<16xi1>) -> f32 {
+  %0 = vector.mask %mask { vector.reduction <minimumf>, %arg0 fastmath<ninf> : vector<16xf32> into f32 } : vector<16xi1> -> f32
+  return %0 : f32
+}
+
+// CHECK-LABEL:   func.func @masked_reduce_minimumf_f32_ninf(
+// CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
+// CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(3.40282347E+38 : f32) : f32
+// CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
+// CHECK:           "llvm.intr.vp.reduce.fminimum"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
+
+// -----
+
+// `fast` is a group that includes `ninf`, so it selects the finite neutral.
+
+func.func @masked_reduce_maximumf_f32_fast(%arg0: vector<16xf32>, %mask : vector<16xi1>) -> f32 {
+  %0 = vector.mask %mask { vector.reduction <maximumf>, %arg0 fastmath<fast> : vector<16xf32> into f32 } : vector<16xi1> -> f32
+  return %0 : f32
+}
+
+// CHECK-LABEL:   func.func @masked_reduce_maximumf_f32_fast(
+// CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
+// CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(-3.40282347E+38 : f32) : f32
+// CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
+// CHECK:           "llvm.intr.vp.reduce.fmaximum"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
+
+// -----
+
+func.func @masked_reduce_minimumf_f32_fast(%arg0: vector<16xf32>, %mask : vector<16xi1>) -> f32 {
+  %0 = vector.mask %mask { vector.reduction <minimumf>, %arg0 fastmath<fast> : vector<16xf32> into f32 } : vector<16xi1> -> f32
+  return %0 : f32
+}
+
+// CHECK-LABEL:   func.func @masked_reduce_minimumf_f32_fast(
+// CHECK-SAME:                                      %[[INPUT:.*]]: vector<16xf32>,
+// CHECK-SAME:                                      %[[MASK:.*]]: vector<16xi1>) -> f32 {
+// CHECK:           %[[NEUTRAL:.*]] = llvm.mlir.constant(3.40282347E+38 : f32) : f32
+// CHECK:           %[[VL:.*]] = llvm.mlir.constant(16 : i32) : i32
+// CHECK:           "llvm.intr.vp.reduce.fminimum"(%[[NEUTRAL]], %[[INPUT]], %[[MASK]], %[[VL]]) : (f32, vector<16xf32>, vector<16xi1>, i32) -> f32
 
 // -----
 
diff --git a/mlir/test/Integration/Dialect/Vector/CPU/reductions-masked-minmax-f32.mlir b/mlir/test/Integration/Dialect/Vector/CPU/reductions-masked-minmax-f32.mlir
new file mode 100644
index 0000000000000..74ae2da875b91
--- /dev/null
+++ b/mlir/test/Integration/Dialect/Vector/CPU/reductions-masked-minmax-f32.mlir
@@ -0,0 +1,80 @@
+// RUN: mlir-opt %s -test-lower-to-llvm  | \
+// RUN: mlir-runner -e entry -entry-point-result=void  \
+// RUN:   -shared-libs=%mlir_c_runner_utils | \
+// RUN: FileCheck %s
+
+func.func @entry() {
+  %inf = arith.constant 0x7F800000 : f32
+  %ninf = arith.constant 0xFF800000 : f32
+  %mask = arith.constant dense<[true, true, true, false]> : vector<4xi1>
+
+  // Ordinary negative data. A neutral value anywhere above the active lanes,
+  // such as a negative subnormal, would be returned instead of the maximum.
+  %v0 = arith.constant dense<[-5.0, -7.0, -5.0, -9.0]> : vector<4xf32>
+  %0 = vector.mask %mask {
+    vector.reduction <maximumf>, %v0 : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %0 : f32
+  // CHECK: -5
+
+  // Mirror image for the minimum.
+  %v1 = arith.constant dense<[5.0, 7.0, 5.0, 9.0]> : vector<4xf32>
+  %1 = vector.mask %mask {
+    vector.reduction <minimumf>, %v1 : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %1 : f32
+  // CHECK: 5
+
+  // Infinite active lanes: the largest finite value would win over them.
+  %v2 = vector.broadcast %ninf : f32 to vector<4xf32>
+  %2 = vector.mask %mask {
+    vector.reduction <maximumf>, %v2 : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %2 : f32
+  // CHECK: -inf
+
+  %v3 = vector.broadcast %inf : f32 to vector<4xf32>
+  %3 = vector.mask %mask {
+    vector.reduction <minimumf>, %v3 : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %3 : f32
+  // CHECK: inf
+
+  // No active lane: the result is the identity of the reduction.
+  %nomask = arith.constant dense<false> : vector<4xi1>
+  %4 = vector.mask %nomask {
+    vector.reduction <maximumf>, %v0 : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %4 : f32
+  // CHECK: -inf
+
+  %5 = vector.mask %nomask {
+    vector.reduction <minimumf>, %v1 : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %5 : f32
+  // CHECK: inf
+
+  // An accumulator combines with the masked reduction.
+  %acc = arith.constant -3.0 : f32
+  %6 = vector.mask %mask {
+    vector.reduction <maximumf>, %v0, %acc : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %6 : f32
+  // CHECK: -3
+
+  // Under `ninf` the neutral value is the largest finite value instead. It is
+  // still neutral for the finite inputs the flag restricts the reduction to.
+  %7 = vector.mask %mask {
+    vector.reduction <maximumf>, %v0 fastmath<ninf> : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %7 : f32
+  // CHECK: -5
+
+  %8 = vector.mask %mask {
+    vector.reduction <minimumf>, %v1 fastmath<ninf> : vector<4xf32> into f32
+  } : vector<4xi1> -> f32
+  vector.print %8 : f32
+  // CHECK: 5
+
+  return
+}
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic.ll b/mlir/test/Target/LLVMIR/Import/intrinsic.ll
index aaebaa2f46d1c..f8d67f997acab 100644
--- a/mlir/test/Target/LLVMIR/Import/intrinsic.ll
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic.ll
@@ -1106,6 +1106,10 @@ define void @vector_predication_intrinsics(<8 x i32> %0, <8 x i32> %1, <8 x floa
   %45 = call float @llvm.vp.reduce.fmax.v8f32(float %8, <8 x float> %2, <8 x i1> %11, i32 %12)
   ; CHECK: "llvm.intr.vp.reduce.fmin"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (f32, vector<8xf32>, vector<8xi1>, i32) -> f32
   %46 = call float @llvm.vp.reduce.fmin.v8f32(float %8, <8 x float> %2, <8 x i1> %11, i32 %12)
+  ; CHECK: "llvm.intr.vp.reduce.fmaximum"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (f32, vector<8xf32>, vector<8xi1>, i32) -> f32
+  %fmaximum = call float @llvm.vp.reduce.fmaximum.v8f32(float %8, <8 x float> %2, <8 x i1> %11, i32 %12)
+  ; CHECK: "llvm.intr.vp.reduce.fminimum"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (f32, vector<8xf32>, vector<8xi1>, i32) -> f32
+  %fminimum = call float @llvm.vp.reduce.fminimum.v8f32(float %8, <8 x float> %2, <8 x i1> %11, i32 %12)
   ; CHECK: llvm.select %{{.*}}, %{{.*}}, %{{.*}} : vector<8xi1>, vector<8xi32>
   %47 = call <8 x i32> @llvm.vp.select.v8i32(<8 x i1> %11, <8 x i32> %0, <8 x i32> %1, i32 %12)
   ; CHECK: "llvm.intr.vp.merge"(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (vector<8xi1>, vector<8xi32>, vector<8xi32>, i32) -> vector<8xi32>
@@ -1924,6 +1928,8 @@ declare i32 @llvm.vp.reduce.umin.v8i32(i32, <8 x i32>, <8 x i1>, i32)
 declare float @llvm.vp.reduce.fadd.v8f32(float, <8 x float>, <8 x i1>, i32)
 declare float @llvm.vp.reduce.fmul.v8f32(float, <8 x float>, <8 x i1>, i32)
 declare float @llvm.vp.reduce.fmax.v8f32(float, <8 x float>, <8 x i1>, i32)
+declare float @llvm.vp.reduce.fmaximum.v8f32(float, <8 x float>, <8 x i1>, i32)
+declare float @llvm.vp.reduce.fminimum.v8f32(float, <8 x float>, <8 x i1>, i32)
 declare float @llvm.vp.reduce.fmin.v8f32(float, <8 x float>, <8 x i1>, i32)
 declare <8 x i32> @llvm.vp.select.v8i32(<8 x i1>, <8 x i32>, <8 x i32>, i32)
 declare <8 x i32> @llvm.vp.merge.v8i32(<8 x i1>, <8 x i32>, <8 x i32>, i32)
diff --git a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir
index b3776c9a99f97..3839b3dc89e25 100644
--- a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir
@@ -1085,6 +1085,12 @@ llvm.func @vector_predication_intrinsics(%A: vector<8xi32>, %B: vector<8xi32>,
   // CHECK: call float @llvm.vp.reduce.fmin.v8f32
   "llvm.intr.vp.reduce.fmin" (%f, %C, %mask, %evl) :
          (f32, vector<8xf32>, vector<8xi1>, i32) -> f32
+  // CHECK: call float @llvm.vp.reduce.fmaximum.v8f32
+  "llvm.intr.vp.reduce.fmaximum" (%f, %C, %mask, %evl) :
+         (f32, vector<8xf32>, vector<8xi1>, i32) -> f32
+  // CHECK: call float @llvm.vp.reduce.fminimum.v8f32
+  "llvm.intr.vp.reduce.fminimum" (%f, %C, %mask, %evl) :
+         (f32, vector<8xf32>, vector<8xi1>,...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/222275


More information about the Mlir-commits mailing list