1*d0cb0d30SAlexander Belyaev //===- ComplexToLLVM.cpp - conversion from Complex to LLVM dialect --------===//
2*d0cb0d30SAlexander Belyaev //
3*d0cb0d30SAlexander Belyaev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d0cb0d30SAlexander Belyaev // See https://llvm.org/LICENSE.txt for license information.
5*d0cb0d30SAlexander Belyaev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*d0cb0d30SAlexander Belyaev //
7*d0cb0d30SAlexander Belyaev //===----------------------------------------------------------------------===//
8*d0cb0d30SAlexander Belyaev 
9*d0cb0d30SAlexander Belyaev #include "mlir/Conversion/ComplexToLLVM/ComplexToLLVM.h"
10*d0cb0d30SAlexander Belyaev 
11*d0cb0d30SAlexander Belyaev #include "../PassDetail.h"
12*d0cb0d30SAlexander Belyaev #include "mlir/Dialect/Complex/IR/Complex.h"
13*d0cb0d30SAlexander Belyaev #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
14*d0cb0d30SAlexander Belyaev 
15*d0cb0d30SAlexander Belyaev using namespace mlir;
16*d0cb0d30SAlexander Belyaev using namespace mlir::LLVM;
17*d0cb0d30SAlexander Belyaev 
18*d0cb0d30SAlexander Belyaev namespace {
19*d0cb0d30SAlexander Belyaev 
20*d0cb0d30SAlexander Belyaev struct CreateOpConversion : public ConvertOpToLLVMPattern<complex::CreateOp> {
21*d0cb0d30SAlexander Belyaev   using ConvertOpToLLVMPattern<complex::CreateOp>::ConvertOpToLLVMPattern;
22*d0cb0d30SAlexander Belyaev 
23*d0cb0d30SAlexander Belyaev   LogicalResult
24*d0cb0d30SAlexander Belyaev   matchAndRewrite(complex::CreateOp complexOp, ArrayRef<Value> operands,
25*d0cb0d30SAlexander Belyaev                   ConversionPatternRewriter &rewriter) const override {
26*d0cb0d30SAlexander Belyaev     complex::CreateOp::Adaptor transformed(operands);
27*d0cb0d30SAlexander Belyaev 
28*d0cb0d30SAlexander Belyaev     // Pack real and imaginary part in a complex number struct.
29*d0cb0d30SAlexander Belyaev     auto loc = complexOp.getLoc();
30*d0cb0d30SAlexander Belyaev     auto structType = typeConverter->convertType(complexOp.getType());
31*d0cb0d30SAlexander Belyaev     auto complexStruct = ComplexStructBuilder::undef(rewriter, loc, structType);
32*d0cb0d30SAlexander Belyaev     complexStruct.setReal(rewriter, loc, transformed.real());
33*d0cb0d30SAlexander Belyaev     complexStruct.setImaginary(rewriter, loc, transformed.imaginary());
34*d0cb0d30SAlexander Belyaev 
35*d0cb0d30SAlexander Belyaev     rewriter.replaceOp(complexOp, {complexStruct});
36*d0cb0d30SAlexander Belyaev     return success();
37*d0cb0d30SAlexander Belyaev   }
38*d0cb0d30SAlexander Belyaev };
39*d0cb0d30SAlexander Belyaev 
40*d0cb0d30SAlexander Belyaev struct ReOpConversion : public ConvertOpToLLVMPattern<complex::ReOp> {
41*d0cb0d30SAlexander Belyaev   using ConvertOpToLLVMPattern<complex::ReOp>::ConvertOpToLLVMPattern;
42*d0cb0d30SAlexander Belyaev 
43*d0cb0d30SAlexander Belyaev   LogicalResult
44*d0cb0d30SAlexander Belyaev   matchAndRewrite(complex::ReOp op, ArrayRef<Value> operands,
45*d0cb0d30SAlexander Belyaev                   ConversionPatternRewriter &rewriter) const override {
46*d0cb0d30SAlexander Belyaev     complex::ReOp::Adaptor transformed(operands);
47*d0cb0d30SAlexander Belyaev 
48*d0cb0d30SAlexander Belyaev     // Extract real part from the complex number struct.
49*d0cb0d30SAlexander Belyaev     ComplexStructBuilder complexStruct(transformed.complex());
50*d0cb0d30SAlexander Belyaev     Value real = complexStruct.real(rewriter, op.getLoc());
51*d0cb0d30SAlexander Belyaev     rewriter.replaceOp(op, real);
52*d0cb0d30SAlexander Belyaev 
53*d0cb0d30SAlexander Belyaev     return success();
54*d0cb0d30SAlexander Belyaev   }
55*d0cb0d30SAlexander Belyaev };
56*d0cb0d30SAlexander Belyaev 
57*d0cb0d30SAlexander Belyaev struct ImOpConversion : public ConvertOpToLLVMPattern<complex::ImOp> {
58*d0cb0d30SAlexander Belyaev   using ConvertOpToLLVMPattern<complex::ImOp>::ConvertOpToLLVMPattern;
59*d0cb0d30SAlexander Belyaev 
60*d0cb0d30SAlexander Belyaev   LogicalResult
61*d0cb0d30SAlexander Belyaev   matchAndRewrite(complex::ImOp op, ArrayRef<Value> operands,
62*d0cb0d30SAlexander Belyaev                   ConversionPatternRewriter &rewriter) const override {
63*d0cb0d30SAlexander Belyaev     complex::ImOp::Adaptor transformed(operands);
64*d0cb0d30SAlexander Belyaev 
65*d0cb0d30SAlexander Belyaev     // Extract imaginary part from the complex number struct.
66*d0cb0d30SAlexander Belyaev     ComplexStructBuilder complexStruct(transformed.complex());
67*d0cb0d30SAlexander Belyaev     Value imaginary = complexStruct.imaginary(rewriter, op.getLoc());
68*d0cb0d30SAlexander Belyaev     rewriter.replaceOp(op, imaginary);
69*d0cb0d30SAlexander Belyaev 
70*d0cb0d30SAlexander Belyaev     return success();
71*d0cb0d30SAlexander Belyaev   }
72*d0cb0d30SAlexander Belyaev };
73*d0cb0d30SAlexander Belyaev 
74*d0cb0d30SAlexander Belyaev struct BinaryComplexOperands {
75*d0cb0d30SAlexander Belyaev   std::complex<Value> lhs;
76*d0cb0d30SAlexander Belyaev   std::complex<Value> rhs;
77*d0cb0d30SAlexander Belyaev };
78*d0cb0d30SAlexander Belyaev 
79*d0cb0d30SAlexander Belyaev template <typename OpTy>
80*d0cb0d30SAlexander Belyaev BinaryComplexOperands
81*d0cb0d30SAlexander Belyaev unpackBinaryComplexOperands(OpTy op, ArrayRef<Value> operands,
82*d0cb0d30SAlexander Belyaev                             ConversionPatternRewriter &rewriter) {
83*d0cb0d30SAlexander Belyaev   auto loc = op.getLoc();
84*d0cb0d30SAlexander Belyaev   typename OpTy::Adaptor transformed(operands);
85*d0cb0d30SAlexander Belyaev 
86*d0cb0d30SAlexander Belyaev   // Extract real and imaginary values from operands.
87*d0cb0d30SAlexander Belyaev   BinaryComplexOperands unpacked;
88*d0cb0d30SAlexander Belyaev   ComplexStructBuilder lhs(transformed.lhs());
89*d0cb0d30SAlexander Belyaev   unpacked.lhs.real(lhs.real(rewriter, loc));
90*d0cb0d30SAlexander Belyaev   unpacked.lhs.imag(lhs.imaginary(rewriter, loc));
91*d0cb0d30SAlexander Belyaev   ComplexStructBuilder rhs(transformed.rhs());
92*d0cb0d30SAlexander Belyaev   unpacked.rhs.real(rhs.real(rewriter, loc));
93*d0cb0d30SAlexander Belyaev   unpacked.rhs.imag(rhs.imaginary(rewriter, loc));
94*d0cb0d30SAlexander Belyaev 
95*d0cb0d30SAlexander Belyaev   return unpacked;
96*d0cb0d30SAlexander Belyaev }
97*d0cb0d30SAlexander Belyaev 
98*d0cb0d30SAlexander Belyaev struct AddOpConversion : public ConvertOpToLLVMPattern<complex::AddOp> {
99*d0cb0d30SAlexander Belyaev   using ConvertOpToLLVMPattern<complex::AddOp>::ConvertOpToLLVMPattern;
100*d0cb0d30SAlexander Belyaev 
101*d0cb0d30SAlexander Belyaev   LogicalResult
102*d0cb0d30SAlexander Belyaev   matchAndRewrite(complex::AddOp op, ArrayRef<Value> operands,
103*d0cb0d30SAlexander Belyaev                   ConversionPatternRewriter &rewriter) const override {
104*d0cb0d30SAlexander Belyaev     auto loc = op.getLoc();
105*d0cb0d30SAlexander Belyaev     BinaryComplexOperands arg =
106*d0cb0d30SAlexander Belyaev         unpackBinaryComplexOperands<complex::AddOp>(op, operands, rewriter);
107*d0cb0d30SAlexander Belyaev 
108*d0cb0d30SAlexander Belyaev     // Initialize complex number struct for result.
109*d0cb0d30SAlexander Belyaev     auto structType = typeConverter->convertType(op.getType());
110*d0cb0d30SAlexander Belyaev     auto result = ComplexStructBuilder::undef(rewriter, loc, structType);
111*d0cb0d30SAlexander Belyaev 
112*d0cb0d30SAlexander Belyaev     // Emit IR to add complex numbers.
113*d0cb0d30SAlexander Belyaev     auto fmf = LLVM::FMFAttr::get({}, op.getContext());
114*d0cb0d30SAlexander Belyaev     Value real =
115*d0cb0d30SAlexander Belyaev         rewriter.create<LLVM::FAddOp>(loc, arg.lhs.real(), arg.rhs.real(), fmf);
116*d0cb0d30SAlexander Belyaev     Value imag =
117*d0cb0d30SAlexander Belyaev         rewriter.create<LLVM::FAddOp>(loc, arg.lhs.imag(), arg.rhs.imag(), fmf);
118*d0cb0d30SAlexander Belyaev     result.setReal(rewriter, loc, real);
119*d0cb0d30SAlexander Belyaev     result.setImaginary(rewriter, loc, imag);
120*d0cb0d30SAlexander Belyaev 
121*d0cb0d30SAlexander Belyaev     rewriter.replaceOp(op, {result});
122*d0cb0d30SAlexander Belyaev     return success();
123*d0cb0d30SAlexander Belyaev   }
124*d0cb0d30SAlexander Belyaev };
125*d0cb0d30SAlexander Belyaev 
126*d0cb0d30SAlexander Belyaev struct SubOpConversion : public ConvertOpToLLVMPattern<complex::SubOp> {
127*d0cb0d30SAlexander Belyaev   using ConvertOpToLLVMPattern<complex::SubOp>::ConvertOpToLLVMPattern;
128*d0cb0d30SAlexander Belyaev 
129*d0cb0d30SAlexander Belyaev   LogicalResult
130*d0cb0d30SAlexander Belyaev   matchAndRewrite(complex::SubOp op, ArrayRef<Value> operands,
131*d0cb0d30SAlexander Belyaev                   ConversionPatternRewriter &rewriter) const override {
132*d0cb0d30SAlexander Belyaev     auto loc = op.getLoc();
133*d0cb0d30SAlexander Belyaev     BinaryComplexOperands arg =
134*d0cb0d30SAlexander Belyaev         unpackBinaryComplexOperands<complex::SubOp>(op, operands, rewriter);
135*d0cb0d30SAlexander Belyaev 
136*d0cb0d30SAlexander Belyaev     // Initialize complex number struct for result.
137*d0cb0d30SAlexander Belyaev     auto structType = typeConverter->convertType(op.getType());
138*d0cb0d30SAlexander Belyaev     auto result = ComplexStructBuilder::undef(rewriter, loc, structType);
139*d0cb0d30SAlexander Belyaev 
140*d0cb0d30SAlexander Belyaev     // Emit IR to substract complex numbers.
141*d0cb0d30SAlexander Belyaev     auto fmf = LLVM::FMFAttr::get({}, op.getContext());
142*d0cb0d30SAlexander Belyaev     Value real =
143*d0cb0d30SAlexander Belyaev         rewriter.create<LLVM::FSubOp>(loc, arg.lhs.real(), arg.rhs.real(), fmf);
144*d0cb0d30SAlexander Belyaev     Value imag =
145*d0cb0d30SAlexander Belyaev         rewriter.create<LLVM::FSubOp>(loc, arg.lhs.imag(), arg.rhs.imag(), fmf);
146*d0cb0d30SAlexander Belyaev     result.setReal(rewriter, loc, real);
147*d0cb0d30SAlexander Belyaev     result.setImaginary(rewriter, loc, imag);
148*d0cb0d30SAlexander Belyaev 
149*d0cb0d30SAlexander Belyaev     rewriter.replaceOp(op, {result});
150*d0cb0d30SAlexander Belyaev     return success();
151*d0cb0d30SAlexander Belyaev   }
152*d0cb0d30SAlexander Belyaev };
153*d0cb0d30SAlexander Belyaev } // namespace
154*d0cb0d30SAlexander Belyaev 
155*d0cb0d30SAlexander Belyaev void mlir::populateComplexToLLVMConversionPatterns(
156*d0cb0d30SAlexander Belyaev     LLVMTypeConverter &converter, OwningRewritePatternList &patterns) {
157*d0cb0d30SAlexander Belyaev   // clang-format off
158*d0cb0d30SAlexander Belyaev   patterns.insert<
159*d0cb0d30SAlexander Belyaev       AddOpConversion,
160*d0cb0d30SAlexander Belyaev       CreateOpConversion,
161*d0cb0d30SAlexander Belyaev       ImOpConversion,
162*d0cb0d30SAlexander Belyaev       ReOpConversion,
163*d0cb0d30SAlexander Belyaev       SubOpConversion
164*d0cb0d30SAlexander Belyaev     >(converter);
165*d0cb0d30SAlexander Belyaev   // clang-format on
166*d0cb0d30SAlexander Belyaev }
167*d0cb0d30SAlexander Belyaev 
168*d0cb0d30SAlexander Belyaev namespace {
169*d0cb0d30SAlexander Belyaev struct ConvertComplexToLLVMPass
170*d0cb0d30SAlexander Belyaev     : public ConvertComplexToLLVMBase<ConvertComplexToLLVMPass> {
171*d0cb0d30SAlexander Belyaev   void runOnOperation() override;
172*d0cb0d30SAlexander Belyaev };
173*d0cb0d30SAlexander Belyaev } // namespace
174*d0cb0d30SAlexander Belyaev 
175*d0cb0d30SAlexander Belyaev void ConvertComplexToLLVMPass::runOnOperation() {
176*d0cb0d30SAlexander Belyaev   auto module = getOperation();
177*d0cb0d30SAlexander Belyaev 
178*d0cb0d30SAlexander Belyaev   // Convert to the LLVM IR dialect using the converter defined above.
179*d0cb0d30SAlexander Belyaev   OwningRewritePatternList patterns;
180*d0cb0d30SAlexander Belyaev   LLVMTypeConverter converter(&getContext());
181*d0cb0d30SAlexander Belyaev   populateStdToLLVMConversionPatterns(converter, patterns);
182*d0cb0d30SAlexander Belyaev   populateComplexToLLVMConversionPatterns(converter, patterns);
183*d0cb0d30SAlexander Belyaev 
184*d0cb0d30SAlexander Belyaev   LLVMConversionTarget target(getContext());
185*d0cb0d30SAlexander Belyaev   target.addLegalOp<ModuleOp, ModuleTerminatorOp>();
186*d0cb0d30SAlexander Belyaev   if (failed(applyFullConversion(module, target, std::move(patterns))))
187*d0cb0d30SAlexander Belyaev     signalPassFailure();
188*d0cb0d30SAlexander Belyaev }
189*d0cb0d30SAlexander Belyaev 
190*d0cb0d30SAlexander Belyaev std::unique_ptr<OperationPass<ModuleOp>>
191*d0cb0d30SAlexander Belyaev mlir::createConvertComplexToLLVMPass() {
192*d0cb0d30SAlexander Belyaev   return std::make_unique<ConvertComplexToLLVMPass>();
193*d0cb0d30SAlexander Belyaev }
194