From 205b47401ed6517cc34e473838e1d307715cc9a4 Mon Sep 17 00:00:00 2001 From: Peixin Qiao Date: Mon, 17 Oct 2022 23:27:17 +0800 Subject: [PATCH] [flang] Fix the trivial type passed as value with bind(C) In the callee side, the value cannot be used directly. For example, the dummy argument is lhs variable or the dummy argument is passed to another procedure as actual argument. Fix this by allocating one temporary storage and store the value. Then map the symbol of dummy argument to the `mlir::Value` of the temporary. Reviewed By: jeanPerier Differential Revision: https://reviews.llvm.org/D136009 --- flang/lib/Lower/Bridge.cpp | 12 +++++++ flang/lib/Lower/CallInterface.cpp | 3 ++ flang/test/Lower/call-by-value.f90 | 69 ++++++++++++++++++++++++++++++++++---- flang/test/Lower/call.f90 | 7 ++-- 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index ac29207..1ef6538 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -2738,6 +2738,14 @@ private: addSymbol(sym, res); } + void mapTrivialByValue(const Fortran::semantics::Symbol &sym, + mlir::Value val) { + mlir::Location loc = toLocation(); + mlir::Value res = builder->create(loc, val.getType()); + builder->create(loc, val, res); + addSymbol(sym, res); + } + /// Map mlir function block arguments to the corresponding Fortran dummy /// variables. When the result is passed as a hidden argument, the Fortran /// result is also mapped. The symbol map is used to hold this mapping. @@ -2767,6 +2775,10 @@ private: mapCPtrArgByValue(arg.entity->get(), arg.firArgument); return; } + if (fir::isa_trivial(argTy)) { + mapTrivialByValue(arg.entity->get(), arg.firArgument); + return; + } } addSymbol(arg.entity->get(), arg.firArgument); } else { diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp index 6758797b..71d7722 100644 --- a/flang/lib/Lower/CallInterface.cpp +++ b/flang/lib/Lower/CallInterface.cpp @@ -929,6 +929,9 @@ private: if (isBindC) { passBy = PassEntityBy::Value; prop = Property::Value; + if (type.isa()) + fir::emitFatalError( + loc, "array with VALUE attribute is not interoperable"); if (fir::isa_builtin_cptr_type(type)) { auto recTy = type.dyn_cast(); mlir::Type fieldTy = recTy.getTypeList()[0].second; diff --git a/flang/test/Lower/call-by-value.f90 b/flang/test/Lower/call-by-value.f90 index 02f399a..717da1a 100644 --- a/flang/test/Lower/call-by-value.f90 +++ b/flang/test/Lower/call-by-value.f90 @@ -1,5 +1,14 @@ ! Test for PassBy::Value ! RUN: bbc -emit-fir %s -o - | FileCheck %s + +!CHECK-LABEL: func @_QQmain() +!CHECK: %[[LOGICAL:.*]] = fir.alloca !fir.logical<4> +!CHECK: %false = arith.constant false +!CHECK: %[[VALUE:.*]] = fir.convert %false : (i1) -> !fir.logical<4> +!CHECK: fir.store %[[VALUE]] to %[[LOGICAL]] +!CHECK: %[[LOAD:.*]] = fir.load %[[LOGICAL]] +!CHECK: fir.call @omp_set_nested(%[[LOAD]]) : {{.*}} + program call_by_value interface subroutine omp_set_nested(enable) bind(c) @@ -11,10 +20,56 @@ program call_by_value do_nested = .FALSE. call omp_set_nested(do_nested) end program call_by_value -!CHECK-LABEL: func @_QQmain() -!CHECK: %[[LOGICAL:.*]] = fir.alloca !fir.logical<4> -!CHECK: %false = arith.constant false -!CHECK: %[[VALUE:.*]] = fir.convert %false : (i1) -> !fir.logical<4> -!CHECK: fir.store %[[VALUE]] to %[[LOGICAL]] -!CHECK: %[[LOAD:.*]] = fir.load %[[LOGICAL]] -!CHECK: fir.call @omp_set_nested(%[[LOAD]]) : {{.*}} + +! CHECK-LABEL: func.func @test_integer_value( +! CHECK-SAME: %[[VAL_0:.*]]: i32 {fir.bindc_name = "x"}) attributes {fir.bindc_name = "test_integer_value"} { +! CHECK: %[[VAL_1:.*]] = fir.alloca i32 +! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref +! CHECK: fir.call @_QPinternal_call(%[[VAL_1]]) : (!fir.ref) -> () +! CHECK: return +! CHECK: } + +subroutine test_integer_value(x) bind(c) + integer, value :: x + call internal_call(x) +end + +! CHECK-LABEL: func.func @test_real_value( +! CHECK-SAME: %[[VAL_0:.*]]: f32 {fir.bindc_name = "x"}) attributes {fir.bindc_name = "test_real_value"} { +! CHECK: %[[VAL_1:.*]] = fir.alloca f32 +! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref +! CHECK: fir.call @_QPinternal_call2(%[[VAL_1]]) : (!fir.ref) -> () +! CHECK: return +! CHECK: } + +subroutine test_real_value(x) bind(c) + real, value :: x + call internal_call2(x) +end + +! CHECK-LABEL: func.func @test_complex_value( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.complex<4> {fir.bindc_name = "x"}) attributes {fir.bindc_name = "test_complex_value"} { +! CHECK: %[[VAL_1:.*]] = fir.alloca !fir.complex<4> +! CHECK: fir.store %[[VAL_0]] to %[[VAL_1]] : !fir.ref> +! CHECK: fir.call @_QPinternal_call3(%[[VAL_1]]) : (!fir.ref>) -> () +! CHECK: return +! CHECK: } + +subroutine test_complex_value(x) bind(c) + complex, value :: x + call internal_call3(x) +end + +! CHECK-LABEL: func.func @test_char_value( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.boxchar<1> {fir.bindc_name = "x"}) attributes {fir.bindc_name = "test_char_value"} { +! CHECK: %[[VAL_1:.*]]:2 = fir.unboxchar %[[VAL_0]] : (!fir.boxchar<1>) -> (!fir.ref>, index) +! CHECK: %[[VAL_2:.*]] = arith.constant 1 : index +! CHECK: %[[VAL_3:.*]] = fir.emboxchar %[[VAL_1]]#0, %[[VAL_2]] : (!fir.ref>, index) -> !fir.boxchar<1> +! CHECK: fir.call @_QPinternal_call4(%[[VAL_3]]) : (!fir.boxchar<1>) -> () +! CHECK: return +! CHECK: } + +subroutine test_char_value(x) bind(c) + character(1), value :: x + call internal_call4(x) +end diff --git a/flang/test/Lower/call.f90 b/flang/test/Lower/call.f90 index de636ee..ef8d418 100644 --- a/flang/test/Lower/call.f90 +++ b/flang/test/Lower/call.f90 @@ -47,11 +47,14 @@ end function ! CHECK-LABEL: func.func @f_int_to_char( ! CHECK-SAME: %[[ARG0:.*]]: i32 {fir.bindc_name = "i"}) -> !fir.char<1> attributes {fir.bindc_name = "f_int_to_char"} { ! CHECK: %[[CHARBOX:.*]] = fir.alloca !fir.char<1> {adapt.valuebyref} +! CHECK: %[[INT_I:.*]] = fir.alloca i32 +! CHECK: fir.store %[[ARG0]] to %[[INT_I]] : !fir.ref ! CHECK: %[[RESULT:.*]] = fir.alloca !fir.char<1> {bindc_name = "f_int_to_char", uniq_name = "_QFf_int_to_charEf_int_to_char"} -! CHECK: %[[ARG0_I64:.*]] = fir.convert %[[ARG0]] : (i32) -> i64 +! CHECK: %[[ARG0_2:.*]] = fir.load %[[INT_I]] : !fir.ref +! CHECK: %[[ARG0_I64:.*]] = fir.convert %[[ARG0_2]] : (i32) -> i64 ! CHECK: %[[ARG0_I8:.*]] = fir.convert %[[ARG0_I64]] : (i64) -> i8 ! CHECK: %[[UNDEF:.*]] = fir.undefined !fir.char<1> -! CHECK: %[[CHAR_RES:.*]] = fir.insert_value %4, %3, [0 : index] : (!fir.char<1>, i8) -> !fir.char<1> +! CHECK: %[[CHAR_RES:.*]] = fir.insert_value %[[UNDEF]], %[[ARG0_I8]], [0 : index] : (!fir.char<1>, i8) -> !fir.char<1> ! CHECK: fir.store %[[CHAR_RES]] to %[[CHARBOX]] : !fir.ref> ! CHECK: %[[LOAD_CHARBOX:.*]] = fir.load %[[CHARBOX]] : !fir.ref> ! CHECK: fir.store %[[LOAD_CHARBOX]] to %[[RESULT]] : !fir.ref> -- 2.7.4