The `ALIGN` directive is used to specify that certain data
objects are to be mapped in the same way as certain other data
objects. Operations between aligned data objects are likely to be
more efficient than operations between data objects that are not known
to be aligned (because two objects that are aligned are intended to be
mapped to the same abstract processor). The `ALIGN` directive
is designed to make it particularly easy to specify explicit mappings
for all the elements of an array at once. While objects can be
aligned in some cases through careful use of matching
`DISTRIBUTE` directives, `ALIGN` is more general and
frequently more convenient.

The `ALIGN` directive may appear only in the
*specification-part* of a scoping unit and can contain only a
*specification-expr* as a *subscript* or in a
*subscript-triplet*.

The syntax of `ALIGN` is as follows:

H313 align-directive isALIGNalignee align-directive-stuffH314 align-directive-stuff is(align-source-list)align-with-clauseH315 align-attribute-stuff is[ (align-source-list) ]align-with-clauseH316 alignee isobject-nameH317 align-source is:

or*

oralign-dummyH318 align-dummy isscalar-int-variable

- An
*object-name*mentioned as an*alignee*must be a simple name and not a subobject designator or a*component-name*. - An
*object-name*mentioned as an*alignee*may not appear as a*distributee*. - An
*object-name*mentioned as an*alignee*may not have the`POINTER`attribute. - An
*object-name*mentioned as an*alignee*may not have the`TARGET`attribute. - If the
*alignee*is scalar, the*align-source-list*(and its surrounding parentheses) must not appear. In this case the statement form of the directive is not allowed. - If the
*align-source-list*is present, its length must equal the rank of each*alignee*to which it applies. - An
*align-dummy*must be a named variable. - An object may not have both the
`INHERIT`attribute and the`ALIGN`attribute.

*Advice to users.*Some of the above constraints are relaxed under the approvedextensions (see Section 8): mapping of derived type components (relaxes constraint 1) and mapping of pointers and targets (relaxes constraints 3 and 4). (

*End of advice to users.*)

Note that the possibility of an `ALIGN` directive of the form

is covered by syntax rule H301 for a!HPF$ ALIGNalign-attribute-stuff::alignee-list

The statement form of an `ALIGN` directive may be considered an abbreviation of an attributed form hat happens to mention only one *alignee*:

is equivalent to!HPF$ ALIGNalignee(align-source-list) WITHalign-spec

!HPF$ ALIGN (align-source-list) WITHalign-spec::alignee

If the *align-source-list* is omitted from the attributed form and the *alignees* are not scalar, the *align-source-list* is assumed to consist of a parenthesized list of ":" entries, equal in number to the rank of the *alignees*. Similarly, if the *align-subscript-list* is omitted from the *align-spec* in either form, it is assumed to consist of a parenthesized list of ":" entries, equal in number to the rank of the *align-target*. So the directive

means!HPF$ ALIGN WITH B :: A1, A2, A3

which in turn means the same as!HPF$ ALIGN (:,:) WITH B(:,:) :: A1, A2, A3

because an attributed-form directive that mentions more than one!HPF$ ALIGN A1(:,:) WITH B(:,:) !HPF$ ALIGN A2(:,:) WITH B(:,:) !HPF$ ALIGN A3(:,:) WITH B(:,:)

Each *align-source* corresponds to one axis of the
*alignee*, and is specified as either ```:`'' or
```*`'' or a dummy variable:

- If it is ``
`:`'', then positions along that axis will be spread out across the matching axis of the*align-spec*(see below). - If it is ``
`*`'', then that axis is*collapsed*: positions along that axis make no difference in determining the corresponding position within the*align-target*. (Replacing the ```*`'' with a dummy variable name not used anywhere else in the directive would have the same effect; ```*`'' is merely a convenience that saves the trouble of inventing a variable name and makes it clear that no dependence on that dimension is intended.) - A dummy variable is considered to range over all valid index
values for that dimension of the
*alignee*.

The `WITH` clause of an `ALIGN` has the following syntax:

H319 align-with-clauseisWITHalign-specH320 align-specisalign-target[ (align-subscript-list) ]

or*align-target[ (align-subscript-list) ]H321 align-targetisobject-name

ortemplate-nameH322 align-subscriptisint-expr

oralign-subscript-use

orsubscript-triplet

or*H323 align-subscript-useis[ [int-level-two-expr]add-op]

oralign-subscript-use add-op int-add-operandH324 align-add-operandis[int-add-operand* ]align-primary

oralign-add-operand*int-mult-operandH325 align-primaryisalign-dummy

or(align-subscript-use)H326 int-add-operandisadd-operandH327 int-mult-operandismult-operandH328 int-level-two-exprislevel-2-expr

The full syntax is given here for completeness. However, some of the
forms are discussed only in Section 4. These
``interprocedural'' forms are those using the second option of
rule H320 (containing the `*` form).

- An
*object-name*mentioned as an*align-target*must be a simple name and not a subobject designator or a*component-name*. - An
*align-target*may not have the`OPTIONAL`attribute. - If the
*align-spec*in an`ALIGN`directive begins with ```*`'' then every*alignee*must be a dummy argument. - In an
*align-directive*any*int-expr*,*int-level-two-expr*,*int-add-operand*or*int-mult-operand*must be a specification expression. - Any
*subscript*or*stride*in a*subscript-triplet*that is an*align-subscript*in an*align-directive*must be a specification expression. - Each
*align-dummy*may appear at most once in an*align-subscript-list*. - An
*align-subscript-use*expression may contain at most one occurrence of an*align-dummy*. - A
*scalar-int-variable*that is used as an*align-dummy*may not appear anywhere in the*align-spec*except where explicitly permitted to appear by virtue of the grammar shown above. Paraphrased, one may construct an*align-subscript-use*only by starting with an*align-dummy*and then doing additive and multiplicative things to it with integer specification expressions that contain no*align-dummy*. - A
*subscript*within an*align-subscript*may not contain occurrences of any*align-dummy*. - An
*int-add-operand*,*int-mult-operand*, or*int-level-two-expr*must be of type integer.

*Advice to users.*Some of the above constraints are relaxed under the approvedextensions (see Section 8): mapping of derived type components (relaxes constraint 1), mapping of pointers (relaxes constraint 3) and remapping of data objects (relaxes constraints 4 and 5). (

*End of advice to users.*)

The syntax rules for an *align-subscript-use* take account of
operator precedence issues, but the basic idea is simple: an
*align-subscript-use* is intended to be a linear (more
precisely: affine) function of a single occurrence of an
*align-dummy*.

For example, the following *align-subscript-use* expressions
are valid, assuming that each of `J`, `K`, and
`M` is an *align-dummy* and `N` is not an
*align-dummy*:

JJ+13-K2*MN*M100-3*M-J+J-K-3M+2**3M+N-(4*7+IOR(6,9))*K-(13-5/3)M*2N*(M-N)2*(J+1)5-K+310000-M*32*(3*(K-1)+13)-100

The following expressions are not valid *align-subscript-use* expressions:

J+JJ-J3*K-2*KM*(N-M)2*J-3*J+J2*(3*(K-1)+13)-KJ*JJ+K3/K2**MM*KK-3*MK-JIOR(J,1)-K/3M*(2+M)M*(M-N)2**(2*J-3*J+J)

The *align-spec* must contain exactly as many
*subscript-triplets* as the number of colons (```:`'')
appearing in the *align-source-list*. These are matched up in
corresponding left-to-right order, ignoring, for this purpose, any
*align-source* that is not a colon and any
*align-subscript* that is not a *subscript-triplet*.
Consider a dimension of the *alignee* for which a colon appears
as an *align-source* and let the lower and upper bounds of that
dimension be *LA* and *UA*. Let the corresponding
subscript triplet be *LT*:*UT*:*ST* or its
equivalent. Then the colon could be replaced by a new, as-yet-unused
dummy variable, say `J`, and the subscript triplet by the
expression `(J- LA)*ST+LT` without
affecting the mapping specified by the directive. However, the colon
form additionaly requires that the axes must conform, which means that

must be true. (This is entirely analogous to the treatment of array assignment.)max(0,UA-LA+1) = max(0,[(UT-LT+1)/ST])

To simplify the remainder of the discussion, we assume that every
colon in the *align-source-list* has been replaced by new dummy
variables in exactly the fashion just described, and that every
```*`'' in the *align-source-list* has likewise been
replaced by an otherwise unused dummy variable. For example,

may be transformed into its equivalent!HPF$ ALIGN A(:,*,K,:,:,*) WITH B(31:,:,K+3,20:100:3)

with the attached requirements!HPF$ ALIGN A(I,J,K,L,M,N) WITH B(I-LBOUND(A,1)+31, & !HPF$ L-LBOUND(A,4)+LBOUND(B,2),K+3,(M-LBOUND(A,5))*3+20)

Thus we need consider further only the case where every *align-source* is a dummy variable and no *align-subscript* is a s*ubscript triplet*.

Each dummy variable is considered to range over all valid index values for the corresponding dimension of the *alignee*. Every combination of possible values for the index variables selects an element of the *alignee*. The *align-spec* indicates a corresponding element (or section) of the *align-target* with which that element of the *alignee* should be aligned; this indication may be a function of the index values, but the nature of this function is syntactically restricted (as discussed above) to linear (precisely: affine) functions in order to limit the complexity of the implementation. Each *align-dummy* variable may appear at most once in the *align-spec* and only in certain rigidly prescribed contexts. The result is that each *align-subscript* expression may contain at most one *align-dummy* variable and the expression is constrained to be a linear function of that variable. (therefore skew alignments are not possible.)

An asterisk "*" as an *align-subscript* indicates a replicated representation. each element of the *alignee* is aligned with every position along that axis of the *align-target*.

Rationale. It may seem strange to use "*" to mean both collapsing and replication; the rationale is that "*" always stands conceptually for a dummy variable that appears nowhere else in the statement and ranges over the set of indices for the indicated dimension. Thus, for example,means that a copy of!HPF$ ALIGN A(:) WITH D(:,*)Ais aligned with every column ofD, because it is conceptually equivalent tojust asfor every legitimate index j, alignA(:) withD(:,j)is conceptually equivalent to!HPF$ ALIGN A(:,*) WITH D(:)Note, however, that while HPF syntax allowsfor every legitimate index j, alignA(:,j) withD(:)to be written in the alternate form!HPF$ ALIGN A(:,*) WITH D(:)it does!HPF$ ALIGN A(:,j) WITH D(:)notallowto be written in the alternate form!HPF$ ALIGN A(:) WITH D(:,*)because that has another meaning (only a variable appearing in the!HPF$ ALIGN A(:) WITH D(:,J)align-source-listfollowing thealigneeis understood to be analign-dummy, so the current value of the variableJis used, thus aligningAwith a single column ofD).Replication allows an optimizing compiler to arrange to read whichever copy is closest. (Of course, when a replicated data object is written, all copies must be updated, not just one copy.) Replicated representations are very useful for small lookup tables, where it is much faster to have a copy in each phsical processor but without giving it an extra dimension that is logically unnecessary to the algorithm. (

End of rationale.)

By applying the transformations given above, all cases of an *align-subscript* may be conceptually reduced to either an *int-expr* (not involving an *align-dummy*) or an *align-subscript-use*, and the *align-source-list* may then be evaluated for any specific combination of values for the *align-dummy* variables simply by evaluating each *align-subscript* as an expression. The resulting subscript values must be legitimate subscripts for the *align-target*. (This implies that the *alignee* is not allowed to "wrap around" or "extend past the edges" of an *align-target*.) The selected element of the *alignee* is then considered to be aligned with the indicated element of the *align-target*; more precisely, the selected element of the *alignee* is considered to be ultimately aligned with the same object with which the indicated element of the *align-target* is currently ultimately aligned (possibly itself).

More examples of `ALIGN` directives:

INTEGER D1(N) LOGICAL D2(N,N) REAL, DIMENSION(N,N)::X,A,B,C,AR1,AR2A,P,Q,R,S !HPF$ ALIGN X(:,*) WITH D1(:) !HPF$ ALIGN (:,*) WITH D1:: A,B,C,AR1,AR2A !HPF$ ALIGN WITH D2:: P,Q,R,S

Note that, in a *alignee-list*, the alignees must all have the
same rank but need not all have the same shape; the extents need match
only for dimensions that correspond to colons in the
*align-source-list*. This turns out to be an extremely
important convenience; one of the most common cases in current
practice is aligning arrays that match in distributed (``parallel'')
dimensions but may differ in collapsed (``on-processor'') dimensions:

REAL A(3,N), B(4,N), C(43,N), Q(N) !HPF$ DISTRIBUTE Q(BLOCK) !HPF$ ALIGN (*,:) WITH Q:: A,B,C

Here there are processors (perhaps `N` of them) and arrays of
different sizes (3, 4, 43) within each processor are required. As far
as HPF is concerned, the numbers 3, 4, and 43 may be different,
because those axes will be collapsed. Thus array elements with
indices differing only along that axis will all be aligned with the
same element of `Q` (and thus be specified as residing in the
same processor).

In the following examples, each directive in a group means the same thing, assuming that corresponding axis upper and lower bounds match:

!Second axis of X is collapsed !HPF$ ALIGN X(:,*) WITH D1(:) !HPF$ ALIGN X(J,*) WITH D1(J) !HPF$ ALIGN X(J,K) WITH D1(J) !Replicated representation along second axis of D3 !HPF$ ALIGN X(:,:) WITH D3(:,*,:) !HPF$ ALIGN X(J,K) WITH D3(J,*,K) !Transposing two axes !HPF$ ALIGN X(J,K) WITH D2(K,J) !HPF$ ALIGN X(J,:) WITH D2(:,J) !HPF$ ALIGN X(:,K) WITH D2(K,:) !But there isn't any way to get rid of *both* index variables; ! the subscript-triplet syntax alone cannot express transposition. !Reversing both axes !HPF$ ALIGN X(J,K) WITH D2(M-J+1,N-K+1) !HPF$ ALIGN X(:,:) WITH D2(M:1:-1,N:1:-1) !Simple case !HPF$ ALIGN X(J,K) WITH D2(J,K) !HPF$ ALIGN X(:,:) WITH D2(:,:) !HPF$ ALIGN (J,K) WITH D2(J,K):: X !HPF$ ALIGN (:,:) WITH D2(:,:):: X !HPF$ ALIGN WITH D2:: X