Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:plunky:20120422210740

Diff

Diff from 1.29 to:

Annotations

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

Annotated File View

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