1 /* function.c - function call protocol for bcc */
3 /* Copyright (C) 1992 Bruce Evans */
17 # define ADJUSTLONGRETURN
18 # define CANHANDLENOFRAME
19 # undef CANHANDLENOFRAME
23 FORWARD
void out_callstring
P((void));
25 /* call a named (assembly interface) procedure, don't print newline after */
27 PUBLIC
void call(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)
41 outnccname(source
->name
.namep
);
46 if (source
->indcount
== 0) /* fix call fixed address */
52 if (source
->indcount
== 1)
53 ++source
->indcount
; /* fake for outadr */
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
65 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
67 regexchange(LONGREG2
, LONGRETURNREGS
& ~LONGREG2
);
68 regexchange(LONGREG2
, DXREG
);
71 # if DYNAMIC_LONG_ORDER
74 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
75 regtransfer(DXREG
, LONGRETURNREGS
& ~LONGREG2
);
78 source
->storage
= LONGRETURNREGS
& ~LONGREG2
;
82 if (source
->type
->scalar
& CHAR
)
85 transfer(source
, DREG
);
87 source
->storage
= BREG
;
92 if (source
->type
->scalar
& DOUBLE
)
93 source
->storage
= doublreturnregs
& ~DREG
;
95 source
->storage
= RETURNREG
;
100 if (source
->type
->scalar
& DOUBLE
)
101 source
->storage
= doublreturnregs
;
103 else if (source
->type
->scalar
& FLOAT
)
104 source
->storage
= RETURNREG
|DATREG2
;
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
;
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.
138 if (arg1inreg
&& symptr
== &locsyms
[0])
140 temptarg
.storage
= ARGREG
;
141 temptarg
.offset
.offi
= 0;
145 temptarg
.storage
= LOCAL
;
146 temptarg
.indcount
= 1;
148 load(&temptarg
, targreg
);
149 symptr
->offset
.offi
= 0;
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
;
168 structarg
= constsym((value_t
) 0);
169 structarg
->type
= pointype(returntype
);
172 structarg
->flags
= 0; /* assign() doesn't like TEMP even for indir */
173 structarg
->offset
.offi
= returnadrsize
;
174 assign(exp
->left
.symptr
, structarg
);
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
186 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN
188 regexchange(LONGREG2
, DXREG
);
189 regexchange(LONGREG2
, LONGRETURNREGS
& ~LONGREG2
);
192 # if DYNAMIC_LONG_ORDER
195 # if DYNAMIC_LONG_ORDER || LONG_BIG_ENDIAN == 0
196 regtransfer(LONGRETURNREGS
& ~LONGREG2
, DXREG
);
206 if (returntype
->scalar
& DOUBLE
)
207 loadexpression(doublreturnregs
& ~DREG
, returntype
);
209 loadexpression(RETURNREG
, returntype
);
214 if (returntype
->scalar
& DOUBLE
)
215 loadexpression(doublreturnregs
, returntype
);
217 else if (returntype
->scalar
& FLOAT
)
218 loadexpression(/* REURNREG|*/ DATREG2
, returntype
);
221 loadexpression(RETURNREG
, returntype
);
226 PUBLIC
void listo(target
, lastargsp
)
227 struct symstruct
*target
;
232 if (lastargsp
!= 0 && sp
!= lastargsp
- target
->type
->typesize
)
237 if (sp
!= lastargsp
- target
->type
->typesize
)
239 bugerror("botched push of arg");
241 outstr("arg type is ");
242 dbtype(target
->type
);
249 PUBLIC
void listroot(target
)
250 struct symstruct
*target
;
253 /* necessary regs are free since they were saved for function */
254 if (target
->type
->scalar
& DLONG
)
255 load(target
, LONGARGREGS
& ~LONGREG2
);
257 load(target
, ARGREG
);
260 PRIVATE
void out_callstring()
262 outop3str(callstring
);
271 PUBLIC
void popframe()
275 if (optimise
&& !callersaves
) {
280 poplist(callee1mask
);
281 if (optimise
&& !callersaves
)
284 poplist(callee1mask
);
294 /* reserve storage for locals if necessary */
295 /* also push 1st function arg and load register args if necessary */
297 PUBLIC
void reslocals()
301 bool_t loadframe
= FALSE
;
306 if (switchnow
!= NULL
)
309 if (framep
== 0 && softsp
!= sp
)
310 bugerror("local variables in switch statement messed up, sorry");
313 bugerror("local variables in switch statement don't work, sorry");
325 regtransfer(STACKREG
, FRAMEREG
);
328 if (optimise
&& !callersaves
) {
333 pushlist(callee1mask
);
334 if (optimise
&& !callersaves
)
337 pushlist(callee1mask
);
339 # else /* not STUPIDFRAME */
340 # ifdef CANHANDLENOFRAME
341 if (stackarg
|| softsp
!= -frameregsize
) /* args or locals */
344 pushlist(frame1list
);
347 # endif /* not STUPIDFRAME */
351 pushlist(callee1mask
);
352 #endif /* FRAMEPOINTER */
355 switch ((fastin_t
) arg1size
)
358 pushlist(doubleargregs
);
365 pushlist(LONGARGREGS
);
376 pushlist(LOC1REGS
| ARGREG
);
379 pushlist(LOC2REGS
| ARGREG
);
382 pushlist(LOC3REGS
| ARGREG
);
385 pushlist(LOC4REGS
| ARGREG
);
393 arg1size
= 0; /* show 1st arg allocated */
396 # ifndef STUPIDFRAME /* else this moved above for compat with Xenix cc frame */
397 if (loadframe
|| softsp
!= -frameregsize
)
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) */
403 regtransfer(STACKREG
, FRAMEREG
);
406 # else /* STUPIDFRAME */
408 # endif /* STUPIDFRAME */
409 #else /* no FRAMEPOINTER */
411 #endif /* FRAMEPOINTER */
416 /* clean up stack and return from a function */
425 newsp
= -(offset_T
) func1saveregsize
;
426 if (switchnow
!= NULL
|| newsp
- sp
>= 0x80)
427 changesp(newsp
, TRUE
);
433 #else /* no FRAMEPOINTER */
440 reglist
= JUNK1REGS
| PCREG
;
443 reglist
= JUNK2REGS
| PCREG
;
446 reglist
= JUNK3REGS
| PCREG
;
449 reglist
= JUNK4REGS
| PCREG
;
460 modstk(-(offset_T
) func1saveregsize
);
461 poplist(callee1mask
);
464 # endif /* no MC6809 */
465 #endif /* no FRAMEPOINTER */