Skip to content

[flang] Lower VALUE derived types in BIND(C) interface #74847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,8 @@ fir::ExtendedValue Fortran::lower::genCallOpAndResult(
if (fir::isa_builtin_cptr_type(fromTy) &&
Fortran::lower::isCPtrArgByValueType(snd)) {
cast = genRecordCPtrValueArg(builder, loc, fst, fromTy);
} else if (fir::isa_derived(snd)) {
// FIXME: This seems like a serious bug elsewhere in lowering. Paper
// over the problem for now.
} else if (fir::isa_derived(snd) && !fir::isa_derived(fst.getType())) {
// TODO: remove this TODO once the old lowering is gone.
TODO(loc, "derived type argument passed by value");
} else {
cast = builder.convertWithSemantics(loc, snd, fst,
Expand Down Expand Up @@ -1188,8 +1187,18 @@ genUserCall(Fortran::lower::PreparedActualArguments &loweredActuals,
value =
hlfir::Entity{genRecordCPtrValueArg(builder, loc, value, eleTy)};
}
} else if (fir::isa_derived(value.getFortranElementType())) {
// BIND(C), VALUE derived type. The derived type value must really
// be loaded here.
auto [derived, cleanup] = hlfir::convertToValue(loc, builder, value);
mlir::Value loadedValue = fir::getBase(derived);
if (fir::isa_ref_type(loadedValue.getType()))
loadedValue = builder.create<fir::LoadOp>(loc, loadedValue);
caller.placeInput(arg, loadedValue);
if (cleanup)
(*cleanup)();
break;
}

caller.placeInput(arg, builder.createConvert(loc, argTy, value));
} break;
case PassBy::BaseAddressValueAttribute:
Expand Down
2 changes: 0 additions & 2 deletions flang/lib/Lower/ConvertVariable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2138,8 +2138,6 @@ void Fortran::lower::mapSymbolAttributes(
if (isCptrByVal || !fir::conformsWithPassByRef(argType)) {
// Dummy argument passed in register. Place the value in memory at that
// point since lowering expect symbols to be mapped to memory addresses.
if (argType.isa<fir::RecordType>())
TODO(loc, "derived type argument passed by value");
mlir::Type symType = converter.genType(sym);
addr = builder.create<fir::AllocaOp>(loc, symType);
if (isCptrByVal) {
Expand Down
37 changes: 37 additions & 0 deletions flang/test/Lower/HLFIR/bindc-value-derived.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
! Test lowering of derived types passed with VALUE attribute in BIND(C)
! interface. They are passed as fir.type<T> value. The actual C struct
! passing ABI is done in code generation according to the target.

! RUN: bbc -emit-hlfir -o - -I nw %s 2>&1 | FileCheck %s

module bindc_byval
type, bind(c) :: t
integer :: i
end type
contains
subroutine test(x) bind(c)
type(t), value :: x
call use_it(x%i)
end subroutine
! CHECK-LABEL: func.func @test(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.type<_QMbindc_byvalTt{i:i32}> {fir.bindc_name = "x"}) attributes {fir.bindc_name = "test"} {
! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.type<_QMbindc_byvalTt{i:i32}>
! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>
! 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}>>)
! CHECK: %[[VAL_3:.*]] = hlfir.designate %[[VAL_2]]#0{"i"} : (!fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>) -> !fir.ref<i32>
! CHECK: fir.call @_QPuse_it(%[[VAL_3]]) fastmath<contract> : (!fir.ref<i32>) -> ()
! CHECK: return
! CHECK: }

subroutine call_it(x)
type(t) x
call test(x)
end subroutine
! CHECK-LABEL: func.func @_QMbindc_byvalPcall_it(
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>> {fir.bindc_name = "x"}) {
! 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}>>)
! CHECK: %[[VAL_2:.*]] = fir.load %[[VAL_1]]#1 : !fir.ref<!fir.type<_QMbindc_byvalTt{i:i32}>>
! CHECK: fir.call @test(%[[VAL_2]]) fastmath<contract> : (!fir.type<_QMbindc_byvalTt{i:i32}>) -> ()
! CHECK: return
! CHECK: }
end module