Newsgroups: comp.sys.hp

Re: Shinn-Tzong Wu's alignment problems in HP Series 700 FORTRAN

From: vsnyder@math.jpl.nasa.gov

> The problem is that a real*8 array is associated to a real*4 array by
> way of the calling sequence.  This violates the Fortran standard, lines
> 21-24 on page 15-16 of ANSI X3.9-1978:
> 
> "The type of each actual argument must agree with the type of
> its associated dummy argument, except when the actual
> argument is a subroutine name (15.9.3.4) or an alternate
> return specifier (15.6.2.3)."

   This is certainly a good defense, but it isn't really the whole story
here, since we do try to let users do ugly things like this even though
their code may be technically illegal.

   The example calls for use of the +A flag to allow for misalignment of
4- and 8-byte data on 2-byte boundaries.  This instructs the compiler to
generate code that can tolerate misaligned data.  For example, +A will
cause real*8 numbers to be loaded 2 bytes at a time.

   The +A3 option generates better code for cases where 4-byte alignment
can be maintained.  It allows 8-byte items to be aligned on 4-byte
boundaries, so it would load a real*8 number 4 bytes at a time.  Both of
these options create big, slow code compared to the default code
generation to load a real*8 with one 8-byte load operation.

   These options cover the user's compiled code, but the FORTRAN
libraries have not been coded to allow misaligned data.  This example
dies with a bus error when a library routine attempts to access a real*8
number with the user's 4-byte-aligned pointer.

   Series 700 Compilers after 8.07 will do a better job of insulating
the IO library routines under +A and +A3.  The A options will cause the
compiler to allocate temporary aligned buffers on the user stack, and to
copy the user's data into the aligned buffer prior to calling write
routines, and out of the aligned buffer after calling read routines.
This scheme works ok for scalar variables, but can be costly in time and
memory for IO with arrays.  The case in this example, a variable length
implied do loop, is not currently implemented in the post-8.07 compiler,
because the compiler can't choose the buffer size at compile time.

From: shinn@agsm.ucla.edu (Shinn-Tzong Wu)
> We found the following bug months ago but was never be able to get it
> solved.  HP response center told us that it will be fixed on Fortran
> 8.3.

A solution to this case is being investigated, but it is not currently
committed for the next release of the compiler.

In the meantime, I'll offer three workarounds, in hopes that you can
make use of one of them to get your project moving.

1) If you really only use odd indices in your real*4 array to access
   real*8 values, and you're just surprised that the first element is
   not aligned for real*8, you can align the real*4 array in the main
   program on a real*8 boundary.  In this case, add an equivalence like:

      real*8 dummy
      equivalence (z(1), dummy)

   and compile with +A3.  Then your program will work with odd values of
   the z array.

2) If the problem is confined to your IO routines, you can declare your
   own real*8 buffer, do the copies yourself, and use this aligned
   buffer for the IO operations.

3) If you really can't modify your code to get things aligned the way
   the hardware wants them, you can plug in a signal handler to take
   care of misaligned accesses.  Just add:

	call allow_unaligned_data_access()

   to your main program and link with -lhppa.  Any alignment bus
   errors that occur will be trapped and emulated by a routine in
   this library.  The performance hit is significant, but if it only
   occurs in a few places in your program it won't be a big deal.  You
   can declare a named common block as follows:
   
      integer icnt
      /unaligned_access_count/ icnt

   Then you can print out the integer at the end of your program to see
   the extent of your trapping problem.  Estimate about 0.1 msec (.0001
   sec) per trap on a 720 to see if the trap handler is costing you a
   significant amount of time.  A version of your example is shown
   below.


Summary:

   1)  Change your code to eliminate misaligned data if possible.
   2)  Use +A3 if you need 4-byte alignment of 8-byte items, but your
      code will grow and performance will suffer.
   3)  Use +A if you need 2-byte alignment of 4- and 8-byte items, but
      your code will grow more and performance will suffer more.
   4)  Use allow_unaligned_data_access as a last resort to catch
      all other alignment errors.

   If you only occasionally use a misaligned pointer, it is probably
   better to compile without +A or +A3, and just use the
   allow_unaligned_data_access handler.  It is a stiff penalty per bus
   error, but it doesn't blow up your code and it doesn't cost you
   anything when you operate on aligned data.

   The +A and +A3 options don't cost anywhere near as much per access as
   the handler, but they cost you on every access, whether your data is
   aligned or not, and they can make your code quite a bit bigger.

I have filed an internal defect report for this problem.

Bob Montgomery, HP


c...  this is a simplified segment of program
c...  compile with +A option in 8.07 
C**** Link this program with -lhppa 
C**** Declare the trap counter
      integer icnt
      common /unaligned_access_count/ icnt

      real*4 z(100)
C**** Arm the trap handler
      call allow_unaligned_data_access()

      open(1,file='test.data')
      write(6,*) 'Give a value '
      read(5,*) ii
      call test2(z(ii))
C**** Report the number of alignment traps
      print *,'traps: ', icnt

      stop
      end
      subroutine test2(z)
      real*8 z(1)
      read(1,*) z(1)
      j1=1
      j2=1
c...  this statement will give core dump
c...  this program will be fine if ii is even
c...  program got core dump if ii is odd
      write(6,*) (z(i),i=j1,j2)
c...  this one will work
c     write(6,*) (z(i),i=1,1)
      return
      end
Newsgroups: comp.sys.hp