diff --git a/src/doc/reference/opencilk-language-specification.md b/src/doc/reference/opencilk-language-specification.md index 8b076f6e..7a805054 100644 --- a/src/doc/reference/opencilk-language-specification.md +++ b/src/doc/reference/opencilk-language-specification.md @@ -1,15 +1,20 @@ --- layout: layouts/page.njk +author: Dorothy Curtis stylesheet: language-specification.css title: OpenCilk language specification +tagline: For people who need to know grammatical details about how Cilk is + integrated with C. date: 2022-07-14T21:37:03.433Z +tags: + - Grammar eleventyNavigation: key: Language specification +attribution: true --- -
Copyright © 2020, 2021 Massachusetts Institute of Technology. All rights reserved.
+Copyright © 2020, 2021, 2022 Massachusetts Institute of Technology. All rights reserved.
More information about OpenCilk can be found at opencilk.org
Feedback on this specification is encouraged and welcome; please send to
@@ -73,14 +78,13 @@ eleventyNavigation:
A program that uses these keywords other than as defined in the grammar extension
below is ill-formed. The three keywords are used in the following new productions: The four keywords are used in the following new productions:cilk_for
cilk_sync
cilk_spawn
cilk_sync ;
The serialization of a pure C or C++ program is itself.
If a C or C++ program has defined behavior and does not use the tasking keywords or library functions, it is an OpenCilk with the same defined behavior.
-The serializations of The serializations of If an OpenCilk program has defined deterministic behavior, then that behavior is
the same as the behavior of the C or C++ program derived from the original by removing
@@ -671,9 +682,9 @@ else ((first) The call to function If a statement is followed by an implicit sync, that sync is the spawn continuation. Programmer note: The sequencing may be more clear if Cilk Plus defines a category of objects called “hyperobjects”.
- Hyperobjects allow thread-safe access to shared objects by giving each Parallel code uses a hyperobject by performing a hyperobject lookup operation.
- The hyperobject lookup returns a reference to an object, called a view,
- that is guaranteed not to be shared with any other active strands in the program.
- The sequencing of a hyperobject lookup within an expression is not specified. The
- runtime system creates a view when needed, using callback functions provided by
- the hyperobject type. When strands synchronize, the hyperobject views are merged
- into a single view, using another callback function provided by the hyperobject
- type. The view of a hyperobject visible to a program may change at any spawn or sync (including
- the implicit spawns and syncs within a Programmer note: If two expressions compute the same address for a view,
- then they have not been scheduled in parallel. This property yields one of the simplest
- ways by which a program can observe the runtime behavior of the scheduler. Implementation note: An implementation can optimize hyperobject lookups
- by performing them only when a view has (or might have) changed. This optimization
- can be facilitated by attaching implementation-specific attributes to the hyperobject
- creation, lookup, and/or destruction operations. The vast majority of hyperobjects belong to a category known as “reducers.”
- Each reducer type provides a The Given a set of strands entering a sync, S1,S2,S3,…Sn,
- associated with views V1,V2,V3,…Vn,
- respectively such that Si is earlier in the serial ordering
- than Si+1, a single view, W, emerges from the sync
- with value W←V1⊗V2⊗V3⊗…⊗Vn,
- such that the left-to-right order is maintained but the grouping (associativity)
- of the operations is unspecified. The timing of this “reduction” is
- unspecified – in particular, subsequences typically will be computed asynchronously
- as child tasks complete. Every view except the one emerging from the sync is destroyed
- after the merge. If any of the strands does not have an associated view, then the
- invocation of the A strand is never associated with more than one view for a given reducer, but multiple
- strands can be associated with the same view if those strands are not scheduled
- in parallel (at run time). Specifically, for a given reducer, the association of
- a strand to a view of the reducer obeys the following rules: Even before the final reduction, the leftmost view of a reducer will contain the
- same value as in the serial execution. Other views, however, will contain partial
- values that are different from the serial execution. If ⊗ is not associative or if Copyright (c) 2020 Massachusetts Institute of Technologycilk_spawn
and cilk_sync
+
+cilk_scope
, cilk_spawn
and cilk_sync
are empty.-
(limit)) /
f
is the spawn point and the statement a++;
is the continuation. The expression a + b
and the initialization of
- the temporary variable holding that value, and the evaluation of x\[g()]
+ the temporary variable holding that value, and the evaluation of x\\\\\\\[g()]
take place before the spawn point. The execution of f
, the assignment
- to x\[g()]
, and the destruction of the temporary variable holding
+ to
x\\\\\\\[g()]
, and the destruction of the temporary variable holding
a + b
take place in the child.parallel
- strand running in parallel a separate instance of the object.cilk_for
loop). The identity
- (address) of the view does not change within a single strand. The view of a given
- hyperobject visible within a given strand is said to be associated with
- that view. A hyperobject has the same view before the first spawn within a task
- block as after a sync within the same task block, even though the thread ID may
- not be the same (i.e., hyperobject views are not tied to threads). A hyperobject
- has the same view upon entering and leaving a cilk_for
loop and within
- the first iteration (at least) of the cilk_for
loop. A special view
- is associated with a hyperobject when the hyperobject is initially created. This
- special view is called the leftmost view or earliest view
- because it is always visible to the leftmost (earliest) descendent in the depth-first,
- left-to-right traversal of the program's spawn tree. The leftmost view is given
- an initial value when the hyperobject is created.reduce
callback operation that merges
- two views in a manner specific to the reducer. For a pair of views V1
- and V2, the result of calling reduce(
V1,
- V2)
is notated as V1⊗V2.
- Each reducer also provides an identity
callback operation that initializes
- a new view.reduce
callback for a “classical” reducer implements
- an operation ⊗ such that (a⊗b)⊗c==a⊗(b⊗c)
- (i.e., ⊗ is associative). The view-initialization callback for such a reducer
- sets the view to an identity value I such that I⊗v==v
- and v⊗I==v for any value v of value_type.
- Given an associative ⊗ and an identity I, the triplet (value_type,
- ⊗, I) describes a mathematical monoid. For example,
- (int
, +
, 0
) is a monoid, as is (list
,
- concatenate
, empty). If each individual view, R,
- of a classical reducer is modified using only expressions that are equivalent to
- R←R⊗v (where v is of
- value_type), then the reducer computes the same value in the parallel
- program as would be computed in the serialization of the program. (In actuality,
- the “⊗” in the expression “R←R⊗v”
- can represent a set of mutually-associative operations. For example, +=
- and -=
are mutually associative.) For example, a spawned function or
- cilk_for
body can append items onto the view of a list reducer with
- monoid (list
, concatenate
, empty). At the end
- of the parallel section of code, the reducer's view contains the same list items
- in the same order as would be generated in a serial execution of the same code.reduce
callback function can be elided (i.e., the
- missing view is treated as an identity).
-
-identity
.
- The implementation may create the new view at any time up until the first hyperobject
- lookup following the spawn. If the continuation strand does not perform a hyperobject
- lookup, then the implementation is not required to create a view for that strand.identity
does not yield a true
- identity value then the result of a set of reductions will be non-deterministic
- (i.e., it will vary based on runtime scheduling). Such “non-classical”
- reducers are nevertheless occasionally useful. Note that, for a classical reducer,
- the ⊗ operator needs to be associative, but does not need to be commutative.