Skip to content
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

[flang2] byval and sret attributes should have associated types #1420

Merged
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
67 changes: 67 additions & 0 deletions test/llvm_ir_correct/byval-sret-aarch64.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
! See https://llvm.org/LICENSE.txt for license information.
! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
!
! Check that correct opaque pointer-compatible IR is generated for
! pass-by-value arguments and struct-type return values, which typically
! appear in C binding interfaces.
!
! Note that the byval attribute is not currently generated on AArch64;
! tools/flang2/flang2exe/aarch64/ll_abi.cpp selects LL_ARG_INDIRECT_BUFFERED
! instead of LL_ARG_BYVAL.

! REQUIRES: aarch64-registered-target
! RUN: %flang -S -emit-flang-llvm %s -o %t
! RUN: FileCheck %s < %t

! CHECK: [[C_TYPE:%struct.c_type.*]] = type <{ double, double, double, double, double}>
! CHECK: [[C_FUNPTR:%struct.c_funptr.*]] = type <{ i64}>
! CHECK: define void @c_interface_byval_sub_({{.*}}, i64 %_V_fp.coerce)
! CHECK: call void @f90_c_f_procptr (ptr [[BSS:@\..+]], ptr {{.*}})
! CHECK: [[TMP:%.*]] = load i64, ptr [[BSS]]
! CHECK: call void @c_interface_byval_sub_ ({{.*}}, i64 [[TMP]])
! CHECK: [[TMP:%.*]] = load ptr, ptr %dur
! CHECK: call void @c_function (ptr sret([[C_TYPE]]) {{%.*}}, ptr [[TMP]])
! CHECK: declare void @c_function(ptr sret([[C_TYPE]]), ptr)

module c_interface
use, intrinsic :: iso_c_binding
type, bind(c) :: c_type
real(kind = c_double) :: year = 0, month = 0, day = 0, hour = 0, minute = 0
end type
interface
type(c_type) function c_function(dur) bind(c)
use iso_c_binding
import :: c_type
type(c_type), value :: dur
end function
end interface
contains
! Reproducer from https://github.com/flang-compiler/flang/issues/1419.
subroutine byval_sub(x1, x2, x3, x4, x5, x6, fp)
implicit none
integer(c_int), intent(in), value :: x1
integer(c_int), intent(in), value :: x2
integer(c_int), intent(in), value :: x3
integer(c_int), intent(in), value :: x4
integer(c_int), intent(in), value :: x5
integer(c_int), intent(in), value :: x6
type(c_funptr), intent(in), value :: fp
end subroutine
end module

module test
use c_interface
contains
function ss(dur) result(res)
implicit none
integer(c_int), parameter :: x = 42
type(c_funptr) :: fp
type(c_type), intent(in) :: dur
type(c_type) :: res
procedure(byval_sub), pointer :: proc
call c_f_procpointer(fp, proc)
call byval_sub(x, x, x, x, x, x, fp)
res = c_function(dur)
end function
end module
63 changes: 63 additions & 0 deletions test/llvm_ir_correct/byval-sret-x86.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
! See https://llvm.org/LICENSE.txt for license information.
! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
!
! Check that correct opaque pointer-compatible IR is generated for
! pass-by-value arguments and struct-type return values, which typically
! appear in C binding interfaces.

! REQUIRES: x86-registered-target
! RUN: %flang -S -emit-flang-llvm %s -o %t
! RUN: FileCheck %s < %t

! CHECK: [[C_TYPE:%struct.c_type.*]] = type <{ double, double, double, double, double}>
! CHECK: [[C_FUNPTR:%struct.c_funptr.*]] = type <{ i64}>
! CHECK: define void @c_interface_byval_sub_({{.*}}, ptr byval([[C_FUNPTR]]) %_V_fp.arg)
! CHECK: call void (ptr, ptr, ...) @f90_c_f_procptr (ptr [[BSS:@\..+]], ptr {{.*}})
! CHECK: [[TMP:%.*]] = load i64, ptr [[BSS]]
! CHECK: [[TMP2:%.*]] = inttoptr i64 [[TMP]]
! CHECK: call void @c_interface_byval_sub_ ({{.*}}, ptr byval([[C_FUNPTR]]) [[TMP2]])
! CHECK: call void @c_function (ptr sret([[C_TYPE]]) {{%.*}}, ptr byval([[C_TYPE]]) %dur)
! CHECK: declare void @c_function(ptr sret([[C_TYPE]]), ptr byval([[C_TYPE]]))

module c_interface
use, intrinsic :: iso_c_binding
type, bind(c) :: c_type
real(kind = c_double) :: year = 0, month = 0, day = 0, hour = 0, minute = 0
end type
interface
type(c_type) function c_function(dur) bind(c)
use iso_c_binding
import :: c_type
type(c_type), value :: dur
end function
end interface
contains
! Reproducer from https://github.com/flang-compiler/flang/issues/1419.
subroutine byval_sub(x1, x2, x3, x4, x5, x6, fp)
implicit none
integer(c_int), intent(in), value :: x1
integer(c_int), intent(in), value :: x2
integer(c_int), intent(in), value :: x3
integer(c_int), intent(in), value :: x4
integer(c_int), intent(in), value :: x5
integer(c_int), intent(in), value :: x6
type(c_funptr), intent(in), value :: fp
end subroutine
end module

module test
use c_interface
contains
function ss(dur) result(res)
implicit none
integer(c_int), parameter :: x = 42
type(c_funptr) :: fp
type(c_type), intent(in) :: dur
type(c_type) :: res
procedure(byval_sub), pointer :: proc
call c_f_procpointer(fp, proc)
call byval_sub(x, x, x, x, x, x, fp)
res = c_function(dur)
end function
end module
12 changes: 9 additions & 3 deletions tools/flang2/flang2exe/cgmain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ ll_check_struct_return(DTYPE dtype)
*
* %struct.S = type { [10 x i32] }
*
* define void @f(%struct.S* noalias sret %agg.result) ...
* define void @f(ptr noalias sret(%struct.S) %agg.result) ...
*
* Some structs can be returned in registers, depending on ABI-specific rules.
* For example, x86-64 can return a struct {long x, y; } struct in registers
Expand Down Expand Up @@ -7279,6 +7279,8 @@ gen_arg_operand(LL_ABI_Info *abi, unsigned abi_arg, int arg_ili)
operand = gen_llvm_expr(value_ili, arg_type);
if (arg->kind == LL_ARG_BYVAL && !missing)
operand->flags |= OPF_SRARG_TYPE;
if (arg->kind == LL_ARG_INDIRECT && !missing && (abi_arg == 0))
pawosm-arm marked this conversation as resolved.
Show resolved Hide resolved
operand->flags |= OPF_SRET_TYPE;
return operand;

arg_type = make_lltype_from_abi_arg(arg);
Expand Down Expand Up @@ -13701,7 +13703,9 @@ print_arg_attributes(LL_ABI_ArgInfo *arg)
print_token(" signext");
break;
case LL_ARG_BYVAL:
print_token(" byval");
print_token(" byval(");
print_token(arg->type->sub_types[0]->str);
print_token(")");
break;
default:
interr("Unknown argument kind", arg->kind, ERR_Fatal);
Expand Down Expand Up @@ -13760,7 +13764,9 @@ print_function_signature(int func_sptr, const char *fn_name, LL_ABI_Info *abi,
/* Hidden sret argument for struct returns. */
if (LL_ABI_HAS_SRET(abi)) {
print_token(abi->arg[0].type->str);
print_token(" sret");
print_token(" sret(");
print_token(abi->arg[0].type->sub_types[0]->str);
print_token(")");
if (print_arg_names) {
print_space(1);
print_token(SNAME(ret_info.sret_sptr));
Expand Down
30 changes: 21 additions & 9 deletions tools/flang2/flang2exe/llutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2349,10 +2349,16 @@ write_operand(OPERAND *p, const char *punc_string, int flags)
#endif
if (!(flags & FLG_OMIT_OP_TYPE))
write_type(pllt);
if (p->flags & OPF_SRET_TYPE)
print_token(" sret");
if (p->flags & OPF_SRARG_TYPE)
print_token(" byval");
if (p->flags & OPF_SRET_TYPE) {
print_token(" sret(");
print_token(p->ll_type->sub_types[0]->str);
print_token(")");
}
if (p->flags & OPF_SRARG_TYPE) {
print_token(" byval(");
print_token(p->ll_type->sub_types[0]->str);
print_token(")");
}
print_space(1);
print_token(p->string);
break;
Expand All @@ -2369,12 +2375,18 @@ write_operand(OPERAND *p, const char *punc_string, int flags)
if (!(flags & FLG_OMIT_OP_TYPE)) {
assert(p->ll_type, "write_operand(): missing type information", 0, ERR_Fatal);
write_type(p->ll_type);
print_space(1);
}
if (p->flags & OPF_SRET_TYPE)
print_token(" sret ");
if (p->flags & OPF_SRARG_TYPE)
print_token(" byval ");
if (p->flags & OPF_SRET_TYPE) {
print_token(" sret(");
print_token(p->ll_type->sub_types[0]->str);
print_token(")");
}
if (p->flags & OPF_SRARG_TYPE) {
print_token(" byval(");
print_token(p->ll_type->sub_types[0]->str);
print_token(")");
}
print_space(1);
if (p->tmps)
print_tmp_name(p->tmps);
else
Expand Down
Loading