/*****************************************************************************/
/* */
-/* function.c */
+/* function.c */
/* */
-/* Parse function entry/body/exit */
+/* Parse function entry/body/exit */
/* */
/* */
/* */
-/* (C) 2000-2009, Ullrich von Bassewitz */
+/* (C) 2000-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include "litpool.h"
#include "locals.h"
#include "scanner.h"
-#include "segments.h"
#include "stackptr.h"
#include "standard.h"
#include "stmt.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* Structure that holds all data needed for function activation */
struct Function {
- struct SymEntry* FuncEntry; /* Symbol table entry */
- Type* ReturnType; /* Function return type */
- struct FuncDesc* Desc; /* Function descriptor */
- int Reserved; /* Reserved local space */
- unsigned RetLab; /* Return code label */
- int TopLevelSP; /* SP at function top level */
+ struct SymEntry* FuncEntry; /* Symbol table entry */
+ Type* ReturnType; /* Function return type */
+ FuncDesc* Desc; /* Function descriptor */
+ int Reserved; /* Reserved local space */
+ unsigned RetLab; /* Return code label */
+ int TopLevelSP; /* SP at function top level */
unsigned RegOffs; /* Register variable space offset */
- funcflags_t Flags; /* Function flags */
+ funcflags_t Flags; /* Function flags */
};
/* Pointer to current function */
/*****************************************************************************/
-/* Subroutines working with struct Function */
+/* Subroutines working with struct Function */
/*****************************************************************************/
/* Initialize the fields */
F->FuncEntry = Sym;
F->ReturnType = GetFuncReturn (Sym->Type);
- F->Desc = GetFuncDesc (Sym->Type);
- F->Reserved = 0;
- F->RetLab = GetLocalLabel ();
+ F->Desc = GetFuncDesc (Sym->Type);
+ F->Reserved = 0;
+ F->RetLab = GetLocalLabel ();
F->TopLevelSP = 0;
F->RegOffs = RegisterSpace;
- F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE;
+ F->Flags = IsTypeVoid (F->ReturnType) ? FF_VOID_RETURN : FF_NONE;
/* Return the new structure */
return F;
+int F_GetStackPtr (const Function* F)
+/* Return the current stack pointer including reserved (but not allocated)
+ * space on the stack.
+ */
+{
+ return StackPtr - F->Reserved;
+}
+
+
+
void F_AllocLocalSpace (Function* F)
/* Allocate any local space previously reserved. The function will do
* nothing if there is no reserved local space.
{
if (F->Reserved > 0) {
- /* Create space on the stack */
- g_space (F->Reserved);
+ /* Create space on the stack */
+ g_space (F->Reserved);
- /* Correct the stack pointer */
- StackPtr -= F->Reserved;
+ /* Correct the stack pointer */
+ StackPtr -= F->Reserved;
- /* Nothing more reserved */
- F->Reserved = 0;
+ /* Nothing more reserved */
+ F->Reserved = 0;
}
}
/* Allow register variables only on top level and if enabled */
if (IS_Get (&EnableRegVars) && GetLexicalLevel () == LEX_LEVEL_FUNCTION) {
- /* Get the size of the variable */
- unsigned Size = CheckedSizeOf (Type);
-
- /* Do we have space left? */
- if (F->RegOffs >= Size) {
- /* Space left. We allocate the variables from high to low addresses,
- * so the adressing is compatible with the saved values on stack.
- * This allows shorter code when saving/restoring the variables.
- */
- F->RegOffs -= Size;
- return F->RegOffs;
- }
+ /* Get the size of the variable */
+ unsigned Size = CheckedSizeOf (Type);
+
+ /* Do we have space left? */
+ if (F->RegOffs >= Size) {
+ /* Space left. We allocate the variables from high to low addresses,
+ * so the adressing is compatible with the saved values on stack.
+ * This allows shorter code when saving/restoring the variables.
+ */
+ F->RegOffs -= Size;
+ return F->RegOffs;
+ }
}
/* No space left or no allocation */
/* If we don't have register variables in this function, bail out early */
if (F->RegOffs == RegisterSpace) {
- return;
+ return;
}
/* Save the accumulator if needed */
if (!F_HasVoidReturn (F)) {
- g_save (CF_CHAR | CF_FORCECHAR);
+ g_save (CF_CHAR | CF_FORCECHAR);
}
/* Get the first symbol from the function symbol table */
/* Restore the accumulator if needed */
if (!F_HasVoidReturn (F)) {
- g_restore (CF_CHAR | CF_FORCECHAR);
+ g_restore (CF_CHAR | CF_FORCECHAR);
+ }
+}
+
+
+
+static void F_EmitDebugInfo (void)
+/* Emit debug infos for the current function */
+{
+ if (DebugInfo) {
+ /* Get the current function */
+ const SymEntry* Sym = CurrentFunc->FuncEntry;
+
+ /* Output info for the function itself */
+ AddTextLine ("\t.dbg\tfunc, \"%s\", \"00\", %s, \"%s\"",
+ Sym->Name,
+ (Sym->Flags & SC_EXTERN)? "extern" : "static",
+ Sym->AsmName);
}
}
/*****************************************************************************/
-/* code */
+/* code */
/*****************************************************************************/
void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
- SymEntry* Param;
+ int C99MainFunc = 0;/* Flag for C99 main function returning int */
+ SymEntry* Param;
/* Get the function descriptor from the function entry */
FuncDesc* D = Func->V.F.Func;
/* Reenter the lexical level */
ReenterFunctionLevel (D);
- /* Check if the function header contains unnamed parameters. These are
+ /* Check if the function header contains unnamed parameters. These are
* only allowed in cc65 mode.
- */
+ */
if ((D->Flags & FD_UNNAMED_PARAMS) != 0 && (IS_Get (&Standard) != STD_CC65)) {
Error ("Parameter name omitted");
}
*/
AddConstSym ("__fixargs__", type_uint, SC_DEF | SC_CONST, D->ParamSize);
if (D->Flags & FD_VARIADIC) {
- /* Variadic function. The variable must be const. */
- static const Type T[] = { TYPE(T_UCHAR | T_QUAL_CONST), TYPE(T_END) };
- AddLocalSym ("__argsize__", T, SC_DEF | SC_REF | SC_AUTO, 0);
+ /* Variadic function. The variable must be const. */
+ static const Type T[] = { TYPE(T_UCHAR | T_QUAL_CONST), TYPE(T_END) };
+ AddLocalSym ("__argsize__", T, SC_DEF | SC_REF | SC_AUTO, 0);
} else {
- /* Non variadic */
- AddConstSym ("__argsize__", type_uchar, SC_DEF | SC_CONST, D->ParamSize);
+ /* Non variadic */
+ AddConstSym ("__argsize__", type_uchar, SC_DEF | SC_CONST, D->ParamSize);
}
/* Function body now defined */
if (D->ParamCount > 0 || (D->Flags & FD_VARIADIC) != 0) {
g_importmainargs ();
}
+
+ /* Determine if this is a main function in a C99 environment that
+ * returns an int.
+ */
+ if (IsTypeInt (F_GetReturnType (CurrentFunc)) &&
+ IS_Get (&Standard) == STD_C99) {
+ C99MainFunc = 1;
+ }
}
/* Allocate code and data segments for this function */
Func->V.F.Seg = PushSegments (Func);
+ /* Allocate a new literal pool */
+ PushLiteralPool (Func);
+
/* If this is a fastcall function, push the last parameter onto the stack */
if (IsQualFastcall (Func->Type) && D->ParamCount > 0) {
- unsigned Flags;
+ unsigned Flags;
- /* Fastcall functions may never have an ellipsis or the compiler is buggy */
- CHECK ((D->Flags & FD_VARIADIC) == 0);
+ /* Fastcall functions may never have an ellipsis or the compiler is buggy */
+ CHECK ((D->Flags & FD_VARIADIC) == 0);
- /* Generate the push */
- if (IsTypeFunc (D->LastParam->Type)) {
- /* Pointer to function */
- Flags = CF_PTR;
- } else {
- Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR;
- }
- g_push (Flags, 0);
+ /* Generate the push */
+ if (IsTypeFunc (D->LastParam->Type)) {
+ /* Pointer to function */
+ Flags = CF_PTR;
+ } else {
+ Flags = TypeOf (D->LastParam->Type) | CF_FORCECHAR;
+ }
+ g_push (Flags, 0);
}
/* Generate function entry code if needed */
/* If stack checking code is requested, emit a call to the helper routine */
if (IS_Get (&CheckStack)) {
- g_stackcheck ();
+ g_stackcheck ();
}
/* Setup the stack */
Statement (0);
}
- /* If this is not a void function, output a warning if we didn't see a
- * return statement.
+ /* If this is not a void function, and not the main function in a C99
+ * environment returning int, output a warning if we didn't see a return
+ * statement.
*/
- if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc)) {
+ if (!F_HasVoidReturn (CurrentFunc) && !F_HasReturn (CurrentFunc) && !C99MainFunc) {
Warning ("Control reaches end of non-void function");
}
+ /* If this is the main function in a C99 environment returning an int, let
+ * it always return zero. Note: Actual return statements jump to the return
+ * label defined below.
+ * The code is removed by the optimizer if unused.
+ */
+ if (C99MainFunc) {
+ g_getimmed (CF_INT | CF_CONST, 0, 0);
+ }
+
/* Output the function exit code label */
g_defcodelabel (F_GetRetLab (CurrentFunc));
/* Emit references to imports/exports */
EmitExternals ();
+ /* Emit function debug info */
+ F_EmitDebugInfo ();
+ EmitDebugInfo ();
+
/* Leave the lexical level */
LeaveFunctionLevel ();
/* Eat the closing brace */
ConsumeRCurly ();
+ /* Restore the old literal pool, remembering the one for the function */
+ Func->V.F.LitPool = PopLiteralPool ();
+
/* Switch back to the old segments */
PopSegments ();
FreeFunction (CurrentFunc);
CurrentFunc = 0;
}
-
-
-