source: mainline/uspace/app/pcc/arch/arm/local2.c@ b670523

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b670523 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 15 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 35.8 KB
RevLine 
[a7de7182]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.
6 *
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
17 *
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.
28 */
29
30#include <assert.h>
31#include <ctype.h>
32#include <string.h>
33#include <stdlib.h>
34
35#include "pass2.h"
36
37extern void defalign(int);
38
39#define exname(x) x
40
41char *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",
47};
48
49/*
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.
54 */
55
56static int
57trepresent(const unsigned int val)
58{
59 int i;
60#define rotate_left(v, n) (v << n | v >> (32 - n))
61
62 for (i = 0; i < 32; i += 2)
63 if (rotate_left(val, i) <= 0xff)
64 return 1;
65 return 0;
66}
67
68/*
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.
72 */
73static int
74encode_constant(int constant, int *values)
75{
76 int tmp = constant;
77 int i = 0;
78 int first_bit, value;
79
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 */
84
85 value = tmp & (0xff << first_bit);
86 values[i++] = value;
87 tmp &= ~value;
88 }
89 return i;
90}
91
92#if 0
93static void
94load_constant(NODE *p)
95{
96 int v = p->n_lval & 0xffffffff;
97 int reg = DECRA(p->n_reg, 1);
98
99 load_constant_into_reg(reg, v);
100}
101#endif
102
103static void
104load_constant_into_reg(int reg, int v)
105{
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;
112
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]);
121 }
122 }
123 }
124}
125
126static TWORD ftype;
127
128/*
129 * calculate stack size and offsets
130 */
131static int
132offcalc(struct interpass_prolog *ipp)
133{
134 int addto;
135
136#ifdef PCC_DEBUG
137 if (x2debug)
138 printf("offcalc: p2maxautooff=%d\n", p2maxautooff);
139#endif
140
141 addto = p2maxautooff;
142
143#if 0
144 addto += 7;
145 addto &= ~7;
146#endif
147
148#ifdef PCC_DEBUG
149 if (x2debug)
150 printf("offcalc: addto=%d\n", addto);
151#endif
152
153 addto -= AUTOINIT / SZCHAR;
154
155 return addto;
156}
157
158void
159prologue(struct interpass_prolog *ipp)
160{
161 int addto;
162 int vals[4], nc, i;
163
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
177
178 ftype = ipp->ipp_type;
179
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));
187
188 /*
189 * We here know what register to save and how much to
190 * add to the stack.
191 */
192 addto = offcalc(ipp);
193
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]);
199
200 if (addto == 0)
201 return;
202
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]);
210 }
211}
212
213void
214eoftn(struct interpass_prolog *ipp)
215{
216 if (ipp->ipp_ip.ip_lbl == 0)
217 return; /* no code needs to be generated */
218
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);
226 }
227 printf("\t.size %s,.-%s\n", exname(ipp->ipp_name),
228 exname(ipp->ipp_name));
229}
230
231
232/*
233 * these mnemonics match the order of the preprocessor decls
234 * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT
235 */
236
237static char *
238ccbranches[] = {
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 */
250};
251
252/*
253 * add/sub/...
254 *
255 * Param given:
256 */
257void
258hopcode(int f, int o)
259{
260 char *str;
261
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 */
281 }
282 printf("%s%c", str, f);
283}
284
285/*
286 * Return type size in bytes. Used by R2REGS, arg 2 to offset().
287 */
288int
289tlen(NODE *p)
290{
291 switch(p->n_type) {
292 case CHAR:
293 case UCHAR:
294 return(1);
295
296 case SHORT:
297 case USHORT:
298 return(SZSHORT/SZCHAR);
299
300 case DOUBLE:
301 return(SZDOUBLE/SZCHAR);
302
303 case INT:
304 case UNSIGNED:
305 case LONG:
306 case ULONG:
307 return(SZINT/SZCHAR);
308
309 case LONGLONG:
310 case ULONGLONG:
311 return SZLONGLONG/SZCHAR;
312
313 default:
314 if (!ISPTR(p->n_type))
315 comperr("tlen type %d not pointer");
316 return SZPOINT(p->n_type)/SZCHAR;
317 }
318}
319
320/*
321 * Emit code to compare two longlong numbers.
322 */
323static void
324twollcomp(NODE *p)
325{
326 int o = p->n_op;
327 int s = getlab2();
328 int e = p->n_label;
329 int cb1, cb2;
330
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;
352
353 default:
354 cb1 = cb2 = 0; /* XXX gcc */
355 }
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);
364}
365
366int
367fldexpand(NODE *p, int cookie, char **cp)
368{
369 CONSZ val;
370 int shft;
371
372 if (p->n_op == ASSIGN)
373 p = p->n_left;
374
375 if (features(FEATURE_BIGENDIAN))
376 shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval);
377 else
378 shft = UPKFOFF(p->n_rval);
379
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");
396 }
397 return 1;
398}
399
400
401/*
402 * Structure assignment.
403 */
404static void
405stasg(NODE *p)
406{
407 NODE *l = p->n_left;
408 int val = l->n_lval;
409
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)]);
427 }
428 }
429 } else if (l->n_op == NAME) {
430 cerror("not implemented");
431 }
432
433 printf("\tbl %s\n", exname("memcpy"));
434}
435
436static void
437shiftop(NODE *p)
438{
439 NODE *r = p->n_right;
440 TWORD ty = p->n_type;
441 char *shifttype;
442
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";
476 }
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");
483 }
484}
485
486/*
487 * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
488 */
489static void
490fpemul(NODE *p)
491{
492 NODE *l = p->n_left;
493 char *ch = NULL;
494
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";
498
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";
502
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";
506
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";
510
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";
514
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";
518
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";
522
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";
526
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";
530
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";
534
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";
538
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";
590 }
591
592 if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
593
594 printf("\tbl __%s" COM "softfloat operation\n", exname(ch));
595
596 if (p->n_op >= EQ && p->n_op <= GT)
597 printf("\tcmp %s,#0\n", rnames[R0]);
598}
599
600
601/*
602 * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
603 */
604
605static void
606emul(NODE *p)
607{
608 char *ch = NULL;
609
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";
613
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";
617
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";
621
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";
625
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";
629
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";
633
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";
637
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";
641
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";
645
646 else ch = 0, comperr("ZE");
647 printf("\tbl __%s" COM "emulated operation\n", exname(ch));
648}
649
650static void
651halfword(NODE *p)
652{
653 NODE *r = getlr(p, 'R');
654 NODE *l = getlr(p, 'L');
655 int idx0 = 0, idx1 = 1;
656
657 if (features(FEATURE_BIGENDIAN)) {
658 idx0 = 1;
659 idx1 = 0;
660 }
661
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");
692 }
693}
694
695static void
696bfext(NODE *p)
697{
698 int sz;
699
700 if (ISUNSIGNED(p->n_right->n_type))
701 return;
702 sz = 32 - UPKFSZ(p->n_left->n_rval);
703
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);
708}
709
710static int
711argsiz(NODE *p)
712{
713 TWORD t = p->n_type;
714
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;
725}
726
727void
728zzzcode(NODE *p, int c)
729{
730 int pr;
731
732 switch (c) {
733
734 case 'B': /* bit-field sign extension */
735 bfext(p);
736 break;
737
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;
749
750 case 'D': /* Long long comparision */
751 twollcomp(p);
752 break;
753
754 case 'E': /* print out emulated ops */
755 emul(p);
756 break;
757
758 case 'F': /* print out emulated floating-point ops */
759 fpemul(p);
760 break;
761
762 case 'H': /* do halfword access */
763 halfword(p);
764 break;
765
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;
772
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;
779
780 case 'O': /* 64-bit left and right shift operators */
781 shiftop(p);
782 break;
783
784 case 'Q': /* emit struct assign */
785 stasg(p);
786 break;
787
788 default:
789 comperr("zzzcode %c", c);
790 }
791}
792
793/*ARGSUSED*/
794int
795rewfld(NODE *p)
796{
797 return(1);
798}
799
800/*
801 * Does the bitfield shape match?
802 */
803int
804flshape(NODE *p)
805{
806 int o = p->n_op;
807
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 */
813}
814
815/* INTEMP shapes must not contain any temporary registers */
816/* XXX should this go away now? */
817int
818shtemp(NODE *p)
819{
820 return 0;
821#if 0
822 int r;
823
824 if (p->n_op == STARG )
825 p = p->n_left;
826
827 switch (p->n_op) {
828 case REG:
829 return (!istreg(p->n_rval));
830
831 case OREG:
832 r = p->n_rval;
833 if (R2TEST(r)) {
834 if (istreg(R2UPK1(r)))
835 return(0);
836 r = R2UPK2(r);
837 }
838 return (!istreg(r));
839
840 case UMUL:
841 p = p->n_left;
842 return (p->n_op != UMUL && shtemp(p));
843 }
844
845 if (optype(p->n_op) != LTYPE)
846 return(0);
847 return(1);
848#endif
849}
850
851void
852adrcon(CONSZ val)
853{
854 printf(CONFMT, val);
855}
856
857void
858conput(FILE *fp, NODE *p)
859{
860 char *s;
861 int val = p->n_lval;
862
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
879
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;
889
890 default:
891 comperr("illegal conput, p %p", p);
892 }
893}
894
895/*ARGSUSED*/
896void
897insput(NODE *p)
898{
899 comperr("insput");
900}
901
902/*
903 * Write out the upper address, like the upper register of a 2-register
904 * reference, or the next memory location.
905 */
906void
907upput(NODE *p, int size)
908{
909
910 size /= SZCHAR;
911 switch (p->n_op) {
912 case REG:
913 fprintf(stdout, "%s", rnames[p->n_rval-R0R1+1]);
914 break;
915
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);
927 }
928}
929
930void
931adrput(FILE *io, NODE *p)
932{
933 int r;
934 /* output an address, with offsets, from p */
935
936 if (p->n_op == FLD)
937 p = p->n_left;
938
939 switch (p->n_op) {
940
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;
949
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;
960
961 case ICON:
962 /* addressable value of the constant */
963 conput(io, p);
964 return;
965
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;
973 }
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]);
981 }
982 return;
983
984 default:
985 comperr("illegal address, op %d, node %p", p->n_op, p);
986 return;
987
988 }
989}
990
991/* printf conditional and unconditional branches */
992void
993cbgen(int o, int lab)
994{
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);
999}
1000
1001/*
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.
1008 */
1009struct addrsymb {
1010 SLIST_ENTRY(addrsymb) link;
1011 char *name; /* symbol name */
1012 int num; /* symbol offset */
1013 char *str; /* replace label */
1014};
1015SLIST_HEAD(, addrsymb) aslist;
1016static struct interpass *ipbase;
1017static int prtnumber, nodcnt, notfirst;
1018#define PRTLAB ".LY%d" /* special for here */
1019
1020static struct interpass *
1021anode(char *p)
1022{
1023 extern int thisline;
1024 struct interpass *ip = tmpalloc(sizeof(struct interpass));
1025
1026 ip->ip_asm = p;
1027 ip->type = IP_ASM;
1028 ip->lineno = thisline;
1029 return ip;
1030}
1031
1032static void
1033flshlab(void)
1034{
1035 struct interpass *ip;
1036 struct addrsymb *el;
1037 int lab = prtnumber++;
1038 char *c;
1039
1040 if (SLIST_FIRST(&aslist) == NULL)
1041 return;
1042
1043 snprintf(c = tmpalloc(32), 32, "\tb " PRTLAB "\n", lab);
1044 ip = anode(c);
1045 DLIST_INSERT_BEFORE(ipbase, ip, qelem);
1046
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);
1058 }
1059 /* generate asm label */
1060 snprintf(c = tmpalloc(32), 32, PRTLAB ":\n", lab);
1061 ip = anode(c);
1062 DLIST_INSERT_BEFORE(ipbase, ip, qelem);
1063}
1064
1065static void
1066prtaddr(NODE *p, void *arg)
1067{
1068 NODE *l = p->n_left;
1069 struct addrsymb *el;
1070 int found = 0;
1071 int lab;
1072
1073 nodcnt++;
1074
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;
1079
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;
1085 }
1086
1087 if (p->n_op != ADDROF || l->n_op != NAME)
1088 return;
1089
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;
1097 }
1098
1099 /* write address to byte stream */
1100
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;
1106 }
1107 }
1108
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);
1119 }
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);
1126 }
1127
1128 nfree(l);
1129 p->n_op = NAME;
1130 p->n_lval = 0;
1131 p->n_name = el->str;
1132}
1133
1134void
1135myreader(struct interpass *ipole)
1136{
1137 struct interpass *ip;
1138
1139 SLIST_INIT(&aslist);
1140 notfirst = nodcnt = 0;
1141
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;
1156 }
1157 }
1158 if (x2debug)
1159 printip(ipole);
1160}
1161
1162/*
1163 * Remove some PCONVs after OREGs are created.
1164 */
1165static void
1166pconv2(NODE *p, void *arg)
1167{
1168 NODE *q;
1169
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;
1181 /*
1182 * This will be converted to another OREG later.
1183 */
1184 }
1185 }
1186}
1187
1188void
1189mycanon(NODE *p)
1190{
1191 walkf(p, pconv2, 0);
1192}
1193
1194void
1195myoptim(struct interpass *ipp)
1196{
1197}
1198
1199/*
1200 * Register move: move contents of register 's' to register 'r'.
1201 */
1202void
1203rmove(int s, int d, TWORD t)
1204{
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;
1212 }
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));
1229 }
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;
1237 }
1238 /* FALLTHROUGH */
1239 default:
1240 printf("\tmov %s,%s" COM "rmove\n", rnames[d], rnames[s]);
1241 }
1242}
1243
1244/*
1245 * Can we assign a register from class 'c', given the set
1246 * of number of assigned registers in each class 'r'.
1247 *
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)
1252 *
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.
1262 *
1263 * [We need to know which registers are allocated, not simply
1264 * the number in each class]
1265 */
1266int
1267COLORMAP(int c, int *r)
1268{
1269 int num = 0; /* number of registers used */
1270
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
1277
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");
1295 }
1296 cerror("colormap 2");
1297 return 0; /* XXX gcc */
1298}
1299
1300/*
1301 * Return a class suitable for a specific type.
1302 */
1303int
1304gclass(TWORD t)
1305{
1306 if (t == DOUBLE || t == LDOUBLE) {
1307 if (features(FEATURE_HARDFLOAT))
1308 return CLASSC;
1309 else
1310 return CLASSB;
1311 }
1312 if (t == FLOAT) {
1313 if (features(FEATURE_HARDFLOAT))
1314 return CLASSC;
1315 else
1316 return CLASSA;
1317 }
1318 if (DEUNSIGN(t) == LONGLONG)
1319 return CLASSB;
1320 return CLASSA;
1321}
1322
1323int
1324retreg(int t)
1325{
1326 int c = gclass(t);
1327 if (c == CLASSB)
1328 return R0R1;
1329 else if (c == CLASSC)
1330 return F0;
1331 return R0;
1332}
1333
1334/*
1335 * Calculate argument sizes.
1336 */
1337void
1338lastcall(NODE *p)
1339{
1340 NODE *op = p;
1341 int size = 0;
1342
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 */
1350}
1351
1352/*
1353 * Special shapes.
1354 */
1355int
1356special(NODE *p, int shape)
1357{
1358 return SRNOPE;
1359}
1360
1361/*
1362 * default to ARMv2
1363 */
1364#ifdef TARGET_BIG_ENDIAN
1365#define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_MUL
1366#else
1367#define DEFAULT_FEATURES FEATURE_MUL
1368#endif
1369
1370static int fset = DEFAULT_FEATURES;
1371
1372/*
1373 * Target-dependent command-line options.
1374 */
1375void
1376mflags(char *str)
1377{
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);
1468 }
1469}
1470
1471int
1472features(int mask)
1473{
1474 if (mask == FEATURE_HARDFLOAT)
1475 return ((fset & mask) != 0);
1476 return ((fset & mask) == mask);
1477}
1478
1479/*
1480 * Define the current location as an internal label.
1481 */
1482void
1483deflab(int label)
1484{
1485 printf(LABFMT ":\n", label);
1486}
1487
1488/*
1489 * Do something target-dependent for xasm arguments.
1490 * Supposed to find target-specific constraints and rewrite them.
1491 */
1492int
1493myxasm(struct interpass *ip, NODE *p)
1494{
1495 return 0;
1496}
Note: See TracBrowser for help on using the repository browser.