[Mlir-commits] [mlir] [mlir][SPIR-V] Add ComplexToSPIRV lowering for complex.sin/cos (PR #231873)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Oct 14 04:37:24 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Arseniy Obolenskiy (aobolensk)
<details>
<summary>Changes</summary>
Lowers complex.sin/cos via the shared TrigonometricOpPattern base, following the standard real/imaginary component identities in terms of sin, cos, and exp of the scalar components.
---
Full diff: https://github.com/llvm/llvm-project/pull/231873.diff
2 Files Affected:
- (modified) mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp (+89-1)
- (modified) mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir (+100)
``````````diff
diff --git a/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp b/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
index e57d6d922e5ba..4195ade8287b1 100644
--- a/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
+++ b/mlir/lib/Conversion/ComplexToSPIRV/ComplexToSPIRV.cpp
@@ -369,6 +369,89 @@ struct SignOpPattern final : OpConversionPattern<complex::SignOp> {
return success();
}
};
+
+/// Common building blocks for complex.sin/cos, following the identities
+/// sin(x + iy) = sin(x) * (0.5*exp(y) + 0.5/exp(y))
+/// + i * cos(x) * (0.5*exp(y) - 0.5/exp(y))
+/// cos(x + iy) = cos(x) * (0.5/exp(y) + 0.5*exp(y))
+/// + i * sin(x) * (0.5/exp(y) - 0.5*exp(y))
+template <typename ComplexOp, typename SinOp, typename CosOp, typename ExpOp>
+struct TrigonometricOpPattern : OpConversionPattern<ComplexOp> {
+ using OpConversionPattern<ComplexOp>::OpConversionPattern;
+ using OpAdaptor = typename ComplexOp::Adaptor;
+
+ LogicalResult
+ matchAndRewrite(ComplexOp 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 half = createFPConstant(rewriter, loc, re.getType(), 0.5);
+ Value exp = ExpOp::create(rewriter, loc, im);
+ Value scaledExp = spirv::FMulOp::create(rewriter, loc, half, exp);
+ Value reciprocalExp = spirv::FDivOp::create(rewriter, loc, half, exp);
+ Value sin = SinOp::create(rewriter, loc, re);
+ Value cos = CosOp::create(rewriter, loc, re);
+
+ auto [resultRe, resultIm] =
+ combine(rewriter, loc, scaledExp, reciprocalExp, sin, cos);
+
+ rewriter.replaceOpWithNewOp<spirv::CompositeConstructOp>(
+ op, spirvType, llvm::ArrayRef<Value>{resultRe, resultIm});
+ return success();
+ }
+
+ virtual std::pair<Value, Value> combine(ConversionPatternRewriter &rewriter,
+ Location loc, Value scaledExp,
+ Value reciprocalExp, Value sin,
+ Value cos) const = 0;
+};
+
+template <typename SinOp, typename CosOp, typename ExpOp>
+struct SinOpPattern final
+ : TrigonometricOpPattern<complex::SinOp, SinOp, CosOp, ExpOp> {
+ using TrigonometricOpPattern<complex::SinOp, SinOp, CosOp,
+ ExpOp>::TrigonometricOpPattern;
+
+ std::pair<Value, Value> combine(ConversionPatternRewriter &rewriter,
+ Location loc, Value scaledExp,
+ Value reciprocalExp, Value sin,
+ Value cos) const override {
+ Value sum = spirv::FAddOp::create(rewriter, loc, scaledExp, reciprocalExp);
+ Value resultRe = spirv::FMulOp::create(rewriter, loc, sum, sin);
+ Value diff = spirv::FSubOp::create(rewriter, loc, scaledExp, reciprocalExp);
+ Value resultIm = spirv::FMulOp::create(rewriter, loc, diff, cos);
+ return {resultRe, resultIm};
+ }
+};
+
+template <typename SinOp, typename CosOp, typename ExpOp>
+struct CosOpPattern final
+ : TrigonometricOpPattern<complex::CosOp, SinOp, CosOp, ExpOp> {
+ using TrigonometricOpPattern<complex::CosOp, SinOp, CosOp,
+ ExpOp>::TrigonometricOpPattern;
+
+ std::pair<Value, Value> combine(ConversionPatternRewriter &rewriter,
+ Location loc, Value scaledExp,
+ Value reciprocalExp, Value sin,
+ Value cos) const override {
+ Value sum = spirv::FAddOp::create(rewriter, loc, reciprocalExp, scaledExp);
+ Value resultRe = spirv::FMulOp::create(rewriter, loc, sum, cos);
+ Value diff = spirv::FSubOp::create(rewriter, loc, reciprocalExp, scaledExp);
+ Value resultIm = spirv::FMulOp::create(rewriter, loc, diff, sin);
+ return {resultRe, resultIm};
+ }
+};
} // namespace
//===----------------------------------------------------------------------===//
@@ -395,5 +478,10 @@ void mlir::populateComplexToSPIRVPatterns(
SignOpPattern<spirv::GLSqrtOp, spirv::GLFAbsOp, spirv::GLFMaxOp,
spirv::GLFMinOp>,
SignOpPattern<spirv::CLSqrtOp, spirv::CLFAbsOp, spirv::CLFMaxOp,
- spirv::CLFMinOp>>(typeConverter, context);
+ spirv::CLFMinOp>,
+ SinOpPattern<spirv::GLSinOp, spirv::GLCosOp, spirv::GLExpOp>,
+ SinOpPattern<spirv::CLSinOp, spirv::CLCosOp, spirv::CLExpOp>,
+ CosOpPattern<spirv::GLSinOp, spirv::GLCosOp, spirv::GLExpOp>,
+ CosOpPattern<spirv::CLSinOp, spirv::CLCosOp, spirv::CLExpOp>>(
+ typeConverter, context);
}
diff --git a/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir b/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
index 1b39062ab985a..5d9bc983ecb13 100644
--- a/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
+++ b/mlir/test/Conversion/ComplexToSPIRV/complex-to-spirv.mlir
@@ -300,3 +300,103 @@ func.func @complex_sign(%arg: complex<f32>) -> complex<f32> {
// 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>
+
+// -----
+
+func.func @complex_sin(%arg: complex<f32>) -> complex<f32> {
+ %sin = complex.sin %arg : complex<f32>
+ return %sin : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex_sin
+// 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: %[[HALF:.+]] = spirv.Constant 5.000000e-01 : f32
+// CHECK: %[[EXP:.+]] = spirv.GL.Exp %[[IM]] : f32
+// CHECK: %[[SCALED:.+]] = spirv.FMul %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[RECIP:.+]] = spirv.FDiv %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[SIN:.+]] = spirv.GL.Sin %[[RE]] : f32
+// CHECK: %[[COS:.+]] = spirv.GL.Cos %[[RE]] : f32
+// CHECK: %[[SUM:.+]] = spirv.FAdd %[[SCALED]], %[[RECIP]] : f32
+// CHECK: %[[RESRE:.+]] = spirv.FMul %[[SUM]], %[[SIN]] : f32
+// CHECK: %[[DIFF:.+]] = spirv.FSub %[[SCALED]], %[[RECIP]] : f32
+// CHECK: %[[RESIM:.+]] = spirv.FMul %[[DIFF]], %[[COS]] : f32
+// CHECK: spirv.CompositeConstruct %[[RESRE]], %[[RESIM]] : (f32, f32) -> vector<2xf32>
+
+// -----
+
+func.func @complex_cos(%arg: complex<f32>) -> complex<f32> {
+ %cos = complex.cos %arg : complex<f32>
+ return %cos : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex_cos
+// 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: %[[HALF:.+]] = spirv.Constant 5.000000e-01 : f32
+// CHECK: %[[EXP:.+]] = spirv.GL.Exp %[[IM]] : f32
+// CHECK: %[[SCALED:.+]] = spirv.FMul %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[RECIP:.+]] = spirv.FDiv %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[SIN:.+]] = spirv.GL.Sin %[[RE]] : f32
+// CHECK: %[[COS:.+]] = spirv.GL.Cos %[[RE]] : f32
+// CHECK: %[[SUM:.+]] = spirv.FAdd %[[RECIP]], %[[SCALED]] : f32
+// CHECK: %[[RESRE:.+]] = spirv.FMul %[[SUM]], %[[COS]] : f32
+// CHECK: %[[DIFF:.+]] = spirv.FSub %[[RECIP]], %[[SCALED]] : f32
+// CHECK: %[[RESIM:.+]] = spirv.FMul %[[DIFF]], %[[SIN]] : f32
+// CHECK: spirv.CompositeConstruct %[[RESRE]], %[[RESIM]] : (f32, f32) -> vector<2xf32>
+
+// -----
+
+module attributes {
+ spirv.target_env = #spirv.target_env<#spirv.vce<v1.0, [Kernel], []>, #spirv.resource_limits<>>
+} {
+
+func.func @complex_sin_opencl(%arg: complex<f32>) -> complex<f32> {
+ %sin = complex.sin %arg : complex<f32>
+ return %sin : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex_sin_opencl
+// 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: %[[HALF:.+]] = spirv.Constant 5.000000e-01 : f32
+// CHECK: %[[EXP:.+]] = spirv.CL.exp %[[IM]] : f32
+// CHECK: %[[SCALED:.+]] = spirv.FMul %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[RECIP:.+]] = spirv.FDiv %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[SIN:.+]] = spirv.CL.sin %[[RE]] : f32
+// CHECK: %[[COS:.+]] = spirv.CL.cos %[[RE]] : f32
+// CHECK: %[[SUM:.+]] = spirv.FAdd %[[SCALED]], %[[RECIP]] : f32
+// CHECK: %[[RESRE:.+]] = spirv.FMul %[[SUM]], %[[SIN]] : f32
+// CHECK: %[[DIFF:.+]] = spirv.FSub %[[SCALED]], %[[RECIP]] : f32
+// CHECK: %[[RESIM:.+]] = spirv.FMul %[[DIFF]], %[[COS]] : f32
+// CHECK: spirv.CompositeConstruct %[[RESRE]], %[[RESIM]] : (f32, f32) -> vector<2xf32>
+
+func.func @complex_cos_opencl(%arg: complex<f32>) -> complex<f32> {
+ %cos = complex.cos %arg : complex<f32>
+ return %cos : complex<f32>
+}
+
+// CHECK-LABEL: func.func @complex_cos_opencl
+// 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: %[[HALF:.+]] = spirv.Constant 5.000000e-01 : f32
+// CHECK: %[[EXP:.+]] = spirv.CL.exp %[[IM]] : f32
+// CHECK: %[[SCALED:.+]] = spirv.FMul %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[RECIP:.+]] = spirv.FDiv %[[HALF]], %[[EXP]] : f32
+// CHECK: %[[SIN:.+]] = spirv.CL.sin %[[RE]] : f32
+// CHECK: %[[COS:.+]] = spirv.CL.cos %[[RE]] : f32
+// CHECK: %[[SUM:.+]] = spirv.FAdd %[[RECIP]], %[[SCALED]] : f32
+// CHECK: %[[RESRE:.+]] = spirv.FMul %[[SUM]], %[[COS]] : f32
+// CHECK: %[[DIFF:.+]] = spirv.FSub %[[RECIP]], %[[SCALED]] : f32
+// CHECK: %[[RESIM:.+]] = spirv.FMul %[[DIFF]], %[[SIN]] : f32
+// CHECK: spirv.CompositeConstruct %[[RESRE]], %[[RESIM]] : (f32, f32) -> vector<2xf32>
+
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/231873
More information about the Mlir-commits
mailing list