diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -19,6 +19,7 @@ #include "mlir/Conversion/LLVMCommon/TypeConverter.h" #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" #include "mlir/IR/BuiltinTypes.h" +#include "mlir/IR/Location.h" #include "mlir/Pass/Pass.h" #include "llvm/ADT/ArrayRef.h" @@ -154,6 +155,53 @@ } }; +// convert to LLVM IR dialect `load` +struct LoadOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + // fir.box is a special case because it is considered as an ssa values in + // fir, but it is lowered as a pointer to a descriptor. So fir.ref + // and fir.box end up being the same llvm types and loading a + // fir.ref is actually a no op in LLVM. + if (load.getType().isa()) { + rewriter.replaceOp(load, adaptor.getOperands()[0]); + } else { + mlir::Type ty = convertType(load.getType()); + ArrayRef at = load->getAttrs(); + rewriter.replaceOpWithNewOp( + load, ty, adaptor.getOperands(), at); + } + return success(); + } +}; + +// convert to LLVM IR dialect `store` +struct StoreOpConversion : public FIROpConversion { + using FIROpConversion::FIROpConversion; + + mlir::LogicalResult + matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + if (store.value().getType().isa()) { + // fir.box value is actually in memory, load it first before storing it. + mlir::Location loc = store.getLoc(); + mlir::Type boxPtrTy = adaptor.getOperands()[0].getType(); + auto val = rewriter.create( + loc, boxPtrTy.cast().getElementType(), + adaptor.getOperands()[0]); + rewriter.replaceOpWithNewOp( + store, val, adaptor.getOperands()[1]); + } else { + rewriter.replaceOpWithNewOp( + store, adaptor.getOperands()[0], adaptor.getOperands()[1]); + } + return success(); + } +}; + // convert to LLVM IR dialect `undef` struct UndefOpConversion : public FIROpConversion { using FIROpConversion::FIROpConversion; @@ -220,10 +268,9 @@ auto *context = getModule().getContext(); fir::LLVMTypeConverter typeConverter{getModule()}; mlir::OwningRewritePatternList pattern(context); - pattern - .insert( - typeConverter); + pattern.insert(typeConverter); mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern); mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter, pattern); diff --git a/flang/test/Fir/convert-to-llvm.fir b/flang/test/Fir/convert-to-llvm.fir --- a/flang/test/Fir/convert-to-llvm.fir +++ b/flang/test/Fir/convert-to-llvm.fir @@ -145,3 +145,43 @@ func @test_unreachable() { fir.unreachable } + +// ----- + +// Verify that fir.store is transformed to llvm.store + +// CHECK-LABEL: llvm.func @test.store( +// CHECK-SAME: %[[arg0:.*]]: i64, %[[arg1:.*]]: !llvm.ptr) { +// CHECK-NEXT: llvm.store %[[arg0]], %[[arg1]] : !llvm.ptr +// CHECK-NEXT: llvm.return +// CHECK-NEXT: } + +func @test.store(%lb : index, %addr : !fir.ref) { + fir.store %lb to %addr : !fir.ref + return +} + +// TODO Add a test with fir.ref once we have the required conversions +// are avaialble, e.g. +// func @test_store_box(%array : !fir.ref>>, %box : !fir.box>) { +// fir.store %box to %array : !fir.ref>> +// return +// } + +// ----- + +// Verify that fir.load is transformed to llvm.load + +// CHECK-LABEL: llvm.func @test_load( +// CHECK-SAME: %[[arg1:.*]]: !llvm.ptr) { +// CHECK-NEXT: %0 = llvm.load %[[arg1]] : !llvm.ptr +// CHECK-NEXT: llvm.return +// CHECK-NEXT: } + +func @test_load(%addr : !fir.ref) { + %0 = fir.load %addr : !fir.ref + return +} + +// TODO Add a test with fir.ref once the required conversions are +// available.