1 /* Id: local2.c,v 1.17 2016/01/30 17:26:19 ragge Exp */
2 /* $NetBSD: local2.c,v 1.1.1.2 2016/02/09 20:28:34 plunky Exp $ */
3 /*
4 * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se).
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 # include "pass2.h"
29 # include <ctype.h>
30 # include <string.h>
31
32 static int stkpos;
33
34 void
deflab(int label)35 deflab(int label)
36 {
37 printf(LABFMT ":\n", label);
38 }
39
40 static int regm, regf, fpsub, nfp;
41
42 void
prologue(struct interpass_prolog * ipp)43 prologue(struct interpass_prolog *ipp)
44 {
45 int i;
46
47 /*
48 * Subtract both space for automatics and permanent regs.
49 * XXX - no struct return yet.
50 */
51
52 fpsub = p2maxautooff;
53 if (fpsub >= AUTOINIT/SZCHAR)
54 fpsub -= AUTOINIT/SZCHAR;
55 regm = regf = nfp = 0;
56 for (i = 0; i < MAXREGS; i++)
57 if (TESTBIT(ipp->ipp_regs, i)) {
58 if (i <= A7) {
59 regm |= (1 << i);
60 fpsub += 4;
61 } else if (i >= FP0) {
62 regf |= (1 << (i - FP0));
63 fpsub += 12;
64 nfp += 12;
65 } else
66 comperr("bad reg range");
67 }
68 printf(" link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub);
69 if (regm)
70 printf(" movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp);
71 if (regf)
72 printf(" fmovem #%d,%d(%%fp)\n", regf, -fpsub);
73 }
74
75 void
eoftn(struct interpass_prolog * ipp)76 eoftn(struct interpass_prolog *ipp)
77 {
78 if (ipp->ipp_ip.ip_lbl == 0)
79 return; /* no code needs to be generated */
80
81 if (regm)
82 printf(" movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm);
83 if (regf)
84 printf(" fmovem %d(%%fp),#%d\n", -fpsub, regf);
85 printf(" unlk %%fp\n rts\n");
86 }
87
88 /*
89 * add/sub/...
90 *
91 * Param given:
92 */
93 void
hopcode(int f,int o)94 hopcode(int f, int o)
95 {
96 char *str;
97
98 switch (o) {
99 case PLUS:
100 str = "add";
101 break;
102 case MINUS:
103 str = "sub";
104 break;
105 case AND:
106 str = "and";
107 break;
108 case OR:
109 str = "or";
110 break;
111 case ER:
112 str = "eor";
113 break;
114 default:
115 comperr("hopcode2: %d", o);
116 str = 0; /* XXX gcc */
117 }
118 printf("%s", str);
119 }
120
121 /*
122 * Return type size in bytes. Used by R2REGS, arg 2 to offset().
123 */
124 int
tlen(NODE * p)125 tlen(NODE *p)
126 {
127 switch(p->n_type) {
128 case CHAR:
129 case UCHAR:
130 return(1);
131
132 case SHORT:
133 case USHORT:
134 return(SZSHORT/SZCHAR);
135
136 case DOUBLE:
137 return(SZDOUBLE/SZCHAR);
138
139 case INT:
140 case UNSIGNED:
141 return(SZINT/SZCHAR);
142
143 case LONG:
144 case ULONG:
145 case LONGLONG:
146 case ULONGLONG:
147 return SZLONGLONG/SZCHAR;
148
149 default:
150 if (!ISPTR(p->n_type))
151 comperr("tlen type %d not pointer");
152 return SZPOINT(p->n_type)/SZCHAR;
153 }
154 }
155
156 int
fldexpand(NODE * p,int cookie,char ** cp)157 fldexpand(NODE *p, int cookie, char **cp)
158 {
159 comperr("fldexpand");
160 return 0;
161 }
162
163 static void
starg(NODE * p)164 starg(NODE *p)
165 {
166 int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0);
167 int subsz = (sz + 3) & ~3;
168 int fr, tr, cr;
169
170 fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */
171 cr = regno(getlr(p, '1')); /* count reg (number of words) */
172 tr = regno(getlr(p, '2')); /* to reg (stack) */
173
174 /* Sub from stack and put in toreg */
175 printf(" sub.l #%d,%%sp\n", subsz);
176 printf(" move.l %%sp,%s\n", rnames[tr]);
177
178 /* Gen an even copy start */
179 if (sz & 1)
180 expand(p, INBREG, " move.b (AL)+,(A2)+\n");
181 if (sz & 2)
182 expand(p, INBREG, " move.w (AL)+,(A2)+\n");
183 sz -= (sz & 3);
184
185 /* if more than 4 words, use loop, otherwise output instructions */
186 if (sz > 16) {
187 printf(" move.l #%d,%s\n", (sz/4)-1, rnames[cr]);
188 expand(p, INBREG, "1: move.l (AL)+,(A2)+\n");
189 expand(p, INBREG, " dbra A1,1b\n");
190 } else {
191 if (sz > 12)
192 expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4;
193 if (sz > 8)
194 expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4;
195 if (sz > 4)
196 expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4;
197 if (sz == 4)
198 expand(p, INBREG, " move.l (AL)+,(A2)+\n");
199 }
200 }
201
202 void
zzzcode(NODE * p,int c)203 zzzcode(NODE *p, int c)
204 {
205 TWORD t = p->n_type;
206 char *s;
207
208 switch (c) {
209 case 'L':
210 t = p->n_left->n_type;
211 /* FALLTHROUGH */
212 case 'A':
213 s = (t == CHAR || t == UCHAR ? "b" :
214 t == SHORT || t == USHORT ? "w" :
215 t == FLOAT ? "s" :
216 t == DOUBLE ? "d" :
217 t == LDOUBLE ? "x" : "l");
218 printf("%s", s);
219 break;
220
221 case 'B':
222 if (p->n_qual)
223 printf(" add.l #%d,%%sp\n", (int)p->n_qual);
224 break;
225
226 case 'C': /* jsr or bsr.l XXX - type of CPU? */
227 printf("%s", kflag ? "bsr.l" : "jsr");
228 break;
229
230 case 'F': /* Emit float branches */
231 switch (p->n_op) {
232 case GT: s = "fjnle"; break;
233 case GE: s = "fjnlt"; break;
234 case LE: s = "fjngt"; break;
235 case LT: s = "fjnge"; break;
236 case NE: s = "fjne"; break;
237 case EQ: s = "fjeq"; break;
238 default: comperr("ZF"); s = 0;
239 }
240 printf("%s " LABFMT "\n", s, p->n_label);
241 break;
242
243 case 'P':
244 printf(" lea -%d(%%fp),%%a0\n", stkpos);
245 break;
246
247 case 'Q': /* struct assign */
248 printf(" move.l %d,-(%%sp)\n",
249 attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0));
250 expand(p, INAREG, " move.l AR,-(%sp)\n");
251 expand(p, INAREG, " move.l AL,-(%sp)\n");
252 printf(" jsr memcpy\n");
253 printf(" add.l #12,%%sp\n");
254 break;
255
256 case 'S': /* struct arg */
257 starg(p);
258 break;
259
260 case '2':
261 if (regno(getlr(p, '2')) != regno(getlr(p, 'L')))
262 expand(p, INAREG, " fmove.x AL,A2\n");
263 break;
264
265 default:
266 comperr("zzzcode %c", c);
267 }
268 }
269
270 #if 0
271 int canaddr(NODE *);
272 int
273 canaddr(NODE *p)
274 {
275 int o = p->n_op;
276
277 if (o==NAME || o==REG || o==ICON || o==OREG ||
278 (o==UMUL && shumul(p->n_left, SOREG)))
279 return(1);
280 return(0);
281 }
282 #endif
283
284 /*
285 * Does the bitfield shape match?
286 */
287 int
flshape(NODE * p)288 flshape(NODE *p)
289 {
290 comperr("flshape");
291 return(0);
292 }
293
294 /* INTEMP shapes must not contain any temporary registers */
295 /* XXX should this go away now? */
296 int
shtemp(NODE * p)297 shtemp(NODE *p)
298 {
299 return 0;
300 #if 0
301 int r;
302
303 if (p->n_op == STARG )
304 p = p->n_left;
305
306 switch (p->n_op) {
307 case REG:
308 return (!istreg(p->n_rval));
309
310 case OREG:
311 r = p->n_rval;
312 if (R2TEST(r)) {
313 if (istreg(R2UPK1(r)))
314 return(0);
315 r = R2UPK2(r);
316 }
317 return (!istreg(r));
318
319 case UMUL:
320 p = p->n_left;
321 return (p->n_op != UMUL && shtemp(p));
322 }
323
324 if (optype(p->n_op) != LTYPE)
325 return(0);
326 return(1);
327 #endif
328 }
329
330 void
adrcon(CONSZ val)331 adrcon(CONSZ val)
332 {
333 printf("#" CONFMT, val);
334 }
335
336 void
conput(FILE * fp,NODE * p)337 conput(FILE *fp, NODE *p)
338 {
339 long val = getlval(p);
340
341 if (p->n_type <= UCHAR)
342 val &= 255;
343 else if (p->n_type <= USHORT)
344 val &= 65535;
345
346 switch (p->n_op) {
347 case ICON:
348 fprintf(fp, "%ld", val);
349 if (p->n_name[0])
350 printf("+%s", p->n_name);
351 break;
352
353 default:
354 comperr("illegal conput, p %p", p);
355 }
356 }
357
358 /*ARGSUSED*/
359 void
insput(NODE * p)360 insput(NODE *p)
361 {
362 comperr("insput");
363 }
364
365 /*
366 * Write out the upper address, like the upper register of a 2-register
367 * reference, or the next memory location.
368 */
369 void
upput(NODE * p,int size)370 upput(NODE *p, int size)
371 {
372 switch (p->n_op) {
373 case REG:
374 printf("%%%s", &rnames[p->n_rval][2]);
375 break;
376 case NAME:
377 case OREG:
378 setlval(p, getlval(p) + 4);
379 adrput(stdout, p);
380 setlval(p, getlval(p) - 4);
381 break;
382
383 case ICON:
384 printf("#%d", (int)getlval(p));
385 break;
386
387 default:
388 comperr("upput bad op %d size %d", p->n_op, size);
389 }
390 }
391
392 void
adrput(FILE * io,NODE * p)393 adrput(FILE *io, NODE *p)
394 {
395 int r;
396
397 /* output an address, with offsets, from p */
398 switch (p->n_op) {
399 case NAME:
400 if (getlval(p))
401 fprintf(io, CONFMT "%s", getlval(p),
402 *p->n_name ? "+" : "");
403 if (p->n_name[0])
404 printf("%s", p->n_name);
405 else
406 comperr("adrput");
407 return;
408
409 case OREG:
410 r = p->n_rval;
411
412 if (getlval(p))
413 fprintf(io, CONFMT "%s", getlval(p),
414 *p->n_name ? "+" : "");
415 if (p->n_name[0])
416 printf("%s", p->n_name);
417 if (R2TEST(r)) {
418 int r1 = R2UPK1(r);
419 int r2 = R2UPK2(r);
420 int sh = R2UPK3(r);
421
422 fprintf(io, "(%s,%s,%d)",
423 r1 == MAXREGS ? "" : rnames[r1],
424 r2 == MAXREGS ? "" : rnames[r2], sh);
425 } else
426 fprintf(io, "(%s)", rnames[p->n_rval]);
427 return;
428 case ICON:
429 /* addressable value of the constant */
430 if (p->n_type == LONGLONG || p->n_type == ULONGLONG) {
431 fprintf(io, "#" CONFMT, getlval(p) >> 32);
432 } else {
433 fputc('#', io);
434 conput(io, p);
435 }
436 return;
437
438 case REG:
439 if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) &&
440 /* XXX allocated reg may get wrong type here */
441 (p->n_rval > A7 && p->n_rval < FP0)) {
442 fprintf(io, "%%%c%c", rnames[p->n_rval][0],
443 rnames[p->n_rval][1]);
444 } else
445 fprintf(io, "%s", rnames[p->n_rval]);
446 return;
447
448 default:
449 comperr("illegal address, op %d, node %p", p->n_op, p);
450 return;
451
452 }
453 }
454
455 static char *
456 ccbranches[] = {
457 "jeq", /* jumpe */
458 "jne", /* jumpn */
459 "jle", /* jumple */
460 "jlt", /* jumpl */
461 "jge", /* jumpge */
462 "jgt", /* jumpg */
463 "jls", /* jumple (jlequ) */
464 "jcs", /* jumpl (jlssu) */
465 "jcc", /* jumpge (jgequ) */
466 "jhi", /* jumpg (jgtru) */
467 };
468
469
470 /* printf conditional and unconditional branches */
471 void
cbgen(int o,int lab)472 cbgen(int o, int lab)
473 {
474 if (o < EQ || o > UGT)
475 comperr("bad conditional branch: %s", opst[o]);
476 printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab);
477 }
478
479 static void
mkcall(NODE * p,char * name)480 mkcall(NODE *p, char *name)
481 {
482 p->n_op = CALL;
483 p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
484 p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
485 p->n_left->n_name = name;
486 }
487
488 static void
mkcall2(NODE * p,char * name)489 mkcall2(NODE *p, char *name)
490 {
491 p->n_op = CALL;
492 p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type);
493 p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type);
494 p->n_right = mkbinode(CM, p->n_left, p->n_right, INT);
495 p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type);
496 p->n_left->n_name = name;
497 }
498
499
500 static void
fixcalls(NODE * p,void * arg)501 fixcalls(NODE *p, void *arg)
502 {
503 struct attr *ap;
504 TWORD lt;
505
506 switch (p->n_op) {
507 case STCALL:
508 case USTCALL:
509 ap = attr_find(p->n_ap, ATTR_P2STRUCT);
510 if (ap->iarg(0)+p2autooff > stkpos)
511 stkpos = ap->iarg(0)+p2autooff;
512 break;
513
514 case DIV:
515 if (p->n_type == LONGLONG)
516 mkcall2(p, "__divdi3");
517 else if (p->n_type == ULONGLONG)
518 mkcall2(p, "__udivdi3");
519 break;
520
521 case MOD:
522 if (p->n_type == LONGLONG)
523 mkcall2(p, "__moddi3");
524 else if (p->n_type == ULONGLONG)
525 mkcall2(p, "__umoddi3");
526 break;
527
528 case MUL:
529 if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
530 mkcall2(p, "__muldi3");
531 break;
532
533 case LS:
534 if (p->n_type == LONGLONG || p->n_type == ULONGLONG)
535 mkcall2(p, "__ashldi3");
536 break;
537
538 case RS:
539 if (p->n_type == LONGLONG)
540 mkcall2(p, "__ashrdi3");
541 else if (p->n_type == ULONGLONG)
542 mkcall2(p, "__lshrdi3");
543 break;
544
545 case SCONV:
546 lt = p->n_left->n_type;
547 switch (p->n_type) {
548 case LONGLONG:
549 if (lt == FLOAT)
550 mkcall(p, "__fixsfdi");
551 else if (lt == DOUBLE)
552 mkcall(p, "__fixdfdi");
553 else if (lt == LDOUBLE)
554 mkcall(p, "__fixxfdi");
555 break;
556 case ULONGLONG:
557 if (lt == FLOAT)
558 mkcall(p, "__fixunssfdi");
559 else if (lt == DOUBLE)
560 mkcall(p, "__fixunsdfdi");
561 else if (lt == LDOUBLE)
562 mkcall(p, "__fixunsxfdi");
563 break;
564 case FLOAT:
565 if (lt == LONGLONG)
566 mkcall(p, "__floatdisf");
567 else if (lt == ULONGLONG)
568 mkcall(p, "__floatundisf");
569 break;
570 case DOUBLE:
571 if (lt == LONGLONG)
572 mkcall(p, "__floatdidf");
573 else if (lt == ULONGLONG)
574 mkcall(p, "__floatundidf");
575 break;
576 case LDOUBLE:
577 if (lt == LONGLONG)
578 mkcall(p, "__floatdixf");
579 else if (lt == ULONGLONG)
580 mkcall(p, "__floatundixf");
581 break;
582 }
583 break;
584 #if 0
585 case XASM:
586 p->n_name = adjustname(p->n_name);
587 break;
588 #endif
589 }
590 }
591
592 void
myreader(struct interpass * ipole)593 myreader(struct interpass *ipole)
594 {
595 struct interpass *ip;
596
597 stkpos = p2autooff;
598 DLIST_FOREACH(ip, ipole, qelem) {
599 if (ip->type != IP_NODE)
600 continue;
601 walkf(ip->ip_node, fixcalls, 0);
602 }
603 if (stkpos > p2autooff)
604 p2autooff = stkpos;
605 if (stkpos > p2maxautooff)
606 p2maxautooff = stkpos;
607 if (x2debug)
608 printip(ipole);
609 }
610
611 /*
612 * Remove some PCONVs after OREGs are created.
613 */
614 static void
pconv2(NODE * p,void * arg)615 pconv2(NODE *p, void *arg)
616 {
617 NODE *q;
618
619 if (p->n_op == PLUS) {
620 if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
621 if (p->n_right->n_op != ICON)
622 return;
623 if (p->n_left->n_op != PCONV)
624 return;
625 if (p->n_left->n_left->n_op != OREG)
626 return;
627 q = p->n_left->n_left;
628 nfree(p->n_left);
629 p->n_left = q;
630 /*
631 * This will be converted to another OREG later.
632 */
633 }
634 }
635 }
636
637 void
mycanon(NODE * p)638 mycanon(NODE *p)
639 {
640 walkf(p, pconv2, 0);
641 }
642
643 void
myoptim(struct interpass * ip)644 myoptim(struct interpass *ip)
645 {
646 }
647
648 void
rmove(int s,int d,TWORD t)649 rmove(int s, int d, TWORD t)
650 {
651
652 if (s >= D0D1 && s <= D6D7) {
653 printf(" move.l %s,%s\n",
654 rnames[s-D0D1], rnames[d-D0D1]);
655 printf(" move.l %s,%s\n",
656 rnames[s+1-D0D1], rnames[d+1-D0D1]);
657 } else if (t >= FLOAT && t <= TDOUBLE)
658 printf(" fmove.x %s,%s\n", rnames[s], rnames[d]);
659 else
660 printf(" move.l %s,%s\n", rnames[s], rnames[d]);
661 }
662
663 /*
664 * For class cc, find worst-case displacement of the number of
665 * registers in the array r[] indexed by class.
666 */
667 int
COLORMAP(int cc,int * r)668 COLORMAP(int cc, int *r)
669 {
670 int a,c;
671
672 a = r[CLASSA];
673 c = r[CLASSC];
674
675 switch (cc) {
676 case CLASSA:
677 if (c * 2 + a < 8)
678 return 1;
679 break;
680 case CLASSB:
681 return r[CLASSB] < 6;
682 case CLASSC:
683 if (c > 2)
684 return 0;
685 if (c == 2 && a > 0)
686 return 0;
687 if (c == 1 && a > 1)
688 return 0;
689 if (c == 0 && a > 3)
690 return 0;
691 return 1;
692 }
693 return 0;
694 }
695
696 char *rnames[] = {
697 "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
698 "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
699 "d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7",
700 "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7",
701 };
702
703 /*
704 * Return a class suitable for a specific type.
705 */
706 int
gclass(TWORD t)707 gclass(TWORD t)
708 {
709 if (t > BTMASK)
710 return CLASSB;
711 if (t == LONGLONG || t == ULONGLONG)
712 return CLASSC;
713 if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
714 return CLASSD;
715 return CLASSA;
716 }
717
718 static int
argsiz(NODE * p)719 argsiz(NODE *p)
720 {
721 TWORD t = p->n_type;
722
723 if (t < LONGLONG || t == FLOAT || t > BTMASK)
724 return 4;
725 if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
726 return 8;
727 if (t == LDOUBLE)
728 return 12;
729 if (t == STRTY || t == UNIONTY)
730 return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3;
731 comperr("argsiz");
732 return 0;
733 }
734
735 /*
736 * Calculate argument sizes.
737 */
738 void
lastcall(NODE * p)739 lastcall(NODE *p)
740 {
741 NODE *op = p;
742 int size = 0;
743
744 p->n_qual = 0;
745 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
746 return;
747 for (p = p->n_right; p->n_op == CM; p = p->n_left)
748 size += argsiz(p->n_right);
749 size += argsiz(p);
750 op->n_qual = size; /* XXX */
751 }
752
753 /*
754 * Special shapes.
755 */
756 int
special(NODE * p,int shape)757 special(NODE *p, int shape)
758 {
759 return SRNOPE;
760 }
761
762 /*
763 * Target-dependent command-line options.
764 */
765 void
mflags(char * str)766 mflags(char *str)
767 {
768 }
769
770 /*
771 * Do something target-dependent for xasm arguments.
772 */
773 int
myxasm(struct interpass * ip,NODE * p)774 myxasm(struct interpass *ip, NODE *p)
775 {
776 int cw = xasmcode(p->n_name);
777 int ww;
778 char *w;
779
780 ww = XASMVAL(cw);
781 again: switch (ww) {
782 case 'd': /* Just convert to reg */
783 case 'a':
784 p->n_name = tmpstrdup(p->n_name);
785 w = strchr(p->n_name, XASMVAL(cw));
786 *w = 'r'; /* now reg */
787 break;
788 case 'o': /* offsetable reg */
789 if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG ||
790 p->n_left->n_op == NAME) {
791 return 1;
792 }
793 if (ww == XASMVAL(cw))
794 ww = XASMVAL1(cw);
795 else
796 ww = XASMVAL2(cw);
797 goto again;
798 }
799 return 0;
800 }
801
802 /*
803 * Handle special characters following % in gcc extended assembler.
804 */
805 int
targarg(char * w,void * arg)806 targarg(char *w, void *arg)
807 {
808 switch (w[1]) {
809 case '.': /* Remove dot if not needed */
810 printf(".");
811 break;
812 default:
813 return 0;
814 }
815 return 1;
816 }
817