[Mlir-commits] [mlir] 2fe7826 - [mlir][SPIR-V] Add ComplexToSPIRV lowering for complex.sign (#216722)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Wed Oct 14 03:33:10 PDT 2026


Author: Arseniy Obolenskiy
Date: 2026-10-14T12:33:04+02:00
New Revision: 2fe78267078428c0b0c9ae8379d78cf93606759e

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

LOG: [mlir][SPIR-V] Add ComplexToSPIRV lowering for complex.sign (#216722)

Computes complex.sign as z / abs(z), using a component-wise spirv.Select
to pick a zero result when z is zero without requiring SPIR-V 1.4 (a
vector-result Select would need a scalar condition paired with a
composite result, which is only legal from 1.4 on)

Added: 
    

Modified: 
    mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
    mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp b/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
index 884df06a4e705..e57d6d922e5ba 100644
--- a/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
+++ b/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
@@ -25,6 +25,12 @@ using namespace mlir;
 //===----------------------------------------------------------------------===//
 
 namespace {
+/// Creates a scalar floating-point constant of the given value.
+Value createFPConstant(OpBuilder &builder, Location loc, Type type,
+                       double value) {
+  return spirv::ConstantOp::create(
+      builder, loc, type, builder.getFloatAttr(cast<FloatType>(type), value));
+}
 
 struct ConstantOpPattern final : OpConversionPattern<complex::ConstantOp> {
   using Base::Base;
@@ -309,6 +315,60 @@ struct AngleOpPattern final : OpConversionPattern<complex::AngleOp> {
   }
 };
 
+/// Computes complex.sign as z / abs(z), selecting a zero result when z is
+/// zero to avoid a division by zero. abs(z) is computed as
+/// max * sqrt(1 + (min / max)^2) to avoid overflow in squaring.
+template <typename SqrtOp, typename FAbsOp, typename FMaxOp, typename FMinOp>
+struct SignOpPattern final : OpConversionPattern<complex::SignOp> {
+  using OpConversionPattern<complex::SignOp>::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(complex::SignOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    Type spirvType =
+        this->getTypeConverter()->convertType(op.getResult().getType());
+    if (!spirvType)
+      return rewriter.notifyMatchFailure(op, "unable to convert result type");
+
+    Location loc = op.getLoc();
+    Value complexVal = adaptor.getComplex();
+
+    Value re =
+        spirv::CompositeExtractOp::create(rewriter, loc, complexVal, {0});
+    Value im =
+        spirv::CompositeExtractOp::create(rewriter, loc, complexVal, {1});
+
+    Value absRe = FAbsOp::create(rewriter, loc, re);
+    Value absIm = FAbsOp::create(rewriter, loc, im);
+    Value max = FMaxOp::create(rewriter, loc, absRe, absIm);
+    Value min = FMinOp::create(rewriter, loc, absRe, absIm);
+    Value ratio = spirv::FDivOp::create(rewriter, loc, min, max);
+    Value ratioSq = spirv::FMulOp::create(rewriter, loc, ratio, ratio);
+    Value one = createFPConstant(rewriter, loc, re.getType(), 1.0);
+    Value ratioSqPlusOne = spirv::FAddOp::create(rewriter, loc, ratioSq, one);
+    Value sqrt = SqrtOp::create(rewriter, loc, ratioSqPlusOne);
+    Value abs = spirv::FMulOp::create(rewriter, loc, max, sqrt);
+
+    Value signRe = spirv::FDivOp::create(rewriter, loc, re, abs);
+    Value signIm = spirv::FDivOp::create(rewriter, loc, im, abs);
+
+    Value zero = createFPConstant(rewriter, loc, re.getType(), 0.0);
+    Value reIsZero = spirv::FOrdEqualOp::create(rewriter, loc, re, zero);
+    Value imIsZero = spirv::FOrdEqualOp::create(rewriter, loc, im, zero);
+    Value isZero =
+        spirv::LogicalAndOp::create(rewriter, loc, reIsZero, imIsZero);
+
+    // Select per component: spirv.Select with a scalar condition and a
+    // composite result requires SPIR-V 1.4, so operate on scalars here and
+    // assemble the result afterwards.
+    Value resultRe = spirv::SelectOp::create(rewriter, loc, isZero, re, signRe);
+    Value resultIm = spirv::SelectOp::create(rewriter, loc, isZero, im, signIm);
+
+    rewriter.replaceOpWithNewOp<spirv::CompositeConstructOp>(
+        op, spirvType, llvm::ArrayRef<Value>{resultRe, resultIm});
+    return success();
+  }
+};
 } // namespace
 
 //===----------------------------------------------------------------------===//
@@ -331,6 +391,9 @@ void mlir::populateComplexToSPIRVPatterns(
            NegationOpPattern<complex::NegOp, /*NegateReal=*/true>,
            NegationOpPattern<complex::ConjOp, /*NegateReal=*/false>,
            AbsOpPattern<spirv::GLSqrtOp>, AbsOpPattern<spirv::CLSqrtOp>,
-           AngleOpPattern<spirv::GLAtan2Op>, AngleOpPattern<spirv::CLAtan2Op>>(
-          typeConverter, context);
+           AngleOpPattern<spirv::GLAtan2Op>, AngleOpPattern<spirv::CLAtan2Op>,
+           SignOpPattern<spirv::GLSqrtOp, spirv::GLFAbsOp, spirv::GLFMaxOp,
+                         spirv::GLFMinOp>,
+           SignOpPattern<spirv::CLSqrtOp, spirv::CLFAbsOp, spirv::CLFMaxOp,
+                         spirv::CLFMinOp>>(typeConverter, context);
 }

diff  --git a/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir b/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
index e060c1c0ad44a..1b39062ab985a 100644
--- a/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
+++ b/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
@@ -268,3 +268,35 @@ func.func @complex_angle_opencl(%arg: complex<f32>) -> f32 {
 //       CHECK:   spirv.CL.atan2
 
 }
+
+// -----
+
+func.func @complex_sign(%arg: complex<f32>) -> complex<f32> {
+  %sign = complex.sign %arg : complex<f32>
+  return %sign : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex_sign
+//  CHECK-SAME: %[[ARG:.+]]: complex<f32>
+//       CHECK:   %[[V:.+]] = builtin.unrealized_conversion_cast %[[ARG]] : complex<f32> to vector<2xf32>
+//       CHECK:   %[[RE:.+]] = spirv.CompositeExtract %[[V]][0 : i32] : vector<2xf32>
+//       CHECK:   %[[IM:.+]] = spirv.CompositeExtract %[[V]][1 : i32] : vector<2xf32>
+//       CHECK:   %[[ABSRE:.+]] = spirv.GL.FAbs %[[RE]] : f32
+//       CHECK:   %[[ABSIM:.+]] = spirv.GL.FAbs %[[IM]] : f32
+//       CHECK:   %[[MAX:.+]] = spirv.GL.FMax %[[ABSRE]], %[[ABSIM]] : f32
+//       CHECK:   %[[MIN:.+]] = spirv.GL.FMin %[[ABSRE]], %[[ABSIM]] : f32
+//       CHECK:   %[[RATIO:.+]] = spirv.FDiv %[[MIN]], %[[MAX]] : f32
+//       CHECK:   %[[RATIOSQ:.+]] = spirv.FMul %[[RATIO]], %[[RATIO]] : f32
+//       CHECK:   %[[ONE:.+]] = spirv.Constant 1.000000e+00 : f32
+//       CHECK:   %[[SUM:.+]] = spirv.FAdd %[[RATIOSQ]], %[[ONE]] : f32
+//       CHECK:   %[[SQRT:.+]] = spirv.GL.Sqrt %[[SUM]] : f32
+//       CHECK:   %[[ABS:.+]] = spirv.FMul %[[MAX]], %[[SQRT]] : f32
+//       CHECK:   %[[SIGNRE:.+]] = spirv.FDiv %[[RE]], %[[ABS]] : f32
+//       CHECK:   %[[SIGNIM:.+]] = spirv.FDiv %[[IM]], %[[ABS]] : f32
+//       CHECK:   %[[ZERO:.+]] = spirv.Constant 0.000000e+00 : f32
+//       CHECK:   %[[REZ:.+]] = spirv.FOrdEqual %[[RE]], %[[ZERO]] : f32
+//       CHECK:   %[[IMZ:.+]] = spirv.FOrdEqual %[[IM]], %[[ZERO]] : f32
+//       CHECK:   %[[ISZERO:.+]] = spirv.LogicalAnd %[[REZ]], %[[IMZ]] : i1
+//       CHECK:   %[[SELRE:.+]] = spirv.Select %[[ISZERO]], %[[RE]], %[[SIGNRE]] : i1, f32
+//       CHECK:   %[[SELIM:.+]] = spirv.Select %[[ISZERO]], %[[IM]], %[[SIGNIM]] : i1, f32
+//       CHECK:   %[[RESULT:.+]] = spirv.CompositeConstruct %[[SELRE]], %[[SELIM]] : (f32, f32) -> vector<2xf32>


        


More information about the Mlir-commits mailing list