An ALIGN, DISTRIBUTE, or DYNAMIC directive may appear within a derived-type-def wherever a component-def-stmt may appear. Every alignee or distributee within such a directive must be the name of a component defined within that derived-type-def. To allow mapping of the structure components, the rules have to be extended as follows:
H807 distributee-extended is object-name
or template-name
or component-name
or structure-component
A derived type is said to be an explicitly mapped type if any of its components is explicitly mapped or if any of its components is of an explicitly mapped type.
H808 alignee-extended is object-name
or component-name
or structure-component
H809 align-target-extended is object-name
or template-name
or component-name
or structure-component
The above constraints imply that components of derived type can be mapped within the derived type definition itself such that when any objects of that type are created the components will be created with the specified mapping.
Consider the following example:
TYPE DT
REAL C(100)
!HPF$ DISTRIBUTE C(BLOCK) ONTO P
END TYPE DT
TYPE (DT) :: S1
TYPE (DT) :: S2(100)
a derived type with one component, array C, which is specified to be distributed block. Therefore the scalar variable S1 of derived type DT has a structure component S1%C that is distributed block onto the processor arrangement P. Similarly, the compontent C of each of the elements of the array S2 will also be distributed block onto the processor arrangement P.
An align directive inside a derived type definition may align a component of the derived type with another component of the same derived type or with another object. A structure component can be used as a target to align other objects including components of derived types.
Example:
!HPF$ TEMPLATE T(100)
!HPF$ DISTRIBUTE T(CYLIC)
TYPE DT
REAL, DIMENSION(100) :: A, B, C
!HPF$ ALIGN WITH A :: B
!HPF$ DISTRIBUTE (BLOCK) :: A
!HPF$ ALIGN WITH T :: C
END TYPE DT
Here variables of derived type DT will be created such the component B is aligned with A, which is itself distributed block, and such that the component C is aligned with a template T that is external to the derived type definition.
Note that if a derived type component is given a partial mapping, it is up to the compiler to choose the rest of the mapping of that component. However, it is expected that the compiler will choose the same mapping for this component of all variables of such a derived type. For example, consider a modification of the above code in which the distribution of the component A is omitted. B and A are specified to be aligned but no distribution is given for A. In such a situation, it is expected that all variables of the derived type DT will be created such that the component A (and in turn the component B) have the same distribution.
The constraints for the mapping of derived type components allow the mapping of structure variables at only one level. Consider for example the following code in which a derived type contains a components that is itself a derived type:
TYPE SIMPLE
REAL S(100)
!HPF$ DISTRIBUTE S(BLOCK)
END TYPE SIMPLE
!HPF TEMPLATE, DISTRIBUTE(BLOCK, *) :: HAIRY_TEMPLATE(47,73)
TYPE COMPLICATED
INTEGER SIZE
REAL RV(100,100), KV(100,100), QV(47,73)
! Arrays RV, KV, and QV may be mapped
!HPF$ DISTRIBUTE (BLOCK, BLOCK):: RV, KV
!HPF$ ALIGN WITH HAIRY_TEMPLATE :: QV
TYPE(SIMPLE) SV(100)
! The following directive is not valid because SIMPLE
! is an explicitly mapped type.
!HPF$ DISTRIBUTE SV(BLOCK)
END TYPE COMPLICATED
TYPE(COMPLICATED) LOTSOF(20)
! The following directive is not valid because COMPLICATED
! is an explicitly mapped type.
!HPF$ DISTRIBUTE LOTSOF(BLOCK)
Here, a component of the derived type SIMPLE has been mapped; thus objects of this type, e.g., SV in type COMPLICATED, cannot be distributed. The array LOTSOF cannot be distributed for the same reason.
Structure components having the POINTER attribute can be remapped using the REALIGN or REDISTRIBUTE directive if they have been declared DYNAMIC. For example, the following code fragment can be used to allocate and map multiple blocks (called SUBGRID here) of a multi-block grid:
!HPF$ PROCESSORS P( number_of_processors())
TYPE SUBGRID
INTEGER SIZE
INTEGER LO, HI ! target subset of processors
REAL, POINTER BL(:)
!HPF DYNAMIC BL
END TYPE SUBGRID
TYPE (SUBGRID), ALLOCATABLE :: GRID(:)
READ (*,*) SUBGRID_COUNT
ALLOCATE GRID(SUBGRID_COUNT)
DO I = 1, SUBGRID_COUNT
READ(*,*) GRID(I)END DO
! Compute processor subsets for each subgrid, setting
! the LO and HI values
CALL FIGURE_THE_PROCS ( GRID, number_of_processors())
! Allocate each subgrid and distribute to the computed processors subset
DO I = 1, SUBGRID_COUNT
ALLOCATE( GRID(I)%BL( GRID(I)%SIZE ) )
!HPF$ REDISTRIBUTE GRID(I)%BL(BLOCK) ONTO P( GRID(I)%LO : GRID(I)%HI )
Rationale. Components of derived types can be remapped only if they have the POINTER attribute in addition to the DYNAMIC attribute. This restriction has been placed to disallow mappings which cannot be directly specified using HPF directives. Consider, for instance, the following code fragment:
TYPE DT
REAL C(100)
!HPF$ DISTRIBUTE C(BLOCK) ONTO P
!HPF$ DYNAMIC C ! Nonconforming
END TYPE DT
TYPE (DT) :: S(10)
...
J = 3
...
!HPF$ REDISTRIBUTE S(J)%C(CYCLIC) ONTO P
... S(:)%C(2) ...
Here the component C of derived type DT has been
declared DYNAMIC. Thus, the array variable S
consists of 10 elements each of which is a structure with a component
C initially distributed block. The REDISTRIBUTE
directive remaps the structure component C of the
Jth element of S so that it is distributed cyclic.
Consider now the mapping of the data object referred to by the
expression S(:)%C(2) which picks out the second element from
each of the ten structures that make up the array variable
S. After the redistribution of one of the elements of
S (element 3 in this case), each element of the object will
reside on processor P(1) except for the third element, which
will reside on processor P(2). Such a distribution cannot be
specified directly using HPF directives.
The Fortran standard disallows such expressions for components with the POINTER attribute. In particular, if a part-name in a data reference has the POINTER attribute then each part-ref to its left must be scalar (F95:6.1.2). Thus, we avoid the above situation by