Example #1
0
Type* PtrConversion (Type* T)
/* If the type is a function, convert it to pointer to function. If the
** expression is an array, convert it to pointer to first element. Otherwise
** return T.
*/
{
    if (IsTypeFunc (T)) {
        return PointerTo (T);
    } else if (IsTypeArray (T)) {
        return ArrayToPtr (T);
    } else {
        return T;
    }
}
Example #2
0
void GetFuncInfo (const char* Name, unsigned short* Use, unsigned short* Chg)
/* For the given function, lookup register information and store it into
** the given variables. If the function is unknown, assume it will use and
** load all registers.
*/
{
    /* If the function name starts with an underline, it is an external
    ** function. Search for it in the symbol table. If the function does
    ** not start with an underline, it may be a runtime support function.
    ** Search for it in the list of builtin functions.
    */
    if (Name[0] == '_') {
        /* Search in the symbol table, skip the leading underscore */
        SymEntry* E = FindGlobalSym (Name+1);

        /* Did we find it in the top-level table? */
        if (E && IsTypeFunc (E->Type)) {
            FuncDesc* D = E->V.F.Func;

            /* A variadic function will use the Y register (the parameter list
            ** size is passed there). A fastcall function will use the A or A/X
            ** registers. In all other cases, no registers are used. However,
            ** we assume that any function will destroy all registers.
            */
            if ((D->Flags & FD_VARIADIC) != 0) {
                *Use = REG_Y;
            } else if (D->ParamCount > 0 &&
                       (AutoCDecl ?
                        IsQualFastcall (E->Type) :
                        !IsQualCDecl (E->Type))) {
                /* Will use registers depending on the last param. */
                switch (CheckedSizeOf (D->LastParam->Type)) {
                    case 1u:
                        *Use = REG_A;
                        break;
                    case 2u:
                        *Use = REG_AX;
                        break;
                    default:
                        *Use = REG_EAX;
                }
            } else {
                /* Will not use any registers */
                *Use = REG_NONE;
            }

            /* Will destroy all registers */
            *Chg = REG_ALL;

            /* Done */
            return;
        }

    } else if (IsDigit (Name[0]) || Name[0] == '$') {

        /* A call to a numeric address. Assume that anything gets used and
        ** destroyed. This is not a real problem, since numeric addresses
        ** are used mostly in inline assembly anyway.
        */
        *Use = REG_ALL;
        *Chg = REG_ALL;
        return;

    } else {

        /* Search for the function in the list of builtin functions */
        const FuncInfo* Info = bsearch (Name, FuncInfoTable, FuncInfoCount,
                                        sizeof(FuncInfo), CompareFuncInfo);

        /* Do we know the function? */
        if (Info) {
            /* Use the information we have */
            *Use = Info->Use;
            *Chg = Info->Chg;
        } else {
            /* It's an internal function we have no information for. If in
            ** debug mode, output an additional warning, so we have a chance
            ** to fix it. Otherwise assume that the internal function will
            ** use and change all registers.
            */
            if (Debug) {
                fprintf (stderr, "No info about internal function `%s'\n", Name);
            }
            *Use = REG_ALL;
            *Chg = REG_ALL;
        }
        return;
    }

    /* Function not found - assume that the primary register is input, and all
    ** registers are changed
    */
    *Use = REG_EAXY;
    *Chg = REG_ALL;
}
Example #3
0
void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
    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;

    /* Allocate the function activation record for the function */
    CurrentFunc = NewFunction (Func);

    /* Reenter the lexical level */
    ReenterFunctionLevel (D);

    /* 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");
    }

    /* 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[] = { 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);
    }

    /* Function body now defined */
    Func->Flags |= SC_DEF;

    /* Special handling for main() */
    if (strcmp (Func->Name, "main") == 0) {

        /* Mark this as the main function */
        CurrentFunc->Flags |= FF_IS_MAIN;

        /* Main cannot be a fastcall function */
        if (IsQualFastcall (Func->Type)) {
            Error ("`main' cannot be declared as __fastcall__");
        }

        /* If cc65 extensions aren't enabled, don't allow a main function that
         * doesn't return an int.
         */
        if (IS_Get (&Standard) != STD_CC65 && CurrentFunc->ReturnType[0].C != T_INT) {
            Error ("`main' must always return an int");
        }

        /* Add a forced import of a symbol that is contained in the startup
         * code. This will force the startup code to be linked in.
         */
        g_importstartup ();

        /* If main() takes parameters, generate a forced import to a function
         * that will setup these parameters. This way, programs that do not
         * need the additional code will not get it.
         */
        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;

        /* 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 function entry code if needed */
    g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc));

    /* If stack checking code is requested, emit a call to the helper routine */
    if (IS_Get (&CheckStack)) {
        g_stackcheck ();
    }

    /* Setup the stack */
    StackPtr = 0;

    /* Walk through the parameter list and allocate register variable space
     * for parameters declared as register. Generate code to swap the contents
     * of the register bank with the save area on the stack.
     */
    Param = D->SymTab->SymHead;
    while (Param && (Param->Flags & SC_PARAM) != 0) {

        /* Check for a register variable */
        if (SymIsRegVar (Param)) {

            /* Allocate space */
            int Reg = F_AllocRegVar (CurrentFunc, Param->Type);

            /* Could we allocate a register? */
            if (Reg < 0) {
                /* No register available: Convert parameter to auto */
                CvtRegVarToAuto (Param);
            } else {
                /* Remember the register offset */
                Param->V.R.RegOffs = Reg;

                /* Generate swap code */
                g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (Param->Type));
            }
        }

        /* Next parameter */
        Param = Param->NextSym;
    }

    /* 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 = StackPtr;

    /* Now process statements in this block */
    while (CurTok.Tok != TOK_RCURLY && CurTok.Tok != TOK_CEOF) {
        Statement (0);
    }

    /* 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) && !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));

    /* Restore the register variables */
    F_RestoreRegVars (CurrentFunc);

    /* Generate the exit code */
    g_leave ();

    /* 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 ();

    /* Reset the current function pointer */
    FreeFunction (CurrentFunc);
    CurrentFunc = 0;
}
Example #4
0
SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
/* Add an external or global symbol to the symbol table and return the entry */
{
    /* There is some special handling for functions, so check if it is one */
    int IsFunc = IsTypeFunc (T);

    /* Functions must be inserted in the global symbol table */
    SymTable* Tab = IsFunc? SymTab0 : SymTab;

    /* Do we have an entry with this name already? */
    SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
    if (Entry) {

        Type* EType;

        /* We have a symbol with this name already */
        if (Entry->Flags & SC_TYPE) {
            Error ("Multiple definition for `%s'", Name);
            return Entry;
        }

        /* Get the type string of the existing symbol */
        EType = Entry->Type;

        /* If we are handling arrays, the old entry or the new entry may be an
        ** incomplete declaration. Accept this, and if the exsting entry is
        ** incomplete, complete it.
        */
        if (IsTypeArray (T) && IsTypeArray (EType)) {

            /* Get the array sizes */
            long Size  = GetElementCount (T);
            long ESize = GetElementCount (EType);

            if ((Size != UNSPECIFIED && ESize != UNSPECIFIED && Size != ESize) ||
                TypeCmp (T + 1, EType + 1) < TC_EQUAL) {
                /* Types not identical: Conflicting types */
                Error ("Conflicting types for `%s'", Name);
                return Entry;
            } else {
                /* Check if we have a size in the existing definition */
                if (ESize == UNSPECIFIED) {
                    /* Existing, size not given, use size from new def */
                    SetElementCount (EType, Size);
                }
            }

        } else {
            /* New type must be identical */
            if (TypeCmp (EType, T) < TC_EQUAL) {
                Error ("Conflicting types for `%s'", Name);
                return Entry;
            }

            /* In case of a function, use the new type descriptor, since it
            ** contains pointers to the new symbol tables that are needed if
            ** an actual function definition follows. Be sure not to use the
            ** new descriptor if it contains a function declaration with an
            ** empty parameter list.
            */
            if (IsFunc) {
                /* Get the function descriptor from the new type */
                FuncDesc* F = GetFuncDesc (T);
                /* Use this new function descriptor if it doesn't contain
                ** an empty parameter list.
                */
                if ((F->Flags & FD_EMPTY) == 0) {
                    Entry->V.F.Func = F;
                    SetFuncDesc (EType, F);
                }
            }
        }

        /* Add the new flags */
        Entry->Flags |= Flags;

    } else {

        /* Create a new entry */
        Entry = NewSymEntry (Name, Flags);

        /* Set the symbol attributes */
        Entry->Type = TypeDup (T);

        /* If this is a function, set the function descriptor and clear
        ** additional fields.
        */
        if (IsFunc) {
            Entry->V.F.Func = GetFuncDesc (Entry->Type);
            Entry->V.F.Seg  = 0;
        }

        /* Add the assembler name of the symbol */
        SymSetAsmName (Entry);

        /* Add the entry to the symbol table */
        AddSymEntry (Tab, Entry);
    }

    /* Return the entry */
    return Entry;
}