Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20140529192002

Diff

Diff from 1.31 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/arch/powerpc/code.c

Annotated File View

plunky
1.31
1 /*      $Id: code.c,v 1.31 2014/05/29 19:20:03 plunky Exp $     */
gmcgarry
1.1
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 #include <assert.h>
gmcgarry
1.2
30 #include <stdlib.h>
gmcgarry
1.1
31
gmcgarry
1.2
32 #include "pass1.h"
gmcgarry
1.1
33 #include "pass2.h"
34
gmcgarry
1.13
35 static void genswitch_bintree(int numTWORD tystruct swents **pint n);
36
stefan
1.7
37 #if 0
gmcgarry
1.2
38 static void genswitch_table(int numstruct swents **pint n);
39 static void genswitch_mrst(int numstruct swents **pint n);
stefan
1.7
40 #endif
gmcgarry
1.2
41
gmcgarry
1.13
42 static int rvnr;
43
ragge
1.12
44 /*
ragge
1.28
45  * Print out assembler segment name.
46  */
47 void
48 setseg(int segchar *name)
49 {
50         switch (seg) {
51         case PROGname = ".text"break;
52         case DATA:
53         case LDATAname = ".data"break;
54         case UDATAbreak;
55 #ifdef MACHOABI
56         case PICLDATA:
57         case PICDATAname = ".section .data.rel.rw,\"aw\""break;
58         case PICRDATAname = ".section .data.rel.ro,\"aw\""break;
59         case STRNGname = ".cstring"break;
60         case RDATAname = ".const_data"break;
61 #else
62         case PICLDATAname = ".section .data.rel.local,\"aw\",@progbits";break;
63         case PICDATAname = ".section .data.rel.rw,\"aw\",@progbits"break;
64         case PICRDATAname = ".section .data.rel.ro,\"aw\",@progbits"break;
65         case STRNG:
66 #ifdef AOUTABI
67         case RDATAname = ".data"break;
68 #else
69         case RDATAname = ".section .rodata"break;
70 #endif
71 #endif
72         case TLSDATAname = ".section .tdata,\"awT\",@progbits"break;
73         case TLSUDATAname = ".section .tbss,\"awT\",@nobits"break;
74         case CTORSname = ".section\t.ctors,\"aw\",@progbits"break;
75         case DTORSname = ".section\t.dtors,\"aw\",@progbits"break;
76         case NMSEG
ragge
1.30
77                 printf("\t.section %s,\"a%c\",@progbits\n"name,
78                     cftnsp ? 'x' : 'w');
ragge
1.28
79                 return;
80         }
81         printf("\t%s\n"name);
82 }
83
84 void
85 defalign(int al)
86 {
87         if (ispow2(al/ALCHAR))
88                 printf("\t.p2align %d\n"ispow2(al/ALCHAR));
89 }
90
91
92 /*
ragge
1.12
93  * Define everything needed to print out some data (or text).
94  * This means segment, alignment, visibility, etc.
95  */
96 void
97 defloc(struct symtab *sp)
98 {
ragge
1.21
99         char *name;
gmcgarry
1.13
100
ragge
1.21
101         name = sp->soname ? sp->soname : exname(sp->sname);
ragge
1.12
102         if (sp->sclass == EXTDEF)
ragge
1.21
103                 printf("        .globl %s\n"name);
ragge
1.12
104         if (sp->slevel == 0)
ragge
1.21
105                 printf("%s:\n"name);
ragge
1.12
106         else
107                 printf(LABFMT ":\n"sp->soffset);
108 }
109
gmcgarry
1.13
110 /* Put a symbol in a temporary
111  * used by bfcode() and its helpers
112  */
113 static void
114 putintemp(struct symtab *sym)
115 {
116         NODE *p;
117
ragge
1.23
118         p = tempnode(0sym->stypesym->sdfsym->sap);
ragge
1.17
119         p = buildtree(ASSIGNpnametree(sym));
gmcgarry
1.13
120         sym->soffset = regno(p->n_left);
121         sym->sflags |= STNODE;
122         ecomp(p);
123 }
124
125 /* setup a 64-bit parameter (double/ldouble/longlong)
126  * used by bfcode() */
127 static void
gmcgarry
1.16
128 param_64bit(struct symtab *symint *argofspint dotemps)
gmcgarry
1.13
129 {
gmcgarry
1.16
130         int argofs = *argofsp;
gmcgarry
1.13
131         NODE *p, *q;
132         int navail;
133
134 #if ALLONGLONG == 64
135         /* alignment */
gmcgarry
1.16
136         ++argofs;
137         argofs &= ~1;
gmcgarry
1.13
138 #endif
139
gmcgarry
1.16
140         navail = NARGREGS - argofs;
ragge
1.12
141
gmcgarry
1.13
142         if (navail < 2) {
143                 /* half in and half out of the registers */
ragge
1.24
144                 q = block(REGNILNILINT00);
gmcgarry
1.16
145                 regno(q) = R3 + argofs;
ragge
1.24
146                 p = block(REGNILNILINT00);
gmcgarry
1.13
147                 regno(p) = FPREG;
ragge
1.24
148                 p = block(PLUSpbcon(sym->soffset/SZCHAR), PTR+INT00);
149                 p = block(UMULpNILINT00);
gmcgarry
1.13
150         } else {
ragge
1.23
151                 q = block(REGNILNILsym->stypesym->sdfsym->sap);
gmcgarry
1.16
152                 regno(q) = R3R4 + argofs;
gmcgarry
1.13
153                 if (dotemps) {
ragge
1.23
154                         p = tempnode(0sym->stypesym->sdfsym->sap);
gmcgarry
1.13
155                         sym->soffset = regno(p);
156                         sym->sflags |= STNODE;
157                 } else {
ragge
1.17
158                         p = nametree(sym);
gmcgarry
1.13
159                 }
160         }
161         p = buildtree(ASSIGNpq);
162         ecomp(p);
gmcgarry
1.16
163         *argofsp = argofs + 2;
gmcgarry
1.13
164 }
165
166 /* setup a 32-bit param on the stack
167  * used by bfcode() */
168 static void
gmcgarry
1.16
169 param_32bit(struct symtab *symint *argofspint dotemps)
gmcgarry
1.13
170 {
171         NODE *p, *q;
172
ragge
1.23
173         q = block(REGNILNILsym->stypesym->sdfsym->sap);
gmcgarry
1.16
174         regno(q) = R3 + (*argofsp)++;
gmcgarry
1.13
175         if (dotemps) {
ragge
1.23
176                 p = tempnode(0sym->stypesym->sdfsym->sap);
gmcgarry
1.13
177                 sym->soffset = regno(p);
178                 sym->sflags |= STNODE;
179         } else {
ragge
1.17
180                 p = nametree(sym);
gmcgarry
1.13
181         }
182         p = buildtree(ASSIGNpq);
183         ecomp(p);
184 }
185
186 /* setup a double param on the stack
187  * used by bfcode() */
188 static void
gmcgarry
1.16
189 param_double(struct symtab *symint *argofspint dotemps)
gmcgarry
1.1
190 {
gmcgarry
1.13
191         NODE *p, *q, *t;
192         int tmpnr;
193
194         /*
195          * we have to dump the double from the general register
196          * into a temp, since the register allocator doesn't like
197          * floats to be in CLASSA.  This may not work for -xtemps.
198          */
199
200         if (xtemps) {
ragge
1.24
201                 q = block(REGNILNILULONGLONG00);
gmcgarry
1.16
202                 regno(q) = R3R4 + *argofsp;
ragge
1.24
203                 p = block(REGNILNILPTR+ULONGLONG00);
gmcgarry
1.13
204                 regno(p) = SPREG;
ragge
1.24
205                 p = block(PLUSpbcon(-8), INT00);
206                 p = block(UMULpNILULONGLONG00);
gmcgarry
1.13
207                 p = buildtree(ASSIGNpq);
208                 ecomp(p);
209         
ragge
1.23
210                 t = tempnode(0sym->stypesym->sdfsym->sap);
gmcgarry
1.13
211                 tmpnr = regno(t);
212                 p = block(REGNILNIL,
ragge
1.23
213                     INCREF(sym->stype), sym->sdfsym->sap);
gmcgarry
1.13
214                 regno(p) = SPREG;
ragge
1.24
215                 p = block(PLUSpbcon(-8), INT00);
ragge
1.23
216                 p = block(UMULpNILsym->stypesym->sdfsym->sap);
gmcgarry
1.13
217                 p = buildtree(ASSIGNtp);
218                 ecomp(p);
219         } else {
220                 /* bounce straight into temp */
ragge
1.24
221                 p = block(REGNILNILULONGLONG00);
gmcgarry
1.16
222                 regno(p) = R3R4 + *argofsp;
ragge
1.24
223                 t = tempnode(0ULONGLONG00);
gmcgarry
1.13
224                 tmpnr = regno(t);
225                 p = buildtree(ASSIGNtp);
226                 ecomp(p);
227         }
228
gmcgarry
1.16
229         (*argofsp) += 2;
gmcgarry
1.13
230         
231         sym->soffset = tmpnr;
232         sym->sflags |= STNODE;
gmcgarry
1.1
233 }
234
gmcgarry
1.13
235 /* setup a float param on the stack
236  * used by bfcode() */
237 static void
gmcgarry
1.16
238 param_float(struct symtab *symint *argofspint dotemps)
gmcgarry
1.1
239 {
gmcgarry
1.13
240         NODE *p, *q, *t;
241         int tmpnr;
242
243         /*
244          * we have to dump the float from the general register
245          * into a temp, since the register allocator doesn't like
246          * floats to be in CLASSA.  This may not work for -xtemps.
247          */
248
249         if (xtemps) {
250                 /* bounce onto TOS */
ragge
1.24
251                 q = block(REGNILNILINT00);
gmcgarry
1.16
252                 regno(q) = R3 + (*argofsp);
ragge
1.24
253                 p = block(REGNILNILINT00);
gmcgarry
1.13
254                 regno(p) = SPREG;
ragge
1.24
255                 p = block(PLUSpbcon(-4), INT00);
256                 p = block(UMULpNILINT00);
gmcgarry
1.13
257                 p = buildtree(ASSIGNpq);
258                 ecomp(p);
259
ragge
1.23
260                 t = tempnode(0sym->stypesym->sdfsym->sap);
gmcgarry
1.13
261                 tmpnr = regno(t);
262                 p = block(REGNILNILINCREF(sym->stype),
ragge
1.23
263                     sym->sdfsym->sap);
gmcgarry
1.13
264                 regno(p) = SPREG;
ragge
1.24
265                 p = block(PLUSpbcon(-4), INT00);
ragge
1.23
266                 p = block(UMULpNILsym->stypesym->sdfsym->sap);
gmcgarry
1.13
267                 p = buildtree(ASSIGNtp);
268                 ecomp(p);
269         } else {
270                 /* bounce straight into temp */
ragge
1.24
271                 p = block(REGNILNILINT00);
gmcgarry
1.16
272                 regno(p) = R3 + (*argofsp);
ragge
1.24
273                 t = tempnode(0INT00);
gmcgarry
1.13
274                 tmpnr = regno(t);
275                 p = buildtree(ASSIGNtp);
276                 ecomp(p);
277         }
gmcgarry
1.1
278
gmcgarry
1.16
279         (*argofsp)++;
gmcgarry
1.13
280
281         sym->soffset = tmpnr;
282         sym->sflags |= STNODE;
gmcgarry
1.1
283 }
284
gmcgarry
1.13
285 /* setup the hidden pointer to struct return parameter
286  * used by bfcode() */
287 static void
288 param_retstruct(void)
gmcgarry
1.1
289 {
290         NODE *p, *q;
291
ragge
1.23
292         p = tempnode(0INCREF(cftnsp->stype), 0cftnsp->sap);
gmcgarry
1.13
293         rvnr = regno(p);
gmcgarry
1.15
294         q = block(REGNILNILINCREF(cftnsp->stype),
ragge
1.23
295             cftnsp->sdfcftnsp->sap);
gmcgarry
1.13
296         regno(q) = R3;
297         p = buildtree(ASSIGNpq);
298         ecomp(p);
299 }
300
301
302 /* setup struct parameter
303  * push the registers out to memory
304  * used by bfcode() */
305 static void
gmcgarry
1.16
306 param_struct(struct symtab *symint *argofsp)
gmcgarry
1.13
307 {
gmcgarry
1.16
308         int argofs = *argofsp;
gmcgarry
1.13
309         NODE *p, *q;
310         int navail;
311         int sz;
312         int off;
313         int num;
314         int i;
315
gmcgarry
1.16
316         navail = NARGREGS - argofs;
ragge
1.23
317         sz = tsize(sym->stypesym->sdfsym->sap) / SZINT;
gmcgarry
1.16
318         off = ARGINIT/SZINT + argofs;
gmcgarry
1.13
319         num = sz > navail ? navail : sz;
320         for (i = 0i < numi++) {
ragge
1.24
321                 q = block(REGNILNILINT00);
gmcgarry
1.16
322                 regno(q) = R3 + argofs++;
ragge
1.24
323                 p = block(REGNILNILINT00);
gmcgarry
1.13
324                 regno(p) = SPREG;
ragge
1.24
325                 p = block(PLUSpbcon(4*off++), INT00);
326                 p = block(UMULpNILINT00);
gmcgarry
1.13
327                 p = buildtree(ASSIGNpq);
328                 ecomp(p);
329         }
gmcgarry
1.1
330
gmcgarry
1.16
331         *argofsp = argofs;
gmcgarry
1.1
332 }
333
334 /*
gmcgarry
1.13
335  * code for the beginning of a function
336  * sp is an array of indices in symtab for the arguments
337  * cnt is the number of arguments
gmcgarry
1.1
338  */
339 void
gmcgarry
1.13
340 bfcode(struct symtab **spint cnt)
gmcgarry
1.1
341 {
gmcgarry
1.13
342 #ifdef USE_GOTNR
343         extern int gotnr;
gmcgarry
1.1
344 #endif
345
ragge
1.17
346         struct symtab *sp2;
gmcgarry
1.13
347         union arglist *usym;
348         int saveallargs = 0;
gmcgarry
1.16
349         int iargofs = 0;
gmcgarry
1.13
350
351         /*
352          * Detect if this function has ellipses and save all
353          * argument registers onto stack.
354          */
355         usym = cftnsp->sdf->dfun;
356         while (usym && usym->type != TNULL) {
357                 if (usym->type == TELLIPSIS) {
358                         saveallargs = 1;
359                         break;
360                 }
361                 ++usym;
362         }
363
364         if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
365                 param_retstruct();
gmcgarry
1.16
366                 ++argofs;
gmcgarry
1.1
367         }
368
gmcgarry
1.13
369 #ifdef USE_GOTNR
370         if (kflag) {
371                 /* put GOT register into temporary */
372                 NODE *q, *p;
ragge
1.24
373                 q = block(REGNILNILINT00);
gmcgarry
1.13
374                 regno(q) = GOTREG;
ragge
1.24
375                 p = tempnode(0INT00);
gmcgarry
1.13
376                 gotnr = regno(p);
377                 ecomp(buildtree(ASSIGNpq));
gmcgarry
1.1
378         }
379 #endif
380
gmcgarry
1.13
381         /* recalculate the arg offset and create TEMP moves */
382         for (i = 0i < cnti++) {
383
384                 if (sp[i] == NULL)
385                         continue;
386
gmcgarry
1.16
387                 if ((argofs >= NARGREGS) && !xtemps)
gmcgarry
1.13
388                         break;
389
gmcgarry
1.16
390                 if (argofs >= NARGREGS) {
gmcgarry
1.13
391                         putintemp(sp[i]);
392                 } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) {
gmcgarry
1.16
393                         param_struct(sp[i], &argofs);
gmcgarry
1.13
394                 } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) {
gmcgarry
1.16
395                         param_64bit(sp[i], &argofsxtemps && !saveallargs);
gmcgarry
1.13
396                 } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) {
397                         if (features(FEATURE_HARDFLOAT))
gmcgarry
1.16
398                                 param_double(sp[i], &argofs,
gmcgarry
1.13
399                                     xtemps && !saveallargs);
400                         else
gmcgarry
1.16
401                                 param_64bit(sp[i], &argofs,
gmcgarry
1.13
402                                     xtemps && !saveallargs);
403                 } else if (sp[i]->stype == FLOAT) {
404                         if (features(FEATURE_HARDFLOAT))
gmcgarry
1.16
405                                 param_float(sp[i], &argofs,
gmcgarry
1.13
406                                     xtemps && !saveallargs);
407                         else
gmcgarry
1.16
408                                 param_32bit(sp[i], &argofs,
gmcgarry
1.13
409                                     xtemps && !saveallargs);
410                 } else {
gmcgarry
1.16
411                         param_32bit(sp[i], &argofsxtemps && !saveallargs);
gmcgarry
1.13
412                 }
413         }
414
415         /* if saveallargs, save the rest of the args onto the stack */
gmcgarry
1.16
416         while (saveallargs && argofs < NARGREGS) {
gmcgarry
1.13
417                 NODE *p, *q;
gmcgarry
1.16
418                 /* int off = (ARGINIT+FIXEDSTACKSIZE*SZCHAR)/SZINT + argofs; */
419                 int off = ARGINIT/SZINT + argofs;
ragge
1.24
420                 q = block(REGNILNILINT00);
gmcgarry
1.16
421                 regno(q) = R3 + argofs++;
ragge
1.24
422                 p = block(REGNILNILINT00);
gmcgarry
1.13
423                 regno(p) = FPREG;
ragge
1.24
424                 p = block(PLUSpbcon(4*off), INT00);
425                 p = block(UMULpNILINT00);
gmcgarry
1.13
426                 p = buildtree(ASSIGNpq);
427                 ecomp(p);
428         }
429
430         /* profiling */
431         if (pflag) {
432                 NODE *p;
433
434 #if defined(ELFABI)
435
ragge
1.17
436                 sp2 = lookup("_mcount"0);
437                 sp2->stype = EXTERN;
438                 p = nametree(sp2);
gmcgarry
1.13
439                 p->n_sp->sclass = EXTERN;
440                 p = clocal(p);
441                 p = buildtree(ADDROFpNIL);
ragge
1.24
442                 p = block(UCALLpNILINT00);
gmcgarry
1.13
443                 ecomp(funcode(p));
444
445
446 #elif defined(MACHOABI)
447
448                 NODE *q;
449                 int tmpnr;
450
ragge
1.24
451                 q = block(REGNILNILINT00);
gmcgarry
1.13
452                 regno(q) = R0;
ragge
1.24
453                 p = tempnode(0INT00);
gmcgarry
1.13
454                 tmpnr = regno(p);
455                 p = buildtree(ASSIGNpq);
456                 ecomp(p);
457
ragge
1.24
458                 q = tempnode(tmpnrINT00);
gmcgarry
1.13
459
ragge
1.17
460                 sp2 = lookup("mcount"0);
461                 sp2->stype = EXTERN;
462                 p = nametree(sp2);
gmcgarry
1.13
463                 p->n_sp->sclass = EXTERN;
464                 p = clocal(p);
465                 p = buildtree(ADDROFpNIL);
ragge
1.24
466                 p = block(CALLpqINT00);
gmcgarry
1.13
467                 ecomp(funcode(p));
468
469 #endif
gmcgarry
1.1
470         }
gmcgarry
1.13
471 }
472
473 /*
474  * code for the end of a function
475  * deals with struct return here
476  */
477 void
plunky
1.29
478 efcode(void)
gmcgarry
1.13
479 {
480         NODE *p, *q;
481         int tempnr;
482         int ty;
483
484 #ifdef USE_GOTNR
485         extern int gotnr;
486         gotnr = 0;
gmcgarry
1.1
487 #endif
gmcgarry
1.13
488
489         if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
490                 return;
491
492         ty = cftnsp->stype - FTN;
493
ragge
1.23
494         q = block(REGNILNILINCREF(ty), 0cftnsp->sap);
gmcgarry
1.13
495         regno(q) = R3;
ragge
1.23
496         p = tempnode(0INCREF(ty), 0cftnsp->sap);
gmcgarry
1.13
497         tempnr = regno(p);
498         p = buildtree(ASSIGNpq);
499         ecomp(p);
500
ragge
1.23
501         q = tempnode(tempnrINCREF(ty), 0cftnsp->sap);
gmcgarry
1.13
502         q = buildtree(UMULqNIL);
503
ragge
1.23
504         p = tempnode(rvnrINCREF(ty), 0cftnsp->sap);
gmcgarry
1.13
505         p = buildtree(UMULpNIL);
506
507         p = buildtree(ASSIGNpq);
508         ecomp(p);
509
ragge
1.23
510         q = tempnode(rvnrINCREF(ty), 0cftnsp->sap);
511         p = block(REGNILNILINCREF(ty), 0cftnsp->sap);
gmcgarry
1.13
512         regno(p) = R3;
513         p = buildtree(ASSIGNpq);
514         ecomp(p);
gmcgarry
1.1
515 }
516
517 struct stub stublist;
518 struct stub nlplist;
519
520 /* called just before final exit */
521 /* flag is 1 if errors, 0 if none */
522 void
plunky
1.29
523 ejobcode(int flag)
gmcgarry
1.1
524 {
525
gmcgarry
1.13
526 #if defined(MACHOABI)
527         /*
528          * iterate over the stublist and output the PIC stubs
529 `        */
gmcgarry
1.1
530         if (kflag) {
531                 struct stub *p;
532
533                 DLIST_FOREACH(p, &stublistlink) {
534                         printf("\t.section __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n");
535                         printf("\t.align 5\n");
gmcgarry
1.13
536                         printf("L%s$stub:\n"p->name);
537                         if (strcmp(p->name"mcount") == 0)
538                                 printf("\t.indirect_symbol %s\n"p->name);
539                         else
gmcgarry
1.22
540                                 printf("\t.indirect_symbol %s\n"p->name);
gmcgarry
1.1
541                         printf("\tmflr r0\n");
gmcgarry
1.13
542                         printf("\tbcl 20,31,L%s$spb\n"p->name);
543                         printf("L%s$spb:\n"p->name);
gmcgarry
1.1
544                         printf("\tmflr r11\n");
gmcgarry
1.13
545                         printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$spb)\n",
546                             p->namep->name);
gmcgarry
1.1
547                         printf("\tmtlr r0\n");
gmcgarry
1.13
548                         printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$spb)(r11)\n",
549                             p->namep->name);
gmcgarry
1.1
550                         printf("\tmtctr r12\n");
551                         printf("\tbctr\n");
552                         printf("\t.lazy_symbol_pointer\n");
553                         printf("L%s$lazy_ptr:\n"p->name);
gmcgarry
1.13
554                         if (strcmp(p->name"mcount") == 0)
555                                 printf("\t.indirect_symbol %s\n"p->name);
556                         else
gmcgarry
1.22
557                                 printf("\t.indirect_symbol %s\n"p->name);
gmcgarry
1.1
558                         printf("\t.long dyld_stub_binding_helper\n");
559                         printf("\t.subsections_via_symbols\n");
560                 }
561
562                 printf("\t.non_lazy_symbol_pointer\n");
563                 DLIST_FOREACH(p, &nlplistlink) {
564                         printf("L%s$non_lazy_ptr:\n"p->name);
gmcgarry
1.13
565                         if (strcmp(p->name"mcount") == 0)
566                                 printf("\t.indirect_symbol %s\n"p->name);
567                         else
gmcgarry
1.22
568                                 printf("\t.indirect_symbol %s\n"p->name);
gmcgarry
1.1
569                         printf("\t.long 0\n");
570                 }
571
572         }
gmcgarry
1.13
573 #endif
574
gmcgarry
1.18
575 #ifndef os_darwin
plunky
1.26
576         printf("\t.ident \"PCC: %s\"\n"VERSSTR);
gmcgarry
1.18
577 #endif
578
gmcgarry
1.1
579 }
580
581 void
plunky
1.29
582 bjobcode(void)
gmcgarry
1.1
583 {
584         DLIST_INIT(&stublistlink);
585         DLIST_INIT(&nlplistlink);
586 }
587
ragge
1.12
588 #ifdef notdef
gmcgarry
1.1
589 /*
590  * Print character t at position i in one string, until t == -1.
591  * Locctr & label is already defined.
592  */
593 void
594 bycode(int tint i)
595 {
596         static  int     lastoctal = 0;
597
598         /* put byte i+1 in a string */
599
600         if (t < 0) {
601                 if (i != 0)
602                         puts("\"");
603         } else {
604                 if (i == 0)
605                         printf("\t.ascii \"");
606                 if (t == '\\' || t == '"') {
607                         lastoctal = 0;
608                         putchar('\\');
609                         putchar(t);
610                 } else if (t < 040 || t >= 0177) {
611                         lastoctal++;
612                         printf("\\%o",t);
613                 } else if (lastoctal && '0' <= t && t <= '9') {
614                         lastoctal = 0;
615                         printf("\"\n\t.ascii \"%c"t);
616                 } else {        
617                         lastoctal = 0;
618                         putchar(t);
619                 }
620         }
621 }
ragge
1.12
622 #endif
gmcgarry
1.1
623
624 /* fix up type of field p */
625 void
626 fldty(struct symtab *p)
627 {
628 }
629
stefan
1.7
630 /*
gmcgarry
1.1
631  * XXX - fix genswitch.
632  */
stefan
1.7
633 int
634 mygenswitch(int numTWORD typestruct swents **pint n)
gmcgarry
1.1
635 {
gmcgarry
1.16
636         if (num < 0) {
gmcgarry
1.13
637                 genswitch_bintree(numtypepn);
638                 return 1;
gmcgarry
1.2
639         }
640
gmcgarry
1.13
641         return 0;
gmcgarry
1.2
642
gmcgarry
1.13
643 #if 0
gmcgarry
1.2
644         if (0)
645         genswitch_table(numpn);
646         if (0)
647         genswitch_bintree(numpn);
648         genswitch_mrst(numpn);
stefan
1.7
649 #endif
gmcgarry
1.2
650 }
651
gmcgarry
1.13
652 static void bintree_rec(TWORD tyint num,
653         struct swents **pint nint sint e);
gmcgarry
1.2
654
655 static void
gmcgarry
1.13
656 genswitch_bintree(int numTWORD tystruct swents **pint n)
gmcgarry
1.2
657 {
658         int lab = getlab();
659
660         if (p[0]->slab == 0)
661                 p[0]->slab = lab;
662
gmcgarry
1.13
663         bintree_rec(tynumpn1n);
gmcgarry
1.2
664
665         plabel(lab);
666 }
667
668 static void
gmcgarry
1.13
669 bintree_rec(TWORD tyint numstruct swents **pint nint sint e)
gmcgarry
1.2
670 {
671         NODE *r;
672         int rlabel;
673         int h;
674
675         if (s == e) {
ragge
1.24
676                 r = tempnode(numty00);
gmcgarry
1.2
677                 r = buildtree(NErbcon(p[s]->sval));
678                 cbranch(buildtree(NOTrNIL), bcon(p[s]->slab));
679                 branch(p[0]->slab);
680                 return;
681         }
682
683         rlabel = getlab();
684
685         h = s + (e - s) / 2;
686
ragge
1.24
687         r = tempnode(numty00);
gmcgarry
1.2
688         r = buildtree(GTrbcon(p[h]->sval));
689         cbranch(rbcon(rlabel));
gmcgarry
1.13
690         bintree_rec(tynumpnsh);
gmcgarry
1.2
691         plabel(rlabel);
gmcgarry
1.13
692         bintree_rec(tynumpnh+1e);
gmcgarry
1.2
693 }
694
695
gmcgarry
1.13
696 #if 0
gmcgarry
1.2
697
698 static void
699 genswitch_table(int numstruct swents **pint n)
700 {
701         NODE *r, *t;
702         int tval;
703         int minvalmaxvalrange;
704         int deflabeltbllabel;
705         int ij;
706
707         minval = p[1]->sval;
708         maxval = p[n]->sval;
709
710         range = maxval - minval + 1;
711
712         if (n < 10 || range > 3 * n) {
713                 /* too small or too sparse for jump table */
714                 genswitch_simple(numpn);
715                 return;
716         }
717
ragge
1.24
718         r = tempnode(numUNSIGNED00);
gmcgarry
1.2
719         r = buildtree(MINUSrbcon(minval));
ragge
1.24
720         t = tempnode(0UNSIGNED00);
ragge
1.10
721         tval = regno(t);
gmcgarry
1.2
722         r = buildtree(ASSIGNtr);
723         ecomp(r);
724
725         deflabel = p[0]->slab;
726         if (deflabel == 0)
727                 deflabel = getlab();
728
ragge
1.24
729         t = tempnode(tvalUNSIGNED00);
gmcgarry
1.2
730         cbranch(buildtree(GTtbcon(maxval-minval)), bcon(deflabel));
731
732         tbllabel = getlab();
733         struct symtab *strtbl = lookup("__switch_table"SLBLNAME|STEMP);
734         strtbl->soffset = tbllabel;
735         strtbl->sclass = ILABEL;
736         strtbl->stype = INCREF(UCHAR);
737
ragge
1.24
738         t = block(NAMENILNILUNSIGNED00);
gmcgarry
1.2
739         t->n_sp = strtbl;
740         t = buildtree(ADDROFtNIL);
ragge
1.24
741         r = tempnode(tvalUNSIGNED00);
gmcgarry
1.2
742         r = buildtree(PLUStr);
ragge
1.24
743         t = tempnode(0INCREF(UNSIGNED), 00);
gmcgarry
1.2
744         r = buildtree(ASSIGNtr);
745         ecomp(r);
746
ragge
1.24
747         r = tempnode(regno(t), INCREF(UNSIGNED), 00);
gmcgarry
1.2
748         r = buildtree(UMULrNIL);
ragge
1.24
749         t = block(NAMENILNILUCHAR00);
gmcgarry
1.2
750         t->n_sp = strtbl;
751         t = buildtree(ADDROFtNIL);
752         r = buildtree(PLUStr);
753         r = block(GOTOrNIL000);
754         ecomp(r);
755
756         plabel(tbllabel);
757         for (i = minvalj=1i <= maxvali++) {
758                 char *entry = tmpalloc(20);
759                 int lab = deflabel;
760                 //printf("; minval=%d, maxval=%d, i=%d, j=%d p[j]=%lld\n", minval, maxval, i, j, p[j]->sval);
761                 if (p[j]->sval == i) {
762                         lab = p[j]->slab;
763                         j++;
764                 }
plunky
1.31
765                 snprintf(entry20"\t.long " LABFMT "-" LABFMT "\n"labtbllabel);
gmcgarry
1.2
766                 send_passt(IP_ASMentry);
767         }
768
769         if (p[0]->slab <= 0)
770                 plabel(deflabel);
771 }
772
773 #define DPRINTF(x)      if (xdebug) printf x
774 //#define DPRINTF(x)    do { } while(0)
775
776 #define MIN_TABLE_SIZE  8
777
778 /*
779  *  Multi-way Radix Search Tree (MRST)
780  */
781
782 static void mrst_rec(int numstruct swents **pint nint *stateint lab);
783 static unsigned long mrst_find_window(struct swents **pint nint *stateint labint *lenint *lowbit);
784 void mrst_put_entry_and_recurse(int numstruct swents **pint nint *stateint tbllabelint labunsigned long junsigned long tblsizeunsigned long Wmaxint lowbit);
785
786 static void
787 genswitch_mrst(int numstruct swents **pint n)
788 {
789         int *state;
790         int i;
791         int putlabel = 0;
792
793         if (n < 10) {
794                 /* too small for MRST */
795                 genswitch_simple(numpn);
796                 return;
797         }
798
799         state = tmpalloc((n+1)*sizeof(int));
800         for (i = 0i <= ni++)
801                 state[i] = 0;
802
803         if (p[0]->slab == 0) {
804                 p[0]->slab = getlab();
805                 putlabel = 1;
806         }
807
808         mrst_rec(numpnstate0);
809
810         if (putlabel)
811                 plabel(p[0]->slab);
812 }
813
814
815 /*
816  *  Look through the cases and generate a table or
817  *  list of simple comparisons.  If generating a table,
818  *  invoke mrst_put_entry_and_recurse() to put
819  *  an entry in the table and recurse.
820  */
821 static void
822 mrst_rec(int numstruct swents **pint nint *stateint lab)
823 {
824         int lenlowbit;
825         unsigned long Wmax;
826         unsigned int tblsize;
827         NODE *t;
828         NODE *r;
829         int tval;
830         int i;
831
832         DPRINTF(("mrst_rec: num=%d, n=%d, lab=%d\n"numnlab));
833
834         /* find best window to cover set*/
835         Wmax = mrst_find_window(pnstatelab, &len, &lowbit);
836         tblsize = (1 << len);
837         assert(len > 0 && tblsize > 0);
838
839         DPRINTF(("mrst_rec: Wmax=%lu, lowbit=%d, tblsize=%u\n",
840                 Wmaxlowbittblsize));
841
842         if (lab)
843                 plabel(lab);
844
845         if (tblsize <= MIN_TABLE_SIZE) {
846                 DPRINTF(("msrt_rec: break the recursion\n"));
847                 for (i = 1i <= ni++) {
848                         if (state[i] == lab) {
ragge
1.24
849                                 t = tempnode(numUNSIGNED00);
gmcgarry
1.2
850                                 cbranch(buildtree(EQtbcon(p[i]->sval)),
851                                     bcon(p[i]->slab));
852                         }
853                 }
854                 branch(p[0]->slab);
855                 return;
856         }
857
858         DPRINTF(("generating table with %d elements\n"tblsize));
859
860         // AND with Wmax
ragge
1.24
861         t = tempnode(numUNSIGNED00);
gmcgarry
1.2
862         r = buildtree(ANDtbcon(Wmax));
863
864         // RS lowbits
865         r = buildtree(RSrbcon(lowbit));
866
ragge
1.24
867         t = tempnode(0UNSIGNED00);
ragge
1.10
868         tval = regno(t);
gmcgarry
1.2
869         r = buildtree(ASSIGNtr);
870         ecomp(r);
871
872         int tbllabel = getlab();
873         struct symtab *strtbl = lookup("__switch_table"SLBLNAME|STEMP);
ragge
1.20
874         strtbl->sclass = STATIC;
ragge
1.24
875         strtbl->sap = 0;
ragge
1.20
876         strtbl->slevel = 1;
gmcgarry
1.2
877         strtbl->soffset = tbllabel;
878         strtbl->stype = INCREF(UCHAR);
ragge
1.20
879         strtbl->squal = (CON >> TSHIFT);
gmcgarry
1.2
880
ragge
1.24
881         t = block(NAMENILNILUNSIGNED00);
gmcgarry
1.2
882         t->n_sp = strtbl;
883         t = buildtree(ADDROFtNIL);
ragge
1.24
884         r = tempnode(tvalUNSIGNED00);
gmcgarry
1.2
885         r = buildtree(PLUStr);
ragge
1.24
886         t = tempnode(0INCREF(UNSIGNED), 00);
gmcgarry
1.2
887         r = buildtree(ASSIGNtr);
888         ecomp(r);
889
ragge
1.24
890         r = tempnode(regno(t), INCREF(UNSIGNED), 00);
gmcgarry
1.2
891         r = buildtree(UMULrNIL);
ragge
1.24
892         t = block(NAMENILNILUCHAR00);
gmcgarry
1.2
893         t->n_sp = strtbl;
894         t = buildtree(ADDROFtNIL);
895         r = buildtree(PLUStr);
896         r = block(GOTOrNIL000);
897         ecomp(r);
898
899         plabel(tbllabel);
900         
901         mrst_put_entry_and_recurse(numpnstatetbllabellab,
902                 0tblsizeWmaxlowbit);
903 }
904
905
906 /*
907  * Put an entry into the table and recurse to the next entry
908  * in the table.  On the way back through the recursion, invoke
909  * mrst_rec() to check to see if we should generate another
910  * table.
911  */
912 void
913 mrst_put_entry_and_recurse(int numstruct swents **pint nint *state,
914         int tbllabelint labval,
915         unsigned long junsigned long tblsizeunsigned long Wmaxint lowbit)
916 {
917         int i;
918         int found = 0;
919         int lab = getlab();
920
921         /*
922          *  Look for labels which map to this table entry.
923          *  Mark each one in "state" that they fall inside this table.
924          */
925         for (i = 1i <= ni++) {
926                 unsigned int val = (p[i]->sval & Wmax) >> lowbit;
927                 if (val == j && state[i] == labval) {
928                         found = 1;
929                         state[i] = lab;
930                 }
931         }
932
933         /* couldn't find any labels?  goto the default label */
934         if (!found)
935                 lab = p[0]->slab;
936
937         /* generate the table entry */
938         char *entry = tmpalloc(20);
plunky
1.31
939         snprintf(entry20"\t.long " LABFMT "-" LABFMT "\n"labtbllabel);
gmcgarry
1.2
940         send_passt(IP_ASMentry);
941
942         DPRINTF(("mrst_put_entry: table=%d, pos=%lu/%lu, label=%d\n",
943             tbllabeljtblsizelab));
944
945         /* go to the next table entry */
946         if (j+1 < tblsize) {
947                 mrst_put_entry_and_recurse(numpnstatetbllabellabval,
948                         j+1tblsizeWmaxlowbit);
949         }
950
951         /* if we are going to the default label, bail now */
952         if (!found)
953                 return;
954
955 #ifdef PCC_DEBUG
956         if (xdebug) {
957                 printf("state: ");
958                 for (i = 1i <= ni++)
959                         printf("%d "state[i]);
960                 printf("\n");
961         }
962 #endif
963
964         /* build another table */
965         mrst_rec(numpnstatelab);
966 }
967
968 /*
969  * counts the number of entries in a table of size (1 << L) which would
970  * be used given the cases and the mask (W, lowbit).
971  */
972 static unsigned int
973 mrst_cardinality(struct swents **pint nint *stateint stepunsigned long Wint Lint lowbit)
974 {
975         unsigned int count = 0;
976         int i;
977
978         if (W == 0)
979                 return 0;
980
981         int *vals = (int *)calloc(1 << Lsizeof(int));
982         assert(vals);
983
984         DPRINTF(("mrst_cardinality: "));
985         for (i = 1i <= ni++) {
986                 int idx;
987                 if (state[i] != step)
988                         continue;
989                 idx = (p[i]->sval & W) >> lowbit;
990                 DPRINTF(("%llu->%d, "p[i]->svalidx));
991                 if (!vals[idx]) {
992                         count++;
993                 }
994                 vals[idx] = 1;
995         }
996         DPRINTF((": found %d entries\n"count));
997         free(vals);
998
999