This is an archive of the discontinued LLVM Phabricator instance.

[flang] Block construct
ClosedPublic

Authored by vdonaldson on Feb 27 2023, 2:25 PM.

Details

Summary

A block construct is an execution control construct that supports
declaration scopes contained within a parent subprogram scope or another
block scope. (blocks may be nested.) This is implemented by applying
basic scope processing to the block level.

Name uniquing/mangling is extended to support this. The term "block" is
heavily overloaded in Fortran standards. Prior name uniquing used tag B
for common block objects. Existing tag choices were modified to free up B
for block construct entities, and C for common blocks, and resolve
additional issues with other tags. The "old tag -> new tag" changes can
be summarized as:

   -> B  -- block construct -> new
B  -> C  -- common block
C  -> YI -- intrinsic type descriptor; not currently generated
CT -> Y  -- nonintrinsic type descriptor; not currently generated
G  -> N  -- namelist group
L  ->    -- block data; not needed -> deleted

Existing name uniquing components consist of a tag followed by a name
from user source code, such as a module, subprogram, or variable name.
Block constructs are different in that they may be anonymous. (Like other
constructs, a block may have a block-construct-name that can be used
in exit statements, but this name is optional.) So blocks are given a
numeric compiler-generated preorder index starting with B1, B2,
and so on, on a per-procedure basis.

Name uniquing is also modified to include component names for all
containing procedures rather than for just the immediate host. This
fixes an existing name clash bug with same-named entities in same-named
host subprograms contained in different-named containing subprograms,
and variations of the bug involving modules and submodules.

F18 clause 9.7.3.1 (Deallocation of allocatable variables) paragraph 1
has a requirement that an allocated, unsaved allocatable local variable
must be deallocated on procedure exit. The following paragraph 2 states:

When a BLOCK construct terminates, any unsaved allocated allocatable
local variable of the construct is deallocated.

Similarly, F18 clause 7.5.6.3 (When finalization occurs) paragraph 3
has a requirement that a nonpointer, nonallocatable object must be
finalized on procedure exit. The following paragraph 4 states:

A nonpointer nonallocatable local variable of a BLOCK construct
is finalized immediately before it would become undefined due to
termination of the BLOCK construct.

These deallocation and finalization requirements, along with stack
restoration requirements, require knowledge of block exits. In addition
to normal block termination at an end-block-stmt, a block may be
terminated by executing a branching statement that targets a statement
outside of the block. This includes

Single-target branch statements:

  • goto
  • exit
  • cycle
  • return

Bounded multiple-target branch statements:

  • arithmetic goto
  • IO statement with END, EOR, or ERR specifiers

Unbounded multiple-target branch statements:

  • call with alternate return specs
  • computed goto
  • assigned goto

Lowering code is extended to determine if one of these branches exits
one or more relevant blocks or other constructs, and adds a mechanism to
insert any necessary deallocation, finalization, or stack restoration
code at the source of the branch. For a single-target branch it suffices
to generate the exit code just prior to taking the indicated branch.
Each target of a multiple-target branch must be analyzed individually.
Where necessary, the code must first branch to an intermediate basic
block that contains exit code, followed by a branch to the original target
statement.

This patch implements an activeConstructStack construct exit mechanism
that queries a new activeConstruct PFT bit to insert stack restoration
code at block exits. It ties in to existing code in ConvertVariable.cpp
routine instantiateLocal which has code for finalization, making block
exit finalization on par with subprogram exit finalization. Deallocation
is as yet unimplemented for subprograms or blocks. This may result in
memory leaks for affected objects at either the subprogram or block level.
Deallocation cases can be addressed uniformly for both scopes in a future
patch, presumably with code insertion in routine instantiateLocal.

The exit code mechanism is not limited to block construct exits. It is
also available for use with other constructs. In particular, it is used
to replace custom deallocation code for a select case construct character
selector expression where applicable. This functionality is also added
to select type and associate constructs. It is available for use with
other constructs, such as select rank and image control constructs,
if that turns out to be necessary.

Overlapping nonfunctional changes include eliminating "FIR" from some
routine names and eliminating obsolete spaces in comments.

Diff Detail

Event Timeline

vdonaldson created this revision.Feb 27 2023, 2:25 PM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 27 2023, 2:25 PM
vdonaldson requested review of this revision.Feb 27 2023, 2:25 PM
PeteSteinfeld accepted this revision.Feb 27 2023, 3:14 PM

Aside from a couple of clang-format diffs, all builds and tests correctly and looks good.

flang/lib/Lower/Bridge.cpp
772

I'm seeing a clang-format diff here.

flang/lib/Lower/Mangler.cpp
96–98

I'm seeing more clang-format diffs here.

This revision is now accepted and ready to land.Feb 27 2023, 3:14 PM

clang-format

vdonaldson marked 2 inline comments as done.Feb 27 2023, 3:32 PM

Done; thanks

jeanPerier accepted this revision.Feb 28 2023, 12:37 AM

It's great to have a generic solution to deal with the clean-ups of construct entities when branching out of them, thanks Val.

clementval accepted this revision.Feb 28 2023, 12:41 AM

LGTM. Great work!