llvm-project/flang/test/Lower/HLFIR/implicit-call-mismatch.f90
jeanPerier 44261dae5b
[flang][NFC] use hlfir.declare first result when both results are raw pointers (#132261)
Currently, the helpers to get fir::ExtendedValue out of hlfir::Entity
use hlfir.declare second result (`#1`) in most cases. This is because
this result is the same as the input and matches what FIR was getting
before lowering to HLFIR.

But this creates odd situations when both hlfir.declare are raw pointers
and either result ends-up being used in the IR depending on whether the
code was generated by a helper using fir::ExtendedValue, or via "pure
HLFIR" helpers using the first result.

This will typically prevent simple CSE and easy identification that two
operation (e.g load/store) are touching the exact same memory location
without using alias analysis or "manual detection" (looking for common
hlfir.declare defining op).

Hence, when hlfir.declare results are both raw pointers, use `#0` when
producing `fir::ExtendedValue`.
When `#0` is a fir.box, keep using `#1` because these are not the same. 
The only code change is in HLFIRTools.cpp and is pretty small, but there
is a big test fallout of `#1` to `#0`.
2025-03-21 11:41:04 +01:00

160 lines
8.2 KiB
Fortran

! Test questionable but existing abuses of implicit interfaces.
! Lowering must close the eyes and do as if it did not know
! about the function definition since semantic lets these
! programs through with a warning.
! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
subroutine takes_char(c)
character(8) :: c
end subroutine
subroutine pass_real_to_char(r)
real(8) :: r
call takes_char(r)
end subroutine
! CHECK-LABEL: func.func @_QPpass_real_to_char(
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Er
! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QPtakes_char) : (!fir.boxchar<1>) -> ()
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : ((!fir.boxchar<1>) -> ()) -> ((!fir.ref<f64>) -> ())
! CHECK: fir.call %[[VAL_3]](%[[VAL_1]]#0) {{.*}}: (!fir.ref<f64>) -> ()
subroutine pass_char_proc_to_char()
character(8), external :: char_proc
call takes_char(char_proc)
end subroutine
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QPchar_proc) : (!fir.ref<!fir.char<1,8>>, index) -> !fir.boxchar<1>
! CHECK: %[[VAL_1:.*]] = arith.constant 8 : i64
! CHECK: %[[VAL_2:.*]] = fir.emboxproc %[[VAL_0]] : ((!fir.ref<!fir.char<1,8>>, index) -> !fir.boxchar<1>) -> !fir.boxproc<() -> ()>
! CHECK: %[[VAL_3:.*]] = fir.undefined tuple<!fir.boxproc<() -> ()>, i64>
! CHECK: %[[VAL_4:.*]] = fir.insert_value %[[VAL_3]], %[[VAL_2]], [0 : index] : (tuple<!fir.boxproc<() -> ()>, i64>, !fir.boxproc<() -> ()>) -> tuple<!fir.boxproc<() -> ()>, i64>
! CHECK: %[[VAL_5:.*]] = fir.insert_value %[[VAL_4]], %[[VAL_1]], [1 : index] : (tuple<!fir.boxproc<() -> ()>, i64>, i64) -> tuple<!fir.boxproc<() -> ()>, i64>
! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QPtakes_char) : (!fir.boxchar<1>) -> ()
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : ((!fir.boxchar<1>) -> ()) -> ((tuple<!fir.boxproc<() -> ()>, i64>) -> ())
! CHECK: fir.call %[[VAL_7]](%[[VAL_5]]) {{.*}}: (tuple<!fir.boxproc<() -> ()>, i64>) -> ()
subroutine pass_kind2_char_to_char(c)
character(4, kind=2) :: c
call takes_char(c)
end subroutine
! CHECK-LABEL: func.func @_QPpass_kind2_char_to_char(
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare {{.*}}Ec
! CHECK: %[[VAL_3:.*]] = fir.emboxchar %[[VAL_2]]#0, %{{.*}} : (!fir.ref<!fir.char<2,4>>, index) -> !fir.boxchar<2>
! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QPtakes_char) : (!fir.boxchar<1>) -> ()
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : ((!fir.boxchar<1>) -> ()) -> ((!fir.boxchar<2>) -> ())
! CHECK: fir.call %[[VAL_5]](%[[VAL_3]]) {{.*}}: (!fir.boxchar<2>) -> ()
subroutine takes_real(r)
real(8) :: r
end subroutine
subroutine pass_int_to_real(i)
integer(8) :: i
call takes_real(i)
end subroutine
! CHECK-LABEL: func.func @_QPpass_int_to_real(
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ei
! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#0 : (!fir.ref<i64>) -> !fir.ref<f64>
! CHECK: fir.call @_QPtakes_real(%[[VAL_2]]) {{.*}}: (!fir.ref<f64>) -> ()
subroutine pass_char_to_real(c)
character(8) :: c
call takes_real(c)
end subroutine
! CHECK-LABEL: func.func @_QPpass_char_to_real(
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare {{.*}}Ec
! CHECK: %[[VAL_3:.*]] = fir.emboxchar %[[VAL_2]]#0, %{{.*}} : (!fir.ref<!fir.char<1,8>>, index) -> !fir.boxchar<1>
! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QPtakes_real) : (!fir.ref<f64>) -> ()
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : ((!fir.ref<f64>) -> ()) -> ((!fir.boxchar<1>) -> ())
! CHECK: fir.call %[[VAL_5]](%[[VAL_3]]) {{.*}}: (!fir.boxchar<1>) -> ()
subroutine pass_proc_to_real()
real(8), external :: proc
call takes_real(proc)
end subroutine
! CHECK-LABEL: func.func @_QPpass_proc_to_real() {
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QPproc) : () -> f64
! CHECK: %[[VAL_1:.*]] = fir.emboxproc %[[VAL_0]] : (() -> f64) -> !fir.boxproc<() -> ()>
! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QPtakes_real) : (!fir.ref<f64>) -> ()
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : ((!fir.ref<f64>) -> ()) -> ((!fir.boxproc<() -> ()>) -> ())
! CHECK: fir.call %[[VAL_3]](%[[VAL_1]]) {{.*}}: (!fir.boxproc<() -> ()>) -> ()
subroutine pass_complex_to_real(cmplx)
complex(4) :: cmplx
call takes_real(cmplx)
end subroutine
! CHECK-LABEL: func.func @_QPpass_complex_to_real(
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Ecmplx
! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]]#0 : (!fir.ref<complex<f32>>) -> !fir.ref<f64>
! CHECK: fir.call @_QPtakes_real(%[[VAL_2]]) {{.*}}: (!fir.ref<f64>) -> ()
subroutine takes_char_proc(c)
character(8), external :: c
end subroutine
subroutine pass_proc_to_char_proc()
external :: proc
call takes_char_proc(proc)
end subroutine
! CHECK-LABEL: func.func @_QPpass_proc_to_char_proc() {
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QPproc) : () -> f64
! CHECK: %[[VAL_1:.*]] = fir.emboxproc %[[VAL_0]] : (() -> f64) -> !fir.boxproc<() -> ()>
! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QPtakes_char_proc) : (tuple<!fir.boxproc<() -> ()>, i64>) -> ()
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : ((tuple<!fir.boxproc<() -> ()>, i64>) -> ()) -> ((!fir.boxproc<() -> ()>) -> ())
! CHECK: fir.call %[[VAL_3]](%[[VAL_1]]) {{.*}}: (!fir.boxproc<() -> ()>) -> ()
subroutine pass_char_to_char_proc(c)
character(8) :: c
call takes_char_proc(c)
end subroutine
! CHECK-LABEL: func.func @_QPpass_char_to_char_proc(
! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare {{.*}}Ec
! CHECK: %[[VAL_3:.*]] = fir.emboxchar %[[VAL_2]]#0, %{{.*}} : (!fir.ref<!fir.char<1,8>>, index) -> !fir.boxchar<1>
! CHECK: %[[VAL_4:.*]] = fir.address_of(@_QPtakes_char_proc) : (tuple<!fir.boxproc<() -> ()>, i64>) -> ()
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : ((tuple<!fir.boxproc<() -> ()>, i64>) -> ()) -> ((!fir.boxchar<1>) -> ())
! CHECK: fir.call %[[VAL_5]](%[[VAL_3]]) {{.*}}: (!fir.boxchar<1>) -> ()
subroutine takes_proc(proc)
real(8), external :: proc
end subroutine
subroutine pass_char_proc_to_proc()
character(8), external :: char_proc
call takes_proc(char_proc)
end subroutine
! CHECK-LABEL: func.func @_QPpass_char_proc_to_proc() {
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QPchar_proc) : (!fir.ref<!fir.char<1,8>>, index) -> !fir.boxchar<1>
! CHECK: %[[VAL_1:.*]] = arith.constant 8 : i64
! CHECK: %[[VAL_2:.*]] = fir.emboxproc %[[VAL_0]] : ((!fir.ref<!fir.char<1,8>>, index) -> !fir.boxchar<1>) -> !fir.boxproc<() -> ()>
! CHECK: %[[VAL_3:.*]] = fir.undefined tuple<!fir.boxproc<() -> ()>, i64>
! CHECK: %[[VAL_4:.*]] = fir.insert_value %[[VAL_3]], %[[VAL_2]], [0 : index] : (tuple<!fir.boxproc<() -> ()>, i64>, !fir.boxproc<() -> ()>) -> tuple<!fir.boxproc<() -> ()>, i64>
! CHECK: %[[VAL_5:.*]] = fir.insert_value %[[VAL_4]], %[[VAL_1]], [1 : index] : (tuple<!fir.boxproc<() -> ()>, i64>, i64) -> tuple<!fir.boxproc<() -> ()>, i64>
! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QPtakes_proc) : (!fir.boxproc<() -> ()>) -> ()
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : ((!fir.boxproc<() -> ()>) -> ()) -> ((tuple<!fir.boxproc<() -> ()>, i64>) -> ())
! CHECK: fir.call %[[VAL_7]](%[[VAL_5]]) {{.*}}: (tuple<!fir.boxproc<() -> ()>, i64>) -> ()
subroutine pass_real_to_proc(r)
real(8) :: r
call takes_proc(r)
end subroutine
! CHECK-LABEL: func.func @_QPpass_real_to_proc(
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare {{.*}}Er
! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QPtakes_proc) : (!fir.boxproc<() -> ()>) -> ()
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : ((!fir.boxproc<() -> ()>) -> ()) -> ((!fir.ref<f64>) -> ())
! CHECK: fir.call %[[VAL_3]](%[[VAL_1]]#0) {{.*}}: (!fir.ref<f64>) -> ()
subroutine pass_too_many_args()
call takes_real(I, Kown, what, I, am, doing)
end subroutine
! CHECK-LABEL: func.func @_QPpass_too_many_args() {
! CHECK: %[[VAL_10:.*]] = fir.address_of(@_QPtakes_real) : (!fir.ref<f64>) -> ()
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : ((!fir.ref<f64>) -> ()) -> ((!fir.ref<i32>, !fir.ref<i32>, !fir.ref<f32>, !fir.ref<i32>, !fir.ref<f32>, !fir.ref<f32>) -> ())
! CHECK: fir.call %[[VAL_11]](%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<i32>, !fir.ref<i32>, !fir.ref<f32>, !fir.ref<i32>, !fir.ref<f32>, !fir.ref<f32>) -> ()
subroutine pass_too_few_args()
call takes_real()
end subroutine
! CHECK-LABEL: func.func @_QPpass_too_few_args() {
! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QPtakes_real) : (!fir.ref<f64>) -> ()
! CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : ((!fir.ref<f64>) -> ()) -> (() -> ())
! CHECK: fir.call %[[VAL_1]]() {{.*}}: () -> ()