Compiler was rewriting SIZE(PACK(x, MASK)) to COUNT(MASK). It was
wrapping the COUNT call without a KIND argument (leading to INTEGER(4)
result in the characteristics) in an Expr<ExtentType> (implying
INTEGER(8) result), this lead to inconsistencies that later hit verifier
errors in lowering.
Set the KIND argument to the KIND of ExtentType to ensure the built
expression is consistent.
This requires giving access to some safe place where the "kind" name can
be saved and turned into a CharBlock (count has a DIM argument that
require using the KIND keyword here). For the FoldingContext that belong
to SemanticsContext, this is the same string set as the one used by
SemanticsContext for similar purposes.
Recognize Cray pointees as such when they are declared as assumed size
arrays, and don't emit a bogus error message about implied shape arrays.
Fixes https://github.com/llvm/llvm-project/issues/77330.
The rewriting of the extension intrinsic function SIZEOF was producing
results that would reference symbols that were not available in the
current scope, leading to crashes in lowering. The symbols could be
function result variables, for SIZEOF(func()), or bare derived type
component names, for SIZEOF(array(n)%component). Fixing this without
regressing on a current test case involved careful threading of some
state through the TypeAndShape characterization code and the
shape/bounds analyzer, and some clean-up was done along the way.
A RANK(*) case in a SELECT RANK construct selects the case of an
assumed-rank dummy argument whose effective actual argument is an
assumed-size array. In this case, the attributes of the selector are
those of a rank-1 assumed-size array, and the selector cannot be
allocatable or a pointer.
Ensure that the representation of a SELECT RANK construct's per-case
AssocEntityDetails can distinguish RANK(n), RANK(*), and RANK DEFAULT,
and clean up various code sites and tests where the distinctions matter.
Implements compatibility checking for initializers in procedure pointer
declarations. This work exposed some inconsistency in how ELEMENTAL
interfaces were handled and checked, from both unrestricted intrinsic
functions and others, and some refinements needed for function result
compatbility checking; these have also been ironed out. Some new
warnings are now emitted, and this affected a dozen or so tests.
Differential Revision: https://reviews.llvm.org/D159026
Work through several issues with LBOUND() and UBOUND() of ASSOCIATE
construct entities that have been associated with named constants or
subobjects of named constants that are sporting non-default lower bounds.
Sometimes the non-default lower bounds matter, sometimes they don't.
Add a fairly exhaustive test to work through the possibilities.
Differential Revision: https://reviews.llvm.org/D156756
It looks like a regression after D151737: shape of the elemental
call became rank-0.
Reviewed By: klausler
Differential Revision: https://reviews.llvm.org/D156386
A CHECK() was firing when a call to the PACK intrinsic does not have a
VECTOR= argument and at least one dimension of the shape of the ARRAY=
argument could not be determined. The CHECK was inappropriate, since
this can of course happen, such as when that argument is the result
of the SPREAD() intrinsic with non-constant DIM= or NCOPIES= arguments.
Replace with an if() statement.
Differential Revision: https://reviews.llvm.org/D152212
When computing the shape of an expression at compilation time as part of
folding an intrinsic function like SIZE(), don't create an expression that
increases a dependence on the presence of an optional dummy argument.
Differential Revision: https://reviews.llvm.org/D151737
In some circumstances, such as in compile-time array shape analysis,
clients of the utility function ResolveAssociations() don't really
want it to drill all of the way down to an assumed-rank dummy argument.
Add a variation, ResolveAssociationsExceptSelectRank(), that
will return a specific rank case's AssocEntity symbol instead.
This fixes a crash in subscript validation checking that stemmed from
deducing an incorrect number of lower and upper bound expressions
from a specific rank case association entity.
Differential Revision: https://reviews.llvm.org/D143778
The ProcInterface structure is used only by ProcEntityDetails; it represents
what a program might have put in parentheses in a procedure-declaration-stmt,
either the name of a procedure interface or a declaration-type-spec.
If a procedure entity has an implicit interface, the function result
type (if any) can be kept in EntityDetails::type_, which already exists
and is currently redundant for ProcEntityDetails symbols.
All that is really needed is a nullable Symbol pointer in ProcEntityDetails
to point to the procedure's explicit interface, when it has one.
Also, catch the case where a procedure has an explicit interface
and a program attempts to also give it a type.
Differential Revision: https://reviews.llvm.org/D140134
When a scalar expression is not expandable -- i.e., it would have to be
evaluated once and saved in a temporary to avoid changing the semantics
of the program if it were to be evaluated more than once -- it affects
some aspects of folding and expression semantics. In cases where
scalar expansion would not cause multiple evaluations due to the shape
of the result having but a single element, however, these "non-expandable"
scalar expressions can be safely allowed.
Differential Revision: https://reviews.llvm.org/D134476
The previous code was rewriting all shape inquires on associate
construct entities to inquires on the associated expression or variable.
This is is incorrect because at the point of inquiry, some statement
between the association and the inquiry may have modified the expression
operands or variable in a way that changes its shapes or bounds.
For instance, in the example below, expression rewrites was previously
replacing `size(x, 1)` by `size(p, 1)` which is invalid if p is a
pointer.
```
associate(x => p + 1)
call call_that_may_modify_p_shape()
print *, size(x, 1)
end associate
```
This change restricts rewrites of shape inquiries on associate construct entity
to use the associated expression shape and bounds if and only if the
shape/bounds are compile time constant. Otherwise, this may be invalid.
Differential Revision: https://reviews.llvm.org/D133857
When MOLD= is an array and there is no SIZE= in a call to TRANSFER(),
the size of an element of the MOLD= is used as the denominator in a
division to establish the extent of the vector result. When the
total storage size of the SOURCE= is known to be zero, the result is
empty and no division is needed.
To avoid a division by zero at runtime, we need to check for a zero-sized
MOLD= element type when the storage size of SOURCE= is nonzero and there
is no SIZE=. Further, in the compilation-time rewriting of calls to
SHAPE(TRANSFER(...)) and SIZE(TRANSFER(...)) for constant folding and
simplification purposes, we can't replace the call with an arithmetic
element count expression when the storage size of SOURCE= is not known
to be zero and the element size of MOLD= is not known to be nonzero at
compilation time.
These changes mostly affect tests using a MOLD= argument that is an
assumed-length character.
Differential Revision: https://reviews.llvm.org/D129680
Adds flang/include/flang/Common/log2-visit.h, which defines
a Fortran::common::visit() template function that is a drop-in
replacement for std::visit(). Modifies most use sites in
the front-end and runtime to use common::visit().
The C++ standard mandates that std::visit() have O(1) execution
time, which forces implementations to build dispatch tables.
This new common::visit() is O(log2 N) in the number of alternatives
in a variant<>, but that N tends to be small and so this change
produces a fairly significant improvement in compiler build
memory requirements, a 5-10% improvement in compiler build time,
and a small improvement in compiler execution time.
Building with -DFLANG_USE_STD_VISIT causes common::visit()
to be an alias for std::visit().
Calls to common::visit() with multiple variant arguments
are referred to std::visit(), pending further work.
This change is enabled only for GCC builds with GCC >= 9;
an earlier attempt (D122441) ran into bugs in some versions of
clang and was reverted rather than simply disabled; and it is
not well tested with MSVC. In non-GCC and older GCC builds,
common::visit() is simply an alias for std::visit().
When a procedure pointer or procedure dummy argument has a
defined interface, the rank of the pointer (or dummy) is the
rank of the interface.
Also tweak code discovered in shape analysis when investigating
this problam so that it returns a vector of emptied extents rather
than std::nullopt when the extents are not scope-invariant, so that
the rank can at least be known.
Differential Revision: https://reviews.llvm.org/D123727
Shape analysis of RESHAPE(..., SHAPE=s) should of course return
the SHAPE= actual argument when it is constant; but when it is
not, its length is still known, and thus so is the rank of the
result of RESHAPE(), and shape analysis should at least return
a shape vector of the right length rather than a result that
makes the result appear to be a scalar, which can lead to some
bogus error messages.
Also, while here: rename a private GetShapeHelper::AsShape()
routine so that it can't be confused with the ones in the API
of shape.h.
Differential Revision: https://reviews.llvm.org/D123712
Adds flang/include/flang/Common/visit.h, which defines
a Fortran::common::visit() template function that is a drop-in
replacement for std::visit(). Modifies most use sites in
the front-end and runtime to use common::visit().
The C++ standard mandates that std::visit() have O(1) execution
time, which forces implementations to build dispatch tables.
This new common::visit() is O(log2 N) in the number of alternatives
in a variant<>, but that N tends to be small and so this change
produces a fairly significant improvement in compiler build
memory requirements, a 5-10% improvement in compiler build time,
and a small improvement in compiler execution time.
Building with -DFLANG_USE_STD_VISIT causes common::visit()
to be an alias for std::visit().
Calls to common::visit() with multiple variant arguments
are referred to std::visit(), pending further work.
Differential Revision: https://reviews.llvm.org/D122441
GetLowerBoundHelper rewrite in https://reviews.llvm.org/D121488 was
incorrect with POINTER/ALLOCATABLE components. The rewrite created a
descriptor inquiry to the component symbol only instead of the whole
named entity. The base information was lost, and not retrievable.
LBOUND(a(10)%p) became LBOUND(p).
Fix this regression, and also update DescriptorInquiry unparsing to
carry the kind information. DescriptorInquiries are KIND 8 expressions,
while LBOUND/SIZE/RANK, %LEN are default kind expressions.
This caused `print *,lbound(x,kind=8)` to unparse as `print*,lbound(x)` which is not
semantically the same (this unparsing issue was not an issue for
lowering, but I noticed it while writing my regression test).
Differential Revision: https://reviews.llvm.org/D122406
Similarly to LBOUND in https://reviews.llvm.org/D121488, UBOUND must
return zero for an empty dimension, no matter the specification
expression.
Add a GetUBOUND method to be used in expression rewrite that prevents
folding UBOUND to a bound specification expression if the extent is
not a compile time constant.
Fold the case where the extents is known to be zero (and also deal with
this case in LBOUND since we can and should to comply with constant
expression requirements).
Differential Revision: https://reviews.llvm.org/D122242
LBOUND must return 1 for an empty dimension, no matter what
explicit expression might appear in a declaration or arrive in
a descriptor.
Differential Revision: https://reviews.llvm.org/D121488
An assumed-type actual argument that corresponds to an assumed-rank dummy
argument shall be assumed-shape or assumed-rank.
Differential Revision: https://reviews.llvm.org/D120750
UBOUND, SIZE, and SHAPE folding was still creating expressions that are
invalid on the caller side without the call expression context.
A previous patch intended to deal with this situation (https://reviews.llvm.org/D116933)
but it assumed the return expression would be a descriptor inquiry to
the result symbol, which is not the case if the extent expression is
"scope invariant" inside the called subroutine (e.g., referring to
intent(in) dummy arguments). Simply prevent folding from inlining non
constant extent expression on the caller side.
Folding could be later improved by having ad-hoc folding for UBOUND, SIZE, and
SHAPE on function references where it could try replacing the dummy symbols
by the actual expression, but this is left as a possible later improvement.
Differential Revision: https://reviews.llvm.org/D117686
Currently, something like `print *, size(foo(n,m))` was rewritten
to `print *, size(foo_result_symbol)` when foo result is a non constant
shape array. This cannot be processed by lowering or reprocessed by a
Fortran compiler since the syntax is wrong (`foo_result_symbol` is
unknown on the caller side) and the arguments are lost when they might
be required to compute the result shape.
It is not possible (and probably not desired) to make GetShape fail in
general in such case since returning nullopt seems only expected for
scalars or assumed rank (see GetRank usage in lib/Semantics/check-call.cpp),
and returning a vector with nullopt extent may trigger some checks to
believe they are facing an assumed size (like here in intrinsic argument
checks: 196204c72c/flang/lib/Evaluate/intrinsics.cpp (L1530)).
Hence, I went for a solution that limits the rewrite change to folding
(where the original expression is returned if the shape depends on a non
constant shape from a call).
I added a non default option to GetShapeHelper that prevents the rewrite
of shape inquiry on calls to descriptor inquiries. At first I wanted to
avoid touching GetShapeHelper, but it would require to re-implement all
its logic to determine if the shape comes from a function call or not
(the expression could be `size(1+foo(n,m))`). So added an alternate
entry point to GetShapeHelper seemed the cleanest solution to me.
Differential Revision: https://reviews.llvm.org/D116933
Some kinds of Fortran arrays are declared with the same syntax,
and it is impossible to tell from a shape (:, :) or (*) whether
the object is assumed shape, deferred shape, assumed size, implied
shape, or whatever without recourse to more information about the
symbol in question. This patch softens the names of some predicate
functions (IsAssumedShape to CanBeAssumedShape) and makes others
more reflective of the syntax they represent (isAssumed to isStar)
in an attempt to encourage coders to seek and find definitive
predicate functions whose names deliver what they seem to mean.
Address TODO comments in IsSimplyContiguous() by using the
updated IsAssumedShape() predicate.
Differential Revision: https://reviews.llvm.org/D114829
When an array's shape involves references to symbols that are not
invariant in a scope -- the classic example being a dummy array
with an explicit shape involving other dummy arguments -- the
compiler was creating shape expressions that referenced those
symbols. This might be valid if those symbols are somehow
captured and copied at each entry point to a subprogram, and
the copies referenced in the shapes instead, but that's not
the case.
This patch introduces a new expression predicate IsScopeInvariantExpr(),
which defines a class of expressions that contains constant expressions
(in the sense that the standard uses that term) as well as references
to items that may be safely accessed in a context-free way throughout
their scopes. This includes dummy arguments that are INTENT(IN)
and not VALUE, descriptor inquiries into descriptors that cannot
change, and bare LEN type parameters within the definitions of
derived types. The new predicate is then used in shape analysis
to winnow out results that would have otherwise been contextual.
Differential Revision: https://reviews.llvm.org/D113309
Fold the transformational intrinsic function FINDLOC() for
all combinations of optional arguments and data types.
Differential Revision: https://reviews.llvm.org/D110757
Catch invalid attempts to extract the unknowable extent of the last
dimension of an assumed-size array dummy argument, and clean up
problems with assumed-rank arguments in similar circumstances
exposed by testing the fix.
Differential Revision: https://reviews.llvm.org/D109918
Silence a bogus error message about an out-of-range DIM= argument
when the argument is assumed-rank. (More generally, don't pretend
to be able to discern a shape of known rank for an assumed-rank
object.)
Differential Revision: https://reviews.llvm.org/D109915
When the upper bound is less than the lower bound, the extent is zero. This is
specified in section 8.5.8.2, paragraph 3.
Note that similar problems exist in the lowering code. This change only fixes
the problem for the front end.
I also added a test.
Differential Revision: https://reviews.llvm.org/D107832
Use derived type information tables to drive default component
initialization (when needed), component destruction, and calls to
final subroutines. Perform these operations automatically for
ALLOCATE()/DEALLOCATE() APIs for allocatables, automatics, and
pointers. Add APIs for use in lowering to perform these operations
for non-allocatable/automatic non-pointer variables.
Data pointer component initialization supports arbitrary constant
designators, a F'2008 feature, which may be a first for Fortran
implementations.
Differential Revision: https://reviews.llvm.org/D106297
Do not use ultimate symbols in DescriptorInquiry. Using the ultimate
symbol may lead to issues later for at least two reasons:
- The original symbols may have volatile/asynchronous attributes that
the ultimate may not have. Later phases working on the DescriptorInquiry
would then not apply potential care required by these attributes.
- HostAssociatedDetails symbols are used by OpenMP for symbols with
special OpenMP attributes inside OpenMP region (e.g variables with
private attribute), so it is very important to preserve this
aspect in the DescriptorInquiry, that would otherwise apply on the
symbol outside of the region.
Differential Revision: https://reviews.llvm.org/D104385
Implement constant folding for the reduction transformational
intrinsic functions MAXVAL and MINVAL.
In anticipation of more folding work to follow, with (I hope)
some common infrastructure, these two have been implemented in a
new header file.
Differential Revision: https://reviews.llvm.org/D104337
To ensure that errors are emitted by CheckConformance and
its callers in all situations, it's necessary for the returned result
of that function to distinguish between three possible
outcomes: the arrays are known to conform at compilation time,
the arrays are known to not conform (and a message has been
produced), and an indeterminate result in which is not possible
to determine conformance. So convert CheckConformance's
result into an optional<bool>, and convert its confusing
Boolean flag arguments into a bit-set of named flags too.
Differential Revision: https://reviews.llvm.org/D103654
Split up MeasureSizeInBytes() so that array element sizes can be
calculated accurately; use the new API in some places where
DynamicType::MeasureSizeInBytes() was being used but the new
API performs better due to TypeAndShape having precise CHARACTER
length information.
Differential Revision: https://reviews.llvm.org/D95897
Analyze the shape of the result of TRANSFER(ptr,array) correctly
when "ptr" is an array of deferred shape. Fixing this bug led to
some refactoring and concentration of common code in TypeAndShape
member functions with code in general shape and character length
analysis, and this led to some regression test failures that have
all been cleaned up.
Differential Revision: https://reviews.llvm.org/D95744
Legacy Fortran implementations support an alternative form of the
PARAMETER statement; it differs syntactically from the standard's
PARAMETER statement by lacking parentheses, and semantically by
using the type and shape of the initialization expression to define
the attributes of the named constant. (GNU Fortran gets that part
wrong; Intel Fortran and nvfortran have full support.)
This patch disables the old style PARAMETER statement by default, as
it is syntactically ambiguous with conforming assignment statements;
adds a new "-falternative-parameter-statement" option to enable it;
and implements it correctly when enabled.
Fixes https://bugs.llvm.org/show_bug.cgi?id=48774, in which a user
tripped over the syntactic ambiguity.
Differential Revision: https://reviews.llvm.org/D95697
There were two problems with constant arrays whose lower bound is not 1.
First, when folding the arrays, we were creating the folded array to have lower
bounds of 1 but, we were not re-adjusting their lower bounds to the
declared values. Second, we were not calculating the extents correctly.
Both of these problems led to bogus error messages.
I fixed the first problem by adjusting the lower bounds in
NonPointerInitializationExpr() in Evaluate/check-expression.cpp. I wrote the
class ArrayConstantBoundChanger, which is similar to the existing class
ScalarConstantExpander. In the process of implementing and testing it, I found
a bug that I fixed in ScalarConstantExpander which caused it to infinitely
recurse on parenthesized expressions. I also removed the unrelated class
ScalarExpansionVisitor, which was not used.
I fixed the second problem by changing the formula that calculates upper bounds
in in the function ComputeUpperBound() in Evaluate/shape.cpp.
I added tests that trigger the bogus error messages mentioned above along with
a constant folding tests that uses array operands with shapes that conform but
have different bounds.
In the process of adding tests, I discovered that tests in
Evaluate/folding09.f90 and folding16.f90 were written incorrectly, and I
fixed them. This also revealed a bug in contant folding of the
intrinsic "lbounds" which I plan to fix in a later change.
Differential Revision: https://reviews.llvm.org/D95449
Correct the analysis of references to transformational intrinsic
functions that have different semantics based on the presence or
absence of a DIM= argument; add shape analysis for UNPACK().
Differential Revision: https://reviews.llvm.org/D94716
In some contexts, including the motivating case of determining whether
the expressions that define the shape of a variable are "constant expressions"
in the sense of the Fortran standard, expression rewriting via Fold()
is not necessary, and should not be required. The inquiry intrinsics LBOUND,
UBOUND, and SIZE work correctly now in specification expressions and are
classified correctly as being constant expressions (or not). Getting this right
led to a fair amount of API clean-up as a consequence, including the
folding of shapes and TypeAndShape objects, and new APIs for shapes
that do not fold for those cases where folding isn't needed. Further,
the symbol-testing predicate APIs in Evaluate/tools.h now all resolve any
associations of their symbols and work transparently on use-, host-, and
construct-association symbols; the tools used to resolve those associations have
been defined and documented more precisely, and their clients adjusted as needed.
Differential Revision: https://reviews.llvm.org/D94561
STORAGE_SIZE() is a standard inquiry intrinsic (size in bits
of an array element of the same type as the argument); SIZEOF()
is a common extension that returns the size in bytes of its
argument; C_SIZEOF() is a renaming of SIZEOF() in module ISO_C_BINDING.
STORAGE_SIZE() and SIZEOF() are implemented via rewrites to
expressions; these expressions will be constant when the necessary
type parameters and bounds are also constant.
Code to calculate the sizes of types (with and without alignment)
was isolated into Evaluate/type.* and /characteristics.*.
Code in Semantics/compute-offsets.* to calculate sizes and alignments
of derived types' scopes was exposed so that it can be called at type
instantiation time (earlier than before) so that these inquiry intrinsics
could be called from specification expressions.
Differential Revision: https://reviews.llvm.org/D93322
This patch plugs many holes in static initializer semantics, improves error
messages for default initial values and other component properties in
parameterized derived type instantiations, and cleans up several small
issues noticed during development. We now do proper scalar expansion,
folding, and type, rank, and shape conformance checking for component
default initializers in derived types and PDT instantiations.
The initial values of named constants are now guaranteed to have been folded
when installed in the symbol table, and are no longer folded or
scalar-expanded at each use in expression folding. Semantics documentation
was extended with information about the various kinds of initializations
in Fortran and when each of them are processed in the compiler.
Some necessary concomitant changes have bulked this patch out a bit:
* contextual messages attachments, which are now produced for parameterized
derived type instantiations so that the user can figure out which
instance caused a problem with a component, have been added as part
of ContextualMessages, and their implementation was debugged
* several APIs in evaluate::characteristics was changed so that a FoldingContext
is passed as an argument rather than just its intrinsic procedure table;
this affected client call sites in many files
* new tools in Evaluate/check-expression.cpp to determine when an Expr
actually is a single constant value and to validate a non-pointer
variable initializer or object component default value
* shape conformance checking has additional arguments that control
whether scalar expansion is allowed
* several now-unused functions and data members noticed and removed
* several crashes and bogus errors exposed by testing this new code
were fixed
* a -fdebug-stack-trace option to enable LLVM's stack tracing on
a crash, which might be useful in the future
TL;DR: Initialization processing does more and takes place at the right
times for all of the various kinds of things that can be initialized.
Differential Review: https://reviews.llvm.org/D92783
When comparing arrays whose shapes do not conform, the contant folding
code ran into problems trying to get the value of an extent that did not
exist. There were actually two problems. First, the routine
"CheckConformance()" was returning "true" when the compiler was unable
to get the extent of an array. Second, the function
"ApplyElementwise()" was calling "CheckConformance()" prior to folding
the elements of two arrays, but it was ignoring the return value.
Differential Revision: https://reviews.llvm.org/D91440
CHARACTER length expressions were not always being
captured or computed as part of procedure "characteristics",
leading to test failures due to an inability to compute
memory size expressions accurately.
Differential revision: https://reviews.llvm.org/D88689
The shape (esp. the size) of the result of a call to TRANSFER
is implemented according to the definition in the standard.
Differential Revision: https://reviews.llvm.org/D85866
Do not rewrite LEN(x) or x%len to the expression that specifies
the length of x when that length is not a constant expression.
Its value may have changed since the value of the expression was
first captured in the definition of the object.
Reviewed By: tskeith, sscalpone
Differential Revision: https://reviews.llvm.org/D83352