Flang Bug: Incorrect SIZE With LBOUND/UBOUND/SHAPE
Introduction
This article delves into a bug discovered in the Flang Fortran compiler, specifically affecting the SIZE intrinsic function when used in conjunction with LBOUND, UBOUND, or SHAPE. This issue, observed in Flang version 22.0.0, leads to incorrect results when the actual argument of SIZE is the result of one of these intrinsic functions. The problem arises under specific conditions related to assumed-type and assumed-rank dummy arguments. Let’s examine the details of this bug, its implications, and how it contrasts with previous versions and other compilers.
The Issue: Incorrect SIZE Results
The core of the problem lies in the incorrect evaluation of the SIZE intrinsic function when it receives the result of LBOUND, UBOUND, or SHAPE as its argument. According to the Fortran standard, the LBOUND intrinsic function, for instance, should return an array of rank one and size zero when the ARRAY argument is a scalar variable. However, Flang version 22.0.0 incorrectly returns 1 in such cases, while earlier versions (e.g., 21.1.2) and other compilers like Intel Fortran (ifx) produce the correct result (0).
This discrepancy can lead to significant issues in Fortran programs that rely on the correct behavior of these intrinsic functions for array manipulation and size determination. The impact is particularly pronounced in generic subroutines or functions that handle arrays of varying shapes and sizes.
Conditions for the Bug
The bug manifests itself under the following specific conditions:
- The intrinsic function
LBOUND,UBOUND, orSHAPEappears in the actual argument of aSIZEintrinsic function reference. - The argument of
LBOUND,UBOUND, orSHAPEis a dummy argument with assumed type and assumed rank. An assumed-rank entity is a dummy argument that takes the rank from its actual argument. An assumed-type entity does not have a declared type; its type is taken from its actual argument. - The actual argument corresponding to the assumed-type and assumed-rank dummy argument is a scalar.
When these three conditions are met, Flang 22.0.0 miscalculates the size, leading to incorrect program behavior.
Example Code: test.f90
To illustrate the issue, consider the following Fortran code snippet:
module m
implicit none
contains
subroutine sub(dd)
implicit none
type(*)::dd(..)
print *,'rank(dd) :',rank(dd)
print *,'size(dd) :',size(dd)
print *,'lbound(dd) : ',lbound(dd)
print *,'rank(lbound(dd)):',rank(lbound(dd))
print *,'size(lbound(dd)):',size(lbound(dd)) ! Incorrect
if(size(lbound(dd)) /= 0) print*,'NG size(lbound(dd)):' ,size(lbound(dd))
if(size(ubound(dd)) /= 0) print*,'NG size(ubound(dd)):' ,size(ubound(dd))
if(size(shape(dd))/=0 ) print*,'NG size(shape(dd)):',size(shape(dd))
end subroutine sub
end module m
use m
integer::scalar
call sub(scalar)
print *,'pass'
In this example, the subroutine sub takes an assumed-type, assumed-rank dummy argument dd. When called with a scalar integer scalar, the LBOUND function should return an array of size 0. However, Flang 22.0.0 incorrectly reports the size as 1.
Observed Behavior
When compiled and executed with Flang 22.0.0, the output is:
$ flang test.f90
$ ./a.out
rank(dd) : 0
size(dd) : 1
lbound(dd) :
rank(lbound(dd)): 1
size(lbound(dd)): 1
NG size(lbound(dd)): 1
NG size(ubound(dd)): 1
NG size(shape(dd)): 1
pass
This output clearly shows that size(lbound(dd)) is incorrectly evaluated as 1.
In contrast, when compiled and executed with Flang version 21.1.6 or Intel Fortran (ifx), the output is correct:
$ /work/groups/ssoft/compiler/llvm/aarch64/21.1.6/bin/flang test.f90
$ ./a.out
rank(dd) : 0
size(dd) : 1
lbound(dd) :
rank(lbound(dd)): 1
size(lbound(dd)): 0
pass
$ ifx test.f90
$ ./a.out
rank(dd) : 0
size(dd) : 1
lbound(dd) :
rank(lbound(dd)): 1
size(lbound(dd)): 0
pass
These results confirm that the bug is specific to Flang 22.0.0 and that other compilers and older versions of Flang behave as expected.
Implications and Impact
The incorrect behavior of the SIZE intrinsic function can lead to several problems:
- Incorrect Array Handling: Programs that rely on the size of arrays returned by
LBOUND,UBOUND, orSHAPEmay misallocate memory, access array elements out of bounds, or perform incorrect calculations. - Logic Errors: Conditional statements that depend on the size of these arrays may execute the wrong branches, leading to unexpected program behavior.
- Portability Issues: Code that works correctly with other Fortran compilers or older versions of Flang may fail or produce incorrect results when compiled with Flang 22.0.0.
- Debugging Challenges: The bug can be difficult to diagnose, as the incorrect size calculation may not immediately manifest as an error but could lead to subtle and hard-to-track-down issues later in the program's execution.
Fortran Standard Interpretation
The Fortran standard (specifically section 16.9.119 for LBOUND) clearly states the expected behavior:
16.9.119 LBOUND (ARRAY [, DIM, KIND])
:
Result Characteristics. Integer. If KIND is present, the kind type parameter is that specified by the value of
KIND; otherwise the kind type parameter is that of default integer type. The result is scalar if DIM is present;
otherwise, the result is an array of rank one and size n, where n is the rank of ARRAY.
When ARRAY is a scalar, the result of LBOUND should be an array of rank one and size 0. Flang 22.0.0 violates this standard by returning a size of 1.
Conclusion
The bug in Flang version 22.0.0, affecting the SIZE intrinsic function when used with LBOUND, UBOUND, or SHAPE under specific conditions, poses a significant issue for Fortran developers. This article has detailed the conditions under which the bug occurs, provided a concrete example demonstrating the incorrect behavior, and highlighted the potential implications for program correctness and portability. Developers using Flang 22.0.0 should be aware of this issue and consider using older versions of Flang or other Fortran compilers until a fix is available.
For more information on the Fortran standard and intrinsic functions, visit the Fortran standards website. This external resource can provide further details and clarifications on the correct behavior of Fortran features.