/* */
/* */
/* */
-/* (C) 2000 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 2000-2001 Ullrich von Bassewitz */
+/* Wacholderweg 14 */
+/* D-70597 Stuttgart */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
-#include "../common/xmalloc.h"
+/* common */
+#include "check.h"
+#include "xmalloc.h"
+/* cc65 */
#include "asmcode.h"
#include "asmlabel.h"
#include "codegen.h"
#include "error.h"
#include "funcdesc.h"
+#include "global.h"
#include "litpool.h"
#include "locals.h"
#include "scanner.h"
+#include "segments.h"
#include "stmt.h"
#include "symtab.h"
#include "function.h"
/* Structure that holds all data needed for function activation */
struct Function {
struct SymEntry* FuncEntry; /* Symbol table entry */
- type* ReturnType; /* Function return type */
+ type* ReturnType; /* Function return type */
struct FuncDesc* Desc; /* Function descriptor */
- CodeMark EntryCode; /* Backpatch addr for entry code */
int Reserved; /* Reserved local space */
unsigned RetLab; /* Return code label */
+ int TopLevelSP; /* SP at function top level */
};
/* Pointer to current function */
/* Create a new function activation structure and return it */
{
/* Allocate a new structure */
- Function* F = xmalloc (sizeof (Function));
+ Function* F = (Function*) xmalloc (sizeof (Function));
/* Initialize the fields */
F->FuncEntry = Sym;
- F->ReturnType = Sym->Type + 1 + DECODE_SIZE;
- F->Desc = DecodePtr (Sym->Type + 1);
- F->EntryCode = 0;
+ F->ReturnType = GetFuncReturn (Sym->Type);
+ F->Desc = (FuncDesc*) DecodePtr (Sym->Type + 1);
F->Reserved = 0;
- F->RetLab = GetLabel ();
+ F->RetLab = GetLocalLabel ();
+ F->TopLevelSP = 0;
/* Return the new structure */
return F;
-const char* GetFuncName (const Function* F)
+const char* F_GetFuncName (const Function* F)
/* Return the name of the current function */
{
return F->FuncEntry->Name;
-unsigned GetParamSize (const Function* F)
+unsigned F_GetParamCount (const Function* F)
+/* Return the parameter count for the current function */
+{
+ return F->Desc->ParamCount;
+}
+
+
+
+unsigned F_GetParamSize (const Function* F)
/* Return the parameter size for the current function */
{
return F->Desc->ParamSize;
-type* GetReturnType (Function* F)
+type* F_GetReturnType (Function* F)
/* Get the return type for the function */
{
return F->ReturnType;
-int HasVoidReturn (const Function* F)
+int F_HasVoidReturn (const Function* F)
/* Return true if the function does not have a return value */
{
- return IsVoid (F->ReturnType);
+ return IsTypeVoid (F->ReturnType);
+}
+
+
+
+int F_IsVariadic (const Function* F)
+/* Return true if this is a variadic function */
+{
+ return (F->Desc->Flags & FD_VARIADIC) != 0;
}
-void RememberEntry (Function* F)
-/* Remember the current output position for local space creation later */
+int F_IsOldStyle (const Function* F)
+/* Return true if this is an old style (K&R) function */
{
- F->EntryCode = GetCodePos ();
+ return (F->Desc->Flags & FD_OLDSTYLE) != 0;
}
-unsigned GetRetLab (const Function* F)
+int F_HasOldStyleIntRet (const Function* F)
+/* Return true if this is an old style (K&R) function with an implicit int return */
+{
+ return (F->Desc->Flags & FD_OLDSTYLE_INTRET) != 0;
+}
+
+
+
+unsigned F_GetRetLab (const Function* F)
/* Return the return jump label */
{
return F->RetLab;
-int ReserveLocalSpace (Function* F, unsigned Size)
+int F_GetTopLevelSP (const Function* F)
+/* Get the value of the stack pointer on function top level */
+{
+ return F->TopLevelSP;
+}
+
+
+
+int F_ReserveLocalSpace (Function* F, unsigned Size)
/* Reserve (but don't allocate) the given local space and return the stack
* offset.
*/
-void AllocLocalSpace (Function* F)
+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) {
- /* Switch to the code segment */
- g_usecode ();
-
- /* Create space on the stack */
- g_space (F->Reserved);
+ /* Create space on the stack */
+ g_space (F->Reserved);
- /* Correct the stack pointer */
- oursp -= F->Reserved;
+ /* Correct the stack pointer */
+ oursp -= F->Reserved;
- /* Nothing more reserved */
- F->Reserved = 0;
+ /* Nothing more reserved */
+ F->Reserved = 0;
}
}
void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
- int isbrk;
+ int HadReturn;
+ int IsVoidFunc;
+ SymEntry* LastParam;
/* Get the function descriptor from the function entry */
- FuncDesc* D = DecodePtr (Func->Type+1);
+ FuncDesc* D = Func->V.F.Func;
/* Allocate the function activation record for the function */
CurrentFunc = NewFunction (Func);
/* Reenter the lexical level */
ReenterFunctionLevel (D);
- /* Function body now defined */
- Func->Flags |= SC_DEF;
+ /* Before adding more symbols, remember the last parameter for later */
+ LastParam = D->SymTab->SymTail;
- /* C functions cannot currently have __fastcall__ calling conventions */
- if (IsFastCallFunc (Func->Type)) {
- Error (ERR_FASTCALL);
+ /* Declare two special functions symbols: __fixargs__ and __argsize__.
+ * The latter is different depending on the type of the function (variadic
+ * or not).
+ */
+ 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 [] = { T_UCHAR | T_QUAL_CONST, 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);
}
- /* Need a starting curly brace */
- if (curtok != TOK_LCURLY) {
- Error (ERR_LCURLY_EXPECTED);
- }
+ /* Function body now defined */
+ Func->Flags |= SC_DEF;
/* Setup register variables */
InitRegVars ();
- /* Switch to the code segment and define the function name label */
- g_usecode ();
- g_defgloblabel (Func->Name);
+ /* Allocate code and data segments for this function */
+ Func->V.F.Seg = PushSegments (Func);
- /* Generate function entry code if needed */
- g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc));
+ /* If this is a fastcall function, push the last parameter onto the stack */
+ if (IsFastCallFunc (Func->Type) && D->ParamCount > 0) {
- /* Remember the current code position. This may be used later to create
- * local variable space once we have created the function body itself.
- * Currently this is not possible because the stack offsets of all locals
- * have to be known in advance.
- */
- RememberEntry (CurrentFunc);
+ unsigned Flags;
+
+ /* Fastcall functions may never have an ellipsis or the compiler is buggy */
+ CHECK ((D->Flags & FD_VARIADIC) == 0);
+
+ /* Generate the push */
+ if (IsTypeFunc (LastParam->Type)) {
+ /* Pointer to function */
+ Flags = CF_PTR;
+ } else {
+ Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
+ }
+ g_push (Flags, 0);
+ }
+
+ /* If stack checking code is requested, emit a call to the helper routine */
+ if (CheckStack) {
+ g_stackcheck ();
+ }
+
+ /* Generate function entry code if needed */
+ g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc));
- /* Parse the function body */
+ /* Setup the stack */
oursp = 0;
- isbrk = compound ();
- /* If the function did not end with an return statement, create exit code */
- if (!isbrk) {
-#if 0
- /* If the function has a return type, flag an error */
- if (!voidfunc) {
- Error (ERR_MUST_RETURN_VALUE);
+ /* Need a starting curly brace */
+ ConsumeLCurly ();
+
+ /* Parse local variable declarations if any */
+ DeclareLocals ();
+
+ /* Remember the current stack pointer. All variables allocated elsewhere
+ * must be dropped when doing a return from an inner block.
+ */
+ CurrentFunc->TopLevelSP = oursp;
+
+ /* Now process statements in this block */
+ HadReturn = 0;
+ while (CurTok.Tok != TOK_RCURLY) {
+ if (CurTok.Tok != TOK_CEOF) {
+ HadReturn = Statement (0);
+ } else {
+ break;
}
-#endif
- RestoreRegVars (0);
- g_leave (CF_NONE, 0);
}
- /* Dump literal data created by the function */
- DumpLiteralPool ();
+ /* If the function has a return type but no return statement, flag
+ * a warning
+ */
+ IsVoidFunc = F_HasVoidReturn (CurrentFunc);
+#if 0
+ /* Does not work reliably */
+ if (!F_IsVoidFunc && !HadReturn) {
+ Warning ("Function `%s' should return a value", Func->Name);
+ }
+#endif
+
+ /* Output the function exit code label */
+ g_defcodelabel (F_GetRetLab (CurrentFunc));
+
+ /* Restore the register variables */
+ RestoreRegVars (!IsVoidFunc);
+
+ /* Generate the exit code */
+ g_leave ();
+
+ /* Eat the closing brace */
+ ConsumeRCurly ();
+
+ /* Emit references to imports/exports */
+ EmitExternals ();
/* Cleanup register variables */
DoneRegVars ();
/* Leave the lexical level */
LeaveFunctionLevel ();
+ /* Switch back to the old segments */
+ PopSegments ();
+
/* Reset the current function pointer */
FreeFunction (CurrentFunc);
CurrentFunc = 0;
-