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