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; }