[flang] Create OpenMP-semantics.md
authorSteve Scalpone <sscalpone@nvidia.com>
Tue, 27 Aug 2019 21:38:48 +0000 (14:38 -0700)
committerSteve Scalpone <sscalpone@nvidia.com>
Tue, 27 Aug 2019 21:38:48 +0000 (14:38 -0700)
Initial markdown document.

Original-commit: flang-compiler/f18@787a0ca058dcfb3e0fe67262547d133773ed7d3a
Reviewed-on: https://github.com/flang-compiler/f18/pull/692
Tree-same-pre-rewrite: false

flang/documentation/OpenMP-semantics.md [new file with mode: 0644]

diff --git a/flang/documentation/OpenMP-semantics.md b/flang/documentation/OpenMP-semantics.md
new file mode 100644 (file)
index 0000000..a04d5e7
--- /dev/null
@@ -0,0 +1,650 @@
+# OpenMP Semantic Analysis
+
+## F18 for OpenMP
+
+1. Define and document the parse tree representation for
+    * Directives (listed below)
+    * Clauses (listed below)
+    * Documentation
+1. All the directives and clauses need source provenance for messages
+1. Define and document how an OpenMP directive in the parse tree
+will be represented as the parent of the statement(s)
+to which the directive applies.
+The parser itself will not be able to construct this representation;
+there will be subsequent passes that do so
+just like for example _do-stmt_ and _do-construct_.
+1. Define and document the symbol table extensions
+1. Define and document the module file extensions
+
+
+### Directives
+
+OpenMP divides directives into three categories as follows.
+The directives that are in the same categories share some characteristics.
+
+
+
+#### Declarative directives
+
+An OpenMP directive that may only be placed in a declarative context.
+A declarative directive results in one or more declarations only;
+it is not associated with the immediate execution of any user code.
+
+List of existing ones:
+* declare simd
+* declare target
+* threadprivate
+* declare reduction
+
+There is a parser node for each of these directives and
+the parser node saves information associated with the directive,
+for example,
+the name of the procedure-name in the `declare simd` directive.
+
+Each parse tree node keeps source provenance,
+one for the directive name itself and
+one for the entire directive starting from the directive name.
+
+A top-level class, `OpenMPDeclarativeConstruct`,
+holds all four of the node types as discriminated unions
+along with the source provenance for the entire directive
+starting from `!$OMP`.
+
+In the `parser-tree.h`,
+`OpenMPDeclarativeConstruct` is part
+of the `SpecificationConstruct` and `SpecificationPart`
+in F18 because
+a declarative directive can only be placed in the specification part
+of a Fortran program.
+
+All the `_Names` or `_Designators` associated
+with the declarative directive will be resolved in later phases.
+
+#### Executable directives
+
+An OpenMP directive that is **not** declarative.
+That is, it may only be placed in an executable context.
+It contains stand-alone directives and constructs
+that are associated with code blocks.
+The stand-alone directive is described in the next section.
+
+The constructs associated with code blocks listed below
+share a similar structure:
+_Begin Directive_, _Clause List_, _Code Block_, _End Directive_.
+The _End Directive_ is optional for constructs
+like Loop-associated constructs.
+
+* Block-associated constructs (`OpenMPBlockConstruct`)
+* Loop-associated constructs (`OpenMPLoopConstruct`)
+* Atomic construct (`OpenMPAtomicConstruct`)
+* Sections Construct (`OpenMPSectionsConstruct`,
+  contains Sections/Parallel Sections constructs)
+* Critical Construct (`OpenMPCriticalConstruct`)
+
+A top-level class, `OpenMPConstruct`,
+includes stand-alone directive and constructs
+listed above as discriminated unions.
+
+In the `parse-tree.h`, `OpenMPConstruct` is an element
+of the `ExecutableConstruct`.
+
+All the `_Names` or `_Designators` associated
+with the executable directive will be resolved in Semantic Analysis.
+
+When the backtracking parser can not identify the associated code blocks,
+the parse tree will be rewritten later in the Semantics Analysis.
+
+#### Stand-alone Directives
+
+An OpenMP executable directive that has no associated user code
+except for that which appears in clauses in the directive.
+
+List of existing ones:
+* taskyield
+* barrier
+* taskwait
+* target enter data
+* target exit data
+* target update
+* ordered
+* flush
+* cancel
+* cancellation point
+
+A higher-level class is created for each categorys
+which contains directives listed above that share a similar structure:
+* OpenMPSimpleStandaloneConstruct
+(taskyield, barrier, taskwait,
+target enter/exit data, target update, ordered)
+* OpenMPFlushConstruct
+* OpenMPCancelConstruct
+* OpenMPCancellationPointConstruct
+
+A top-level class, `OpenMPStandaloneConstruct`,
+holds all four of the node types as discriminated unions
+along with the source provenance for the entire directive.
+Also, each parser node for the stand-alone directive saves
+the source provenance for the directive name itself.
+
+### Clauses
+
+Each clause represented as a distinct class in `parse-tree.h`.
+A top-level class, `OmpClause`, includes all the clauses as discriminated unions. The parser node for `OmpClause` saves the source provenance for the entire clause.
+
+All the `_Names` or `_Designators` associated
+with the clauses will be resolved in Semantic Analysis.
+
+Note that the backtracking parser will not validate
+that the list of clauses associated
+with a directive is valid other than to make sure they are well-formed.
+In particular,
+the parser does not check that
+the association between directive and clauses is correct
+nor check that the values in the directives or clauses are correct.
+These checks are deferred to later phases of semantics to simplify the parser.
+
+## Symbol Table Extensions for OpenMP
+
+Name resolution can be impacted by the OpenMP code.
+In addition to the regular steps to do the name resolution,
+new scopes and symbols may need to be created
+when encountering certain OpenMP constructs.
+This section describes the extensions
+for OpenMP during Symbol Table construction.
+
+OpenMP uses the fork-join model of parallel execution and
+all OpenMP threads have access to
+a _shared_ memory place to store and retrieve variables
+but each thread can also have access to
+its _threadprivate_ memory that must not be accessed by other threads.
+
+For the directives and clauses that can control the data environments,
+compiler needs to determine two kinds of _access_
+to variables used in the directive’s associated structured block:
+**shared** and **private**.
+Each variable referenced in the structured block
+has an original variable immediately outside of the OpenMP constructs. Reference to a shared variable in the structured block
+becomes a reference to the original variable.
+However, each private variable referenced in the structured block,
+a new version of the original variable (of the same type and size)
+will be created in the threadprivate memory.
+
+There are exceptions that directives/clauses
+need to create a new `Symbol` without creating a new `Scope`,
+but in general,
+when encountering each of the data environment controlling directives
+(discussed in the following sections),
+a new `Scope` will be created.
+For each private variable referenced in the structured block,
+a new `Symbol` is created out of the original variable
+and the new `Symbol` is associated
+with original variable’s `Symbol` via `HostAssocDetails`.
+A new set of OpenMP specific flags are added
+into `Flag` class in `symbol.h` to indicate the types of
+associations,
+data-sharing attributes,
+and data-mapping attributes
+in the OpenMP data environments.
+
+### New Symbol without new Scope
+
+OpenMP directives that require new `Symbol` to be created
+but not new `Scope` are listed in the following table
+in terms of the Symbol Table extensions for OpenMP:
+
+<table>
+  <tr>
+   <td rowspan="2" colspan="2" >Directives/Clauses
+   </td>
+   <td rowspan="2" >Create New
+<p>
+Symbol
+<p>
+w/
+   </td>
+   <td colspan="2" >Add Flag
+   </td>
+  </tr>
+  <tr>
+   <td>on Symbol of
+   </td>
+   <td>Flag
+   </td>
+  </tr>
+  <tr>
+   <td rowspan="4" >Declarative Directives
+   </td>
+   <td>declare simd [(proc-name)]
+   </td>
+   <td>-
+   </td>
+   <td>The name of the enclosing function, subroutine, or interface body to which it applies, or proc-name
+   </td>
+   <td>OmpDeclareSimd
+   </td>
+  </tr>
+  <tr>
+   <td>declare target
+   </td>
+   <td>-
+   </td>
+   <td>The name of the enclosing function, subroutine, or interface body to which it applies
+   </td>
+   <td>OmpDeclareTarget
+   </td>
+  </tr>
+  <tr>
+   <td>threadprivate(list)
+   </td>
+   <td>-
+   </td>
+   <td>named variables and named common blocks
+   </td>
+   <td>OmpThreadPrivate
+   </td>
+  </tr>
+  <tr>
+   <td>declare reduction
+   </td>
+   <td>*
+   </td>
+   <td>reduction-identifier
+   </td>
+   <td>OmpDeclareReduction
+   </td>
+  </tr>
+  <tr>
+   <td>Stand-alone directives
+   </td>
+   <td>flush
+   </td>
+   <td>-
+   </td>
+   <td>variable, array section or common block name
+   </td>
+   <td>OmpFlushed
+   </td>
+  </tr>
+  <tr>
+   <td colspan="2" >critical [(name)]
+   </td>
+   <td>-
+   </td>
+   <td>name (user-defined identifier)
+   </td>
+   <td>OmpCriticalLock
+   </td>
+  </tr>
+  <tr>
+   <td colspan="2" >if ([ directive-name-modifier :] scalar-logical-expr)
+   </td>
+   <td>-
+   </td>
+   <td>directive-name-modifier
+   </td>
+   <td>OmpIfSpecified
+   </td>
+  </tr>
+</table>
+
+
+      -      No Action
+
+      *      Discussed in “Module File Extensions for OpenMP” section
+
+
+### New Symbol with new Scope
+
+For the following OpenMP regions:
+
+* `target` regions
+* `teams` regions
+* `parallel` regions
+* `simd` regions
+* task generating regions (created by `task` or `taskloop` constructs)
+* worksharing regions
+(created by `do`, `sections`, `single`, or `workshare` constructs)
+
+A new `Scope` will be created
+when encountering the above OpenMP constructs
+to ensure the correct data environment during the Code Generation.
+To determine whether a variable referenced in these regions
+needs the creation of a new `Symbol`,
+all the data-sharing attribute rules
+described in OpenMP Spec [2.15.1] apply during the Name Resolution.
+The available data-sharing attributes are:
+**_shared_**,
+**_private_**,
+**_linear_**,
+**_firstprivate_**,
+and **_lastprivate_**.
+The attribute is represented as `Flag` in the `Symbol` object.
+
+More details are listed in the following table:
+
+<table>
+  <tr>
+   <td rowspan="2" >Attribute
+   </td>
+   <td rowspan="2" >Create New Symbol
+   </td>
+   <td colspan="2" >Add Flag
+   </td>
+  </tr>
+  <tr>
+   <td>on Symbol of
+   </td>
+   <td>Flag
+   </td>
+  </tr>
+  <tr>
+   <td>shared
+   </td>
+   <td>No
+   </td>
+   <td>Original variable
+   </td>
+   <td>OmpShared
+   </td>
+  </tr>
+  <tr>
+   <td>private
+   </td>
+   <td>Yes
+   </td>
+   <td>New Symbol
+   </td>
+   <td>OmpPrivate
+   </td>
+  </tr>
+  <tr>
+   <td>linear
+   </td>
+   <td>Yes
+   </td>
+   <td>New Symbol
+   </td>
+   <td>OmpLinear
+   </td>
+  </tr>
+  <tr>
+   <td>firstprivate
+   </td>
+   <td>Yes
+   </td>
+   <td>New Symbol
+   </td>
+   <td>OmpFirstPrivate
+   </td>
+  </tr>
+  <tr>
+   <td>lastprivate
+   </td>
+   <td>Yes
+   </td>
+   <td>New Symbol
+   </td>
+   <td>OmpLastPrivate
+   </td>
+  </tr>
+</table>
+
+To determine the right data-sharing attribute,
+OpenMP defines that the data-sharing attributes
+of variables that are referenced in a construct can be
+_predetermined_, _explicitly determined_, or _implicitly determined_.
+
+#### Predetermined data-sharing attributes
+
+* Assumed-size arrays are **shared**
+* The loop iteration variable(s)
+in the associated _do-loop(s)_ of a
+_do_,
+_parallel do_,
+_taskloop_,
+or _distributeconstruct_
+is (are) **private**
+* A loop iteration variable
+for a sequential loop in a _parallel_ or task generating construct
+is **private** in the innermost such construct that encloses the loop
+* Implied-do indices and _forall_ indices are **private**
+* The loop iteration variable in the associated _do-loop_
+of a _simd_ construct with just one associated _do-_taskloop_
+is **linear** with a linear-step
+that is the increment of the associated _do-loop_
+* The loop iteration variables in the associated _do-loop(s)_ of a _simd_
+construct with multiple associated _do-loop(s)_ are **lastprivate**
+
+#### Explicitly determined data-sharing attributes
+
+Variables with _explicitly determined_ data-sharing attributes are:
+
+* Variables are referenced in a given construct
+* Variables are listed in a data-sharing attribute clause on the construct.
+
+The data-sharing attribute clauses are:
+* _default_ clause
+(discussed in “Implicitly determined data-sharing attributes”)
+* _shared_ clause
+* _private_ clause
+* _linear_ clause
+* _firstprivate_ clause
+* _lastprivate_ clause
+* _reduction_ clause
+(new `Symbol` created with the flag `OmpReduction` set)
+
+Note that variables with _predetermined_ data-sharing attributes
+may not be listed (with exceptions) in data-sharing attribute clauses.
+
+#### Implicitly determined data-sharing attributes
+
+Variables with implicitly determined data-sharing attributes are:
+
+* Variables are referenced in a given construct
+* Variables do not have _predetermined_ data-sharing attributes
+* Variables are not listed in a data-sharing attribute clause
+on the construct.
+
+Rules for variables with _implicitly determined_ data-sharing attributes:
+
+* In a _parallel_ construct, if no _default_ clause is present,
+these variables are **shared**
+* In a task generating construct,
+if no _default_ clause is present,
+a variable for which the data-sharing attribute
+is not determined by the rules above
+and that in the enclosing context is determined
+to be shared by all implicit tasks
+bound to the current team is **shared**
+* In a _target_ construct,
+variables that are not mapped after applying data-mapping attribute rules
+(discussed later) are **firstprivate**
+* In an orphaned task generating construct,
+if no _default_ clause is present, dummy arguments are **firstprivate**
+* In a task generating construct, if no _default_ clause is present,
+a variable for which the data-sharing attribute is not determined
+by the rules above is **firstprivate**
+* For constructs other than task generating constructs or _target_constructs,
+if no _default_ clause is present,
+these variables reference the variables with the same names
+that exist in the enclosing context
+* In a _parallel_, _teams_, or task generating construct,
+the data-sharing attributes of these variables are determined
+by the _default_clause, if present:
+    * _default(shared)_
+    clause causes all variables referenced in the construct
+    that have _implicitly determined_ data-sharing attributes
+    to be **shared**
+    * _default(private)_
+    clause causes all variables referenced in the construct
+    that have _implicitly determined_ data-sharing attributes
+    to be **private**
+    * _default(firstprivate)_
+    clause causes all variables referenced in the construct
+    that have _implicitly determined_ data-sharing attributes
+    to be **firstprivate**
+    * _default(none)_
+    clause requires that each variable
+    that is referenced in the construct,
+    and that does not have a _predetermined_ data-sharing attribute,
+    must have its data-sharing attribute _explicitly determined_
+    by being listed in a data-sharing attribute clause
+
+
+### Data-mapping Attribute
+
+When encountering the _target data_ and _target_ directives,
+the data-mapping attributes of any variable referenced in a target region
+will be determined and represented as `Flag` in the `Symbol` object
+of the variable.
+No `Symbol` or `Scope` will be created.
+
+The basic steps to determine the data-mapping attribute are:
+
+1. If _map_ clause is present,
+the data-mapping attribute is determined by the _map-type_
+on the clause and its corresponding `Flag` are listed below:
+
+<table>
+  <tr>
+   <td>
+data-mapping attribute
+   </td>
+   <td>Flag
+   </td>
+  </tr>
+  <tr>
+   <td>to
+   </td>
+   <td>OmpMapTo
+   </td>
+  </tr>
+  <tr>
+   <td>from
+   </td>
+   <td>OmpMapFrom
+   </td>
+  </tr>
+  <tr>
+   <td>tofrom \
+(default if map-type is not present)
+   </td>
+   <td>OmpMapTo & OmpMapFrom
+   </td>
+  </tr>
+  <tr>
+   <td>alloc
+   </td>
+   <td>OmpMapAlloc
+   </td>
+  </tr>
+  <tr>
+   <td>release
+   </td>
+   <td>OmpMapRelease
+   </td>
+  </tr>
+  <tr>
+   <td>delete
+   </td>
+   <td>OmpMapDelete
+   </td>
+  </tr>
+</table>
+
+2. Otherwise, the following data-mapping rules apply
+for variables referenced in a _target_ construct
+that are _not_ declared in the construct and
+do not appear in data-sharing attribute or map clauses:
+    * If a variable appears in a _to _or _link _clause on a _declare target _directive then it is treated as if it had appeared in a _map _clause with a _map-type_ of **tofrom**
+3. Otherwise, the following implicit data-mapping attribute rules apply:
+    * If a _defaultmap(tofrom:scalar)_ clause is _not_ present
+    then a scalar variable is not mapped,
+    but instead has an implicit data-sharing attribute of **firstprivate**
+    * If a _defaultmap(tofrom:scalar)_ clause is present
+    then a scalar variable is treated as if it had appeared
+    in a map clause with a map-type of **tofrom**
+    * If a variable is not a scalar
+    then it is treated as if it had appeared in a map clause
+    with a _map-type_ of **tofrom**
+
+After the completion of the Name Resolution phase, all the data-sharing or data-mapping attributes marked for the `Symbols` may be used later in the Semantics Analysis and in the Code Generation.
+
+## Module File Extensions for OpenMP
+
+After the successful compilation of modules and submodules that may contain the following Declarative Directives, the entire directive starts from `!$OMP` needs to be written out into `.mod` files in their corresponding Specification Part:
+
+* _declare simd_ or _declare target_
+
+    In the “New Symbol without new Scope” section,
+    we described that when encountering these two declarative directives,
+    new `Flag` will be applied to the Symbol of the name of
+    the enclosing function, subroutine, or interface body to
+    which it applies, or proc-name.
+    This `Flag` should be part of the API information
+    for the given subroutine or function
+
+* _declare reduction_
+
+    The _reduction-identifier_ in this directive
+    can be use-associated or host-associated.
+    However, it will not act like other Symbols
+    because user may have a reduction name
+    that is the same as a Fortran entity name in the same scope.
+    Therefore a specific data structure needs to be created
+    to save the _reduction-identifier_ information
+    in the Scope and this directive needs to be written into `.mod` files
+
+## Phases of OpenMP Analysis
+
+1. Create the parse tree for OpenMP
+    1. Add types for directives and clauses.
+        1. Add type(s) that will be used for directives
+        2. Add type(s) that will be used for clauses
+        3. Add other types, e.g. wrappers or other containers
+        4. Use std::variant to encapsulate meaningful types
+    2. Implemented in the parser for OpenMP (openmp-grammar.h)
+2. Create canonical nesting
+    1. Restructure parse tree to reflect the association
+    of directives and stmts
+        1. Associate `OpenMPLoopConstruct`
+        with `DoConstruct` and `OpenMPEndLoopDirective`
+    1. Investigate, and perhaps reuse,
+    the algorithm used to restructure do-loops
+    2. Add a pass near the code that restructures do-loops;
+    but do not extend the code that handles do-loop for OpenMP;
+    keep this code separate.
+    3. Report errors that prevent restructuring
+    (e.g. loop directive not followed by loop)
+    We should abort in case of errors
+    because there is no point to perform further checks
+    if it is not a legal OpenMP construct
+    4. N.B. Consider moving this code and the do-loops code to the parser namespace.
+3. Validate the structured-block
+    1. Structured-block is a block of executable statements
+    1. Single entry and single exit
+    1. Access to the structured block must not be the result of a branch
+    1. The point of exit cannot be a branch out of the structured block
+4. Check that directive and clause combinations are legal
+    1. Begin and End directive should match
+    1. Simply check that the clauses are allowed by the directives
+    1. Write as a separate pass for simplicity and correctness of the parse tree
+5. Write parse tree tests
+    1. At this point, the parse tree should be perfectly formed
+    1. Write tests that check for correct form and provenance information
+    1. Write tests for errors that can occur during the restructuring
+6. Scope, symbol tables, and name resolution
+    1. Update the existing code to handle names and scopes introduced by OpenMP
+    1. Write tests to make sure names are properly implemented
+7. Check semantics that is specific to each directive
+    1. Validate the directive and its clauses
+    1. Some clause checks require the result of name resolution,
+    i.e. “A list item may appear in a _linear_ or _firstprivate_ clause
+    but not both.”
+    1. TBD:
+    Validate the nested statement for legality in the scope of the directive
+    1. Check the nesting of regions [OpenMP 4.5 spec 2.17]
+8. Module file utilities
+    1.  Write necessary OpenMP declarative directives to `.mod` files
+    2. Update the existing code
+    to read available OpenMP directives from the `.mod` files