1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* function.c */ |
4 | /* */ |
5 | /* Parse function entry/body/exit */ |
6 | /* */ |
7 | /* */ |
8 | /* */ |
9 | /* (C) 2000-2015, Ullrich von Bassewitz */ |
10 | /* Roemerstrasse 52 */ |
11 | /* D-70794 Filderstadt */ |
12 | /* EMail: uz@cc65.org */ |
13 | /* */ |
14 | /* */ |
15 | /* This software is provided 'as-is', without any expressed or implied */ |
16 | /* warranty. In no event will the authors be held liable for any damages */ |
17 | /* arising from the use of this software. */ |
18 | /* */ |
19 | /* Permission is granted to anyone to use this software for any purpose, */ |
20 | /* including commercial applications, and to alter it and redistribute it */ |
21 | /* freely, subject to the following restrictions: */ |
22 | /* */ |
23 | /* 1. The origin of this software must not be misrepresented; you must not */ |
24 | /* claim that you wrote the original software. If you use this software */ |
25 | /* in a product, an acknowledgment in the product documentation would be */ |
26 | /* appreciated but is not required. */ |
27 | /* 2. Altered source versions must be plainly marked as such, and must not */ |
28 | /* be misrepresented as being the original software. */ |
29 | /* 3. This notice may not be removed or altered from any source */ |
30 | /* distribution. */ |
31 | /* */ |
32 | /*****************************************************************************/ |
33 | |
34 | |
35 | |
36 | /* common */ |
37 | #include "check.h" |
38 | #include "xmalloc.h" |
39 | |
40 | /* cc65 */ |
41 | #include "asmcode.h" |
42 | #include "asmlabel.h" |
43 | #include "codegen.h" |
44 | #include "error.h" |
45 | #include "funcdesc.h" |
46 | #include "global.h" |
47 | #include "litpool.h" |
48 | #include "locals.h" |
49 | #include "scanner.h" |
50 | #include "stackptr.h" |
51 | #include "standard.h" |
52 | #include "stmt.h" |
53 | #include "symtab.h" |
54 | #include "function.h" |
55 | |
56 | |
57 | |
58 | /*****************************************************************************/ |
59 | /* Data */ |
60 | /*****************************************************************************/ |
61 | |
62 | |
63 | |
64 | /* Pointer to current function */ |
65 | Function* CurrentFunc = 0; |
66 | |
67 | |
68 | |
69 | /*****************************************************************************/ |
70 | /* Subroutines working with struct Function */ |
71 | /*****************************************************************************/ |
72 | |
73 | |
74 | |
75 | static Function* NewFunction (struct SymEntry* Sym) |
76 | /* Create a new function activation structure and return it */ |
77 | { |
78 | /* Allocate a new structure */ |
79 | Function* F = (Function*) xmalloc (sizeof (Function)); |
80 | |
81 | /* Initialize the fields */ |
82 | F->FuncEntry = Sym; |
83 | F->ReturnType = GetFuncReturn (Sym->Type); |
84 | F->Desc = GetFuncDesc (Sym->Type); |
85 | F->Reserved = 0; |
86 | F->RetLab = GetLocalLabel (); |
87 | F->TopLevelSP = 0; |
88 | F->RegOffs = RegisterSpace; |
89 | F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE; |
90 | |
91 | InitCollection (&F->LocalsBlockStack); |
92 | |
93 | /* Return the new structure */ |
94 | return F; |
95 | } |
96 | |
97 | |
98 | |
99 | static void FreeFunction (Function* F) |
100 | /* Free a function activation structure */ |
101 | { |
102 | DoneCollection (&F->LocalsBlockStack); |
103 | xfree (F); |
104 | } |
105 | |
106 | |
107 | |
108 | const char* F_GetFuncName (const Function* F) |
109 | /* Return the name of the current function */ |
110 | { |
111 | return F->FuncEntry->Name; |
112 | } |
113 | |
114 | |
115 | |
116 | unsigned F_GetParamCount (const Function* F) |
117 | /* Return the parameter count for the current function */ |
118 | { |
119 | return F->Desc->ParamCount; |
120 | } |
121 | |
122 | |
123 | |
124 | unsigned F_GetParamSize (const Function* F) |
125 | /* Return the parameter size for the current function */ |
126 | { |
127 | return F->Desc->ParamSize; |
128 | } |
129 | |
130 | |
131 | |
132 | Type* F_GetReturnType (Function* F) |
133 | /* Get the return type for the function */ |
134 | { |
135 | return F->ReturnType; |
136 | } |
137 | |
138 | |
139 | |
140 | int F_HasVoidReturn (const Function* F) |
141 | /* Return true if the function does not have a return value */ |
142 | { |
143 | return (F->Flags & FF_VOID_RETURN) != 0; |
144 | } |
145 | |
146 | |
147 | |
148 | void F_ReturnFound (Function* F) |
149 | /* Mark the function as having a return statement */ |
150 | { |
151 | F->Flags |= FF_HAS_RETURN; |
152 | } |
153 | |
154 | |
155 | |
156 | int F_HasReturn (const Function* F) |
157 | /* Return true if the function contains a return statement*/ |
158 | { |
159 | return (F->Flags & FF_HAS_RETURN) != 0; |
160 | } |
161 | |
162 | |
163 | |
164 | int F_IsMainFunc (const Function* F) |
165 | /* Return true if this is the main function */ |
166 | { |
167 | return (F->Flags & FF_IS_MAIN) != 0; |
168 | } |
169 | |
170 | |
171 | |
172 | int F_IsVariadic (const Function* F) |
173 | /* Return true if this is a variadic function */ |
174 | { |
175 | return (F->Desc->Flags & FD_VARIADIC) != 0; |
176 | } |
177 | |
178 | |
179 | |
180 | int F_IsOldStyle (const Function* F) |
181 | /* Return true if this is an old style (K&R) function */ |
182 | { |
183 | return (F->Desc->Flags & FD_OLDSTYLE) != 0; |
184 | } |
185 | |
186 | |
187 | |
188 | int F_HasOldStyleIntRet (const Function* F) |
189 | /* Return true if this is an old style (K&R) function with an implicit int return */ |
190 | { |
191 | return (F->Desc->Flags & FD_OLDSTYLE_INTRET) != 0; |
192 | } |
193 | |
194 | |
195 | |
196 | unsigned F_GetRetLab (const Function* F) |
197 | /* Return the return jump label */ |
198 | { |
199 | return F->RetLab; |
200 | } |
201 | |
202 | |
203 | |
204 | int F_GetTopLevelSP (const Function* F) |
205 | /* Get the value of the stack pointer on function top level */ |
206 | { |
207 | return F->TopLevelSP; |
208 | } |
209 | |
210 | |
211 | |
212 | int F_ReserveLocalSpace (Function* F, unsigned Size) |
213 | /* Reserve (but don't allocate) the given local space and return the stack |
214 | ** offset. |
215 | */ |
216 | { |
217 | F->Reserved += Size; |
218 | return StackPtr - F->Reserved; |
219 | } |
220 | |
221 | |
222 | |
223 | int F_GetStackPtr (const Function* F) |
224 | /* Return the current stack pointer including reserved (but not allocated) |
225 | ** space on the stack. |
226 | */ |
227 | { |
228 | return StackPtr - F->Reserved; |
229 | } |
230 | |
231 | |
232 | |
233 | void F_AllocLocalSpace (Function* F) |
234 | /* Allocate any local space previously reserved. The function will do |
235 | ** nothing if there is no reserved local space. |
236 | */ |
237 | { |
238 | if (F->Reserved > 0) { |
239 | |
240 | /* Create space on the stack */ |
241 | g_space (F->Reserved); |
242 | |
243 | /* Correct the stack pointer */ |
244 | StackPtr -= F->Reserved; |
245 | |
246 | /* Nothing more reserved */ |
247 | F->Reserved = 0; |
248 | } |
249 | } |
250 | |
251 | |
252 | |
253 | int F_AllocRegVar (Function* F, const Type* Type) |
254 | /* Allocate a register variable for the given variable type. If the allocation |
255 | ** was successful, return the offset of the register variable in the register |
256 | ** bank (zero page storage). If there is no register space left, return -1. |
257 | */ |
258 | { |
259 | /* Allow register variables only on top level and if enabled */ |
260 | if (IS_Get (&EnableRegVars) && GetLexicalLevel () == LEX_LEVEL_FUNCTION) { |
261 | |
262 | /* Get the size of the variable */ |
263 | unsigned Size = CheckedSizeOf (Type); |
264 | |
265 | /* Do we have space left? */ |
266 | if (F->RegOffs >= Size) { |
267 | /* Space left. We allocate the variables from high to low addresses, |
268 | ** so the addressing is compatible with the saved values on stack. |
269 | ** This allows shorter code when saving/restoring the variables. |
270 | */ |
271 | F->RegOffs -= Size; |
272 | return F->RegOffs; |
273 | } |
274 | } |
275 | |
276 | /* No space left or no allocation */ |
277 | return -1; |
278 | } |
279 | |
280 | |
281 | |
282 | static void F_RestoreRegVars (Function* F) |
283 | /* Restore the register variables for the local function if there are any. */ |
284 | { |
285 | const SymEntry* Sym; |
286 | |
287 | /* If we don't have register variables in this function, bail out early */ |
288 | if (F->RegOffs == RegisterSpace) { |
289 | return; |
290 | } |
291 | |
292 | /* Save the accumulator if needed */ |
293 | if (!F_HasVoidReturn (F)) { |
294 | g_save (CF_CHAR | CF_FORCECHAR); |
295 | } |
296 | |
297 | /* Get the first symbol from the function symbol table */ |
298 | Sym = F->FuncEntry->V.F.Func->SymTab->SymHead; |
299 | |
300 | /* Walk through all symbols checking for register variables */ |
301 | while (Sym) { |
302 | if (SymIsRegVar (Sym)) { |
303 | |
304 | /* Check for more than one variable */ |
305 | int Offs = Sym->V.R.SaveOffs; |
306 | unsigned Bytes = CheckedSizeOf (Sym->Type); |
307 | |
308 | while (1) { |
309 | |
310 | /* Find next register variable */ |
311 | const SymEntry* NextSym = Sym->NextSym; |
312 | while (NextSym && !SymIsRegVar (NextSym)) { |
313 | NextSym = NextSym->NextSym; |
314 | } |
315 | |
316 | /* If we have a next one, compare the stack offsets */ |
317 | if (NextSym) { |
318 | |
319 | /* We have a following register variable. Get the size */ |
320 | int Size = CheckedSizeOf (NextSym->Type); |
321 | |
322 | /* Adjacent variable? */ |
323 | if (NextSym->V.R.SaveOffs + Size != Offs) { |
324 | /* No */ |
325 | break; |
326 | } |
327 | |
328 | /* Adjacent variable */ |
329 | Bytes += Size; |
330 | Offs -= Size; |
331 | Sym = NextSym; |
332 | |
333 | } else { |
334 | break; |
335 | } |
336 | } |
337 | |
338 | /* Restore the memory range */ |
339 | g_restore_regvars (Offs, Sym->V.R.RegOffs, Bytes); |
340 | |
341 | } |
342 | |
343 | /* Check next symbol */ |
344 | Sym = Sym->NextSym; |
345 | } |
346 | |
347 | /* Restore the accumulator if needed */ |
348 | if (!F_HasVoidReturn (F)) { |
349 | g_restore (CF_CHAR | CF_FORCECHAR); |
350 | } |
351 | } |
352 | |
353 | |
354 | |
355 | static void F_EmitDebugInfo (void) |
356 | /* Emit debug infos for the current function */ |
357 | { |
358 | if (DebugInfo) { |
359 | /* Get the current function */ |
360 | const SymEntry* Sym = CurrentFunc->FuncEntry; |
361 | |
362 | /* Output info for the function itself */ |
363 | AddTextLine ("\t.dbg\tfunc, \"%s\", \"00\", %s, \"%s\"" , |
364 | Sym->Name, |
365 | (Sym->Flags & SC_EXTERN)? "extern" : "static" , |
366 | Sym->AsmName); |
367 | } |
368 | } |
369 | |
370 | |
371 | |
372 | /*****************************************************************************/ |
373 | /* code */ |
374 | /*****************************************************************************/ |
375 | |
376 | |
377 | |
378 | void NewFunc (SymEntry* Func) |
379 | /* Parse argument declarations and function body. */ |
380 | { |
381 | int C99MainFunc = 0;/* Flag for C99 main function returning int */ |
382 | SymEntry* Param; |
383 | |
384 | /* Get the function descriptor from the function entry */ |
385 | FuncDesc* D = Func->V.F.Func; |
386 | |
387 | /* Allocate the function activation record for the function */ |
388 | CurrentFunc = NewFunction (Func); |
389 | |
390 | /* Reenter the lexical level */ |
391 | ReenterFunctionLevel (D); |
392 | |
393 | /* Check if the function header contains unnamed parameters. These are |
394 | ** only allowed in cc65 mode. |
395 | */ |
396 | if ((D->Flags & FD_UNNAMED_PARAMS) != 0 && (IS_Get (&Standard) != STD_CC65)) { |
397 | Error ("Parameter name omitted" ); |
398 | } |
399 | |
400 | /* Declare two special functions symbols: __fixargs__ and __argsize__. |
401 | ** The latter is different depending on the type of the function (variadic |
402 | ** or not). |
403 | */ |
404 | AddConstSym ("__fixargs__" , type_uint, SC_DEF | SC_CONST, D->ParamSize); |
405 | if (D->Flags & FD_VARIADIC) { |
406 | /* Variadic function. The variable must be const. */ |
407 | static const Type T[] = { TYPE(T_UCHAR | T_QUAL_CONST), TYPE(T_END) }; |
408 | AddLocalSym ("__argsize__" , T, SC_DEF | SC_REF | SC_AUTO, 0); |
409 | } else { |
410 | /* Non variadic */ |
411 | AddConstSym ("__argsize__" , type_uchar, SC_DEF | SC_CONST, D->ParamSize); |
412 | } |
413 | |
414 | /* Function body now defined */ |
415 | Func->Flags |= SC_DEF; |
416 | |
417 | /* Special handling for main() */ |
418 | if (strcmp (Func->Name, "main" ) == 0) { |
419 | |
420 | /* Mark this as the main function */ |
421 | CurrentFunc->Flags |= FF_IS_MAIN; |
422 | |
423 | /* Main cannot be a fastcall function */ |
424 | if (IsQualFastcall (Func->Type)) { |
425 | Error ("'main' cannot be declared as __fastcall__" ); |
426 | } |
427 | |
428 | /* If cc65 extensions aren't enabled, don't allow a main function that |
429 | ** doesn't return an int. |
430 | */ |
431 | if (IS_Get (&Standard) != STD_CC65 && CurrentFunc->ReturnType[0].C != T_INT) { |
432 | Error ("'main' must always return an int" ); |
433 | } |
434 | |
435 | /* Add a forced import of a symbol that is contained in the startup |
436 | ** code. This will force the startup code to be linked in. |
437 | */ |
438 | g_importstartup (); |
439 | |
440 | /* If main() takes parameters, generate a forced import to a function |
441 | ** that will setup these parameters. This way, programs that do not |
442 | ** need the additional code will not get it. |
443 | */ |
444 | if (D->ParamCount > 0 || (D->Flags & FD_VARIADIC) != 0) { |
445 | g_importmainargs (); |
446 | |
447 | /* The start-up code doesn't fast-call main(). */ |
448 | Func->Type->C |= T_QUAL_CDECL; |
449 | } |
450 | |
451 | /* Determine if this is a main function in a C99 environment that |
452 | ** returns an int. |
453 | */ |
454 | if (IsTypeInt (F_GetReturnType (CurrentFunc)) && |
455 | IS_Get (&Standard) == STD_C99) { |
456 | C99MainFunc = 1; |
457 | } |
458 | } |
459 | |
460 | /* Allocate code and data segments for this function */ |
461 | Func->V.F.Seg = PushSegments (Func); |
462 | |
463 | /* Allocate a new literal pool */ |
464 | PushLiteralPool (Func); |
465 | |
466 | /* If this is a fastcall function, push the last parameter onto the stack */ |
467 | if ((D->Flags & FD_VARIADIC) == 0 && D->ParamCount > 0 && |
468 | (AutoCDecl ? |
469 | IsQualFastcall (Func->Type) : |
470 | !IsQualCDecl (Func->Type))) { |
471 | unsigned Flags; |
472 | |
473 | /* Generate the push */ |
474 | if (IsTypeFunc (D->LastParam->Type)) { |
475 | /* Pointer to function */ |
476 | Flags = CF_PTR; |
477 | } else { |
478 | Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR; |
479 | } |
480 | g_push (Flags, 0); |
481 | } |
482 | |
483 | /* Generate function entry code if needed */ |
484 | g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc)); |
485 | |
486 | /* If stack checking code is requested, emit a call to the helper routine */ |
487 | if (IS_Get (&CheckStack)) { |
488 | g_stackcheck (); |
489 | } |
490 | |
491 | /* Setup the stack */ |
492 | StackPtr = 0; |
493 | |
494 | /* Walk through the parameter list and allocate register variable space |
495 | ** for parameters declared as register. Generate code to swap the contents |
496 | ** of the register bank with the save area on the stack. |
497 | */ |
498 | Param = D->SymTab->SymHead; |
499 | while (Param && (Param->Flags & SC_PARAM) != 0) { |
500 | |
501 | /* Check for a register variable */ |
502 | if (SymIsRegVar (Param)) { |
503 | |
504 | /* Allocate space */ |
505 | int Reg = F_AllocRegVar (CurrentFunc, Param->Type); |
506 | |
507 | /* Could we allocate a register? */ |
508 | if (Reg < 0) { |
509 | /* No register available: Convert parameter to auto */ |
510 | CvtRegVarToAuto (Param); |
511 | } else { |
512 | /* Remember the register offset */ |
513 | Param->V.R.RegOffs = Reg; |
514 | |
515 | /* Generate swap code */ |
516 | g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (Param->Type)); |
517 | } |
518 | } |
519 | |
520 | /* Next parameter */ |
521 | Param = Param->NextSym; |
522 | } |
523 | |
524 | /* Need a starting curly brace */ |
525 | ConsumeLCurly (); |
526 | |
527 | /* Make sure there is always something on the stack of local variable blocks */ |
528 | CollAppend (&CurrentFunc->LocalsBlockStack, 0); |
529 | |
530 | /* Parse local variable declarations if any */ |
531 | DeclareLocals (); |
532 | |
533 | /* Remember the current stack pointer. All variables allocated elsewhere |
534 | ** must be dropped when doing a return from an inner block. |
535 | */ |
536 | CurrentFunc->TopLevelSP = StackPtr; |
537 | |
538 | /* Now process statements in this block */ |
539 | while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) { |
540 | Statement (0); |
541 | } |
542 | |
543 | /* If this is not a void function, and not the main function in a C99 |
544 | ** environment returning int, output a warning if we didn't see a return |
545 | ** statement. |
546 | */ |
547 | if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc) { |
548 | Warning ("Control reaches end of non-void function" ); |
549 | } |
550 | |
551 | /* If this is the main function in a C99 environment returning an int, let |
552 | ** it always return zero. Note: Actual return statements jump to the return |
553 | ** label defined below. |
554 | ** The code is removed by the optimizer if unused. |
555 | */ |
556 | if (C99MainFunc) { |
557 | g_getimmed (CF_INT | CF_CONST, 0, 0); |
558 | } |
559 | |
560 | /* Output the function exit code label */ |
561 | g_defcodelabel (F_GetRetLab (CurrentFunc)); |
562 | |
563 | /* Restore the register variables */ |
564 | F_RestoreRegVars (CurrentFunc); |
565 | |
566 | /* Generate the exit code */ |
567 | g_leave (); |
568 | |
569 | /* Emit references to imports/exports */ |
570 | EmitExternals (); |
571 | |
572 | /* Emit function debug info */ |
573 | F_EmitDebugInfo (); |
574 | EmitDebugInfo (); |
575 | |
576 | /* Leave the lexical level */ |
577 | LeaveFunctionLevel (); |
578 | |
579 | /* Eat the closing brace */ |
580 | ConsumeRCurly (); |
581 | |
582 | /* Restore the old literal pool, remembering the one for the function */ |
583 | Func->V.F.LitPool = PopLiteralPool (); |
584 | |
585 | /* Switch back to the old segments */ |
586 | PopSegments (); |
587 | |
588 | /* Reset the current function pointer */ |
589 | FreeFunction (CurrentFunc); |
590 | CurrentFunc = 0; |
591 | } |
592 | |