1<!--===- docs/OpenMP-semantics.md
2
3   Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4   See https://llvm.org/LICENSE.txt for license information.
5   SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
7-->
8
9# OpenMP Semantic Analysis
10
11## OpenMP for F18
12
131. Define and document the parse tree representation for
14    * Directives (listed below)
15    * Clauses (listed below)
16    * Documentation
171. All the directives and clauses need source provenance for messages
181. Define and document how an OpenMP directive in the parse tree
19will be represented as the parent of the statement(s)
20to which the directive applies.
21The parser itself will not be able to construct this representation;
22there will be subsequent passes that do so
23just like for example _do-stmt_ and _do-construct_.
241. Define and document the symbol table extensions
251. Define and document the module file extensions
26
27
28### Directives
29
30OpenMP divides directives into three categories as follows.
31The directives that are in the same categories share some characteristics.
32
33
34
35#### Declarative directives
36
37An OpenMP directive may only be placed in a declarative context.
38A declarative directive results in one or more declarations only;
39it is not associated with the immediate execution of any user code.
40
41List of existing ones:
42* declare simd
43* declare target
44* threadprivate
45* declare reduction
46
47There is a parser node for each of these directives and
48the parser node saves information associated with the directive,
49for example,
50the name of the procedure-name in the `declare simd` directive.
51
52Each parse tree node keeps source provenance,
53one for the directive name itself and
54one for the entire directive starting from the directive name.
55
56A top-level class, `OpenMPDeclarativeConstruct`,
57holds all four of the node types as discriminated unions
58along with the source provenance for the entire directive
59starting from `!$OMP`.
60
61In `parser-tree.h`,
62`OpenMPDeclarativeConstruct` is part
63of the `SpecificationConstruct` and `SpecificationPart`
64in F18 because
65a declarative directive can only be placed in the specification part
66of a Fortran program.
67
68All the `Names` or `Designators` associated
69with the declarative directive will be resolved in later phases.
70
71#### Executable directives
72
73An OpenMP directive that is **not** declarative.
74That is, it may only be placed in an executable context.
75It contains stand-alone directives and constructs
76that are associated with code blocks.
77The stand-alone directive is described in the next section.
78
79The constructs associated with code blocks listed below
80share a similar structure:
81_Begin Directive_, _Clause List_, _Code Block_, _End Directive_.
82The _End Directive_ is optional for constructs
83like Loop-associated constructs.
84
85* Block-associated constructs (`OpenMPBlockConstruct`)
86* Loop-associated constructs (`OpenMPLoopConstruct`)
87* Atomic construct (`OpenMPAtomicConstruct`)
88* Sections Construct (`OpenMPSectionsConstruct`,
89  contains Sections/Parallel Sections constructs)
90* Critical Construct (`OpenMPCriticalConstruct`)
91
92A top-level class, `OpenMPConstruct`,
93includes stand-alone directive and constructs
94listed above as discriminated unions.
95
96In the `parse-tree.h`, `OpenMPConstruct` is an element
97of the `ExecutableConstruct`.
98
99All the `Names` or `Designators` associated
100with the executable directive will be resolved in Semantic Analysis.
101
102When the backtracking parser can not identify the associated code blocks,
103the parse tree will be rewritten later in the Semantics Analysis.
104
105#### Stand-alone Directives
106
107An OpenMP executable directive that has no associated user code
108except for that which appears in clauses in the directive.
109
110List of existing ones:
111* taskyield
112* barrier
113* taskwait
114* target enter data
115* target exit data
116* target update
117* ordered
118* flush
119* cancel
120* cancellation point
121
122A higher-level class is created for each category
123which contains directives listed above that share a similar structure:
124* OpenMPSimpleStandaloneConstruct
125(taskyield, barrier, taskwait,
126target enter/exit data, target update, ordered)
127* OpenMPFlushConstruct
128* OpenMPCancelConstruct
129* OpenMPCancellationPointConstruct
130
131A top-level class, `OpenMPStandaloneConstruct`,
132holds all four of the node types as discriminated unions
133along with the source provenance for the entire directive.
134Also, each parser node for the stand-alone directive saves
135the source provenance for the directive name itself.
136
137### Clauses
138
139Each clause represented as a distinct class in `parse-tree.h`.
140A top-level class, `OmpClause`,
141includes all the clauses as discriminated unions.
142The parser node for `OmpClause` saves the source provenance
143for the entire clause.
144
145All the `Names` or `Designators` associated
146with the clauses will be resolved in Semantic Analysis.
147
148Note that the backtracking parser will not validate
149that the list of clauses associated
150with a directive is valid other than to make sure they are well-formed.
151In particular,
152the parser does not check that
153the association between directive and clauses is correct
154nor check that the values in the directives or clauses are correct.
155These checks are deferred to later phases of semantics to simplify the parser.
156
157## Symbol Table Extensions for OpenMP
158
159Name resolution can be impacted by the OpenMP code.
160In addition to the regular steps to do the name resolution,
161new scopes and symbols may need to be created
162when encountering certain OpenMP constructs.
163This section describes the extensions
164for OpenMP during Symbol Table construction.
165
166OpenMP uses the fork-join model of parallel execution and
167all OpenMP threads have access to
168a _shared_ memory place to store and retrieve variables
169but each thread can also have access to
170its _threadprivate_ memory that must not be accessed by other threads.
171
172For the directives and clauses that can control the data environments,
173compiler needs to determine two kinds of _access_
174to variables used in the directive’s associated structured block:
175**shared** and **private**.
176Each variable referenced in the structured block
177has an original variable immediately outside of the OpenMP constructs.
178Reference to a shared variable in the structured block
179becomes a reference to the original variable.
180However, each private variable referenced in the structured block,
181a new version of the original variable (of the same type and size)
182will be created in the threadprivate memory.
183
184There are exceptions that directives/clauses
185need to create a new `Symbol` without creating a new `Scope`,
186but in general,
187when encountering each of the data environment controlling directives
188(discussed in the following sections),
189a new `Scope` will be created.
190For each private variable referenced in the structured block,
191a new `Symbol` is created out of the original variable
192and the new `Symbol` is associated
193with original variable’s `Symbol` via `HostAssocDetails`.
194A new set of OpenMP specific flags are added
195into `Flag` class in `symbol.h` to indicate the types of
196associations,
197data-sharing attributes,
198and data-mapping attributes
199in the OpenMP data environments.
200
201### New Symbol without new Scope
202
203OpenMP directives that require new `Symbol` to be created
204but not new `Scope` are listed in the following table
205in terms of the Symbol Table extensions for OpenMP:
206
207<table>
208  <tr>
209   <td rowspan="2" colspan="2" >Directives/Clauses
210   </td>
211   <td rowspan="2" >Create New
212<p>
213Symbol
214<p>
215w/
216   </td>
217   <td colspan="2" >Add Flag
218   </td>
219  </tr>
220  <tr>
221   <td>on Symbol of
222   </td>
223   <td>Flag
224   </td>
225  </tr>
226  <tr>
227   <td rowspan="4" >Declarative Directives
228   </td>
229   <td>declare simd [(proc-name)]
230   </td>
231   <td>-
232   </td>
233   <td>The name of the enclosing function, subroutine, or interface body
234   to which it applies, or proc-name
235   </td>
236   <td>OmpDeclareSimd
237   </td>
238  </tr>
239  <tr>
240   <td>declare target
241   </td>
242   <td>-
243   </td>
244   <td>The name of the enclosing function, subroutine, or interface body
245   to which it applies
246   </td>
247   <td>OmpDeclareTarget
248   </td>
249  </tr>
250  <tr>
251   <td>threadprivate(list)
252   </td>
253   <td>-
254   </td>
255   <td>named variables and named common blocks
256   </td>
257   <td>OmpThreadPrivate
258   </td>
259  </tr>
260  <tr>
261   <td>declare reduction
262   </td>
263   <td>*
264   </td>
265   <td>reduction-identifier
266   </td>
267   <td>OmpDeclareReduction
268   </td>
269  </tr>
270  <tr>
271   <td>Stand-alone directives
272   </td>
273   <td>flush
274   </td>
275   <td>-
276   </td>
277   <td>variable, array section or common block name
278   </td>
279   <td>OmpFlushed
280   </td>
281  </tr>
282  <tr>
283   <td colspan="2" >critical [(name)]
284   </td>
285   <td>-
286   </td>
287   <td>name (user-defined identifier)
288   </td>
289   <td>OmpCriticalLock
290   </td>
291  </tr>
292  <tr>
293   <td colspan="2" >if ([ directive-name-modifier :] scalar-logical-expr)
294   </td>
295   <td>-
296   </td>
297   <td>directive-name-modifier
298   </td>
299   <td>OmpIfSpecified
300   </td>
301  </tr>
302</table>
303
304
305      -      No Action
306
307      *      Discussed in “Module File Extensions for OpenMP” section
308
309
310### New Symbol with new Scope
311
312For the following OpenMP regions:
313
314* `target` regions
315* `teams` regions
316* `parallel` regions
317* `simd` regions
318* task generating regions (created by `task` or `taskloop` constructs)
319* worksharing regions
320(created by `do`, `sections`, `single`, or `workshare` constructs)
321
322A new `Scope` will be created
323when encountering the above OpenMP constructs
324to ensure the correct data environment during the Code Generation.
325To determine whether a variable referenced in these regions
326needs the creation of a new `Symbol`,
327all the data-sharing attribute rules
328described in OpenMP Spec [2.15.1] apply during the Name Resolution.
329The available data-sharing attributes are:
330**_shared_**,
331**_private_**,
332**_linear_**,
333**_firstprivate_**,
334and **_lastprivate_**.
335The attribute is represented as `Flag` in the `Symbol` object.
336
337More details are listed in the following table:
338
339<table>
340  <tr>
341   <td rowspan="2" >Attribute
342   </td>
343   <td rowspan="2" >Create New Symbol
344   </td>
345   <td colspan="2" >Add Flag
346   </td>
347  </tr>
348  <tr>
349   <td>on Symbol of
350   </td>
351   <td>Flag
352   </td>
353  </tr>
354  <tr>
355   <td>shared
356   </td>
357   <td>No
358   </td>
359   <td>Original variable
360   </td>
361   <td>OmpShared
362   </td>
363  </tr>
364  <tr>
365   <td>private
366   </td>
367   <td>Yes
368   </td>
369   <td>New Symbol
370   </td>
371   <td>OmpPrivate
372   </td>
373  </tr>
374  <tr>
375   <td>linear
376   </td>
377   <td>Yes
378   </td>
379   <td>New Symbol
380   </td>
381   <td>OmpLinear
382   </td>
383  </tr>
384  <tr>
385   <td>firstprivate
386   </td>
387   <td>Yes
388   </td>
389   <td>New Symbol
390   </td>
391   <td>OmpFirstPrivate
392   </td>
393  </tr>
394  <tr>
395   <td>lastprivate
396   </td>
397   <td>Yes
398   </td>
399   <td>New Symbol
400   </td>
401   <td>OmpLastPrivate
402   </td>
403  </tr>
404</table>
405
406To determine the right data-sharing attribute,
407OpenMP defines that the data-sharing attributes
408of variables that are referenced in a construct can be
409_predetermined_, _explicitly determined_, or _implicitly determined_.
410
411#### Predetermined data-sharing attributes
412
413* Assumed-size arrays are **shared**
414* The loop iteration variable(s)
415in the associated _do-loop(s)_ of a
416_do_,
417_parallel do_,
418_taskloop_,
419or _distributeconstruct_
420is (are) **private**
421* A loop iteration variable
422for a sequential loop in a _parallel_ or task generating construct
423is **private** in the innermost such construct that encloses the loop
424* Implied-do indices and _forall_ indices are **private**
425* The loop iteration variable in the associated _do-loop_
426of a _simd_ construct with just one associated _do-loop_
427is **linear** with a linear-step
428that is the increment of the associated _do-loop_
429* The loop iteration variables in the associated _do-loop(s)_ of a _simd_
430construct with multiple associated _do-loop(s)_ are **lastprivate**
431
432#### Explicitly determined data-sharing attributes
433
434Variables with _explicitly determined_ data-sharing attributes are:
435
436* Variables are referenced in a given construct
437* Variables are listed in a data-sharing attribute clause on the construct.
438
439The data-sharing attribute clauses are:
440* _default_ clause
441(discussed in “Implicitly determined data-sharing attributes”)
442* _shared_ clause
443* _private_ clause
444* _linear_ clause
445* _firstprivate_ clause
446* _lastprivate_ clause
447* _reduction_ clause
448(new `Symbol` created with the flag `OmpReduction` set)
449
450Note that variables with _predetermined_ data-sharing attributes
451may not be listed (with exceptions) in data-sharing attribute clauses.
452
453#### Implicitly determined data-sharing attributes
454
455Variables with implicitly determined data-sharing attributes are:
456
457* Variables are referenced in a given construct
458* Variables do not have _predetermined_ data-sharing attributes
459* Variables are not listed in a data-sharing attribute clause
460on the construct.
461
462Rules for variables with _implicitly determined_ data-sharing attributes:
463
464* In a _parallel_ construct, if no _default_ clause is present,
465these variables are **shared**
466* In a task generating construct,
467if no _default_ clause is present,
468a variable for which the data-sharing attribute
469is not determined by the rules above
470and that in the enclosing context is determined
471to be shared by all implicit tasks
472bound to the current team is **shared**
473* In a _target_ construct,
474variables that are not mapped after applying data-mapping attribute rules
475(discussed later) are **firstprivate**
476* In an orphaned task generating construct,
477if no _default_ clause is present, dummy arguments are **firstprivate**
478* In a task generating construct, if no _default_ clause is present,
479a variable for which the data-sharing attribute is not determined
480by the rules above is **firstprivate**
481* For constructs other than task generating constructs or _target_ constructs,
482if no _default_ clause is present,
483these variables reference the variables with the same names
484that exist in the enclosing context
485* In a _parallel_, _teams_, or task generating construct,
486the data-sharing attributes of these variables are determined
487by the _default_ clause, if present:
488    * _default(shared)_
489    clause causes all variables referenced in the construct
490    that have _implicitly determined_ data-sharing attributes
491    to be **shared**
492    * _default(private)_
493    clause causes all variables referenced in the construct
494    that have _implicitly determined_ data-sharing attributes
495    to be **private**
496    * _default(firstprivate)_
497    clause causes all variables referenced in the construct
498    that have _implicitly determined_ data-sharing attributes
499    to be **firstprivate**
500    * _default(none)_
501    clause requires that each variable
502    that is referenced in the construct,
503    and that does not have a _predetermined_ data-sharing attribute,
504    must have its data-sharing attribute _explicitly determined_
505    by being listed in a data-sharing attribute clause
506
507
508### Data-mapping Attribute
509
510When encountering the _target data_ and _target_ directives,
511the data-mapping attributes of any variable referenced in a target region
512will be determined and represented as `Flag` in the `Symbol` object
513of the variable.
514No `Symbol` or `Scope` will be created.
515
516The basic steps to determine the data-mapping attribute are:
517
5181. If _map_ clause is present,
519the data-mapping attribute is determined by the _map-type_
520on the clause and its corresponding `Flag` are listed below:
521
522<table>
523  <tr>
524   <td>
525data-mapping attribute
526   </td>
527   <td>Flag
528   </td>
529  </tr>
530  <tr>
531   <td>to
532   </td>
533   <td>OmpMapTo
534   </td>
535  </tr>
536  <tr>
537   <td>from
538   </td>
539   <td>OmpMapFrom
540   </td>
541  </tr>
542  <tr>
543   <td>tofrom
544(default if map-type is not present)
545   </td>
546   <td>OmpMapTo & OmpMapFrom
547   </td>
548  </tr>
549  <tr>
550   <td>alloc
551   </td>
552   <td>OmpMapAlloc
553   </td>
554  </tr>
555  <tr>
556   <td>release
557   </td>
558   <td>OmpMapRelease
559   </td>
560  </tr>
561  <tr>
562   <td>delete
563   </td>
564   <td>OmpMapDelete
565   </td>
566  </tr>
567</table>
568
5692. Otherwise, the following data-mapping rules apply
570for variables referenced in a _target_ construct
571that are _not_ declared in the construct and
572do not appear in data-sharing attribute or map clauses:
573    * If a variable appears in a _to_ or _link_ clause
574    on a _declare target_ directive then it is treated
575    as if it had appeared in a _map_ clause with a _map-type_ of **tofrom**
5763. Otherwise, the following implicit data-mapping attribute rules apply:
577    * If a _defaultmap(tofrom:scalar)_ clause is _not_ present
578    then a scalar variable is not mapped,
579    but instead has an implicit data-sharing attribute of **firstprivate**
580    * If a _defaultmap(tofrom:scalar)_ clause is present
581    then a scalar variable is treated as if it had appeared
582    in a map clause with a map-type of **tofrom**
583    * If a variable is not a scalar
584    then it is treated as if it had appeared in a map clause
585    with a _map-type_ of **tofrom**
586
587After the completion of the Name Resolution phase,
588all the data-sharing or data-mapping attributes marked for the `Symbols`
589may be used later in the Semantics Analysis and in the Code Generation.
590
591## Module File Extensions for OpenMP
592
593After the successful compilation of modules and submodules
594that may contain the following Declarative Directives,
595the entire directive starting from `!$OMP` needs to be written out
596into `.mod` files in their corresponding Specification Part:
597
598* _declare simd_ or _declare target_
599
600    In the “New Symbol without new Scope” section,
601    we described that when encountering these two declarative directives,
602    new `Flag` will be applied to the Symbol of the name of
603    the enclosing function, subroutine, or interface body to
604    which it applies, or proc-name.
605    This `Flag` should be part of the API information
606    for the given subroutine or function
607
608* _declare reduction_
609
610    The _reduction-identifier_ in this directive
611    can be use-associated or host-associated.
612    However, it will not act like other Symbols
613    because user may have a reduction name
614    that is the same as a Fortran entity name in the same scope.
615    Therefore a specific data structure needs to be created
616    to save the _reduction-identifier_ information
617    in the Scope and this directive needs to be written into `.mod` files
618
619## Phases of OpenMP Analysis
620
6211. Create the parse tree for OpenMP
622    1. Add types for directives and clauses
623        1. Add type(s) that will be used for directives
624        2. Add type(s) that will be used for clauses
625        3. Add other types, e.g. wrappers or other containers
626        4. Use std::variant to encapsulate meaningful types
627    2. Implemented in the parser for OpenMP (openmp-grammar.h)
6282. Create canonical nesting
629    1. Restructure parse tree to reflect the association
630    of directives and stmts
631        1. Associate `OpenMPLoopConstruct`
632        with `DoConstruct` and `OpenMPEndLoopDirective`
633    1. Investigate, and perhaps reuse,
634    the algorithm used to restructure do-loops
635    2. Add a pass near the code that restructures do-loops;
636    but do not extend the code that handles do-loop for OpenMP;
637    keep this code separate.
638    3. Report errors that prevent restructuring
639    (e.g. loop directive not followed by loop)
640    We should abort in case of errors
641    because there is no point to perform further checks
642    if it is not a legal OpenMP construct
6433. Validate the structured-block
644    1. Structured-block is a block of executable statements
645    1. Single entry and single exit
646    1. Access to the structured block must not be the result of a branch
647    1. The point of exit cannot be a branch out of the structured block
6484. Check that directive and clause combinations are legal
649    1. Begin and End directive should match
650    1. Simply check that the clauses are allowed by the directives
651    1. Write as a separate pass for simplicity and correctness of the parse tree
6525. Write parse tree tests
653    1. At this point, the parse tree should be perfectly formed
654    1. Write tests that check for correct form and provenance information
655    1. Write tests for errors that can occur during the restructuring
6566. Scope, symbol tables, and name resolution
657    1. Update the existing code to handle names and scopes introduced by OpenMP
658    1. Write tests to make sure names are properly implemented
6597. Check semantics that is specific to each directive
660    1. Validate the directive and its clauses
661    1. Some clause checks require the result of name resolution,
662    i.e. “A list item may appear in a _linear_ or _firstprivate_ clause
663    but not both.”
664    1. TBD:
665    Validate the nested statement for legality in the scope of the directive
666    1. Check the nesting of regions [OpenMP 4.5 spec 2.17]
6678. Module file utilities
668    1.  Write necessary OpenMP declarative directives to `.mod` files
669    2. Update the existing code
670    to read available OpenMP directives from the `.mod` files
671