[flang-commits] [flang] [flang] Region-based HLFIR operation for conditional expressions lowering (PR #194411)
Caroline Newcombe via flang-commits
flang-commits at lists.llvm.org
Thu May 7 14:02:50 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))
----------------
cenewcombe wrote:
Fixed — the new code only defers the single `DestroyOp` whose operand matches `yieldedEntity`. All other destroys are cloned in their original position, so sub-expression temps are properly freed.
https://github.com/llvm/llvm-project/pull/194411
More information about the flang-commits
mailing list