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