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