[flang-commits] [flang] b38e78c - [flang][NFC] Add module lowering tests

Valentin Clement via flang-commits flang-commits at lists.llvm.org
Wed Mar 23 09:51:19 PDT 2022


Author: Valentin Clement
Date: 2022-03-23T17:51:09+01:00
New Revision: b38e78cc445c0b6e119e8b3b7e42371caab14a05

URL: https://github.com/llvm/llvm-project/commit/b38e78cc445c0b6e119e8b3b7e42371caab14a05
DIFF: https://github.com/llvm/llvm-project/commit/b38e78cc445c0b6e119e8b3b7e42371caab14a05.diff

LOG: [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 at nvidia.com>
Co-authored-by: Eric Schweitz <eschweitz at nvidia.com>

Added: 
    flang/test/Lower/module-and-internal-proc.f90
    flang/test/Lower/module-single-point-of-def.f90
    flang/test/Lower/module_definition.f90
    flang/test/Lower/module_use.f90
    flang/test/Lower/module_use_in_same_file.f90

Modified: 
    flang/test/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/flang/test/CMakeLists.txt b/flang/test/CMakeLists.txt
index 282426ec66d1a..cd2cae200cdb9 100644
--- a/flang/test/CMakeLists.txt
+++ b/flang/test/CMakeLists.txt
@@ -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)

diff  --git a/flang/test/Lower/module-and-internal-proc.f90 b/flang/test/Lower/module-and-internal-proc.f90
new file mode 100644
index 0000000000000..1da5ce4229397
--- /dev/null
+++ b/flang/test/Lower/module-and-internal-proc.f90
@@ -0,0 +1,39 @@
+! Test that module data access are lowered correctly in the 
diff erent
+! 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

diff  --git a/flang/test/Lower/module-single-point-of-def.f90 b/flang/test/Lower/module-single-point-of-def.f90
new file mode 100644
index 0000000000000..06dba7438e9bd
--- /dev/null
+++ b/flang/test/Lower/module-single-point-of-def.f90
@@ -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: }
+

diff  --git a/flang/test/Lower/module_definition.f90 b/flang/test/Lower/module_definition.f90
new file mode 100644
index 0000000000000..f2e9badec7e98
--- /dev/null
+++ b/flang/test/Lower/module_definition.f90
@@ -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)

diff  --git a/flang/test/Lower/module_use.f90 b/flang/test/Lower/module_use.f90
new file mode 100644
index 0000000000000..06064fb755a50
--- /dev/null
+++ b/flang/test/Lower/module_use.f90
@@ -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>

diff  --git a/flang/test/Lower/module_use_in_same_file.f90 b/flang/test/Lower/module_use_in_same_file.f90
new file mode 100644
index 0000000000000..f380abde33c42
--- /dev/null
+++ b/flang/test/Lower/module_use_in_same_file.f90
@@ -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


        


More information about the flang-commits mailing list