[fir] Add complex operations conversion from FIR LLVM IR
This patch add conversion for primitive operations on complex types. - fir.addc - fir.subc - fir.mulc - fir.divc - fir.negc This adds also the type conversion for !fir.complex<KIND> type. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: rovka Differential Revision: https://reviews.llvm.org/D113434 Co-authored-by: Jean Perier <jperier@nvidia.com> Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
This commit is contained in:
		
							parent
							
								
									2ca1cd7e37
								
							
						
					
					
						commit
						b9bc64ba14
					
				| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
#include "PassDetail.h"
 | 
					#include "PassDetail.h"
 | 
				
			||||||
#include "flang/Optimizer/Dialect/FIROps.h"
 | 
					#include "flang/Optimizer/Dialect/FIROps.h"
 | 
				
			||||||
#include "flang/Optimizer/Dialect/FIRType.h"
 | 
					#include "flang/Optimizer/Dialect/FIRType.h"
 | 
				
			||||||
 | 
					#include "flang/Optimizer/Support/FIRContext.h"
 | 
				
			||||||
#include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
 | 
					#include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
 | 
				
			||||||
#include "mlir/Conversion/LLVMCommon/Pattern.h"
 | 
					#include "mlir/Conversion/LLVMCommon/Pattern.h"
 | 
				
			||||||
#include "mlir/Conversion/LLVMCommon/TypeConverter.h"
 | 
					#include "mlir/Conversion/LLVMCommon/TypeConverter.h"
 | 
				
			||||||
| 
						 | 
					@ -487,6 +488,175 @@ struct InsertOnRangeOpConversion
 | 
				
			||||||
    return success();
 | 
					    return success();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static mlir::Type getComplexEleTy(mlir::Type complex) {
 | 
				
			||||||
 | 
					  if (auto cc = complex.dyn_cast<mlir::ComplexType>())
 | 
				
			||||||
 | 
					    return cc.getElementType();
 | 
				
			||||||
 | 
					  return complex.cast<fir::ComplexType>().getElementType();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Primitive operations on Complex types
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Generate inline code for complex addition/subtraction
 | 
				
			||||||
 | 
					template <typename LLVMOP, typename OPTY>
 | 
				
			||||||
 | 
					mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
 | 
				
			||||||
 | 
					                                     mlir::ConversionPatternRewriter &rewriter,
 | 
				
			||||||
 | 
					                                     fir::LLVMTypeConverter &lowering) {
 | 
				
			||||||
 | 
					  mlir::Value a = opnds[0];
 | 
				
			||||||
 | 
					  mlir::Value b = opnds[1];
 | 
				
			||||||
 | 
					  auto loc = sumop.getLoc();
 | 
				
			||||||
 | 
					  auto ctx = sumop.getContext();
 | 
				
			||||||
 | 
					  auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
 | 
				
			||||||
 | 
					  auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
 | 
				
			||||||
 | 
					  mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
 | 
				
			||||||
 | 
					  mlir::Type ty = lowering.convertType(sumop.getType());
 | 
				
			||||||
 | 
					  auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
 | 
				
			||||||
 | 
					  auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
 | 
				
			||||||
 | 
					  auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
 | 
				
			||||||
 | 
					  auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
 | 
				
			||||||
 | 
					  auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
 | 
				
			||||||
 | 
					  auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
 | 
				
			||||||
 | 
					  auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
 | 
				
			||||||
 | 
					  auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
 | 
				
			||||||
 | 
					  return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
 | 
				
			||||||
 | 
					  using FIROpConversion::FIROpConversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mlir::LogicalResult
 | 
				
			||||||
 | 
					  matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
 | 
				
			||||||
 | 
					                  mlir::ConversionPatternRewriter &rewriter) const override {
 | 
				
			||||||
 | 
					    // given: (x + iy) + (x' + iy')
 | 
				
			||||||
 | 
					    // result: (x + x') + i(y + y')
 | 
				
			||||||
 | 
					    auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
 | 
				
			||||||
 | 
					                                            rewriter, lowerTy());
 | 
				
			||||||
 | 
					    rewriter.replaceOp(addc, r.getResult());
 | 
				
			||||||
 | 
					    return success();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
 | 
				
			||||||
 | 
					  using FIROpConversion::FIROpConversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mlir::LogicalResult
 | 
				
			||||||
 | 
					  matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
 | 
				
			||||||
 | 
					                  mlir::ConversionPatternRewriter &rewriter) const override {
 | 
				
			||||||
 | 
					    // given: (x + iy) - (x' + iy')
 | 
				
			||||||
 | 
					    // result: (x - x') + i(y - y')
 | 
				
			||||||
 | 
					    auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
 | 
				
			||||||
 | 
					                                            rewriter, lowerTy());
 | 
				
			||||||
 | 
					    rewriter.replaceOp(subc, r.getResult());
 | 
				
			||||||
 | 
					    return success();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Inlined complex multiply
 | 
				
			||||||
 | 
					struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
 | 
				
			||||||
 | 
					  using FIROpConversion::FIROpConversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mlir::LogicalResult
 | 
				
			||||||
 | 
					  matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
 | 
				
			||||||
 | 
					                  mlir::ConversionPatternRewriter &rewriter) const override {
 | 
				
			||||||
 | 
					    // TODO: Can we use a call to __muldc3 ?
 | 
				
			||||||
 | 
					    // given: (x + iy) * (x' + iy')
 | 
				
			||||||
 | 
					    // result: (xx'-yy')+i(xy'+yx')
 | 
				
			||||||
 | 
					    mlir::Value a = adaptor.getOperands()[0];
 | 
				
			||||||
 | 
					    mlir::Value b = adaptor.getOperands()[1];
 | 
				
			||||||
 | 
					    auto loc = mulc.getLoc();
 | 
				
			||||||
 | 
					    auto *ctx = mulc.getContext();
 | 
				
			||||||
 | 
					    auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
 | 
				
			||||||
 | 
					    auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
 | 
				
			||||||
 | 
					    mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
 | 
				
			||||||
 | 
					    mlir::Type ty = convertType(mulc.getType());
 | 
				
			||||||
 | 
					    auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
 | 
				
			||||||
 | 
					    auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
 | 
				
			||||||
 | 
					    auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
 | 
				
			||||||
 | 
					    auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
 | 
				
			||||||
 | 
					    auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
 | 
				
			||||||
 | 
					    auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
 | 
				
			||||||
 | 
					    auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
 | 
				
			||||||
 | 
					    auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
 | 
				
			||||||
 | 
					    auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
 | 
				
			||||||
 | 
					    auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
 | 
				
			||||||
 | 
					    auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
 | 
				
			||||||
 | 
					    auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
 | 
				
			||||||
 | 
					    auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
 | 
				
			||||||
 | 
					    rewriter.replaceOp(mulc, r0.getResult());
 | 
				
			||||||
 | 
					    return success();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Inlined complex division
 | 
				
			||||||
 | 
					struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
 | 
				
			||||||
 | 
					  using FIROpConversion::FIROpConversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mlir::LogicalResult
 | 
				
			||||||
 | 
					  matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
 | 
				
			||||||
 | 
					                  mlir::ConversionPatternRewriter &rewriter) const override {
 | 
				
			||||||
 | 
					    // TODO: Can we use a call to __divdc3 instead?
 | 
				
			||||||
 | 
					    // Just generate inline code for now.
 | 
				
			||||||
 | 
					    // given: (x + iy) / (x' + iy')
 | 
				
			||||||
 | 
					    // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
 | 
				
			||||||
 | 
					    mlir::Value a = adaptor.getOperands()[0];
 | 
				
			||||||
 | 
					    mlir::Value b = adaptor.getOperands()[1];
 | 
				
			||||||
 | 
					    auto loc = divc.getLoc();
 | 
				
			||||||
 | 
					    auto *ctx = divc.getContext();
 | 
				
			||||||
 | 
					    auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
 | 
				
			||||||
 | 
					    auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
 | 
				
			||||||
 | 
					    mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
 | 
				
			||||||
 | 
					    mlir::Type ty = convertType(divc.getType());
 | 
				
			||||||
 | 
					    auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
 | 
				
			||||||
 | 
					    auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
 | 
				
			||||||
 | 
					    auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
 | 
				
			||||||
 | 
					    auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
 | 
				
			||||||
 | 
					    auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
 | 
				
			||||||
 | 
					    auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
 | 
				
			||||||
 | 
					    auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
 | 
				
			||||||
 | 
					    auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
 | 
				
			||||||
 | 
					    auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
 | 
				
			||||||
 | 
					    auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
 | 
				
			||||||
 | 
					    auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
 | 
				
			||||||
 | 
					    auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
 | 
				
			||||||
 | 
					    auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
 | 
				
			||||||
 | 
					    auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
 | 
				
			||||||
 | 
					    auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
 | 
				
			||||||
 | 
					    auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
 | 
				
			||||||
 | 
					    auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
 | 
				
			||||||
 | 
					    auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
 | 
				
			||||||
 | 
					    rewriter.replaceOp(divc, r0.getResult());
 | 
				
			||||||
 | 
					    return success();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Inlined complex negation
 | 
				
			||||||
 | 
					struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
 | 
				
			||||||
 | 
					  using FIROpConversion::FIROpConversion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mlir::LogicalResult
 | 
				
			||||||
 | 
					  matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
 | 
				
			||||||
 | 
					                  mlir::ConversionPatternRewriter &rewriter) const override {
 | 
				
			||||||
 | 
					    // given: -(x + iy)
 | 
				
			||||||
 | 
					    // result: -x - iy
 | 
				
			||||||
 | 
					    auto *ctxt = neg.getContext();
 | 
				
			||||||
 | 
					    auto eleTy = convertType(getComplexEleTy(neg.getType()));
 | 
				
			||||||
 | 
					    auto ty = convertType(neg.getType());
 | 
				
			||||||
 | 
					    auto loc = neg.getLoc();
 | 
				
			||||||
 | 
					    mlir::Value o0 = adaptor.getOperands()[0];
 | 
				
			||||||
 | 
					    auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
 | 
				
			||||||
 | 
					    auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
 | 
				
			||||||
 | 
					    auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
 | 
				
			||||||
 | 
					    auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
 | 
				
			||||||
 | 
					    auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
 | 
				
			||||||
 | 
					    auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
 | 
				
			||||||
 | 
					    auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
 | 
				
			||||||
 | 
					    rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
 | 
				
			||||||
 | 
					    return success();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace
 | 
					} // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
| 
						 | 
					@ -504,12 +674,13 @@ public:
 | 
				
			||||||
    auto *context = getModule().getContext();
 | 
					    auto *context = getModule().getContext();
 | 
				
			||||||
    fir::LLVMTypeConverter typeConverter{getModule()};
 | 
					    fir::LLVMTypeConverter typeConverter{getModule()};
 | 
				
			||||||
    mlir::OwningRewritePatternList pattern(context);
 | 
					    mlir::OwningRewritePatternList pattern(context);
 | 
				
			||||||
    pattern.insert<
 | 
					    pattern.insert<AddcOpConversion, AddrOfOpConversion, CallOpConversion,
 | 
				
			||||||
        AddrOfOpConversion, CallOpConversion, ExtractValueOpConversion,
 | 
					                   DivcOpConversion, ExtractValueOpConversion,
 | 
				
			||||||
        HasValueOpConversion, GlobalOpConversion, InsertOnRangeOpConversion,
 | 
					                   HasValueOpConversion, GlobalOpConversion,
 | 
				
			||||||
        InsertValueOpConversion, SelectOpConversion, SelectRankOpConversion,
 | 
					                   InsertOnRangeOpConversion, InsertValueOpConversion,
 | 
				
			||||||
        UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>(
 | 
					                   NegcOpConversion, MulcOpConversion, SelectOpConversion,
 | 
				
			||||||
        typeConverter);
 | 
					                   SelectRankOpConversion, SubcOpConversion, UndefOpConversion,
 | 
				
			||||||
 | 
					                   UnreachableOpConversion, ZeroOpConversion>(typeConverter);
 | 
				
			||||||
    mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
 | 
					    mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
 | 
				
			||||||
    mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
 | 
					    mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
 | 
				
			||||||
                                                            pattern);
 | 
					                                                            pattern);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,13 @@ struct GenericTarget : public CodeGenSpecifics {
 | 
				
			||||||
  using CodeGenSpecifics::CodeGenSpecifics;
 | 
					  using CodeGenSpecifics::CodeGenSpecifics;
 | 
				
			||||||
  using AT = CodeGenSpecifics::Attributes;
 | 
					  using AT = CodeGenSpecifics::Attributes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mlir::Type complexMemoryType(mlir::Type eleTy) const override {
 | 
				
			||||||
 | 
					    assert(fir::isa_real(eleTy));
 | 
				
			||||||
 | 
					    // { t, t }   struct of 2 eleTy
 | 
				
			||||||
 | 
					    mlir::TypeRange range = {eleTy, eleTy};
 | 
				
			||||||
 | 
					    return mlir::TupleType::get(eleTy.getContext(), range);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override {
 | 
					  Marshalling boxcharArgumentType(mlir::Type eleTy, bool sret) const override {
 | 
				
			||||||
    CodeGenSpecifics::Marshalling marshal;
 | 
					    CodeGenSpecifics::Marshalling marshal;
 | 
				
			||||||
    auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
 | 
					    auto idxTy = mlir::IntegerType::get(eleTy.getContext(), S::defaultWidth);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,9 @@ public:
 | 
				
			||||||
  CodeGenSpecifics() = delete;
 | 
					  CodeGenSpecifics() = delete;
 | 
				
			||||||
  virtual ~CodeGenSpecifics() {}
 | 
					  virtual ~CodeGenSpecifics() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Type presentation of a `complex<ele>` type value in memory.
 | 
				
			||||||
 | 
					  virtual mlir::Type complexMemoryType(mlir::Type eleTy) const = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Type representation of a `complex<eleTy>` type argument when passed by
 | 
					  /// Type representation of a `complex<eleTy>` type argument when passed by
 | 
				
			||||||
  /// value. An argument value may need to be passed as a (safe) reference
 | 
					  /// value. An argument value may need to be passed as a (safe) reference
 | 
				
			||||||
  /// argument.
 | 
					  /// argument.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
#define FORTRAN_OPTIMIZER_CODEGEN_TYPECONVERTER_H
 | 
					#define FORTRAN_OPTIMIZER_CODEGEN_TYPECONVERTER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "DescriptorModel.h"
 | 
					#include "DescriptorModel.h"
 | 
				
			||||||
 | 
					#include "Target.h"
 | 
				
			||||||
#include "flang/Lower/Todo.h" // remove when TODO's are done
 | 
					#include "flang/Lower/Todo.h" // remove when TODO's are done
 | 
				
			||||||
#include "flang/Optimizer/Support/FIRContext.h"
 | 
					#include "flang/Optimizer/Support/FIRContext.h"
 | 
				
			||||||
#include "flang/Optimizer/Support/KindMapping.h"
 | 
					#include "flang/Optimizer/Support/KindMapping.h"
 | 
				
			||||||
| 
						 | 
					@ -28,7 +29,10 @@ class LLVMTypeConverter : public mlir::LLVMTypeConverter {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  LLVMTypeConverter(mlir::ModuleOp module)
 | 
					  LLVMTypeConverter(mlir::ModuleOp module)
 | 
				
			||||||
      : mlir::LLVMTypeConverter(module.getContext()),
 | 
					      : mlir::LLVMTypeConverter(module.getContext()),
 | 
				
			||||||
        kindMapping(getKindMapping(module)) {
 | 
					        kindMapping(getKindMapping(module)),
 | 
				
			||||||
 | 
					        specifics(CodeGenSpecifics::get(module.getContext(),
 | 
				
			||||||
 | 
					                                        getTargetTriple(module),
 | 
				
			||||||
 | 
					                                        getKindMapping(module))) {
 | 
				
			||||||
    LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n");
 | 
					    LLVM_DEBUG(llvm::dbgs() << "FIR type converter\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Each conversion should return a value of type mlir::Type.
 | 
					    // Each conversion should return a value of type mlir::Type.
 | 
				
			||||||
| 
						 | 
					@ -39,6 +43,10 @@ public:
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    addConversion(
 | 
					    addConversion(
 | 
				
			||||||
        [&](fir::RecordType derived) { return convertRecordType(derived); });
 | 
					        [&](fir::RecordType derived) { return convertRecordType(derived); });
 | 
				
			||||||
 | 
					    addConversion(
 | 
				
			||||||
 | 
					        [&](fir::ComplexType cmplx) { return convertComplexType(cmplx); });
 | 
				
			||||||
 | 
					    addConversion(
 | 
				
			||||||
 | 
					        [&](fir::RealType real) { return convertRealType(real.getFKind()); });
 | 
				
			||||||
    addConversion(
 | 
					    addConversion(
 | 
				
			||||||
        [&](fir::ReferenceType ref) { return convertPointerLike(ref); });
 | 
					        [&](fir::ReferenceType ref) { return convertPointerLike(ref); });
 | 
				
			||||||
    addConversion(
 | 
					    addConversion(
 | 
				
			||||||
| 
						 | 
					@ -140,6 +148,24 @@ public:
 | 
				
			||||||
                                               /*isPacked=*/false));
 | 
					                                               /*isPacked=*/false));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Use the target specifics to figure out how to map complex to LLVM IR. The
 | 
				
			||||||
 | 
					  // use of complex values in function signatures is handled before conversion
 | 
				
			||||||
 | 
					  // to LLVM IR dialect here.
 | 
				
			||||||
 | 
					  //
 | 
				
			||||||
 | 
					  // fir.complex<T> | std.complex<T>    --> llvm<"{t,t}">
 | 
				
			||||||
 | 
					  template <typename C>
 | 
				
			||||||
 | 
					  mlir::Type convertComplexType(C cmplx) {
 | 
				
			||||||
 | 
					    LLVM_DEBUG(llvm::dbgs() << "type convert: " << cmplx << '\n');
 | 
				
			||||||
 | 
					    auto eleTy = cmplx.getElementType();
 | 
				
			||||||
 | 
					    return convertType(specifics->complexMemoryType(eleTy));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // convert a front-end kind value to either a std or LLVM IR dialect type
 | 
				
			||||||
 | 
					  // fir.real<n>  -->  llvm.anyfloat  where anyfloat is a kind mapping
 | 
				
			||||||
 | 
					  mlir::Type convertRealType(fir::KindTy kind) {
 | 
				
			||||||
 | 
					    return fromRealTypeID(kindMapping.getRealTypeID(kind), kind);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename A>
 | 
					  template <typename A>
 | 
				
			||||||
  mlir::Type convertPointerLike(A &ty) {
 | 
					  mlir::Type convertPointerLike(A &ty) {
 | 
				
			||||||
    mlir::Type eleTy = ty.getEleTy();
 | 
					    mlir::Type eleTy = ty.getEleTy();
 | 
				
			||||||
| 
						 | 
					@ -187,8 +213,33 @@ public:
 | 
				
			||||||
    return mlir::LLVM::LLVMPointerType::get(baseTy);
 | 
					    return mlir::LLVM::LLVMPointerType::get(baseTy);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Convert llvm::Type::TypeID to mlir::Type
 | 
				
			||||||
 | 
					  mlir::Type fromRealTypeID(llvm::Type::TypeID typeID, fir::KindTy kind) {
 | 
				
			||||||
 | 
					    switch (typeID) {
 | 
				
			||||||
 | 
					    case llvm::Type::TypeID::HalfTyID:
 | 
				
			||||||
 | 
					      return mlir::FloatType::getF16(&getContext());
 | 
				
			||||||
 | 
					    case llvm::Type::TypeID::BFloatTyID:
 | 
				
			||||||
 | 
					      return mlir::FloatType::getBF16(&getContext());
 | 
				
			||||||
 | 
					    case llvm::Type::TypeID::FloatTyID:
 | 
				
			||||||
 | 
					      return mlir::FloatType::getF32(&getContext());
 | 
				
			||||||
 | 
					    case llvm::Type::TypeID::DoubleTyID:
 | 
				
			||||||
 | 
					      return mlir::FloatType::getF64(&getContext());
 | 
				
			||||||
 | 
					    case llvm::Type::TypeID::X86_FP80TyID:
 | 
				
			||||||
 | 
					      return mlir::FloatType::getF80(&getContext());
 | 
				
			||||||
 | 
					    case llvm::Type::TypeID::FP128TyID:
 | 
				
			||||||
 | 
					      return mlir::FloatType::getF128(&getContext());
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					      emitError(UnknownLoc::get(&getContext()))
 | 
				
			||||||
 | 
					          << "unsupported type: !fir.real<" << kind << ">";
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  KindMapping &getKindMap() { return kindMapping; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  KindMapping kindMapping;
 | 
					  KindMapping kindMapping;
 | 
				
			||||||
 | 
					  std::unique_ptr<CodeGenSpecifics> specifics;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace fir
 | 
					} // namespace fir
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -376,3 +376,137 @@ func @test_call_return_val() -> i32 {
 | 
				
			||||||
// CHECK-NEXT:    %0 = llvm.call @dummy_return_val() : () -> i32
 | 
					// CHECK-NEXT:    %0 = llvm.call @dummy_return_val() : () -> i32
 | 
				
			||||||
// CHECK-NEXT:    llvm.return %0 : i32
 | 
					// CHECK-NEXT:    llvm.return %0 : i32
 | 
				
			||||||
// CHECK-NEXT:  }
 | 
					// CHECK-NEXT:  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test FIR complex addition conversion
 | 
				
			||||||
 | 
					// given: (x + iy) + (x' + iy')
 | 
				
			||||||
 | 
					// result: (x + x') + i(y + y')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func @fir_complex_add(%a: !fir.complex<16>, %b: !fir.complex<16>) -> !fir.complex<16> {
 | 
				
			||||||
 | 
					  %c = fir.addc %a, %b : !fir.complex<16>
 | 
				
			||||||
 | 
					  return %c : !fir.complex<16>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CHECK-LABEL: llvm.func @fir_complex_add(
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG0:.*]]: !llvm.struct<(f128, f128)>, 
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG1:.*]]: !llvm.struct<(f128, f128)>) -> !llvm.struct<(f128, f128)> {
 | 
				
			||||||
 | 
					// CHECK:         %[[X0:.*]] = llvm.extractvalue %[[ARG0]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y0:.*]] = llvm.extractvalue %[[ARG0]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[X1:.*]] = llvm.extractvalue %[[ARG1]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y1:.*]] = llvm.extractvalue %[[ARG1]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[ADD_X0_X1:.*]] = llvm.fadd %[[X0]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[ADD_Y0_Y1:.*]] = llvm.fadd %[[Y0]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.mlir.undef : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[ADD_X0_X1]], %{{.*}}[0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[ADD_Y0_Y1]], %{{.*}}[1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         llvm.return %{{.*}} : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test FIR complex substraction conversion
 | 
				
			||||||
 | 
					// given: (x + iy) - (x' + iy')
 | 
				
			||||||
 | 
					// result: (x - x') + i(y - y')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func @fir_complex_sub(%a: !fir.complex<16>, %b: !fir.complex<16>) -> !fir.complex<16> {
 | 
				
			||||||
 | 
					  %c = fir.subc %a, %b : !fir.complex<16>
 | 
				
			||||||
 | 
					  return %c : !fir.complex<16>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CHECK-LABEL: llvm.func @fir_complex_sub(
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG0:.*]]: !llvm.struct<(f128, f128)>, 
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG1:.*]]: !llvm.struct<(f128, f128)>) -> !llvm.struct<(f128, f128)> {
 | 
				
			||||||
 | 
					// CHECK:         %[[X0:.*]] = llvm.extractvalue %[[ARG0]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y0:.*]] = llvm.extractvalue %[[ARG0]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[X1:.*]] = llvm.extractvalue %[[ARG1]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y1:.*]] = llvm.extractvalue %[[ARG1]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[SUB_X0_X1:.*]] = llvm.fsub %[[X0]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[SUB_Y0_Y1:.*]] = llvm.fsub %[[Y0]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.mlir.undef : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[SUB_X0_X1]], %{{.*}}[0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[SUB_Y0_Y1]], %{{.*}}[1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         llvm.return %{{.*}} : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test FIR complex multiply conversion
 | 
				
			||||||
 | 
					// given: (x + iy) * (x' + iy')
 | 
				
			||||||
 | 
					// result: (xx'-yy')+i(xy'+yx')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func @fir_complex_mul(%a: !fir.complex<16>, %b: !fir.complex<16>) -> !fir.complex<16> {
 | 
				
			||||||
 | 
					  %c = fir.mulc %a, %b : !fir.complex<16>
 | 
				
			||||||
 | 
					  return %c : !fir.complex<16>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CHECK-LABEL: llvm.func @fir_complex_mul(
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG0:.*]]: !llvm.struct<(f128, f128)>, 
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG1:.*]]: !llvm.struct<(f128, f128)>) -> !llvm.struct<(f128, f128)> {
 | 
				
			||||||
 | 
					// CHECK:         %[[X0:.*]] = llvm.extractvalue %[[ARG0]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y0:.*]] = llvm.extractvalue %[[ARG0]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[X1:.*]] = llvm.extractvalue %[[ARG1]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y1:.*]] = llvm.extractvalue %[[ARG1]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_X0_X1:.*]] = llvm.fmul %[[X0]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_Y0_X1:.*]] = llvm.fmul %[[Y0]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_X0_Y1:.*]] = llvm.fmul %[[X0]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[ADD:.*]] = llvm.fadd %[[MUL_X0_Y1]], %[[MUL_Y0_X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_Y0_Y1:.*]] = llvm.fmul %[[Y0]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[SUB:.*]] = llvm.fsub %[[MUL_X0_X1]], %[[MUL_Y0_Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.mlir.undef : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[SUB]], %{{.*}}[0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[ADD]], %{{.*}}[1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         llvm.return %{{.*}} : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test FIR complex division conversion
 | 
				
			||||||
 | 
					// given: (x + iy) / (x' + iy')
 | 
				
			||||||
 | 
					// result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func @fir_complex_div(%a: !fir.complex<16>, %b: !fir.complex<16>) -> !fir.complex<16> {
 | 
				
			||||||
 | 
					  %c = fir.divc %a, %b : !fir.complex<16>
 | 
				
			||||||
 | 
					  return %c : !fir.complex<16>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CHECK-LABEL: llvm.func @fir_complex_div(
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG0:.*]]: !llvm.struct<(f128, f128)>, 
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG1:.*]]: !llvm.struct<(f128, f128)>) -> !llvm.struct<(f128, f128)> {
 | 
				
			||||||
 | 
					// CHECK:         %[[X0:.*]] = llvm.extractvalue %[[ARG0]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y0:.*]] = llvm.extractvalue %[[ARG0]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[X1:.*]] = llvm.extractvalue %[[ARG1]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y1:.*]] = llvm.extractvalue %[[ARG1]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_X0_X1:.*]] = llvm.fmul %[[X0]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_X1_X1:.*]] = llvm.fmul %[[X1]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_Y0_X1:.*]] = llvm.fmul %[[Y0]], %[[X1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_X0_Y1:.*]] = llvm.fmul %[[X0]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_Y0_Y1:.*]] = llvm.fmul %[[Y0]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[MUL_Y1_Y1:.*]] = llvm.fmul %[[Y1]], %[[Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[ADD_X1X1_Y1Y1:.*]] = llvm.fadd %[[MUL_X1_X1]], %[[MUL_Y1_Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[ADD_X0X1_Y0Y1:.*]] = llvm.fadd %[[MUL_X0_X1]], %[[MUL_Y0_Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[SUB_Y0X1_X0Y1:.*]] = llvm.fsub %[[MUL_Y0_X1]], %[[MUL_X0_Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[DIV0:.*]] = llvm.fdiv %[[ADD_X0X1_Y0Y1]], %[[ADD_X1X1_Y1Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[DIV1:.*]] = llvm.fdiv %[[SUB_Y0X1_X0Y1]], %[[ADD_X1X1_Y1Y1]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.mlir.undef : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[DIV0]], %{{.*}}[0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[DIV1]], %{{.*}}[1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         llvm.return %{{.*}} : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test FIR complex negation conversion
 | 
				
			||||||
 | 
					// given: -(x + iy)
 | 
				
			||||||
 | 
					// result: -x - iy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func @fir_complex_neg(%a: !fir.complex<16>) -> !fir.complex<16> {
 | 
				
			||||||
 | 
					  %c = fir.negc %a : !fir.complex<16>
 | 
				
			||||||
 | 
					  return %c : !fir.complex<16>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CHECK-LABEL: llvm.func @fir_complex_neg(
 | 
				
			||||||
 | 
					// CHECK-SAME:                             %[[ARG0:.*]]: !llvm.struct<(f128, f128)>) -> !llvm.struct<(f128, f128)> {
 | 
				
			||||||
 | 
					// CHECK:         %[[X:.*]] = llvm.extractvalue %[[ARG0]][0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[Y:.*]] = llvm.extractvalue %[[ARG0]][1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %[[NEGX:.*]] = llvm.fneg %[[X]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %[[NEGY:.*]] = llvm.fneg %[[Y]]  : f128
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[NEGX]], %{{.*}}[0 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         %{{.*}} = llvm.insertvalue %[[NEGY]], %{{.*}}[1 : i32] : !llvm.struct<(f128, f128)>
 | 
				
			||||||
 | 
					// CHECK:         llvm.return %{{.*}} : !llvm.struct<(f128, f128)>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,3 +72,31 @@ func private @foo3(%arg0: !fir.logical<8>)
 | 
				
			||||||
func private @foo4(%arg0: !fir.logical<16>)
 | 
					func private @foo4(%arg0: !fir.logical<16>)
 | 
				
			||||||
// CHECK-LABEL: foo4
 | 
					// CHECK-LABEL: foo4
 | 
				
			||||||
// CHECK-SAME: i128
 | 
					// CHECK-SAME: i128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// -----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test `!fir.complex<KIND>` conversion.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func private @foo0(%arg0: !fir.complex<2>)
 | 
				
			||||||
 | 
					// CHECK-LABEL: foo0
 | 
				
			||||||
 | 
					// CHECK-SAME: !llvm.struct<(f16, f16)>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func private @foo1(%arg0: !fir.complex<3>)
 | 
				
			||||||
 | 
					// CHECK-LABEL: foo1
 | 
				
			||||||
 | 
					// CHECK-SAME: !llvm.struct<(bf16, bf16)>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func private @foo2(%arg0: !fir.complex<4>)
 | 
				
			||||||
 | 
					// CHECK-LABEL: foo2
 | 
				
			||||||
 | 
					// CHECK-SAME: !llvm.struct<(f32, f32)>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func private @foo3(%arg0: !fir.complex<8>)
 | 
				
			||||||
 | 
					// CHECK-LABEL: foo3
 | 
				
			||||||
 | 
					// CHECK-SAME: !llvm.struct<(f64, f64)>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func private @foo4(%arg0: !fir.complex<10>)
 | 
				
			||||||
 | 
					// CHECK-LABEL: foo4
 | 
				
			||||||
 | 
					// CHECK-SAME: !llvm.struct<(f80, f80)>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func private @foo5(%arg0: !fir.complex<16>)
 | 
				
			||||||
 | 
					// CHECK-LABEL: foo5
 | 
				
			||||||
 | 
					// CHECK-SAME: !llvm.struct<(f128, f128)>)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue