xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/arm/local2.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
1 /*      Id: local2.c,v 1.38 2015/01/07 05:24:53 gmcgarry Exp     */
2 /*      $NetBSD: local2.c,v 1.1.1.5 2016/02/09 20:28:12 plunky Exp $    */
3 /*
4  * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
5  * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <assert.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdlib.h>
35 
36 #include "pass2.h"
37 
38 extern void defalign(int);
39 
40 #define	exname(x) x
41 
42 char *rnames[] = {
43 	"r0", "r1", "r2", "r3","r4","r5", "r6", "r7",
44 	"r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc",
45 	"r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6",
46 	"r6r7", "r7r8", "r8r9", "r9r10",
47 	"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
48 };
49 
50 /*
51  * Handling of integer constants.  We have 8 bits + an even
52  * number of rotates available as a simple immediate.
53  * If a constant isn't trivially representable, use an ldr
54  * and a subsequent sequence of orr operations.
55  */
56 
57 static int
trepresent(const unsigned int val)58 trepresent(const unsigned int val)
59 {
60 	int i;
61 #define rotate_left(v, n) (v << n | v >> (32 - n))
62 
63 	for (i = 0; i < 32; i += 2)
64 		if (rotate_left(val, i) <= 0xff)
65 			return 1;
66 	return 0;
67 }
68 
69 /*
70  * Return values are:
71  * 0 - output constant as is (should be covered by trepresent() above)
72  * 1 - 4 generate 1-4 instructions as needed.
73  */
74 static int
encode_constant(int constant,int * values)75 encode_constant(int constant, int *values)
76 {
77 	int tmp = constant;
78 	int i = 0;
79 	int first_bit, value;
80 
81 	while (tmp) {
82 		first_bit = ffs(tmp);
83 		first_bit -= 1; /* ffs indexes from 1, not 0 */
84 		first_bit &= ~1; /* must use even bit offsets */
85 
86 		value = tmp & (0xff << first_bit);
87 		values[i++] = value;
88 		tmp &= ~value;
89 	}
90 	return i;
91 }
92 
93 #if 0
94 static void
95 load_constant(NODE *p)
96 {
97 	int v = p->n_lval & 0xffffffff;
98 	int reg = DECRA(p->n_reg, 1);
99 
100 	load_constant_into_reg(reg, v);
101 }
102 #endif
103 
104 static void
load_constant_into_reg(int reg,int v)105 load_constant_into_reg(int reg, int v)
106 {
107 	if (trepresent(v))
108 		printf("\tmov %s,#%d\n", rnames[reg], v);
109 	else if (trepresent(-v))
110 		printf("\tmvn %s,#%d\n", rnames[reg], -v);
111 	else {
112 		int vals[4], nc, i;
113 
114 		nc = encode_constant(v, vals);
115 		for (i = 0; i < nc; i++) {
116 			if (i == 0) {
117 				printf("\tmov %s,#%d" COM "load constant %d\n",
118 				    rnames[reg], vals[i], v);
119 			} else {
120 				printf("\torr %s,%s,#%d\n",
121 				    rnames[reg], rnames[reg], vals[i]);
122 			}
123 		}
124 	}
125 }
126 
127 static TWORD ftype;
128 
129 /*
130  * calculate stack size and offsets
131  */
132 static int
offcalc(struct interpass_prolog * ipp)133 offcalc(struct interpass_prolog *ipp)
134 {
135 	int addto;
136 
137 #ifdef PCC_DEBUG
138 	if (x2debug)
139 		printf("offcalc: p2maxautooff=%d\n", p2maxautooff);
140 #endif
141 
142 	addto = p2maxautooff;
143 
144 #if 0
145 	addto += 7;
146 	addto &= ~7;
147 #endif
148 
149 #ifdef PCC_DEBUG
150 	if (x2debug)
151 		printf("offcalc: addto=%d\n", addto);
152 #endif
153 
154 	addto -= AUTOINIT / SZCHAR;
155 
156 	return addto;
157 }
158 
159 void
prologue(struct interpass_prolog * ipp)160 prologue(struct interpass_prolog *ipp)
161 {
162 	int addto;
163 	int vals[4], nc, i;
164 
165 #ifdef PCC_DEBUG
166 	if (x2debug)
167 		printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%lx, autos=%d, tmpnum=%d, lblnum=%d\n",
168 			ipp->ipp_ip.type,
169 			ipp->ipp_ip.lineno,
170 			ipp->ipp_name,
171 			ipp->ipp_vis,
172 			ipp->ipp_type,
173 			ipp->ipp_regs[0],
174 			ipp->ipp_autos,
175 			ipp->ip_tmpnum,
176 			ipp->ip_lblnum);
177 #endif
178 
179 	ftype = ipp->ipp_type;
180 
181 #if 0
182 	printf("\t.align 2\n");
183 	if (ipp->ipp_vis)
184 		printf("\t.global %s\n", exname(ipp->ipp_name));
185 	printf("\t.type %s,%%function\n", exname(ipp->ipp_name));
186 #endif
187 	printf("%s:\n", exname(ipp->ipp_name));
188 
189 	/*
190 	 * We here know what register to save and how much to
191 	 * add to the stack.
192 	 */
193 	addto = offcalc(ipp);
194 
195 	printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], 16);
196 	printf("\tmov %s,%s\n", rnames[IP], rnames[SP]);
197 	printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP],
198 	    rnames[IP], rnames[LR], rnames[PC]);
199 	printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]);
200 
201 	if (addto == 0)
202 		return;
203 
204 	if (trepresent(addto)) {
205 		printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto);
206 	} else {
207 		nc = encode_constant(addto, vals);
208 		for (i = 0; i < nc; i++)
209 			printf("\tsub %s,%s,#%d\n",
210 			    rnames[SP], rnames[SP], vals[i]);
211 	}
212 }
213 
214 void
eoftn(struct interpass_prolog * ipp)215 eoftn(struct interpass_prolog *ipp)
216 {
217 	if (ipp->ipp_ip.ip_lbl == 0)
218 		return; /* no code needs to be generated */
219 
220 	/* struct return needs special treatment */
221 	if (ftype == STRTY || ftype == UNIONTY) {
222 		assert(0);
223 	} else {
224 		printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP],
225 		    rnames[SP], rnames[PC]);
226 		printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], 16);
227 	}
228 	printf("\t.size %s,.-%s\n", exname(ipp->ipp_name),
229 	    exname(ipp->ipp_name));
230 }
231 
232 
233 /*
234  * these mnemonics match the order of the preprocessor decls
235  * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
236  */
237 
238 static char *
239 ccbranches[] = {
240 	"beq",		/* branch if equal */
241 	"bne",		/* branch if not-equal */
242 	"ble",		/* branch if less-than-or-equal */
243 	"blt",		/* branch if less-than */
244 	"bge",		/* branch if greater-than-or-equal */
245 	"bgt",		/* branch if greater-than */
246 	/* what should these be ? */
247 	"bls",		/* branch if lower-than-or-same */
248 	"blo",		/* branch if lower-than */
249 	"bhs",		/* branch if higher-than-or-same */
250 	"bhi",		/* branch if higher-than */
251 };
252 
253 /*
254  * add/sub/...
255  *
256  * Param given:
257  */
258 void
hopcode(int f,int o)259 hopcode(int f, int o)
260 {
261 	char *str;
262 
263 	switch (o) {
264 	case PLUS:
265 		str = "add";
266 		break;
267 	case MINUS:
268 		str = "sub";
269 		break;
270 	case AND:
271 		str = "and";
272 		break;
273 	case OR:
274 		str = "orr";
275 		break;
276 	case ER:
277 		str = "eor";
278 		break;
279 	default:
280 		comperr("hopcode2: %d", o);
281 		str = 0; /* XXX gcc */
282 	}
283 	printf("%s%c", str, f);
284 }
285 
286 /*
287  * Return type size in bytes.  Used by R2REGS, arg 2 to offset().
288  */
289 int
tlen(NODE * p)290 tlen(NODE *p)
291 {
292 	switch(p->n_type) {
293 		case CHAR:
294 		case UCHAR:
295 			return(1);
296 
297 		case SHORT:
298 		case USHORT:
299 			return(SZSHORT/SZCHAR);
300 
301 		case DOUBLE:
302 			return(SZDOUBLE/SZCHAR);
303 
304 		case INT:
305 		case UNSIGNED:
306 		case LONG:
307 		case ULONG:
308 			return(SZINT/SZCHAR);
309 
310 		case LONGLONG:
311 		case ULONGLONG:
312 			return SZLONGLONG/SZCHAR;
313 
314 		default:
315 			if (!ISPTR(p->n_type))
316 				comperr("tlen type %d not pointer");
317 			return SZPOINT(p->n_type)/SZCHAR;
318 		}
319 }
320 
321 /*
322  * Emit code to compare two longlong numbers.
323  */
324 static void
twollcomp(NODE * p)325 twollcomp(NODE *p)
326 {
327 	int o = p->n_op;
328 	int s = getlab2();
329 	int e = p->n_label;
330 	int cb1, cb2;
331 
332 	if (o >= ULE)
333 		o -= (ULE-LE);
334 	switch (o) {
335 	case NE:
336 		cb1 = 0;
337 		cb2 = NE;
338 		break;
339 	case EQ:
340 		cb1 = NE;
341 		cb2 = 0;
342 		break;
343 	case LE:
344 	case LT:
345 		cb1 = GT;
346 		cb2 = LT;
347 		break;
348 	case GE:
349 	case GT:
350 		cb1 = LT;
351 		cb2 = GT;
352 		break;
353 
354 	default:
355 		cb1 = cb2 = 0; /* XXX gcc */
356 	}
357 	if (p->n_op >= ULE)
358 		cb1 += 4, cb2 += 4;
359 	expand(p, 0, "\tcmp UR,UL" COM "compare 64-bit values (upper)\n");
360 	if (cb1) cbgen(cb1, s);
361 	if (cb2) cbgen(cb2, e);
362 	expand(p, 0, "\tcmp AR,AL" COM "(and lower)\n");
363 	cbgen(p->n_op, e);
364 	deflab(s);
365 }
366 
367 int
fldexpand(NODE * p,int cookie,char ** cp)368 fldexpand(NODE *p, int cookie, char **cp)
369 {
370 	CONSZ val;
371 	int shft;
372 
373         if (p->n_op == ASSIGN)
374                 p = p->n_left;
375 
376 	if (features(FEATURE_BIGENDIAN))
377 		shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
378 	else
379 		shft = UPKFOFF(p->n_rval);
380 
381         switch (**cp) {
382         case 'S':
383                 printf("#%d", UPKFSZ(p->n_rval));
384                 break;
385         case 'H':
386                 printf("#%d", shft);
387                 break;
388         case 'M':
389         case 'N':
390                 val = (CONSZ)1 << UPKFSZ(p->n_rval);
391                 --val;
392                 val <<= shft;
393                 printf("%lld", (**cp == 'M' ? val : ~val)  & 0xffffffff);
394                 break;
395         default:
396                 comperr("fldexpand");
397         }
398         return 1;
399 }
400 
401 
402 /*
403  * Structure assignment.
404  */
405 static void
stasg(NODE * p)406 stasg(NODE *p)
407 {
408 	NODE *l = p->n_left;
409 	int val = l->n_lval;
410 
411 	/* R0 = dest, R1 = src, R2 = len */
412 	load_constant_into_reg(R2, attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
413 	if (l->n_op == OREG) {
414 		if (R2TEST(regno(l))) {
415 			int r = regno(l);
416 			printf("\tadd %s,%s,lsl #%d\n",
417 			    rnames[R0], rnames[R2UPK2(r)], R2UPK3(r));
418 			printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0],
419 			    rnames[R2UPK1(r)]);
420 		} else  {
421 			if (trepresent(val)) {
422 				printf("\tadd %s,%s,#%d\n",
423 				    rnames[R0], rnames[regno(l)], val);
424 			} else {
425 				load_constant_into_reg(R0, val);
426 				printf("\tadd %s,%s,%s\n", rnames[R0],
427 				    rnames[R0], rnames[regno(l)]);
428 			}
429 		}
430 	} else if (l->n_op == NAME) {
431 		cerror("not implemented");
432 	}
433 
434 	printf("\tbl %s\n", exname("memcpy"));
435 }
436 
437 static void
shiftop(NODE * p)438 shiftop(NODE *p)
439 {
440 	NODE *r = p->n_right;
441 	TWORD ty = p->n_type;
442 	char *shifttype;
443 
444 	if (p->n_op == LS && r->n_op == ICON && r->n_lval < 32) {
445 		expand(p, INBREG, "\tmov A1,AL,lsr ");
446 		printf(CONFMT COM "64-bit left-shift\n", 32 - r->n_lval);
447 		expand(p, INBREG, "\tmov U1,UL,asl AR\n");
448 		expand(p, INBREG, "\torr U1,U1,A1\n");
449 		expand(p, INBREG, "\tmov A1,AL,asl AR\n");
450 	} else if (p->n_op == LS && r->n_op == ICON && r->n_lval < 64) {
451 		expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n");
452 		expand(p, INBREG, "\tmov U1,AL");
453 		if (r->n_lval - 32 != 0)
454 			printf(",asl " CONFMT, r->n_lval - 32);
455 		printf("\n");
456 	} else if (p->n_op == LS && r->n_op == ICON) {
457 		expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n");
458 		expand(p, INBREG, "\tmov U1,#0\n");
459 	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 32) {
460 		expand(p, INBREG, "\tmov U1,UL,asl ");
461 		printf(CONFMT COM "64-bit right-shift\n", 32 - r->n_lval);
462 		expand(p, INBREG, "\tmov A1,AL,lsr AR\n");
463 		expand(p, INBREG, "\torr A1,A1,U1\n");
464 		if (ty == LONGLONG)
465 			expand(p, INBREG, "\tmov U1,UL,asr AR\n");
466 		else
467 			expand(p, INBREG, "\tmov U1,UL,lsr AR\n");
468 	} else if (p->n_op == RS && r->n_op == ICON && r->n_lval < 64) {
469 		if (ty == LONGLONG) {
470 			expand(p, INBREG, "\tmvn U1,#1" COM "64-bit right-shift\n");
471 			expand(p, INBREG, "\tmov A1,UL");
472 			shifttype = "asr";
473 		}else {
474 			expand(p, INBREG, "\tmov U1,#0" COM "64-bit right-shift\n");
475 			expand(p, INBREG, "\tmov A1,UL");
476 			shifttype = "lsr";
477 		}
478 		if (r->n_lval - 32 != 0)
479 			printf(",%s " CONFMT, shifttype, r->n_lval - 32);
480 		printf("\n");
481 	} else if (p->n_op == RS && r->n_op == ICON) {
482 		expand(p, INBREG, "\tmov A1,#0" COM "64-bit right-shift\n");
483 		expand(p, INBREG, "\tmov U1,#0\n");
484 	}
485 }
486 
487 /*
488  * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
489  */
490 static void
fpemul(NODE * p)491 fpemul(NODE *p)
492 {
493 	NODE *l = p->n_left;
494 	char *ch = NULL;
495 
496 	if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3";
497 	else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3";
498 	else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "adddf3";
499 
500 	else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3";
501 	else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3";
502 	else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subdf3";
503 
504 	else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3";
505 	else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3";
506 	else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "muldf3";
507 
508 	else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3";
509 	else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3";
510 	else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divdf3";
511 
512 	else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2";
513 	else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2";
514 	else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negdf2";
515 
516 	else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2";
517 	else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2";
518 	else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqdf2";
519 
520 	else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2";
521 	else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2";
522 	else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "nedf2";
523 
524 	else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2";
525 	else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2";
526 	else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "gedf2";
527 
528 	else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2";
529 	else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2";
530 	else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "ledf2";
531 
532 	else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2";
533 	else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2";
534 	else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gtdf2";
535 
536 	else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2";
537 	else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2";
538 	else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "ltdf2";
539 
540 	else if (p->n_op == SCONV && p->n_type == FLOAT) {
541 		if (l->n_type == DOUBLE) ch = "truncdfsf2";
542 		else if (l->n_type == LDOUBLE) ch = "truncdfsf2";
543 		else if (l->n_type == ULONGLONG) ch = "floatunsdisf";
544 		else if (l->n_type == LONGLONG) ch = "floatdisf";
545 		else if (l->n_type == LONG) ch = "floatsisf";
546 		else if (l->n_type == ULONG) ch = "floatunsisf";
547 		else if (l->n_type == INT) ch = "floatsisf";
548 		else if (l->n_type == UNSIGNED) ch = "floatunsisf";
549 	} else if (p->n_op == SCONV && p->n_type == DOUBLE) {
550 		if (l->n_type == FLOAT) ch = "extendsfdf2";
551 		else if (l->n_type == LDOUBLE) ch = "trunctfdf2";
552 		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
553 		else if (l->n_type == LONGLONG) ch = "floatdidf";
554 		else if (l->n_type == LONG) ch = "floatsidf";
555 		else if (l->n_type == ULONG) ch = "floatunsidf";
556 		else if (l->n_type == INT) ch = "floatsidf";
557 		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
558 	} else if (p->n_op == SCONV && p->n_type == LDOUBLE) {
559 		if (l->n_type == FLOAT) ch = "extendsfdf2";
560 		else if (l->n_type == DOUBLE) ch = "extenddftd2";
561 		else if (l->n_type == ULONGLONG) ch = "floatunsdidf";
562 		else if (l->n_type == LONGLONG) ch = "floatdidf";
563 		else if (l->n_type == LONG) ch = "floatsidf";
564 		else if (l->n_type == ULONG) ch = "floatunsidf";
565 		else if (l->n_type == INT) ch = "floatsidf";
566 		else if (l->n_type == UNSIGNED) ch = "floatunsidf";
567 	} else if (p->n_op == SCONV && p->n_type == ULONGLONG) {
568 		if (l->n_type == FLOAT) ch = "fixunssfdi";
569 		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
570 		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
571 	} else if (p->n_op == SCONV && p->n_type == LONGLONG) {
572 		if (l->n_type == FLOAT) ch = "fixsfdi";
573 		else if (l->n_type == DOUBLE) ch = "fixdfdi";
574 		else if (l->n_type == LDOUBLE) ch = "fixdfdi";
575 	} else if (p->n_op == SCONV && p->n_type == LONG) {
576 		if (l->n_type == FLOAT) ch = "fixsfsi";
577 		else if (l->n_type == DOUBLE) ch = "fixdfsi";
578 		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
579 	} else if (p->n_op == SCONV && p->n_type == ULONG) {
580 		if (l->n_type == FLOAT) ch = "fixunssfdi";
581 		else if (l->n_type == DOUBLE) ch = "fixunsdfdi";
582 		else if (l->n_type == LDOUBLE) ch = "fixunsdfdi";
583 	} else if (p->n_op == SCONV && p->n_type == INT) {
584 		if (l->n_type == FLOAT) ch = "fixsfsi";
585 		else if (l->n_type == DOUBLE) ch = "fixdfsi";
586 		else if (l->n_type == LDOUBLE) ch = "fixdfsi";
587 	} else if (p->n_op == SCONV && p->n_type == UNSIGNED) {
588 		if (l->n_type == FLOAT) ch = "fixunssfsi";
589 		else if (l->n_type == DOUBLE) ch = "fixunsdfsi";
590 		else if (l->n_type == LDOUBLE) ch = "fixunsdfsi";
591 	}
592 
593 	if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
594 
595 	printf("\tbl __%s" COM "softfloat operation\n", exname(ch));
596 
597 	if (p->n_op >= EQ && p->n_op <= GT)
598 		printf("\tcmp %s,#0\n", rnames[R0]);
599 }
600 
601 
602 /*
603  * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
604  */
605 
606 static void
emul(NODE * p)607 emul(NODE *p)
608 {
609 	char *ch = NULL;
610 
611 	if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3";
612 	else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashlsi3";
613 	else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3";
614 
615 	else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3";
616 	else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrsi3";
617 	else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3";
618 
619 	else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3";
620 	else if (p->n_op == RS && p->n_type == LONG) ch = "ashrsi3";
621 	else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3";
622 
623 	else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3";
624 	else if (p->n_op == DIV && p->n_type == LONG) ch = "divsi3";
625 	else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3";
626 
627 	else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3";
628 	else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivsi3";
629 	else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3";
630 
631 	else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3";
632 	else if (p->n_op == MOD && p->n_type == LONG) ch = "modsi3";
633 	else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3";
634 
635 	else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3";
636 	else if (p->n_op == MOD && p->n_type == ULONG) ch = "umodsi3";
637 	else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3";
638 
639 	else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3";
640 	else if (p->n_op == MUL && p->n_type == LONG) ch = "mulsi3";
641 	else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3";
642 
643 	else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2";
644 	else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2";
645 	else if (p->n_op == UMINUS && p->n_type == INT) ch = "negsi2";
646 
647 	else ch = 0, comperr("ZE");
648 	printf("\tbl __%s" COM "emulated operation\n", exname(ch));
649 }
650 
651 static void
halfword(NODE * p)652 halfword(NODE *p)
653 {
654         NODE *r = getlr(p, 'R');
655         NODE *l = getlr(p, 'L');
656 	int idx0 = 0, idx1 = 1;
657 
658 	if (features(FEATURE_BIGENDIAN)) {
659 		idx0 = 1;
660 		idx1 = 0;
661 	}
662 
663 	if (p->n_op == ASSIGN && r->n_op == OREG) {
664                 /* load */
665                 expand(p, 0, "\tldrb A1,");
666                 printf("[%s," CONFMT "]\n", rnames[r->n_rval], r->n_lval+idx0);
667                 expand(p, 0, "\tldrb AL,");
668                 printf("[%s," CONFMT "]\n", rnames[r->n_rval], r->n_lval+idx1);
669                 expand(p, 0, "\torr AL,A1,AL,asl #8\n");
670         } else if (p->n_op == ASSIGN && l->n_op == OREG) {
671                 /* store */
672                 expand(p, 0, "\tstrb AR,");
673                 printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx0);
674                 expand(p, 0, "\tmov A1,AR,asr #8\n");
675                 expand(p, 0, "\tstrb A1,");
676                 printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx1);
677         } else if (p->n_op == SCONV || p->n_op == UMUL) {
678                 /* load */
679                 expand(p, 0, "\tldrb A1,");
680                 printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx0);
681                 expand(p, 0, "\tldrb A2,");
682                 printf("[%s," CONFMT "]\n", rnames[l->n_rval], l->n_lval+idx1);
683                 expand(p, 0, "\torr A1,A1,A2,asl #8\n");
684         } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) {
685                 /* load */
686                 expand(p, 0, "\tldrb A1,");
687                 printf("[%s," CONFMT "]\n", rnames[p->n_rval], p->n_lval+idx0);
688                 expand(p, 0, "\tldrb A2,");
689                 printf("[%s," CONFMT "]\n", rnames[p->n_rval], p->n_lval+idx1);
690                 expand(p, 0, "\torr A1,A1,A2,asl #8\n");
691 	} else {
692 		comperr("halfword");
693         }
694 }
695 
696 static void
bfext(NODE * p)697 bfext(NODE *p)
698 {
699         int sz;
700 
701         if (ISUNSIGNED(p->n_right->n_type))
702                 return;
703         sz = 32 - UPKFSZ(p->n_left->n_rval);
704 
705 	expand(p, 0, "\tmov AD,AD,asl ");
706         printf("#%d\n", sz);
707 	expand(p, 0, "\tmov AD,AD,asr ");
708         printf("#%d\n", sz);
709 }
710 
711 static int
argsiz(NODE * p)712 argsiz(NODE *p)
713 {
714 	TWORD t = p->n_type;
715 
716 	if (t < LONGLONG || t == FLOAT || t > BTMASK)
717 		return 4;
718 	if (t == LONGLONG || t == ULONGLONG)
719 		return 8;
720 	if (t == DOUBLE || t == LDOUBLE)
721 		return 8;
722 	if (t == STRTY || t == UNIONTY)
723 		return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
724 	comperr("argsiz");
725 	return 0;
726 }
727 
728 void
zzzcode(NODE * p,int c)729 zzzcode(NODE *p, int c)
730 {
731 	int pr;
732 
733 	switch (c) {
734 
735 	case 'B': /* bit-field sign extension */
736 		bfext(p);
737 		break;
738 
739 	case 'C':  /* remove from stack after subroutine call */
740 		pr = p->n_qual;
741 #if 0
742 		if (p->n_op == STCALL || p->n_op == USTCALL)
743 			pr += 4;
744 #endif
745 		if (p->n_op == UCALL)
746 			return; /* XXX remove ZC from UCALL */
747 		if (pr > 0)
748 			printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr);
749 		break;
750 
751 	case 'D': /* Long long comparision */
752 		twollcomp(p);
753 		break;
754 
755 	case 'E': /* print out emulated ops */
756 		emul(p);
757                 break;
758 
759 	case 'F': /* print out emulated floating-point ops */
760 		fpemul(p);
761 		break;
762 
763 	case 'H':		/* do halfword access */
764 		halfword(p);
765 		break;
766 
767 	case 'I':		/* init constant */
768 		if (p->n_name[0] != '\0')
769 			comperr("named init");
770 		load_constant_into_reg(DECRA(p->n_reg, 1),
771 		    p->n_lval & 0xffffffff);
772 		break;
773 
774 	case 'J':		/* init longlong constant */
775 		load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1,
776 		    p->n_lval & 0xffffffff);
777 		load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1 + 1,
778                     (p->n_lval >> 32));
779                 break;
780 
781 	case 'O': /* 64-bit left and right shift operators */
782 		shiftop(p);
783 		break;
784 
785 	case 'Q': /* emit struct assign */
786 		stasg(p);
787 		break;
788 
789 	default:
790 		comperr("zzzcode %c", c);
791 	}
792 }
793 
794 /*ARGSUSED*/
795 int
rewfld(NODE * p)796 rewfld(NODE *p)
797 {
798 	return(1);
799 }
800 
801 /*
802  * Does the bitfield shape match?
803  */
804 int
flshape(NODE * p)805 flshape(NODE *p)
806 {
807 	int o = p->n_op;
808 
809 	if (o == OREG || o == REG || o == NAME)
810 		return SRDIR; /* Direct match */
811 	if (o == UMUL && shumul(p->n_left, SOREG))
812 		return SROREG; /* Convert into oreg */
813 	return SRREG; /* put it into a register */
814 }
815 
816 /* INTEMP shapes must not contain any temporary registers */
817 /* XXX should this go away now? */
818 int
shtemp(NODE * p)819 shtemp(NODE *p)
820 {
821 	return 0;
822 #if 0
823 	int r;
824 
825 	if (p->n_op == STARG )
826 		p = p->n_left;
827 
828 	switch (p->n_op) {
829 	case REG:
830 		return (!istreg(p->n_rval));
831 
832 	case OREG:
833 		r = p->n_rval;
834 		if (R2TEST(r)) {
835 			if (istreg(R2UPK1(r)))
836 				return(0);
837 			r = R2UPK2(r);
838 		}
839 		return (!istreg(r));
840 
841 	case UMUL:
842 		p = p->n_left;
843 		return (p->n_op != UMUL && shtemp(p));
844 	}
845 
846 	if (optype(p->n_op) != LTYPE)
847 		return(0);
848 	return(1);
849 #endif
850 }
851 
852 void
adrcon(CONSZ val)853 adrcon(CONSZ val)
854 {
855 	printf(CONFMT, val);
856 }
857 
858 void
conput(FILE * fp,NODE * p)859 conput(FILE *fp, NODE *p)
860 {
861 	char *s;
862 	int val = p->n_lval;
863 
864 	switch (p->n_op) {
865 	case ICON:
866 #if 0
867 		if (p->n_sp)
868 			printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel);
869 #endif
870 #ifdef notdef	/* ICON cannot ever use sp here */
871 		/* If it does, it's a giant bug */
872 		if (p->n_sp == NULL || (
873 		   (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0)))
874 			s = p->n_name;
875 		else
876 			s = exname(p->n_name);
877 #else
878 		s = p->n_name;
879 #endif
880 
881 		if (*s != '\0') {
882 			fprintf(fp, "%s", s);
883 			if (val > 0)
884 				fprintf(fp, "+%d", val);
885 			else if (val < 0)
886 				fprintf(fp, "-%d", -val);
887 		} else
888 			fprintf(fp, CONFMT, (CONSZ)val);
889 		return;
890 
891 	default:
892 		comperr("illegal conput, p %p", p);
893 	}
894 }
895 
896 /*ARGSUSED*/
897 void
insput(NODE * p)898 insput(NODE *p)
899 {
900 	comperr("insput");
901 }
902 
903 /*
904  * Write out the upper address, like the upper register of a 2-register
905  * reference, or the next memory location.
906  */
907 void
upput(NODE * p,int size)908 upput(NODE *p, int size)
909 {
910 
911 	size /= SZCHAR;
912 	switch (p->n_op) {
913 	case REG:
914 		printf("%s", rnames[p->n_rval-R0R1+1]);
915 		break;
916 
917 	case NAME:
918 	case OREG:
919 		p->n_lval += size;
920 		adrput(stdout, p);
921 		p->n_lval -= size;
922 		break;
923 	case ICON:
924 		printf(CONFMT, p->n_lval >> 32);
925 		break;
926 	default:
927 		comperr("upput bad op %d size %d", p->n_op, size);
928 	}
929 }
930 
931 void
adrput(FILE * io,NODE * p)932 adrput(FILE *io, NODE *p)
933 {
934 	int r;
935 	/* output an address, with offsets, from p */
936 
937 	if (p->n_op == FLD)
938 		p = p->n_left;
939 
940 	switch (p->n_op) {
941 
942 	case NAME:
943 		if (p->n_name[0] != '\0') {
944 			fputs(p->n_name, io);
945 			if (p->n_lval != 0)
946 				fprintf(io, "+%lld", p->n_lval);
947 		} else
948 			fprintf(io, CONFMT, p->n_lval);
949 		return;
950 
951 	case OREG:
952 		r = p->n_rval;
953                 if (R2TEST(r))
954 			fprintf(io, "[%s, %s, lsl #%d]",
955 				rnames[R2UPK1(r)],
956 				rnames[R2UPK2(r)],
957 				R2UPK3(r));
958 		else
959 			fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)p->n_lval);
960 		return;
961 
962 	case ICON:
963 		/* addressable value of the constant */
964 		conput(io, p);
965 		return;
966 
967 	case REG:
968 		switch (p->n_type) {
969 		case DOUBLE:
970 		case LDOUBLE:
971 			if (features(FEATURE_HARDFLOAT)) {
972 				fprintf(io, "%s", rnames[p->n_rval]);
973 				break;
974 			}
975 			/* FALLTHROUGH */
976 		case LONGLONG:
977 		case ULONGLONG:
978 			fprintf(io, "%s", rnames[p->n_rval-R0R1]);
979 			break;
980 		default:
981 			fprintf(io, "%s", rnames[p->n_rval]);
982 		}
983 		return;
984 
985 	default:
986 		comperr("illegal address, op %d, node %p", p->n_op, p);
987 		return;
988 
989 	}
990 }
991 
992 /*   printf conditional and unconditional branches */
993 void
cbgen(int o,int lab)994 cbgen(int o, int lab)
995 {
996 	if (o < EQ || o > UGT)
997 		comperr("bad conditional branch: %s", opst[o]);
998 	printf("\t%s " LABFMT COM "conditional branch\n",
999 	    ccbranches[o-EQ], lab);
1000 }
1001 
1002 /*
1003  * The arm can only address 4k to get a NAME, so there must be some
1004  * rewriting here.  Strategy:
1005  * For first 1000 nodes found, print out the word directly.
1006  * For the following 1000 nodes, group them together in asm statements
1007  * and create a jump over.
1008  * For the last <1000 statements, print out the words last.
1009  */
1010 struct addrsymb {
1011 	SLIST_ENTRY(addrsymb) link;
1012 	char *name;	/* symbol name */
1013 	int num;	/* symbol offset */
1014 	char *str;	/* replace label */
1015 };
1016 SLIST_HEAD(, addrsymb) aslist;
1017 static struct interpass *ipbase;
1018 static int prtnumber, nodcnt, notfirst;
1019 #define	PRTLAB	".LY%d"	/* special for here */
1020 
1021 static struct interpass *
anode(char * p)1022 anode(char *p)
1023 {
1024 	extern int thisline;
1025 	struct interpass *ip = tmpalloc(sizeof(struct interpass));
1026 
1027 	ip->ip_asm = p;
1028 	ip->type = IP_ASM;
1029 	ip->lineno = thisline;
1030 	return ip;
1031 }
1032 
1033 static void
flshlab(void)1034 flshlab(void)
1035 {
1036 	struct interpass *ip;
1037 	struct addrsymb *el;
1038 	int lab = prtnumber++;
1039 	char *c;
1040 
1041 	if (SLIST_FIRST(&aslist) == NULL)
1042 		return;
1043 
1044 	snprintf(c = tmpalloc(32), 32, "\tb " PRTLAB "\n", lab);
1045 	ip = anode(c);
1046 	DLIST_INSERT_BEFORE(ipbase, ip, qelem);
1047 
1048 	SLIST_FOREACH(el, &aslist, link) {
1049 		/* insert each node as asm */
1050 		int l = 32+strlen(el->name);
1051 		c = tmpalloc(l);
1052 		if (el->num)
1053 			snprintf(c, l, "%s:\n\t.word %s+%d\n",
1054 			    el->str, el->name, el->num);
1055 		else
1056 			snprintf(c, l, "%s:\n\t.word %s\n", el->str, el->name);
1057 		ip = anode(c);
1058 		DLIST_INSERT_BEFORE(ipbase, ip, qelem);
1059 	}
1060 	/* generate asm label */
1061 	snprintf(c = tmpalloc(32), 32, PRTLAB ":\n", lab);
1062 	ip = anode(c);
1063 	DLIST_INSERT_BEFORE(ipbase, ip, qelem);
1064 }
1065 
1066 static void
prtaddr(NODE * p,void * arg)1067 prtaddr(NODE *p, void *arg)
1068 {
1069 	NODE *l = p->n_left;
1070 	struct addrsymb *el;
1071 	int found = 0;
1072 	int lab;
1073 
1074 	nodcnt++;
1075 
1076 	if (p->n_op == ASSIGN && p->n_right->n_op == ICON &&
1077 	    p->n_right->n_name[0] != '\0') {
1078 		/* named constant */
1079 		p = p->n_right;
1080 
1081 		/* Restore addrof */
1082 		l = mklnode(NAME, p->n_lval, 0, 0);
1083 		l->n_name = p->n_name;
1084 		p->n_left = l;
1085 		p->n_op = ADDROF;
1086 	}
1087 
1088 	if (p->n_op != ADDROF || l->n_op != NAME)
1089 		return;
1090 
1091 	/* if we passed 1k nodes printout list */
1092 	if (nodcnt > 1000) {
1093 		if (notfirst)
1094 			flshlab();
1095 		SLIST_INIT(&aslist);
1096 		notfirst = 1;
1097 		nodcnt = 0;
1098 	}
1099 
1100 	/* write address to byte stream */
1101 
1102 	SLIST_FOREACH(el, &aslist, link) {
1103 		if (el->num == l->n_lval && el->name[0] == l->n_name[0] &&
1104 		    strcmp(el->name, l->n_name) == 0) {
1105 			found = 1;
1106 			break;
1107 		}
1108 	}
1109 
1110 	if (!found) {
1111 		/* we know that this is text segment */
1112 		lab = prtnumber++;
1113 		if (nodcnt <= 1000 && notfirst == 0) {
1114 			if (l->n_lval)
1115 				printf(PRTLAB ":\n\t.word %s+%lld\n",
1116 				    lab, l->n_name, l->n_lval);
1117 			else
1118 				printf(PRTLAB ":\n\t.word %s\n",
1119 				    lab, l->n_name);
1120 		}
1121 		el = tmpalloc(sizeof(struct addrsymb));
1122 		el->num = l->n_lval;
1123 		el->name = l->n_name;
1124 		el->str = tmpalloc(32);
1125 		snprintf(el->str, 32, PRTLAB, lab);
1126 		SLIST_INSERT_LAST(&aslist, el, link);
1127 	}
1128 
1129 	nfree(l);
1130 	p->n_op = NAME;
1131 	p->n_lval = 0;
1132 	p->n_name = el->str;
1133 }
1134 
1135 void
myreader(struct interpass * ipole)1136 myreader(struct interpass *ipole)
1137 {
1138 	struct interpass *ip;
1139 
1140 	SLIST_INIT(&aslist);
1141 	notfirst = nodcnt = 0;
1142 
1143 	DLIST_FOREACH(ip, ipole, qelem) {
1144 		switch (ip->type) {
1145 		case IP_NODE:
1146 			lineno = ip->lineno;
1147 			ipbase = ip;
1148 			walkf(ip->ip_node, prtaddr, 0);
1149 			break;
1150 		case IP_EPILOG:
1151 			ipbase = ip;
1152 			if (notfirst)
1153 				flshlab();
1154 			break;
1155 		default:
1156 			break;
1157 		}
1158 	}
1159 	if (x2debug)
1160 		printip(ipole);
1161 }
1162 
1163 /*
1164  * Remove some PCONVs after OREGs are created.
1165  */
1166 static void
pconv2(NODE * p,void * arg)1167 pconv2(NODE *p, void *arg)
1168 {
1169 	NODE *q;
1170 
1171 	if (p->n_op == PLUS) {
1172 		if (p->n_type == (PTR+SHORT) || p->n_type == (PTR+USHORT)) {
1173 			if (p->n_right->n_op != ICON)
1174 				return;
1175 			if (p->n_left->n_op != PCONV)
1176 				return;
1177 			if (p->n_left->n_left->n_op != OREG)
1178 				return;
1179 			q = p->n_left->n_left;
1180 			nfree(p->n_left);
1181 			p->n_left = q;
1182 			/*
1183 			 * This will be converted to another OREG later.
1184 			 */
1185 		}
1186 	}
1187 }
1188 
1189 void
mycanon(NODE * p)1190 mycanon(NODE *p)
1191 {
1192 	walkf(p, pconv2, 0);
1193 }
1194 
1195 void
myoptim(struct interpass * ipp)1196 myoptim(struct interpass *ipp)
1197 {
1198 }
1199 
1200 /*
1201  * Register move: move contents of register 's' to register 'r'.
1202  */
1203 void
rmove(int s,int d,TWORD t)1204 rmove(int s, int d, TWORD t)
1205 {
1206         switch (t) {
1207 	case DOUBLE:
1208 	case LDOUBLE:
1209 		if (features(FEATURE_HARDFLOAT)) {
1210 			printf("\tfmr %s,%s" COM "rmove\n",
1211 				rnames[d], rnames[s]);
1212 			break;
1213 		}
1214 		/* FALLTHROUGH */
1215         case LONGLONG:
1216         case ULONGLONG:
1217 #define LONGREG(x, y) rnames[(x)-(R0R1-(y))]
1218                 if (s == d+1) {
1219                         /* dh = sl, copy low word first */
1220                         printf("\tmov %s,%s" COM "rmove\n",
1221 			    LONGREG(d,0), LONGREG(s,0));
1222                         printf("\tmov %s,%s\n",
1223 			    LONGREG(d,1), LONGREG(s,1));
1224                 } else {
1225                         /* copy high word first */
1226                         printf("\tmov %s,%s" COM "rmove\n",
1227 			    LONGREG(d,1), LONGREG(s,1));
1228                         printf("\tmov %s,%s\n",
1229 			    LONGREG(d,0), LONGREG(s,0));
1230                 }
1231 #undef LONGREG
1232                 break;
1233 	case FLOAT:
1234 		if (features(FEATURE_HARDFLOAT)) {
1235 			printf("\tmr %s,%s" COM "rmove\n",
1236 				rnames[d], rnames[s]);
1237 			break;
1238 		}
1239 		/* FALLTHROUGH */
1240         default:
1241 		printf("\tmov %s,%s" COM "rmove\n", rnames[d], rnames[s]);
1242         }
1243 }
1244 
1245 /*
1246  * Can we assign a register from class 'c', given the set
1247  * of number of assigned registers in each class 'r'.
1248  *
1249  * On ARM, we have:
1250  *	11  CLASSA registers (32-bit hard registers)
1251  *	10  CLASSB registers (64-bit composite registers)
1252  *	8 or 32 CLASSC registers (floating-point)
1253  *
1254  *  There is a problem calculating the available composite registers
1255  *  (ie CLASSB).  The algorithm below assumes that given any two
1256  *  registers, we can make a composite register.  But this isn't true
1257  *  here (or with other targets), since the number of combinations
1258  *  of register pairs could become very large.  Additionally,
1259  *  having so many combinations really isn't so practical, since
1260  *  most register pairs cannot be used to pass function arguments.
1261  *  Consequently, when there is pressure composite registers,
1262  *  "beenhere" compilation failures are common.
1263  *
1264  *  [We need to know which registers are allocated, not simply
1265  *  the number in each class]
1266  */
1267 int
COLORMAP(int c,int * r)1268 COLORMAP(int c, int *r)
1269 {
1270 	int num = 0;	/* number of registers used */
1271 
1272 #if 0
1273 	static const char classes[] = { 'X', 'A', 'B', 'C', 'D' };
1274 	printf("COLORMAP: requested class %c\n", classes[c]);
1275 	printf("COLORMAP: class A: %d\n", r[CLASSA]);
1276 	printf("COLORMAP: class B: %d\n", r[CLASSB]);
1277 #endif
1278 
1279 	switch (c) {
1280 	case CLASSA:
1281 		num += r[CLASSA];
1282 		num += 2*r[CLASSB];
1283 		return num < 11;
1284 	case CLASSB:
1285 		num += 2*r[CLASSB];
1286 		num += r[CLASSA];
1287 		return num < 6;  /* XXX see comments above */
1288 	case CLASSC:
1289 		num += r[CLASSC];
1290 		if (features(FEATURE_FPA))
1291 			return num < 8;
1292 		else if (features(FEATURE_VFP))
1293 			return num < 8;
1294 		else
1295 			cerror("colormap 1");
1296 	}
1297 	cerror("colormap 2");
1298 	return 0; /* XXX gcc */
1299 }
1300 
1301 /*
1302  * Return a class suitable for a specific type.
1303  */
1304 int
gclass(TWORD t)1305 gclass(TWORD t)
1306 {
1307 	if (t == DOUBLE || t == LDOUBLE) {
1308 		if (features(FEATURE_HARDFLOAT))
1309 			return CLASSC;
1310 		else
1311 			return CLASSB;
1312 	}
1313 	if (t == FLOAT) {
1314 		if (features(FEATURE_HARDFLOAT))
1315 			return CLASSC;
1316 		else
1317 			return CLASSA;
1318 	}
1319 	if (DEUNSIGN(t) == LONGLONG)
1320 		return CLASSB;
1321 	return CLASSA;
1322 }
1323 
1324 int
retreg(int t)1325 retreg(int t)
1326 {
1327 	int c = gclass(t);
1328 	if (c == CLASSB)
1329 		return R0R1;
1330 	else if (c == CLASSC)
1331 		return F0;
1332 	return R0;
1333 }
1334 
1335 /*
1336  * Calculate argument sizes.
1337  */
1338 void
lastcall(NODE * p)1339 lastcall(NODE *p)
1340 {
1341 	NODE *op = p;
1342 	int size = 0;
1343 
1344 	p->n_qual = 0;
1345 	if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1346 		return;
1347 	for (p = p->n_right; p->n_op == CM; p = p->n_left)
1348 		size += argsiz(p->n_right);
1349 	size += argsiz(p);
1350 	op->n_qual = size - 16; /* XXX */
1351 }
1352 
1353 /*
1354  * Special shapes.
1355  */
1356 int
special(NODE * p,int shape)1357 special(NODE *p, int shape)
1358 {
1359 	return SRNOPE;
1360 }
1361 
1362 /*
1363  * default to ARMv2
1364  */
1365 #ifdef TARGET_BIG_ENDIAN
1366 #define DEFAULT_FEATURES	FEATURE_BIGENDIAN | FEATURE_MUL
1367 #else
1368 #define DEFAULT_FEATURES	FEATURE_MUL
1369 #endif
1370 
1371 static int fset = DEFAULT_FEATURES;
1372 
1373 /*
1374  * Target-dependent command-line options.
1375  */
1376 void
mflags(char * str)1377 mflags(char *str)
1378 {
1379 	if (strcasecmp(str, "little-endian") == 0) {
1380 		fset &= ~FEATURE_BIGENDIAN;
1381 	} else if (strcasecmp(str, "big-endian") == 0) {
1382 		fset |= FEATURE_BIGENDIAN;
1383 	} else if (strcasecmp(str, "fpe=fpa") == 0) {
1384 		fset &= ~(FEATURE_VFP | FEATURE_FPA);
1385 		fset |= FEATURE_FPA;
1386 	} else if (strcasecmp(str, "fpe=vfp") == 0) {
1387 		fset &= ~(FEATURE_VFP | FEATURE_FPA);
1388 		fset |= FEATURE_VFP;
1389 	} else if (strcasecmp(str, "fpe=vfpv3-d16") == 0) {
1390 		fset &= ~(FEATURE_VFP | FEATURE_FPA);
1391 		fset |= FEATURE_VFP;
1392 	} else if (strcasecmp(str, "soft-float") == 0) {
1393 		fset &= ~(FEATURE_VFP | FEATURE_FPA);
1394 	} else if (strcasecmp(str, "arch=armv1") == 0) {
1395 		fset &= ~FEATURE_HALFWORDS;
1396 		fset &= ~FEATURE_EXTEND;
1397 		fset &= ~FEATURE_MUL;
1398 		fset &= ~FEATURE_MULL;
1399 		fset &= ~FEATURE_DIV;
1400 	} else if (strcasecmp(str, "arch=armv2") == 0) {
1401 		fset &= ~FEATURE_HALFWORDS;
1402 		fset &= ~FEATURE_EXTEND;
1403 		fset |= FEATURE_MUL;
1404 		fset &= ~FEATURE_MULL;
1405 		fset &= ~FEATURE_DIV;
1406 	} else if (strcasecmp(str, "arch=armv2a") == 0) {
1407 		fset &= ~FEATURE_HALFWORDS;
1408 		fset &= ~FEATURE_EXTEND;
1409 		fset |= FEATURE_MUL;
1410 		fset &= ~FEATURE_MULL;
1411 		fset &= ~FEATURE_DIV;
1412 	} else if (strcasecmp(str, "arch=armv3") == 0) {
1413 		fset &= ~FEATURE_HALFWORDS;
1414 		fset &= ~FEATURE_EXTEND;
1415 		fset |= FEATURE_MUL;
1416 		fset &= ~FEATURE_MULL;
1417 		fset &= ~FEATURE_DIV;
1418 	} else if (strcasecmp(str, "arch=armv4") == 0) {
1419 		fset |= FEATURE_HALFWORDS;
1420 		fset &= ~FEATURE_EXTEND;
1421 		fset |= FEATURE_MUL;
1422 		fset |= FEATURE_MULL;
1423 		fset &= ~FEATURE_DIV;
1424 	} else if (strcasecmp(str, "arch=armv4t") == 0) {
1425 		fset |= FEATURE_HALFWORDS;
1426 		fset &= ~FEATURE_EXTEND;
1427 		fset |= FEATURE_MUL;
1428 		fset |= FEATURE_MULL;
1429 		fset &= ~FEATURE_DIV;
1430 	} else if (strcasecmp(str, "arch=armv4tej") == 0) {
1431 		fset |= FEATURE_HALFWORDS;
1432 		fset &= ~FEATURE_EXTEND;
1433 		fset |= FEATURE_MUL;
1434 		fset |= FEATURE_MULL;
1435 		fset &= ~FEATURE_DIV;
1436 	} else if (strcasecmp(str, "arch=armv5") == 0) {
1437 		fset |= FEATURE_HALFWORDS;
1438 		fset &= ~FEATURE_EXTEND;
1439 		fset |= FEATURE_MUL;
1440 		fset |= FEATURE_MULL;
1441 		fset &= ~FEATURE_DIV;
1442 	} else if (strcasecmp(str, "arch=armv5te") == 0) {
1443 		fset |= FEATURE_HALFWORDS;
1444 		fset &= ~FEATURE_EXTEND;
1445 		fset |= FEATURE_MUL;
1446 		fset |= FEATURE_MULL;
1447 		fset &= ~FEATURE_DIV;
1448 	} else if (strcasecmp(str, "arch=armv5tej") == 0) {
1449 		fset |= FEATURE_HALFWORDS;
1450 		fset &= ~FEATURE_EXTEND;
1451 		fset |= FEATURE_MUL;
1452 		fset |= FEATURE_MULL;
1453 		fset &= ~FEATURE_DIV;
1454 	} else if (strcasecmp(str, "arch=armv6") == 0) {
1455 		fset |= FEATURE_HALFWORDS;
1456 		fset |= FEATURE_EXTEND;
1457 		fset |= FEATURE_MUL;
1458 		fset |= FEATURE_MULL;
1459 		fset &= ~FEATURE_DIV;
1460 	} else if (strcasecmp(str, "arch=armv6t2") == 0) {
1461 		fset |= FEATURE_HALFWORDS;
1462 		fset |= FEATURE_EXTEND;
1463 		fset |= FEATURE_MUL;
1464 		fset |= FEATURE_MULL;
1465 		fset &= ~FEATURE_DIV;
1466 	} else if (strcasecmp(str, "arch=armv6kz") == 0) {
1467 		fset |= FEATURE_HALFWORDS;
1468 		fset |= FEATURE_EXTEND;
1469 		fset |= FEATURE_MUL;
1470 		fset |= FEATURE_MULL;
1471 		fset &= ~FEATURE_DIV;
1472 	} else if (strcasecmp(str, "arch=armv6k") == 0) {
1473 		fset |= FEATURE_HALFWORDS;
1474 		fset |= FEATURE_EXTEND;
1475 		fset |= FEATURE_MUL;
1476 		fset |= FEATURE_MULL;
1477 		fset &= ~FEATURE_DIV;
1478 	} else if (strcasecmp(str, "arch=armv7") == 0) {
1479 		fset |= FEATURE_HALFWORDS;
1480 		fset |= FEATURE_EXTEND;
1481 		fset |= FEATURE_MUL;
1482 		fset |= FEATURE_MULL;
1483 		fset |= FEATURE_DIV;
1484 	} else if (strcasecmp(str, "arch=armv7-m") == 0 || strcasecmp(str, "arch=armv7e-m") == 0) {
1485 		fset |= FEATURE_HALFWORDS;
1486 		fset |= FEATURE_EXTEND;
1487 		fset |= FEATURE_MUL;
1488 		fset |= FEATURE_MULL;
1489 		fset |= FEATURE_DIV;
1490 	} else if (strcasecmp(str, "arch=armv7-a") == 0) {
1491 		fset |= FEATURE_HALFWORDS;
1492 		fset |= FEATURE_EXTEND;
1493 		fset |= FEATURE_MUL;
1494 		fset |= FEATURE_MULL;
1495 		fset &= ~FEATURE_DIV;
1496 	} else {
1497 		fprintf(stderr, "unknown m option '%s'\n", str);
1498 		exit(1);
1499 	}
1500 }
1501 
1502 int
features(int mask)1503 features(int mask)
1504 {
1505 	if (mask == FEATURE_HARDFLOAT)
1506 		return ((fset & mask) != 0);
1507 	return ((fset & mask) == mask);
1508 }
1509 
1510 /*
1511  * Define the current location as an internal label.
1512  */
1513 void
deflab(int label)1514 deflab(int label)
1515 {
1516 	printf(LABFMT ":\n", label);
1517 }
1518 
1519 /*
1520  * Do something target-dependent for xasm arguments.
1521  * Supposed to find target-specific constraints and rewrite them.
1522  */
1523 int
myxasm(struct interpass * ip,NODE * p)1524 myxasm(struct interpass *ip, NODE *p)
1525 {
1526 	return 0;
1527 }
1528