diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp index 9109f2b331567..327e385a11eec 100644 --- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp @@ -29,6 +29,7 @@ #include "flang/Optimizer/OpenMP/Passes.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/IR/Dominance.h" +#include "mlir/IR/IRMapping.h" #include "mlir/IR/PatternMatch.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassManager.h" @@ -880,6 +881,42 @@ struct EvaluateInMemoryOpConversion } }; +struct ExactlyOnceOpConversion + : public mlir::OpConversionPattern { + using mlir::OpConversionPattern::OpConversionPattern; + explicit ExactlyOnceOpConversion(mlir::MLIRContext *ctx) + : mlir::OpConversionPattern{ctx} {} + llvm::LogicalResult + matchAndRewrite(hlfir::ExactlyOnceOp exactlyOnce, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const override { + fir::FirOpBuilder builder(rewriter, exactlyOnce.getOperation()); + + // The body of the exactly_once op may contain operations that will require + // to be translated + HLFIRListener listener{builder, rewriter}; + builder.setListener(&listener); + + // Clone the exactly_once region body and convert it inline + mlir::Region ®ion = exactlyOnce.getBody(); + mlir::Block &block = region.front(); + mlir::IRMapping mapper; + + // Clone all operations except the terminator + for (auto &op : block.without_terminator()) { + rewriter.clone(op, mapper); + } + + // Get the yielded value and replace the exactly_once operation with it. + // Later we will register the pattern and mark the ExactlyOnceOp as + // illegal (see below). + auto yield = mlir::cast(block.getTerminator()); + mlir::Value yieldedValue = mapper.lookupOrDefault(yield.getEntity()); + + rewriter.replaceOp(exactlyOnce, yieldedValue); + return mlir::success(); + } +}; + class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase { public: using BufferizeHLFIRBase::BufferizeHLFIRBase; @@ -899,8 +936,9 @@ class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase { AssociateOpConversion, CharExtremumOpConversion, ConcatOpConversion, DestroyOpConversion, EndAssociateOpConversion, EvaluateInMemoryOpConversion, - NoReassocOpConversion, SetLengthOpConversion, - ShapeOfOpConversion, GetLengthOpConversion>(context); + ExactlyOnceOpConversion, NoReassocOpConversion, + SetLengthOpConversion, ShapeOfOpConversion, + GetLengthOpConversion>(context); patterns.insert(context, optimizeEmptyElementals); mlir::ConversionTarget target(*context); // Note that YieldElementOp is not marked as an illegal operation. @@ -909,7 +947,8 @@ class BufferizeHLFIR : public hlfir::impl::BufferizeHLFIRBase { // survives this pass, the verifier will detect it because it has to be // a child of ElementalOp and ElementalOp's are explicitly illegal. target.addIllegalOp(); + hlfir::EndAssociateOp, hlfir::ExactlyOnceOp, + hlfir::SetLengthOp>(); target.markUnknownOpDynamicallyLegal([](mlir::Operation *op) { return llvm::all_of(op->getResultTypes(), diff --git a/flang/test/HLFIR/bufferize-exactly_once.f90 b/flang/test/HLFIR/bufferize-exactly_once.f90 new file mode 100644 index 0000000000000..be97a70113653 --- /dev/null +++ b/flang/test/HLFIR/bufferize-exactly_once.f90 @@ -0,0 +1,20 @@ +! RUN: bbc -emit-hlfir %s -o - | FileCheck %s + +program main + call test06() + print *,'pass' +end program main + +subroutine test06() + type ty1 + integer ,allocatable :: a(:,:,:) + end type ty1 + type(ty1) :: str(1) + integer ,allocatable :: b(:,:,:) + allocate(str(1)%a(1,1,1),b(1,1,1)) + b=1 + write(6,*) "b = ", b + write(6,*) "reshape((/(b,jj=1,1)/),(/1,1,1/)) = ", reshape((/(b,jj=1,1)/),(/1,1,1/)) + where ((/.true./)) str=(/(ty1(reshape((/(b,jj=1,1)/),(/1,1,1/))),ii=1,1)/) + ! CHECK: hlfir.exactly_once : !hlfir.expr<1x1x1xi32> +end subroutine test06