1 /* function.c - function call protocol for bcc */
2 
3 /* Copyright (C) 1992 Bruce Evans */
4 
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"
15 
16 #ifdef I8088
17 # define ADJUSTLONGRETURN
18 # define CANHANDLENOFRAME
19 # undef CANHANDLENOFRAME
20 # define STUPIDFRAME
21 #endif
22 
23 FORWARD void out_callstring P((void));
24 
25 /* call a named (assembly interface) procedure, don't print newline after */
26 
call(name)27 PUBLIC void call(name)
28 char *name;
29 {
30     out_callstring();
31     outstr(name);
32 }
33 
function(source)34 PUBLIC void function(source)
35 struct symstruct *source;
36 {
37     if (source->indcount == 0 && source->storage == GLOBAL &&
38 	!(source->flags & LABELLED) && *source->name.namep != 0)
39     {
40 	out_callstring();
41 	outnccname(source->name.namep);
42     }
43     else
44     {
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);
56     }
57     source->type = source->type->nexttype;
58 #ifdef LONGRETSPECIAL /* LONGRETURNREGS!=RETURNREG && RETURNREG==LONGREG2 */
59     if (source->type->scalar & DLONG)
60     {
61 # ifdef ADJUSTLONGRETURN
62 #  if DYNAMIC_LONG_ORDER
63 	if (long_big_endian)
64 #  endif
65 #  if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
66 	{
67 	    regexchange(LONGREG2, LONGRETURNREGS & ~LONGREG2);
68 	    regexchange(LONGREG2, DXREG);
69 	}
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;
79     }
80     else
81 #endif
82     if (source->type->scalar & CHAR)
83     {
84 #if RETURNREG != DREG
85 	transfer(source, DREG);
86 #endif
87 	source->storage = BREG;
88     }
89 #ifdef I80386
90     else if (i386_32)
91     {
92         if (source->type->scalar & DOUBLE)
93 	    source->storage = doublreturnregs & ~DREG;
94         else
95 	    source->storage = RETURNREG;
96     }
97     else
98 #endif
99     {
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;
108     }
109     source->offset.offi = source->indcount = 0;
110     if (source->level == OFFKLUDGELEVEL)
111 	source->level = EXPRLEVEL;
112     if (source->type->constructor & STRUCTU)
113     {
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 */
118     }
119 }
120 
ldregargs()121 PUBLIC void ldregargs()
122 {
123     register struct symstruct *symptr;
124     store_pt targreg;
125     struct symstruct temptarg;
126 
127     for (symptr = &locsyms[0]; symptr < locptr && symptr->level == ARGLEVEL;
128 	 symptr = (struct symstruct *)
129 		  align(&symptr->name.namea[strlen(symptr->name.namea) + 1]))
130     {
131 	if ((store_t) (targreg = symptr->storage) & allregs)
132 	{
133 
134 	    /* load() is designed to work on expression symbols, so don't
135 	     * trust it on reg variables although it almost works.
136 	     */
137 	    temptarg = *symptr;
138 	    if (arg1inreg && symptr == &locsyms[0])
139 	    {
140 		temptarg.storage = ARGREG;
141 		temptarg.offset.offi = 0;
142 	    }
143 	    else
144 	    {
145 		temptarg.storage = LOCAL;
146 		temptarg.indcount = 1;
147 	    }
148 	    load(&temptarg, targreg);
149 	    symptr->offset.offi = 0;
150 	}
151     }
152     regarg = FALSE;
153 }
154 
loadretexpression()155 PUBLIC void loadretexpression()
156 {
157     if (returntype->constructor & STRUCTU)
158     {
159 	struct nodestruct *etmark;
160 	struct nodestruct *exp;
161 	struct symstruct *exprmark;
162 	struct symstruct *structarg;
163 
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;
177     }
178 #ifdef LONGRETSPECIAL /* LONGRETURNREGS!=RETURNREG && RETURNREG==LONGREG2 */
179     else if (returntype->scalar & DLONG)
180     {
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
187 	{
188 	    regexchange(LONGREG2, DXREG);
189 	    regexchange(LONGREG2, LONGRETURNREGS & ~LONGREG2);
190 	}
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
199     }
200     else
201 #endif
202     {
203 #ifdef I80386
204         if (i386_32)
205         {
206             if (returntype->scalar & DOUBLE)
207 	        loadexpression(doublreturnregs & ~DREG, returntype);
208             else
209 	        loadexpression(RETURNREG, returntype);
210         }
211         else
212 #endif
213 	{
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);
222         }
223     }
224 }
225 
listo(target,lastargsp)226 PUBLIC void listo(target, lastargsp)
227 struct symstruct *target;
228 offset_T lastargsp;
229 {
230     extend(target);
231     push(target);
232     if (lastargsp != 0 && sp != lastargsp - target->type->typesize)
233     {
234 	loadany(target);
235 	modstk(lastargsp);
236 	push(target);
237 	if (sp != lastargsp - target->type->typesize)
238 	{
239 	    bugerror("botched push of arg");
240 #ifdef DBNODE
241 	    outstr("arg type is ");
242 	    dbtype(target->type);
243 	    outnl();
244 #endif
245 	}
246     }
247 }
248 
listroot(target)249 PUBLIC void listroot(target)
250 struct symstruct *target;
251 {
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);
258 }
259 
out_callstring()260 PRIVATE void out_callstring()
261 {
262     outop3str(callstring);
263 #ifdef I80386
264     if (i386_32)
265 	bumplc2();
266 #endif
267 }
268 
269 #ifdef FRAMEPOINTER
270 
popframe()271 PUBLIC void popframe()
272 {
273 #ifdef STUPIDFRAME
274 #ifndef NO_DEL_PUSH
275     if (optimise && !callersaves) {
276         outstr("if ");
277         outstr(funcname);
278         outnstr(".off=0");
279     }
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
290 }
291 
292 #endif
293 
294 /* reserve storage for locals if necessary */
295 /* also push 1st function arg and load register args if necessary */
296 
reslocals()297 PUBLIC void reslocals()
298 {
299 #ifdef FRAMEPOINTER
300 # ifndef STUPIDFRAME
301     bool_t loadframe = FALSE;
302 
303 # endif
304 #endif
305 
306     if (switchnow != NULL)
307     {
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;
319     }
320 #ifdef FRAMEPOINTER
321     if (framep == 0)
322     {
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");
332 	}
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
343 	{
344 	    pushlist(frame1list);
345 	    loadframe = TRUE;
346 	}
347 # endif /* not STUPIDFRAME */
348     }
349 #else
350     if (sp == 0)
351 	pushlist(callee1mask);
352 #endif /* FRAMEPOINTER */
353     if (arg1size)
354     {
355 	switch ((fastin_t) arg1size)
356 	{
357 	case 8:
358 	    pushlist(doubleargregs);
359 	    break;
360 	case 4:
361 # ifdef I80386
362 	    if (!i386_32)
363 # endif
364 	    {
365 		pushlist(LONGARGREGS);
366 		break;
367 	    }
368 	case 2:
369 # ifdef I8088
370 	    pushlist(ARGREG);
371 # endif
372 # ifdef MC6809
373 	    switch (sp - softsp)
374 	    {
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;
390 	    }
391 # endif /* MC6809 */
392 	}
393 	arg1size = 0;		/* show 1st arg allocated */
394     }
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)
402     {
403 	regtransfer(STACKREG, FRAMEREG);
404 	framep = sp;
405     }
406 # else /* STUPIDFRAME */
407     modstk(softsp);
408 # endif /* STUPIDFRAME */
409 #else /* no FRAMEPOINTER */
410     modstk(softsp);
411 #endif /* FRAMEPOINTER */
412     if (regarg)
413 	ldregargs();
414 }
415 
416 /* clean up stack and return from a function */
417 
ret()418 PUBLIC void ret()
419 {
420 #ifdef FRAMEPOINTER
421     offset_T newsp;
422 
423     if (framep != 0)
424     {
425 	newsp = -(offset_T) func1saveregsize;
426 	if (switchnow != NULL || newsp - sp >= 0x80)
427 	    changesp(newsp, TRUE);
428 	else
429 	    modstk(newsp);
430 	popframe();
431     }
432     outreturn();
433 #else /* no FRAMEPOINTER */
434 # ifdef MC6809
435     store_pt reglist;
436 
437     switch (sp)
438     {
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;
455     }
456     poplist(reglist);
457 #else
458     if (sp != 0)
459     {
460 	modstk(-(offset_T) func1saveregsize);
461 	poplist(callee1mask);
462     }
463     outreturn();
464 # endif /* no MC6809 */
465 #endif /* no FRAMEPOINTER */
466 }
467