1 /* $Id: local2.c,v 1.25 2008/12/03 22:23:38 gmcgarry Exp $ */
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
31 * Simon Olsson (simols-1@student.ltu.se) 2005.
42 #ifdef TARGET_BIG_ENDIAN
48 int nargregs
= MIPS_O32_NARGREGS
;
50 static int argsiz(NODE
*p
);
55 printf(LABFMT
":\n", label
);
58 static int regoff
[32];
62 * calculate stack size and offsets
65 offcalc(struct interpass_prolog
* ipp
)
71 for (i
= ipp
->ipp_regs
[0], j
= 0; i
; i
>>= 1, j
++) {
73 addto
+= SZINT
/ SZCHAR
;
78 /* round to 8-byte boundary */
86 * Print out the prolog assembler.
89 prologue(struct interpass_prolog
* ipp
)
94 ftype
= ipp
->ipp_type
;
95 printf("\t.align 2\n");
97 printf("\t.globl %s\n", ipp
->ipp_name
);
98 printf("\t.ent %s\n", ipp
->ipp_name
);
99 printf("%s:\n", ipp
->ipp_name
);
101 addto
= offcalc(ipp
);
103 /* for the moment, just emit this PIC stuff - NetBSD does it */
104 printf("\t.frame %s,%d,%s\n", rnames
[FP
], ARGINIT
/SZCHAR
, rnames
[RA
]);
105 printf("\t.set noreorder\n");
106 printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n");
107 printf("\t.set reorder\n");
109 printf("\tsubu %s,%s,%d\n", rnames
[SP
], rnames
[SP
], ARGINIT
/SZCHAR
);
110 /* for the moment, just emit PIC stuff - NetBSD does it */
111 printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n");
113 printf("\tsw %s,4(%s)\n", rnames
[RA
], rnames
[SP
]);
114 printf("\tsw %s,(%s)\n", rnames
[FP
], rnames
[SP
]);
115 printf("\tmove %s,%s\n", rnames
[FP
], rnames
[SP
]);
120 printf("\t.set noat\n");
121 printf("\tmove %s,%s\t# save current return address\n",
122 rnames
[AT
], rnames
[RA
]);
123 printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n",
124 rnames
[SP
], rnames
[SP
]);
125 printf("\tjal %s\n", exname("_mcount"));
127 printf("\t.set at\n");
132 printf("\tsubu %s,%s,%d\n", rnames
[SP
], rnames
[SP
], addto
);
134 for (i
= ipp
->ipp_regs
[0], j
= 0; i
; i
>>= 1, j
++)
136 fprintf(stdout
, "\tsw %s,-%d(%s) # save permanent\n",
137 rnames
[j
], regoff
[j
], rnames
[FP
]);
142 eoftn(struct interpass_prolog
* ipp
)
147 addto
= offcalc(ipp
);
149 if (ipp
->ipp_ip
.ip_lbl
== 0)
150 return; /* no code needs to be generated */
152 /* return from function code */
153 for (i
= ipp
->ipp_regs
[0], j
= 0; i
; i
>>= 1, j
++) {
155 fprintf(stdout
, "\tlw %s,-%d(%s)\n\tnop\n",
156 rnames
[j
], regoff
[j
], rnames
[FP
]);
159 printf("\taddiu %s,%s,%d\n", rnames
[SP
], rnames
[FP
], ARGINIT
/SZCHAR
);
160 printf("\tlw %s,%d(%s)\n", rnames
[RA
], 4-ARGINIT
/SZCHAR
, rnames
[SP
]);
161 printf("\tlw %s,%d(%s)\n", rnames
[FP
], 0-ARGINIT
/SZCHAR
, rnames
[SP
]);
163 printf("\tjr %s\n", rnames
[RA
]);
167 printf("\t.end %s\n", ipp
->ipp_name
);
168 printf("\t.size %s,.-%s\n", ipp
->ipp_name
, ipp
->ipp_name
);
178 hopcode(int f
, int o
)
184 str
= "beqz"; /* pseudo-op */
187 str
= "bnez"; /* pseudo-op */
221 comperr("hopcode2: %d", o
);
222 str
= 0; /* XXX gcc */
225 printf("%s%c", str
, f
);
232 "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7",
233 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
234 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
236 "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra",
238 "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!",
239 "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!",
240 "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!",
241 "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!",
242 "$20!$21!", "$21!$22!", "$22!$23!",
245 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
246 "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
247 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
249 "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
251 "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!",
252 "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!",
253 "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!",
254 "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
255 "$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
257 "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
258 "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
259 "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
260 "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
266 "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
267 "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3",
268 "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
270 "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
272 "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!",
273 "$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!",
274 "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!",
275 "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!",
276 "$s4!$s5!", "$s5!$s6!", "$s6!$s7!",
277 "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!",
278 "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15",
279 "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23",
280 "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31",
293 return (SZSHORT
/ SZCHAR
);
296 return (SZDOUBLE
/ SZCHAR
);
302 return (SZINT
/ SZCHAR
);
306 return SZLONGLONG
/ SZCHAR
;
309 if (!ISPTR(p
->n_type
))
310 comperr("tlen type %d not pointer");
311 return SZPOINT(p
->n_type
) / SZCHAR
;
317 * Push a structure on stack as argument.
322 //assert(p->n_rval == A1);
323 printf("\tsubu %s,%s,%d\n", rnames
[SP
], rnames
[SP
], p
->n_stsize
);
324 /* A0 = dest, A1 = src, A2 = len */
325 printf("\tmove %s,%s\n", rnames
[A0
], rnames
[SP
]);
326 printf("\tli %s,%d\t# structure size\n", rnames
[A2
], p
->n_stsize
);
327 printf("\tsubu %s,%s,16\n", rnames
[SP
], rnames
[SP
]);
328 printf("\tjal %s\t# structure copy\n", exname("memcpy"));
330 printf("\taddiu %s,%s,16\n", rnames
[SP
], rnames
[SP
]);
334 * Structure assignment.
339 assert(p
->n_right
->n_rval
== A1
);
340 /* A0 = dest, A1 = src, A2 = len */
341 printf("\tli %s,%d\t# structure size\n", rnames
[A2
], p
->n_stsize
);
342 if (p
->n_left
->n_op
== OREG
) {
343 printf("\taddiu %s,%s," CONFMT
"\t# dest address\n",
344 rnames
[A0
], rnames
[p
->n_left
->n_rval
],
346 } else if (p
->n_left
->n_op
== NAME
) {
347 printf("\tla %s,", rnames
[A0
]);
348 adrput(stdout
, p
->n_left
);
351 printf("\tsubu %s,%s,16\n", rnames
[SP
], rnames
[SP
]);
352 printf("\tjal %s\t# structure copy\n", exname("memcpy"));
354 printf("\taddiu %s,%s,16\n", rnames
[SP
], rnames
[SP
]);
360 NODE
*r
= p
->n_right
;
361 TWORD ty
= p
->n_type
;
363 if (p
->n_op
== LS
&& r
->n_op
== ICON
&& r
->n_lval
< 32) {
364 expand(p
, INBREG
, "\tsrl A1,AL,");
365 printf(CONFMT
"\t# 64-bit left-shift\n", 32 - r
->n_lval
);
366 expand(p
, INBREG
, "\tsll U1,UL,AR\n");
367 expand(p
, INBREG
, "\tor U1,U1,A1\n");
368 expand(p
, INBREG
, "\tsll A1,AL,AR\n");
369 } else if (p
->n_op
== LS
&& r
->n_op
== ICON
&& r
->n_lval
< 64) {
370 expand(p
, INBREG
, "\tli A1,0\t# 64-bit left-shift\n");
371 expand(p
, INBREG
, "\tsll U1,AL,");
372 printf(CONFMT
"\n", r
->n_lval
- 32);
373 } else if (p
->n_op
== LS
&& r
->n_op
== ICON
) {
374 expand(p
, INBREG
, "\tli A1,0\t# 64-bit left-shift\n");
375 expand(p
, INBREG
, "\tli U1,0\n");
376 } else if (p
->n_op
== RS
&& r
->n_op
== ICON
&& r
->n_lval
< 32) {
377 expand(p
, INBREG
, "\tsll U1,UL,");
378 printf(CONFMT
"\t# 64-bit right-shift\n", 32 - r
->n_lval
);
379 expand(p
, INBREG
, "\tsrl A1,AL,AR\n");
380 expand(p
, INBREG
, "\tor A1,A1,U1\n");
382 expand(p
, INBREG
, "\tsra U1,UL,AR\n");
384 expand(p
, INBREG
, "\tsrl U1,UL,AR\n");
385 } else if (p
->n_op
== RS
&& r
->n_op
== ICON
&& r
->n_lval
< 64) {
386 if (ty
== LONGLONG
) {
387 expand(p
, INBREG
, "\tsra U1,UL,31\t# 64-bit right-shift\n");
388 expand(p
, INBREG
, "\tsra A1,UL,");
390 expand(p
, INBREG
, "\tli U1,0\t# 64-bit right-shift\n");
391 expand(p
, INBREG
, "\tsrl A1,UL,");
393 printf(CONFMT
"\n", r
->n_lval
- 32);
394 } else if (p
->n_op
== LS
&& r
->n_op
== ICON
) {
395 expand(p
, INBREG
, "\tli A1,0\t# 64-bit right-shift\n");
396 expand(p
, INBREG
, "\tli U1,0\n");
403 * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
411 if (p
->n_op
== PLUS
&& p
->n_type
== FLOAT
) ch
= "addsf3";
412 else if (p
->n_op
== PLUS
&& p
->n_type
== DOUBLE
) ch
= "adddf3";
413 else if (p
->n_op
== PLUS
&& p
->n_type
== LDOUBLE
) ch
= "addtf3";
415 else if (p
->n_op
== MINUS
&& p
->n_type
== FLOAT
) ch
= "subsf3";
416 else if (p
->n_op
== MINUS
&& p
->n_type
== DOUBLE
) ch
= "subdf3";
417 else if (p
->n_op
== MINUS
&& p
->n_type
== LDOUBLE
) ch
= "subtf3";
419 else if (p
->n_op
== MUL
&& p
->n_type
== FLOAT
) ch
= "mulsf3";
420 else if (p
->n_op
== MUL
&& p
->n_type
== DOUBLE
) ch
= "muldf3";
421 else if (p
->n_op
== MUL
&& p
->n_type
== LDOUBLE
) ch
= "multf3";
423 else if (p
->n_op
== DIV
&& p
->n_type
== FLOAT
) ch
= "divsf3";
424 else if (p
->n_op
== DIV
&& p
->n_type
== DOUBLE
) ch
= "divdf3";
425 else if (p
->n_op
== DIV
&& p
->n_type
== LDOUBLE
) ch
= "divtf3";
427 else if (p
->n_op
== UMINUS
&& p
->n_type
== FLOAT
) ch
= "negsf2";
428 else if (p
->n_op
== UMINUS
&& p
->n_type
== DOUBLE
) ch
= "negdf2";
429 else if (p
->n_op
== UMINUS
&& p
->n_type
== LDOUBLE
) ch
= "negtf2";
431 else if (p
->n_op
== EQ
&& l
->n_type
== FLOAT
) ch
= "eqsf2";
432 else if (p
->n_op
== EQ
&& l
->n_type
== DOUBLE
) ch
= "eqdf2";
433 else if (p
->n_op
== EQ
&& l
->n_type
== LDOUBLE
) ch
= "eqtf2";
435 else if (p
->n_op
== NE
&& l
->n_type
== FLOAT
) ch
= "nesf2";
436 else if (p
->n_op
== NE
&& l
->n_type
== DOUBLE
) ch
= "nedf2";
437 else if (p
->n_op
== NE
&& l
->n_type
== LDOUBLE
) ch
= "netf2";
439 else if (p
->n_op
== GE
&& l
->n_type
== FLOAT
) ch
= "gesf2";
440 else if (p
->n_op
== GE
&& l
->n_type
== DOUBLE
) ch
= "gedf2";
441 else if (p
->n_op
== GE
&& l
->n_type
== LDOUBLE
) ch
= "getf2";
443 else if (p
->n_op
== LE
&& l
->n_type
== FLOAT
) ch
= "lesf2";
444 else if (p
->n_op
== LE
&& l
->n_type
== DOUBLE
) ch
= "ledf2";
445 else if (p
->n_op
== LE
&& l
->n_type
== LDOUBLE
) ch
= "letf2";
447 else if (p
->n_op
== GT
&& l
->n_type
== FLOAT
) ch
= "gtsf2";
448 else if (p
->n_op
== GT
&& l
->n_type
== DOUBLE
) ch
= "gtdf2";
449 else if (p
->n_op
== GT
&& l
->n_type
== LDOUBLE
) ch
= "gttf2";
451 else if (p
->n_op
== LT
&& l
->n_type
== FLOAT
) ch
= "ltsf2";
452 else if (p
->n_op
== LT
&& l
->n_type
== DOUBLE
) ch
= "ltdf2";
453 else if (p
->n_op
== LT
&& l
->n_type
== LDOUBLE
) ch
= "lttf2";
455 else if (p
->n_op
== SCONV
&& p
->n_type
== FLOAT
) {
456 if (l
->n_type
== DOUBLE
) ch
= "truncdfsf2";
457 else if (l
->n_type
== LDOUBLE
) ch
= "trunctfsf2";
458 else if (l
->n_type
== ULONGLONG
) ch
= "floatdisf"; /**/
459 else if (l
->n_type
== LONGLONG
) ch
= "floatdisf";
460 else if (l
->n_type
== LONG
) ch
= "floatsisf";
461 else if (l
->n_type
== ULONG
) ch
= "floatunsisf";
462 else if (l
->n_type
== INT
) ch
= "floatsisf";
463 else if (l
->n_type
== UNSIGNED
) ch
= "floatunsisf";
464 } else if (p
->n_op
== SCONV
&& p
->n_type
== DOUBLE
) {
465 if (l
->n_type
== FLOAT
) ch
= "extendsfdf2";
466 else if (l
->n_type
== LDOUBLE
) ch
= "trunctfdf2";
467 else if (l
->n_type
== ULONGLONG
) ch
= "floatunsdidf";
468 else if (l
->n_type
== LONGLONG
) ch
= "floatdidf";
469 else if (l
->n_type
== LONG
) ch
= "floatsidf";
470 else if (l
->n_type
== ULONG
) ch
= "floatunsidf";
471 else if (l
->n_type
== INT
) ch
= "floatsidf";
472 else if (l
->n_type
== UNSIGNED
) ch
= "floatunsidf";
473 } else if (p
->n_op
== SCONV
&& p
->n_type
== LDOUBLE
) {
474 if (l
->n_type
== FLOAT
) ch
= "extendsftf2";
475 else if (l
->n_type
== DOUBLE
) ch
= "extenddfdf2";
476 else if (l
->n_type
== ULONGLONG
) ch
= "floatunsdidf";
477 else if (l
->n_type
== LONGLONG
) ch
= "floatdidf";
478 else if (l
->n_type
== LONG
) ch
= "floatsidf";
479 else if (l
->n_type
== ULONG
) ch
= "floatunssidf";
480 else if (l
->n_type
== INT
) ch
= "floatsidf";
481 else if (l
->n_type
== UNSIGNED
) ch
= "floatunsidf";
482 } else if (p
->n_op
== SCONV
&& p
->n_type
== ULONGLONG
) {
483 if (l
->n_type
== FLOAT
) ch
= "fixunssfdi";
484 else if (l
->n_type
== DOUBLE
) ch
= "fixunsdfdi";
485 else if (l
->n_type
== LDOUBLE
) ch
= "fixunsdfdi";
486 } else if (p
->n_op
== SCONV
&& p
->n_type
== LONGLONG
) {
487 if (l
->n_type
== FLOAT
) ch
= "fixsfdi";
488 else if (l
->n_type
== DOUBLE
) ch
= "fixdfdi";
489 else if (l
->n_type
== LDOUBLE
) ch
= "fixdfdi";
490 } else if (p
->n_op
== SCONV
&& p
->n_type
== LONG
) {
491 if (l
->n_type
== FLOAT
) ch
= "fixsfsi";
492 else if (l
->n_type
== DOUBLE
) ch
= "fixdfsi";
493 else if (l
->n_type
== LDOUBLE
) ch
= "fixdfsi";
494 } else if (p
->n_op
== SCONV
&& p
->n_type
== ULONG
) {
495 if (l
->n_type
== FLOAT
) ch
= "fixunssfsi";
496 else if (l
->n_type
== DOUBLE
) ch
= "fixunsdfsi";
497 else if (l
->n_type
== LDOUBLE
) ch
= "fixunsdfsi";
498 } else if (p
->n_op
== SCONV
&& p
->n_type
== INT
) {
499 if (l
->n_type
== FLOAT
) ch
= "fixsfsi";
500 else if (l
->n_type
== DOUBLE
) ch
= "fixdfsi";
501 else if (l
->n_type
== LDOUBLE
) ch
= "fixdfsi";
502 } else if (p
->n_op
== SCONV
&& p
->n_type
== UNSIGNED
) {
503 if (l
->n_type
== FLOAT
) ch
= "fixunssfsi";
504 else if (l
->n_type
== DOUBLE
) ch
= "fixunsdfsi";
505 else if (l
->n_type
== LDOUBLE
) ch
= "fixunsdfsi";
508 if (ch
== NULL
) comperr("ZF: op=0x%x (%d)\n", p
->n_op
, p
->n_op
);
510 if (p
->n_op
== SCONV
) {
511 if (l
->n_type
== FLOAT
) {
512 printf("\tmfc1 %s,", rnames
[A0
]);
515 } else if (l
->n_type
== DOUBLE
|| l
->n_type
== LDOUBLE
) {
516 printf("\tmfc1 %s,", rnames
[A1
]);
519 printf("\tmfc1 %s,", rnames
[A0
]);
524 comperr("ZF: incomplete softfloat - put args in registers");
527 printf("\tjal __%s\t# softfloat operation\n", exname(ch
));
530 if (p
->n_op
>= EQ
&& p
->n_op
<= GT
)
531 printf("\tcmp %s,0\n", rnames
[V0
]);
535 * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
542 if (p
->n_op
== LS
&& DEUNSIGN(p
->n_type
) == LONGLONG
) ch
= "ashldi3";
543 else if (p
->n_op
== LS
&& (DEUNSIGN(p
->n_type
) == LONG
||
544 DEUNSIGN(p
->n_type
) == INT
))
547 else if (p
->n_op
== RS
&& p
->n_type
== ULONGLONG
) ch
= "lshrdi3";
548 else if (p
->n_op
== RS
&& (p
->n_type
== ULONG
|| p
->n_type
== INT
))
551 else if (p
->n_op
== RS
&& p
->n_type
== LONGLONG
) ch
= "ashrdi3";
552 else if (p
->n_op
== RS
&& (p
->n_type
== LONG
|| p
->n_type
== INT
))
555 else if (p
->n_op
== DIV
&& p
->n_type
== LONGLONG
) ch
= "divdi3";
556 else if (p
->n_op
== DIV
&& (p
->n_type
== LONG
|| p
->n_type
== INT
))
559 else if (p
->n_op
== DIV
&& p
->n_type
== ULONGLONG
) ch
= "udivdi3";
560 else if (p
->n_op
== DIV
&& (p
->n_type
== ULONG
||
561 p
->n_type
== UNSIGNED
))
564 else if (p
->n_op
== MOD
&& p
->n_type
== LONGLONG
) ch
= "moddi3";
565 else if (p
->n_op
== MOD
&& (p
->n_type
== LONG
|| p
->n_type
== INT
))
568 else if (p
->n_op
== MOD
&& p
->n_type
== ULONGLONG
) ch
= "umoddi3";
569 else if (p
->n_op
== MOD
&& (p
->n_type
== ULONG
||
570 p
->n_type
== UNSIGNED
))
573 else if (p
->n_op
== MUL
&& p
->n_type
== LONGLONG
) ch
= "muldi3";
574 else if (p
->n_op
== MUL
&& (p
->n_type
== LONG
|| p
->n_type
== INT
))
577 else if (p
->n_op
== UMINUS
&& p
->n_type
== LONGLONG
) ch
= "negdi2";
578 else if (p
->n_op
== UMINUS
&& p
->n_type
== LONG
) ch
= "negsi2";
580 else ch
= 0, comperr("ZE");
581 printf("\tsubu %s,%s,16\n", rnames
[SP
], rnames
[SP
]);
582 printf("\tjal __%s\t# emulated operation\n", exname(ch
));
584 printf("\taddiu %s,%s,16\n", rnames
[SP
], rnames
[SP
]);
588 * Emit code to compare two longlong numbers.
621 cb1
= cb2
= 0; /* XXX gcc */
625 expand(p
, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n");
630 printf("," LABFMT
"\n", s
);
637 printf("," LABFMT
"\n", e
);
640 expand(p
, 0, "\tsub A1,AL,AR\t# (and lower)\n");
644 printf("," LABFMT
"\n", e
);
656 if (l
->n_type
== FLOAT
)
657 expand(p
, 0, "\tc.eq.s AL,AR\n");
659 expand(p
, 0, "\tc.eq.d AL,AR\n");
660 expand(p
, 0, "\tnop\n\tbc1t LC\n");
663 if (l
->n_type
== FLOAT
)
664 expand(p
, 0, "\tc.eq.s AL,AR\n");
666 expand(p
, 0, "\tc.eq.d AL,AR\n");
667 expand(p
, 0, "\tnop\n\tbc1f LC\n");
670 if (l
->n_type
== FLOAT
)
671 expand(p
, 0, "\tc.lt.s AL,AR\n");
673 expand(p
, 0, "\tc.lt.d AL,AR\n");
674 expand(p
, 0, "\tnop\n\tbc1t LC\n");
677 if (l
->n_type
== FLOAT
)
678 expand(p
, 0, "\tc.lt.s AL,AR\n");
680 expand(p
, 0, "\tc.lt.d AL,AR\n");
681 expand(p
, 0, "\tnop\n\tbc1f LC\n");
684 if (l
->n_type
== FLOAT
)
685 expand(p
, 0, "\tc.le.s AL,AR\n");
687 expand(p
, 0, "\tc.le.d AL,AR\n");
688 expand(p
, 0, "\tnop\n\tbc1t LC\n");
691 if (l
->n_type
== FLOAT
)
692 expand(p
, 0, "\tc.le.s AL,AR\n");
694 expand(p
, 0, "\tc.le.d AL,AR\n");
695 expand(p
, 0, "\tnop\n\tbc1f LC\n");
698 printf("\tnop\n\tnop\n");
702 zzzcode(NODE
* p
, int c
)
708 case 'C': /* remove arguments from stack after subroutine call */
709 sz
= p
->n_qual
> 16 ? p
->n_qual
: 16;
710 printf("\taddiu %s,%s,%d\n", rnames
[SP
], rnames
[SP
], sz
);
713 case 'D': /* long long comparison */
717 case 'E': /* emit emulated ops */
721 case 'F': /* emit emulate floating point ops */
725 case 'G': /* emit hardware floating-point compare op */
729 case 'H': /* structure argument */
733 case 'I': /* high part of init constant */
734 if (p
->n_name
[0] != '\0')
735 comperr("named highword");
736 fprintf(stdout
, CONFMT
, (p
->n_lval
>> 32) & 0xffffffff);
739 case 'O': /* 64-bit left and right shift operators */
743 case 'Q': /* emit struct assign */
748 comperr("zzzcode %c", c
);
760 fldexpand(NODE
*p
, int cookie
, char **cp
)
764 if (p
->n_op
== ASSIGN
)
768 printf("%d", UPKFSZ(p
->n_rval
));
771 printf("%d", UPKFOFF(p
->n_rval
));
775 val
= (CONSZ
)1 << UPKFSZ(p
->n_rval
);
777 val
<<= UPKFOFF(p
->n_rval
);
778 printf("0x%llx", (**cp
== 'M' ? val
: ~val
) & 0xffffffff);
781 comperr("fldexpand");
787 * Does the bitfield shape match?
794 if (o
== OREG
|| o
== REG
|| o
== NAME
)
795 return SRDIR
; /* Direct match */
796 if (o
== UMUL
&& shumul(p
->n_left
, SOREG
))
797 return SROREG
; /* Convert into oreg */
798 return SRREG
; /* put it into a register */
801 /* INTEMP shapes must not contain any temporary registers */
802 /* XXX should this go away now? */
810 if (p
->n_op
== STARG
)
815 return (!istreg(p
->n_rval
));
820 if (istreg(R2UPK1(r
)))
828 return (p
->n_op
!= UMUL
&& shtemp(p
));
831 if (optype(p
->n_op
) != LTYPE
)
844 conput(FILE *fp
, NODE
*p
)
850 if (p
->n_name
[0] != '\0') {
851 fprintf(fp
, "%s", p
->n_name
);
853 fprintf(fp
, "+%d", val
);
855 fprintf(fp
, "%d", val
);
859 comperr("illegal conput");
871 * Print lower or upper name of 64-bit register.
874 print_reg64name(FILE *fp
, int rval
, int hi
)
876 int off
= 4 * (hi
!= 0);
877 char *regname
= rnames
[rval
];
882 if (regname
[off
+ 2] != '!')
883 fputc(regname
[off
+ 2], fp
);
884 if (regname
[off
+ 3] != '!')
885 fputc(regname
[off
+ 3], fp
);
889 * Write out the upper address, like the upper register of a 2-register
890 * reference, or the next memory location.
893 upput(NODE
* p
, int size
)
899 if (GCLASS(p
->n_rval
) == CLASSB
|| GCLASS(p
->n_rval
) == CLASSC
)
900 print_reg64name(stdout
, p
->n_rval
, 1);
902 fputs(rnames
[p
->n_rval
], stdout
);
912 fprintf(stdout
, CONFMT
, p
->n_lval
>> 32);
915 comperr("upput bad op %d size %d", p
->n_op
, size
);
920 adrput(FILE * io
, NODE
* p
)
923 /* output an address, with offsets, from p */
931 if (p
->n_name
[0] != '\0')
932 fputs(p
->n_name
, io
);
934 fprintf(io
, "+" CONFMT
, p
->n_lval
);
941 fprintf(io
, "%d", (int) p
->n_lval
);
943 fprintf(io
, "(%s)", rnames
[p
->n_rval
]);
946 /* addressable value of the constant */
951 if (GCLASS(p
->n_rval
) == CLASSB
|| GCLASS(p
->n_rval
) == CLASSC
)
952 print_reg64name(io
, p
->n_rval
, 0);
954 fputs(rnames
[p
->n_rval
], io
);
958 comperr("illegal address, op %d, node %p", p
->n_op
, p
);
964 /* printf conditional and unconditional branches */
966 cbgen(int o
, int lab
)
971 myreader(struct interpass
* ipole
)
977 * Calculate the stack size for arguments
979 static int stacksize
;
982 calcstacksize(NODE
*p
, void *arg
)
986 printf("op=%d\n", p
->n_op
);
988 if (p
->n_op
!= CALL
&& p
->n_op
!= STCALL
)
991 sz
= argsiz(p
->n_right
);
997 printf("stacksize: %d\n", stacksize
);
1003 * If we're big endian, then all OREG loads of a type
1004 * larger than the destination, must have the
1005 * offset changed to point to the correct bytes in memory.
1008 offchg(NODE
*p
, void *arg
)
1012 if (p
->n_op
!= SCONV
)
1017 if (l
->n_op
!= OREG
)
1020 switch (l
->n_type
) {
1023 if (DEUNSIGN(p
->n_type
) == CHAR
)
1030 if (DEUNSIGN(p
->n_type
) == CHAR
)
1032 else if (DEUNSIGN(p
->n_type
) == SHORT
)
1037 if (DEUNSIGN(p
->n_type
) == CHAR
)
1039 else if (DEUNSIGN(p
->n_type
) == SHORT
)
1041 else if (DEUNSIGN(p
->n_type
) == INT
||
1042 DEUNSIGN(p
->n_type
) == LONG
)
1046 comperr("offchg: unknown type");
1052 * Remove some PCONVs after OREGs are created.
1055 pconv2(NODE
* p
, void *arg
)
1059 if (p
->n_op
== PLUS
) {
1060 if (p
->n_type
== (PTR
| SHORT
) || p
->n_type
== (PTR
| USHORT
)) {
1061 if (p
->n_right
->n_op
!= ICON
)
1063 if (p
->n_left
->n_op
!= PCONV
)
1065 if (p
->n_left
->n_left
->n_op
!= OREG
)
1067 q
= p
->n_left
->n_left
;
1071 * This will be converted to another OREG later.
1080 walkf(p
, pconv2
, 0);
1084 myoptim(struct interpass
* ipole
)
1086 struct interpass
*ip
;
1090 printf("myoptim:\n");
1097 DLIST_FOREACH(ip
, ipole
, qelem
) {
1098 if (ip
->type
!= IP_NODE
)
1101 walkf(ip
->ip_node
, offchg
, 0);
1103 walkf(ip
->ip_node
, calcstacksize
, 0);
1109 * Move data between registers. While basic registers aren't a problem,
1110 * we have to handle the special case of overlapping composite registers.
1113 rmove(int s
, int d
, TWORD t
)
1119 /* dh = sl, copy low word first */
1121 print_reg64name(stdout
, d
, 0);
1123 print_reg64name(stdout
, s
, 0);
1124 printf("\t# 64-bit rmove\n");
1126 print_reg64name(stdout
, d
, 1);
1128 print_reg64name(stdout
, s
, 1);
1131 /* copy high word first */
1133 print_reg64name(stdout
, d
, 1);
1135 print_reg64name(stdout
, s
, 1);
1136 printf(" # 64-bit rmove\n");
1138 print_reg64name(stdout
, d
, 0);
1140 print_reg64name(stdout
, s
, 0);
1151 print_reg64name(stdout
, d
, 0);
1153 print_reg64name(stdout
, s
, 0);
1154 printf("\t# float/double rmove\n");
1157 printf("\tmove %s,%s\t# default rmove\n", rnames
[d
], rnames
[s
]);
1163 * For class c, find worst-case displacement of the number of
1164 * registers in the array r[] indexed by class.
1168 * 32 32-bit registers (8 reserved)
1169 * 26 64-bit pseudo registers (1 unavailable)
1170 * 16 floating-point register pairs
1173 COLORMAP(int c
, int *r
)
1190 comperr("COLORMAP");
1191 return 0; /* XXX gcc */
1195 * Return a class suitable for a specific type.
1200 if (t
== LONGLONG
|| t
== ULONGLONG
)
1202 if (t
>= FLOAT
&& t
<= LDOUBLE
)
1208 * Calculate argument sizes.
1217 printf("lastcall:\n");
1221 if (p
->n_op
!= CALL
&& p
->n_op
!= FORTCALL
&& p
->n_op
!= STCALL
)
1224 sz
= argsiz(p
->n_right
);
1226 if ((sz
> 4*nargregs
) && (sz
& 7) != 0) {
1227 printf("\tsubu %s,%s,4\t# align stack\n",
1228 rnames
[SP
], rnames
[SP
]);
1230 assert((sz
& 7) == 0);
1233 p
->n_qual
= sz
; /* XXX */
1243 if (p
->n_op
== CM
) {
1244 size
= argsiz(p
->n_left
);
1249 if (t
< LONGLONG
|| t
> BTMASK
)
1251 else if (DEUNSIGN(t
) == LONGLONG
)
1253 else if (t
== DOUBLE
|| t
== LDOUBLE
)
1255 else if (t
== FLOAT
)
1257 else if (t
== STRTY
|| t
== UNIONTY
)
1260 if (p
->n_type
== STRTY
|| p
->n_type
== UNIONTY
) {
1265 if (sz
== 8 && (size
& 7) != 0)
1268 // printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
1276 special(NODE
*p
, int shape
)
1281 if (o
== ICON
&& p
->n_name
[0] == 0 &&
1282 (p
->n_lval
& ~0xffff) == 0)
1291 * Target-dependent command-line options.
1296 if (strcasecmp(str
, "big-endian") == 0) {
1298 } else if (strcasecmp(str
, "little-endian") == 0) {
1301 fprintf(stderr
, "unknown m option '%s'\n", str
);
1306 else if (strcasecmp(str
, "ips2")) {
1307 } else if (strcasecmp(str
, "ips2")) {
1308 } else if (strcasecmp(str
, "ips3")) {
1309 } else if (strcasecmp(str
, "ips4")) {
1310 } else if (strcasecmp(str
, "hard-float")) {
1311 } else if (strcasecmp(str
, "soft-float")) {
1312 } else if (strcasecmp(str
, "abi=32")) {
1313 nargregs
= MIPS_O32_NARGREGS
;
1314 } else if (strcasecmp(str
, "abi=n32")) {
1315 nargregs
= MIPS_N32_NARGREGS
;
1316 } else if (strcasecmp(str
, "abi=64")) {
1317 nargregs
= MIPS_N32_NARGREGS
;
1322 * Do something target-dependent for xasm arguments.
1323 * Supposed to find target-specific constraints and rewrite them.
1326 myxasm(struct interpass
*ip
, NODE
*p
)