diff --git a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp --- a/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp +++ b/flang/lib/Optimizer/HLFIR/Transforms/ConvertToFIR.cpp @@ -286,26 +286,52 @@ mlir::Value hlfirBase; mlir::Type hlfirBaseType = declareOp.getBase().getType(); if (hlfirBaseType.isa()) { - // Need to conditionally rebox/embox for optional. - if (mlir::cast(declareOp.getOperation()) - .isOptional()) - TODO(loc, "converting hlfir declare of optional box to fir"); - if (!firBase.getType().isa()) { - llvm::SmallVector typeParams; - auto maybeCharType = - fir::unwrapSequenceType(fir::unwrapPassByRefType(hlfirBaseType)) - .dyn_cast(); - if (!maybeCharType || maybeCharType.hasDynamicLen()) - typeParams.append(declareOp.getTypeparams().begin(), - declareOp.getTypeparams().end()); - hlfirBase = rewriter.create( - loc, hlfirBaseType, firBase, declareOp.getShape(), - /*slice=*/mlir::Value{}, typeParams); + auto module = declareOp->getParentOfType(); + fir::FirOpBuilder builder(rewriter, fir::getKindMapping(module)); + // Helper to generate the hlfir fir.box with the local lower bounds and + // type parameters. + auto genHlfirBox = [&]() -> mlir::Value { + if (!firBase.getType().isa()) { + llvm::SmallVector typeParams; + auto maybeCharType = + fir::unwrapSequenceType(fir::unwrapPassByRefType(hlfirBaseType)) + .dyn_cast(); + if (!maybeCharType || maybeCharType.hasDynamicLen()) + typeParams.append(declareOp.getTypeparams().begin(), + declareOp.getTypeparams().end()); + return builder.create( + loc, hlfirBaseType, firBase, declareOp.getShape(), + /*slice=*/mlir::Value{}, typeParams); + } else { + // Rebox so that lower bounds are correct. + return builder.create(loc, hlfirBaseType, firBase, + declareOp.getShape(), + /*slice=*/mlir::Value{}); + } + }; + if (!mlir::cast(declareOp.getOperation()) + .isOptional()) { + hlfirBase = genHlfirBox(); } else { - // Rebox so that lower bounds are correct. - hlfirBase = rewriter.create(loc, hlfirBaseType, firBase, - declareOp.getShape(), - /*slice=*/mlir::Value{}); + // Need to conditionally rebox/embox the optional: the input fir.box + // may be null and the rebox would be illegal. It is also important to + // preserve the optional aspect: the hlfir fir.box should be null if + // the entity is absent so that later fir.is_present on the hlfir base + // are valid. + mlir::Value isPresent = + builder.create(loc, builder.getI1Type(), firBase); + hlfirBase = builder + .genIfOp(loc, {hlfirBaseType}, isPresent, + /*withElseRegion=*/true) + .genThen([&] { + builder.create(loc, genHlfirBox()); + }) + .genElse([&]() { + mlir::Value absent = + builder.create(loc, hlfirBaseType); + builder.create(loc, absent); + }) + .getResults()[0]; } } else if (hlfirBaseType.isa()) { assert(declareOp.getTypeparams().size() == 1 && diff --git a/flang/test/HLFIR/declare-codegen.fir b/flang/test/HLFIR/declare-codegen.fir --- a/flang/test/HLFIR/declare-codegen.fir +++ b/flang/test/HLFIR/declare-codegen.fir @@ -178,3 +178,25 @@ // CHECK-LABEL: func.func @array_declare_unlimited_polymorphic_boxaddr( // CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>>) { // CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "x"} : (!fir.ref>>>) -> !fir.ref>>> + + +func.func @test_optional_declare(%arg0: !fir.box>) { + %c42 = arith.constant 42 : index + %0 = fir.shift %c42 : (index) -> !fir.shift<1> + %1:2 = hlfir.declare %arg0(%0) {fortran_attrs = #fir.var_attrs, uniq_name = "x"} : (!fir.box>, !fir.shift<1>) -> (!fir.box>, !fir.box>) + return +} + +// CHECK-LABEL: func.func @test_optional_declare( +// CHECK-SAME: %[[VAL_0:.*]]: !fir.box>) { +// CHECK: %[[VAL_1:.*]] = arith.constant 42 : index +// CHECK: %[[VAL_2:.*]] = fir.shift %[[VAL_1]] : (index) -> !fir.shift<1> +// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]](%[[VAL_2]]) {fortran_attrs = #fir.var_attrs, uniq_name = "x"} : (!fir.box>, !fir.shift<1>) -> !fir.box> +// CHECK: %[[VAL_4:.*]] = fir.is_present %[[VAL_3]] : (!fir.box>) -> i1 +// CHECK: %[[VAL_5:.*]] = fir.if %[[VAL_4]] -> (!fir.box>) { +// CHECK: %[[VAL_6:.*]] = fir.rebox %[[VAL_3]](%[[VAL_2]]) : (!fir.box>, !fir.shift<1>) -> !fir.box> +// CHECK: fir.result %[[VAL_6]] : !fir.box> +// CHECK: } else { +// CHECK: %[[VAL_7:.*]] = fir.absent !fir.box> +// CHECK: fir.result %[[VAL_7]] : !fir.box> +// CHECK: }