Chapter 3. Cray C and C++ Extensions

Table of Contents
3.1. Restricted Pointers
3.2. long long and unsigned long long Data Types
3.3. // Comments
3.4. Complex Data Types
3.5. Variable Length Arrays
3.6. fortran Keyword
3.7. Hexadecimal Floating-point Constants
3.8. Arithmetic Conversions

This chapter describes the Cray Standard C and Cray C++ extensions to their respective standards. A program that uses one or more extensions does not strictly conform to the standard. These extensions are not available in strict conformance mode.

Extensions to both the C and C++ standards include the following:

The following extensions apply only to the C standard:

3.1. Restricted Pointers

In extended mode, the identifier restrict is treated as a keyword that specifies a third type qualifier (in addition to const and volatile). A pointer with restrict-qualified type is termed a restricted pointer.

Restricted pointers are a language extension offered by Cray Standard C and Cray C++ for asserting the absence of aliasing through pointers. One advantage of using restricted pointers on UNICOS systems is that they can increase the number of loops that the compiler can vectorize. On UNICOS/mk systems, they can improve instruction scheduling and memory hierarchy analysis.

When it is inconvenient to modify the source code so that the restrict qualifier appears explicitly in pointer declarations, use the -h restrict= command-line option (for more information, see Section 2.7.2).

A program that uses the restrict qualifier can easily be ported to a system that does not support the qualifier by defining the identifier restrict to be an empty preprocessor macro. You can do this with the -D restrict= option or by using the following code:

#ifndef _CRAYC #define restrict #endif

If the preceding directives are included in a program, a declaration of the following form expands into a declaration of a restricted pointer with Cray Research compilers and into a declaration of an ordinary pointer with other compilers:

int * restrict p;

On UNICOS systems, the compiler ignores some uses of restrict that it currently cannot vectorize. Some cases that are ignored are discussed in Section 3.1.6.

3.1.1. Function Parameters

If a function has pointer parameters that point into disjoint (array or non-array) objects in each call, the use of these parameters can be asserted to the compiler by declaring the pointer parameters to be restrict-qualified. This eliminates potential aliasing through those pointers as an obstacle to vectorization of the loops in the function, and also allows improved scheduling of scalar code.

The following example illustrates the use of restrict-qualified pointer parameters:

void f1 (int n, int * restrict p, int * restrict q) {
   int i;

   /* Compiler may analyze dependences  */
   /* as if the following two lines     */
   /* were present:                     */
   /*   p = malloc(n * sizeof(int));    */
   /*   q = malloc(n * sizeof(int));    */

  for (i = 0; i < n; i++) { /* Vectorized   */
        p[i] = q[i];
  }
}

This operation will also vectorize if the restricted pointers are incremented as in the following example:

void f2 (int n, int * restrict p, int * restrict q) {
   int i;
   for (i = 0; i < n; i++) { /* Vectorized */
        *p++ = *q++;
   }
}

3.1.2. File Scope

Restricted pointers are also useful when declared at file scope. In the next example, restrict is used to assert that the global pointer p points into a unique array object, which in this case is obtained from a malloc call.

#include <stdlib.h>

int * restrict p;

void alloc_p(int n) {
   p = malloc(n * sizeof p[0]);
}

3.1.3. Block Scope

Similarly, a restricted pointer declared in the outermost block of a function can be used to point to an array allocated for use within the function. Continuing the example shown in the previous subsection:

extern int * restrict p;

void modify_p(int n) {
   int * restrict q = malloc(n * sizeof q[0]);
   int i;
   for (i = 0; i < n; i++) {    /* Vectorized */
      q[i] = p[i];
   }
   for (i = 0; i < n-1; i+=2) { /* Vectorized */
      p[i]   = q[i+1] + q[i];
      p[i+1] = q[i+1] - q[i];
   }
   free(q);
}

3.1.4. Unrestricted Pointers

Like array names, restricted pointers are not immune from aliasing through unrestricted pointers. At the point of its declaration, a restricted pointer may be assumed to provide the only means of designating an array object that is disjoint from any other object, but a restricted pointer's value can be assigned to one or more unrestricted pointers. Such an assignment may occur in an assignment expression or in the assignment of an argument value to a parameter in a function call. Although permitted, the use of restricted and unrestricted pointers together should be avoided, since such use often inhibits vectorization.

3.1.5. Comparison with #pragma ivdep

Restricted pointers and the #pragma ivdep directive both provide a means of promoting vectorization. Because they convey different information to the compiler, they can give different results. One may be effective in causing a particular loop to vectorize when the other is not. For loops that will vectorize either way, restricted pointers may give better performance.

3.1.6. Implementation Limits

At default vectorization level, the current implementation only takes advantage of the qualifier for simple identifiers declared with file scope, as function parameters, or in the outermost block of a function. In other contexts, uses of the qualifier are checked only for syntactic correctness. The -h vector3 option enables a more detailed analysis that can take advantage of restricted pointers that are members of structures or elements of arrays.

Inlining a function with restricted pointer parameters can cause a loss of vectorization.