Available No. of Registers

howard at cpocd2.UUCP howard at cpocd2.UUCP
Sat Feb 14 03:39:09 AEST 1987


In article <873 at celerity.UUCP> jjw at celerity.UUCP (Jim (JJ) Whelan) writes:
>For example, postulate a function which has more than 6 variables  6 of
>which have the following characteristics:
>	a -- Is extremely frequently used.  It is critical to performance
>	     that it be in a register.
>	b, c -- Are used very frequently.  They should be in registers to
>	        obtain optimal performance.
>	d, e, f -- Are used frequently.  If possible, they should be in
>	           registers.
>	The remaining variables are only used infrequently and should never
>	be in registers in preference to those listed.
>The question is -- How do I declare these variables so that I get the best
>performance on machines with 1, 3, 6, 8 ... registers available for register
>variables?  I am trying to code in a machine and compiler independent
>manner.  I do not want to reshuffle the declarations nor to have to
>re-define a "REGISTER" macro.  In fact I don't even want to care about how
>many register variables the compiler allocates.

Boy, there are sure a lot of things you "don't want" to do to get good code!
Seriously, there is an easy way to get approximately what you want, with a
fixed amount of work PER MACHINE (not per program).  Declare your variables
as follows (assuming they are all ints):

	#include	"register.h"

	main()
	{
	REG1 int	a;
	REG2 int	b;
	REG3 int	c;
	REG4 int	d;
	REG5 int	e;
	REG6 int	f;
	}

And then have register.h contain (assuming there are 3 usable registers):

	#define	REG1	register
	#define	REG2	register
	#define	REG3	register
	#define	REG4
	#define	REG5
	#define	REG6
	...

If you do this for all your programs, then when you port to a new machine
you only need to change ONE register.h file, once, and you're set!

In actuality, this is oversimplified, since some machines have separate
registers for integer, floating point, and/or pointer; and a double may
eat up 2 registers!

A similar approach can be used to get total portability with respect to
the length of short, int, and long.  Just define INTn for n = 1 up to
the maximum of the machine (example here assumes short=16, int=32, long=64):

	#define	INT1	short
	...
	#define	INT16	short
	#define	INT17	int
	...
	#define	INT32	int
	#define	INT33	long
	...
	#define	INT64	long
	/* ... and likewise for UINT1 to UINT64 */

Then you declare each int with the precise number of bits you actually require:

	REG1 INT5	a;	/* This works with register scheme above. */
	INT16		b;
	INT16		c;
	INT10		d;
	INT18		e;	/* May pay off on a 36-bit machine! */
	INT60		f;	/* Just the thing for a Cray 2? */

Now of course, INT60 isn't very portable, but at least you'll know instantly
every place in your program that needs to be fixed.  You can also use, e.g.:

	#ifdef INT60
		/* simple code using 60-bit int */
	#else
		/* complex code to emulate 60-bit int */
	#endif
	
to get a better shot at portability.  The drawback of this approach is that
it requires you to understand (and declare) exactly how many bits each variable
requires; but shouldn't you know that anyway?  (Note to wizards: you will
have noticed that using a short instead of an int for a loop variable can
cause performance degradation on some machines.  If you're that smart, you
should be able to figure out how to modify the above scheme to do what you
want.  "An exercise for the reader".  It's not very hard.)

Wouldn't it be nice if UNIX was written this way?  Then we wouldn't be arguing
about whether or not we're stuck with sizeof(int) == sizeof(long)!
-- 

	Howard A. Landman
	...!intelca!mipos3!cpocd2!howard



More information about the Comp.lang.c mailing list