[flang-commits] [flang] [flang] Region-based HLFIR operation for conditional expressions lowering (PR #194411)
via flang-commits
flang-commits at lists.llvm.org
Wed May 27 06:55:06 PDT 2026
================
@@ -857,6 +858,137 @@ struct CharExtremumOpConversion
}
};
+struct ConditionalOpConversion
+ : public mlir::OpConversionPattern<hlfir::ConditionalOp> {
+ using mlir::OpConversionPattern<hlfir::ConditionalOp>::OpConversionPattern;
+ explicit ConditionalOpConversion(mlir::MLIRContext *ctx)
+ : mlir::OpConversionPattern<hlfir::ConditionalOp>{ctx} {
+ // This pattern recursively converts nested ConditionalOp's
+ // by cloning and then converting them, so we have to allow
+ // for recursive pattern application. The recursion is bounded
+ // by the nesting level of ConditionalOp's.
+ setHasBoundedRewriteRecursion();
+ }
+ /// Compute the MLIR type of the temp's DeclareOp base result,
+ /// given the hlfir.expr type of the conditional. This must match
+ /// what createAndDeclareTemp + hlfir::DeclareOp would produce.
+ static mlir::Type computeTempBaseType(fir::FirOpBuilder &builder,
+ hlfir::ExprType exprType) {
+ const mlir::Type eleTy{exprType.getEleTy()};
+ const bool isPolymorphic{exprType.isPolymorphic()};
+ const bool isArray{exprType.isArray()};
+ mlir::Type elemOrSeqType{eleTy};
+ if (isArray)
+ elemOrSeqType = fir::SequenceType::get(exprType.getShape(), eleTy);
+ // Polymorphic: runtime allocate produces fir.class<fir.heap<T>>,
+ // DeclareOp strips the heap attribute → fir.class<T>.
+ if (isPolymorphic)
+ return fir::ClassType::get(elemOrSeqType);
+ // Arrays (non-polymorphic): heap alloc → fir.heap<seqTy>,
+ // DeclareOp wraps in box → fir.box<seqTy>.
+ if (isArray)
+ return fir::BoxType::get(elemOrSeqType);
+ // Scalar, non-polymorphic.
+ if (auto charTy{mlir::dyn_cast<fir::CharacterType>(eleTy)})
+ if (charTy.hasDynamicLen())
+ return fir::BoxCharType::get(builder.getContext(), charTy.getFKind());
+ if (fir::isRecordWithTypeParameters(eleTy))
+ return fir::BoxType::get(eleTy);
+ return fir::ReferenceType::get(eleTy);
+ }
+
+ llvm::LogicalResult
+ matchAndRewrite(hlfir::ConditionalOp condOp, OpAdaptor adaptor,
+ mlir::ConversionPatternRewriter &rewriter) const override {
+ const mlir::Location loc{condOp->getLoc()};
+ fir::FirOpBuilder builder(rewriter, condOp.getOperation());
+ HLFIRListener listener{builder, rewriter};
+ builder.setListener(&listener);
+ // Use ExprType to ensure both branches produce identical MLIR temp types.
+ const auto exprType{
+ mlir::cast<hlfir::ExprType>(condOp.getResult().getType())};
+ const bool isPolymorphic{exprType.isPolymorphic()};
+ const bool isArray{exprType.isArray()};
+ mlir::Type elemOrSeqType{exprType.getEleTy()};
+ if (isArray)
+ elemOrSeqType =
+ fir::SequenceType::get(exprType.getShape(), elemOrSeqType);
+ const bool useStack{!isArray && !isPolymorphic};
+ const mlir::Type tempBaseType{computeTempBaseType(builder, exprType)};
+ // Callback for hlfir::DeclareOp.
+ auto genTempDeclareOp =
+ [](fir::FirOpBuilder &bldr, mlir::Location l, mlir::Value memref,
+ llvm::StringRef name, mlir::Value shape,
+ llvm::ArrayRef<mlir::Value> typeParams,
+ fir::FortranVariableFlagsAttr attrs) -> mlir::Value {
+ auto declareOp =
+ hlfir::DeclareOp::create(bldr, l, memref, name, shape, typeParams,
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, attrs);
+ return declareOp.getBase();
+ };
+
+ // Emit one branch: clone ops, create temp, assign, run deferred
+ // destroys, yield (temp, mustFree).
+ auto emitBranch = [&](mlir::Region ®ion) {
+ mlir::IRMapping mapper;
+ // Clone all ops except hlfir.destroy and the terminator.
+ for (auto &op : region.front().without_terminator())
+ if (!mlir::isa<hlfir::DestroyOp>(op))
+ builder.clone(op, mapper);
+ auto yield{mlir::cast<hlfir::YieldOp>(region.front().getTerminator())};
----------------
jeanPerier wrote:
I see. I think a solution for this is to generate an hlfir.associate operation to create the temporary from the expression value and let the AssociateOp pattern lowering try to forward the buffer of that was given to the expression value input after bufferization to the output.
In general, I think a valid generic codegen would be to:
1. generate hlfir.as_expr if the yielded is not an hlfir.expr (without move semantics)
2. generate hlfir.associate on the yielded expr or created hlfir.as_expr result
3. cast result storage as appropriate and forward the storage + must free flags.
The pattern iteration will deal with doing the codegeneration of hlfir.as_expr and hlfir.associate as best as possible.
https://github.com/llvm/llvm-project/pull/194411
More information about the flang-commits
mailing list