Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29236 Discussions

Use of %LOC to get address of variable

Chris_H_4
Beginner
2,271 Views

I am trying to build/run some old Compaq VF in Intel VF and it is failing with the error below however I think the error may be a red-herring, Looking at the FORT.1 file it seems to be in 256 byte blocks (there is an FF every 256 bytes).  I have stepped through the code and the error is thrown by a read statement:

READ(1,REC=IREC1) ( BUFER1(J+IBUFER10), J=1,LREC )

However IBUFFER10 is -1472 and I suspect this is the actual cause of the problem, IBUFFER10 gets set by a call to a subroutine

CALL XXMADDR( BUFER1_1, BUFER1, 1, IBUFER10 )

And the subroutine is

SUBROUTINE XXMADDR( X_1, X, N, IX0 )

C Purpose
C     Find the element IX0 in the dummy array X corresponding to the
C     array X such that X(I+IX0) = X_1(I) for all I.

C Method
C     The function %LOC is used on the VAX, IG2LOC on the IBM.  These
C     find the addresses of X and X_1.
C     X_1, X must be non-character variables on the VAX in particular.

C Input
C  ?*N  X_1(*) - The array that is needed to be referenced via X.
C                 Usually this will have been passed into the previous
C                 subroutine through a dummy ENTRY point.
C  ?*N  X(*)   - Dummy array
C  I*4  N      - No. of bytes for each element of X_1 and X

C Output
C  I*4  IX0 - Location in X such that X(I+IX0) = X_1(I) for all I.

C Programmed by A.Penwill, June '91



      INTEGER  X_1(*), X(*)

      IDIFF = %LOC(X_1) - %LOC(X)

C       Test that the difference between the addresses of X_1 and X is
C       divisible by N.

      IF ( MOD( IDIFF, N ) .NE. 0 ) CALL XXERR( 'XXMADDR1', 26,
     1                                 'Alignment error in XXMADDR', 4 )

      IX0 = IDIFF / N

      RETURN
*     ======>

      END

Stepping though this the address of X is > than the address of X_1 hence the negative result. I have tried swapping the input variables to get a +ve offset but it still fails with the inconsistent record length error. Am I barking up the right tree???

The error, just for info

forrtl: severe (37): inconsistent record length, unit 1, file d:\_work\CAPS\CDMIN_Problem\fort.1
Image              PC        Routine            Line        Source
libifcoremd.dll    0F2519A2  Unknown               Unknown  Unknown
libifcoremd.dll    0F27DA8C  Unknown               Unknown  Unknown
XXSUBS.dll         0FB24A61  _XXWF00                   165  XXWF00.FOR
XXSUBS.dll         0FB3608A  _XXDM00                   228  XXDM00.FOR
XXSUBS.dll         0FB2602D  _XXDBSC                    48  XXDBSC.FOR
XXMJOB.DLL         6C221252  _XXMJOB                   119  XXMJOB.FOR
XXMAIN.EXE         00411DF7  Unknown               Unknown  Unknown
XXMAIN.EXE         004123F8  Unknown               Unknown  Unknown

 

0 Kudos
11 Replies
andrew_4619
Honored Contributor III
2,271 Views

That is horrible code. How are BUFER1_1 and BUFER1 declared? As you intimate code is probably relaying n the compiler to store these variables in a specific order and contiguous with each order. With a big more information I suspect the code can do this in a somewhat more reliable way!

0 Kudos
Chris_H_4
Beginner
2,271 Views

Thanks for the quick response Andrew. BUFFER_1 is passed in as an argument to the calling routine but they are both declared:

 LOGICAL*1  COPY, X(*), BUFER1_1(LREC_1), BUFER2_1(LREC_1),
1                       BUFER1(1),        BUFER2(1)

LREC_1 is passed in as 256

The purpose of all this is that the data is set up in some PL/I (you think the above code is bad...) and then read by some FORTRAN routines hence the need to read from the correct offset. All of this builds and runs under Compaq VF on Windows XP but we are hoping to migrate it to Win 7

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,271 Views

>>Looking at the FORT.1 file it seems to be in 256 byte blocks (there is an FF every 256 bytes). 

Please consult the IVF documentation using the index entry for "record types". The information there are for Intel implementation and not necessarily for universal file transfer. The document pages will/may indicate if the information is portable.

Note, if some other program, or an early version of IVF wrote the data file, then the record overhead bytes (if present), may differ from those in the current IVF document.

As Andrew implies, you may have an error in how you declared BUFER1_1 and BUFER1 (where they are defined). Example of possible problem. In 1991 they may have been in COMMON but now you make them allocatable. Or other nuance that affect placement.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
2,271 Views

The error you describe has nothing to do with %LOC. Rather, you've done a direct-access READ without opening the unit first for direct access with a record length.

0 Kudos
Chris_H_4
Beginner
2,271 Views

Thanks for the replies

Jim, I've had a quick look at the IVF documentation as you suggest and there was nothing obvious but I need to read it in more depth. The FORT.1 is generated as part of running the program so it is not an old version but some good suggestions to look at.

 

Steve - I believe this is the code that opens the file which looks to me like a direct access read as you suggest.

OPEN(1,ACCESS='DIRECT',FORM='BINARY',RECL=256)

 

0 Kudos
andrew_4619
Honored Contributor III
2,271 Views

You have more than one problem I think. The IBUFFER10 being negative surely isn't correct as you suggest. Is seems to me that all that all XXMADDR does is set IBUFFER10 = size(X) ( the number of declared elemens in X)

I can't work out from what is shown what the program is actually trying to do......

 

0 Kudos
Chris_H_4
Beginner
2,271 Views

I can't work out from what is shown what the program is actually trying to do......

I have to say that my understanding of this code is very limited, however your comment got me thinking and my conclusion is that I don't know either!

A FORT.1 file is written by some PL/I code (256k in size) which contains data needed by the Fortran routines and I had assumed that what XXMADDR is trying to do is calculate an offset from the start of the file to the required data and then load it. BUT it doesn't look like that can be the case since what it returns is the difference between the addresses of two arrays which bear no relationship to the position of data in the file.

What actually seems to happen is BUFFER1 is declared as LOGICAL(1) and an attempt is made to READ data from a file into BUFFER1 at some offset J+IBUFER10 which would suggest it is writing to some undeclared memory... Off for a lie-down in a darkened room...

0 Kudos
LRaim
New Contributor I
2,271 Views

Sorry to have no time to analyze your problem in detail.

However I use to calculate address differences in some core subroutines of my sw applications. 

It is quite standard to obtain a negative difference and to use this value without any problem. 

In this way you simply have access to one vector using as a base element an element of a different vector.

For integer (4) vectors N should be 4. Check record length (bytes or words ?) 

0 Kudos
Chris_H_4
Beginner
2,271 Views

Well this is embarrassing...

I thought I'd do an INQUIRE to try to see if the file was open and find the record length and of course it turns out the file wasn't open. Hacking in an OPEN statement just before the read gets me past this problem and on to the next so progress at least. Obviously I need to find where the file is being closed after the first OPEN and fix that.

Thanks for all the help.

0 Kudos
mecej4
Honored Contributor III
2,271 Views

I second Andrew's opinion regarding the code. Consider this statement of purpose:

C Purpose
C     Find the element IX0 in the dummy array X corresponding to the
C     array X such that X(I+IX0) = X_1(I) for all I.

and note that the subroutine never examines the value of a single element of X. Can this subroutine do anything but harm unless one is  going to ensure that X_1 and X are always going to be different segments of the same array? Obviously, some limits need to be placed on the range of allowed values of I; "for all I" has to be taken in the same spirit as "2 > 3 for sufficiently large values of 2".

The comments

C  ?*N  X_1(*) - The array that is needed to be referenced via X.
C                 Usually this will have been passed into the previous
C                 subroutine through a dummy ENTRY point.

indicate that the program must be compiled with /Qsave.

How big is the PL/I code, and do you have a PL/I compiler that runs on Windows?

0 Kudos
Chris_H_4
Beginner
2,271 Views

Thanks @mecej4, I'll use /Qsave. FWIW there 54 PLI files amounting to 674KB and yes we have a very old PL/I compiler for Windows

0 Kudos
Reply