- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear all,
Using ifort 11.1.046 with -check all, I get "forrtl: severe (408): fort: (8): Attempt to fetch from allocatable variable VALUES when it is not allocated" at runtime, but I don't understand why. As far as I can tell, img1%values and img2%values are allocated. What am I doing wrong?
Using ifort 11.1.046 with -check all, I get "forrtl: severe (408): fort: (8): Attempt to fetch from allocatable variable VALUES when it is not allocated" at runtime, but I don't understand why. As far as I can tell, img1%values and img2%values are allocated. What am I doing wrong?
[cpp]module image_mod type image real, allocatable :: values(:) end type image interface assignment(=) module procedure image_assignment end interface interface operator(+) module procedure add_images end interface contains function add_images(img1,img2) result(imgout) implicit none type(image), intent(in) :: img1, img2 type(image) :: imgout imgout%values = img1%values + img2%values end function subroutine image_assignment(imgout,imgin) implicit none type(image), intent(out) :: imgout type(image), intent(in) :: imgin imgout%values = imgin%values end subroutine end module image_mod program images use image_mod implicit none type(image) :: img1, img2 integer :: ierr allocate(img1%values(5), img2%values(5), stat=ierr) if (ierr == 0) write(*,*) 'Allocation successful' img1%values = 1.0 img2%values = 2.0 img2 = img1 + img2 write(*,*) img2%values end program images [/cpp]
Link Copied
12 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Kevin Davis (Intel)
Kevin,
Thanks for the hint. Using this option does remove the runtime error. However, it seems to me that this option is almost exactly the opposite of the behaviour I would want. I would much rather have a segfault if trying to write to an unallocated array or an array allocated the wrong size rather than duplicate or reallocate large arrays on the fly like the documentation for -assume realloc_lhs seems to imply:
Tells the compiler that when the left-hand side of an assignment is an allocatable object, it should be reallocated to the shape of the right-hand side of the assignment before the assignment occurs. This is the Fortran 2003 definition. This feature may cause extra overhead at run time.
(In fact, I don't really understand what this sentence means in detail. Is the entity on the left-hand side always reallocated, even when its shape already matches that of the right-hand side?)
Further, I feel there is an inconsistency at play. If I replace line 46 above with the line below, I don't have an error anymore at runtime.
[cpp] img2%values = img1%values + img2%values[/cpp]So the error I was getting ("Attempt to fetch from allocatable variable when it is not allocated") must have been plain wrong, since img1%values and img2%values can be read from and written to perfectly well with the line above. To my layman's eyes, this looks like buggy behaviour when checking the allocation status of allocatable arrays within derived types vs. allocatable arrays themselves.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - tim18
Thanks for the link, my issue does seem related, in that it looks to me like in my case the checks for the allocation status of an array is dodgy when that array is within a derived type and isn't directly refered to in the assignment.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Some details of the post Tim noted (reply #5 here) suggest a "SAVE imgout" may be needed in function add_images. Adding such a statement does not yield the desired results.
I'm still a bit unclear. The Doctor is in today so I will consult w/him.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Kevin Davis (Intel)
Some details of the post Tim noted (reply #5 here) suggest a "SAVE imgout" may be needed in function add_images. Adding such a statement does not yield the desired results.
I'm still a bit unclear. The Doctor is in today so I will consult w/him.
Thanks for looking into this.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Kevin was correct in suggesting that you use -assume realloc_lhs. The issue is the assignment in image_assignment. The left side of this assignment is NOT allocated - the INTENT(OUT) guarantees that, even if the argument you passed to it was already allocated. If you change the INTENT to INOUT, then if the left side is already allocated to the proper shape, no reallocation will be done. However, if you can't guarantee this, then you'll have to deallocate it and then reallocate to the proper shape. Use of -assume realloc_lhs takes care of this.
You would not get the initial error ("Attempt to fetch...") unless you had also enabled "-check pointer". Perhaps you just have -check or -C.
So, my recommendation:
1. Use -assume realloc_lhs
2. Change the imgout argument to be INTENT(INOUT) to avoid unnecessary reallocation
P.S. SAVE is not appropriate or relevant to this discussion
You would not get the initial error ("Attempt to fetch...") unless you had also enabled "-check pointer". Perhaps you just have -check or -C.
So, my recommendation:
1. Use -assume realloc_lhs
2. Change the imgout argument to be INTENT(INOUT) to avoid unnecessary reallocation
P.S. SAVE is not appropriate or relevant to this discussion
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I forgot to mention. -assume realloc_lhs is absolutely required for the add_images routine since the result variable is initially unallocated.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your reply. It was foolish of me to overlook how using intent(out) on imgout would affect my problem.
I have a few remaining questions.
1. Is there no way to make sure that no reallocation happens under any circumstances? I would rather force the developer into making sure the lhs of the assignment is already allocated than allow on-the-fly reallocations.
2. Why is the option called -assume if it will only do it if the reallocation is necessary? Reading that part of the documentation again, I still feel it sounds like reallocation will happen every time, whether shapes match or not.
3. Why is -assume realloc_lhs absolutely necessary for add_images? On line 46 of the above example, the lhs of the assignment is allocated, therefore I would have thought IMGOUT in that instance of the assignment is allocated already. Are you saying that the allocation status of the function result is not checked at runtime?
3b. If the allocation status of the function result is not checked at runtime, does that mean that line 21 above creates a temporary array, the contents of which are then copied over to the lhs variable (imgout%values in this case)? If so, the operator overloading becomes useless for my purposes, since it would create huge overheads when dealing with huge arrays.
I have a few remaining questions.
1. Is there no way to make sure that no reallocation happens under any circumstances? I would rather force the developer into making sure the lhs of the assignment is already allocated than allow on-the-fly reallocations.
2. Why is the option called -assume if it will only do it if the reallocation is necessary? Reading that part of the documentation again, I still feel it sounds like reallocation will happen every time, whether shapes match or not.
3. Why is -assume realloc_lhs absolutely necessary for add_images? On line 46 of the above example, the lhs of the assignment is allocated, therefore I would have thought IMGOUT in that instance of the assignment is allocated already. Are you saying that the allocation status of the function result is not checked at runtime?
3b. If the allocation status of the function result is not checked at runtime, does that mean that line 21 above creates a temporary array, the contents of which are then copied over to the lhs variable (imgout%values in this case)? If so, the operator overloading becomes useless for my purposes, since it would create huge overheads when dealing with huge arrays.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
1. If you don't use -assume realloc_lhs, then reallocation will not occur, except possibly for the line:
img2=img1+img2
but then, only if the shapes don't match. However, you'll then need to add an allocate in add_images because there's no way to "pass in" an already-allocated function result.
2. It's called "assume" because this is the name of the switch that tells the compiler what language behaviors should be in effect. There are quite a few other options. Most of these have to deal with reconciling traditional (or at least older) Intel/Compaq/DEC Fortran behavior with what newer standards specify. I note that at least one other Fortran vendor takes the same approach we do with "realloc_lhs" (they spell it differently). The reason for this option is that assignment of allocatable arrays in F90/95 required that the LHS already be allocated to the shape of the RHS and we felt that the extra checking code would slow down programs written to assume that. (Note that even if realloc_lhs is enabled, reallocation is done only if the shapes don't match or the LHS is not allocated.)
3. The LHS in the assignment is not part of the call to add_images. The right side of an assignment is completely evaluated before the left side is looked at. You could have img1+img2+img3+img4 , for example, which would cause add_images to be called three times. For each of these calls, the function result needs to go somewhere, and it goes into the newly allocated function result. If you don't add an explicit allocate to add_images. then you must use either realloc_lhs or get an error. An allocatable function result, like an INTENT(OUT) allocatable argument, starts out deallocated.
3b. Yes, it creates a temporary allocatable array which is automatically deallocated when the statement completes. The only alternative that comes to mind is to write a subroutine where you pass all three arguments, the LHS and the two RHS operands, and it has a DO loop that adds and assigns each element. No copy will be made in that case, but it is rather ugly in the code and not easily extensible.
img2=img1+img2
but then, only if the shapes don't match. However, you'll then need to add an allocate in add_images because there's no way to "pass in" an already-allocated function result.
2. It's called "assume" because this is the name of the switch that tells the compiler what language behaviors should be in effect. There are quite a few other options. Most of these have to deal with reconciling traditional (or at least older) Intel/Compaq/DEC Fortran behavior with what newer standards specify. I note that at least one other Fortran vendor takes the same approach we do with "realloc_lhs" (they spell it differently). The reason for this option is that assignment of allocatable arrays in F90/95 required that the LHS already be allocated to the shape of the RHS and we felt that the extra checking code would slow down programs written to assume that. (Note that even if realloc_lhs is enabled, reallocation is done only if the shapes don't match or the LHS is not allocated.)
3. The LHS in the assignment is not part of the call to add_images. The right side of an assignment is completely evaluated before the left side is looked at. You could have img1+img2+img3+img4 , for example, which would cause add_images to be called three times. For each of these calls, the function result needs to go somewhere, and it goes into the newly allocated function result. If you don't add an explicit allocate to add_images. then you must use either realloc_lhs or get an error. An allocatable function result, like an INTENT(OUT) allocatable argument, starts out deallocated.
3b. Yes, it creates a temporary allocatable array which is automatically deallocated when the statement completes. The only alternative that comes to mind is to write a subroutine where you pass all three arguments, the LHS and the two RHS operands, and it has a DO loop that adds and assigns each element. No copy will be made in that case, but it is rather ugly in the code and not easily extensible.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The right side of an assignment is completely evaluated before the left side is looked at.
Out of interest, what happens if I have something like this, where the assignment isn't within a function whose result is the LHS:
[cpp]REAL, ALLOCATABLE :: LARGEARRAY(:,:,:)Does the program (i) create a temporary array of shape (1024,1024,1024) filled with 1.0, and then copy contents over to LARGEARRAY and deallocate the temporary array, or (ii) directly write to LARGEARRAY, element-by-element? I always thought (ii), but I just want to make sure
ALLOCATE(LARGEARRAY(1024,1024,1024))
LARGEARRAY = 1.0[/cpp]
Question 2.
Now that operator overloading does not seem to be an option for me, I'm going with a set of subroutines instead, e.g.
[cpp] SUBROUTINE ADD_IMAGES(IMG1,IMG2,IMGOUT) IMPLICIT NONE TYPE(IMAGE), INTENT(IN) :: IMG1 TYPE(IMAGE), INTENT(IN) :: IMG2 TYPE(IMAGE), INTENT(INOUT) :: IMGOUT IMGOUT%VALUES = IMG1%VALUES + IMG2%VALUES END SUBROUTINE ADD_IMAGESAm I correct in thinking that in this case, since the LHS is passed as an argument, (i) provided the three arrays have the same shapes, no reallocation of LHS will occur and (ii) the RHS is only evaluated one element at a time, creating a tiny overhead of one REAL (assuming just one thread / no optimisation)?
[/cpp]
Again, thanks for the tuition :)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
1. Semantically, a temporary array is created, filled in and then copied. However, in this case, the optimizer recognizes that it doesn't need to do that and will very likely produce a nicely vectorized loop that does the initialization.
2. Again, semantically, a temporary is created and then copied. But again, this is the sort of assignment the compiler can optimize and you should get good code for this.
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page