Skip to content

Commit dfb7d56

Browse files
authored
[flang] Lower VALUE derived types in BIND(C) interface (#74847)
VALUE derived type are passed by reference outside of BIND(C) interface. The ABI is much simpler and it is possible for these arguments to have the OPTIONAL attribute. In the BIND(C) context, these arguments must follow the C ABI for struct, which may lead the data to be passed in register. OPTIONAL is also forbidden for those arguments, so it is safe to directly use the fir.type<T> type for the func.func argument. Codegen is in charge of later applying the C passing ABI according to the target (#74829).
1 parent 0c2b6a0 commit dfb7d56

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

flang/lib/Lower/ConvertCall.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,9 +360,8 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
360360
if (fir::isa_builtin_cptr_type(fromTy) &&
361361
Fortran::lower::isCPtrArgByValueType(snd)) {
362362
cast = genRecordCPtrValueArg(builder, loc, fst, fromTy);
363-
} else if (fir::isa_derived(snd)) {
364-
// FIXME: This seems like a serious bug elsewhere in lowering. Paper
365-
// over the problem for now.
363+
} else if (fir::isa_derived(snd) && !fir::isa_derived(fst.getType())) {
364+
// TODO: remove this TODO once the old lowering is gone.
366365
TODO(loc, "derived type argument passed by value");
367366
} else {
368367
cast = builder.convertWithSemantics(loc, snd, fst,
@@ -1188,8 +1187,18 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
11881187
value =
11891188
hlfir::Entity{genRecordCPtrValueArg(builder, loc, value, eleTy)};
11901189
}
1190+
} else if (fir::isa_derived(value.getFortranElementType())) {
1191+
// BIND(C), VALUE derived type. The derived type value must really
1192+
// be loaded here.
1193+
auto [derived, cleanup] = hlfir::convertToValue(loc, builder, value);
1194+
mlir::Value loadedValue = fir::getBase(derived);
1195+
if (fir::isa_ref_type(loadedValue.getType()))
1196+
loadedValue = builder.create<fir::LoadOp>(loc, loadedValue);
1197+
caller.placeInput(arg, loadedValue);
1198+
if (cleanup)
1199+
(*cleanup)();
1200+
break;
11911201
}
1192-
11931202
caller.placeInput(arg, builder.createConvert(loc, argTy, value));
11941203
} break;
11951204
case PassBy::BaseAddressValueAttribute:

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,8 +2138,6 @@ void Fortran::lower::mapSymbolAttributes(
21382138
if (isCptrByVal || !fir::conformsWithPassByRef(argType)) {
21392139
// Dummy argument passed in register. Place the value in memory at that
21402140
// point since lowering expect symbols to be mapped to memory addresses.
2141-
if (argType.isa<fir::RecordType>())
2142-
TODO(loc, "derived type argument passed by value");
21432141
mlir::Type symType = converter.genType(sym);
21442142
addr = builder.create<fir::AllocaOp>(loc, symType);
21452143
if (isCptrByVal) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
! Test lowering of derived types passed with VALUE attribute in BIND(C)
2+
! interface. They are passed as fir.type<T> value. The actual C struct
3+
! passing ABI is done in code generation according to the target.
4+
5+
! RUN: bbc -emit-hlfir -o - -I nw %s 2>&1 | FileCheck %s
6+
7+
module bindc_byval
8+
type, bind(c) :: t
9+
integer :: i
10+
end type
11+
contains
12+
subroutine test(x) bind(c)
13+
type(t), value :: x
14+
call use_it(x%i)
15+
end subroutine
16+
! CHECK-LABEL: func.func @test(
17+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.type<_QMbindc_byvalTt{i:i32}> {fir.bindc_name = "x"}) attributes {fir.bindc_name = "test"} {
18+
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMbindc_byvalTt{i:i32}>
19+
! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>
20+
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[VAL_1]] {fortran_attrs = #fir.var_attrs<value>, uniq_name = "_QMbindc_byvalFtestEx"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>) -> (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>, !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>)
21+
! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]#0{"i"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>) -> !fir.ref<i32>
22+
! CHECK: fir.call @_QPuse_it(%[[VAL_3]]) fastmath<contract> : (!fir.ref<i32>) -> ()
23+
! CHECK: return
24+
! CHECK: }
25+
26+
subroutine call_it(x)
27+
type(t) x
28+
call test(x)
29+
end subroutine
30+
! CHECK-LABEL: func.func @_QMbindc_byvalPcall_it(
31+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>> {fir.bindc_name = "x"}) {
32+
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QMbindc_byvalFcall_itEx"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>) -> (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>, !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>)
33+
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>
34+
! CHECK: fir.call @test(%[[VAL_2]]) fastmath<contract> : (!fir.type<_QMbindc_byvalTt{i:i32}>) -> ()
35+
! CHECK: return
36+
! CHECK: }
37+
end module

0 commit comments

Comments
 (0)