source: mainline/uspace/app/pcc/arch/m16c/order.c@ 2568c94

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2568c94 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: 13.4 KB
Line 
1/* $Id: order.c,v 1.20 2008/09/27 07:35:23 ragge 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# include "pass2.h"
31# include <strings.h>
32
33int canaddr(NODE *);
34
35/*
36 * should the assignment op p be stored,
37 * given that it lies as the right operand of o
38 * (or the left, if o==UNARY MUL)
39 */
40/*
41void
42stoasg(NODE *p, int o)
43{
44 if (x2debug)
45 printf("stoasg(%p, %o)\n", p, o);
46}
47*/
48/* should we delay the INCR or DECR operation p */
49int
50deltest(NODE *p)
51{
52 return 0;
53}
54
55/*
56 * Check if p can be autoincremented.
57 * XXX - nothing can be autoincremented for now.
58 */
59int
60autoincr(NODE *p)
61{
62 return 0;
63}
64
65/* is it legal to make an OREG or NAME entry which has an
66 * offset of off, (from a register of r), if the
67 * resulting thing had type t */
68int
69notoff(TWORD t, int r, CONSZ off, char *cp)
70{
71 return(0); /* YES */
72}
73
74/*
75 * Turn a UMUL-referenced node into OREG.
76 */
77int
78offstar(NODE *p, int shape)
79{
80 if (x2debug)
81 printf("offstar(%p)\n", p);
82
83 if( p->n_op == PLUS || p->n_op == MINUS ){
84 if( p->n_right->n_op == ICON ){
85 geninsn(p->n_left, INBREG);
86 p->n_su = -1;
87 return 1;
88 }
89 }
90 geninsn(p, INBREG);
91 return 0;
92}
93
94/*
95 * Shape matches for UMUL. Cooperates with offstar().
96 */
97int
98shumul(NODE *p, int shape)
99{
100// NODE *l = p->n_left;
101
102#ifdef PCC_DEBUG
103 if (x2debug) {
104 printf("shumul(%p)\n", p);
105 fwalk(p, e2print, 0);
106 }
107#endif
108 /* XXX - fix */
109
110 /* Can only generate OREG of BREGs (or FB) */
111 if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB))
112 return SROREG;
113#if 0
114 if ((p->n_op == PLUS || p->n_op == MINUS) &&
115 (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) &&
116 p->n_right->n_op == ICON)
117 return SOREG;
118 return 0;
119#else
120 return SROREG;
121#endif
122}
123
124/*
125 * Rewrite increment/decrement operation.
126 */
127int
128setincr(NODE *p)
129{
130 if (x2debug)
131 printf("setincr(%p)\n", p);
132
133 return(0);
134}
135
136/*
137 * Rewrite operations on binary operators (like +, -, etc...).
138 * Called as a result of table lookup.
139 */
140int
141setbin(NODE *p)
142{
143
144 if (x2debug)
145 printf("setbin(%p)\n", p);
146 return 0;
147
148}
149
150/* setup for assignment operator */
151int
152setasg(NODE *p, int cookie)
153{
154 if (x2debug)
155 printf("setasg(%p)\n", p);
156 return(0);
157}
158
159/* setup for unary operator */
160int
161setuni(NODE *p, int cookie)
162{
163 return 0;
164}
165
166#if 0
167/*
168 * register allocation for instructions with special preferences.
169 */
170regcode
171regalloc(NODE *p, struct optab *q, int wantreg)
172{
173 regcode regc;
174
175 if (q->op == DIV || q->op == MOD) {
176 /*
177 * 16-bit div.
178 */
179 if (regblk[R0] & 1 || regblk[R2] & 1)
180 comperr("regalloc: needed regs inuse, node %p", p);
181 if (p->n_su & DORIGHT) {
182 regc = alloregs(p->n_right, A0);
183 if (REGNUM(regc) != A0) {
184 p->n_right = movenode(p->n_right, A0);
185 if ((p->n_su & RMASK) == ROREG) {
186 p->n_su &= ~RMASK;
187 p->n_su |= RREG;
188 p->n_right->n_su &= ~LMASK;
189 p->n_right->n_su |= LOREG;
190 }
191 freeregs(regc);
192 regblk[A0] |= 1;
193 }
194 }
195 regc = alloregs(p->n_left, R0);
196 if (REGNUM(regc) != R0) {
197 p->n_left = movenode(p->n_left, R0);
198 freeregs(regc);
199 regblk[R0] |= 1;
200 }
201 if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) {
202 regc = alloregs(p->n_right, A0);
203 if (REGNUM(regc) != A0) {
204 p->n_right = movenode(p->n_right, A0);
205 if ((p->n_su & RMASK) == ROREG) {
206 p->n_su &= ~RMASK;
207 p->n_su |= RREG;
208 p->n_right->n_su &= ~LMASK;
209 p->n_right->n_su |= LOREG;
210 }
211 }
212 }
213 regblk[A0] &= ~1;
214 regblk[R0] &= ~1;
215 regblk[R2] &= ~1;
216 if (q->op == DIV) {
217 MKREGC(regc, R0, 1);
218 regblk[R0] |= 1;
219 } else {
220 MKREGC(regc, R2, 1);
221 regblk[R2] |= 1;
222 }
223 } else
224 comperr("regalloc");
225 p->n_rall = REGNUM(regc);
226 return regc;
227}
228#endif
229
230/*
231 * Special handling of some instruction register allocation.
232 * - left is the register that left node wants.
233 * - right is the register that right node wants.
234 * - res is in which register the result will end up.
235 * - mask is registers that will be clobbered.
236 *
237 * XXX - Fix this function
238 */
239struct rspecial *
240nspecial(struct optab *q)
241{
242 switch (q->op) {
243
244 case DIV:
245 case MOD:
246 if(q->ltype & (TINT|TSHORT)){
247 static struct rspecial s[] = {
248 { NRES, R0 }, { NRES, R2}, { 0 } };
249 return s;
250 }
251 /*
252 else if(q->ltype & TCHAR) {
253 static struct rspecial s[] = {
254 { NRES, R0L }, { NRES, R0H}, { 0 } };
255 return s;
256 }*/
257 break;
258
259 case MUL:
260 /*
261 if(q->ltype & (TINT|TSHORT)){
262 static struct rspecial s[] = {
263 { NRES, R0 }, { NRES, R2}, { 0 } };
264 return s;
265 }*/
266 comperr("multiplication not implemented");
267 break;
268
269 default:
270 break;
271 }
272 comperr("nspecial entry %d", q - table);
273 return 0; /* XXX gcc */
274}
275
276
277/*
278 * Splitup a function call and give away its arguments first.
279 * Calling convention used ("normal" in IAR syntax) is:
280 * - 1-byte parameters in R0L if possible, otherwise in R0H.
281 * - 2-byte pointers in A0.
282 * - 2-byte non-pointers in R0 if no byte-size arguments are found in
283 * in the first 6 bytes of parameters, otherwise R2 or at last A0.
284 * - 4-byte parameters in R2R0.
285 */
286void
287gencall(NODE *p, NODE *prev)
288{
289 NODE *n = 0; /* XXX gcc */
290 static int storearg(NODE *);
291 int o = p->n_op;
292 int ty = optype(o);
293
294 if (ty == LTYPE)
295 return;
296
297 switch (o) {
298 case CALL:
299 /* swap arguments on some hardop-converted insns */
300 /* Normal call, just push args and be done with it */
301 p->n_op = UCALL;
302//printf("call\n");
303 /* Check if left can be evaluated directly */
304 if (p->n_left->n_op == UMUL) {
305 TWORD t = p->n_left->n_type;
306 int k = BITOOR(freetemp(szty(t)));
307 NODE *n = mklnode(OREG, k, FB, t);
308 NODE *q = tcopy(n);
309 pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t)));
310 p->n_left = q;
311 }
312 gencall(p->n_left, p);
313 p->n_rval = storearg(p->n_right);
314//printf("end call\n");
315 break;
316
317 case UFORTCALL:
318 case FORTCALL:
319 comperr("FORTCALL");
320
321 case USTCALL:
322 case STCALL:
323 /*
324 * Structure return. Look at the node above
325 * to decide about buffer address:
326 * - FUNARG, allocate space on stack, don't remove.
327 * - nothing, allocate space on stack and remove.
328 * - STASG, get the address of the left side as arg.
329 * - FORCE, this ends up in a return, get supplied addr.
330 * (this is not pretty, but what to do?)
331 */
332 if (prev == NULL || prev->n_op == FUNARG) {
333 /* Create nodes to generate stack space */
334 n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT),
335 mkbinode(MINUS, mklnode(REG, 0, STKREG, INT),
336 mklnode(ICON, p->n_stsize, 0, INT), INT), INT);
337//printf("stsize %d\n", p->n_stsize);
338 pass2_compile(ipnode(n));
339 } else if (prev->n_op == STASG) {
340 n = prev->n_left;
341 if (n->n_op == UMUL)
342 n = nfree(n);
343 else if (n->n_op == NAME) {
344 n->n_op = ICON; /* Constant reference */
345 n->n_type = INCREF(n->n_type);
346 } else
347 comperr("gencall stasg");
348 } else if (prev->n_op == FORCE) {
349 ; /* do nothing here */
350 } else {
351 comperr("gencall bad op %d", prev->n_op);
352 }
353
354 /* Deal with standard arguments */
355 gencall(p->n_left, p);
356 if (o == STCALL) {
357 p->n_op = USTCALL;
358 p->n_rval = storearg(p->n_right);
359 } else
360 p->n_rval = 0;
361 /* push return struct address */
362 if (prev == NULL || prev->n_op == FUNARG) {
363 n = mklnode(REG, 0, STKREG, INT);
364 if (p->n_rval)
365 n = mkbinode(PLUS, n,
366 mklnode(ICON, p->n_rval, 0, INT), INT);
367 pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
368 if (prev == NULL)
369 p->n_rval += p->n_stsize/4;
370 } else if (prev->n_op == FORCE) {
371 /* return value for this function */
372 n = mklnode(OREG, 8, FPREG, INT);
373 pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
374 p->n_rval++;
375 } else {
376 pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT)));
377 n = p;
378 *prev = *p;
379 nfree(n);
380 }
381//printf("end stcall\n");
382 break;
383
384 default:
385 if (ty != UTYPE)
386 gencall(p->n_right, p);
387 gencall(p->n_left, p);
388 break;
389 }
390}
391
392/*
393 * Create separate node trees for function arguments.
394 * This is partly ticky, the strange calling convention
395 * may cause a bunch of code reorganization here.
396 */
397static int
398storearg(NODE *p)
399{
400 NODE *n, *q, **narry;
401 int nch, k, i, nn, rary[4];
402 int r0l, r0h, r2, a0, stk, sz;
403 TWORD t;
404 int maxrargs = 0;
405
406 if (p->n_op == CM)
407 maxrargs = p->n_stalign;
408
409 /* count the arguments */
410 for (i = 1, q = p; q->n_op == CM; q = q->n_left)
411 i++;
412 nn = i;
413
414 /* allocate array to store arguments */
415 narry = tmpalloc(sizeof(NODE *)*nn);
416
417 /* enter nodes into array */
418 for (q = p; q->n_op == CM; q = q->n_left)
419 narry[--i] = q->n_right;
420 narry[--i] = q;
421
422 /* free CM nodes */
423 for (q = p; q->n_op == CM; ) {
424 n = q->n_left;
425 nfree(q);
426 q = n;
427 }
428
429 /* count char args */
430 r0l = r0h = r2 = a0 = 0;
431 for (sz = nch = i = 0; i < nn && i < 6; i++) {
432 TWORD t = narry[i]->n_type;
433 if (sz >= 6)
434 break;
435 if (t == CHAR || t == UCHAR) {
436 nch++;
437 sz++;
438 } else if ((t >= SHORT && t <= UNSIGNED) ||
439 t > BTMASK || t == FLOAT) {
440 sz += 2;
441 } else /* long, double */
442 sz += 4;
443
444 }
445
446 /*
447 * Now the tricky part. The parameters that should be on stack
448 * must be found and pushed first, then the register parameters.
449 * For the latter, be sure that evaluating them do not use any
450 * registers where argument values already are inserted.
451 * XXX - function pointers?
452 * XXX foo(long a, char b) ???
453 */
454 for (stk = 0; stk < 4; stk++) {
455 TWORD t;
456
457 if (stk == nn)
458 break;
459 t = narry[stk]->n_type;
460 if (ISFTN(DECREF(t)))
461 t = LONG;
462 switch (t) {
463 case CHAR: case UCHAR:
464 if (r0l) {
465 if (r0h)
466 break;
467 rary[stk] = R2; /* char talk for 'R0H' */
468 r0h = 1;
469 } else {
470 rary[stk] = R0;
471 r0l = 1;
472 }
473 continue;
474
475 case INT: case UNSIGNED:
476 if (r0l || nch) {
477 if (r2) {
478 if (a0)
479 break;
480 rary[stk] = A0;
481 a0 = 1;
482 } else {
483 rary[stk] = R2;
484 r2 = 1;
485 }
486 } else {
487 rary[stk] = R0;
488 r0l = r0h = 1;
489 }
490 continue;
491
492 case LONG: case ULONG:
493 if (r0l || r2)
494 break;
495 rary[stk] = R0;
496 r0l = r0h = r2 = 1;
497 continue;
498
499 default:
500 if (ISPTR(narry[stk]->n_type) &&
501 !ISFTN(DECREF(narry[stk]->n_type))) {
502 if (a0) {
503 if (r0l || nch) {
504 if (r2)
505 break;
506 rary[stk] = R2;
507 r2 = 1;
508 } else {
509 rary[stk] = R0;
510 r0l = r0h = 1;
511 }
512 } else {
513 rary[stk] = A0;
514 a0 = 1;
515 }
516 continue;
517 }
518 break;
519 }
520 break;
521 }
522
523 /*
524 * The arguments that must be on stack are stk->nn args.
525 * Argument 0->stk-1 should be put in the rary[] register.
526 */
527 for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */
528 NODE nod;
529 pass2_compile(ipnode(mkunode(FUNARG,
530 narry[i], 0, narry[i]->n_type)));
531 nod.n_type = narry[i]->n_type;
532 sz += tlen(&nod);
533 }
534 /* if param cannot be addressed directly, evaluate and put on stack */
535 for (i = 0; i < stk; i++) {
536
537 if (canaddr(narry[i]))
538 continue;
539 t = narry[i]->n_type;
540 k = BITOOR(freetemp(szty(t)));
541 n = mklnode(OREG, k, FB, t);
542 q = tcopy(n);
543 pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t)));
544 narry[i] = q;
545 }
546 /* move args to registers */
547 for (i = 0; i < stk; i++) {
548 t = narry[i]->n_type;
549 pass2_compile(ipnode(mkbinode(ASSIGN,
550 mklnode(REG, 0, rary[i], t), narry[i], t)));
551 }
552 return sz;
553}
554
555/*
556 * Tell if a register can hold a specific datatype.
557 */
558#if 0
559int
560mayuse(int reg, TWORD type)
561{
562 return 1; /* Everything is OK */
563}
564#endif
565
566#ifdef TAILCALL
567void
568mktailopt(struct interpass *ip1, struct interpass *ip2)
569{
570 extern int earlylab;
571 extern char *cftname;
572 char *fn;
573 NODE *p;
574
575 p = ip1->ip_node->n_left->n_left;
576 if (p->n_op == ICON) {
577 fn = p->n_name;
578 /* calling ourselves */
579 p = ip1->ip_node->n_left;
580 if (p->n_op == CALL) {
581 if (storearg(p->n_right))
582 comperr("too many args: fix mktailopt");
583 p->n_op = UCALL;
584 }
585 tfree(ip1->ip_node);
586 p = ip2->ip_node->n_left;
587 if (strcmp(fn, cftname)) {
588 /* Not us, must generate fake prologue */
589 ip1->type = IP_ASM;
590 ip1->ip_asm = "mov.w FB,SP\n\tpop.w FB";
591 pass2_compile(ip1);
592 p->n_lval = p->n_rval = 0;
593 p->n_name = fn;
594 } else
595 p->n_lval = earlylab;
596 } else {
597 pass2_compile(ip1);
598 }
599 pass2_compile(ip2);
600}
601#endif
602/*
603 * Set registers "live" at function calls (like arguments in registers).
604 * This is for liveness analysis of registers.
605 */
606int *
607livecall(NODE *p)
608{
609 static int r[1] = { -1 }; /* Terminate with -1 */
610
611 return &r[0];
612}
613
614/*
615 * Signal whether the instruction is acceptable for this target.
616 */
617int
618acceptable(struct optab *op)
619{
620 return 1;
621}
Note: See TracBrowser for help on using the repository browser.