* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / bcc / function.c
blob8fe679f17e254f4a9b63b10ba7ef75b62c1c265a
1 /* function.c - function call protocol for bcc */
3 /* Copyright (C) 1992 Bruce Evans */
5 #include "bcc.h"
6 #include "align.h"
7 #include "byteord.h"
8 #include "gencode.h"
9 #include "parse.h"
10 #include "reg.h"
11 #include "sc.h"
12 #include "table.h"
13 #include "type.h"
14 #include "scan.h"
16 #ifdef I8088
17 # define ADJUSTLONGRETURN
18 # define CANHANDLENOFRAME
19 # undef CANHANDLENOFRAME
20 # define STUPIDFRAME
21 #endif
23 FORWARD void out_callstring P((void));
25 /* call a named (assembly interface) procedure, don't print newline after */
27 PUBLIC void call(name)
28 char *name;
30 out_callstring();
31 outstr(name);
34 PUBLIC void function(source)
35 struct symstruct *source;
37 if (source->indcount == 0 && source->storage == GLOBAL &&
38 !(source->flags & LABELLED) && *source->name.namep != 0)
40 out_callstring();
41 outnccname(source->name.namep);
43 else
45 #ifdef XENIX_AS
46 if (source->indcount == 0) /* fix call fixed address */
47 out_callstring();
48 else
49 #endif
50 outcalladr();
51 #ifdef MC6809
52 if (source->indcount == 1)
53 ++source->indcount; /* fake for outadr */
54 #endif
55 outadr(source);
57 source->type = source->type->nexttype;
58 #ifdef LONGRETSPECIAL /* LONGRETURNREGS!=RETURNREG && RETURNREG==LONGREG2 */
59 if (source->type->scalar & DLONG)
61 # ifdef ADJUSTLONGRETURN
62 # if DYNAMIC_LONG_ORDER
63 if (long_big_endian)
64 # endif
65 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
67 regexchange(LONGREG2, LONGRETURNREGS & ~LONGREG2);
68 regexchange(LONGREG2, DXREG);
70 # endif
71 # if DYNAMIC_LONG_ORDER
72 else
73 # endif
74 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
75 regtransfer(DXREG, LONGRETURNREGS & ~LONGREG2);
76 # endif
77 # endif
78 source->storage = LONGRETURNREGS & ~LONGREG2;
80 else
81 #endif
82 if (source->type->scalar & CHAR)
84 #if RETURNREG != DREG
85 transfer(source, DREG);
86 #endif
87 source->storage = BREG;
89 #ifdef I80386
90 else if (i386_32)
92 if (source->type->scalar & DOUBLE)
93 source->storage = doublreturnregs & ~DREG;
94 else
95 source->storage = RETURNREG;
97 else
98 #endif
100 if (source->type->scalar & DOUBLE)
101 source->storage = doublreturnregs;
102 #ifdef I8088
103 else if (source->type->scalar & FLOAT)
104 source->storage = RETURNREG|DATREG2;
105 #endif
106 else
107 source->storage = RETURNREG;
109 source->offset.offi = source->indcount = 0;
110 if (source->level == OFFKLUDGELEVEL)
111 source->level = EXPRLEVEL;
112 if (source->type->constructor & STRUCTU)
114 transfer(source, getindexreg()); /* so it can be indirected
115 * and/or preserved in blockmove() */
116 source->indcount = 1;
117 source->flags = TEMP; /* kludge so blockpush can be avoided */
121 PUBLIC void ldregargs()
123 register struct symstruct *symptr;
124 store_pt targreg;
125 struct symstruct temptarg;
127 for (symptr = &locsyms[0]; symptr < locptr && symptr->level == ARGLEVEL;
128 symptr = (struct symstruct *)
129 align(&symptr->name.namea[strlen(symptr->name.namea) + 1]))
131 if ((store_t) (targreg = symptr->storage) & allregs)
134 /* load() is designed to work on expression symbols, so don't
135 * trust it on reg variables although it almost works.
137 temptarg = *symptr;
138 if (arg1inreg && symptr == &locsyms[0])
140 temptarg.storage = ARGREG;
141 temptarg.offset.offi = 0;
143 else
145 temptarg.storage = LOCAL;
146 temptarg.indcount = 1;
148 load(&temptarg, targreg);
149 symptr->offset.offi = 0;
152 regarg = FALSE;
155 PUBLIC void loadretexpression()
157 if (returntype->constructor & STRUCTU)
159 struct nodestruct *etmark;
160 struct nodestruct *exp;
161 struct symstruct *exprmark;
162 struct symstruct *structarg;
164 etmark = etptr;
165 exprmark = exprptr;
166 exp = expression();
167 makeleaf(exp);
168 structarg = constsym((value_t) 0);
169 structarg->type = pointype(returntype);
170 onstack(structarg);
171 indirec(structarg);
172 structarg->flags = 0; /* assign() doesn't like TEMP even for indir */
173 structarg->offset.offi = returnadrsize;
174 assign(exp->left.symptr, structarg);
175 etptr = etmark;
176 exprptr = exprmark;
178 #ifdef LONGRETSPECIAL /* LONGRETURNREGS!=RETURNREG && RETURNREG==LONGREG2 */
179 else if (returntype->scalar & DLONG)
181 loadexpression(LONGRETURNREGS & ~LONGREG2, returntype);
182 # ifdef ADJUSTLONGRETURN
183 # if DYNAMIC_LONG_ORDER
184 if (long_big_endian)
185 # endif
186 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
188 regexchange(LONGREG2, DXREG);
189 regexchange(LONGREG2, LONGRETURNREGS & ~LONGREG2);
191 # endif
192 # if DYNAMIC_LONG_ORDER
193 else
194 # endif
195 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
196 regtransfer(LONGRETURNREGS & ~LONGREG2, DXREG);
197 # endif
198 # endif
200 else
201 #endif
203 #ifdef I80386
204 if (i386_32)
206 if (returntype->scalar & DOUBLE)
207 loadexpression(doublreturnregs & ~DREG, returntype);
208 else
209 loadexpression(RETURNREG, returntype);
211 else
212 #endif
214 if (returntype->scalar & DOUBLE)
215 loadexpression(doublreturnregs, returntype);
216 #ifdef I8088
217 else if (returntype->scalar & FLOAT)
218 loadexpression(/* REURNREG|*/ DATREG2, returntype);
219 #endif
220 else
221 loadexpression(RETURNREG, returntype);
226 PUBLIC void listo(target, lastargsp)
227 struct symstruct *target;
228 offset_T lastargsp;
230 extend(target);
231 push(target);
232 if (lastargsp != 0 && sp != lastargsp - target->type->typesize)
234 loadany(target);
235 modstk(lastargsp);
236 push(target);
237 if (sp != lastargsp - target->type->typesize)
239 bugerror("botched push of arg");
240 #ifdef DBNODE
241 outstr("arg type is ");
242 dbtype(target->type);
243 outnl();
244 #endif
249 PUBLIC void listroot(target)
250 struct symstruct *target;
252 extend(target);
253 /* necessary regs are free since they were saved for function */
254 if (target->type->scalar & DLONG)
255 load(target, LONGARGREGS & ~LONGREG2);
256 else
257 load(target, ARGREG);
260 PRIVATE void out_callstring()
262 outop3str(callstring);
263 #ifdef I80386
264 if (i386_32)
265 bumplc2();
266 #endif
269 #ifdef FRAMEPOINTER
271 PUBLIC void popframe()
273 #ifdef STUPIDFRAME
274 #ifndef NO_DEL_PUSH
275 if (optimise && !callersaves) {
276 outstr("if ");
277 outstr(funcname);
278 outnstr(".off=0");
280 poplist(callee1mask);
281 if (optimise && !callersaves)
282 outnstr("endif");
283 #else
284 poplist(callee1mask);
285 #endif
286 poplist(FRAMEREG);
287 #else
288 poplist(frame1list);
289 #endif
292 #endif
294 /* reserve storage for locals if necessary */
295 /* also push 1st function arg and load register args if necessary */
297 PUBLIC void reslocals()
299 #ifdef FRAMEPOINTER
300 # ifndef STUPIDFRAME
301 bool_t loadframe = FALSE;
303 # endif
304 #endif
306 if (switchnow != NULL)
308 #ifdef FRAMEPOINTER
309 if (framep == 0 && softsp != sp)
310 bugerror("local variables in switch statement messed up, sorry");
311 #else
312 if (sp != softsp)
313 bugerror("local variables in switch statement don't work, sorry");
314 #endif
315 if (lowsp > softsp)
316 lowsp = softsp;
317 sp = softsp;
318 return;
320 #ifdef FRAMEPOINTER
321 if (framep == 0)
323 # ifdef STUPIDFRAME
324 pushreg(FRAMEREG);
325 regtransfer(STACKREG, FRAMEREG);
326 framep = sp;
327 #ifndef NO_DEL_PUSH
328 if (optimise && !callersaves) {
329 outstr("if ");
330 outstr(funcname);
331 outnstr(".off=0");
333 pushlist(callee1mask);
334 if (optimise && !callersaves)
335 outnstr("endif");
336 #else
337 pushlist(callee1mask);
338 #endif
339 # else /* not STUPIDFRAME */
340 # ifdef CANHANDLENOFRAME
341 if (stackarg || softsp != -frameregsize) /* args or locals */
342 # endif
344 pushlist(frame1list);
345 loadframe = TRUE;
347 # endif /* not STUPIDFRAME */
349 #else
350 if (sp == 0)
351 pushlist(callee1mask);
352 #endif /* FRAMEPOINTER */
353 if (arg1size)
355 switch ((fastin_t) arg1size)
357 case 8:
358 pushlist(doubleargregs);
359 break;
360 case 4:
361 # ifdef I80386
362 if (!i386_32)
363 # endif
365 pushlist(LONGARGREGS);
366 break;
368 case 2:
369 # ifdef I8088
370 pushlist(ARGREG);
371 # endif
372 # ifdef MC6809
373 switch (sp - softsp)
375 case 3:
376 pushlist(LOC1REGS | ARGREG);
377 break;
378 case 4:
379 pushlist(LOC2REGS | ARGREG);
380 break;
381 case 5:
382 pushlist(LOC3REGS | ARGREG);
383 break;
384 case 6:
385 pushlist(LOC4REGS | ARGREG);
386 break;
387 default:
388 pushlist(ARGREG);
389 break;
391 # endif /* MC6809 */
393 arg1size = 0; /* show 1st arg allocated */
395 #ifdef FRAMEPOINTER
396 # ifndef STUPIDFRAME /* else this moved above for compat with Xenix cc frame */
397 if (loadframe || softsp != -frameregsize)
398 modstk(softsp);
399 /* else avoid modstk() because softsp holds space for frame pointer only) */
400 /* but pointer has not been pushed (must keep softsp for later levels) */
401 if (loadframe)
403 regtransfer(STACKREG, FRAMEREG);
404 framep = sp;
406 # else /* STUPIDFRAME */
407 modstk(softsp);
408 # endif /* STUPIDFRAME */
409 #else /* no FRAMEPOINTER */
410 modstk(softsp);
411 #endif /* FRAMEPOINTER */
412 if (regarg)
413 ldregargs();
416 /* clean up stack and return from a function */
418 PUBLIC void ret()
420 #ifdef FRAMEPOINTER
421 offset_T newsp;
423 if (framep != 0)
425 newsp = -(offset_T) func1saveregsize;
426 if (switchnow != NULL || newsp - sp >= 0x80)
427 changesp(newsp, TRUE);
428 else
429 modstk(newsp);
430 popframe();
432 outreturn();
433 #else /* no FRAMEPOINTER */
434 # ifdef MC6809
435 store_pt reglist;
437 switch (sp)
439 case -1:
440 reglist = JUNK1REGS | PCREG;
441 break;
442 case -2:
443 reglist = JUNK2REGS | PCREG;
444 break;
445 case -3:
446 reglist = JUNK3REGS | PCREG;
447 break;
448 case -4:
449 reglist = JUNK4REGS | PCREG;
450 break;
451 default:
452 modstk(0);
453 outreturn();
454 return;
456 poplist(reglist);
457 #else
458 if (sp != 0)
460 modstk(-(offset_T) func1saveregsize);
461 poplist(callee1mask);
463 outreturn();
464 # endif /* no MC6809 */
465 #endif /* no FRAMEPOINTER */