source: mainline/uspace/app/pcc/arch/mips/local2.c@ c6a7b3a

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

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

  • Property mode set to 100644
File size: 30.7 KB
Line 
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.
5 *
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
16 *
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.
27 */
28
29/*
30 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
31 * Simon Olsson (simols-1@student.ltu.se) 2005.
32 */
33
34#include <ctype.h>
35#include <string.h>
36#include <stdlib.h>
37#include <assert.h>
38
39#include "pass1.h"
40#include "pass2.h"
41
42#ifdef TARGET_BIG_ENDIAN
43int bigendian = 1;
44#else
45int bigendian = 0;
46#endif
47
48int nargregs = MIPS_O32_NARGREGS;
49
50static int argsiz(NODE *p);
51
52void
53deflab(int label)
54{
55 printf(LABFMT ":\n", label);
56}
57
58static int regoff[32];
59static TWORD ftype;
60
61/*
62 * calculate stack size and offsets
63 */
64static int
65offcalc(struct interpass_prolog * ipp)
66{
67 int i, j, addto;
68
69 addto = p2maxautooff;
70
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;
75 }
76 }
77
78 /* round to 8-byte boundary */
79 addto += 7;
80 addto &= ~7;
81
82 return addto;
83}
84
85/*
86 * Print out the prolog assembler.
87 */
88void
89prologue(struct interpass_prolog * ipp)
90{
91 int addto;
92 int i, j;
93
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);
100
101 addto = offcalc(ipp);
102
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");
108
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");
112
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]);
116
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");
128 }
129#endif
130
131 if (addto)
132 printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto);
133
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]);
138
139}
140
141void
142eoftn(struct interpass_prolog * ipp)
143{
144 int i, j;
145 int addto;
146
147 addto = offcalc(ipp);
148
149 if (ipp->ipp_ip.ip_lbl == 0)
150 return; /* no code needs to be generated */
151
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]);
157 }
158
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]);
162
163 printf("\tjr %s\n", rnames[RA]);
164 printf("\tnop\n");
165
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
170}
171
172/*
173 * add/sub/...
174 *
175 * Param given:
176 */
177void
178hopcode(int f, int o)
179{
180 char *str;
181
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 */
223 }
224
225 printf("%s%c", str, f);
226}
227
228char *
229rnames[] = {
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",
261};
262
263char *
264rnames_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",
281};
282
283int
284tlen(NODE *p)
285{
286 switch (p->n_type) {
287 case CHAR:
288 case UCHAR:
289 return (1);
290
291 case SHORT:
292 case USHORT:
293 return (SZSHORT / SZCHAR);
294
295 case DOUBLE:
296 return (SZDOUBLE / SZCHAR);
297
298 case INT:
299 case UNSIGNED:
300 case LONG:
301 case ULONG:
302 return (SZINT / SZCHAR);
303
304 case LONGLONG:
305 case ULONGLONG:
306 return SZLONGLONG / SZCHAR;
307
308 default:
309 if (!ISPTR(p->n_type))
310 comperr("tlen type %d not pointer");
311 return SZPOINT(p->n_type) / SZCHAR;
312 }
313}
314
315
316/*
317 * Push a structure on stack as argument.
318 */
319static void
320starg(NODE *p)
321{
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]);
331}
332
333/*
334 * Structure assignment.
335 */
336static void
337stasg(NODE *p)
338{
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");
350 }
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]);
355}
356
357static void
358shiftop(NODE *p)
359{
360 NODE *r = p->n_right;
361 TWORD ty = p->n_type;
362
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,");
392 }
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");
399 }
400}
401
402/*
403 * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines
404 */
405static void
406fpemulop(NODE *p)
407{
408 NODE *l = p->n_left;
409 char *ch = NULL;
410
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";
414
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";
418
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";
422
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";
426
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";
430
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";
434
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";
438
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";
442
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";
446
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";
450
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";
454
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";
506 }
507
508 if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op);
509
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");
522 }
523 } else {
524 comperr("ZF: incomplete softfloat - put args in registers");
525 }
526
527 printf("\tjal __%s\t# softfloat operation\n", exname(ch));
528 printf("\tnop\n");
529
530 if (p->n_op >= EQ && p->n_op <= GT)
531 printf("\tcmp %s,0\n", rnames[V0]);
532}
533
534/*
535 * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines
536 */
537static void
538emulop(NODE *p)
539{
540 char *ch = NULL;
541
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";
546
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";
550
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";
554
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";
558
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";
563
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";
567
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";
572
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";
576
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";
579
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]);
585}
586
587/*
588 * Emit code to compare two longlong numbers.
589 */
590static void
591twollcomp(NODE *p)
592{
593 int o = p->n_op;
594 int s = getlab2();
595 int e = p->n_label;
596 int cb1, cb2;
597
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;
619
620 default:
621 cb1 = cb2 = 0; /* XXX gcc */
622 }
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");
632 }
633 if (cb2) {
634 printf("\t");
635 hopcode(' ', cb2);
636 expand(p, 0, "A1");
637 printf("," LABFMT "\n", e);
638 printf("\tnop\n");
639 }
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);
647}
648
649static void
650fpcmpops(NODE *p)
651{
652 NODE *l = p->n_left;
653
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;
697 }
698 printf("\tnop\n\tnop\n");
699}
700
701void
702zzzcode(NODE * p, int c)
703{
704 int sz;
705
706 switch (c) {
707
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;
712
713 case 'D': /* long long comparison */
714 twollcomp(p);
715 break;
716
717 case 'E': /* emit emulated ops */
718 emulop(p);
719 break;
720
721 case 'F': /* emit emulate floating point ops */
722 fpemulop(p);
723 break;
724
725 case 'G': /* emit hardware floating-point compare op */
726 fpcmpops(p);
727 break;
728
729 case 'H': /* structure argument */
730 starg(p);
731 break;
732
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;
738
739 case 'O': /* 64-bit left and right shift operators */
740 shiftop(p);
741 break;
742
743 case 'Q': /* emit struct assign */
744 stasg(p);
745 break;
746
747 default:
748 comperr("zzzcode %c", c);
749 }
750}
751
752/* ARGSUSED */
753int
754rewfld(NODE * p)
755{
756 return (1);
757}
758
759int
760fldexpand(NODE *p, int cookie, char **cp)
761{
762 CONSZ val;
763
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");
782 }
783 return 1;
784}
785
786/*
787 * Does the bitfield shape match?
788 */
789int
790flshape(NODE * p)
791{
792 int o = p->n_op;
793
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 */
799}
800
801/* INTEMP shapes must not contain any temporary registers */
802/* XXX should this go away now? */
803int
804shtemp(NODE * p)
805{
806 return 0;
807#if 0
808 int r;
809
810 if (p->n_op == STARG)
811 p = p->n_left;
812
813 switch (p->n_op) {
814 case REG:
815 return (!istreg(p->n_rval));
816
817 case OREG:
818 r = p->n_rval;
819 if (R2TEST(r)) {
820 if (istreg(R2UPK1(r)))
821 return (0);
822 r = R2UPK2(r);
823 }
824 return (!istreg(r));
825
826 case UMUL:
827 p = p->n_left;
828 return (p->n_op != UMUL && shtemp(p));
829 }
830
831 if (optype(p->n_op) != LTYPE)
832 return (0);
833 return (1);
834#endif
835}
836
837void
838adrcon(CONSZ val)
839{
840 printf(CONFMT, val);
841}
842
843void
844conput(FILE *fp, NODE *p)
845{
846 int val = p->n_lval;
847
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;
857
858 default:
859 comperr("illegal conput");
860 }
861}
862
863/* ARGSUSED */
864void
865insput(NODE * p)
866{
867 comperr("insput");
868}
869
870/*
871 * Print lower or upper name of 64-bit register.
872 */
873static void
874print_reg64name(FILE *fp, int rval, int hi)
875{
876 int off = 4 * (hi != 0);
877 char *regname = rnames[rval];
878
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);
886}
887
888/*
889 * Write out the upper address, like the upper register of a 2-register
890 * reference, or the next memory location.
891 */
892void
893upput(NODE * p, int size)
894{
895
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;
904
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);
916 }
917}
918
919void
920adrput(FILE * io, NODE * p)
921{
922 int r;
923 /* output an address, with offsets, from p */
924
925 if (p->n_op == FLD)
926 p = p->n_left;
927
928 switch (p->n_op) {
929
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;
936
937 case OREG:
938 r = p->n_rval;
939
940 if (p->n_lval)
941 fprintf(io, "%d", (int) p->n_lval);
942
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;
949
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;
956
957 default:
958 comperr("illegal address, op %d, node %p", p->n_op, p);
959 return;
960
961 }
962}
963
964/* printf conditional and unconditional branches */
965void
966cbgen(int o, int lab)
967{
968}
969
970void
971myreader(struct interpass * ipole)
972{
973}
974
975#if 0
976/*
977 * Calculate the stack size for arguments
978 */
979static int stacksize;
980
981static void
982calcstacksize(NODE *p, void *arg)
983{
984 int sz;
985
986 printf("op=%d\n", p->n_op);
987
988 if (p->n_op != CALL && p->n_op != STCALL)
989 return;
990
991 sz = argsiz(p->n_right);
992 if (sz > stacksize)
993 stacksize = sz;
994
995#ifdef PCC_DEBUG
996 if (x2debug)
997 printf("stacksize: %d\n", stacksize);
998#endif
999}
1000#endif
1001
1002/*
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.
1006 */
1007static void
1008offchg(NODE *p, void *arg)
1009{
1010 NODE *l;
1011
1012 if (p->n_op != SCONV)
1013 return;
1014
1015 l = p->n_left;
1016
1017 if (l->n_op != OREG)
1018 return;
1019
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;
1048 }
1049}
1050
1051/*
1052 * Remove some PCONVs after OREGs are created.
1053 */
1054static void
1055pconv2(NODE * p, void *arg)
1056{
1057 NODE *q;
1058
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;
1070 /*
1071 * This will be converted to another OREG later.
1072 */
1073 }
1074 }
1075}
1076
1077void
1078mycanon(NODE * p)
1079{
1080 walkf(p, pconv2, 0);
1081}
1082
1083void
1084myoptim(struct interpass * ipole)
1085{
1086 struct interpass *ip;
1087
1088#ifdef PCC_DEBUG
1089 if (x2debug)
1090 printf("myoptim:\n");
1091#endif
1092
1093#if 0
1094 stacksize = 0;
1095#endif
1096
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
1105 }
1106}
1107
1108/*
1109 * Move data between registers. While basic registers aren't a problem,
1110 * we have to handle the special case of overlapping composite registers.
1111 */
1112void
1113rmove(int s, int d, TWORD t)
1114{
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");
1142 }
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]);
1158 }
1159}
1160
1161
1162/*
1163 * For class c, find worst-case displacement of the number of
1164 * registers in the array r[] indexed by class.
1165 *
1166 * On MIPS, we have:
1167 *
1168 * 32 32-bit registers (8 reserved)
1169 * 26 64-bit pseudo registers (1 unavailable)
1170 * 16 floating-point register pairs
1171 */
1172int
1173COLORMAP(int c, int *r)
1174{
1175 int num = 0;
1176
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;
1189 }
1190 comperr("COLORMAP");
1191 return 0; /* XXX gcc */
1192}
1193
1194/*
1195 * Return a class suitable for a specific type.
1196 */
1197int
1198gclass(TWORD t)
1199{
1200 if (t == LONGLONG || t == ULONGLONG)
1201 return CLASSB;
1202 if (t >= FLOAT && t <= LDOUBLE)
1203 return CLASSC;
1204 return CLASSA;
1205}
1206
1207/*
1208 * Calculate argument sizes.
1209 */
1210void
1211lastcall(NODE *p)
1212{
1213 int sz;
1214
1215#ifdef PCC_DEBUG
1216 if (x2debug)
1217 printf("lastcall:\n");
1218#endif
1219
1220 p->n_qual = 0;
1221 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1222 return;
1223
1224 sz = argsiz(p->n_right);
1225
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);
1231 }
1232
1233 p->n_qual = sz; /* XXX */
1234}
1235
1236static int
1237argsiz(NODE *p)
1238{
1239 TWORD t;
1240 int size = 0;
1241 int sz = 0;
1242
1243 if (p->n_op == CM) {
1244 size = argsiz(p->n_left);
1245 p = p->n_right;
1246 }
1247
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;
1259
1260 if (p->n_type == STRTY || p->n_type == UNIONTY) {
1261 return (size + sz);
1262 }
1263
1264 /* alignment */
1265 if (sz == 8 && (size & 7) != 0)
1266 sz += 4;
1267
1268// printf("size=%d, sz=%d -> %d\n", size, sz, size + sz);
1269 return (size + sz);
1270}
1271
1272/*
1273 * Special shapes.
1274 */
1275int
1276special(NODE *p, int shape)
1277{
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;
1285 }
1286
1287 return SRNOPE;
1288}
1289
1290/*
1291 * Target-dependent command-line options.
1292 */
1293void
1294mflags(char *str)
1295{
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);
1303 }
1304
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;
1318 }
1319#endif
1320}
1321/*
1322 * Do something target-dependent for xasm arguments.
1323 * Supposed to find target-specific constraints and rewrite them.
1324 */
1325int
1326myxasm(struct interpass *ip, NODE *p)
1327{
1328 return 0;
1329}
Note: See TracBrowser for help on using the repository browser.