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

Issue with MOVE_ALLOC

OP1
New Contributor II
4,510 Views

I tried to post about this yesterday but my post was marked as spam, yikes. So here is try #2.

In the example below I don't understand why the call to MOVE_ALLOC returns a negative ERROR value (-858993460 to be precise) when it seems that the call was successful. This is with ifort classic 2021.5.0 (Windows platform, x64).

It also seems that MESSAGE contains some non-printable character somewhere - but this may be a different problem.

Any thoughts on this?

 

MODULE M
IMPLICIT NONE
TYPE T
    INTEGER, ALLOCATABLE :: A(:)
    CONTAINS
        PROCEDURE P
END TYPE T
CONTAINS
SUBROUTINE P(SELF, A)
CLASS(T), INTENT(INOUT) :: SELF
INTEGER, ALLOCATABLE, INTENT(INOUT) :: A(:)
INTEGER :: ERROR
CHARACTER(LEN = 132) :: MESSAGE
CALL MOVE_ALLOC(A, SELF%A, STAT = ERROR, ERRMSG = MESSAGE)
WRITE(*, *) ERROR, (TRIM(MESSAGE) == ''), TRIM(MESSAGE), ALLOCATED(SELF%A), SIZE(SELF%A)
END SUBROUTINE P
END MODULE M

PROGRAM P
USE M
IMPLICIT NONE
TYPE(T) :: VAR
INTEGER, ALLOCATABLE :: A(:)
ALLOCATE(A(1))
CALL VAR%P(A)
END PROGRAM P

 

 

0 Kudos
1 Solution
Ron_Green
Moderator
4,191 Views

I opened a case on this.  But in testing I found that the error is already fixed in the IFX and IFORT coming out in the next update release at the end of this month.  I tested on Linux but found the same issue with the current 2021.5 compiler like you reported;

more move_allocTest.f90
program movalloctest
    implicit none
    integer, allocatable :: x(:)
    integer, allocatable :: b(:)
    integer :: istat
    character (len=132) :: message = 'The bean bag and the cornhole'
    x = [ 42 , 43 ]
    istat = -99
    call move_alloc( x, b, stat=istat, errmsg=message )
    print *, "istat = ", istat
    if (istat /= 0) print *, "message = ", message
end program

ifort -V -o move_allocTest move_allocTest.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

 Intel(R) Fortran 2021.5.0-1068
GNU ld version 2.30-108.el8_5.1
[rwgreen@orcsle162 q05399693]$ ./move_allocTest 
 istat =          -99
 message = 
 The bean bag and the cornhole                                                  
                              

Then with the new IFX or IFORT

 

ifort -V -o move_allocTest move_allocTest.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.6.0 Build 20220227_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

 Intel(R) Fortran 2021.6.0-1299
GNU ld version 2.30-108.el8_5.1

./move_allocTest 
 istat =            0

 

I don't show the IFX results but they are the same since ifort and ifx use the same FRTL.

So wait for the update coming out end of this month.

View solution in original post

0 Kudos
34 Replies
FortranFan
Honored Contributor II
3,202 Views

@OP1 ,

I suggest you always show the exact steps you followed to investigate Intel Fortran behavior, say the along the lines of

 

C:\temp>ifort /standard-semantics p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 0 F
 └ƒ
                                                       T 1

C:\temp>

 

A couple of comments then:

  1. On Windows with the compiler options shown, the problem you report with "MOVE_ALLOC returns a negative ERROR value (-858993460 to be precise) " is not noticed,
  2. Your code does not conform to the standard.  The optional argument corresponding to `ERRMSG` is "INTENT(INOUT)" and the standard states, "If the ERRMSG argument is present and an error condition occurs, it is assigned an explanatory message. If no error condition occurs, the definition status and value of ERRMSG are unchanged."  Thus the code should not reference `MESSAGE` unless it is known for sure it is defined. 

In your case, it is entirely unclear what is going on.

0 Kudos
OP1
New Contributor II
3,175 Views

Thanks @FortranFan for taking the time to try to reproduce this.

First, yes you are correct, the ERRMSG specifier is INTENT(INOUT), so any existing garbage in the uninitialized MESSAGE variable would stay untouched in the absence of error. Good catch!

Now, for the issue itself: I just noticed that the bug only occurs when the program is build in Debug (x64) mode, not in Release (x64) mode - using Visual Studio 2019. All other compiler flags are the default ones. Adding /standard-semantics does not modify this behavior.

 

Here it the output from the build command:

Deleting intermediate files and output files for project 'MOVE_ALLOC_BUG', configuration 'Debug|x64'.
Compiling with Intel® Fortran Compiler Classic 2021.5.0 [Intel(R) 64]...
ifort /nologo /debug:full /Od /warn:interfaces /module:"x64\Debug\\" /object:"x64\Debug\\" /Fd"x64\Debug\vc160.pdb" /traceback /check:bounds /check:stack /libs:dll /threads /dbglibs /c /Qlocation,link,"C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\bin\HostX64\x64" /Qm64 "C:\TEMP\MOVE_ALLOC_BUG\MAIN.F90"
Linking...
Link /OUT:"x64\Debug\MOVE_ALLOC_BUG.exe" /INCREMENTAL:NO /NOLOGO /MANIFEST /MANIFESTFILE:"x64\Debug\MOVE_ALLOC_BUG.exe.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"C:\TEMP\MOVE_ALLOC_BUG\x64\Debug\MOVE_ALLOC_BUG.pdb" /SUBSYSTEM:CONSOLE /IMPLIB:"C:\TEMP\MOVE_ALLOC_BUG\x64\Debug\MOVE_ALLOC_BUG.lib" -qm64 "x64\Debug\MAIN.obj"
Embedding manifest...
mt.exe /nologo /outputresource:"C:\TEMP\MOVE_ALLOC_BUG\x64\Debug\MOVE_ALLOC_BUG.exe;#1" /manifest "x64\Debug\MOVE_ALLOC_BUG.exe.intermediate.manifest"

MOVE_ALLOC_BUG - 0 error(s), 0 warning(s)

 

0 Kudos
FortranFan
Honored Contributor II
3,169 Views

@OP1 ,

I suggest you submit a support request at Intel OSC if you can.  Otherwise Intel support staff will likely pick it up from this thread.

 

Hopefully the Intel team can also pay attention to the case below which is a variant of yours and what they indicate is the optional STAT= argument in MOVE_ALLOC is not treated as INTENT(OUT) as stipulated in the standard but rather as INTENT(INOUT).

 

   integer, allocatable :: x
   x = 0 ; call sub( x )
contains
   subroutine sub( a )
      integer, allocatable, intent(inout) :: a
      integer, allocatable :: b
      integer :: astat
      call move_alloc( a, b, stat=istat )
      print *, "istat = ", istat
   end subroutine
end
C:\temp>ifort /standard-semantics /Od p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 istat =  32758

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,141 Views

FF, excusing the implicit typing (astat vs istat), this may indicate that the STAT= variable is left untouched when there is no error. Which in turn would imply that that dummy is treated as INOUT... had the move_alloc been written in Fortran. Be it written in C/C++. there is no requirement for references to be updated. FWIW, back in about 2008, there was an issue with allocate, where the STAT= variable would not be updated when no error occurs. The fix then was to define the value to 0 prior to allocation.

Could you pre-zero out istat and or set to 666 to see what happens with move_alloc?

Jim Dempsey 

0 Kudos
FortranFan
Honored Contributor II
3,103 Views

Jim, apologies for the typo.

 

Here's the updated case with the error status variable undefined in caller:

C:\temp>type p.f90
   integer, allocatable :: x
   x = 0 ; call sub( x )
contains
   subroutine sub( a )
      integer, allocatable, intent(inout) :: a
      integer, allocatable :: b
      integer :: astat
      call move_alloc( a, b, stat=astat )
      print *, "astat = ", astat
   end subroutine
end

C:\temp>ifort /standard-semantics /Od p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 astat =  32758

C:\temp>

 

And here's the case where the status variable is defined:

C:\temp>type p.f90
   integer, allocatable :: x
   x = 0 ; call sub( x )
contains
   subroutine sub( a )
      integer, allocatable, intent(inout) :: a
      integer, allocatable :: b
      integer :: astat
      astat = -999  !<-- predefine the status code to an arbitrary value
      call move_alloc( a, b, stat=astat )
      print *, "astat = ", astat
   end subroutine
end

C:\temp>ifort /standard-semantics /Od p.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 14.30.30706.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:p.exe
-subsystem:console
p.obj

C:\temp>p.exe
 astat =  -999

C:\temp>

As I mentioned above, this points to optional STAT= dummy argument being treated as INTENT(INOUT) rather than INTENT(OUT) and left untouched when no error condition is present.  Thus the interest for the Intel Support team to take a look at this case also.

0 Kudos
jimdempseyatthecove
Honored Contributor III
3,009 Views

>As I mentioned above, this points to optional STAT= dummy argument being treated as INTENT(INOUT) rather than INTENT(OUT) and left untouched when no error condition is present.

And as stated before, there is no analog to INTENT in C/C++ under the suspicion that move_alloc is written in C as opposed to written in Fortran (with the mis-stated INTENT). The reason I suspect it is written in C/C++ is that it must be mucking around with the array descriptor (i.e. swapping the contents of the array descriptors).

Jim Dempsey 

0 Kudos
andrew_4619
Honored Contributor II
3,134 Views

 

 

!  movalloctest.f90
program movalloctest
    implicit none
    integer, allocatable :: x(:)
    integer, allocatable :: b(:)
    integer :: istat
    x = [ 42 , 43 ]
    istat = -99
    call move_alloc( x, b, stat=istat )
    print *, "istat = ", istat
end program movalloctest

 

 

I did wonder if is was because they were scalars but istat is untouched with array or scalar. At line 10 b = [42,43], x is undefined and istat = -99.  Looks buggy to me. I am now checking the implication in my production codes.....

 

Update: I checked all my codes an it seems I have never used stat= with move_alloc so I can't say if it is a new or old problem....

0 Kudos
JohnNichols
Valued Contributor III
3,088 Views

Who dreamed up move_alloc -- It seems to be an example of Syntactic Sugar as noted by Perlis and please let us not start a discussion on Perlis, we have done this before. 

 

0 Kudos
OP1
New Contributor II
2,856 Views

Your comment is narrow-sighted. There are other posters in this thread who made valuable contributions regarding a valid use of MOVE_ALLOC, and I can offer another scenario:

Instead of:

INTEGER, ALLOCATABLE :: A(:, :), B(:, :)
! <snip>
A = B
DEALLOCATE(B)

which implies that the memory footprint of the operation is twice the size of B (which is a concern for programs manipulating very large data), you can simply use:

CALL MOVE_ALLOC(A, B)

Not only you save on memory requirements; but you also completely bypass the need to copy the data - which can be desirable for large, complex, deeply nested derived types for instance.

0 Kudos
JNichols
New Contributor I
2,590 Views

Your comment is narrow-sighted.

My comment was a question again we tend be more polite on this forum than your statements. 

0 Kudos
FortranFan
Honored Contributor II
3,103 Views

@andrew_4619 ,

 

Re: "I have never used stat= with move_alloc so I can't say if it is a new or old problem,"

  • you may know it is a Fortran 2018 feature that introduces STAT= and ERRMSG= options with MOVE_ALLOC,
  • Whereas MOVE_ALLOC was first introduced in Fortran 2003. 

Intel folks can best comment on this, but this is likely a new problem in your context based on a presumption your existing codes would not have made use of this since it is a "new" feature. 

0 Kudos
andrew_4619
Honored Contributor II
3,051 Views

@FortranFan Yes that would be the case I didn't know stat now exists for move_alloc and usage cases are not that common for me now since we got allocate LHS on assignment. It explains why I have never used it as I am an really keen on status and error flags wherever possible, I hate software that crashes without grace.... 

 @JohnNichols , move_alloc is very very useful when resizing arrays and much faster with large arrays

a)1] Allocate a new larger array, 2] copy old array data to new array. 3] deallocate old array 4] allocate old array to new bigger size 5] copy new array data back into new size old array. 5] deallocate new array.

b) 1] Allocate a new larger array, 2] copy old array data to new array. 3] move_alloc

 

Thus the copy twice gets eliminated and the temp array is automatically deallocated. It is a very useful trick when you don't know how big to make an array you can make it much too big and then downsize it at the end or increase it in sensible chunks steps when it gets full. Try it....

0 Kudos
Ron_Green
Moderator
4,192 Views

I opened a case on this.  But in testing I found that the error is already fixed in the IFX and IFORT coming out in the next update release at the end of this month.  I tested on Linux but found the same issue with the current 2021.5 compiler like you reported;

more move_allocTest.f90
program movalloctest
    implicit none
    integer, allocatable :: x(:)
    integer, allocatable :: b(:)
    integer :: istat
    character (len=132) :: message = 'The bean bag and the cornhole'
    x = [ 42 , 43 ]
    istat = -99
    call move_alloc( x, b, stat=istat, errmsg=message )
    print *, "istat = ", istat
    if (istat /= 0) print *, "message = ", message
end program

ifort -V -o move_allocTest move_allocTest.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.5.0 Build 20211109_000000
Copyright (C) 1985-2021 Intel Corporation.  All rights reserved.

 Intel(R) Fortran 2021.5.0-1068
GNU ld version 2.30-108.el8_5.1
[rwgreen@orcsle162 q05399693]$ ./move_allocTest 
 istat =          -99
 message = 
 The bean bag and the cornhole                                                  
                              

Then with the new IFX or IFORT

 

ifort -V -o move_allocTest move_allocTest.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.6.0 Build 20220227_000000
Copyright (C) 1985-2022 Intel Corporation.  All rights reserved.

 Intel(R) Fortran 2021.6.0-1299
GNU ld version 2.30-108.el8_5.1

./move_allocTest 
 istat =            0

 

I don't show the IFX results but they are the same since ifort and ifx use the same FRTL.

So wait for the update coming out end of this month.

0 Kudos
Steve_Lionel
Honored Contributor III
2,878 Views

MOVE_ALLOC is not "syntactic sugar". Its motivation was the common desire to extend the size of an allocatable array with data already in it. Without MOVE_ALLOC, you'd have to allocate an array to hold the existing data, copy the existing data, deallocate the old array, allocate a new one to the new size and then copy the data a second time. With MOVE_ALLOC, you just allocate the new, larger array, copy the existing data once, and then MOVE_ALLOC it back to the original variable.

0 Kudos
JNichols
New Contributor I
2,811 Views

From Wikipedia:

A construct in a language is syntactic sugar if it can be removed from the language without any effect on what the language can do: functionality and expressive power will remain the same.

Language processors, including compilers and static analyzers, often expand sugared constructs into more fundamental constructs before processing, a process sometimes called "desugaring".

---------------------------------------------------------------------------------------------------------------------------------------

I tend to think constructs like move_alloc are syntactic sugar, the real question is what is the underlying code to implement the function.  There is nothing wrong with syntactic sugar as long as you look at the impact on the compiler, it gets larger.   I appreciate it makes the programmers job easier.  

Comments and opinions are free except in a few places in their world, where holding a blank sign will get you arrested.  

0 Kudos
andrew_4619
Honored Contributor II
2,797 Views

move_alloc adds functionality.

Steve_Lionel
Honored Contributor III
2,730 Views

I agree with @andrew_4619 - MOVE_ALLOC adds significant and useful functionality. The primary use case is when you want to extend the size of an existing allocatable array. Before MOVE_ALLOC you'd have to do it like this:

  • Allocate a temporary array of the size of the current array
  • Copy the current array to the temp
  • Deallocate the current array
  • Allocate the array to the new size
  • Copy the old values from the temp to the newly allocated array
  • Deallocate the temp

With MOVE_ALLOC:

  • Allocate a new array to the new size
  • Copy the old elements to the new array
  • MOVE_ALLOC the new array to the old

This saves an allocate/deallocate and a copy.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,681 Views

IOW think of it as the following in C++

float* array = NULL;
int arraySize = 0;
...
array = new float[initialSize];
arraySize = initialSize;
...
// need to grow array
float* temp = new float[arraySize + growth];
memcpy(temp, array, arraySize*sizeof(array[0]));
swap(temp, array);
delete temp;
arraySize += growth;
...

The Fortran move_alloc has a little more work as the C++ example above, the "descriptor" contains only a base pointer and a size, whereas the Fortran descriptor contains a base pointer together with a variable number of (rank number of) ranges with stride (may be stored as base, count, stride or any other implementation method chosen).

Jim Dempsey

 

0 Kudos
JNichols
New Contributor I
2,649 Views

The command adds another abstraction layer into Fortran and adds simplicity to Fortran, but the functionality exists in a set of Fortran commands that do not include this command.  Simplicity is not functionality, it is simplicity, and I accept that is useful, it is the same as creating a LISP function that moves a point from A to B - it turns several commands into one line of LISP, but the original lines are still in the program, just abstracted.  

Syntactic sugar is just added simplicity to make the program easier to read, but it does not add functionality, it merely adds an internal function.  

If you want to see language with little syntactic sugar then program in LISP.  

It's best if we end this, we are never going to agree, but having programmed in LISP  a lot, you learn very quickly to abstract.  

 

It is a useful abstraction, it is just not one I would use, I program engineering things that are countable at the start. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,640 Views

>but it does not add functionality

I disagree. The functionality is that it removes an extra copy (or two copies) of the data.

A function not only has a result objective, but also has a cost objective (performance/resource). These are not syntactic sugar.

Jim Dempsey

0 Kudos
Reply