forked from OSchip/llvm-project
[flang][NFC] Add module lowering tests
This patch adds test for the lowering of Fortran modules. This patch is part of the upstreaming effort from fir-dev branch. Reviewed By: PeteSteinfeld Differential Revision: https://reviews.llvm.org/D122317 Co-authored-by: Jean Perier <jperier@nvidia.com> Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
This commit is contained in:
parent
5800fb41a6
commit
b38e78cc44
|
@ -46,7 +46,17 @@ set(FLANG_TEST_PARAMS
|
|||
flang_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py)
|
||||
|
||||
set(FLANG_TEST_DEPENDS
|
||||
flang-new llvm-config FileCheck count not module_files fir-opt tco bbc llvm-objdump
|
||||
flang-new
|
||||
llvm-config
|
||||
FileCheck
|
||||
count
|
||||
not
|
||||
module_files
|
||||
fir-opt
|
||||
tco
|
||||
bbc
|
||||
llvm-objdump
|
||||
split-file
|
||||
)
|
||||
|
||||
if (FLANG_INCLUDE_TESTS)
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
! Test that module data access are lowered correctly in the different
|
||||
! procedure contexts.
|
||||
! RUN: bbc -emit-fir %s -o - | FileCheck %s
|
||||
|
||||
module parent
|
||||
integer :: i
|
||||
contains
|
||||
! Test simple access to the module data
|
||||
! CHECK-LABEL: func @_QMparentPtest1
|
||||
subroutine test1()
|
||||
! CHECK: fir.address_of(@_QMparentEi) : !fir.ref<i32>
|
||||
print *, i
|
||||
end subroutine
|
||||
|
||||
! Test access to the module data inside an internal procedure where the
|
||||
! host is defined inside the module.
|
||||
subroutine test2()
|
||||
call test2internal()
|
||||
contains
|
||||
! CHECK-LABEL: func @_QMparentFtest2Ptest2internal()
|
||||
subroutine test2internal()
|
||||
! CHECK: fir.address_of(@_QMparentEi) : !fir.ref<i32>
|
||||
print *, i
|
||||
end subroutine
|
||||
end subroutine
|
||||
end module
|
||||
|
||||
! Test access to the module data inside an internal procedure where the
|
||||
! host is using the module.
|
||||
subroutine test3()
|
||||
use parent
|
||||
call test3internal()
|
||||
contains
|
||||
! CHECK-LABEL: func @_QFtest3Ptest3internal()
|
||||
subroutine test3internal()
|
||||
! CHECK: fir.address_of(@_QMparentEi) : !fir.ref<i32>
|
||||
print *, i
|
||||
end subroutine
|
||||
end subroutine
|
|
@ -0,0 +1,78 @@
|
|||
! Test that module variables with an initializer are only defined once,
|
||||
! except for compiler generated derived type descriptor that should be
|
||||
! always fully defined as linkonce_odr by the compilation units defining or
|
||||
! using them.
|
||||
! Test that this holds true in contexts with namelist members that are special
|
||||
! because the symbol on the use site are not symbols with semantics::UseDetails,
|
||||
! but directly the symbols from the module scope.
|
||||
|
||||
|
||||
! RUN: split-file %s %t
|
||||
! RUN: bbc -emit-fir %t/definition-a.f90 -o - | FileCheck %s --check-prefix=CHECK-A-DEF
|
||||
! RUN: bbc -emit-fir %t/definition-b.f90 -o - | FileCheck %s --check-prefix=CHECK-B-DEF
|
||||
! RUN: bbc -emit-fir %t/use.f90 -o - | FileCheck %s --check-prefix=CHECK-USE
|
||||
|
||||
|
||||
|
||||
!--- definition-a.f90
|
||||
|
||||
! Test definition of `atype` derived type descriptor as `linkonce_odr`
|
||||
module define_a
|
||||
type atype
|
||||
real :: x
|
||||
end type
|
||||
end module
|
||||
|
||||
! CHECK-A-DEF: fir.global linkonce_odr @_QMdefine_aE.dt.atype constant : !fir.type<{{.*}}> {
|
||||
! CHECK-A-DEF: fir.has_value
|
||||
! CHECK-A-DEF: }
|
||||
|
||||
!--- definition-b.f90
|
||||
|
||||
! Test define_b `i` is defined here.
|
||||
! Also test that the derived type descriptor of types defined here (`btype`) and used
|
||||
! here (`atype`) are fully defined here as linkonce_odr.
|
||||
module define_b
|
||||
use :: define_a
|
||||
type btype
|
||||
type(atype) :: atype
|
||||
end type
|
||||
integer :: i = 42
|
||||
namelist /some_namelist/ i
|
||||
end module
|
||||
|
||||
! CHECK-B-DEF: fir.global @_QMdefine_bEi : i32 {
|
||||
! CHECK-B-DEF: fir.has_value %{{.*}} : i32
|
||||
! CHECK-B-DEF: }
|
||||
|
||||
! CHECK-B-DEF: fir.global linkonce_odr @_QMdefine_bE.dt.btype constant : !fir.type<{{.*}}> {
|
||||
! CHECK-B-DEF: fir.has_value
|
||||
! CHECK-B-DEF: }
|
||||
|
||||
! CHECK-B-DEF: fir.global linkonce_odr @_QMdefine_aE.dt.atype constant : !fir.type<{{.*}}> {
|
||||
! CHECK-B-DEF: fir.has_value
|
||||
! CHECK-B-DEF: }
|
||||
|
||||
|
||||
|
||||
!--- use.f90
|
||||
|
||||
! Test define_b `i` is declared but not defined here and that derived types
|
||||
! descriptors are fully defined as linkonce_odr here.
|
||||
subroutine foo()
|
||||
use :: define_b
|
||||
type(btype) :: somet
|
||||
print *, somet
|
||||
write(*, some_namelist)
|
||||
end subroutine
|
||||
! CHECK-USE: fir.global @_QMdefine_bEi : i32{{$}}
|
||||
! CHECK-USE-NOT: fir.has_value %{{.*}} : i32
|
||||
|
||||
! CHECK-USE: fir.global linkonce_odr @_QMdefine_aE.dt.atype constant : !fir.type<{{.*}}> {
|
||||
! CHECK-USE: fir.has_value
|
||||
! CHECK-USE: }
|
||||
|
||||
! CHECK-USE: fir.global linkonce_odr @_QMdefine_bE.dt.btype constant : !fir.type<{{.*}}> {
|
||||
! CHECK-USE: fir.has_value
|
||||
! CHECK-USE: }
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
! RUN: bbc -emit-fir %s -o - | FileCheck %s
|
||||
|
||||
! Test lowering of module that defines data that is otherwise not used
|
||||
! in this file.
|
||||
|
||||
! Module m1 defines simple data
|
||||
module m1
|
||||
real :: x
|
||||
integer :: y(100)
|
||||
end module
|
||||
! CHECK: fir.global @_QMm1Ex : f32
|
||||
! CHECK: fir.global @_QMm1Ey : !fir.array<100xi32>
|
||||
|
||||
! Module modEq1 defines data that is equivalenced and not used in this
|
||||
! file.
|
||||
module modEq1
|
||||
! Equivalence, no initialization
|
||||
real :: x1(10), x2(10), x3(10)
|
||||
! Equivalence with initialization
|
||||
real :: y1 = 42.
|
||||
real :: y2(10)
|
||||
equivalence (x1(1), x2(5), x3(10)), (y1, y2(5))
|
||||
end module
|
||||
! CHECK-LABEL: fir.global @_QMmodeq1Ex1 : !fir.array<76xi8>
|
||||
! CHECK-LABEL: fir.global @_QMmodeq1Ey1 : !fir.array<10xi32> {
|
||||
! CHECK: %[[undef:.*]] = fir.undefined !fir.array<10xi32>
|
||||
! CHECK: %[[v1:.*]] = fir.insert_on_range %0, %c0{{.*}} from (0) to (3) : (!fir.array<10xi32>, i32) -> !fir.array<10xi32>
|
||||
! CHECK: %[[v2:.*]] = fir.insert_value %1, %c1109917696{{.*}}, [4 : index] : (!fir.array<10xi32>, i32) -> !fir.array<10xi32>
|
||||
! CHECK: %[[v3:.*]] = fir.insert_on_range %2, %c0{{.*}} from (5) to (9) : (!fir.array<10xi32>, i32) -> !fir.array<10xi32>
|
||||
! CHECK: fir.has_value %[[v3]] : !fir.array<10xi32>
|
||||
|
||||
! Module defines variable in common block without initializer
|
||||
module modCommonNoInit1
|
||||
! Module variable is in blank common
|
||||
real :: x_blank
|
||||
common // x_blank
|
||||
! Module variable is in named common, no init
|
||||
real :: x_named1
|
||||
common /named1/ x_named1
|
||||
end module
|
||||
! CHECK-LABEL: fir.global common @_QB(dense<0> : vector<4xi8>) : !fir.array<4xi8>
|
||||
! CHECK-LABEL: fir.global common @_QBnamed1(dense<0> : vector<4xi8>) : !fir.array<4xi8>
|
||||
|
||||
! Module defines variable in common block with initialization
|
||||
module modCommonInit1
|
||||
integer :: i_named2 = 42
|
||||
common /named2/ i_named2
|
||||
end module
|
||||
! CHECK-LABEL: fir.global @_QBnamed2 : tuple<i32> {
|
||||
! CHECK: %[[init:.*]] = fir.insert_value %{{.*}}, %c42{{.*}}, [0 : index] : (tuple<i32>, i32) -> tuple<i32>
|
||||
! CHECK: fir.has_value %[[init]] : tuple<i32>
|
||||
|
||||
! Test defining two module variables whose initializers depend on each others
|
||||
! addresses.
|
||||
module global_init_depending_on_each_other_address
|
||||
type a
|
||||
type(b), pointer :: pb
|
||||
end type
|
||||
type b
|
||||
type(a), pointer :: pa
|
||||
end type
|
||||
type(a), target :: xa
|
||||
type(b), target :: xb
|
||||
data xa, xb/a(xb), b(xa)/
|
||||
end module
|
||||
! CHECK-LABEL: fir.global @_QMglobal_init_depending_on_each_other_addressExb
|
||||
! CHECK: fir.address_of(@_QMglobal_init_depending_on_each_other_addressExa)
|
||||
! CHECK-LABEL: fir.global @_QMglobal_init_depending_on_each_other_addressExa
|
||||
! CHECK: fir.address_of(@_QMglobal_init_depending_on_each_other_addressExb)
|
|
@ -0,0 +1,42 @@
|
|||
! RUN: bbc -emit-fir %S/module_definition.f90
|
||||
! RUN: bbc -emit-fir %s -o - | FileCheck %s
|
||||
|
||||
! Test use of module data not defined in this file.
|
||||
! The modules are defined in module_definition.f90
|
||||
! The first runs ensures the module file is generated.
|
||||
|
||||
! CHECK-LABEL: func @_QPm1use()
|
||||
real function m1use()
|
||||
use m1
|
||||
! CHECK-DAG: fir.address_of(@_QMm1Ex) : !fir.ref<f32>
|
||||
! CHECK-DAG: fir.address_of(@_QMm1Ey) : !fir.ref<!fir.array<100xi32>>
|
||||
m1use = x + y(1)
|
||||
end function
|
||||
|
||||
! TODO: test equivalences once front-end fix in module file is pushed.
|
||||
!! CHECK-LABEL func @_QPmodeq1use()
|
||||
!real function modEq1use()
|
||||
! use modEq1
|
||||
! ! CHECK-DAG fir.address_of(@_QMmodeq1Ex1) : !fir.ref<tuple<!fir.array<36xi8>, !fir.array<40xi8>>>
|
||||
! ! CHECK-DAG fir.address_of(@_QMmodeq1Ey1) : !fir.ref<tuple<!fir.array<16xi8>, !fir.array<24xi8>>>
|
||||
! modEq1use = x2(1) + y1
|
||||
!end function
|
||||
! CHECK-DAG fir.global @_QMmodeq1Ex1 : tuple<!fir.array<36xi8>, !fir.array<40xi8>>
|
||||
! CHECK-DAG fir.global @_QMmodeq1Ey1 : tuple<!fir.array<16xi8>, !fir.array<24xi8>>
|
||||
|
||||
! CHECK-LABEL: func @_QPmodcommon1use()
|
||||
real function modCommon1Use()
|
||||
use modCommonInit1
|
||||
use modCommonNoInit1
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed2) : !fir.ref<!fir.array<4xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QB) : !fir.ref<!fir.array<4xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed1) : !fir.ref<!fir.array<4xi8>>
|
||||
modCommon1Use = x_blank + x_named1 + i_named2
|
||||
end function
|
||||
|
||||
|
||||
! CHECK-DAG: fir.global @_QMm1Ex : f32
|
||||
! CHECK-DAG: fir.global @_QMm1Ey : !fir.array<100xi32>
|
||||
! CHECK-DAG: fir.global common @_QBnamed2(dense<0> : vector<4xi8>) : !fir.array<4xi8>
|
||||
! CHECK-DAG: fir.global common @_QB(dense<0> : vector<4xi8>) : !fir.array<4xi8>
|
||||
! CHECK-DAG: fir.global common @_QBnamed1(dense<0> : vector<4xi8>) : !fir.array<4xi8>
|
|
@ -0,0 +1,122 @@
|
|||
! RUN: bbc -emit-fir %s -o - | FileCheck %s
|
||||
|
||||
! Test use of module data that is defined in this file.
|
||||
! TODO: similar tests for the functions that are using the modules, but without the
|
||||
! module being defined in this file. This require a front-end fix to be pushed first
|
||||
! so
|
||||
|
||||
! Module m2 defines simple data
|
||||
module m2
|
||||
real :: x
|
||||
integer :: y(100)
|
||||
contains
|
||||
! CHECK-LABEL: func @_QMm2Pfoo()
|
||||
real function foo()
|
||||
! CHECK-DAG: fir.address_of(@_QMm2Ex) : !fir.ref<f32>
|
||||
! CHECK-DAG: fir.address_of(@_QMm2Ey) : !fir.ref<!fir.array<100xi32>>
|
||||
foo = x + y(1)
|
||||
end function
|
||||
end module
|
||||
! CHECK-LABEL: func @_QPm2use()
|
||||
real function m2use()
|
||||
use m2
|
||||
! CHECK-DAG: fir.address_of(@_QMm2Ex) : !fir.ref<f32>
|
||||
! CHECK-DAG: fir.address_of(@_QMm2Ey) : !fir.ref<!fir.array<100xi32>>
|
||||
m2use = x + y(1)
|
||||
end function
|
||||
! Test renaming
|
||||
! CHECK-LABEL: func @_QPm2use_rename()
|
||||
real function m2use_rename()
|
||||
use m2, only: renamedx => x
|
||||
! CHECK-DAG: fir.address_of(@_QMm2Ex) : !fir.ref<f32>
|
||||
m2use_rename = renamedx
|
||||
end function
|
||||
|
||||
! Module modEq2 defines data that is equivalenced
|
||||
module modEq2
|
||||
! Equivalence, no initialization
|
||||
real :: x1(10), x2(10), x3(10)
|
||||
! Equivalence with initialization
|
||||
real :: y1 = 42.
|
||||
real :: y2(10)
|
||||
equivalence (x1(1), x2(5), x3(10)), (y1, y2(5))
|
||||
contains
|
||||
! CHECK-LABEL: func @_QMmodeq2Pfoo()
|
||||
real function foo()
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ex1) : !fir.ref<!fir.array<76xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ey1) : !fir.ref<!fir.array<10xi32>>
|
||||
foo = x2(1) + y1
|
||||
end function
|
||||
end module
|
||||
! CHECK-LABEL: func @_QPmodeq2use()
|
||||
real function modEq2use()
|
||||
use modEq2
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ex1) : !fir.ref<!fir.array<76xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ey1) : !fir.ref<!fir.array<10xi32>>
|
||||
modEq2use = x2(1) + y1
|
||||
end function
|
||||
! Test rename of used equivalence members
|
||||
! CHECK-LABEL: func @_QPmodeq2use_rename()
|
||||
real function modEq2use_rename()
|
||||
use modEq2, only: renamedx => x2, renamedy => y1
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ex1) : !fir.ref<!fir.array<76xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ey1) : !fir.ref<!fir.array<10xi32>>
|
||||
modEq2use = renamedx(1) + renamedy
|
||||
end function
|
||||
|
||||
|
||||
! Module defines variable in common block
|
||||
module modCommon2
|
||||
! Module variable is in blank common
|
||||
real :: x_blank
|
||||
common // x_blank
|
||||
! Module variable is in named common, no init
|
||||
real :: x_named1(10)
|
||||
common /named1/ x_named1
|
||||
! Module variable is in named common, with init
|
||||
integer :: i_named2 = 42
|
||||
common /named2/ i_named2
|
||||
contains
|
||||
! CHECK-LABEL: func @_QMmodcommon2Pfoo()
|
||||
real function foo()
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed2) : !fir.ref<tuple<i32>>
|
||||
! CHECK-DAG: fir.address_of(@_QB) : !fir.ref<!fir.array<4xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed1) : !fir.ref<!fir.array<40xi8>>
|
||||
foo = x_blank + x_named1(5) + i_named2
|
||||
end function
|
||||
end module
|
||||
! CHECK-LABEL: func @_QPmodcommon2use()
|
||||
real function modCommon2use()
|
||||
use modCommon2
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed2) : !fir.ref<tuple<i32>>
|
||||
! CHECK-DAG: fir.address_of(@_QB) : !fir.ref<!fir.array<4xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed1) : !fir.ref<!fir.array<40xi8>>
|
||||
modCommon2use = x_blank + x_named1(5) + i_named2
|
||||
end function
|
||||
! CHECK-LABEL: func @_QPmodcommon2use_rename()
|
||||
real function modCommon2use_rename()
|
||||
use modCommon2, only : renamed0 => x_blank, renamed1 => x_named1, renamed2 => i_named2
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed2) : !fir.ref<tuple<i32>>
|
||||
! CHECK-DAG: fir.address_of(@_QB) : !fir.ref<!fir.array<4xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QBnamed1) : !fir.ref<!fir.array<40xi8>>
|
||||
modCommon2use_rename = renamed0 + renamed1(5) + renamed2
|
||||
end function
|
||||
|
||||
|
||||
! Test that there are no conflicts between equivalence use associated and the ones
|
||||
! from the scope
|
||||
real function test_no_equiv_conflicts()
|
||||
use modEq2
|
||||
! Same equivalences as in modEq2. Test that lowering does not mixes
|
||||
! up the equivalence based on the similar offset inside the scope.
|
||||
real :: x1l(10), x2l(10), x3l(10)
|
||||
real :: y1l = 42.
|
||||
real :: y2l(10)
|
||||
save :: x1l, x2l, x3l, y1l, y2l
|
||||
equivalence (x1l(1), x2l(5), x3l(10)), (y1l, y2l(5))
|
||||
! CHECK-DAG: fir.address_of(@_QFtest_no_equiv_conflictsEx1l) : !fir.ref<!fir.array<76xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QFtest_no_equiv_conflictsEy1l) : !fir.ref<!fir.array<10xi32>>
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ex1) : !fir.ref<!fir.array<76xi8>>
|
||||
! CHECK-DAG: fir.address_of(@_QMmodeq2Ey1) : !fir.ref<!fir.array<10xi32>>
|
||||
test_no_equiv_conflicts = x2(1) + y1 + x2l(1) + y1l
|
||||
end function
|
Loading…
Reference in New Issue