Bug 44856 - Usage of array PARAMETERs: Literal copy vs. global variable
Summary: Usage of array PARAMETERs: Literal copy vs. global variable
Status: WAITING
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: missed-optimization, rejects-valid
Depends on:
Blocks: 40571
  Show dependency treegraph
 
Reported: 2010-07-07 12:39 UTC by Tobias Burnus
Modified: 2015-11-09 09:16 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-11-09 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Burnus 2010-07-07 12:39:21 UTC
Currently, gfortran saves scalar constants (PARAMETER) only in the .mod file while array parameters are saved as global, static variable in the .o file and additionally as expression in the .mod file.

This has all kind of funny consequences. For instance:

   print *, array_par, (array_par), shape(array_par)

Here, the first item is accessed via the global variable, for the second one a static variable is produced in place, which is then accessed, and for the third one, the front end simplifies the expression and generates an variable containing the shape.

Similarly for:
  a = array_par(1)
  a = array_par(1) + 0
In the first case, one accesses the global variable while in the second case, one generates a temporary local variable, initialized by the literal.


There are a couple of issues:

a) For intrinsic modules, it does not work (cf. PR 40571) as there is no .o file.

b) Accessing the global variable in case of taking a scalar does not make sense:
  a = parameter_array(1)
should always use (a local variable with) the literal.

c) Also in other cases, it can make sense to generate a local copy of the literal - as done in case of "(parameter_array)" - though, one probably wants to limit the inline size.


Comments? Suggestions?
Comment 1 Tobias Burnus 2010-07-07 14:47:06 UTC
My idea is:

a) For scalar expressions, generate simply always the scalar variable.

b) For array accesses, generate a const variable at the beginning of the current block (subroutine, function, BLOCK) - if the variable is smaller than "-farray-parameter-inline-limit" or if from an intrinsic module.

The trick for (b) is to collect this information in the symbol attribute (i.e. not needed if never access or when only scalars are accessed). Additionally, one needs to make sure that then in the current block the copied parameter is accessed. I think a reasonable value for the limit could be something like 10, 20.

(I am actually not sure whether the FE does mark the module global parameters variable as "restricted" or as constant. If one and if possible, one should do so.)


An example. The trick is to make sure that  (ModulePara(1))  does not simply generate, e.g., "D.1558 = modulepara[0];" which is pointless.


module m
  integer, parameter :: ModulePara(2) = [ 1, 2 ]
end module m

program test
  use m
  implicit none

  integer :: aaaa(2),i
  i=1

  aaaa = ModulePara         ! access modulepara (1)
  print *, ModulePara       ! access modulepara (2)
  print *, ModulePara(i)    ! access modulepara (3)
  print *, ModulePara(i)+i  ! access modulepara (4)
  print *, ModulePara(i)+1  ! access modulepara (5)

  aaaa(1) = (ModulePara(1)) ! use literal
  aaaa(1) = ModulePara(1)   ! use literal
  print *, ModulePara(1)    ! use literal
end program test

Dump contains the (correct!) six accesses to modulepara (5 + "extern").
Comment 2 Tobias Burnus 2010-07-07 15:23:24 UTC
Note: The tricky part for a simple fix is:
   moduleArray(i)

If one simply wraps in resolve_code the code->expr(1,2) with parentheses (e = gfc_get_parentheses (e)") this leads to "D.123 = modulearray[i]", which does not help for internal modules (cf. PR 40571) ...
Comment 3 Tobias Burnus 2010-12-08 16:28:07 UTC
Other example - from James,
cf. http://groups.google.com/group/comp.lang.fortran/browse_thread/thread/1a695db0fcfaa3e9

program kindtest
   use ISO_FORTRAN_ENV
   implicit none
   integer i
   REAL_KINDS(1) = 42
   i = sum([(kind(real(0,REAL_KINDS(i))),i=1,size(REAL_KINDS))])
   write(*,*) i
end program kindtest

which is rejected with
  Error: 'kind' argument of 'real' intrinsic at (1) must be a constant

A quick test shows that for locally defined parameter arrays, only NAG f95 is able to use it as KIND= argument to REAL. While g95, Intel, pathf95 and openf95 have the same problem as gfortran.
Comment 4 Dominique d'Humieres 2015-11-09 09:16:48 UTC
Concerning the test in comment 3, is "REAL_KINDS(i)" a constant if "i" is not? IMO it is not and it is why I have used the convoluted code

    do i=1,size(real_kinds)
      if (i == 1) then
        write(s, '(2F4.1,2F4.0)') real(-9.49999905,kind=j(1)), &
                                  real(9.49999905,kind=j(1)),  &
                                  real(9.5,kind=j(1)), real(8.5,kind=j(1))
        write(s1, '(3PE10.3,2PE10.3)') real(987350.,kind=j(1)), &
                                       real(98765.0,kind=j(1))
      else if (i == 2) then
...
      end if

in gfortran.dg/fmt_en.f90.