1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied,
8 modified or distributed except as expressly authorized under the terms
9 of the license contained in the file LICENSE in this distribution.
10
11 Refer to licensing information at http://www.artifex.com or contact
12 Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /*
18 * Generate a header file (arch.h) with parameters
19 * reflecting the machine architecture and compiler characteristics.
20 */
21
22 #include "stdpre.h"
23 #include <ctype.h>
24 #include <stdio.h>
25 /*
26 * In theory, not all systems provide <string.h> or declare memset
27 * there, but at this point we don't think we care about any that don't.
28 */
29 #include <string.h>
30 #include <time.h>
31
32 /* We provide a _SIZEOF_ macro for GX_COLOR_INDEX_TYPE
33 fallback to a generic int if no such type is defined.
34 This default must be kept in sync with the one in gxcindex.h
35 or ARCH_SIZEOF_GX_COLOR_INDEX will be incorrect for such builds. */
36 #ifndef GX_COLOR_INDEX_TYPE
37 #define GX_COLOR_INDEX_TYPE ulong
38 #endif
39
40 /* We should write the result on stdout, but the original Turbo C 'make' */
41 /* can't handle output redirection (sigh). */
42
43 static void
section(FILE * f,const char * str)44 section(FILE * f, const char *str)
45 {
46 fprintf(f, "\n\t /* ---------------- %s ---------------- */\n\n", str);
47 }
48
49 static void
define(FILE * f,const char * str)50 define(FILE *f, const char *str)
51 {
52 fprintf(f, "#define %s ", str);
53 }
54
55 static void
define_int(FILE * f,const char * str,int value)56 define_int(FILE *f, const char *str, int value)
57 {
58 fprintf(f, "#define %s %d\n", str, value);
59 }
60
61 static void
print_ffs(FILE * f,int nbytes)62 print_ffs(FILE *f, int nbytes)
63 {
64 int i;
65
66 for (i = 0; i < nbytes; ++i)
67 fprintf(f, "ff");
68 }
69
70 static int
ilog2(int n)71 ilog2(int n)
72 {
73 int i = 0, m = n;
74
75 while (m > 1)
76 ++i, m = (m + 1) >> 1;
77 return i;
78 }
79
80 static int
copy_existing_file(FILE * f,char * infname)81 copy_existing_file(FILE *f, char *infname)
82 {
83 FILE *in = fopen(infname, "r");
84 char buffer[1024];
85 size_t l;
86
87 if (in == NULL) {
88 fprintf(stderr, "genarch.c: can't open %s for reading\n", infname);
89 fclose(f);
90 return exit_FAILED;
91 }
92 while (!feof(in)) {
93 l = fread(buffer, 1, 1024, in);
94 if (l > 0)
95 fwrite(buffer, 1, l, f);
96 }
97 fclose(in);
98 fclose(f);
99
100 return exit_OK;
101 }
102
103 int
main(int argc,char * argv[])104 main(int argc, char *argv[])
105 {
106 char *fname;
107 long one = 1;
108 struct {
109 char c;
110 short s;
111 } ss;
112 struct {
113 char c;
114 int i;
115 } si;
116 struct {
117 char c;
118 long l;
119 } sl;
120 struct {
121 char c;
122 char *p;
123 } sp;
124 struct {
125 char c;
126 float f;
127 } sf;
128 struct {
129 char c;
130 double d;
131 } sd;
132 struct {
133 char c;
134 size_t z;
135 } sz;
136 long lm1 = -1;
137 long lr1 = lm1 >> 1, lr2 = lm1 >> 2;
138 int im1 = -1;
139 int ir1 = im1 >> 1, ir2 = im1 >> 2;
140 union {
141 long l;
142 char *p;
143 } pl0, pl1;
144 int ars;
145 union {
146 float f;
147 int i;
148 long l;
149 } f0, f1, fm1;
150 int floats_are_IEEE;
151 FILE *f;
152
153 if (argc < 2 || argc > 3) {
154 fprintf(stderr, "genarch: Invalid invocation\n"
155 "genarch <output-file> [ <existing-config-file> ]\n");
156 return exit_FAILED;
157 }
158
159 fname = argv[1];
160 f = fopen(fname, "w");
161 if (f == NULL) {
162 fprintf(stderr, "genarch.c: can't open %s for writing\n", fname);
163 return exit_FAILED;
164 }
165
166 if (argc == 3) {
167 return copy_existing_file(f, argv[2]);
168 }
169
170 fprintf(f, "/* Parameters derived from machine and compiler architecture. */\n");
171 fprintf(f, "/* This file is generated mechanically by genarch.c. */\n");
172
173 /* We have to test the size dynamically here, */
174 /* because the preprocessor can't evaluate sizeof. */
175 f0.f = 0.0, f1.f = 1.0, fm1.f = -1.0;
176 floats_are_IEEE =
177 (size_of(float) == size_of(int) ?
178 f0.i == 0 && f1.i == (int)0x3f800000 && fm1.i == (int)0xbf800000 :
179 f0.l == 0 && f1.l == 0x3f800000L && fm1.l == 0xbf800000L);
180
181 section(f, "Scalar alignments");
182
183 #define OFFSET_IN(s, e) (int)((char *)&s.e - (char *)&s)
184 define_int(f, "ARCH_ALIGN_SHORT_MOD", OFFSET_IN(ss, s));
185 define_int(f, "ARCH_ALIGN_INT_MOD", OFFSET_IN(si, i));
186 define_int(f, "ARCH_ALIGN_LONG_MOD", OFFSET_IN(sl, l));
187 define_int(f, "ARCH_ALIGN_SIZE_T_MOD", OFFSET_IN(sz, z));
188
189 #if defined (GS_MEMPTR_ALIGNMENT) && GS_MEMPTR_ALIGNMENT != 0
190 define_int(f, "ARCH_ALIGN_PTR_MOD", GS_MEMPTR_ALIGNMENT);
191 #else
192 #if defined (sparc) || defined (__hpux)
193 # ifndef __BIGGEST_ALIGNMENT__
194 # define __BIGGEST_ALIGNMENT__ 8
195 # endif
196 define_int(f, "ARCH_ALIGN_PTR_MOD", __BIGGEST_ALIGNMENT__);
197 #else
198 define_int(f, "ARCH_ALIGN_PTR_MOD", OFFSET_IN(sp, p));
199 #endif
200 #endif
201
202 define_int(f, "ARCH_ALIGN_FLOAT_MOD", OFFSET_IN(sf, f));
203 define_int(f, "ARCH_ALIGN_DOUBLE_MOD", OFFSET_IN(sd, d));
204 #undef OFFSET_IN
205
206 /* Some architectures have special alignment requirements for */
207 /* jmp_buf, and we used to provide ALIGN_STRUCT_MOD for that. */
208 /* We've now dropped that in favor of aligning jmp_buf by hand. */
209 /* See setjmp_.h for the implementation of this. */
210
211 section(f, "Scalar sizes");
212
213 define_int(f, "ARCH_LOG2_SIZEOF_CHAR", ilog2(size_of(char)));
214 define_int(f, "ARCH_LOG2_SIZEOF_SHORT", ilog2(size_of(short)));
215 define_int(f, "ARCH_LOG2_SIZEOF_INT", ilog2(size_of(int)));
216 define_int(f, "ARCH_LOG2_SIZEOF_LONG", ilog2(size_of(long)));
217 define_int(f, "ARCH_LOG2_SIZEOF_SIZE_T", ilog2(size_of(size_t)));
218 #if !defined(_MSC_VER) && ! (defined(__BORLANDC__) && defined(__WIN32__))
219 /* MSVC does not provide 'long long' but we need this on some archs
220 to define a 64 bit type. A corresponding #ifdef in stdint_.h handles
221 that case for MSVC. Most other platforms do support long long if
222 they have a 64 bit type at all */
223 define_int(f, "ARCH_LOG2_SIZEOF_LONG_LONG", ilog2(size_of(long long)));
224 #endif
225 define_int(f, "ARCH_SIZEOF_SIZE_T", size_of(size_t));
226 define_int(f, "ARCH_SIZEOF_GX_COLOR_INDEX", sizeof(GX_COLOR_INDEX_TYPE));
227 define_int(f, "ARCH_SIZEOF_PTR", size_of(char *));
228 define_int(f, "ARCH_SIZEOF_FLOAT", size_of(float));
229 define_int(f, "ARCH_SIZEOF_DOUBLE", size_of(double));
230 if (floats_are_IEEE) {
231 define_int(f, "ARCH_FLOAT_MANTISSA_BITS", 24);
232 define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", 53);
233 } else {
234 /*
235 * There isn't any general way to compute the number of mantissa
236 * bits accurately, especially if the machine uses hex rather
237 * than binary exponents. Use conservative values, assuming
238 * the exponent is stored in a 16-bit word of its own.
239 */
240 define_int(f, "ARCH_FLOAT_MANTISSA_BITS", sizeof(float) * 8 - 17);
241 define_int(f, "ARCH_DOUBLE_MANTISSA_BITS", sizeof(double) * 8 - 17);
242 }
243
244 section(f, "Unsigned max values");
245
246 /*
247 * We can't use fprintf with a numeric value for PRINT_MAX, because
248 * too many compilers produce warnings or do the wrong thing for
249 * complementing or widening unsigned types.
250 */
251 #define PRINT_MAX(str, typ, tstr, l)\
252 BEGIN\
253 define(f, str);\
254 fprintf(f, "((%s)0x", tstr);\
255 print_ffs(f, sizeof(typ));\
256 fprintf(f, "%s + (%s)0)\n", l, tstr);\
257 END
258 PRINT_MAX("ARCH_MAX_UCHAR", unsigned char, "unsigned char", "");
259 PRINT_MAX("ARCH_MAX_USHORT", unsigned short, "unsigned short", "");
260 /*
261 * For uint and ulong, a different approach is required to keep gcc
262 * with -Wtraditional from spewing out pointless warnings.
263 */
264 define(f, "ARCH_MAX_UINT");
265 fprintf(f, "((unsigned int)~0 + (unsigned int)0)\n");
266 define(f, "ARCH_MAX_ULONG");
267 fprintf(f, "((unsigned long)~0L + (unsigned long)0)\n");
268 define(f, "ARCH_MAX_SIZE_T");
269 fprintf(f, "((size_t)~0L + (size_t)0)\n");
270 #undef PRINT_MAX
271
272 section(f, "Miscellaneous");
273
274 define_int(f, "ARCH_IS_BIG_ENDIAN", 1 - *(char *)&one);
275 pl0.l = 0;
276 pl1.l = -1;
277 define_int(f, "ARCH_PTRS_ARE_SIGNED", (pl1.p < pl0.p));
278 define_int(f, "ARCH_FLOATS_ARE_IEEE", (floats_are_IEEE ? 1 : 0));
279
280 /*
281 * There are three cases for arithmetic right shift:
282 * always correct, correct except for right-shifting a long by 1
283 * (a bug in some versions of the Turbo C compiler), and
284 * never correct.
285 */
286 ars = (lr2 != -1 || ir1 != -1 || ir2 != -1 ? 0 :
287 lr1 != -1 ? 1 : /* Turbo C problem */
288 2);
289 define_int(f, "ARCH_ARITH_RSHIFT", ars);
290 /*
291 * Determine whether dividing a negative integer by a positive one
292 * takes the floor or truncates toward zero.
293 */
294 define_int(f, "ARCH_DIV_NEG_POS_TRUNCATES", im1 / 2 == 0);
295
296 /* ---------------- Done. ---------------- */
297
298 fclose(f);
299 return exit_OK;
300 }
301