* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / arch / mips / local2.c
blobfe4d3f9b4dbd306f4fad276ee80bd7dd5a230d97
1 /* $Id: local2.c,v 1.25 2008/12/03 22:23:38 gmcgarry Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
34 #include <ctype.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <assert.h>
39 #include "pass1.h"
40 #include "pass2.h"
42 #ifdef TARGET_BIG_ENDIAN
43 int bigendian = 1;
44 #else
45 int bigendian = 0;
46 #endif
48 int nargregs = MIPS_O32_NARGREGS;
50 static int argsiz(NODE *p);
52 void
53 deflab(int label)
55 printf(LABFMT ":\n", label);
58 static int regoff[32];
59 static TWORD ftype;
62 * calculate stack size and offsets
64 static int
65 offcalc(struct interpass_prolog * ipp)
67 int i, j, addto;
69 addto = p2maxautooff;
71 for (i = ipp->ipp_regs[0], j = 0; i; i >>= 1, j++) {
72 if (i & 1) {
73 addto += SZINT / SZCHAR;
74 regoff[j] = addto;
78 /* round to 8-byte boundary */
79 addto += 7;
80 addto &= ~7;
82 return addto;
86 * Print out the prolog assembler.
88 void
89 prologue(struct interpass_prolog * ipp)
91 int addto;
92 int i, j;
94 ftype = ipp->ipp_type;
95 printf("\t.align 2\n");
96 if (ipp->ipp_vis)
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]);
117 #ifdef notyet
118 /* profiling */
119 if (pflag) {
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"));
126 printf("\tnop\n");
127 printf("\t.set at\n");
129 #endif
131 if (addto)
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++)
135 if (i & 1)
136 fprintf(stdout, "\tsw %s,-%d(%s) # save permanent\n",
137 rnames[j], regoff[j], rnames[FP]);
141 void
142 eoftn(struct interpass_prolog * ipp)
144 int i, j;
145 int addto;
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++) {
154 if (i & 1)
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]);
164 printf("\tnop\n");
166 #ifdef USE_GAS
167 printf("\t.end %s\n", ipp->ipp_name);
168 printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name);
169 #endif
173 * add/sub/...
175 * Param given:
177 void
178 hopcode(int f, int o)
180 char *str;
182 switch (o) {
183 case EQ:
184 str = "beqz"; /* pseudo-op */
185 break;
186 case NE:
187 str = "bnez"; /* pseudo-op */
188 break;
189 case ULE:
190 case LE:
191 str = "blez";
192 break;
193 case ULT:
194 case LT:
195 str = "bltz";
196 break;
197 case UGE:
198 case GE:
199 str = "bgez";
200 break;
201 case UGT:
202 case GT:
203 str = "bgtz";
204 break;
205 case PLUS:
206 str = "add";
207 break;
208 case MINUS:
209 str = "sub";
210 break;
211 case AND:
212 str = "and";
213 break;
214 case OR:
215 str = "or";
216 break;
217 case ER:
218 str = "xor";
219 break;
220 default:
221 comperr("hopcode2: %d", o);
222 str = 0; /* XXX gcc */
225 printf("%s%c", str, f);
228 char *
229 rnames[] = {
230 #ifdef USE_GAS
231 /* gnu assembler */
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",
235 "$24", "$25",
236 "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra",
237 "$2!!$3!!",
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!",
243 #else
244 /* mips assembler */
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",
248 "$t8", "$t9",
249 "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
250 "$v0!$v1!",
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!",
256 #endif
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",
263 char *
264 rnames_n32[] = {
265 /* mips assembler */
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",
269 "$t8", "$t9",
270 "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
271 "$v0!$v1!",
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",
284 tlen(NODE *p)
286 switch (p->n_type) {
287 case CHAR:
288 case UCHAR:
289 return (1);
291 case SHORT:
292 case USHORT:
293 return (SZSHORT / SZCHAR);
295 case DOUBLE:
296 return (SZDOUBLE / SZCHAR);
298 case INT:
299 case UNSIGNED:
300 case LONG:
301 case ULONG:
302 return (SZINT / SZCHAR);
304 case LONGLONG:
305 case ULONGLONG:
306 return SZLONGLONG / SZCHAR;
308 default:
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.
319 static void
320 starg(NODE *p)
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"));
329 printf("\tnop\n");
330 printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
334 * Structure assignment.
336 static void
337 stasg(NODE *p)
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],
345 p->n_left->n_lval);
346 } else if (p->n_left->n_op == NAME) {
347 printf("\tla %s,", rnames[A0]);
348 adrput(stdout, p->n_left);
349 printf("\n");
351 printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]);
352 printf("\tjal %s\t# structure copy\n", exname("memcpy"));
353 printf("\tnop\n");
354 printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
357 static void
358 shiftop(NODE *p)
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");
381 if (ty == LONGLONG)
382 expand(p, INBREG, "\tsra U1,UL,AR\n");
383 else
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,");
389 }else {
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");
397 } else {
398 comperr("shiftop");
403 * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
405 static void
406 fpemulop(NODE *p)
408 NODE *l = p->n_left;
409 char *ch = NULL;
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]);
513 adrput(stdout, l);
514 printf("\n\tnop\n");
515 } else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) {
516 printf("\tmfc1 %s,", rnames[A1]);
517 upput(l, 0);
518 printf("\n\tnop\n");
519 printf("\tmfc1 %s,", rnames[A0]);
520 adrput(stdout, l);
521 printf("\n\tnop\n");
523 } else {
524 comperr("ZF: incomplete softfloat - put args in registers");
527 printf("\tjal __%s\t# softfloat operation\n", exname(ch));
528 printf("\tnop\n");
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
537 static void
538 emulop(NODE *p)
540 char *ch = NULL;
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))
545 ch = "ashlsi3";
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))
549 ch = "lshrsi3";
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))
553 ch = "ashrsi3";
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))
557 ch = "divsi3";
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))
562 ch = "udivsi3";
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))
566 ch = "modsi3";
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))
571 ch = "umodsi3";
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))
575 ch = "mulsi3";
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));
583 printf("\tnop\n");
584 printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]);
588 * Emit code to compare two longlong numbers.
590 static void
591 twollcomp(NODE *p)
593 int o = p->n_op;
594 int s = getlab2();
595 int e = p->n_label;
596 int cb1, cb2;
598 if (o >= ULE)
599 o -= (ULE-LE);
600 switch (o) {
601 case NE:
602 cb1 = 0;
603 cb2 = NE;
604 break;
605 case EQ:
606 cb1 = NE;
607 cb2 = 0;
608 break;
609 case LE:
610 case LT:
611 cb1 = GT;
612 cb2 = LT;
613 break;
614 case GE:
615 case GT:
616 cb1 = LT;
617 cb2 = GT;
618 break;
620 default:
621 cb1 = cb2 = 0; /* XXX gcc */
623 if (p->n_op >= ULE)
624 cb1 += 4, cb2 += 4;
625 expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n");
626 if (cb1) {
627 printf("\t");
628 hopcode(' ', cb1);
629 expand(p, 0, "A1");
630 printf("," LABFMT "\n", s);
631 printf("\tnop\n");
633 if (cb2) {
634 printf("\t");
635 hopcode(' ', cb2);
636 expand(p, 0, "A1");
637 printf("," LABFMT "\n", e);
638 printf("\tnop\n");
640 expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n");
641 printf("\t");
642 hopcode(' ', o);
643 expand(p, 0, "A1");
644 printf("," LABFMT "\n", e);
645 printf("\tnop\n");
646 deflab(s);
649 static void
650 fpcmpops(NODE *p)
652 NODE *l = p->n_left;
654 switch (p->n_op) {
655 case EQ:
656 if (l->n_type == FLOAT)
657 expand(p, 0, "\tc.eq.s AL,AR\n");
658 else
659 expand(p, 0, "\tc.eq.d AL,AR\n");
660 expand(p, 0, "\tnop\n\tbc1t LC\n");
661 break;
662 case NE:
663 if (l->n_type == FLOAT)
664 expand(p, 0, "\tc.eq.s AL,AR\n");
665 else
666 expand(p, 0, "\tc.eq.d AL,AR\n");
667 expand(p, 0, "\tnop\n\tbc1f LC\n");
668 break;
669 case LT:
670 if (l->n_type == FLOAT)
671 expand(p, 0, "\tc.lt.s AL,AR\n");
672 else
673 expand(p, 0, "\tc.lt.d AL,AR\n");
674 expand(p, 0, "\tnop\n\tbc1t LC\n");
675 break;
676 case GE:
677 if (l->n_type == FLOAT)
678 expand(p, 0, "\tc.lt.s AL,AR\n");
679 else
680 expand(p, 0, "\tc.lt.d AL,AR\n");
681 expand(p, 0, "\tnop\n\tbc1f LC\n");
682 break;
683 case LE:
684 if (l->n_type == FLOAT)
685 expand(p, 0, "\tc.le.s AL,AR\n");
686 else
687 expand(p, 0, "\tc.le.d AL,AR\n");
688 expand(p, 0, "\tnop\n\tbc1t LC\n");
689 break;
690 case GT:
691 if (l->n_type == FLOAT)
692 expand(p, 0, "\tc.le.s AL,AR\n");
693 else
694 expand(p, 0, "\tc.le.d AL,AR\n");
695 expand(p, 0, "\tnop\n\tbc1f LC\n");
696 break;
698 printf("\tnop\n\tnop\n");
701 void
702 zzzcode(NODE * p, int c)
704 int sz;
706 switch (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);
711 break;
713 case 'D': /* long long comparison */
714 twollcomp(p);
715 break;
717 case 'E': /* emit emulated ops */
718 emulop(p);
719 break;
721 case 'F': /* emit emulate floating point ops */
722 fpemulop(p);
723 break;
725 case 'G': /* emit hardware floating-point compare op */
726 fpcmpops(p);
727 break;
729 case 'H': /* structure argument */
730 starg(p);
731 break;
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);
737 break;
739 case 'O': /* 64-bit left and right shift operators */
740 shiftop(p);
741 break;
743 case 'Q': /* emit struct assign */
744 stasg(p);
745 break;
747 default:
748 comperr("zzzcode %c", c);
752 /* ARGSUSED */
754 rewfld(NODE * p)
756 return (1);
760 fldexpand(NODE *p, int cookie, char **cp)
762 CONSZ val;
764 if (p->n_op == ASSIGN)
765 p = p->n_left;
766 switch (**cp) {
767 case 'S':
768 printf("%d", UPKFSZ(p->n_rval));
769 break;
770 case 'H':
771 printf("%d", UPKFOFF(p->n_rval));
772 break;
773 case 'M':
774 case 'N':
775 val = (CONSZ)1 << UPKFSZ(p->n_rval);
776 --val;
777 val <<= UPKFOFF(p->n_rval);
778 printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff);
779 break;
780 default:
781 comperr("fldexpand");
783 return 1;
787 * Does the bitfield shape match?
790 flshape(NODE * p)
792 int o = p->n_op;
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? */
804 shtemp(NODE * p)
806 return 0;
807 #if 0
808 int r;
810 if (p->n_op == STARG)
811 p = p->n_left;
813 switch (p->n_op) {
814 case REG:
815 return (!istreg(p->n_rval));
817 case OREG:
818 r = p->n_rval;
819 if (R2TEST(r)) {
820 if (istreg(R2UPK1(r)))
821 return (0);
822 r = R2UPK2(r);
824 return (!istreg(r));
826 case UMUL:
827 p = p->n_left;
828 return (p->n_op != UMUL && shtemp(p));
831 if (optype(p->n_op) != LTYPE)
832 return (0);
833 return (1);
834 #endif
837 void
838 adrcon(CONSZ val)
840 printf(CONFMT, val);
843 void
844 conput(FILE *fp, NODE *p)
846 int val = p->n_lval;
848 switch (p->n_op) {
849 case ICON:
850 if (p->n_name[0] != '\0') {
851 fprintf(fp, "%s", p->n_name);
852 if (p->n_lval)
853 fprintf(fp, "+%d", val);
854 } else
855 fprintf(fp, "%d", val);
856 return;
858 default:
859 comperr("illegal conput");
863 /* ARGSUSED */
864 void
865 insput(NODE * p)
867 comperr("insput");
871 * Print lower or upper name of 64-bit register.
873 static void
874 print_reg64name(FILE *fp, int rval, int hi)
876 int off = 4 * (hi != 0);
877 char *regname = rnames[rval];
879 fprintf(fp, "%c%c",
880 regname[off],
881 regname[off + 1]);
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.
892 void
893 upput(NODE * p, int size)
896 size /= SZCHAR;
897 switch (p->n_op) {
898 case REG:
899 if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
900 print_reg64name(stdout, p->n_rval, 1);
901 else
902 fputs(rnames[p->n_rval], stdout);
903 break;
905 case NAME:
906 case OREG:
907 p->n_lval += size;
908 adrput(stdout, p);
909 p->n_lval -= size;
910 break;
911 case ICON:
912 fprintf(stdout, CONFMT, p->n_lval >> 32);
913 break;
914 default:
915 comperr("upput bad op %d size %d", p->n_op, size);
919 void
920 adrput(FILE * io, NODE * p)
922 int r;
923 /* output an address, with offsets, from p */
925 if (p->n_op == FLD)
926 p = p->n_left;
928 switch (p->n_op) {
930 case NAME:
931 if (p->n_name[0] != '\0')
932 fputs(p->n_name, io);
933 if (p->n_lval != 0)
934 fprintf(io, "+" CONFMT, p->n_lval);
935 return;
937 case OREG:
938 r = p->n_rval;
940 if (p->n_lval)
941 fprintf(io, "%d", (int) p->n_lval);
943 fprintf(io, "(%s)", rnames[p->n_rval]);
944 return;
945 case ICON:
946 /* addressable value of the constant */
947 conput(io, p);
948 return;
950 case REG:
951 if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC)
952 print_reg64name(io, p->n_rval, 0);
953 else
954 fputs(rnames[p->n_rval], io);
955 return;
957 default:
958 comperr("illegal address, op %d, node %p", p->n_op, p);
959 return;
964 /* printf conditional and unconditional branches */
965 void
966 cbgen(int o, int lab)
970 void
971 myreader(struct interpass * ipole)
975 #if 0
977 * Calculate the stack size for arguments
979 static int stacksize;
981 static void
982 calcstacksize(NODE *p, void *arg)
984 int sz;
986 printf("op=%d\n", p->n_op);
988 if (p->n_op != CALL && p->n_op != STCALL)
989 return;
991 sz = argsiz(p->n_right);
992 if (sz > stacksize)
993 stacksize = sz;
995 #ifdef PCC_DEBUG
996 if (x2debug)
997 printf("stacksize: %d\n", stacksize);
998 #endif
1000 #endif
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.
1007 static void
1008 offchg(NODE *p, void *arg)
1010 NODE *l;
1012 if (p->n_op != SCONV)
1013 return;
1015 l = p->n_left;
1017 if (l->n_op != OREG)
1018 return;
1020 switch (l->n_type) {
1021 case SHORT:
1022 case USHORT:
1023 if (DEUNSIGN(p->n_type) == CHAR)
1024 l->n_lval += 1;
1025 break;
1026 case LONG:
1027 case ULONG:
1028 case INT:
1029 case UNSIGNED:
1030 if (DEUNSIGN(p->n_type) == CHAR)
1031 l->n_lval += 3;
1032 else if (DEUNSIGN(p->n_type) == SHORT)
1033 l->n_lval += 2;
1034 break;
1035 case LONGLONG:
1036 case ULONGLONG:
1037 if (DEUNSIGN(p->n_type) == CHAR)
1038 l->n_lval += 7;
1039 else if (DEUNSIGN(p->n_type) == SHORT)
1040 l->n_lval += 6;
1041 else if (DEUNSIGN(p->n_type) == INT ||
1042 DEUNSIGN(p->n_type) == LONG)
1043 l->n_lval += 4;
1044 break;
1045 default:
1046 comperr("offchg: unknown type");
1047 break;
1052 * Remove some PCONVs after OREGs are created.
1054 static void
1055 pconv2(NODE * p, void *arg)
1057 NODE *q;
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)
1062 return;
1063 if (p->n_left->n_op != PCONV)
1064 return;
1065 if (p->n_left->n_left->n_op != OREG)
1066 return;
1067 q = p->n_left->n_left;
1068 nfree(p->n_left);
1069 p->n_left = q;
1071 * This will be converted to another OREG later.
1077 void
1078 mycanon(NODE * p)
1080 walkf(p, pconv2, 0);
1083 void
1084 myoptim(struct interpass * ipole)
1086 struct interpass *ip;
1088 #ifdef PCC_DEBUG
1089 if (x2debug)
1090 printf("myoptim:\n");
1091 #endif
1093 #if 0
1094 stacksize = 0;
1095 #endif
1097 DLIST_FOREACH(ip, ipole, qelem) {
1098 if (ip->type != IP_NODE)
1099 continue;
1100 if (bigendian)
1101 walkf(ip->ip_node, offchg, 0);
1102 #if 0
1103 walkf(ip->ip_node, calcstacksize, 0);
1104 #endif
1109 * Move data between registers. While basic registers aren't a problem,
1110 * we have to handle the special case of overlapping composite registers.
1112 void
1113 rmove(int s, int d, TWORD t)
1115 switch (t) {
1116 case LONGLONG:
1117 case ULONGLONG:
1118 if (s == d+1) {
1119 /* dh = sl, copy low word first */
1120 printf("\tmove ");
1121 print_reg64name(stdout, d, 0);
1122 printf(",");
1123 print_reg64name(stdout, s, 0);
1124 printf("\t# 64-bit rmove\n");
1125 printf("\tmove ");
1126 print_reg64name(stdout, d, 1);
1127 printf(",");
1128 print_reg64name(stdout, s, 1);
1129 printf("\n");
1130 } else {
1131 /* copy high word first */
1132 printf("\tmove ");
1133 print_reg64name(stdout, d, 1);
1134 printf(",");
1135 print_reg64name(stdout, s, 1);
1136 printf(" # 64-bit rmove\n");
1137 printf("\tmove ");
1138 print_reg64name(stdout, d, 0);
1139 printf(",");
1140 print_reg64name(stdout, s, 0);
1141 printf("\n");
1143 break;
1144 case FLOAT:
1145 case DOUBLE:
1146 case LDOUBLE:
1147 if (t == FLOAT)
1148 printf("\tmov.s ");
1149 else
1150 printf("\tmov.d ");
1151 print_reg64name(stdout, d, 0);
1152 printf(",");
1153 print_reg64name(stdout, s, 0);
1154 printf("\t# float/double rmove\n");
1155 break;
1156 default:
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.
1166 * On MIPS, we have:
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)
1175 int num = 0;
1177 switch (c) {
1178 case CLASSA:
1179 num += r[CLASSA];
1180 num += 2*r[CLASSB];
1181 return num < 24;
1182 case CLASSB:
1183 num += 2*r[CLASSB];
1184 num += r[CLASSA];
1185 return num < 25;
1186 case CLASSC:
1187 num += r[CLASSC];
1188 return num < 6;
1190 comperr("COLORMAP");
1191 return 0; /* XXX gcc */
1195 * Return a class suitable for a specific type.
1198 gclass(TWORD t)
1200 if (t == LONGLONG || t == ULONGLONG)
1201 return CLASSB;
1202 if (t >= FLOAT && t <= LDOUBLE)
1203 return CLASSC;
1204 return CLASSA;
1208 * Calculate argument sizes.
1210 void
1211 lastcall(NODE *p)
1213 int sz;
1215 #ifdef PCC_DEBUG
1216 if (x2debug)
1217 printf("lastcall:\n");
1218 #endif
1220 p->n_qual = 0;
1221 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1222 return;
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]);
1229 sz += 4;
1230 assert((sz & 7) == 0);
1233 p->n_qual = sz; /* XXX */
1236 static int
1237 argsiz(NODE *p)
1239 TWORD t;
1240 int size = 0;
1241 int sz = 0;
1243 if (p->n_op == CM) {
1244 size = argsiz(p->n_left);
1245 p = p->n_right;
1248 t = p->n_type;
1249 if (t < LONGLONG || t > BTMASK)
1250 sz = 4;
1251 else if (DEUNSIGN(t) == LONGLONG)
1252 sz = 8;
1253 else if (t == DOUBLE || t == LDOUBLE)
1254 sz = 8;
1255 else if (t == FLOAT)
1256 sz = 4;
1257 else if (t == STRTY || t == UNIONTY)
1258 sz = p->n_stsize;
1260 if (p->n_type == STRTY || p->n_type == UNIONTY) {
1261 return (size + sz);
1264 /* alignment */
1265 if (sz == 8 && (size & 7) != 0)
1266 sz += 4;
1268 // printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
1269 return (size + sz);
1273 * Special shapes.
1276 special(NODE *p, int shape)
1278 int o = p->n_op;
1279 switch(shape) {
1280 case SPCON:
1281 if (o == ICON && p->n_name[0] == 0 &&
1282 (p->n_lval & ~0xffff) == 0)
1283 return SRDIR;
1284 break;
1287 return SRNOPE;
1291 * Target-dependent command-line options.
1293 void
1294 mflags(char *str)
1296 if (strcasecmp(str, "big-endian") == 0) {
1297 bigendian = 1;
1298 } else if (strcasecmp(str, "little-endian") == 0) {
1299 bigendian = 0;
1300 } else {
1301 fprintf(stderr, "unknown m option '%s'\n", str);
1302 exit(1);
1305 #if 0
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;
1319 #endif
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)
1328 return 0;