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