1 /* Copyright (C) 1989, 1995, 1996, 1998, 1999 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: genarch.c,v 1.2.6.1.2.1 2003/01/17 00:49:02 giles Exp $ */
20 /* Generate a header file (arch.h) with parameters */
21 /* reflecting the machine architecture and compiler characteristics. */
22 
23 #include "stdpre.h"
24 #include <ctype.h>
25 #include <stdio.h>
26 /*
27  * In theory, not all systems provide <string.h>, or declare memset in
28  * that header file, but at this point I don't think we care about any
29  * that don't.
30  */
31 #include <string.h>
32 #include <time.h>
33 
34 /* We should write the result on stdout, but the original Turbo C 'make' */
35 /* can't handle output redirection (sigh). */
36 
37 private void
section(FILE * f,const char * str)38 section(FILE * f, const char *str)
39 {
40     fprintf(f, "\n\t /* ---------------- %s ---------------- */\n\n", str);
41 }
42 
43 #ifndef __FreeBSD__
44 private clock_t
time_clear(char * buf,int bsize,int nreps)45 time_clear(char *buf, int bsize, int nreps)
46 {
47     clock_t t = clock();
48     int i;
49 
50     for (i = 0; i < nreps; ++i)
51 	memset(buf, 0, bsize);
52     return clock() - t;
53 }
54 #endif /* __FreeBSD__ */
55 
56 private void
define(FILE * f,const char * str)57 define(FILE *f, const char *str)
58 {
59     fprintf(f, "#define %s ", str);
60 }
61 
62 private void
define_int(FILE * f,const char * str,int value)63 define_int(FILE *f, const char *str, int value)
64 {
65     fprintf(f, "#define %s %d\n", str, value);
66 }
67 
68 const char ff_str[] = "ffffffffffffffff";	/* 8 bytes */
69 
70 int
main(int argc,char * argv[])71 main(int argc, char *argv[])
72 {
73     char *fname = argv[1];
74     long one = 1;
75     int ff_strlen = sizeof(ff_str) - 1;
76     struct {
77 	char c;
78 	short s;
79     } ss;
80     struct {
81 	char c;
82 	int i;
83     } si;
84     struct {
85 	char c;
86 	long l;
87     } sl;
88     struct {
89 	char c;
90 	char *p;
91     } sp;
92     struct {
93 	char c;
94 	float f;
95     } sf;
96     struct {
97 	char c;
98 	double d;
99     } sd;
100     static int log2s[17] =
101     {0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4};
102     long lm1 = -1;
103     long lr1 = lm1 >> 1, lr2 = lm1 >> 2;
104     unsigned long um1 = ~(unsigned long)0;
105     int im1 = -1;
106     int ir1 = im1 >> 1, ir2 = im1 >> 2;
107     union {
108 	long l;
109 	char *p;
110     } pl0, pl1;
111     int ars;
112     int lwidth = size_of(long) * 8;
113     union {
114 	float f;
115 	int i;
116 	long l;
117     } f0 , f1, fm1;
118     int floats_are_IEEE;
119     FILE *f = fopen(fname, "w");
120 
121     if (f == NULL) {
122 	fprintf(stderr, "genarch.c: can't open %s for writing\n", fname);
123 	return exit_FAILED;
124     }
125     fprintf(f, "/* Parameters derived from machine and compiler architecture */\n");
126     /* We have to test the size dynamically here, */
127     /* because the preprocessor can't evaluate sizeof. */
128     f0.f = 0.0, f1.f = 1.0, fm1.f = -1.0;
129     floats_are_IEEE =
130 	(size_of(float) == size_of(int) ?
131 	 f0.i == 0 && f1.i == (int)0x3f800000 && fm1.i == (int)0xbf800000 :
132 	 f0.l == 0 && f1.l == 0x3f800000L && fm1.l == 0xbf800000L);
133 
134     section(f, "Scalar alignments");
135 
136 #define OFFSET_IN(s, e) (int)((char *)&s.e - (char *)&s)
137     define_int(f, "ARCH_ALIGN_SHORT_MOD", OFFSET_IN(ss, s));
138     define_int(f, "ARCH_ALIGN_INT_MOD", OFFSET_IN(si, i));
139     define_int(f, "ARCH_ALIGN_LONG_MOD", OFFSET_IN(sl, l));
140     define_int(f, "ARCH_ALIGN_PTR_MOD", OFFSET_IN(sp, p));
141     define_int(f, "ARCH_ALIGN_FLOAT_MOD", OFFSET_IN(sf, f));
142     define_int(f, "ARCH_ALIGN_DOUBLE_MOD", OFFSET_IN(sd, d));
143 #undef OFFSET_IN
144 
145     section(f, "Scalar sizes");
146 
147     define_int(f, "ARCH_LOG2_SIZEOF_SHORT", log2s[size_of(short)]);
148     define_int(f, "ARCH_LOG2_SIZEOF_INT", log2s[size_of(int)]);
149     define_int(f, "ARCH_LOG2_SIZEOF_LONG", log2s[size_of(long)]);
150     define_int(f, "ARCH_SIZEOF_PTR", size_of(char *));
151     define_int(f, "ARCH_SIZEOF_FLOAT", size_of(float));
152     define_int(f, "ARCH_SIZEOF_DOUBLE", size_of(double));
153     if (floats_are_IEEE) {
154 	define_int(f, "ARCH_FLOAT_MANTISSA_BITS", 24);
155 	define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", 53);
156     } else {
157 	/*
158 	 * There isn't any general way to compute the number of mantissa
159 	 * bits accurately, especially if the machine uses hex rather
160 	 * than binary exponents.  Use conservative values, assuming
161 	 * the exponent is stored in a 16-bit word of its own.
162 	 */
163 	define_int(f, "ARCH_FLOAT_MANTISSA_BITS", sizeof(float) * 8 - 17);
164 	define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", sizeof(double) * 8 - 17);
165     }
166 
167     section(f, "Unsigned max values");
168 
169 #define PRINT_MAX(str, typ, tstr, l)\
170   define(f, str);\
171   fprintf(f, "((%s)0x%s%s + (%s)0)\n",\
172     tstr, ff_str + ff_strlen - size_of(typ) * 2, l, tstr)
173     PRINT_MAX("ARCH_MAX_UCHAR", unsigned char, "unsigned char", "");
174     PRINT_MAX("ARCH_MAX_USHORT", unsigned short, "unsigned short", "");
175     /*
176      * For uint and ulong, a different approach is required to keep gcc
177      * with -Wtraditional from spewing out pointless warnings.
178      */
179     define(f, "ARCH_MAX_UINT");
180     fprintf(f, "((unsigned int)~0 + (unsigned int)0)\n");
181     define(f, "ARCH_MAX_ULONG");
182     fprintf(f, "((unsigned long)~0L + (unsigned long)0)\n");
183 #undef PRINT_MAX
184 
185 #ifndef __FreeBSD__
186     section(f, "Cache sizes");
187 
188     /*
189      * Determine the primary and secondary cache sizes by looking for a
190      * non-linearity in the time required to fill blocks with memset.
191      */
192     {
193 #define MAX_BLOCK (1 << 20)
194 	static char buf[MAX_BLOCK];
195 	int bsize = 1 << 10;
196 	int nreps = 1;
197 	clock_t t = 0;
198 	clock_t t_eps;
199 
200 	/*
201 	 * Increase the number of repetitions until the time is
202 	 * long enough to exceed the likely uncertainty.
203 	 */
204 
205 	while ((t = time_clear(buf, bsize, nreps)) == 0)
206 	    nreps <<= 1;
207 	t_eps = t;
208 	while ((t = time_clear(buf, bsize, nreps)) < t_eps * 10)
209 	    nreps <<= 1;
210 
211 	/*
212 	 * Increase the block size until the time jumps non-linearly.
213 	 */
214 	for (; bsize <= MAX_BLOCK;) {
215 	    clock_t dt = time_clear(buf, bsize, nreps);
216 
217 	    if (dt > t + (t >> 1)) {
218 		t = dt;
219 		break;
220 	    }
221 	    bsize <<= 1;
222 	    nreps >>= 1;
223 	    if (nreps == 0)
224 		nreps = 1, t <<= 1;
225 	}
226 	define_int(f, "ARCH_CACHE1_SIZE", bsize >> 1);
227 	/*
228 	 * Do the same thing a second time for the secondary cache.
229 	 */
230 	if (nreps > 1)
231 	    nreps >>= 1, t >>= 1;
232 	for (; bsize <= MAX_BLOCK;) {
233 	    clock_t dt = time_clear(buf, bsize, nreps);
234 
235 	    if (dt > t * 1.25) {
236 		t = dt;
237 		break;
238 	    }
239 	    bsize <<= 1;
240 	    nreps >>= 1;
241 	    if (nreps == 0)
242 		nreps = 1, t <<= 1;
243 	}
244 	define_int(f, "ARCH_CACHE2_SIZE", bsize >> 1);
245     }
246 #endif /* __FreeBSD__ */
247 
248     section(f, "Miscellaneous");
249 
250     define_int(f, "ARCH_IS_BIG_ENDIAN", 1 - *(char *)&one);
251     pl0.l = 0;
252     pl1.l = -1;
253     define_int(f, "ARCH_PTRS_ARE_SIGNED", (pl1.p < pl0.p));
254     define_int(f, "ARCH_FLOATS_ARE_IEEE", (floats_are_IEEE ? 1 : 0));
255 
256     /*
257      * There are three cases for arithmetic right shift:
258      * always correct, correct except for right-shifting a long by 1
259      * (a bug in some versions of the Turbo C compiler), and
260      * never correct.
261      */
262     ars = (lr2 != -1 || ir1 != -1 || ir2 != -1 ? 0 :
263 	   lr1 != -1 ? 1 :	/* Turbo C problem */
264 	   2);
265     define_int(f, "ARCH_ARITH_RSHIFT", ars);
266     /*
267      * Some machines can't handle a variable shift by
268      * the full width of a long.
269      */
270     define_int(f, "ARCH_CAN_SHIFT_FULL_LONG", um1 >> lwidth == 0);
271     /*
272      * Determine whether dividing a negative integer by a positive one
273      * takes the floor or truncates toward zero.
274      */
275     define_int(f, "ARCH_DIV_NEG_POS_TRUNCATES", im1 / 2 == 0);
276 
277 /* ---------------- Done. ---------------- */
278 
279     fclose(f);
280     return exit_OK;
281 }
282