1 /* $Id: local2.c,v 1.34 2008/12/14 21:16:58 ragge Exp $ */
3 * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
4 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
37 extern void defalign(int);
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.
57 trepresent(const unsigned int val
)
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)
70 * 0 - output constant as is (should be covered by trepresent() above)
71 * 1 - 4 generate 1-4 instructions as needed.
74 encode_constant(int constant
, int *values
)
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
);
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
);
104 load_constant_into_reg(int reg
, int v
)
107 printf("\tmov %s,#%d\n", rnames
[reg
], v
);
108 else if (trepresent(-v
))
109 printf("\tmvn %s,#%d\n", rnames
[reg
], -v
);
113 nc
= encode_constant(v
, vals
);
114 for (i
= 0; i
< nc
; i
++) {
116 printf("\tmov %s,#%d" COM
"load constant %d\n",
117 rnames
[reg
], vals
[i
], v
);
119 printf("\torr %s,%s,#%d\n",
120 rnames
[reg
], rnames
[reg
], vals
[i
]);
129 * calculate stack size and offsets
132 offcalc(struct interpass_prolog
*ipp
)
138 printf("offcalc: p2maxautooff=%d\n", p2maxautooff
);
141 addto
= p2maxautooff
;
150 printf("offcalc: addto=%d\n", addto
);
153 addto
-= AUTOINIT
/ SZCHAR
;
159 prologue(struct interpass_prolog
*ipp
)
166 printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, regs=0x%x, autos=%d, tmpnum=%d, lblnum=%d\n",
178 ftype
= ipp
->ipp_type
;
181 printf("\t.align 2\n");
183 printf("\t.global %s\n", exname(ipp
->ipp_name
));
184 printf("\t.type %s,%%function\n", exname(ipp
->ipp_name
));
186 printf("%s:\n", exname(ipp
->ipp_name
));
189 * We here know what register to save and how much to
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
]);
203 if (trepresent(addto
)) {
204 printf("\tsub %s,%s,#%d\n", rnames
[SP
], rnames
[SP
], addto
);
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
]);
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
) {
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
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 */
258 hopcode(int f
, int o
)
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().
298 return(SZSHORT
/SZCHAR
);
301 return(SZDOUBLE
/SZCHAR
);
307 return(SZINT
/SZCHAR
);
311 return SZLONGLONG
/SZCHAR
;
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.
354 cb1
= cb2
= 0; /* XXX gcc */
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");
367 fldexpand(NODE
*p
, int cookie
, char **cp
)
372 if (p
->n_op
== ASSIGN
)
375 if (features(FEATURE_BIGENDIAN
))
376 shft
= SZINT
- UPKFSZ(p
->n_rval
) - UPKFOFF(p
->n_rval
);
378 shft
= UPKFOFF(p
->n_rval
);
382 printf("#%d", UPKFSZ(p
->n_rval
));
389 val
= (CONSZ
)1 << UPKFSZ(p
->n_rval
);
392 printf("%lld", (**cp
== 'M' ? val
: ~val
) & 0xffffffff);
395 comperr("fldexpand");
402 * Structure assignment.
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
))) {
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
],
420 if (trepresent(val
)) {
421 printf("\tadd %s,%s,#%d\n",
422 rnames
[R0
], rnames
[regno(l
)], val
);
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"));
439 NODE
*r
= p
->n_right
;
440 TWORD ty
= p
->n_type
;
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);
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");
464 expand(p
, INBREG
, "\tmov U1,UL,asr AR\n");
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");
473 expand(p
, INBREG
, "\tmov U1,#0" COM
"64-bit right-shift\n");
474 expand(p
, INBREG
, "\tmov A1,UL");
477 if (r
->n_lval
- 32 != 0)
478 printf(",%s " CONFMT
, shifttype
, r
->n_lval
- 32);
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
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
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
));
653 NODE
*r
= getlr(p
, 'R');
654 NODE
*l
= getlr(p
, 'L');
655 int idx0
= 0, idx1
= 1;
657 if (features(FEATURE_BIGENDIAN
)) {
662 if (p
->n_op
== ASSIGN
&& r
->n_op
== OREG
) {
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
) {
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
) {
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
) {
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");
700 if (ISUNSIGNED(p
->n_right
->n_type
))
702 sz
= 32 - UPKFSZ(p
->n_left
->n_rval
);
704 expand(p
, 0, "\tmov AD,AD,asl ");
706 expand(p
, 0, "\tmov AD,AD,asr ");
715 if (t
< LONGLONG
|| t
== FLOAT
|| t
> BTMASK
)
717 if (t
== LONGLONG
|| t
== ULONGLONG
)
719 if (t
== DOUBLE
|| t
== LDOUBLE
)
721 if (t
== STRTY
|| t
== UNIONTY
)
728 zzzcode(NODE
*p
, int c
)
734 case 'B': /* bit-field sign extension */
738 case 'C': /* remove from stack after subroutine call */
741 if (p
->n_op
== STCALL
|| p
->n_op
== USTCALL
)
744 if (p
->n_op
== UCALL
)
745 return; /* XXX remove ZC from UCALL */
747 printf("\tadd %s,%s,#%d\n", rnames
[SP
], rnames
[SP
], pr
);
750 case 'D': /* Long long comparision */
754 case 'E': /* print out emulated ops */
758 case 'F': /* print out emulated floating-point ops */
762 case 'H': /* do halfword access */
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);
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,
780 case 'O': /* 64-bit left and right shift operators */
784 case 'Q': /* emit struct assign */
789 comperr("zzzcode %c", c
);
801 * Does the bitfield shape match?
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? */
824 if (p
->n_op
== STARG
)
829 return (!istreg(p
->n_rval
));
834 if (istreg(R2UPK1(r
)))
842 return (p
->n_op
!= UMUL
&& shtemp(p
));
845 if (optype(p
->n_op
) != LTYPE
)
858 conput(FILE *fp
, NODE
*p
)
867 printf(" [class=%d,level=%d] ", p
->n_sp
->sclass
, p
->n_sp
->slevel
);
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)))
875 s
= exname(p
->n_name
);
881 fprintf(fp
, "%s", s
);
883 fprintf(fp
, "+%d", val
);
885 fprintf(fp
, "-%d", -val
);
887 fprintf(fp
, CONFMT
, (CONSZ
)val
);
891 comperr("illegal conput, p %p", p
);
903 * Write out the upper address, like the upper register of a 2-register
904 * reference, or the next memory location.
907 upput(NODE
*p
, int size
)
913 fprintf(stdout
, "%s", rnames
[p
->n_rval
-R0R1
+1]);
923 fprintf(stdout
, CONFMT
, p
->n_lval
>> 32);
926 comperr("upput bad op %d size %d", p
->n_op
, size
);
931 adrput(FILE *io
, NODE
*p
)
934 /* output an address, with offsets, from p */
942 if (p
->n_name
[0] != '\0') {
943 fputs(p
->n_name
, io
);
945 fprintf(io
, "+%lld", p
->n_lval
);
947 fprintf(io
, CONFMT
, p
->n_lval
);
953 fprintf(io
, "[%s, %s, lsl #%d]",
958 fprintf(io
, "[%s,#%d]", rnames
[p
->n_rval
], (int)p
->n_lval
);
962 /* addressable value of the constant */
970 if (features(FEATURE_HARDFLOAT
)) {
971 fprintf(io
, "%s", rnames
[p
->n_rval
]);
977 fprintf(stdout
, "%s", rnames
[p
->n_rval
-R0R1
]);
980 fprintf(io
, "%s", rnames
[p
->n_rval
]);
985 comperr("illegal address, op %d, node %p", p
->n_op
, p
);
991 /* printf conditional and unconditional branches */
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.
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
*
1023 extern int thisline
;
1024 struct interpass
*ip
= tmpalloc(sizeof(struct interpass
));
1028 ip
->lineno
= thisline
;
1035 struct interpass
*ip
;
1036 struct addrsymb
*el
;
1037 int lab
= prtnumber
++;
1040 if (SLIST_FIRST(&aslist
) == NULL
)
1043 snprintf(c
= tmpalloc(32), 32, "\tb " PRTLAB
"\n", lab
);
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
);
1052 snprintf(c
, l
, "%s:\n\t.word %s+%d\n",
1053 el
->str
, el
->name
, el
->num
);
1055 snprintf(c
, l
, "%s:\n\t.word %s\n", el
->str
, el
->name
);
1057 DLIST_INSERT_BEFORE(ipbase
, ip
, qelem
);
1059 /* generate asm label */
1060 snprintf(c
= tmpalloc(32), 32, PRTLAB
":\n", lab
);
1062 DLIST_INSERT_BEFORE(ipbase
, ip
, qelem
);
1066 prtaddr(NODE
*p
, void *arg
)
1068 NODE
*l
= p
->n_left
;
1069 struct addrsymb
*el
;
1075 if (p
->n_op
== ASSIGN
&& p
->n_right
->n_op
== ICON
&&
1076 p
->n_right
->n_name
[0] != '\0') {
1077 /* named constant */
1080 /* Restore addrof */
1081 l
= mklnode(NAME
, p
->n_lval
, 0, 0);
1082 l
->n_name
= p
->n_name
;
1087 if (p
->n_op
!= ADDROF
|| l
->n_op
!= NAME
)
1090 /* if we passed 1k nodes printout list */
1091 if (nodcnt
> 1000) {
1094 SLIST_INIT(&aslist
);
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) {
1110 /* we know that this is text segment */
1112 if (nodcnt
<= 1000 && notfirst
== 0) {
1114 printf(PRTLAB
":\n\t.word %s+%lld\n",
1115 lab
, l
->n_name
, l
->n_lval
);
1117 printf(PRTLAB
":\n\t.word %s\n",
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
);
1131 p
->n_name
= el
->str
;
1135 myreader(struct interpass
*ipole
)
1137 struct interpass
*ip
;
1139 SLIST_INIT(&aslist
);
1140 notfirst
= nodcnt
= 0;
1142 DLIST_FOREACH(ip
, ipole
, qelem
) {
1145 lineno
= ip
->lineno
;
1147 walkf(ip
->ip_node
, prtaddr
, 0);
1163 * Remove some PCONVs after OREGs are created.
1166 pconv2(NODE
*p
, void *arg
)
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
)
1174 if (p
->n_left
->n_op
!= PCONV
)
1176 if (p
->n_left
->n_left
->n_op
!= OREG
)
1178 q
= p
->n_left
->n_left
;
1182 * This will be converted to another OREG later.
1191 walkf(p
, pconv2
, 0);
1195 myoptim(struct interpass
*ipp
)
1200 * Register move: move contents of register 's' to register 'r'.
1203 rmove(int s
, int d
, TWORD t
)
1208 if (features(FEATURE_HARDFLOAT
)) {
1209 printf("\tfmr %s,%s" COM
"rmove\n",
1210 rnames
[d
], rnames
[s
]);
1216 #define LONGREG(x, y) rnames[(x)-(R0R1-(y))]
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));
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));
1233 if (features(FEATURE_HARDFLOAT
)) {
1234 printf("\tmr %s,%s" COM
"rmove\n",
1235 rnames
[d
], rnames
[s
]);
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'.
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 */
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
]);
1286 return num
< 6; /* XXX see comments above */
1289 if (features(FEATURE_FPA
))
1291 else if (features(FEATURE_VFP
))
1294 cerror("colormap 1");
1296 cerror("colormap 2");
1297 return 0; /* XXX gcc */
1301 * Return a class suitable for a specific type.
1306 if (t
== DOUBLE
|| t
== LDOUBLE
) {
1307 if (features(FEATURE_HARDFLOAT
))
1313 if (features(FEATURE_HARDFLOAT
))
1318 if (DEUNSIGN(t
) == LONGLONG
)
1329 else if (c
== CLASSC
)
1335 * Calculate argument sizes.
1344 if (p
->n_op
!= CALL
&& p
->n_op
!= FORTCALL
&& p
->n_op
!= STCALL
)
1346 for (p
= p
->n_right
; p
->n_op
== CM
; p
= p
->n_left
)
1347 size
+= argsiz(p
->n_right
);
1349 op
->n_qual
= size
- 16; /* XXX */
1356 special(NODE
*p
, int shape
)
1364 #ifdef TARGET_BIG_ENDIAN
1365 #define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_MUL
1367 #define DEFAULT_FEATURES FEATURE_MUL
1370 static int fset
= DEFAULT_FEATURES
;
1373 * Target-dependent command-line options.
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
;
1466 fprintf(stderr
, "unknown m option '%s'\n", str
);
1474 if (mask
== FEATURE_HARDFLOAT
)
1475 return ((fset
& mask
) != 0);
1476 return ((fset
& mask
) == mask
);
1480 * Define the current location as an internal 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
)