Skip to content

Commit 1b74fad

Browse files
committed
[flang][hlfir] intrinsic dynamically optional arguments
This adds support for dynamically optional arguments for intrinsics which do not have their own hlfir operations. The functions for processing these arguments are mostly the same as the equivalent functions in ConvertExpr.cpp. I chose not to share implementations so that HLFIR helpers can be used here. Presumably ConvertExpr.cpp will go away one day. Depends on D154236 Differential Revision: https://reviews.llvm.org/D154237
1 parent be4518f commit 1b74fad

File tree

2 files changed

+272
-2
lines changed

2 files changed

+272
-2
lines changed

flang/lib/Lower/ConvertCall.cpp

Lines changed: 115 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,9 @@ struct CallContext {
616616
std::optional<mlir::Type> resultType;
617617
mlir::Location loc;
618618
};
619+
620+
using ExvAndCleanup =
621+
std::pair<fir::ExtendedValue, std::optional<hlfir::CleanupFunction>>;
619622
} // namespace
620623

621624
// Helper to transform a fir::ExtendedValue to an hlfir::EntityWithAttributes.
@@ -1179,6 +1182,80 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
11791182
return extendedValueToHlfirEntity(loc, builder, result, ".tmp.func_result");
11801183
}
11811184

1185+
/// Create an optional dummy argument value from \p entity that may be
1186+
/// absent. This can only be called with numerical or logical scalar \p entity.
1187+
/// If \p entity is considered absent according to 15.5.2.12 point 1., the
1188+
/// returned value is zero (or false), otherwise it is the value of \p entity.
1189+
static ExvAndCleanup genOptionalValue(fir::FirOpBuilder &builder,
1190+
mlir::Location loc, hlfir::Entity entity,
1191+
mlir::Value isPresent) {
1192+
mlir::Type eleType = entity.getFortranElementType();
1193+
assert(entity.isScalar() && fir::isa_trivial(eleType) &&
1194+
"must be a numerical or logical scalar");
1195+
return {builder
1196+
.genIfOp(loc, {eleType}, isPresent,
1197+
/*withElseRegion=*/true)
1198+
.genThen([&]() {
1199+
mlir::Value val =
1200+
hlfir::loadTrivialScalar(loc, builder, entity);
1201+
builder.create<fir::ResultOp>(loc, val);
1202+
})
1203+
.genElse([&]() {
1204+
mlir::Value zero =
1205+
fir::factory::createZeroValue(builder, loc, eleType);
1206+
builder.create<fir::ResultOp>(loc, zero);
1207+
})
1208+
.getResults()[0],
1209+
std::nullopt};
1210+
}
1211+
1212+
/// Create an optional dummy argument address from \p entity that may be
1213+
/// absent. If \p entity is considered absent according to 15.5.2.12 point 1.,
1214+
/// the returned value is a null pointer, otherwise it is the address of \p
1215+
/// entity.
1216+
static ExvAndCleanup genOptionalAddr(fir::FirOpBuilder &builder,
1217+
mlir::Location loc, hlfir::Entity entity,
1218+
mlir::Value isPresent) {
1219+
auto [exv, cleanup] = hlfir::translateToExtendedValue(loc, builder, entity);
1220+
// If it is an exv pointer/allocatable, then it cannot be absent
1221+
// because it is passed to a non-pointer/non-allocatable.
1222+
if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
1223+
return {fir::factory::genMutableBoxRead(builder, loc, *box), cleanup};
1224+
// If this is not a POINTER or ALLOCATABLE, then it is already an OPTIONAL
1225+
// address and can be passed directly.
1226+
return {exv, cleanup};
1227+
}
1228+
1229+
/// Create an optional dummy argument address from \p entity that may be
1230+
/// absent. If \p entity is considered absent according to 15.5.2.12 point 1.,
1231+
/// the returned value is an absent fir.box, otherwise it is a fir.box
1232+
/// describing \p entity.
1233+
static ExvAndCleanup genOptionalBox(fir::FirOpBuilder &builder,
1234+
mlir::Location loc, hlfir::Entity entity,
1235+
mlir::Value isPresent) {
1236+
auto [exv, cleanup] = hlfir::translateToExtendedValue(loc, builder, entity);
1237+
1238+
// Non allocatable/pointer optional box -> simply forward
1239+
if (exv.getBoxOf<fir::BoxValue>())
1240+
return {exv, cleanup};
1241+
1242+
fir::ExtendedValue newExv = exv;
1243+
// Optional allocatable/pointer -> Cannot be absent, but need to translate
1244+
// unallocated/diassociated into absent fir.box.
1245+
if (const auto *box = exv.getBoxOf<fir::MutableBoxValue>())
1246+
newExv = fir::factory::genMutableBoxRead(builder, loc, *box);
1247+
1248+
// createBox will not do create any invalid memory dereferences if exv is
1249+
// absent. The created fir.box will not be usable, but the SelectOp below
1250+
// ensures it won't be.
1251+
mlir::Value box = builder.createBox(loc, newExv);
1252+
mlir::Type boxType = box.getType();
1253+
auto absent = builder.create<fir::AbsentOp>(loc, boxType);
1254+
auto boxOrAbsent = builder.create<mlir::arith::SelectOp>(
1255+
loc, boxType, isPresent, box, absent);
1256+
return {fir::BoxValue(boxOrAbsent), cleanup};
1257+
}
1258+
11821259
/// Lower calls to intrinsic procedures with actual arguments that have been
11831260
/// pre-lowered but have not yet been prepared according to the interface.
11841261
static std::optional<hlfir::EntityWithAttributes>
@@ -1187,6 +1264,11 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
11871264
const fir::IntrinsicArgumentLoweringRules *argLowering,
11881265
CallContext &callContext) {
11891266
llvm::SmallVector<fir::ExtendedValue> operands;
1267+
llvm::SmallVector<hlfir::CleanupFunction> cleanupFns;
1268+
auto addToCleanups = [&cleanupFns](std::optional<hlfir::CleanupFunction> fn) {
1269+
if (fn)
1270+
cleanupFns.emplace_back(std::move(*fn));
1271+
};
11901272
auto &stmtCtx = callContext.stmtCtx;
11911273
auto &converter = callContext.converter;
11921274
fir::FirOpBuilder &builder = callContext.getBuilder();
@@ -1196,8 +1278,6 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
11961278
operands.emplace_back(fir::getAbsentIntrinsicArgument());
11971279
continue;
11981280
}
1199-
if (arg.value()->handleDynamicOptional())
1200-
TODO(loc, "intrinsic dynamically optional arguments");
12011281
hlfir::Entity actual = arg.value()->getActual(loc, builder);
12021282
if (!argLowering) {
12031283
// No argument lowering instruction, lower by value.
@@ -1222,6 +1302,37 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
12221302
// Ad-hoc argument lowering handling.
12231303
fir::ArgLoweringRule argRules =
12241304
fir::lowerIntrinsicArgumentAs(*argLowering, arg.index());
1305+
if (arg.value()->handleDynamicOptional()) {
1306+
mlir::Value isPresent = arg.value()->getIsPresent();
1307+
switch (argRules.lowerAs) {
1308+
case fir::LowerIntrinsicArgAs::Value: {
1309+
auto [exv, cleanup] = genOptionalValue(builder, loc, actual, isPresent);
1310+
addToCleanups(std::move(cleanup));
1311+
operands.emplace_back(exv);
1312+
continue;
1313+
}
1314+
case fir::LowerIntrinsicArgAs::Addr: {
1315+
auto [exv, cleanup] = genOptionalAddr(builder, loc, actual, isPresent);
1316+
addToCleanups(std::move(cleanup));
1317+
operands.emplace_back(exv);
1318+
continue;
1319+
}
1320+
case fir::LowerIntrinsicArgAs::Box: {
1321+
auto [exv, cleanup] = genOptionalBox(builder, loc, actual, isPresent);
1322+
addToCleanups(std::move(cleanup));
1323+
operands.emplace_back(exv);
1324+
continue;
1325+
}
1326+
case fir::LowerIntrinsicArgAs::Inquired: {
1327+
auto [exv, cleanup] =
1328+
hlfir::translateToExtendedValue(loc, builder, actual);
1329+
addToCleanups(std::move(cleanup));
1330+
operands.emplace_back(exv);
1331+
continue;
1332+
}
1333+
}
1334+
llvm_unreachable("bad switch");
1335+
}
12251336
switch (argRules.lowerAs) {
12261337
case fir::LowerIntrinsicArgAs::Value:
12271338
operands.emplace_back(
@@ -1278,6 +1389,8 @@ genIntrinsicRefCore(Fortran::lower::PreparedActualArguments &loweredActuals,
12781389
// Let the intrinsic library lower the intrinsic procedure call.
12791390
auto [resultExv, mustBeFreed] =
12801391
genIntrinsicCall(builder, loc, intrinsicName, scalarResultType, operands);
1392+
for (const hlfir::CleanupFunction &fn : cleanupFns)
1393+
fn();
12811394
if (!fir::getBase(resultExv))
12821395
return std::nullopt;
12831396
hlfir::EntityWithAttributes resultEntity = extendedValueToHlfirEntity(
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
! RUN: bbc --emit-hlfir %s -o - | FileCheck %s
2+
3+
! mask argument is dynamically optional, lowered as a box
4+
integer function test_optional_as_box(x, mask)
5+
integer :: x(:)
6+
logical, optional :: mask(:)
7+
test_optional_as_box = iall(x, mask=mask)
8+
end function
9+
! CHECK-LABEL: func.func @_QPtest_optional_as_box(
10+
! CHECK-SAME: %[[X_ARG:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "x"},
11+
! CHECK-SAME: %[[MASK_ARG:.*]]: !fir.box<!fir.array<?x!fir.logical<4>>> {fir.bindc_name = "mask", fir.optional}) -> i32 {
12+
! CHECK: %[[MASK_VAR:.*]]:2 = hlfir.declare %[[MASK_ARG]]
13+
! CHECK: %[[RET_ALLOC:.*]] = fir.alloca i32 {bindc_name = "test_optional_as_box", uniq_name = "_QFtest_optional_as_boxEtest_optional_as_box"}
14+
! CHECK: %[[RET_VAR:.*]]:2 = hlfir.declare %[[RET_ALLOC]]
15+
! CHECK: %[[X_VAR:.*]]:2 = hlfir.declare %[[X_ARG]]
16+
! CHECK: %[[C0:.*]] = arith.constant 0 : index
17+
! CHECK: %[[SRC_LINE:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<
18+
! CHECK: %[[C7:.*]] = arith.constant 7 : i32
19+
! CHECK: %[[VAL_6:.*]] = fir.convert %[[X_VAR]]#1 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
20+
! CHECK: %[[VAL_7:.*]] = fir.convert %[[SRC_LINE]] : (!fir.ref<!fir.char<{{.*}}>>) -> !fir.ref<i8>
21+
! CHECK: %[[VAL_8:.*]] = fir.convert %[[C0]] : (index) -> i32
22+
! CHECK: %[[VAL_9:.*]] = fir.convert %[[MASK_VAR]]#1 : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> !fir.box<none>
23+
! CHECK: %[[RES:.*]] = fir.call @_FortranAIAll4(%[[VAL_6]], %[[VAL_7]], %[[C7]], %[[VAL_8]], %[[VAL_9]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32, i32, !fir.box<none>) -> i32
24+
! CHECK: hlfir.assign %[[RES]] to %[[RET_VAR]]#0 : i32, !fir.ref<i32>
25+
! CHECK: %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref<i32>
26+
! CHECK: return %[[RET]] : i32
27+
! CHECK: }
28+
29+
! mask argument is dynamically optional, lowered as a box
30+
integer function test_optional_as_box2(x, mask)
31+
integer :: x(:)
32+
logical, allocatable :: mask(:)
33+
test_optional_as_box2 = iall(x, mask=mask)
34+
end function
35+
! CHECK-LABEL: func.func @_QPtest_optional_as_box2(
36+
! CHECK-SAME: %[[X_ARG:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "x"},
37+
! CHECK-SAME: %[[MASK_ARG:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>> {fir.bindc_name = "mask"}) -> i32 {
38+
! CHECK: %[[MASK_VAR:.*]]:2 = hlfir.declare %[[MASK_ARG]]
39+
! CHECK: %[[RET_ALLOC:.*]] = fir.alloca i32 {bindc_name = "test_optional_as_box2", uniq_name = "_QFtest_optional_as_box2Etest_optional_as_box2"}
40+
! CHECK: %[[RET_VAR:.*]]:2 = hlfir.declare %[[RET_ALLOC]]
41+
! CHECK: %[[X_VAR:.*]]:2 = hlfir.declare %[[X_ARG]]
42+
! CHECK: %[[MASK_LD:.*]] = fir.load %[[MASK_VAR]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
43+
! CHECK: %[[MASK_ADDR:.*]] = fir.box_addr %[[MASK_LD]] : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>) -> !fir.heap<!fir.array<?x!fir.logical<4>>>
44+
! CHECK: %[[MASK_INT:.*]] = fir.convert %[[MASK_ADDR]] : (!fir.heap<!fir.array<?x!fir.logical<4>>>) -> i64
45+
! CHECK: %[[C0_I64:.*]] = arith.constant 0 : i64
46+
! CHECK: %[[MASK_PRESENT:.*]] = arith.cmpi ne, %[[MASK_INT]], %[[C0_I64]] : i64
47+
! CHECK: %[[MASK_LD2:.*]] = fir.load %[[MASK_VAR]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>>
48+
! CHECK: %[[C0:.*]] = arith.constant 0 : index
49+
! CHECK: %[[MASK_DIMS:.*]]:3 = fir.box_dims %[[MASK_LD2]], %[[C0]] : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>, index) -> (index, index, index)
50+
! CHECK: %[[MASK_ADDR2:.*]] = fir.box_addr %[[MASK_LD2]] : (!fir.box<!fir.heap<!fir.array<?x!fir.logical<4>>>>) -> !fir.heap<!fir.array<?x!fir.logical<4>>>
51+
! CHECK: %[[MASK_SHAPE:.*]] = fir.shape_shift %[[MASK_DIMS]]#0, %[[MASK_DIMS]]#1 : (index, index) -> !fir.shapeshift<1>
52+
! CHECK: %[[MASK_REBOX:.*]] = fir.embox %[[MASK_ADDR2]](%[[MASK_SHAPE]]) : (!fir.heap<!fir.array<?x!fir.logical<4>>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<?x!fir.logical<4>>>
53+
! CHECK: %[[ABSENT:.*]] = fir.absent !fir.box<!fir.array<?x!fir.logical<4>>>
54+
! CHECK: %[[MASK_SEL:.*]] = arith.select %[[MASK_PRESENT]], %[[MASK_REBOX]], %[[ABSENT]] : !fir.box<!fir.array<?x!fir.logical<4>>>
55+
! CHECK: %[[VAL_16:.*]] = arith.constant 0 : index
56+
! CHECK: %[[VAL_17:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<{{.*}}>>
57+
! CHECK: %[[VAL_18:.*]] = arith.constant 33 : i32
58+
! CHECK: %[[VAL_19:.*]] = fir.convert %[[X_VAR]]#1 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<none>
59+
! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<!fir.char<{{.*}}>>) -> !fir.ref<i8>
60+
! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_16]] : (index) -> i32
61+
! CHECK: %[[VAL_22:.*]] = fir.convert %[[MASK_SEL]] : (!fir.box<!fir.array<?x!fir.logical<4>>>) -> !fir.box<none>
62+
! CHECK: %[[RES:.*]] = fir.call @_FortranAIAll4(%[[VAL_19]], %[[VAL_20]], %[[VAL_18]], %[[VAL_21]], %[[VAL_22]]) fastmath<contract> : (!fir.box<none>, !fir.ref<i8>, i32, i32, !fir.box<none>) -> i32
63+
! CHECK: hlfir.assign %[[RES]] to %[[RET_VAR]]#0 : i32, !fir.ref<i32>
64+
! CHECK: %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref<i32>
65+
! CHECK: return %[[RET]] : i32
66+
! CHECK: }
67+
68+
! imaginary component is dyamically optional, lowered as a value
69+
complex function test_optional_as_value(real, imaginary)
70+
real :: real
71+
real, optional :: imaginary
72+
test_optional_as_value = cmplx(real, imaginary)
73+
end function
74+
! CHECK-LABEL: func.func @_QPtest_optional_as_value(
75+
! CHECK-SAME: %[[REAL_ARG:.*]]: !fir.ref<f32> {fir.bindc_name = "real"},
76+
! CHECK-SAME: %[[IMAG_ARG:.*]]: !fir.ref<f32> {fir.bindc_name = "imaginary", fir.optional}) -> !fir.complex<4> {
77+
! CHECK: %[[IMAG_VAR:.*]]:2 = hlfir.declare %[[IMAG_ARG]]
78+
! CHECK: %[[REAL_VAR:.*]]:2 = hlfir.declare %[[REAL_ARG]]
79+
! CHECK: %[[RET_ALLOC:.*]] = fir.alloca !fir.complex<4> {bindc_name = "test_optional_as_value", uniq_name = "_QFtest_optional_as_valueEtest_optional_as_value"}
80+
! CHECK: %[[RET_VAR:.*]]:2 = hlfir.declare %[[RET_ALLOC]]
81+
! CHECK: %[[IS_PRESENT:.*]] = fir.is_present %[[IMAG_VAR]]#0 : (!fir.ref<f32>) -> i1
82+
! CHECK: %[[REAL_LD:.*]] = fir.load %[[REAL_VAR]]#0 : !fir.ref<f32>
83+
! CHECK: %[[IMAG_LD:.*]] = fir.if %[[IS_PRESENT]] -> (f32) {
84+
! CHECK: %[[IMAG_PRESENT:.*]] = fir.load %[[IMAG_VAR]]#0 : !fir.ref<f32>
85+
! CHECK: fir.result %[[IMAG_PRESENT]] : f32
86+
! CHECK: } else {
87+
! CHECK: %[[IMAG_ABSENT:.*]] = arith.constant 0.000000e+00 : f32
88+
! CHECK: fir.result %[[IMAG_ABSENT]] : f32
89+
! CHECK: }
90+
! CHECK: %[[UNDEF:.*]] = fir.undefined !fir.complex<4>
91+
! CHECK: %[[INS_REAL:.*]] = fir.insert_value %[[UNDEF]], %[[REAL_LD]], [0 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
92+
! CHECK: %[[INS_IMAG:.*]] = fir.insert_value %[[INS_REAL]], %[[IMAG_LD:.*]], [1 : index] : (!fir.complex<4>, f32) -> !fir.complex<4>
93+
! CHECK: hlfir.assign %[[INS_IMAG]] to %[[RET_VAR]]#0
94+
! CHECK: %[[RET:.*]] = fir.load %[[RET_VAR]]#1 : !fir.ref<!fir.complex<4>>
95+
! CHECK: return %[[RET]] : !fir.complex<4>
96+
! CHECK: }
97+
98+
! stat argument is dynamically optional, lowered as an address
99+
subroutine test_optional_as_addr
100+
integer, allocatable :: from(:), to(:)
101+
integer, allocatable :: stat
102+
allocate(from(20))
103+
call move_alloc(from, to, stat)
104+
deallocate(to)
105+
end subroutine
106+
! CHECK-LABEL: func.func @_QPtest_optional_as_addr() {
107+
! CHECK: %[[FROM_STACK:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "from", uniq_name = "_QFtest_optional_as_addrEfrom"}
108+
! CHECK: %[[NULLPTR:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
109+
! CHECK: %[[C0:.*]] = arith.constant 0 : index
110+
! CHECK: %[[ZERO_SHAPE:.*]] = fir.shape %[[C0]] : (index) -> !fir.shape<1>
111+
! CHECK: %[[ZERO_BOX:.*]] = fir.embox %[[NULLPTR]](%[[ZERO_SHAPE]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
112+
! CHECK: fir.store %[[ZERO_BOX]] to %[[FROM_STACK]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
113+
! CHECK: %[[FROM_VAR:.*]]:2 = hlfir.declare %[[FROM_STACK]]
114+
! CHECK: %[[STAT_STACK:.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "stat", uniq_name = "_QFtest_optional_as_addrEstat"}
115+
! CHECK: %[[STAT_NULLPTR:.*]] = fir.zero_bits !fir.heap<i32>
116+
! CHECK: %[[STAT_NULLBOX:.*]] = fir.embox %[[STAT_NULLPTR]] : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
117+
! CHECK: fir.store %[[STAT_NULLBOX]] to %[[STAT_STACK]] : !fir.ref<!fir.box<!fir.heap<i32>>>
118+
! CHECK: %[[STAT_VAR:.*]]:2 = hlfir.declare %[[STAT_STACK]]
119+
! CHECK: %[[TO_STACK:.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "to", uniq_name = "_QFtest_optional_as_addrEto"}
120+
! CHECK: %[[TO_NULLPTR:.*]] = fir.zero_bits !fir.heap<!fir.array<?xi32>>
121+
! CHECK: %[[C0_1:.*]] = arith.constant 0 : index
122+
! CHECK: %[[TO_ZERO_SHAPE:.*]] = fir.shape %[[C0_1]] : (index) -> !fir.shape<1>
123+
! CHECK: %[[TO_NULLBOX:.*]] = fir.embox %[[TO_NULLPTR]](%[[TO_ZERO_SHAPE]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
124+
! CHECK: fir.store %[[TO_NULLBOX]] to %[[TO_STACK]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
125+
! CHECK: %[[TO_VAR:.*]]:2 = hlfir.declare %[[TO_STACK]]
126+
! CHECK: %[[C20_I32:.*]] = arith.constant 20 : i32
127+
! CHECK: %[[C20:.*]] = fir.convert %[[C20_I32]] : (i32) -> index
128+
! CHECK: %[[C0_2:.*]] = arith.constant 0 : index
129+
! CHECK: %[[CMPI:.*]] = arith.cmpi sgt, %[[C20]], %[[C0_2]] : index
130+
! CHECK: %[[ALLOC_SZ:.*]] = arith.select %[[CMPI]], %[[C20]], %[[C0_2]] : index
131+
! CHECK: %[[FROM_ALLOC:.*]] = fir.allocmem !fir.array<?xi32>, %[[ALLOC_SZ]] {fir.must_be_heap = true, uniq_name = "_QFtest_optional_as_addrEfrom.alloc"}
132+
! CHECK: %[[FROM_SHAPE:.*]] = fir.shape %[[ALLOC_SZ]] : (index) -> !fir.shape<1>
133+
! CHECK: %[[FROM_BOX:.*]] = fir.embox %[[FROM_ALLOC]](%[[FROM_SHAPE]]) : (!fir.heap<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
134+
! CHECK: fir.store %[[FROM_BOX]] to %[[FROM_VAR]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
135+
! CHECK: %[[STAT_BOX:.*]] = fir.load %[[STAT_VAR]]#1 : !fir.ref<!fir.box<!fir.heap<i32>>>
136+
! CHECK: %[[STAT_ADDR:.*]] = fir.box_addr %[[STAT_BOX]] : (!fir.box<!fir.heap<i32>>) -> !fir.heap<i32>
137+
! CHECK: %[[ABSENT:.*]] = fir.absent !fir.box<none>
138+
! CHECK: %[[TRUE:.*]] = arith.constant true
139+
! CHECK: %[[VAL_25:.*]] = fir.address_of({{.*}}) : !fir.ref<!fir.char<{{.*}}>>
140+
! CHECK: %[[VAL_26:.*]] = arith.constant {{.*}} : i32
141+
! CHECK: %[[VAL_27:.*]] = fir.zero_bits !fir.ref<none>
142+
! CHECK: %[[VAL_28:.*]] = fir.convert %[[TO_VAR]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
143+
! CHECK: %[[VAL_29:.*]] = fir.convert %[[FROM_VAR]]#1 : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<none>>
144+
! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_25]] : (!fir.ref<!fir.char<{{.*}}>>) -> !fir.ref<i8>
145+
! CHECK: %[[RES:.*]] = fir.call @_FortranAMoveAlloc(%[[VAL_28]], %[[VAL_29]], %[[VAL_27]], %[[TRUE]], %[[ABSENT]], %[[VAL_30]], %[[VAL_26]]) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<!fir.box<none>>, !fir.ref<none>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
146+
! CHECK: %[[STAT_INT:.*]] = fir.convert %[[STAT_ADDR]] : (!fir.heap<i32>) -> i64
147+
! CHECK: %[[C0_3:.*]] = arith.constant 0 : i64
148+
! CHECK: %[[STAT_NOT_NULL:.*]] = arith.cmpi ne, %[[STAT_INT]], %[[C0_3]] : i64
149+
! CHECK: fir.if %[[STAT_NOT_NULL]] {
150+
! CHECK: fir.store %[[RES]] to %[[STAT_ADDR]] : !fir.heap<i32>
151+
! CHECK: }
152+
! [...]
153+
! CHECK: return
154+
! CHECK: }
155+
156+
! TODO: there seem to be no intrinsics with dynamically optional arguments lowered asInquired
157+

0 commit comments

Comments
 (0)