#include <string.h>
/* common */
+#include "attrib.h"
#include "check.h"
/* cc65 */
#include "codegen.h"
#include "error.h"
+#include "funcdesc.h"
#include "global.h"
#include "scanner.h"
#include "stdfunc.h"
/*****************************************************************************/
-/* Function forwards */
+/* Function forwards */
/*****************************************************************************/
-static void StdFunc_strlen (struct expent*);
+static void StdFunc_memset (FuncDesc*, ExprDesc*);
+static void StdFunc_strlen (FuncDesc*, ExprDesc*);
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* Table with all known functions and their handlers. Must be sorted
* alphabetically!
*/
-static struct FuncDesc {
- const char* Name;
- void (*Handler) (struct expent*);
+static struct StdFuncDesc {
+ const char* Name;
+ void (*Handler) (FuncDesc*, ExprDesc*);
} StdFuncs [] = {
+ { "memset", StdFunc_memset },
{ "strlen", StdFunc_strlen },
};
static int CmpFunc (const void* Key, const void* Elem)
/* Compare function for bsearch */
{
- return strcmp ((const char*) Key, ((const struct FuncDesc*) Elem)->Name);
+ return strcmp ((const char*) Key, ((const struct StdFuncDesc*) Elem)->Name);
}
-static struct FuncDesc* FindFunc (const char* Name)
+static struct StdFuncDesc* FindFunc (const char* Name)
/* Find a function with the given name. Return a pointer to the descriptor if
* found, return NULL otherwise.
*/
+static unsigned ParseArg (type* Type, ExprDesc* pval)
+/* Parse one argument but do not push it onto the stack. Return the code
+ * generator flags needed to do the actual push.
+ */
+{
+ unsigned CFlags;
+ unsigned Flags;
+
+ /* Do some optimization: If we have a constant value to push,
+ * use a special function that may optimize.
+ */
+ CFlags = CF_NONE;
+ if (CheckedSizeOf (Type) == 1) {
+ CFlags = CF_FORCECHAR;
+ }
+ Flags = CF_NONE;
+ if (evalexpr (CFlags, hie1, pval) == 0) {
+ /* A constant value */
+ Flags |= CF_CONST;
+ }
+
+ /* Promote the argument if needed */
+ assignadjust (Type, pval);
+
+ /* We have a prototype, so chars may be pushed as chars */
+ Flags |= CF_FORCECHAR;
+
+ /* Use the type of the argument for the push */
+ return (Flags | TypeOf (pval->Type));
+}
+
+
+
/*****************************************************************************/
-/* Handle known functions */
+/* Handle known functions */
/*****************************************************************************/
-static void StdFunc_strlen (struct expent* lval)
+static void StdFunc_memset (FuncDesc* F attribute ((unused)),
+ ExprDesc* lval attribute ((unused)))
+/* Handle the memset function */
+{
+ /* Argument types */
+ static type Arg1Type[] = { T_PTR, T_VOID, T_END }; /* void* */
+ static type Arg2Type[] = { T_INT, T_END }; /* int */
+ static type Arg3Type[] = { T_UINT, T_END }; /* size_t */
+
+ unsigned Flags;
+ ExprDesc Arg;
+ int MemSet = 1; /* Use real memset if true */
+ unsigned ParamSize = 0;
+
+
+ /* Check the prototype of the function against what we know about it, so
+ * we can detect errors.
+ */
+ /* ### */
+
+ /* Argument #1 */
+ Flags = ParseArg (Arg1Type, &Arg);
+ g_push (Flags, Arg.ConstVal);
+ ParamSize += SizeOf (Arg1Type);
+ ConsumeComma ();
+
+ /* Argument #2. This argument is special in that we will call another
+ * function if it is a constant zero.
+ */
+ Flags = ParseArg (Arg2Type, &Arg);
+ if ((Flags & CF_CONST) != 0 && Arg.ConstVal == 0) {
+ /* Don't call memset, call bzero instead */
+ MemSet = 0;
+ } else {
+ /* Push the argument */
+ g_push (Flags, Arg.ConstVal);
+ ParamSize += SizeOf (Arg2Type);
+ }
+ ConsumeComma ();
+
+ /* Argument #3. Since memset is a fastcall function, we must load the
+ * arg into the primary if it is not already there. This parameter is
+ * also ignored for the calculation of the parameter size, since it is
+ * not passed via the stack.
+ */
+ Flags = ParseArg (Arg3Type, &Arg);
+ if (Flags & CF_CONST) {
+ exprhs (CF_FORCECHAR, 0, &Arg);
+ }
+
+ /* Emit the actual function call */
+ g_call (CF_NONE, MemSet? "memset" : "_bzero", ParamSize);
+
+ /* We expect the closing brace */
+ ConsumeRParen ();
+}
+
+
+
+static void StdFunc_strlen (FuncDesc* F attribute ((unused)),
+ ExprDesc* lval attribute ((unused)))
/* Handle the strlen function */
{
- struct expent pval;
+ ExprDesc pval;
+ static type ArgType[] = { T_PTR, T_SCHAR, T_END };
+
/* Fetch the parameter */
int k = hie1 (&pval);
/* Check if the parameter is a const address */
unsigned flags = 0;
- unsigned pflags = pval.e_flags & ~E_MCTYPE;
+ unsigned pflags = pval.Flags & ~E_MCTYPE;
if (pflags == E_MCONST) {
/* Constant numeric address */
flags |= CF_CONST | CF_ABSOLUTE;
- } else if (k == 0 && ((pflags & E_MGLOBAL) != 0 || pval.e_flags == E_MEOFFS)) {
+ } else if (k == 0 && ((pflags & E_MGLOBAL) != 0 || pval.Flags == E_MEOFFS)) {
/* Global array with or without offset */
flags |= CF_CONST;
- if (pval.e_flags & E_TGLAB) {
+ if (pval.Flags & E_TGLAB) {
/* External linkage */
flags |= CF_EXTERNAL;
} else {
exprhs (CF_NONE, k, &pval);
}
+ /* Setup the argument type string */
+ ArgType[1] = GetDefaultChar () | T_QUAL_CONST;
+
/* Convert the parameter type to the type needed, check for mismatches */
- assignadjust (SignedChars? type_pschar : type_puchar, &pval);
+ assignadjust (ArgType, &pval);
/* Generate the strlen code */
- g_strlen (flags, pval.e_name, pval.e_const);
+ g_strlen (flags, pval.Name, pval.ConstVal);
/* We expect the closing brace */
ConsumeRParen ();
-void HandleStdFunc (struct expent* lval)
+void HandleStdFunc (FuncDesc* F, ExprDesc* lval)
/* Generate code for a known standard function. */
{
/* Get a pointer to the table entry */
- struct FuncDesc* F = FindFunc ((const char*) lval->e_name);
- CHECK (F != 0);
+ struct StdFuncDesc* D = FindFunc ((const char*) lval->Name);
+ CHECK (D != 0);
/* Call the handler function */
- F->Handler (lval);
+ D->Handler (F, lval);
}