Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* Copyright (C) 1989-2004 artofcode LLC. All rights reserved.
2
 
3
  This software is provided AS-IS with no warranty, either express or
4
  implied.
5
 
6
  This software is distributed under license and may not be copied,
7
  modified or distributed except as expressly authorized under the terms
8
  of the license contained in the file LICENSE in this distribution.
9
 
10
  For more information about licensing, please refer to
11
  http://www.ghostscript.com/licensing/. For information on
12
  commercial licensing, go to http://www.artifex.com/licensing/ or
13
  contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14
  San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15
*/
16
 
17
/* $Id: genarch.c,v 1.11 2004/06/17 21:42:53 giles Exp $ */
18
/*
19
 * Generate a header file (arch.h) with parameters
20
 * reflecting the machine architecture and compiler characteristics.
21
 */
22
 
23
#include "stdpre.h"
24
#include <ctype.h>
25
#include <stdio.h>
26
/*
27
 * In theory, not all systems provide <string.h> or <setjmp.h>, or declare
28
 * memset in <string.h>, 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
#include <setjmp.h>
34
 
35
/* We should write the result on stdout, but the original Turbo C 'make' */
36
/* can't handle output redirection (sigh). */
37
 
38
private void
39
section(FILE * f, const char *str)
40
{
41
    fprintf(f, "\n\t /* ---------------- %s ---------------- */\n\n", str);
42
}
43
 
44
private clock_t
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
 
55
private void
56
define(FILE *f, const char *str)
57
{
58
    fprintf(f, "#define %s ", str);
59
}
60
 
61
private void
62
define_int(FILE *f, const char *str, int value)
63
{
64
    fprintf(f, "#define %s %d\n", str, value);
65
}
66
 
67
private void
68
print_ffs(FILE *f, int nbytes)
69
{
70
    int i;
71
 
72
    for (i = 0; i < nbytes; ++i)
73
	fprintf(f, "ff");
74
}
75
 
76
private int
77
ilog2(int n)
78
{
79
    int i = 0, m = n;
80
 
81
    while (m > 1)
82
	++i, m = (m + 1) >> 1;
83
    return i;
84
}
85
 
86
int
87
main(int argc, char *argv[])
88
{
89
    char *fname = argv[1];
90
    long one = 1;
91
    struct {
92
	char c;
93
	short s;
94
    } ss;
95
    struct {
96
	char c;
97
	int i;
98
    } si;
99
    struct {
100
	char c;
101
	long l;
102
    } sl;
103
    struct {
104
	char c;
105
	char *p;
106
    } sp;
107
    struct {
108
	char c;
109
	float f;
110
    } sf;
111
    struct {
112
	char c;
113
	double d;
114
    } sd;
115
    /* Some architectures have special alignment requirements for jmpbuf. */
116
    struct {
117
	char c;
118
	jmp_buf j;
119
    } sj;
120
    long lm1 = -1;
121
    long lr1 = lm1 >> 1, lr2 = lm1 >> 2;
122
    unsigned long um1 = ~(unsigned long)0;
123
    int im1 = -1;
124
    int ir1 = im1 >> 1, ir2 = im1 >> 2;
125
    union {
126
	long l;
127
	char *p;
128
    } pl0, pl1;
129
    int ars;
130
    int lwidth = size_of(long) * 8;
131
    union {
132
	float f;
133
	int i;
134
	long l;
135
    } f0, f1, fm1;
136
    int floats_are_IEEE;
137
    FILE *f = fopen(fname, "w");
138
 
139
    if (f == NULL) {
140
	fprintf(stderr, "genarch.c: can't open %s for writing\n", fname);
141
	return exit_FAILED;
142
    }
143
    fprintf(f, "/* Parameters derived from machine and compiler architecture. */\n");
144
    fprintf(f, "/* This file is generated mechanically by genarch.c. */\n");
145
 
146
    /* We have to test the size dynamically here, */
147
    /* because the preprocessor can't evaluate sizeof. */
148
    f0.f = 0.0, f1.f = 1.0, fm1.f = -1.0;
149
    floats_are_IEEE =
150
	(size_of(float) == size_of(int) ?
151
	 f0.i == 0 && f1.i == (int)0x3f800000 && fm1.i == (int)0xbf800000 :
152
	 f0.l == 0 && f1.l == 0x3f800000L && fm1.l == 0xbf800000L);
153
 
154
    section(f, "Scalar alignments");
155
 
156
#define OFFSET_IN(s, e) (int)((char *)&s.e - (char *)&s)
157
    define_int(f, "ARCH_ALIGN_SHORT_MOD", OFFSET_IN(ss, s));
158
    define_int(f, "ARCH_ALIGN_INT_MOD", OFFSET_IN(si, i));
159
    define_int(f, "ARCH_ALIGN_LONG_MOD", OFFSET_IN(sl, l));
160
    define_int(f, "ARCH_ALIGN_PTR_MOD", OFFSET_IN(sp, p));
161
    define_int(f, "ARCH_ALIGN_FLOAT_MOD", OFFSET_IN(sf, f));
162
    define_int(f, "ARCH_ALIGN_DOUBLE_MOD", OFFSET_IN(sd, d));
163
    define_int(f, "ARCH_ALIGN_STRUCT_MOD", OFFSET_IN(sj, j));
164
#undef OFFSET_IN
165
 
166
    section(f, "Scalar sizes");
167
 
168
    define_int(f, "ARCH_LOG2_SIZEOF_CHAR", ilog2(size_of(char)));
169
    define_int(f, "ARCH_LOG2_SIZEOF_SHORT", ilog2(size_of(short)));
170
    define_int(f, "ARCH_LOG2_SIZEOF_INT", ilog2(size_of(int)));
171
    define_int(f, "ARCH_LOG2_SIZEOF_LONG", ilog2(size_of(long)));
172
#ifdef HAVE_LONG_LONG
173
    define_int(f, "ARCH_LOG2_SIZEOF_LONG_LONG", ilog2(size_of(long long)));
174
#endif
175
    define_int(f, "ARCH_SIZEOF_PTR", size_of(char *));
176
    define_int(f, "ARCH_SIZEOF_FLOAT", size_of(float));
177
    define_int(f, "ARCH_SIZEOF_DOUBLE", size_of(double));
178
    if (floats_are_IEEE) {
179
	define_int(f, "ARCH_FLOAT_MANTISSA_BITS", 24);
180
	define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", 53);
181
    } else {
182
	/*
183
	 * There isn't any general way to compute the number of mantissa
184
	 * bits accurately, especially if the machine uses hex rather
185
	 * than binary exponents.  Use conservative values, assuming
186
	 * the exponent is stored in a 16-bit word of its own.
187
	 */
188
	define_int(f, "ARCH_FLOAT_MANTISSA_BITS", sizeof(float) * 8 - 17);
189
	define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", sizeof(double) * 8 - 17);
190
    }
191
 
192
    section(f, "Unsigned max values");
193
 
194
    /*
195
     * We can't use fprintf with a numeric value for PRINT_MAX, because
196
     * too many compilers produce warnings or do the wrong thing for
197
     * complementing or widening unsigned types.
198
     */
199
#define PRINT_MAX(str, typ, tstr, l)\
200
  BEGIN\
201
    define(f, str);\
202
    fprintf(f, "((%s)0x", tstr);\
203
    print_ffs(f, sizeof(typ));\
204
    fprintf(f, "%s + (%s)0)\n", l, tstr);\
205
  END
206
    PRINT_MAX("ARCH_MAX_UCHAR", unsigned char, "unsigned char", "");
207
    PRINT_MAX("ARCH_MAX_USHORT", unsigned short, "unsigned short", "");
208
    /*
209
     * For uint and ulong, a different approach is required to keep gcc
210
     * with -Wtraditional from spewing out pointless warnings.
211
     */
212
    define(f, "ARCH_MAX_UINT");
213
    fprintf(f, "((unsigned int)~0 + (unsigned int)0)\n");
214
    define(f, "ARCH_MAX_ULONG");
215
    fprintf(f, "((unsigned long)~0L + (unsigned long)0)\n");
216
#undef PRINT_MAX
217
 
218
    section(f, "Cache sizes");
219
 
220
    /*
221
     * Determine the primary and secondary cache sizes by looking for a
222
     * non-linearity in the time required to fill blocks with memset.
223
     */
224
    {
225
#define MAX_BLOCK (1 << 22)	/* max 4M cache */
226
#define MAX_NREPS (1 << 10)	/* limit the number of reps we try */
227
	static char buf[MAX_BLOCK];
228
	int bsize = 1 << 10;
229
	int nreps = 1;
230
	clock_t t = 0;
231
	clock_t t_eps;
232
 
233
	/*
234
	 * Increase the number of repetitions until the time is
235
	 * long enough to exceed the likely uncertainty.
236
	 */
237
 
238
	while (nreps < MAX_NREPS && (t = time_clear(buf, bsize, nreps)) == 0)
239
	    nreps <<= 1;
240
	t_eps = t;
241
	while (nreps < MAX_NREPS && (t = time_clear(buf, bsize, nreps)) < t_eps * 10)
242
	    nreps <<= 1;
243
 
244
	/*
245
	 * Increase the block size until the time jumps non-linearly.
246
	 */
247
	for (; bsize <= MAX_BLOCK;) {
248
	    clock_t dt = time_clear(buf, bsize, nreps);
249
 
250
	    if (dt > t + (t >> 1)) {
251
		t = dt;
252
		break;
253
	    }
254
	    bsize <<= 1;
255
	    nreps >>= 1;
256
	    if (nreps == 0)
257
		nreps = 1, t <<= 1;
258
	}
259
	define_int(f, "ARCH_CACHE1_SIZE", bsize >> 1);
260
	/*
261
	 * Do the same thing a second time for the secondary cache.
262
	 */
263
	if (nreps > 1)
264
	    nreps >>= 1, t >>= 1;
265
	for (; bsize <= MAX_BLOCK;) {
266
	    clock_t dt = time_clear(buf, bsize, nreps);
267
 
268
	    if (dt > t * 1.25) {
269
		t = dt;
270
		break;
271
	    }
272
	    bsize <<= 1;
273
	    nreps >>= 1;
274
	    if (nreps == 0)
275
		nreps = 1, t <<= 1;
276
	}
277
	define_int(f, "ARCH_CACHE2_SIZE", bsize >> 1);
278
    }
279
 
280
    section(f, "Miscellaneous");
281
 
282
    define_int(f, "ARCH_IS_BIG_ENDIAN", 1 - *(char *)&one);
283
    pl0.l = 0;
284
    pl1.l = -1;
285
    define_int(f, "ARCH_PTRS_ARE_SIGNED", (pl1.p < pl0.p));
286
    define_int(f, "ARCH_FLOATS_ARE_IEEE", (floats_are_IEEE ? 1 : 0));
287
 
288
    /*
289
     * There are three cases for arithmetic right shift:
290
     * always correct, correct except for right-shifting a long by 1
291
     * (a bug in some versions of the Turbo C compiler), and
292
     * never correct.
293
     */
294
    ars = (lr2 != -1 || ir1 != -1 || ir2 != -1 ? 0 :
295
	   lr1 != -1 ? 1 :	/* Turbo C problem */
296
	   2);
297
    define_int(f, "ARCH_ARITH_RSHIFT", ars);
298
    /*
299
     * Some machines can't handle a variable shift by
300
     * the full width of a long.
301
     */
302
    define_int(f, "ARCH_CAN_SHIFT_FULL_LONG", um1 >> lwidth == 0);
303
    /*
304
     * Determine whether dividing a negative integer by a positive one
305
     * takes the floor or truncates toward zero.
306
     */
307
    define_int(f, "ARCH_DIV_NEG_POS_TRUNCATES", im1 / 2 == 0);
308
 
309
/* ---------------- Done. ---------------- */
310
 
311
    fclose(f);
312
    return exit_OK;
313
}