[flang-commits] [flang] [flang] Implement conditional expressions lowering (F2023) (PR #186490)
Eugene Epshteyn via flang-commits
flang-commits at lists.llvm.org
Wed Apr 1 07:48:56 PDT 2026
================
@@ -1821,6 +1821,189 @@ class HlfirBuilder {
llvm_unreachable("unknown descriptor inquiry");
}
+ /// Build nested if-then-else chain by walking the right-skewed
+ /// ConditionalExpr tree. The assignValue callback generates and assigns
+ /// each value to avoid evaluating non-taken branches.
+ template <typename T, typename Callback>
+ void
+ buildConditionalIfChain(const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+ const Callback &assignValue) {
+ const mlir::Location loc{getLoc()};
+ fir::FirOpBuilder &builder{getBuilder()};
+ getStmtCtx().pushScope();
+ const hlfir::EntityWithAttributes condEntity{gen(condExpr.condition())};
+ mlir::Value condition{hlfir::loadTrivialScalar(loc, builder, condEntity)};
+ condition = builder.createConvert(loc, builder.getI1Type(), condition);
+ builder.genIfOp(loc, {}, condition, /*withElseRegion=*/true)
+ .genThen([&]() {
+ getStmtCtx().pushScope();
+ assignValue(condExpr.thenValue());
+ getStmtCtx().finalizeAndPop();
+ })
+ .genElse([&]() {
+ // Recurse for nested ConditionalExpr; else assign terminal value.
+ if (const auto *nested =
+ std::get_if<Fortran::evaluate::ConditionalExpr<T>>(
+ &condExpr.elseValue().u)) {
+ buildConditionalIfChain(*nested, assignValue);
+ } else {
+ getStmtCtx().pushScope();
+ assignValue(condExpr.elseValue());
+ getStmtCtx().finalizeAndPop();
+ }
+ })
+ .end();
+ getStmtCtx().finalizeAndPop();
+ }
+
+ /// Generate scalar conditional with lazy evaluation using assignment.
+ /// Creates a temporary and assigns the selected branch value to it.
+ template <typename T>
+ hlfir::Entity genScalarConditionalLazy(
+ const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+ mlir::Type elementType,
+ const llvm::SmallVector<mlir::Value, 1> &typeParams) {
+ const mlir::Location loc{getLoc()};
+ fir::FirOpBuilder &builder{getBuilder()};
+ const mlir::Value tempStorage{builder.createTemporary(
+ loc, elementType, ".cond.scalar",
+ /*shape=*/mlir::ValueRange{}, /*typeParams=*/typeParams)};
+ const hlfir::DeclareOp tempDecl{hlfir::DeclareOp::create(
+ builder, loc, tempStorage, ".cond.result",
+ /*shape=*/mlir::Value{}, /*typeParams=*/typeParams)};
+ const hlfir::Entity temp{tempDecl};
+ buildConditionalIfChain(
+ condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
+ hlfir::Entity entity{gen(expr)};
+ auto [exv, cleanup] = hlfir::convertToValue(loc, builder, entity);
+ hlfir::Entity value{fir::getBase(exv)};
+ if (cleanup) {
+ getStmtCtx().attachCleanup(*cleanup);
+ }
+ hlfir::AssignOp::create(builder, loc, value, temp);
+ });
+ return temp;
+ }
+
+ /// Generate conditional expression using an allocatable temporary with lazy
+ /// evaluation. Creates an unallocated allocatable, then uses assignment to
+ /// set the value from the chosen branch (allocation/reallocation handled by
+ /// runtime).
+ template <typename T>
+ hlfir::Entity genAllocatableConditionalLazy(
+ const Fortran::evaluate::ConditionalExpr<T> &condExpr,
+ mlir::Type resultType, llvm::StringRef debugName) {
+ const mlir::Location loc{getLoc()};
+ fir::FirOpBuilder &builder{getBuilder()};
+ const mlir::Type heapType{fir::HeapType::get(resultType)};
+ const mlir::Type boxHeapType{fir::BoxType::get(heapType)};
+ const mlir::Value tempStorage{
+ builder.createTemporary(loc, boxHeapType, debugName)};
+ const mlir::Value unallocBox{fir::factory::createUnallocatedBox(
+ builder, loc, boxHeapType, /*nonDeferredParams=*/{})};
+ builder.createStoreWithConvert(loc, unallocBox, tempStorage);
+ const hlfir::DeclareOp tempDecl{
+ hlfir::DeclareOp::create(builder, loc, tempStorage, ".cond.result")};
+ const hlfir::Entity temp{tempDecl};
+ // Lazy evaluation: only the selected branch is evaluated and assigned.
+ buildConditionalIfChain(
+ condExpr, [&](const Fortran::evaluate::Expr<T> &expr) {
+ const hlfir::Entity entity{gen(expr)};
+ hlfir::AssignOp::create(builder, loc, entity, temp,
+ /*isWholeAllocatableAssignment=*/true,
+ /*keepLhsLengthIfRealloc=*/false,
+ /*temporary_lhs=*/true);
+ });
+ return temp;
----------------
eugeneepshteyn wrote:
Does `temp` need to be scheduled for deallocation?
https://github.com/llvm/llvm-project/pull/186490
More information about the flang-commits
mailing list