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