* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / arch / i386 / code.c
blobc891c1ca9dce1462018507d626bece0b9e41eaf8
1 /* $Id: code.c,v 1.56.2.1 2011/03/01 17:33:24 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
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
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.
30 # include "pass1.h"
32 int lastloc = -1;
35 * Define everything needed to print out some data (or text).
36 * This means segment, alignment, visibility, etc.
38 void
39 defloc(struct symtab *sp)
41 extern char *nextsect;
42 struct attr *ap;
43 int weak = 0;
44 char *name = NULL;
45 #if defined(ELFABI) || defined(PECOFFABI)
46 static char *loctbl[] = { "text", "data", "section .rodata" };
47 #elif defined(MACHOABI)
48 static char *loctbl[] = { "text", "data", "const_data" };
49 #endif
50 TWORD t;
51 int s, al;
53 if (sp == NULL) {
54 lastloc = -1;
55 return;
57 t = sp->stype;
58 s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
59 if ((name = sp->soname) == NULL)
60 name = exname(sp->sname);
61 #ifdef TLS
62 if (sp->sflags & STLS) {
63 if (s != DATA)
64 cerror("non-data symbol in tls section");
65 nextsect = ".tdata";
67 #endif
68 #ifdef GCC_COMPAT
70 if ((ap = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL)
71 nextsect = ap->sarg(0);
72 if (attr_find(sp->sap, GCC_ATYP_WEAK) != NULL)
73 weak = 1;
74 if (attr_find(sp->sap, GCC_ATYP_DESTRUCTOR)) {
75 printf("\t.section\t.dtors,\"aw\",@progbits\n");
76 printf("\t.align 4\n\t.long\t%s\n", name);
77 lastloc = -1;
79 if (attr_find(sp->sap, GCC_ATYP_CONSTRUCTOR)) {
80 printf("\t.section\t.ctors,\"aw\",@progbits\n");
81 printf("\t.align 4\n\t.long\t%s\n", name);
82 lastloc = -1;
84 if ((ap = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) &&
85 strcmp(ap->sarg(0), "default"))
86 printf("\t.%s %s\n", ap->sarg(0), name);
88 #endif
89 #ifdef ELFABI
90 if (kflag && !ISFTN(t)) {
91 /* Must place aggregates with pointers in relocatable memory */
92 TWORD t2 = t;
94 while (ISARY(t2))
95 t2 = DECREF(t2);
96 if (t2 > LDOUBLE) {
97 /* put in reloc memory */
98 printf("\t.section .data.rel.local,\"aw\",@progbits\n");
99 s = lastloc = -1;
102 #endif
103 if (nextsect) {
104 printf(" .section %s,\"wa\",@progbits\n", nextsect);
105 nextsect = NULL;
106 s = -1;
107 } else if (s != lastloc)
108 printf(" .%s\n", loctbl[s]);
109 lastloc = s;
110 while (ISARY(t))
111 t = DECREF(t);
112 al = ISFTN(t) ? ALINT : talign(t, sp->sap);
113 if (al > ALCHAR)
114 printf(" .align %d\n", al/ALCHAR);
115 if (weak)
116 printf(" .weak %s\n", name);
117 else if (sp->sclass == EXTDEF) {
118 printf(" .globl %s\n", name);
119 #if defined(ELFABI)
120 printf("\t.type %s,@%s\n", name,
121 ISFTN(t)? "function" : "object");
122 #endif
124 #if defined(ELFABI)
125 if (!ISFTN(t)) {
126 if (sp->slevel == 0)
127 printf("\t.size %s,%d\n", name,
128 (int)tsize(t, sp->sdf, sp->sap)/SZCHAR);
129 else
130 printf("\t.size " LABFMT ",%d\n", sp->soffset,
131 (int)tsize(t, sp->sdf, sp->sap)/SZCHAR);
133 #endif
134 if (sp->slevel == 0)
135 printf("%s:\n", name);
136 else
137 printf(LABFMT ":\n", sp->soffset);
141 * code for the end of a function
142 * deals with struct return here
144 void
145 efcode()
147 extern int gotnr;
148 NODE *p, *q;
150 gotnr = 0; /* new number for next fun */
151 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
152 return;
153 #if defined(os_openbsd)
154 /* struct return for small structs */
155 int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
156 if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) {
157 /* Pointer to struct in eax */
158 if (sz == SZLONGLONG) {
159 q = block(OREG, NIL, NIL, INT, 0, MKAP(INT));
160 q->n_lval = 4;
161 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
162 p->n_rval = EDX;
163 ecomp(buildtree(ASSIGN, p, q));
165 if (sz < SZSHORT) sz = CHAR;
166 else if (sz > SZSHORT) sz = INT;
167 else sz = SHORT;
168 q = block(OREG, NIL, NIL, sz, 0, MKAP(sz));
169 p = block(REG, NIL, NIL, sz, 0, MKAP(sz));
170 ecomp(buildtree(ASSIGN, p, q));
171 return;
173 #endif
174 /* Create struct assignment */
175 q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
176 q->n_rval = EBP;
177 q->n_lval = 8; /* return buffer offset */
178 q = buildtree(UMUL, q, NIL);
179 p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
180 p = buildtree(UMUL, p, NIL);
181 p = buildtree(ASSIGN, q, p);
182 ecomp(p);
184 /* put hidden arg in eax on return */
185 q = block(OREG, NIL, NIL, INT, 0, MKAP(INT));
186 regno(q) = FPREG;
187 q->n_lval = 8;
188 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
189 regno(p) = EAX;
190 ecomp(buildtree(ASSIGN, p, q));
194 * code for the beginning of a function; a is an array of
195 * indices in symtab for the arguments; n is the number
197 void
198 bfcode(struct symtab **sp, int cnt)
200 extern int argstacksize;
201 struct symtab *sp2;
202 extern int gotnr;
203 NODE *n, *p;
204 int i;
206 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
207 /* Function returns struct, adjust arg offset */
208 #if defined(os_openbsd)
209 /* OpenBSD uses non-standard return for small structs */
210 int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
211 if (sz != SZCHAR && sz != SZSHORT &&
212 sz != SZINT && sz != SZLONGLONG)
213 #endif
214 for (i = 0; i < cnt; i++)
215 sp[i]->soffset += SZPOINT(INT);
218 #ifdef GCC_COMPAT
219 if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
220 cftnsp->sflags |= SSTDCALL;
221 #endif
224 * Count the arguments
226 argstacksize = 0;
227 if (cftnsp->sflags & SSTDCALL) {
228 #ifdef os_win32
230 char buf[256];
231 char *name;
232 #endif
234 for (i = 0; i < cnt; i++) {
235 TWORD t = sp[i]->stype;
236 if (t == STRTY || t == UNIONTY)
237 argstacksize +=
238 tsize(t, sp[i]->sdf, sp[i]->sap);
239 else
240 argstacksize += szty(t) * SZINT / SZCHAR;
242 #ifdef os_win32
244 * mangle name in symbol table as a callee.
246 if ((name = cftnsp->soname) == NULL)
247 name = exname(cftnsp->sname);
248 snprintf(buf, 256, "%s@%d", name, argstacksize);
249 cftnsp->soname = addname(buf);
250 #endif
253 if (kflag) {
254 #define STL 200
255 char *str = inlalloc(STL);
256 #if !defined(MACHOABI)
257 int l = getlab();
258 #else
259 char *name;
260 #endif
262 /* Generate extended assembler for PIC prolog */
263 p = tempnode(0, INT, 0, MKAP(INT));
264 gotnr = regno(p);
265 p = block(XARG, p, NIL, INT, 0, MKAP(INT));
266 p->n_name = "=g";
267 p = block(XASM, p, bcon(0), INT, 0, MKAP(INT));
269 #if defined(MACHOABI)
270 if ((name = cftnsp->soname) == NULL)
271 name = cftnsp->sname;
272 if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n",
273 name, name) >= STL)
274 cerror("bfcode");
275 #else
276 if (snprintf(str, STL,
277 "call " LABFMT "\n" LABFMT ":\n popl %%0\n"
278 " addl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0\n",
279 l, l, l) >= STL)
280 cerror("bfcode");
281 #endif
282 p->n_name = str;
283 p->n_right->n_type = STRTY;
284 ecomp(p);
286 if (xtemps == 0)
287 return;
289 /* put arguments in temporaries */
290 for (i = 0; i < cnt; i++) {
291 if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY ||
292 cisreg(sp[i]->stype) == 0)
293 continue;
294 if (cqual(sp[i]->stype, sp[i]->squal) & VOL)
295 continue;
296 sp2 = sp[i];
297 n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap);
298 n = buildtree(ASSIGN, n, nametree(sp2));
299 sp[i]->soffset = regno(n->n_left);
300 sp[i]->sflags |= STNODE;
301 ecomp(n);
307 * by now, the automatics and register variables are allocated
309 void
310 bccode()
312 SETOFF(autooff, SZINT);
315 #if defined(MACHOABI)
316 struct stub stublist;
317 struct stub nlplist;
318 #endif
320 /* called just before final exit */
321 /* flag is 1 if errors, 0 if none */
322 void
323 ejobcode(int flag )
325 #if defined(MACHOABI)
327 * iterate over the stublist and output the PIC stubs
328 ` */
329 if (kflag) {
330 struct stub *p;
332 DLIST_FOREACH(p, &stublist, link) {
333 printf("\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n");
334 printf("L%s$stub:\n", p->name);
335 printf("\t.indirect_symbol %s\n", p->name);
336 printf("\thlt ; hlt ; hlt ; hlt ; hlt\n");
337 printf("\t.subsections_via_symbols\n");
340 printf("\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
341 DLIST_FOREACH(p, &nlplist, link) {
342 printf("L%s$non_lazy_ptr:\n", p->name);
343 printf("\t.indirect_symbol %s\n", p->name);
344 printf("\t.long 0\n");
348 #endif
350 #define _MKSTR(x) #x
351 #define MKSTR(x) _MKSTR(x)
352 #define OS MKSTR(TARGOS)
353 printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
356 void
357 bjobcode()
359 #if defined(MACHOABI)
360 DLIST_INIT(&stublist, link);
361 DLIST_INIT(&nlplist, link);
362 #endif
366 * Called with a function call with arguments as argument.
367 * This is done early in buildtree() and only done once.
368 * Returns p.
370 NODE *
371 funcode(NODE *p)
373 extern int gotnr;
374 NODE *r, *l;
376 /* Fix function call arguments. On x86, just add funarg */
377 for (r = p->n_right; r->n_op == CM; r = r->n_left) {
378 if (r->n_right->n_op != STARG)
379 r->n_right = block(FUNARG, r->n_right, NIL,
380 r->n_right->n_type, r->n_right->n_df,
381 r->n_right->n_ap);
383 if (r->n_op != STARG) {
384 l = talloc();
385 *l = *r;
386 r->n_op = FUNARG;
387 r->n_left = l;
388 r->n_type = l->n_type;
390 if (kflag == 0)
391 return p;
392 #if defined(ELFABI)
393 /* Create an ASSIGN node for ebx */
394 l = block(REG, NIL, NIL, INT, 0, MKAP(INT));
395 l->n_rval = EBX;
396 l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, MKAP(INT)));
397 if (p->n_right->n_op != CM) {
398 p->n_right = block(CM, l, p->n_right, INT, 0, MKAP(INT));
399 } else {
400 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
402 r->n_left = block(CM, l, r->n_left, INT, 0, MKAP(INT));
404 #endif
405 return p;
409 * return the alignment of field of type t
412 fldal(unsigned int t)
414 uerror("illegal field type");
415 return(ALINT);
418 /* fix up type of field p */
419 void
420 fldty(struct symtab *p)
425 * XXX - fix genswitch.
428 mygenswitch(int num, TWORD type, struct swents **p, int n)
430 return 0;