[flang][hlfir] support dynamically optional array arguments to intrinsics with custom handling

The previous code path created the elemental kernel by generating a
scalar intrinsic call using pre-prepared arguments using genIntrinsicRefCore,
which then generated the intrinsic call using genIntrinsicCall().

The problem with this approach was that the dynamically optional
arguments were marked as having no argLowering, which meant that they
were unconditionally passed by value without any check to see if they
were present.

It would be nice to put an if operation in the path for !argLowering,
doing something similar to genOptionalValue(). However, this can't be
done because it isn't clear what value should be used for the default.
If zero was used (like in genOptionalValue) this could effect the result
of MIN or MAX.

Instead, this patch re-uses the implementation for scalar dynamically
optional arguments (in non-elemental calls). This does the correct
thing, entirely ignoring absent optional arguments.

Depends On: D155292

Differential Revision: https://reviews.llvm.org/D155293
This commit is contained in:
Tom Eccles 2023-07-13 15:36:22 +00:00
parent 09880ef6c9
commit db7b665c5c
2 changed files with 375 additions and 36 deletions

View File

@ -1272,6 +1272,52 @@ static ExvAndCleanup genOptionalBox(fir::FirOpBuilder &builder,
return {fir::BoxValue(boxOrAbsent), cleanup};
}
/// Lower calls to intrinsic procedures with custom optional handling where the
/// actual arguments have been pre-lowered
static std::optional<hlfir::EntityWithAttributes> genCustomIntrinsicRefCore(
Fortran::lower::PreparedActualArguments &loweredActuals,
const Fortran::evaluate::SpecificIntrinsic *intrinsic,
CallContext &callContext) {
auto &converter = callContext.converter;
auto &builder = callContext.getBuilder();
const auto &loc = callContext.loc;
assert(intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling(
callContext.procRef, *intrinsic, converter));
// helper to get a particular prepared argument
auto getArgument = [&](std::size_t i, bool loadArg) -> fir::ExtendedValue {
if (!loweredActuals[i])
return fir::getAbsentIntrinsicArgument();
hlfir::Entity actual = loweredActuals[i]->getActual(loc, builder);
if (loadArg && fir::conformsWithPassByRef(actual.getType())) {
return hlfir::loadTrivialScalar(loc, builder, actual);
}
return actual;
};
// helper to get the isPresent flag for a particular prepared argument
auto isPresent = [&](std::size_t i) -> std::optional<mlir::Value> {
if (!loweredActuals[i])
return {builder.createBool(loc, false)};
if (loweredActuals[i]->handleDynamicOptional())
return {loweredActuals[i]->getIsPresent()};
return std::nullopt;
};
assert(callContext.resultType &&
"the elemental intrinsics with custom handling are all functions");
// if callContext.resultType is an array then this was originally an elemental
// call. What we are lowering here is inside the kernel of the hlfir.elemental
// so we should return the scalar type. If the return type is already a scalar
// then it should be unchanged here.
mlir::Type resTy = hlfir::getFortranElementType(*callContext.resultType);
fir::ExtendedValue result = Fortran::lower::lowerCustomIntrinsic(
builder, loc, callContext.getProcedureName(), resTy, isPresent,
getArgument, loweredActuals.size(), callContext.stmtCtx);
return {hlfir::EntityWithAttributes{extendedValueToHlfirEntity(
loc, builder, result, ".tmp.custom_intrinsic_result")}};
}
/// Lower calls to intrinsic procedures with actual arguments that have been
/// pre-lowered but have not yet been prepared according to the interface.
static std::optional<hlfir::EntityWithAttributes>
@ -1279,6 +1325,10 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
const Fortran::evaluate::SpecificIntrinsic *intrinsic,
const fir::IntrinsicArgumentLoweringRules *argLowering,
CallContext &callContext) {
auto &converter = callContext.converter;
if (intrinsic && Fortran::lower::intrinsicRequiresCustomOptionalHandling(
callContext.procRef, *intrinsic, converter))
return genCustomIntrinsicRefCore(loweredActuals, intrinsic, callContext);
llvm::SmallVector<fir::ExtendedValue> operands;
llvm::SmallVector<hlfir::CleanupFunction> cleanupFns;
auto addToCleanups = [&cleanupFns](std::optional<hlfir::CleanupFunction> fn) {
@ -1286,7 +1336,6 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
cleanupFns.emplace_back(std::move(*fn));
};
auto &stmtCtx = callContext.stmtCtx;
auto &converter = callContext.converter;
fir::FirOpBuilder &builder = callContext.getBuilder();
mlir::Location loc = callContext.loc;
for (auto arg : llvm::enumerate(loweredActuals)) {
@ -1758,16 +1807,11 @@ genCustomElementalIntrinsicRef(
auto prepareOptionalArg = [&](const Fortran::lower::SomeExpr &expr) {
hlfir::EntityWithAttributes actual = Fortran::lower::convertExprToHLFIR(
loc, converter, expr, callContext.symMap, callContext.stmtCtx);
if (expr.Rank() == 0) {
std::optional<mlir::Value> isPresent =
genIsPresentIfArgMaybeAbsent(loc, actual, expr, callContext,
/*passAsAllocatableOrPointer=*/false);
operands.emplace_back(
Fortran::lower::PreparedActualArgument{actual, isPresent});
} else {
TODO(loc, "elemental intrinsic with custom optional handling optional "
"array argument");
}
std::optional<mlir::Value> isPresent =
genIsPresentIfArgMaybeAbsent(loc, actual, expr, callContext,
/*passAsAllocatableOrPointer=*/false);
operands.emplace_back(
Fortran::lower::PreparedActualArgument{actual, isPresent});
};
// callback for non-optional arguments
@ -1855,31 +1899,7 @@ genCustomIntrinsicRef(const Fortran::evaluate::SpecificIntrinsic *intrinsic,
callContext.procRef, *intrinsic, callContext.resultType,
prepareOptionalArg, prepareOtherArg, converter);
// helper to get a particular prepared argument
auto getArgument = [&](std::size_t i, bool loadArg) -> fir::ExtendedValue {
if (!loweredActuals[i])
return fir::getAbsentIntrinsicArgument();
hlfir::Entity actual = loweredActuals[i]->getActual(loc, builder);
if (loadArg && fir::conformsWithPassByRef(actual.getType())) {
return hlfir::loadTrivialScalar(loc, builder, actual);
}
return actual;
};
// helper to get the isPresent flag for a particular prepared argument
auto isPresent = [&](std::size_t i) -> std::optional<mlir::Value> {
if (!loweredActuals[i])
return {builder.createBool(loc, false)};
if (loweredActuals[i]->handleDynamicOptional())
return {loweredActuals[i]->getIsPresent()};
return std::nullopt;
};
fir::ExtendedValue result = Fortran::lower::lowerCustomIntrinsic(
builder, loc, callContext.getProcedureName(), callContext.resultType,
isPresent, getArgument, loweredActuals.size(), stmtCtx);
return {hlfir::EntityWithAttributes{extendedValueToHlfirEntity(
loc, builder, result, ".tmp.custom_intrinsic_result")}};
return genCustomIntrinsicRefCore(loweredActuals, intrinsic, callContext);
}
/// Lower an intrinsic procedure reference.

View File

@ -128,6 +128,51 @@ end function
! CHECK: return %[[VAL_21]] : !fir.array<42xi32>
! CHECK: }
function max_dynamic_optional_array(a, b, c)
integer :: a, b(10), max_dynamic_optional_array(10)
integer, optional :: c(10)
max_dynamic_optional_array = max(a, b, c)
end function
! CHECK-LABEL: func.func @_QPmax_dynamic_optional_array(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "a"},
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "b"},
! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "c", fir.optional}) -> !fir.array<10xi32> {
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFmax_dynamic_optional_arrayEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_4:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = "_QFmax_dynamic_optional_arrayEb"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[VAL_7:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_7]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_2]](%[[VAL_8]]) {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QFmax_dynamic_optional_arrayEc"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[VAL_10:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_11:.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "max_dynamic_optional_array", uniq_name = "_QFmax_dynamic_optional_arrayEmax_dynamic_optional_array"}
! CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_12]]) {uniq_name = "_QFmax_dynamic_optional_arrayEmax_dynamic_optional_array"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_9]]#0 : (!fir.ref<!fir.array<10xi32>>) -> i1
! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_16:.*]] = hlfir.elemental %[[VAL_5]] unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> {
! CHECK: ^bb0(%[[VAL_17:.*]]: index):
! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_17]]) : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_18]] : !fir.ref<i32>
! CHECK: %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_19]] : i32
! CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_15]], %[[VAL_19]] : i32
! CHECK: %[[VAL_22:.*]] = fir.if %[[VAL_14]] -> (i32) {
! CHECK: %[[VAL_23:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_17]]) : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_23]] : !fir.ref<i32>
! CHECK: %[[VAL_25:.*]] = arith.cmpi sgt, %[[VAL_21]], %[[VAL_24]] : i32
! CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_21]], %[[VAL_24]] : i32
! CHECK: fir.result %[[VAL_26]] : i32
! CHECK: } else {
! CHECK: fir.result %[[VAL_21]] : i32
! CHECK: }
! CHECK: hlfir.yield_element %[[VAL_27:.*]] : i32
! CHECK: }
! CHECK: hlfir.assign %[[VAL_28:.*]] to %[[VAL_13]]#0 : !hlfir.expr<10xi32>, !fir.ref<!fir.array<10xi32>>
! CHECK: hlfir.destroy %[[VAL_28]] : !hlfir.expr<10xi32>
! CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_13]]#1 : !fir.ref<!fir.array<10xi32>>
! CHECK: return %[[VAL_29]] : !fir.array<10xi32>
! CHECK: }
function min_simple(a, b)
integer :: a, b, min_simple
min_simple = min(a, b)
@ -256,6 +301,51 @@ end function
! CHECK: return %[[VAL_21]] : !fir.array<42xi32>
! CHECK: }
function min_dynamic_optional_array(a, b, c)
integer :: a, b(10), min_dynamic_optional_array(10)
integer, optional :: c(10)
min_dynamic_optional_array = min(a, b, c)
end function
! CHECK-LABEL: func.func @_QPmin_dynamic_optional_array(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<i32> {fir.bindc_name = "a"},
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "b"},
! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "c", fir.optional}) -> !fir.array<10xi32> {
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFmin_dynamic_optional_arrayEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_4:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_1]](%[[VAL_5]]) {uniq_name = "_QFmin_dynamic_optional_arrayEb"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[VAL_7:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_7]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_2]](%[[VAL_8]]) {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QFmin_dynamic_optional_arrayEc"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[VAL_10:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_11:.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "min_dynamic_optional_array", uniq_name = "_QFmin_dynamic_optional_arrayEmin_dynamic_optional_array"}
! CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_10]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_11]](%[[VAL_12]]) {uniq_name = "_QFmin_dynamic_optional_arrayEmin_dynamic_optional_array"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[VAL_14:.*]] = fir.is_present %[[VAL_9]]#0 : (!fir.ref<!fir.array<10xi32>>) -> i1
! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_16:.*]] = hlfir.elemental %[[VAL_5]] unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> {
! CHECK: ^bb0(%[[VAL_17:.*]]: index):
! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_17]]) : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_18]] : !fir.ref<i32>
! CHECK: %[[VAL_20:.*]] = arith.cmpi slt, %[[VAL_15]], %[[VAL_19]] : i32
! CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_15]], %[[VAL_19]] : i32
! CHECK: %[[VAL_22:.*]] = fir.if %[[VAL_14]] -> (i32) {
! CHECK: %[[VAL_23:.*]] = hlfir.designate %[[VAL_9]]#0 (%[[VAL_17]]) : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
! CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_23]] : !fir.ref<i32>
! CHECK: %[[VAL_25:.*]] = arith.cmpi slt, %[[VAL_21]], %[[VAL_24]] : i32
! CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_21]], %[[VAL_24]] : i32
! CHECK: fir.result %[[VAL_26]] : i32
! CHECK: } else {
! CHECK: fir.result %[[VAL_21]] : i32
! CHECK: }
! CHECK: hlfir.yield_element %[[VAL_27:.*]] : i32
! CHECK: }
! CHECK: hlfir.assign %[[VAL_28:.*]] to %[[VAL_13]]#0 : !hlfir.expr<10xi32>, !fir.ref<!fir.array<10xi32>>
! CHECK: hlfir.destroy %[[VAL_28]] : !hlfir.expr<10xi32>
! CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_13]]#1 : !fir.ref<!fir.array<10xi32>>
! CHECK: return %[[VAL_29]] : !fir.array<10xi32>
! CHECK: }
function associated_simple(pointer)
integer, pointer :: pointer
logical :: associated_simple
@ -521,4 +611,233 @@ end function
! CHECK: hlfir.destroy %[[VAL_53]] : !hlfir.expr<42xi32>
! CHECK: %[[VAL_54:.*]] = fir.load %[[VAL_9]]#1 : !fir.ref<!fir.array<42xi32>>
! CHECK: return %[[VAL_54]] : !fir.array<42xi32>
! CHECK: }
function ishftc_dynamically_optional_array(i, shift, size)
integer :: ishftc_dynamically_optional_array(42), i(42), shift
integer, optional :: size
ishftc_dynamically_optional_array = ishftc(i, shift, size)
end function
! CHECK-LABEL: func.func @_QPishftc_dynamically_optional_array(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.array<42xi32>> {fir.bindc_name = "i"},
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32> {fir.bindc_name = "shift"},
! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<i32> {fir.bindc_name = "size", fir.optional}) -> !fir.array<42xi32> {
! CHECK: %[[VAL_3:.*]] = arith.constant 42 : index
! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_3]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_0]](%[[VAL_4]]) {uniq_name = "_QFishftc_dynamically_optional_arrayEi"} : (!fir.ref<!fir.array<42xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<42xi32>>, !fir.ref<!fir.array<42xi32>>)
! CHECK: %[[VAL_6:.*]] = arith.constant 42 : index
! CHECK: %[[VAL_7:.*]] = fir.alloca !fir.array<42xi32> {bindc_name = "ishftc_dynamically_optional_array", uniq_name = "_QFishftc_dynamically_optional_arrayEishftc_dynamically_optional_array"}
! CHECK: %[[VAL_8:.*]] = fir.shape %[[VAL_6]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]](%[[VAL_8]]) {uniq_name = "_QFishftc_dynamically_optional_arrayEishftc_dynamically_optional_array"} : (!fir.ref<!fir.array<42xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<42xi32>>, !fir.ref<!fir.array<42xi32>>)
! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFishftc_dynamically_optional_arrayEshift"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_2]] {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QFishftc_dynamically_optional_arrayEsize"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_12:.*]] = fir.is_present %[[VAL_11]]#0 : (!fir.ref<i32>) -> i1
! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref<i32>
! CHECK: %[[VAL_14:.*]] = hlfir.elemental %[[VAL_4]] unordered : (!fir.shape<1>) -> !hlfir.expr<42xi32> {
! CHECK: ^bb0(%[[VAL_15:.*]]: index):
! CHECK: %[[VAL_16:.*]] = hlfir.designate %[[VAL_5]]#0 (%[[VAL_15]]) : (!fir.ref<!fir.array<42xi32>>, index) -> !fir.ref<i32>
! CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_16]] : !fir.ref<i32>
! CHECK: %[[VAL_18:.*]] = fir.if %[[VAL_12]] -> (i32) {
! CHECK: %[[VAL_19:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref<i32>
! CHECK: fir.result %[[VAL_19]] : i32
! CHECK: } else {
! CHECK: %[[VAL_20:.*]] = arith.constant 32 : i32
! CHECK: fir.result %[[VAL_20]] : i32
! CHECK: }
! CHECK: %[[VAL_21:.*]] = arith.constant 32 : i32
! CHECK: %[[VAL_22:.*]] = arith.constant 0 : i32
! CHECK: %[[VAL_23:.*]] = arith.constant -1 : i32
! CHECK: %[[VAL_24:.*]] = arith.constant 31 : i32
! CHECK: %[[VAL_25:.*]] = arith.shrsi %[[VAL_13]], %[[VAL_24]] : i32
! CHECK: %[[VAL_26:.*]] = arith.xori %[[VAL_13]], %[[VAL_25]] : i32
! CHECK: %[[VAL_27:.*]] = arith.subi %[[VAL_26]], %[[VAL_25]] : i32
! CHECK: %[[VAL_28:.*]] = arith.subi %[[VAL_29:.*]], %[[VAL_27]] : i32
! CHECK: %[[VAL_30:.*]] = arith.cmpi eq, %[[VAL_13]], %[[VAL_22]] : i32
! CHECK: %[[VAL_31:.*]] = arith.cmpi eq, %[[VAL_27]], %[[VAL_29]] : i32
! CHECK: %[[VAL_32:.*]] = arith.ori %[[VAL_30]], %[[VAL_31]] : i1
! CHECK: %[[VAL_33:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_22]] : i32
! CHECK: %[[VAL_34:.*]] = arith.select %[[VAL_33]], %[[VAL_27]], %[[VAL_28]] : i32
! CHECK: %[[VAL_35:.*]] = arith.select %[[VAL_33]], %[[VAL_28]], %[[VAL_27]] : i32
! CHECK: %[[VAL_36:.*]] = arith.cmpi ne, %[[VAL_29]], %[[VAL_21]] : i32
! CHECK: %[[VAL_37:.*]] = arith.shrui %[[VAL_17]], %[[VAL_29]] : i32
! CHECK: %[[VAL_38:.*]] = arith.shli %[[VAL_37]], %[[VAL_29]] : i32
! CHECK: %[[VAL_39:.*]] = arith.select %[[VAL_36]], %[[VAL_38]], %[[VAL_22]] : i32
! CHECK: %[[VAL_40:.*]] = arith.subi %[[VAL_21]], %[[VAL_34]] : i32
! CHECK: %[[VAL_41:.*]] = arith.shrui %[[VAL_23]], %[[VAL_40]] : i32
! CHECK: %[[VAL_42:.*]] = arith.shrui %[[VAL_17]], %[[VAL_35]] : i32
! CHECK: %[[VAL_43:.*]] = arith.andi %[[VAL_42]], %[[VAL_41]] : i32
! CHECK: %[[VAL_44:.*]] = arith.subi %[[VAL_21]], %[[VAL_35]] : i32
! CHECK: %[[VAL_45:.*]] = arith.shrui %[[VAL_23]], %[[VAL_44]] : i32
! CHECK: %[[VAL_46:.*]] = arith.andi %[[VAL_17]], %[[VAL_45]] : i32
! CHECK: %[[VAL_47:.*]] = arith.shli %[[VAL_46]], %[[VAL_34]] : i32
! CHECK: %[[VAL_48:.*]] = arith.ori %[[VAL_39]], %[[VAL_43]] : i32
! CHECK: %[[VAL_49:.*]] = arith.ori %[[VAL_48]], %[[VAL_47]] : i32
! CHECK: %[[VAL_50:.*]] = arith.select %[[VAL_32]], %[[VAL_17]], %[[VAL_49]] : i32
! CHECK: hlfir.yield_element %[[VAL_50]] : i32
! CHECK: }
! CHECK: hlfir.assign %[[VAL_51:.*]] to %[[VAL_9]]#0 : !hlfir.expr<42xi32>, !fir.ref<!fir.array<42xi32>>
! CHECK: hlfir.destroy %[[VAL_51]] : !hlfir.expr<42xi32>
! CHECK: %[[VAL_52:.*]] = fir.load %[[VAL_9]]#1 : !fir.ref<!fir.array<42xi32>>
! CHECK: return %[[VAL_52]] : !fir.array<42xi32>
! CHECK: }
subroutine allocatables_test(a, b, c)
implicit none
integer, parameter :: nx = 1
integer, parameter :: ny = 2
integer, parameter :: nz = 3
integer, dimension(:,:,:), allocatable :: a, b, c
allocate(a(nx,ny,nz))
allocate(b(nx,ny,nz))
allocate(c(nx,ny,nz))
c = min(a, b, c)
end subroutine
! CHECK-LABEL: func.func @_QPallocatables_test(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>> {fir.bindc_name = "a"},
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>> {fir.bindc_name = "b"},
! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>> {fir.bindc_name = "c"}) {
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFallocatables_testEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>)
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFallocatables_testEb"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>)
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_2]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFallocatables_testEc"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>)
! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QFallocatables_testECnx) : !fir.ref<i32>
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QFallocatables_testECnx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QFallocatables_testECny) : !fir.ref<i32>
! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QFallocatables_testECny"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QFallocatables_testECnz) : !fir.ref<i32>
! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QFallocatables_testECnz"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (i32) -> index
! CHECK: %[[VAL_14:.*]] = arith.constant 2 : i32
! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (i32) -> index
! CHECK: %[[VAL_16:.*]] = arith.constant 3 : i32
! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i32) -> index
! CHECK: %[[VAL_18:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_19:.*]] = arith.cmpi sgt, %[[VAL_13]], %[[VAL_18]] : index
! CHECK: %[[VAL_20:.*]] = arith.select %[[VAL_19]], %[[VAL_13]], %[[VAL_18]] : index
! CHECK: %[[VAL_21:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_22:.*]] = arith.cmpi sgt, %[[VAL_15]], %[[VAL_21]] : index
! CHECK: %[[VAL_23:.*]] = arith.select %[[VAL_22]], %[[VAL_15]], %[[VAL_21]] : index
! CHECK: %[[VAL_24:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_25:.*]] = arith.cmpi sgt, %[[VAL_17]], %[[VAL_24]] : index
! CHECK: %[[VAL_26:.*]] = arith.select %[[VAL_25]], %[[VAL_17]], %[[VAL_24]] : index
! CHECK: %[[VAL_27:.*]] = fir.allocmem !fir.array<?x?x?xi32>, %[[VAL_20]], %[[VAL_23]], %[[VAL_26]] {fir.must_be_heap = true, uniq_name = "_QFallocatables_testEa.alloc"}
! CHECK: %[[VAL_28:.*]] = fir.shape %[[VAL_20]], %[[VAL_23]], %[[VAL_26]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[VAL_29:.*]] = fir.embox %[[VAL_27]](%[[VAL_28]]) : (!fir.heap<!fir.array<?x?x?xi32>>, !fir.shape<3>) -> !fir.box<!fir.heap<!fir.array<?x?x?xi32>>>
! CHECK: fir.store %[[VAL_29]] to %[[VAL_3]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_30:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30]] : (i32) -> index
! CHECK: %[[VAL_32:.*]] = arith.constant 2 : i32
! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_32]] : (i32) -> index
! CHECK: %[[VAL_34:.*]] = arith.constant 3 : i32
! CHECK: %[[VAL_35:.*]] = fir.convert %[[VAL_34]] : (i32) -> index
! CHECK: %[[VAL_36:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_37:.*]] = arith.cmpi sgt, %[[VAL_31]], %[[VAL_36]] : index
! CHECK: %[[VAL_38:.*]] = arith.select %[[VAL_37]], %[[VAL_31]], %[[VAL_36]] : index
! CHECK: %[[VAL_39:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_40:.*]] = arith.cmpi sgt, %[[VAL_33]], %[[VAL_39]] : index
! CHECK: %[[VAL_41:.*]] = arith.select %[[VAL_40]], %[[VAL_33]], %[[VAL_39]] : index
! CHECK: %[[VAL_42:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_43:.*]] = arith.cmpi sgt, %[[VAL_35]], %[[VAL_42]] : index
! CHECK: %[[VAL_44:.*]] = arith.select %[[VAL_43]], %[[VAL_35]], %[[VAL_42]] : index
! CHECK: %[[VAL_45:.*]] = fir.allocmem !fir.array<?x?x?xi32>, %[[VAL_38]], %[[VAL_41]], %[[VAL_44]] {fir.must_be_heap = true, uniq_name = "_QFallocatables_testEb.alloc"}
! CHECK: %[[VAL_46:.*]] = fir.shape %[[VAL_38]], %[[VAL_41]], %[[VAL_44]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[VAL_47:.*]] = fir.embox %[[VAL_45]](%[[VAL_46]]) : (!fir.heap<!fir.array<?x?x?xi32>>, !fir.shape<3>) -> !fir.box<!fir.heap<!fir.array<?x?x?xi32>>>
! CHECK: fir.store %[[VAL_47]] to %[[VAL_4]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_48:.*]] = arith.constant 1 : i32
! CHECK: %[[VAL_49:.*]] = fir.convert %[[VAL_48]] : (i32) -> index
! CHECK: %[[VAL_50:.*]] = arith.constant 2 : i32
! CHECK: %[[VAL_51:.*]] = fir.convert %[[VAL_50]] : (i32) -> index
! CHECK: %[[VAL_52:.*]] = arith.constant 3 : i32
! CHECK: %[[VAL_53:.*]] = fir.convert %[[VAL_52]] : (i32) -> index
! CHECK: %[[VAL_54:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_55:.*]] = arith.cmpi sgt, %[[VAL_49]], %[[VAL_54]] : index
! CHECK: %[[VAL_56:.*]] = arith.select %[[VAL_55]], %[[VAL_49]], %[[VAL_54]] : index
! CHECK: %[[VAL_57:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_58:.*]] = arith.cmpi sgt, %[[VAL_51]], %[[VAL_57]] : index
! CHECK: %[[VAL_59:.*]] = arith.select %[[VAL_58]], %[[VAL_51]], %[[VAL_57]] : index
! CHECK: %[[VAL_60:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_61:.*]] = arith.cmpi sgt, %[[VAL_53]], %[[VAL_60]] : index
! CHECK: %[[VAL_62:.*]] = arith.select %[[VAL_61]], %[[VAL_53]], %[[VAL_60]] : index
! CHECK: %[[VAL_63:.*]] = fir.allocmem !fir.array<?x?x?xi32>, %[[VAL_56]], %[[VAL_59]], %[[VAL_62]] {fir.must_be_heap = true, uniq_name = "_QFallocatables_testEc.alloc"}
! CHECK: %[[VAL_64:.*]] = fir.shape %[[VAL_56]], %[[VAL_59]], %[[VAL_62]] : (index, index, index) -> !fir.shape<3>
! CHECK: %[[VAL_65:.*]] = fir.embox %[[VAL_63]](%[[VAL_64]]) : (!fir.heap<!fir.array<?x?x?xi32>>, !fir.shape<3>) -> !fir.box<!fir.heap<!fir.array<?x?x?xi32>>>
! CHECK: fir.store %[[VAL_65]] to %[[VAL_5]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_66:.*]] = fir.load %[[VAL_5]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_67:.*]] = fir.box_addr %[[VAL_66]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>) -> !fir.heap<!fir.array<?x?x?xi32>>
! CHECK: %[[VAL_68:.*]] = fir.convert %[[VAL_67]] : (!fir.heap<!fir.array<?x?x?xi32>>) -> i64
! CHECK: %[[VAL_69:.*]] = arith.constant 0 : i64
! CHECK: %[[VAL_70:.*]] = arith.cmpi ne, %[[VAL_68]], %[[VAL_69]] : i64
! CHECK: %[[VAL_71:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_72:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_73:.*]]:3 = fir.box_dims %[[VAL_71]], %[[VAL_72]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_74:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_75:.*]]:3 = fir.box_dims %[[VAL_71]], %[[VAL_74]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_76:.*]] = arith.constant 2 : index
! CHECK: %[[VAL_77:.*]]:3 = fir.box_dims %[[VAL_71]], %[[VAL_76]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_78:.*]] = fir.shape %[[VAL_73]]#1, %[[VAL_75]]#1, %[[VAL_77]]#1 : (index, index, index) -> !fir.shape<3>
! CHECK: %[[VAL_79:.*]] = fir.load %[[VAL_4]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_80:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: %[[VAL_81:.*]] = hlfir.elemental %[[VAL_78]] unordered : (!fir.shape<3>) -> !hlfir.expr<?x?x?xi32> {
! CHECK: ^bb0(%[[VAL_82:.*]]: index, %[[VAL_83:.*]]: index, %[[VAL_84:.*]]: index):
! CHECK: %[[VAL_85:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_86:.*]]:3 = fir.box_dims %[[VAL_71]], %[[VAL_85]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_87:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_88:.*]]:3 = fir.box_dims %[[VAL_71]], %[[VAL_87]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_89:.*]] = arith.constant 2 : index
! CHECK: %[[VAL_90:.*]]:3 = fir.box_dims %[[VAL_71]], %[[VAL_89]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_91:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_92:.*]] = arith.subi %[[VAL_86]]#0, %[[VAL_91]] : index
! CHECK: %[[VAL_93:.*]] = arith.addi %[[VAL_82]], %[[VAL_92]] : index
! CHECK: %[[VAL_94:.*]] = arith.subi %[[VAL_88]]#0, %[[VAL_91]] : index
! CHECK: %[[VAL_95:.*]] = arith.addi %[[VAL_83]], %[[VAL_94]] : index
! CHECK: %[[VAL_96:.*]] = arith.subi %[[VAL_90]]#0, %[[VAL_91]] : index
! CHECK: %[[VAL_97:.*]] = arith.addi %[[VAL_84]], %[[VAL_96]] : index
! CHECK: %[[VAL_98:.*]] = hlfir.designate %[[VAL_71]] (%[[VAL_93]], %[[VAL_95]], %[[VAL_97]]) : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index, index, index) -> !fir.ref<i32>
! CHECK: %[[VAL_99:.*]] = fir.load %[[VAL_98]] : !fir.ref<i32>
! CHECK: %[[VAL_100:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_101:.*]]:3 = fir.box_dims %[[VAL_79]], %[[VAL_100]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_102:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_103:.*]]:3 = fir.box_dims %[[VAL_79]], %[[VAL_102]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_104:.*]] = arith.constant 2 : index
! CHECK: %[[VAL_105:.*]]:3 = fir.box_dims %[[VAL_79]], %[[VAL_104]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_106:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_107:.*]] = arith.subi %[[VAL_101]]#0, %[[VAL_106]] : index
! CHECK: %[[VAL_108:.*]] = arith.addi %[[VAL_82]], %[[VAL_107]] : index
! CHECK: %[[VAL_109:.*]] = arith.subi %[[VAL_103]]#0, %[[VAL_106]] : index
! CHECK: %[[VAL_110:.*]] = arith.addi %[[VAL_83]], %[[VAL_109]] : index
! CHECK: %[[VAL_111:.*]] = arith.subi %[[VAL_105]]#0, %[[VAL_106]] : index
! CHECK: %[[VAL_112:.*]] = arith.addi %[[VAL_84]], %[[VAL_111]] : index
! CHECK: %[[VAL_113:.*]] = hlfir.designate %[[VAL_79]] (%[[VAL_108]], %[[VAL_110]], %[[VAL_112]]) : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index, index, index) -> !fir.ref<i32>
! CHECK: %[[VAL_114:.*]] = fir.load %[[VAL_113]] : !fir.ref<i32>
! CHECK: %[[VAL_115:.*]] = arith.cmpi slt, %[[VAL_99]], %[[VAL_114]] : i32
! CHECK: %[[VAL_116:.*]] = arith.select %[[VAL_115]], %[[VAL_99]], %[[VAL_114]] : i32
! CHECK: %[[VAL_117:.*]] = fir.if %[[VAL_70]] -> (i32) {
! CHECK: %[[VAL_118:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_119:.*]]:3 = fir.box_dims %[[VAL_80]], %[[VAL_118]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_120:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_121:.*]]:3 = fir.box_dims %[[VAL_80]], %[[VAL_120]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_122:.*]] = arith.constant 2 : index
! CHECK: %[[VAL_123:.*]]:3 = fir.box_dims %[[VAL_80]], %[[VAL_122]] : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index) -> (index, index, index)
! CHECK: %[[VAL_124:.*]] = arith.constant 1 : index
! CHECK: %[[VAL_125:.*]] = arith.subi %[[VAL_119]]#0, %[[VAL_124]] : index
! CHECK: %[[VAL_126:.*]] = arith.addi %[[VAL_82]], %[[VAL_125]] : index
! CHECK: %[[VAL_127:.*]] = arith.subi %[[VAL_121]]#0, %[[VAL_124]] : index
! CHECK: %[[VAL_128:.*]] = arith.addi %[[VAL_83]], %[[VAL_127]] : index
! CHECK: %[[VAL_129:.*]] = arith.subi %[[VAL_123]]#0, %[[VAL_124]] : index
! CHECK: %[[VAL_130:.*]] = arith.addi %[[VAL_84]], %[[VAL_129]] : index
! CHECK: %[[VAL_131:.*]] = hlfir.designate %[[VAL_80]] (%[[VAL_126]], %[[VAL_128]], %[[VAL_130]]) : (!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>, index, index, index) -> !fir.ref<i32>
! CHECK: %[[VAL_132:.*]] = fir.load %[[VAL_131]] : !fir.ref<i32>
! CHECK: %[[VAL_133:.*]] = arith.cmpi slt, %[[VAL_116]], %[[VAL_132]] : i32
! CHECK: %[[VAL_134:.*]] = arith.select %[[VAL_133]], %[[VAL_116]], %[[VAL_132]] : i32
! CHECK: fir.result %[[VAL_134]] : i32
! CHECK: } else {
! CHECK: fir.result %[[VAL_116]] : i32
! CHECK: }
! CHECK: hlfir.yield_element %[[VAL_135:.*]] : i32
! CHECK: }
! CHECK: hlfir.assign %[[VAL_136:.*]] to %[[VAL_5]]#0 realloc : !hlfir.expr<?x?x?xi32>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xi32>>>>
! CHECK: hlfir.destroy %[[VAL_136]] : !hlfir.expr<?x?x?xi32>
! CHECK: return
! CHECK: }