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

loc intrinsic function returning negative integer on 32-bit Win7

franzw82
Beginner
1,372 Views

Greetings!

I am running the following code on a 32-bit Win7 machine with /3GB option enabled. The code is compiled with option /largeaddressaware.

integer(8) :: locarr

! allocation is successful and allocerr is zero; arr uses about 30MB of memory
allocate (arr(1:length), stat = allocerr)

! loc returns negative integer
locarr = loc(arr)

The documentation says that the result type of loc is "INTEGER(4) on IA-32 architecture; INTEGER(8) on Intel® 64 architecture". I can see that the array is allocated beyond the 2GB barrier. Therefore, I suspect that there is an integer overflow because the starting address of 'arr' does not fit into integer(4). Am I correct? I think I am missing something.

I would appreciate any help / comments. The compiler version is

Version 12.0.3.175 Build 20110309

-Franz

 

 

 

0 Kudos
9 Replies
GVautier
New Contributor II
1,372 Views

Hello

Memory addresses are unsigned values from 0 to 232-1 in a 32bits architecture

Integer values in fortran are signed. So it is normal that  the loc function could return a value (>=231) that is considered by fortran as negative. So when you assign the return value to an integer(8) variable it is always considered as negative.

 

 

 

 

 

 

0 Kudos
franzw82
Beginner
1,371 Views

@gvautier: thanks for your comments.

So cray (integer) pointers will just not work if "allocate" allocates memory above the 2 GB barrier on win32? I tried to increase the size of the cray pointers to integer(8) on win32, but got the following error:

Error #7226: An integer pointer variable has been explicitly given a data type that is not the integer type and kind for an address on the current platform.

Unfortunately, I cannot move away from using cray pointers easily and, therefore, I am looking for ways to work around this.

0 Kudos
TimP
Honored Contributor III
1,371 Views

There's no evidence here that Cray pointers won't work.  Normally, you would not be making a 64-bit signed copy of a 32-bit pointer and caring about its sign.  If you have a reason for making a 64-bit copy, you could zero extend, if that helps.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,371 Views

There is no issue with storing unsigned integers in signed integers provided that you do not perform math or relational operations that assume the numbers are properly ranged (sign bit 0). Such as:

if(CrayPointerA .LT. CrayPointerB) ...

ShortPointer = CrayPointer / 4

Instead use 

if(SHIFT(CrayPointerA, 2) .LT. SHIFT(CrayPointerB, 2)) ...

ShortPointer =SHIFT(CrayPointer, 2)

Jim Dempsey

0 Kudos
GVautier
New Contributor II
1,371 Views

Hello

I think that plus or minus operations can be made safely.

multiply might work

but divide not because the result for dividing a negative number will be a negative number

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,371 Views

Multiply would produce incorrect result if multiplicand were .gt. 1.

The if(SHIFT(CrayPointerA, 1) .LT. SHIFT(CrayPointerB, 1)) ... is the most effective way to compare two pointers and get the correct result....

I take that back... The above is true provided that the pointers are to objects that are at least 2 bytes long. For 1 byte protection

 if( IAND(INT8(CrayPointerA), Z'00000000FFFFFFFF') .LT. IAND(INT8(CrayPointerB), Z'00000000FFFFFFFF') ) then ...

Jim Dempsey

0 Kudos
GVautier
New Contributor II
1,371 Views

 

Fortunately, operations on addresses are mainly additions or subtractions.

 

If you want to store interg(4) pointers in integer(8) then

CrayPointer8=IAND(INT8(CrayPointer4), Z'00000000FFFFFFFF')

is the best way.

0 Kudos
JVanB
Valued Contributor II
1,371 Views

Life is just too short to count all those F's. The ifort extension:

CrayPointer8 = ZEXT(CrayPointer4,KIND(CrayPointer8))

would be my choice; don't know why the standards committee hasn't co-opted it. The standard syntax is:

CrayPointer8 = IAND(INT(CrayPointer4,KIND(CrayPointer8)),MASKR(BIT_SIZE(CrayPointer4),KIND(CrayPointer8)))

which is just a little verbose.

 

0 Kudos
John_Campbell
New Contributor II
1,371 Views

You can use the standard intrinsic TRANSFER to obtain the value as Integer*8. I use the following function to return memory addresses on Win32 between 2gb to 4gb.

integer*8 function JLOC (mem)
 integer*4 mem
 integer*4 ii(2)
 integer*8 jj
!
 ii(1) = loc (mem)
 ii(2) = 0
 jloc  = transfer (ii,jj)
end

The following program will report successfully on 64 bit OS systems that support /3gb using 32 bit compiler. 

 integer*8 JLOC, address
 external  JLOC
 integer*4 ii, n, stat
 integer*4, allocatable, dimension(:,:) :: aa, bb, cc
 real*4    mb
!
 address = JLOC (ii)
 write (*,*) address, loc(ii)
!
!  allocate 3 arrays of 800 mb
  n = nint ( sqrt ( (800.*1024.*1024.) / 4. ) )
 write (*,*) 'Array dimension =',n
!
  allocate ( aa(n,n), stat=stat )
  mb = real(Jloc(aa)) / 1024./1024.
  write (*,*) 'AA allocated : stat=',stat, JLOC(aa), loc(aa), mb
!
  allocate ( bb(n,n), stat=stat )
  mb = real(Jloc(bb)) / 1024./1024.
  write (*,*) 'BB allocated : stat=',stat, JLOC(bb), loc(bb), mb
!
  allocate ( cc(n,n), stat=stat )
  mb = real(Jloc(cc)) / 1024./1024.
  write (*,*) 'CC allocated : stat=',stat, JLOC(cc), loc(cc), mb
!
 end 

 

0 Kudos
Reply