1 /*****************************************************************************/
5 /* Handle inlining of known functions for the cc65 compiler */
9 /* (C) 1998-2004 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
57 /*****************************************************************************/
58 /* Function forwards */
59 /*****************************************************************************/
63 static void StdFunc_memset (FuncDesc*, ExprDesc*);
64 static void StdFunc_strlen (FuncDesc*, ExprDesc*);
68 /*****************************************************************************/
70 /*****************************************************************************/
74 /* Table with all known functions and their handlers. Must be sorted
77 static struct StdFuncDesc {
79 void (*Handler) (FuncDesc*, ExprDesc*);
81 { "memset", StdFunc_memset },
82 { "strlen", StdFunc_strlen },
85 #define FUNC_COUNT (sizeof (StdFuncs) / sizeof (StdFuncs[0]))
89 /*****************************************************************************/
90 /* Helper functions */
91 /*****************************************************************************/
95 static int CmpFunc (const void* Key, const void* Elem)
96 /* Compare function for bsearch */
98 return strcmp ((const char*) Key, ((const struct StdFuncDesc*) Elem)->Name);
103 static unsigned ParseArg (type* Type, ExprDesc* Arg)
104 /* Parse one argument but do not push it onto the stack. Return the code
105 * generator flags needed to do the actual push.
108 /* We have a prototype, so chars may be pushed as chars */
109 unsigned Flags = CF_FORCECHAR;
111 /* Read the expression we're going to pass to the function */
114 /* Convert this expression to the expected type */
115 TypeConversion (Arg, Type);
117 /* If the value is a constant, set the flag, otherwise load it into the
120 if (ED_IsConstAbsInt (Arg)) {
121 /* Remember that we have a constant value */
124 /* Load into the primary */
125 ExprLoad (CF_NONE, Arg);
129 /* Use the type of the argument for the push */
130 return (Flags | TypeOf (Arg->Type));
135 /*****************************************************************************/
136 /* Handle known functions */
137 /*****************************************************************************/
141 static void StdFunc_memset (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
142 /* Handle the memset function */
145 static type Arg1Type[] = { T_PTR, T_VOID, T_END }; /* void* */
146 static type Arg2Type[] = { T_INT, T_END }; /* int */
147 static type Arg3Type[] = { T_UINT, T_END }; /* size_t */
151 int MemSet = 1; /* Use real memset if true */
152 unsigned ParamSize = 0;
155 Flags = ParseArg (Arg1Type, &Arg);
156 g_push (Flags, Arg.Val);
157 ParamSize += SizeOf (Arg1Type);
160 /* Argument #2. This argument is special in that we will call another
161 * function if it is a constant zero.
163 Flags = ParseArg (Arg2Type, &Arg);
164 if ((Flags & CF_CONST) != 0 && Arg.Val == 0) {
165 /* Don't call memset, call bzero instead */
168 /* Push the argument */
169 g_push (Flags, Arg.Val);
170 ParamSize += SizeOf (Arg2Type);
174 /* Argument #3. Since memset is a fastcall function, we must load the
175 * arg into the primary if it is not already there. This parameter is
176 * also ignored for the calculation of the parameter size, since it is
177 * not passed via the stack.
179 Flags = ParseArg (Arg3Type, &Arg);
180 if (Flags & CF_CONST) {
182 Warning ("Call to memset has no effect");
184 ExprLoad (CF_FORCECHAR, &Arg);
187 /* Emit the actual function call */
188 g_call (CF_NONE, MemSet? Func_memset : Func__bzero, ParamSize);
190 /* We expect the closing brace */
193 /* The function result is an rvalue in the primary register */
194 ED_MakeRValExpr (Expr);
195 Expr->Type = GetFuncReturn (Expr->Type);
200 static void StdFunc_strlen (FuncDesc* F attribute ((unused)), ExprDesc* Expr)
201 /* Handle the strlen function */
203 static type ArgType[] = { T_PTR, T_SCHAR, T_END };
208 /* Setup the argument type string */
209 ArgType[1] = GetDefaultChar () | T_QUAL_CONST;
211 /* Evaluate the parameter */
214 /* We can generate special code for several locations */
215 if (ED_IsLocConst (&Arg) && IsTypeArray (Arg.Type)) {
217 /* Do type conversion */
218 TypeConversion (&Arg, ArgType);
220 /* If the expression is a literal, and if string literals are read
221 * only, we can calculate the length of the string and remove it
222 * from the literal pool. Otherwise we have to calculate the length
225 if (ED_IsLocLiteral (&Arg) && IS_Get (&WritableStrings)) {
227 /* Constant string literal */
228 ED_MakeConstAbs (Expr, strlen (GetLiteral (Arg.Val)), type_size_t);
229 ResetLiteralPoolOffs (Arg.Val);
233 /* Generate the strlen code */
234 L = GetLocalLabel ();
235 AddCodeLine ("ldy #$FF");
238 AddCodeLine ("lda %s,y", ED_GetLabelName (&Arg, 0));
239 AddCodeLine ("bne %s", LocalLabelName (L));
243 /* The function result is an rvalue in the primary register */
244 ED_MakeRValExpr (Expr);
245 Expr->Type = type_size_t;
249 } else if (ED_IsLocStack (&Arg) && StackPtr >= -255 && IsTypeArray (Arg.Type)) {
251 /* Calculate the true stack offset */
252 unsigned Offs = (unsigned) (Arg.Val - StackPtr);
254 /* Do type conversion */
255 TypeConversion (&Arg, ArgType);
257 /* Generate the strlen code */
258 L = GetLocalLabel ();
259 AddCodeLine ("ldx #$FF");
260 AddCodeLine ("ldy #$%02X", (unsigned char) (Offs-1));
264 AddCodeLine ("lda (sp),y");
265 AddCodeLine ("bne %s", LocalLabelName (L));
267 AddCodeLine ("ldx #$00");
269 /* The function result is an rvalue in the primary register */
270 ED_MakeRValExpr (Expr);
271 Expr->Type = type_size_t;
273 } else if (ED_IsLocRegister (&Arg) && ED_IsLVal (&Arg) && IsTypePtr (Arg.Type)) {
275 /* Do type conversion */
276 TypeConversion (&Arg, ArgType);
278 /* Generate the strlen code */
279 L = GetLocalLabel ();
280 AddCodeLine ("ldy #$FF");
283 AddCodeLine ("lda (%s),y", ED_GetLabelName (&Arg, 0));
284 AddCodeLine ("bne %s", LocalLabelName (L));
288 /* The function result is an rvalue in the primary register */
289 ED_MakeRValExpr (Expr);
290 Expr->Type = type_size_t;
294 /* Do type conversion */
295 TypeConversion (&Arg, ArgType);
297 /* Load the expression into the primary */
298 ExprLoad (CF_NONE, &Arg);
300 /* Call the strlen function */
301 AddCodeLine ("jsr _%s", Func_strlen);
303 /* The function result is an rvalue in the primary register */
304 ED_MakeRValExpr (Expr);
305 Expr->Type = type_size_t;
309 /* We expect the closing brace */
315 /*****************************************************************************/
317 /*****************************************************************************/
321 int FindStdFunc (const char* Name)
322 /* Determine if the given function is a known standard function that may be
323 * called in a special way. If so, return the index, otherwise return -1.
326 /* Look into the table for known names */
327 struct StdFuncDesc* D =
328 bsearch (Name, StdFuncs, FUNC_COUNT, sizeof (StdFuncs[0]), CmpFunc);
330 /* Return the function index or -1 */
340 void HandleStdFunc (int Index, FuncDesc* F, ExprDesc* lval)
341 /* Generate code for a known standard function. */
343 struct StdFuncDesc* D;
345 /* Get a pointer to the table entry */
346 CHECK (Index >= 0 && Index < (int)FUNC_COUNT);
347 D = StdFuncs + Index;
349 /* Call the handler function */
350 D->Handler (F, lval);