You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This change is a nearly complete implementation of the F08 BLOCK
construct. The exception to full standard compliance is that
the special handling of ASYNCHRONOUS and VOLATILE statements in
Clause 8.1.4p2 is not implemented. The expectation is that this
minor functionality would be relatively difficult to reliably
implement. This CL also disallows blocks in OpenMP parallel
constructs. OpenMP 5.0 Section 1.7 states that use of the BLOCK
construct is not explicitly addressed, and such use "may result in
unspecified behavior." However, to the extent that BLOCK is similar
to C name scopes, it should be possible to use BLOCKs in parallel
code. These limitations might be addressed with future changes. In
this CL, use of these features will generate error messages. Relative
to Fortran 2008, the Fortran 2018 standard has a few changes that
are not implemented, such as allowing IMPORT statements in a block.
The block construct allows variables and other entities to be
declared with a restricted scope. A declaration in a block can hide
same-named entities in an ancestor subprogram or block scope, and can
in turn be hidden by declarations in a nested block. The handling
of declarations in a block differs from declarations in module
and subprogram scopes in that implicit declarations in a block have
subprogram scope, not block scope (Note 5.39). This is one of several
reasons why existing symbol management routines are not easily
extendable to fully process declarations in a block. In contexts
where block locality must be taken into account, this functionality
is instead provided by a new routine - block_local_sym. These calls
are distributed throughout the parsing/semantic processing phase.
Code downstream from parsing must insert code at the entry to
the block to allocate memory, initialize derived type values,
and do array bounds checking as necessary. At block exit, code
must be inserted to finalize derived type objects, and deallocate
memory. Routine-level instances of these code insertions are
distributed across three phases. Most are done either in the bblock
or convert-output phases. The code that does these insertions is
somewhat decentralized, with different techniques used for different
cases, both within and across phases, with some dependencies between
phases. This code has been modified to make it somewhat more uniform
where possible, and to apply it to block level insertions. Additional
insertions for array bounds checking are done in the output/lowering
phase. The code for these insertions is mostly independent of block
context, but a few changes are required there as well.
In part to allow for code insertions, the form of code for a
block is:
continue -- first block std (labeled)
block prolog -- allocate/init/array_check code
comment (continue) -- prolog end == body begin boundary marker
block body -- user code
block epilog -- finalize/deallocate code
continue -- last block std (labeled)
For any sptr local to a block, the block entry, end-of-prolog,
and exit stds that are needed for inserting prolog and epilog code
are accessible via macros:
- BLOCK_ENTRY_STD(sptr)
- BLOCK_ENDPROLOG_STD(sptr)
- BLOCK_EXIT_STD(sptr)
Code can be inserted at the top of the prolog via BLOCK_ENTRY_STD,
and at the end of the prolog via BLOCK_ENDPROLOG_STD. Epilog code
can be inserted at the end of the epilog via BLOCK_EXIT_STD. There
is no known need to insert code at the top of the epilog, so there
is no marker std between body and epilog code.
The comm-optimize compilation phase analyzes forall loops
to determine if they can be fused. Fusion of two otherwise
compatible loops in different blocks can be invalid if either
loop declares a variable that has associated block entry/exit code
insertions. Incorrect fusion is conservatively avoided by disallowing
any fusion across block boundaries. More detailed analysis and/or
a more sophisticated fusion implementation could allow this fusion
in some cases.
There is some degree of code cleanup in various files, notably
scan.c, dpm_out.c, scopestack.c, and semant.h. For scan.c, some
of the changes were made in support of functionality that was
later found to be unneeded and removed, but the cleanup changes
were retained.
All -g block compilations fail with linker errors about undefined
block entry/exit label references. This is because these labels
currently don't survive through to the back end. This was done
because at -O2 and higher, unrolling + constant propagation +
dead code elimination can potentially generate a control flow
graph with an unreachable basic block that setup for vectorization
can't handle. In the long run, these labels need to be retained
for parallel code, so we need to look for a permanent fix for
this issue. However, parallelelization of code containing a block
is currently prohibited. Debugging only needs these labels below
-O2 (at the cost of degraded optimized code debugging), and the
"vectorization" problem only occurs at -O2 and above. So for now,
a simple fix is to only retain these labels below -O2. This is done
by marking them as volatile in semant.c.
F08 constraint C807 is "A SAVE statement in a BLOCK construct
shall contain a saved-entity-list that does not specify a
common-block-name." It is somewhat reasonable to interpret this
as saying (in part) that "A SAVE statement in a BLOCK construct
shall contain a saved-entity-list." However, other compilers allow
such SAVE statements; there doesn't seem to be any good language
justification for disallowing them; and the standard seems to
also suggest this elsewhere, such as in Note 8.5. So we modify the
compiler to allow these SAVE statements. This is done by marking the
ST_BLOCK symbol of a block scope with SAVE, and checking for this
flag when necessary by calling new utility function in_save_scope.
Variables such as arrays, pointers, and allocatables may have
associated compiler-created syms such as descriptors and pointers.
Secondary syms associated with a primary sym declared in a block
should probably have block locality. Changes are made to do this
somewhat more consistently. (More such changes may eventually
be needed.)
0 commit comments