Next: The TASK_REGION Construct Up: The RESIDENT ClauseDirective, Previous: Examples of RESIDENT Clauses

## RESIDENT Directives Applied to Procedure Reference

If a RESIDENT directive applies to procedure reference, then the assertion is more subtle.

• If a res-object-list appears in the RESIDENT directive, then no assertion is made about behavior within the called procedure. For example, consider the statements:
!HPF\$ RESIDENT( A(I), B )
A(I) = F( A(I), B(LO:HI) )

The directive declares all variable refences in the statement (including the actual arguments) to be local to the current ON processor set, and that F itself does not reference or update any nonlocal variables.

Rationale. Propagating assertions about the behavior of lexical entities is difficult to define consistently and usefully. For example, consider the following function called from the code fragment above:
REAL FUNCTION F( X, Y )
USE MODULE_DEFINING_A
REAL X, Y(:), B(I)
!HPF\$ INHERIT Y
!HPF\$ ALIGN B(:) WITH Y(:)
INTEGER I

Z = 0.0
DO I = 1, SIZE(Y)
Z = Z + A(I)*X + B(I)*Y(I)
END DO
F=Z
END FUNCTION

Assume A is defined as a distributed, global array in module MODULE_DEFINING_A. What should the RESIDENT clause mean regarding operations in F? The expression A(I) in the RESIDENT directive might reasonably mean references only to the array A. Note that the A in the caller may be local, the same global array as the A in F (if the caller used MODULE_DEFINING_A), or a different global array (if the caller used a different module). Perhaps a limiting cvase is array B. The array B in function F is local, and thus different from the caller; however, because of the restrictions on ON clauses it is certain that the local B will be mapped to the ON processor set. Thus, the RESIDENT assertion is trivially true. To further confuse matters, RESIDENT variables might seem to apply to dummy arguments that become associated with those variables. Unfortunately, this implies that the lexical expression B in the caller refers to the lexical expression Y in F, which stretches the definition of "lexical" beyond the breaking point. For all these reasons, it was decided to limit the meaning of named variables in RESIDENT clauses to the lexical scope of the directive. (End of rationale.)

• If the RESIDENT directive does not contain a res-object-list, then the directive asserts that all references in the caller and the called procedures are local as defined above. For example, consider the statements
!HPF\$ RESIDENT
A(I) = F( A(I), B(LO:HI) )

The directive declares all variable refences in the statement (including the actual arguments) to be local to the current ON processor set, and that F itself does not reference or update any nonlocal variables.

Rationale.The RESIDENT assertion is always true for data local to the called procedure. This is true because the called procedure must use a declarative ON clause, which in turn limits the set of processors that can store any local explicitly mapped variables. The above definition extends this assertion to all global explicitly mapped data, producing a very powerful directive. This is similar to the meaning of INDEPENDENT, in that it also makes an assertion about variable accesses in any called procedure in the loop. An alternative semantics for RESIDENT would have been to avoid propagating the assertion interprocedurally (i.e., treat both the variable-list version and the no-list version the same). However, this would not provide enough information to optimize code on certain machines. In particular, it would have made task parallelism quite difficult on message-passing machines. (End of rationale.)

Advice to implementors.RESIDENT without a variable list guarantees that no one-sided communication outside of the ON processor set will be generated by the callee. Such a procedure can be called only on the ``active'' processors, unless the runtime system has additional constraints (for example, if the runtime system requires all processors to participate in collective communications).

The other forms of RESIDENT provide information that could be propagated interprocedurally. For example, if the actual argument to a subprogram is asserted to be RESIDENT and is passed transcriptively, then anything that is aligned to it in the callee will also be RESIDENT. If the information is not propagated, the only result will be less optimization. (End of advice to implementors.)

Advice to users.Although the RESIDENT assertion applies interprocedurally, it is by no means certain that all compilers will make use of this information. In particular, separate compilation limits the propagation that can take place. It is therefore good practice to include a RESIDENT clause both in the caller's ON directive and in the callee. (This assumes that the assertion is true, of course!) This ensures that the compiler has the RESIDENT information available when it is compiling both ends of the procedure call. This is especially useful for RESIDENT clauses without a variable list; knowing that all data accessed is local allows many optimizations that are not otherwise possible. (End of advice to users.)

Locality information is particularly critical interprocedurally. Here, the RESIDENT directive without a res-object-list can be used to good advantage. Consider the following extension of the block-structured example from Section 9.2.4:

!HPF\$ PROCESSORS PROCS(NP)
!HPF DISTRIBUTE X(BLOCK) ONTO PROCS

! Compute ILO(IP) = lower bound on PROCS(IP)
! Compute IHI(IP) = upper bound on PROCS(IP)
DONE = .FALSE.
DO WHILE (.NOT. DONE)
!HPF\$ INDEPENDENT
DO IP = 1, NP
!HPF\$ ON (PROCS(IP)), RESIDENT
CALL SOLVE_SUBDOMAIN( IP, X(ILO(IP):IHI(IP)) )
END DO
!HPF\$ ON HOME(X) BEGIN
CALL SOLVE_BOUNDARIES( X, ILO(1:NP), IHI(1:NP) )
!HPF\$ RESIDENT
DONE = CONVERGENCE_TEST( X, ILO(1:NP), IHI(1:NP) )
!HPF\$ END ON
END DO

Recall that the INDEPENDENT IP loop performs a computation on each subdomain's interior, where a subdomain is mapped to a particular processor. The first RESIDENT clause additionally informs the compiler that no subdomain uses data from another processor. Without this information, the compiler would have to assume a worst-case scenario in which each subdomain performed its updates based on non-local read-only data. Any nonlocal data could not be written by another processor without violating the tt INDEPENDENT directive; however, if the data were not updated (for example, a large lookup table) it could be stored remotely. Particularly on nonshared-memory machines, access to this remote data would be difficult. The RESIDENT clause ensures that this possibility need not be considered. All data required by SOLVE_SUBDOMAIN is stored locally. The second RESIDENT clause asserts that all data for CONVERGENCE_TEST is stored on the same processors that store X. The same cannot be said for SOLVE_BOUNDARIES, which does not fall in the scope of the RESIDENT directive. For example, there might be a processors arrangement other than PROCS with necessary data. Accessing this data might well cause a bottleneck in the computation as described above.

Again, note the usefulness of RESIDENT clauses in giving the compiler information. Few compilers would be able to unravel nontrivial assignments to ILO and IHI, and no current compiler would even attempt to understand the comments in the above code fragment. End of advice to programmers.

Next: The TASK_REGION Construct Up: The RESIDENT ClauseDirective, Previous: Examples of RESIDENT Clauses