Listing 1: A test for compiler support of restrict

/* 
 * This program is legal C and C++, except for the use of 
 * restrict. The abuses of restrict are deliberately illegal.
 * Some compilers, such as the DEC Alpha cc compiler, recognize
 *  __restrict instead of restrict.  Others such as KAI C++ 
 * require the option --restrict. 
 */
#include <stdio.h>
     
#define N 1000
     
#ifdef USE_UNDERSCORE
#define restrict __restrict 
#endif /* USE_UNDERSCORE */
     
/* BODY is the computation shared by all tests here. */
#define BODY int i; for( i=0; i<n; ++i ) \
    a[i] = (b[j+N/4] + b[j-N/4]) * 0.5f;
     
float * wash( float * ptr );    /* forward declaration */
     
/* Base line version without restrict */
void simple( float * a, float * b, int n, int j ) {
    BODY
}
     
/* 
 * Version with restrict on both formal parameters. 
 * If the compiler complains about the declaration, 
 * it probably does not understand restrict. 
 */
void 
with_restrict_formals( float * restrict a, float * restrict b, 
    int n, int j) {

    BODY
}
     
/* Version with restrict only on output pointer */
void 
with_restrict_out_formal( float * restrict a, float * b, 
    int n, int j ) {

    BODY
}
     
/* Version with restrict only on input pointer */
void 
with_restrict_in_formal( float * a, float * restrict b, 
    int n, int j ) {

    BODY
}
     
/* Version with restrict on pointers local to a block */
void 
with_restrict_local( float * ap, float * bp, int n, int j ) {

    float * restrict a = wash(ap);
    float * restrict b = wash(bp);
    BODY
}
     
/* Version with restrict on pointers, but work is done with 
   local copies of the pointers */
void 
with_local_copy_of_restrict_formals( float * restrict ap, 
    float * restrict bp, int n, int j ) {

    float * a = ap+n-N;
    float * b = bp+n-N;
    BODY
}
     
typedef 
void (*a_ptr_to_function)( float * a, float * b, int n, int j );
     
#define ENTRY(x) {#x,x}
     
struct {
    char * name;
    a_ptr_to_function ptr_to_function;
} table[] = {
    ENTRY(simple),
    ENTRY(with_restrict_formals),
    ENTRY(with_restrict_out_formal),
    ENTRY(with_restrict_in_formal),
    ENTRY(with_restrict_local),
    ENTRY(with_local_copy_of_restrict_formals)
};
     
#define M (sizeof(table)/sizeof(table)[0])
     
/* 
 * Function report_differences compares results a and b. 
 *
 * A report of a few differences (2-4) probably indicates that 
 * the compiler exploited restrict for software pipelining, 
 * but not for invariant hoisting. 
 *
 * A report of about 3*N/4 differences probably indicates that 
 * the compiler exploited restrict for hoisting of invariants. 
 */
void 
report_differences( float * a, float * b, const char * name ) {
    int i;
    int current = -1;
    printf("%s:",name);
    for( i=0; i<=N; ++i ) 
        if( i==N || a[i]==b[i] ) {
            if( current>=0 ) {
                if( current!=i-1 ) printf("...%d", i-1 ); 
                current = -1;
            }
        } else {
            if( current<0 ) {
                printf(" %d", i );
                current = i;
            }   
        }
    printf("\n");
}
     
float array[M][N];
float* array_ptr[M];
     
/* 
 * The purpose of function "wash" is to return a pointer the 
 * same as "ptr", but in a way the disguises that the returned 
 * pointer really is the same. 
 */
float * wash( float * ptr ) {
    int j;
    for( j=0; ptr!=array[j]; ++j ) 
        continue;
    return array_ptr[j];
}
     
int main() {
    int i, j;
     
    /* Initialize data sets */
    for( j=0; j<M; ++j ) {
        array_ptr[j] = array[j];
        for( i=0; i<N; ++i ) {
            array[j][i] = i;
        }
    }
     
    /* Run each test */
    for( j=0; j<M; ++j ) {
        (*table[j].ptr_to_function)(array[j], array[j], N, N/2);
    }
     
    /* Report the errors - more is better! */ 
    for( j=1; j<M; ++j ) {
        report_differences( array[0], array[j], table[j].name );
    }
     
    return 0;
}