1/*	Id: mkext.c,v 1.50 2011/06/05 08:54:43 plunky Exp 	*/
2/*	$NetBSD: mkext.c,v 1.1.1.4 2011/09/01 12:47:13 plunky Exp $	*/
3
4/*
5 * Generate defines for the needed hardops.
6 */
7#include "pass2.h"
8#include <stdlib.h>
9
10#ifdef HAVE_STRING_H
11#include <string.h>
12#endif
13
14#ifdef HAVE_C99_FORMAT
15#define FMTdPTR "%td"
16#else
17#if defined(_WIN64) || defined(LP64)
18#define FMTdPTR "%ld"
19#else
20#define FMTdPTR "%d"
21#endif
22#endif
23
24int chkop[DSIZE];
25
26void mktables(void);
27
28char *ftitle;
29char *cname = "external.c";
30char *hname = "external.h";
31FILE *fc, *fh;
32
33/*
34 * masks for matching dope with shapes
35 */
36int mamask[] = {
37        SIMPFLG,                /* OPSIMP */
38        SIMPFLG|ASGFLG,         /* ASG OPSIMP */
39        COMMFLG,        /* OPCOMM */
40        COMMFLG|ASGFLG, /* ASG OPCOMM */
41        MULFLG,         /* OPMUL */
42        MULFLG|ASGFLG,  /* ASG OPMUL */
43        DIVFLG,         /* OPDIV */
44        DIVFLG|ASGFLG,  /* ASG OPDIV */
45        UTYPE,          /* OPUNARY */
46        TYFLG,          /* ASG OPUNARY is senseless */
47        LTYPE,          /* OPLEAF */
48        TYFLG,          /* ASG OPLEAF is senseless */
49        0,              /* OPANY */
50        ASGOPFLG|ASGFLG,        /* ASG OPANY */
51        LOGFLG,         /* OPLOG */
52        TYFLG,          /* ASG OPLOG is senseless */
53        FLOFLG,         /* OPFLOAT */
54        FLOFLG|ASGFLG,  /* ASG OPFLOAT */
55        SHFFLG,         /* OPSHFT */
56        SHFFLG|ASGFLG,  /* ASG OPSHIFT */
57        SPFLG,          /* OPLTYPE */
58        TYFLG,          /* ASG OPLTYPE is senseless */
59        };
60
61
62struct checks {
63	int op, type;
64	char *name;
65} checks[] = {
66	{ MUL, TLONGLONG, "SMULLL", },
67	{ DIV, TLONGLONG, "SDIVLL", },
68	{ MOD, TLONGLONG, "SMODLL", },
69	{ PLUS, TLONGLONG, "SPLUSLL", },
70	{ MINUS, TLONGLONG, "SMINUSLL", },
71	{ MUL, TULONGLONG, "UMULLL", },
72	{ DIV, TULONGLONG, "UDIVLL", },
73	{ MOD, TULONGLONG, "UMODLL", },
74	{ PLUS, TULONGLONG, "UPLUSLL", },
75	{ MINUS, TULONGLONG, "UMINUSLL", },
76	{ 0, 0, 0, },
77};
78
79int rstatus[] = { RSTATUS };
80int roverlay[MAXREGS][MAXREGS] = { ROVERLAP };
81int regclassmap[CLASSG][MAXREGS]; /* CLASSG is highest class */
82
83static void
84compl(struct optab *q, char *str)
85{
86	int op = q->op;
87	char *s;
88
89	if (op < OPSIMP) {
90		s = opst[op];
91	} else
92		switch (op) {
93		default:	s = "Special op";	break;
94		case OPSIMP:	s = "OPLSIMP";	break;
95		case OPCOMM:	s = "OPCOMM";	break;
96		case OPMUL:	s = "OPMUL";	break;
97		case OPDIV:	s = "OPDIV";	break;
98		case OPUNARY:	s = "OPUNARY";	break;
99		case OPLEAF:	s = "OPLEAF";	break;
100		case OPANY:	s = "OPANY";	break;
101		case OPLOG:	s = "OPLOG";	break;
102		case OPFLOAT:	s = "OPFLOAT";	break;
103		case OPSHFT:	s = "OPSHFT";	break;
104		case OPLTYPE:	s = "OPLTYPE";	break;
105		}
106
107	printf("table entry " FMTdPTR ", op %s: %s\n", q - table, s, str);
108}
109
110static int
111getrcl(struct optab *q)
112{
113	int v = q->needs &
114	    (NACOUNT|NBCOUNT|NCCOUNT|NDCOUNT|NECOUNT|NFCOUNT|NGCOUNT);
115	int r = q->rewrite & RESC1 ? 1 : q->rewrite & RESC2 ? 2 : 3;
116	int i = 0;
117
118#define INCK(c) while (v & c##COUNT) { \
119	v -= c##REG, i++; if (i == r) return I##c##REG; }
120	INCK(NA)
121	INCK(NB)
122	INCK(NC)
123	INCK(ND)
124	INCK(NE)
125	INCK(NF)
126	INCK(NG)
127	return 0;
128}
129
130int
131main(int argc, char *argv[])
132{
133	struct optab *q;
134	struct checks *ch;
135	int i, j, areg, breg, creg, dreg, mx, ereg, freg, greg;
136	char *bitary;
137	int bitsz, rval, nelem;
138
139	if (argc == 2) {
140		i = atoi(argv[1]);
141		printf("Entry %d:\n%s\n", i, table[i].cstring);
142		return 0;
143	}
144
145	mkdope();
146
147	for (q = table; q->op != FREE; q++) {
148		if (q->op >= OPSIMP)
149			continue;
150		if ((q->ltype & TLONGLONG) &&
151		    (q->rtype & TLONGLONG))
152			chkop[q->op] |= TLONGLONG;
153		if ((q->ltype & TULONGLONG) &&
154		    (q->rtype & TULONGLONG))
155			chkop[q->op] |= TULONGLONG;
156	}
157	if ((fc = fopen(cname, "w")) == NULL) {
158		perror("open cfile");
159		return(1);
160	}
161	if ((fh = fopen(hname, "w")) == NULL) {
162		perror("open hfile");
163		return(1);
164	}
165	fprintf(fh, "#ifndef _EXTERNAL_H_\n#define _EXTERNAL_H_\n");
166
167	for (ch = checks; ch->op != 0; ch++) {
168		if ((chkop[ch->op] & ch->type) == 0)
169			fprintf(fh, "#define NEED_%s\n", ch->name);
170	}
171
172	fprintf(fc, "#include \"pass2.h\"\n");
173	/* create fast-lookup tables */
174	mktables();
175
176	/* create efficient bitset sizes */
177	if (sizeof(long) == 8) { /* 64-bit arch */
178		bitary = "long";
179		bitsz = 64;
180	} else {
181		bitary = "int";
182		bitsz = sizeof(int) == 4 ? 32 : 16;
183	}
184	fprintf(fh, "#define NUMBITS %d\n", bitsz);
185	fprintf(fh, "#define BIT2BYTE(bits) "
186	     "((((bits)+NUMBITS-1)/NUMBITS)*(NUMBITS/8))\n");
187	fprintf(fh, "#define BITSET(arr, bit) "
188	     "(arr[bit/NUMBITS] |= ((%s)1 << (bit & (NUMBITS-1))))\n",
189	     bitary);
190	fprintf(fh, "#define BITCLEAR(arr, bit) "
191	     "(arr[bit/NUMBITS] &= ~((%s)1 << (bit & (NUMBITS-1))))\n",
192	     bitary);
193	fprintf(fh, "#define TESTBIT(arr, bit) "
194	     "(arr[bit/NUMBITS] & ((%s)1 << (bit & (NUMBITS-1))))\n",
195	     bitary);
196	fprintf(fh, "typedef %s bittype;\n", bitary);
197
198	/* register class definitions, used by graph-coloring */
199	/* TODO */
200
201	/* Sanity-check the table */
202	rval = 0;
203	for (q = table; q->op != FREE; q++) {
204		switch (q->op) {
205		case ASSIGN:
206#define	F(x) (q->visit & x && q->rewrite & (RLEFT|RRIGHT) && \
207		    q->lshape & ~x && q->rshape & ~x)
208			if (F(INAREG) || F(INBREG) || F(INCREG) || F(INDREG) ||
209			    F(INEREG) || F(INFREG) || F(INGREG)) {
210				compl(q, "may match without result register");
211				rval++;
212			}
213#undef F
214			/* FALLTHROUGH */
215		case STASG:
216			if ((q->visit & INREGS) && !(q->rewrite & RDEST)) {
217				compl(q, "ASSIGN/STASG reclaim must be RDEST");
218				rval++;
219			}
220			break;
221		}
222		/* check that reclaim is not the wrong class */
223		if ((q->rewrite & (RESC1|RESC2|RESC3)) &&
224		    !(q->needs & REWRITE)) {
225			if ((q->visit & getrcl(q)) == 0) {
226				compl(q, "wrong RESCx class");
227				rval++;
228			}
229		}
230		if (q->rewrite & (RESC1|RESC2|RESC3) && q->visit & FOREFF)
231			compl(q, "FOREFF may cause reclaim of wrong class");
232	}
233
234	/* print out list of scratched and permanent registers */
235	fprintf(fh, "extern int tempregs[], permregs[];\n");
236	fprintf(fc, "int tempregs[] = { ");
237	for (i = j = 0; i < MAXREGS; i++)
238		if (rstatus[i] & TEMPREG)
239			fprintf(fc, "%d, ", i), j++;
240	fprintf(fc, "-1 };\n");
241	fprintf(fh, "#define NTEMPREG %d\n", j+1);
242	fprintf(fh, "#define FREGS %d\n", j);	/* XXX - to die */
243	fprintf(fc, "int permregs[] = { ");
244	for (i = j = 0; i < MAXREGS; i++)
245		if (rstatus[i] & PERMREG)
246			fprintf(fc, "%d, ", i), j++;
247	fprintf(fc, "-1 };\n");
248	fprintf(fh, "#define NPERMREG %d\n", j+1);
249	fprintf(fc, "bittype validregs[] = {\n");
250
251if (bitsz == 64) {
252	for (j = 0; j < MAXREGS; j += bitsz) {
253		long cbit = 0;
254		for (i = 0; i < bitsz; i++) {
255			if (i+j == MAXREGS)
256				break;
257			if (rstatus[i+j] & INREGS)
258				cbit |= ((long)1 << i);
259		}
260		fprintf(fc, "\t0x%lx,\n", cbit);
261	}
262} else {
263	for (j = 0; j < MAXREGS; j += bitsz) {
264		int cbit = 0;
265		for (i = 0; i < bitsz; i++) {
266			if (i+j == MAXREGS)
267				break;
268			if (rstatus[i+j] & INREGS)
269				cbit |= (1 << i);
270		}
271		fprintf(fc, "\t0x%08x,\n", cbit);
272	}
273}
274
275	fprintf(fc, "};\n");
276	fprintf(fh, "extern bittype validregs[];\n");
277
278	/*
279	 * The register allocator uses bitmasks of registers for each class.
280	 */
281	areg = breg = creg = dreg = ereg = freg = greg = 0;
282	for (i = 0; i < MAXREGS; i++) {
283		for (j = 0; j < NUMCLASS; j++)
284			regclassmap[j][i] = -1;
285		if (rstatus[i] & SAREG) regclassmap[0][i] = areg++;
286		if (rstatus[i] & SBREG) regclassmap[1][i] = breg++;
287		if (rstatus[i] & SCREG) regclassmap[2][i] = creg++;
288		if (rstatus[i] & SDREG) regclassmap[3][i] = dreg++;
289		if (rstatus[i] & SEREG) regclassmap[4][i] = ereg++;
290		if (rstatus[i] & SFREG) regclassmap[5][i] = freg++;
291		if (rstatus[i] & SGREG) regclassmap[6][i] = greg++;
292	}
293	fprintf(fh, "#define AREGCNT %d\n", areg);
294	fprintf(fh, "#define BREGCNT %d\n", breg);
295	fprintf(fh, "#define CREGCNT %d\n", creg);
296	fprintf(fh, "#define DREGCNT %d\n", dreg);
297	fprintf(fh, "#define EREGCNT %d\n", ereg);
298	fprintf(fh, "#define FREGCNT %d\n", freg);
299	fprintf(fh, "#define GREGCNT %d\n", greg);
300	if (areg > bitsz)
301		printf("%d regs in class A (max %d)\n", areg, bitsz), rval++;
302	if (breg > bitsz)
303		printf("%d regs in class B (max %d)\n", breg, bitsz), rval++;
304	if (creg > bitsz)
305		printf("%d regs in class C (max %d)\n", creg, bitsz), rval++;
306	if (dreg > bitsz)
307		printf("%d regs in class D (max %d)\n", dreg, bitsz), rval++;
308	if (ereg > bitsz)
309		printf("%d regs in class E (max %d)\n", ereg, bitsz), rval++;
310	if (freg > bitsz)
311		printf("%d regs in class F (max %d)\n", freg, bitsz), rval++;
312	if (greg > bitsz)
313		printf("%d regs in class G (max %d)\n", greg, bitsz), rval++;
314
315	fprintf(fc, "static int amap[MAXREGS][NUMCLASS] = {\n");
316	for (i = 0; i < MAXREGS; i++) {
317		int ba, bb, bc, bd, r, be, bf, bg;
318		ba = bb = bc = bd = be = bf = bg = 0;
319		if (rstatus[i] & SAREG) ba = (1 << regclassmap[0][i]);
320		if (rstatus[i] & SBREG) bb = (1 << regclassmap[1][i]);
321		if (rstatus[i] & SCREG) bc = (1 << regclassmap[2][i]);
322		if (rstatus[i] & SDREG) bd = (1 << regclassmap[3][i]);
323		if (rstatus[i] & SEREG) be = (1 << regclassmap[4][i]);
324		if (rstatus[i] & SFREG) bf = (1 << regclassmap[5][i]);
325		if (rstatus[i] & SGREG) bg = (1 << regclassmap[6][i]);
326		for (j = 0; roverlay[i][j] >= 0; j++) {
327			r = roverlay[i][j];
328			if (rstatus[r] & SAREG)
329				ba |= (1 << regclassmap[0][r]);
330			if (rstatus[r] & SBREG)
331				bb |= (1 << regclassmap[1][r]);
332			if (rstatus[r] & SCREG)
333				bc |= (1 << regclassmap[2][r]);
334			if (rstatus[r] & SDREG)
335				bd |= (1 << regclassmap[3][r]);
336			if (rstatus[r] & SEREG)
337				be |= (1 << regclassmap[4][r]);
338			if (rstatus[r] & SFREG)
339				bf |= (1 << regclassmap[5][r]);
340			if (rstatus[r] & SGREG)
341				bg |= (1 << regclassmap[6][r]);
342		}
343		fprintf(fc, "\t/* %d */{ 0x%x", i, ba);
344		if (NUMCLASS > 1) fprintf(fc, ",0x%x", bb);
345		if (NUMCLASS > 2) fprintf(fc, ",0x%x", bc);
346		if (NUMCLASS > 3) fprintf(fc, ",0x%x", bd);
347		if (NUMCLASS > 4) fprintf(fc, ",0x%x", be);
348		if (NUMCLASS > 5) fprintf(fc, ",0x%x", bf);
349		if (NUMCLASS > 6) fprintf(fc, ",0x%x", bg);
350		fprintf(fc, " },\n");
351	}
352	fprintf(fc, "};\n");
353
354	fprintf(fh, "int aliasmap(int class, int regnum);\n");
355	fprintf(fc, "int\naliasmap(int class, int regnum)\n{\n");
356	fprintf(fc, "	return amap[regnum][class-1];\n}\n");
357
358	/* routines to convert back from color to regnum */
359	mx = areg;
360	if (breg > mx) mx = breg;
361	if (creg > mx) mx = creg;
362	if (dreg > mx) mx = dreg;
363	if (ereg > mx) mx = ereg;
364	if (freg > mx) mx = freg;
365	if (greg > mx) mx = greg;
366	if (mx > (int)(sizeof(int)*8)-1) {
367		printf("too many regs in a class, use two classes instead\n");
368#ifdef HAVE_C99_FORMAT
369		printf("%d > %zu\n", mx, (sizeof(int)*8)-1);
370#else
371		printf("%d > %d\n", mx, (int)(sizeof(int)*8)-1);
372#endif
373		rval++;
374	}
375	fprintf(fc, "static int rmap[NUMCLASS][%d] = {\n", mx);
376	for (j = 0; j < NUMCLASS; j++) {
377		int cl = (1 << (j+1));
378		fprintf(fc, "\t{ ");
379		for (i = 0; i < MAXREGS; i++)
380			if (rstatus[i] & cl) fprintf(fc, "%d, ", i);
381		fprintf(fc, "},\n");
382	}
383	fprintf(fc, "};\n\n");
384
385	fprintf(fh, "int color2reg(int color, int class);\n");
386	fprintf(fc, "int\ncolor2reg(int color, int class)\n{\n");
387	fprintf(fc, "	return rmap[class-1][color];\n}\n");
388
389	/* used by register allocator */
390	fprintf(fc, "int regK[] = { 0, %d, %d, %d, %d, %d, %d, %d };\n",
391	    areg, breg, creg, dreg, ereg, freg, greg);
392	fprintf(fc, "int\nclassmask(int class)\n{\n");
393	fprintf(fc, "\tif(class == CLASSA) return 0x%x;\n", (1 << areg)-1);
394	fprintf(fc, "\tif(class == CLASSB) return 0x%x;\n", (1 << breg)-1);
395	fprintf(fc, "\tif(class == CLASSC) return 0x%x;\n", (1 << creg)-1);
396	fprintf(fc, "\tif(class == CLASSD) return 0x%x;\n", (1 << dreg)-1);
397	fprintf(fc, "\tif(class == CLASSE) return 0x%x;\n", (1 << ereg)-1);
398	fprintf(fc, "\tif(class == CLASSF) return 0x%x;\n", (1 << freg)-1);
399	fprintf(fc, "\treturn 0x%x;\n}\n", (1 << greg)-1);
400
401	fprintf(fh, "int interferes(int reg1, int reg2);\n");
402	nelem = (MAXREGS+bitsz-1)/bitsz;
403	fprintf(fc, "static bittype ovlarr[MAXREGS][%d] = {\n", nelem);
404	for (i = 0; i < MAXREGS; i++) {
405		int el[10];
406		memset(el, 0, sizeof(el));
407		el[i/bitsz] = 1 << (i % bitsz);
408		for (j = 0; roverlay[i][j] >= 0; j++) {
409			int k = roverlay[i][j];
410			el[k/bitsz] |= (1 << (k % bitsz));
411		}
412		fprintf(fc, "{ ");
413		for (j = 0; j < MAXREGS; j += bitsz)
414			fprintf(fc, "0x%x, ", el[j/bitsz]);
415		fprintf(fc, " },\n");
416	}
417	fprintf(fc, "};\n");
418
419	fprintf(fc, "int\ninterferes(int reg1, int reg2)\n{\n");
420	fprintf(fc, "return (TESTBIT(ovlarr[reg1], reg2)) != 0;\n}\n");
421	fclose(fc);
422	fprintf(fh, "#endif /* _EXTERNAL_H_ */\n");
423	fclose(fh);
424	return rval;
425}
426
427#define	P(x)	fprintf x
428
429void
430mktables()
431{
432	struct optab *op;
433	int mxalen = 0, curalen;
434	int i;
435
436#if 0
437	P((fc, "#include \"pass2.h\"\n\n"));
438#endif
439	for (i = 0; i <= MAXOP; i++) {
440		curalen = 0;
441		P((fc, "static int op%d[] = { ", i));
442		if (dope[i] != 0)
443		for (op = table; op->op != FREE; op++) {
444			if (op->op < OPSIMP) {
445				if (op->op == i) {
446					P((fc, FMTdPTR ", ", op - table));
447					curalen++;
448				}
449			} else {
450				int opmtemp;
451				if ((opmtemp=mamask[op->op - OPSIMP])&SPFLG) {
452					if (i==NAME || i==ICON || i==TEMP ||
453					    i==OREG || i == REG || i == FCON) {
454						P((fc, FMTdPTR ", ",
455						    op - table));
456						curalen++;
457					}
458				} else if ((dope[i]&(opmtemp|ASGFLG))==opmtemp){
459					P((fc, FMTdPTR ", ", op - table));
460					curalen++;
461				}
462			}
463		}
464		if (curalen > mxalen)
465			mxalen = curalen;
466		P((fc, "-1 };\n"));
467	}
468	P((fc, "\n"));
469
470	P((fc, "int *qtable[] = { \n"));
471	for (i = 0; i <= MAXOP; i++) {
472		P((fc, "	op%d,\n", i));
473	}
474	P((fc, "};\n"));
475	P((fh, "#define MAXOPLEN %d\n", mxalen+1));
476}
477