From: cuz Date: Sun, 30 Sep 2001 21:56:45 +0000 (+0000) Subject: More source splitting. X-Git-Tag: V2.12.0~2601 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=c8415fc17c540cb97387ecac25eb5fce8e372807;p=cc65 More source splitting. Remove the -Wno-unused-parameter in favour of __atribute__((unused)). git-svn-id: svn://svn.cc65.org/cc65/trunk@986 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/cc65/asmstmt.c b/src/cc65/asmstmt.c index b34f78591..1910d945b 100644 --- a/src/cc65/asmstmt.c +++ b/src/cc65/asmstmt.c @@ -190,7 +190,7 @@ static void ParseWordArg (StrBuf* T, unsigned Arg) -static void ParseLongArg (StrBuf* T, unsigned Arg) +static void ParseLongArg (StrBuf* T, unsigned Arg attribute ((unused))) /* Parse the %l format specifier */ { ExprDesc Expr; diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 83944f503..214f1e42b 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -752,23 +752,15 @@ void g_getlocal (unsigned flags, int offs) AddCodeLine ("dey"); AddCodeLine ("lda (sp),y"); } else { - if (offs) { - ldyconst (offs+1); - AddCodeLine ("jsr ldaxysp"); - } else { - AddCodeLine ("jsr ldax0sp"); - } + ldyconst (offs+1); + AddCodeLine ("jsr ldaxysp"); } } break; case CF_LONG: - if (offs) { - ldyconst (offs+3); - AddCodeLine ("jsr ldeaxysp"); - } else { - AddCodeLine ("jsr ldeax0sp"); - } + ldyconst (offs+3); + AddCodeLine ("jsr ldeaxysp"); break; default: @@ -812,22 +804,14 @@ void g_getind (unsigned flags, unsigned offs) AddCodeLine ("iny"); AddCodeLine ("ora (ptr1),y"); } else { - if (offs == 0) { - AddCodeLine ("jsr ldaxi"); - } else { - ldyconst (offs+1); - AddCodeLine ("jsr ldaxidx"); - } + ldyconst (offs+1); + AddCodeLine ("jsr ldaxidx"); } break; case CF_LONG: - if (offs == 0) { - AddCodeLine ("jsr ldeaxi"); - } else { - ldyconst (offs+3); - AddCodeLine ("jsr ldeaxidx"); - } + ldyconst (offs+3); + AddCodeLine ("jsr ldeaxidx"); if (flags & CF_TEST) { AddCodeLine ("jsr tsteax"); } @@ -1034,12 +1018,8 @@ void g_putlocal (unsigned Flags, int Offs, long Val) if (Flags & CF_CONST) { g_getimmed (Flags, Val, 0); } - if (Offs) { - ldyconst (Offs); - AddCodeLine ("jsr steaxysp"); - } else { - AddCodeLine ("jsr steax0sp"); - } + ldyconst (Offs); + AddCodeLine ("jsr steaxysp"); break; default: @@ -1527,28 +1507,6 @@ void g_addstatic (unsigned flags, unsigned long label, unsigned offs) -/*****************************************************************************/ -/* Compares of ax with a variable with fixed address */ -/*****************************************************************************/ - - - -void g_cmplocal (unsigned flags, int offs) -/* Compare a local variable to ax */ -{ - Internal ("g_cmplocal not implemented"); -} - - - -void g_cmpstatic (unsigned flags, unsigned label, unsigned offs) -/* Compare a static variable to ax */ -{ - Internal ("g_cmpstatic not implemented"); -} - - - /*****************************************************************************/ /* Special op= functions */ /*****************************************************************************/ @@ -1728,12 +1686,8 @@ void g_addeqlocal (unsigned flags, int offs, unsigned long val) if (flags & CF_CONST) { g_getimmed (flags, val, 0); } - if (offs == 0) { - AddCodeLine ("jsr laddeq0sp"); - } else { - ldyconst (offs); - AddCodeLine ("jsr laddeqysp"); - } + ldyconst (offs); + AddCodeLine ("jsr laddeqysp"); break; default: @@ -1881,12 +1835,8 @@ void g_subeqstatic (unsigned flags, unsigned long label, unsigned offs, AddCodeLine ("ldy #<(%s)", lbuf); AddCodeLine ("sty ptr1"); AddCodeLine ("ldy #>(%s+1)", lbuf); - if (val == 1) { - AddCodeLine ("jsr lsubeq1"); - } else { - AddCodeLine ("lda #$%02X", (unsigned char)val); - AddCodeLine ("jsr lsubeqa"); - } + AddCodeLine ("lda #$%02X", (unsigned char)val); + AddCodeLine ("jsr lsubeqa"); } else { g_getstatic (flags, label, offs); g_dec (flags, val); @@ -1945,24 +1895,16 @@ void g_subeqlocal (unsigned flags, int offs, unsigned long val) if (flags & CF_CONST) { g_getimmed (flags, val, 0); } - if (offs == 0) { - AddCodeLine ("jsr subeq0sp"); - } else { - ldyconst (offs); - AddCodeLine ("jsr subeqysp"); - } + ldyconst (offs); + AddCodeLine ("jsr subeqysp"); break; case CF_LONG: if (flags & CF_CONST) { g_getimmed (flags, val, 0); } - if (offs == 0) { - AddCodeLine ("jsr lsubeq0sp"); - } else { - ldyconst (offs); - AddCodeLine ("jsr lsubeqysp"); - } + ldyconst (offs); + AddCodeLine ("jsr lsubeqysp"); break; default: @@ -2037,7 +1979,7 @@ void g_subeqind (unsigned flags, unsigned offs, unsigned long val) -void g_addaddr_local (unsigned flags, int offs) +void g_addaddr_local (unsigned flags attribute ((unused)), int offs) /* Add the address of a local variable to ax */ { unsigned L = 0; @@ -2281,36 +2223,20 @@ void g_test (unsigned flags) void g_push (unsigned flags, unsigned long val) /* Push the primary register or a constant value onto the stack */ { - unsigned char hi; - if (flags & CF_CONST && (flags & CF_TYPE) != CF_LONG) { /* We have a constant 8 or 16 bit value */ if ((flags & CF_TYPE) == CF_CHAR && (flags & CF_FORCECHAR)) { /* Handle as 8 bit value */ - if (CodeSizeFactor >= 165 || val > 2) { - ldaconst (val); - AddCodeLine ("jsr pusha"); - } else { - AddCodeLine ("jsr pushc%d", (int) val); - } + ldaconst (val); + AddCodeLine ("jsr pusha"); } else { /* Handle as 16 bit value */ - hi = (unsigned char) (val >> 8); - if (val <= 7) { - AddCodeLine ("jsr push%u", (unsigned) val); - } else if (hi == 0 || hi == 0xFF) { - /* Use special function */ - ldaconst (val); - AddCodeLine ("jsr %s", (hi == 0)? "pusha0" : "pushaFF"); - } else { - /* Long way ... */ - g_getimmed (flags, val, 0); - AddCodeLine ("jsr pushax"); - } + g_getimmed (flags, val, 0); + AddCodeLine ("jsr pushax"); } } else { @@ -2475,7 +2401,7 @@ void g_case (unsigned flags, unsigned label, unsigned long val) -void g_truejump (unsigned flags, unsigned label) +void g_truejump (unsigned flags attribute ((unused)), unsigned label) /* Jump to label if zero flag clear */ { AddCodeLine ("jne %s", LocalLabelName (label)); @@ -2483,7 +2409,7 @@ void g_truejump (unsigned flags, unsigned label) -void g_falsejump (unsigned flags, unsigned label) +void g_falsejump (unsigned flags attribute ((unused)), unsigned label) /* Jump to label if zero flag set */ { AddCodeLine ("jeq %s", LocalLabelName (label)); diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index d249b9958..3461af698 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -50,6 +50,7 @@ #include "coptadd.h" #include "coptcmp.h" #include "coptind.h" +#include "coptneg.h" #include "coptstop.h" #include "coptsub.h" #include "copttest.h" @@ -114,383 +115,6 @@ static unsigned OptShift1 (CodeSeg* S) -/*****************************************************************************/ -/* nega optimizations */ -/*****************************************************************************/ - - - -static unsigned OptNegA1 (CodeSeg* S) -/* Check for - * - * ldx #$00 - * lda .. - * jsr bnega - * - * Remove the ldx if the lda does not use it. - */ -{ - unsigned Changes = 0; - - /* Walk over the entries */ - unsigned I = 0; - while (I < CS_GetEntryCount (S)) { - - CodeEntry* L[2]; - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Check for a ldx */ - if (E->OPC == OP65_LDX && - E->AM == AM65_IMM && - (E->Flags & CEF_NUMARG) != 0 && - E->Num == 0 && - CS_GetEntries (S, L, I+1, 2) && - L[0]->OPC == OP65_LDA && - (L[0]->Use & REG_X) == 0 && - !CE_HasLabel (L[0]) && - CE_IsCall (L[1], "bnega") && - !CE_HasLabel (L[1])) { - - /* Remove the ldx instruction */ - CS_DelEntry (S, I); - - /* Remember, we had changes */ - ++Changes; - - } - - /* Next entry */ - ++I; - - } - - /* Return the number of changes made */ - return Changes; -} - - - -static unsigned OptNegA2 (CodeSeg* S) -/* Check for - * - * lda .. - * jsr bnega - * jeq/jne .. - * - * Adjust the conditional branch and remove the call to the subroutine. - */ -{ - unsigned Changes = 0; - - /* Walk over the entries */ - unsigned I = 0; - while (I < CS_GetEntryCount (S)) { - - CodeEntry* L[2]; - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Check for the sequence */ - if ((E->OPC == OP65_ADC || - E->OPC == OP65_AND || - E->OPC == OP65_DEA || - E->OPC == OP65_EOR || - E->OPC == OP65_INA || - E->OPC == OP65_LDA || - E->OPC == OP65_ORA || - E->OPC == OP65_PLA || - E->OPC == OP65_SBC || - E->OPC == OP65_TXA || - E->OPC == OP65_TYA) && - CS_GetEntries (S, L, I+1, 2) && - CE_IsCall (L[0], "bnega") && - !CE_HasLabel (L[0]) && - (L[1]->Info & OF_ZBRA) != 0 && - !CE_HasLabel (L[1])) { - - /* Invert the branch */ - CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC)); - - /* Delete the subroutine call */ - CS_DelEntry (S, I+1); - - /* Remember, we had changes */ - ++Changes; - - } - - /* Next entry */ - ++I; - - } - - /* Return the number of changes made */ - return Changes; -} - - - -/*****************************************************************************/ -/* negax optimizations */ -/*****************************************************************************/ - - - -static unsigned OptNegAX1 (CodeSeg* S) -/* On a call to bnegax, if X is zero, the result depends only on the value in - * A, so change the call to a call to bnega. This will get further optimized - * later if possible. - */ -{ - unsigned Changes = 0; - unsigned I; - - /* Generate register info for this step */ - CS_GenRegInfo (S); - - /* Walk over the entries */ - I = 0; - while (I < CS_GetEntryCount (S)) { - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Check if this is a call to bnegax, and if X is known and zero */ - if (E->RI->In.RegX == 0 && - CE_IsCall (E, "bnegax")) { - - /* We're cheating somewhat here ... */ - E->Arg[5] = '\0'; - E->Use &= ~REG_X; - - /* We had changes */ - ++Changes; - } - - /* Next entry */ - ++I; - - } - - /* Free register info */ - CS_FreeRegInfo (S); - - /* Return the number of changes made */ - return Changes; -} - - - -static unsigned OptNegAX2 (CodeSeg* S) -/* Search for the sequence: - * - * lda (xx),y - * tax - * dey - * lda (xx),y - * jsr bnegax - * jne/jeq ... - * - * and replace it by - * - * lda (xx),y - * dey - * ora (xx),y - * jeq/jne ... - */ -{ - unsigned Changes = 0; - - /* Walk over the entries */ - unsigned I = 0; - while (I < CS_GetEntryCount (S)) { - - CodeEntry* L[5]; - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Check for the sequence */ - if (E->OPC == OP65_LDA && - E->AM == AM65_ZP_INDY && - CS_GetEntries (S, L, I+1, 5) && - L[0]->OPC == OP65_TAX && - L[1]->OPC == OP65_DEY && - L[2]->OPC == OP65_LDA && - L[2]->AM == AM65_ZP_INDY && - strcmp (L[2]->Arg, E->Arg) == 0 && - !CE_HasLabel (L[2]) && - CE_IsCall (L[3], "bnegax") && - !CE_HasLabel (L[3]) && - (L[4]->Info & OF_ZBRA) != 0 && - !CE_HasLabel (L[4])) { - - /* lda --> ora */ - CE_ReplaceOPC (L[2], OP65_ORA); - - /* Invert the branch */ - CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC)); - - /* Delete the entries no longer needed. Beware: Deleting entries - * will change the indices. - */ - CS_DelEntry (S, I+4); /* jsr bnegax */ - CS_DelEntry (S, I+1); /* tax */ - - /* Remember, we had changes */ - ++Changes; - - } - - /* Next entry */ - ++I; - - } - - /* Return the number of changes made */ - return Changes; -} - - - -static unsigned OptNegAX3 (CodeSeg* S) -/* Search for the sequence: - * - * lda xx - * ldx yy - * jsr bnegax - * jne/jeq ... - * - * and replace it by - * - * lda xx - * ora xx+1 - * jeq/jne ... - */ -{ - unsigned Changes = 0; - - /* Walk over the entries */ - unsigned I = 0; - while (I < CS_GetEntryCount (S)) { - - CodeEntry* L[3]; - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Check for the sequence */ - if (E->OPC == OP65_LDA && - CS_GetEntries (S, L, I+1, 3) && - L[0]->OPC == OP65_LDX && - !CE_HasLabel (L[0]) && - CE_IsCall (L[1], "bnegax") && - !CE_HasLabel (L[1]) && - (L[2]->Info & OF_ZBRA) != 0 && - !CE_HasLabel (L[2])) { - - /* ldx --> ora */ - CE_ReplaceOPC (L[0], OP65_ORA); - - /* Invert the branch */ - CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC)); - - /* Delete the subroutine call */ - CS_DelEntry (S, I+2); - - /* Remember, we had changes */ - ++Changes; - - } - - /* Next entry */ - ++I; - - } - - /* Return the number of changes made */ - return Changes; -} - - - -static unsigned OptNegAX4 (CodeSeg* S) -/* Search for the sequence: - * - * jsr xxx - * jsr bnega(x) - * jeq/jne ... - * - * and replace it by: - * - * jsr xxx - * - * jne/jeq ... - */ -{ - unsigned Changes = 0; - - /* Walk over the entries */ - unsigned I = 0; - while (I < CS_GetEntryCount (S)) { - - CodeEntry* L[2]; - - /* Get next entry */ - CodeEntry* E = CS_GetEntry (S, I); - - /* Check for the sequence */ - if (E->OPC == OP65_JSR && - CS_GetEntries (S, L, I+1, 2) && - L[0]->OPC == OP65_JSR && - strncmp (L[0]->Arg,"bnega",5) == 0 && - !CE_HasLabel (L[0]) && - (L[1]->Info & OF_ZBRA) != 0 && - !CE_HasLabel (L[1])) { - - CodeEntry* X; - - /* Check if we're calling bnega or bnegax */ - int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0); - - /* Insert apropriate test code */ - if (ByteSized) { - /* Test bytes */ - X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI); - CS_InsertEntry (S, X, I+2); - } else { - /* Test words */ - X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+2); - X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI); - CS_InsertEntry (S, X, I+3); - } - - /* Delete the subroutine call */ - CS_DelEntry (S, I+1); - - /* Invert the branch */ - CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC)); - - /* Remember, we had changes */ - ++Changes; - - } - - /* Next entry */ - ++I; - - } - - /* Return the number of changes made */ - return Changes; -} - - - /*****************************************************************************/ /* Optimize stores through pointers */ /*****************************************************************************/ @@ -1403,7 +1027,118 @@ static unsigned OptDecouple (CodeSeg* S) -static unsigned OptSize (CodeSeg* S) +static unsigned OptSize1 (CodeSeg* S) +/* Do size optimization by calling special subroutines that preload registers. + * This routine does not work standalone, it needs a following register load + * removal pass. + */ +{ +#if 0 + static const char* Func = { + "stax0sp", /* staxysp, y = 0 */ + "addeq0sp", + "ldax0sp", /* ldaxysp, y = 1 */ + "ldeax0sp", /* ldeaxysp, y = 3 */ + "push0", /* pushax, a = 0, x = 0 */ + "pusha0", /* pushax, x = 0 */ + "pushaFF", /* pushax, x = ff */ + "pusha0sp", /* pushaysp, y = 0 */ + "tosadda0", /* tosaddax, x = 0 */ + "tosanda0", /* tosandax, x = 0 */ + "tosdiva0", /* tosdivax, x = 0 */ + "toseqa0", /* toseqax, x = 0 */ + "tosgea0", /* tosgeax, x = 0 */ + "tosgta0", /* tosgtax, x = 0 */ + "tosadd0ax", /* tosaddeax, sreg = 0 */ + "laddeqa", /* laddeq, sreg = 0, x = 0 */ + "laddeq1", /* laddeq, sreg = 0, x = 0, a = 1 */ + "laddeq0sp", /* laddeqysp, y = 0 */ + "tosand0ax", /* tosandeax, sreg = 0 */ + "ldaxi", /* ldaxidx, y = 1 */ + "ldeaxi", /* ldeaxidx, y = 3 */ + "ldeax0sp", /* ldeaxysp, y = 3 */ + "tosdiv0ax", /* tosdiveax, sreg = 0 */ + "toslea0", /* tosleax, x = 0 */ + "tosmod0ax", /* tosmodeax, sreg = 0 */ + "tosmul0ax", /* tosmuleax, sreg = 0 */ + "tosumul0ax", /* tosumuleax, sreg = 0 */ + "tosor0ax", /* tosoreax, sreg = 0 */ + "push0ax", /* pusheax, sreg = 0 */ + "tosrsub0ax", /* tosrsubeax, sreg = 0 */ + "tosshl0ax", /* tosshleax, sreg = 0 */ + "tosasl0ax", /* tosasleax, sreg = 0 */ + "tosshr0ax", /* tosshreax, sreg = 0 */ + "tosasr0ax", /* tosasreax, sreg = 0 */ + "tossub0ax", /* tossubeax, sreg = 0 */ + "lsubeqa", /* lsubeq, sreg = 0, x = 0 */ + "lsubeq1", /* lsubeq, sreg = 0, x = 0, a = 1 */ + "lsubeq0sp", /* lsubeqysp, y = 0 */ + "toslta0", /* tosltax, x = 0 */ + "tosudiv0ax", /* tosudiveax, sreg = 0 */ + "tosumod0ax", /* tosumodeax, sreg = 0 */ + "tosxor0ax", /* tosxoreax, sreg = 0 */ + "tosmoda0", /* tosmodax, x = 0 */ + "tosmula0", /* tosmulax, x = 0 */ + "tosumula0", /* tosumulax, x = 0 */ + "tosnea0", /* tosneax, x = 0 */ + "tosora0", /* tosorax, x = 0 */ + "push1", /* pushax, x = 0, a = 1 */ + "push2", /* pushax, x = 0, a = 2 */ + "push3", /* pushax, x = 0, a = 3 */ + "push4", /* pushax, x = 0, a = 4 */ + "push5", /* pushax, x = 0, a = 5 */ + "push6", /* pushax, x = 0, a = 6 */ + "push7", /* pushax, x = 0, a = 7 */ + "pushc0", /* pusha, a = 0 */ + "pushc1", /* pusha, a = 1 */ + "pushc2", /* pusha, a = 2 */ + "tosrsuba0", /* tosrsubax, x = 0 */ + "tosshla0", /* tosshlax, x = 0 */ + "tosasla0", /* tosaslax, x = 0 */ + "tosshra0", /* tosshrax, x = 0 */ + "tosasra0", /* tosasrax, x = 0 */ + "steax0sp", /* steaxsp, y = 0 */ + "tossuba0", /* tossubax, x = 0 */ + "subeq0sp", /* subeqysp, y = 0 */ + "tosudiva0", /* tosudivax, x = 0 */ + "tosugea0", /* tosugeax, x = 0 */ + "tosugta0", /* tosugtax, x = 0 */ + "tosulea0", /* tosuleax, x = 0 */ + "tosulta0", /* tosultax, x = 0 */ + "tosumoda0", /* tosumodax, x = 0 */ + "tosxora0", /* tosxorax, x = 0 */ + }; +#endif + + unsigned Changes = 0; + unsigned I; + + /* Generate register info for the following step */ + CS_GenRegInfo (S); + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + + /* Next entry */ + ++I; + + } + + /* Free register info */ + CS_FreeRegInfo (S); + + /* Return the number of changes made */ + return Changes; +} + + + +static unsigned OptSize2 (CodeSeg* S) /* Do size optimization by using shorter code sequences, even if this * introduces relations between instructions. This step must be one of the * last steps, because it makes further work much more difficult. @@ -1443,7 +1178,7 @@ static unsigned OptSize (CodeSeg* S) X = NewCodeEntry (OP65_INA, AM65_IMP, 0, 0, E->LI); } } - } + } break; case OP65_LDX: @@ -1564,7 +1299,8 @@ static OptFunc DOptPtrLoad6 = { OptPtrLoad6, "OptPtrLoad6", 0, 0, 0, 0 static OptFunc DOptPtrStore1 = { OptPtrStore1, "OptPtrStore1", 0, 0, 0, 0, 0 }; static OptFunc DOptPtrStore2 = { OptPtrStore2, "OptPtrStore2", 0, 0, 0, 0, 0 }; static OptFunc DOptShift1 = { OptShift1, "OptShift1", 0, 0, 0, 0, 0 }; -static OptFunc DOptSize = { OptSize, "OptSize", 0, 0, 0, 0, 0 }; +static OptFunc DOptSize1 = { OptSize1, "OptSize1", 0, 0, 0, 0, 0 }; +static OptFunc DOptSize2 = { OptSize2, "OptSize2", 0, 0, 0, 0, 0 }; static OptFunc DOptStackOps = { OptStackOps, "OptStackOps", 0, 0, 0, 0, 0 }; static OptFunc DOptStoreLoad = { OptStoreLoad, "OptStoreLoad", 0, 0, 0, 0, 0 }; static OptFunc DOptSub1 = { OptSub1, "OptSub1", 0, 0, 0, 0, 0 }; @@ -1602,22 +1338,23 @@ static OptFunc* OptFuncs[] = { &DOptNegAX2, &DOptNegAX3, &DOptNegAX4, - &DOptPtrStore1, - &DOptPtrStore2, &DOptPtrLoad1, &DOptPtrLoad2, &DOptPtrLoad3, &DOptPtrLoad4, &DOptPtrLoad5, &DOptPtrLoad6, + &DOptPtrStore1, + &DOptPtrStore2, &DOptRTS, &DOptRTSJumps, &DOptShift1, - &DOptSize, - &DOptSub1, - &DOptSub2, + &DOptSize1, + &DOptSize2, &DOptStackOps, &DOptStoreLoad, + &DOptSub1, + &DOptSub2, &DOptTest1, &DOptTransfers, &DOptUnusedLoads, @@ -1929,7 +1666,7 @@ static void RunOptGroup4 (CodeSeg* S) * if this does hinder further optimizations (no problem since we're * done soon). */ - RunOptFunc (S, &DOptSize, 1); + RunOptFunc (S, &DOptSize2, 1); /* Run the jump target optimization again, since the size optimization * above may have opened new oportunities. diff --git a/src/cc65/coptcmp.c b/src/cc65/coptcmp.c index 60a033cc7..38078477f 100644 --- a/src/cc65/coptcmp.c +++ b/src/cc65/coptcmp.c @@ -246,7 +246,7 @@ static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond) -static int IsImmCmp16 (CodeSeg* S, CodeEntry** L) +static int IsImmCmp16 (CodeEntry** L) /* Check if the instructions at L are an immidiate compare of a/x: * * @@ -405,7 +405,7 @@ unsigned OptBoolTrans (CodeSeg* S) /*****************************************************************************/ /* Optimizations for compares */ /*****************************************************************************/ - + unsigned OptCmp1 (CodeSeg* S) @@ -565,7 +565,7 @@ unsigned OptCmp3 (CodeSeg* S) CS_GetEntries (S, L, I+1, 5) && L[0]->OPC == OP65_LDX && !CE_HasLabel (L[0]) && - IsImmCmp16 (S, L+1)) { + IsImmCmp16 (L+1)) { if (L[1]->Num == 0 && L[3]->Num == 0) { /* The value is zero, we may use the simple code version. */ @@ -628,7 +628,7 @@ unsigned OptCmp4 (CodeSeg* S) CodeEntry* L[9]; /* Check for the sequence */ - if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (S, L+5)) { + if (IsLocalLoad16 (S, I, L, 9) && IsImmCmp16 (L+5)) { if (L[5]->Num == 0 && L[7]->Num == 0) { diff --git a/src/cc65/coptneg.c b/src/cc65/coptneg.c new file mode 100644 index 000000000..6aed9ccc2 --- /dev/null +++ b/src/cc65/coptneg.c @@ -0,0 +1,419 @@ +/*****************************************************************************/ +/* */ +/* coptneg.c */ +/* */ +/* Optimize negation sequences */ +/* */ +/* */ +/* */ +/* (C) 2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +/* cc65 */ +#include "codeent.h" +#include "codeinfo.h" +#include "coptneg.h" + + + +/*****************************************************************************/ +/* nega optimizations */ +/*****************************************************************************/ + + + +unsigned OptNegA1 (CodeSeg* S) +/* Check for + * + * ldx #$00 + * lda .. + * jsr bnega + * + * Remove the ldx if the lda does not use it. + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[2]; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check for a ldx */ + if (E->OPC == OP65_LDX && + E->AM == AM65_IMM && + (E->Flags & CEF_NUMARG) != 0 && + E->Num == 0 && + CS_GetEntries (S, L, I+1, 2) && + L[0]->OPC == OP65_LDA && + (L[0]->Use & REG_X) == 0 && + !CE_HasLabel (L[0]) && + CE_IsCall (L[1], "bnega") && + !CE_HasLabel (L[1])) { + + /* Remove the ldx instruction */ + CS_DelEntry (S, I); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +unsigned OptNegA2 (CodeSeg* S) +/* Check for + * + * lda .. + * jsr bnega + * jeq/jne .. + * + * Adjust the conditional branch and remove the call to the subroutine. + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[2]; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check for the sequence */ + if ((E->OPC == OP65_ADC || + E->OPC == OP65_AND || + E->OPC == OP65_DEA || + E->OPC == OP65_EOR || + E->OPC == OP65_INA || + E->OPC == OP65_LDA || + E->OPC == OP65_ORA || + E->OPC == OP65_PLA || + E->OPC == OP65_SBC || + E->OPC == OP65_TXA || + E->OPC == OP65_TYA) && + CS_GetEntries (S, L, I+1, 2) && + CE_IsCall (L[0], "bnega") && + !CE_HasLabel (L[0]) && + (L[1]->Info & OF_ZBRA) != 0 && + !CE_HasLabel (L[1])) { + + /* Invert the branch */ + CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC)); + + /* Delete the subroutine call */ + CS_DelEntry (S, I+1); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +/*****************************************************************************/ +/* negax optimizations */ +/*****************************************************************************/ + + + +unsigned OptNegAX1 (CodeSeg* S) +/* On a call to bnegax, if X is zero, the result depends only on the value in + * A, so change the call to a call to bnega. This will get further optimized + * later if possible. + */ +{ + unsigned Changes = 0; + unsigned I; + + /* Generate register info for this step */ + CS_GenRegInfo (S); + + /* Walk over the entries */ + I = 0; + while (I < CS_GetEntryCount (S)) { + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check if this is a call to bnegax, and if X is known and zero */ + if (E->RI->In.RegX == 0 && + CE_IsCall (E, "bnegax")) { + + /* We're cheating somewhat here ... */ + E->Arg[5] = '\0'; + E->Use &= ~REG_X; + + /* We had changes */ + ++Changes; + } + + /* Next entry */ + ++I; + + } + + /* Free register info */ + CS_FreeRegInfo (S); + + /* Return the number of changes made */ + return Changes; +} + + + +unsigned OptNegAX2 (CodeSeg* S) +/* Search for the sequence: + * + * lda (xx),y + * tax + * dey + * lda (xx),y + * jsr bnegax + * jne/jeq ... + * + * and replace it by + * + * lda (xx),y + * dey + * ora (xx),y + * jeq/jne ... + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[5]; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check for the sequence */ + if (E->OPC == OP65_LDA && + E->AM == AM65_ZP_INDY && + CS_GetEntries (S, L, I+1, 5) && + L[0]->OPC == OP65_TAX && + L[1]->OPC == OP65_DEY && + L[2]->OPC == OP65_LDA && + L[2]->AM == AM65_ZP_INDY && + strcmp (L[2]->Arg, E->Arg) == 0 && + !CE_HasLabel (L[2]) && + CE_IsCall (L[3], "bnegax") && + !CE_HasLabel (L[3]) && + (L[4]->Info & OF_ZBRA) != 0 && + !CE_HasLabel (L[4])) { + + /* lda --> ora */ + CE_ReplaceOPC (L[2], OP65_ORA); + + /* Invert the branch */ + CE_ReplaceOPC (L[4], GetInverseBranch (L[4]->OPC)); + + /* Delete the entries no longer needed. Beware: Deleting entries + * will change the indices. + */ + CS_DelEntry (S, I+4); /* jsr bnegax */ + CS_DelEntry (S, I+1); /* tax */ + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +unsigned OptNegAX3 (CodeSeg* S) +/* Search for the sequence: + * + * lda xx + * ldx yy + * jsr bnegax + * jne/jeq ... + * + * and replace it by + * + * lda xx + * ora xx+1 + * jeq/jne ... + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[3]; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check for the sequence */ + if (E->OPC == OP65_LDA && + CS_GetEntries (S, L, I+1, 3) && + L[0]->OPC == OP65_LDX && + !CE_HasLabel (L[0]) && + CE_IsCall (L[1], "bnegax") && + !CE_HasLabel (L[1]) && + (L[2]->Info & OF_ZBRA) != 0 && + !CE_HasLabel (L[2])) { + + /* ldx --> ora */ + CE_ReplaceOPC (L[0], OP65_ORA); + + /* Invert the branch */ + CE_ReplaceOPC (L[2], GetInverseBranch (L[2]->OPC)); + + /* Delete the subroutine call */ + CS_DelEntry (S, I+2); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + +unsigned OptNegAX4 (CodeSeg* S) +/* Search for the sequence: + * + * jsr xxx + * jsr bnega(x) + * jeq/jne ... + * + * and replace it by: + * + * jsr xxx + * + * jne/jeq ... + */ +{ + unsigned Changes = 0; + + /* Walk over the entries */ + unsigned I = 0; + while (I < CS_GetEntryCount (S)) { + + CodeEntry* L[2]; + + /* Get next entry */ + CodeEntry* E = CS_GetEntry (S, I); + + /* Check for the sequence */ + if (E->OPC == OP65_JSR && + CS_GetEntries (S, L, I+1, 2) && + L[0]->OPC == OP65_JSR && + strncmp (L[0]->Arg,"bnega",5) == 0 && + !CE_HasLabel (L[0]) && + (L[1]->Info & OF_ZBRA) != 0 && + !CE_HasLabel (L[1])) { + + CodeEntry* X; + + /* Check if we're calling bnega or bnegax */ + int ByteSized = (strcmp (L[0]->Arg, "bnega") == 0); + + /* Insert apropriate test code */ + if (ByteSized) { + /* Test bytes */ + X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[0]->LI); + CS_InsertEntry (S, X, I+2); + } else { + /* Test words */ + X = NewCodeEntry (OP65_STX, AM65_ZP, "tmp1", 0, L[0]->LI); + CS_InsertEntry (S, X, I+2); + X = NewCodeEntry (OP65_ORA, AM65_ZP, "tmp1", 0, L[0]->LI); + CS_InsertEntry (S, X, I+3); + } + + /* Delete the subroutine call */ + CS_DelEntry (S, I+1); + + /* Invert the branch */ + CE_ReplaceOPC (L[1], GetInverseBranch (L[1]->OPC)); + + /* Remember, we had changes */ + ++Changes; + + } + + /* Next entry */ + ++I; + + } + + /* Return the number of changes made */ + return Changes; +} + + + diff --git a/src/cc65/coptneg.h b/src/cc65/coptneg.h new file mode 100644 index 000000000..e7d12a16f --- /dev/null +++ b/src/cc65/coptneg.h @@ -0,0 +1,140 @@ +/*****************************************************************************/ +/* */ +/* coptneg.h */ +/* */ +/* Optimize negation sequences */ +/* */ +/* */ +/* */ +/* (C) 2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef COPTNEG_H +#define COPTNEG_H + + + +/* cc65 */ +#include "codeseg.h" + + + +/*****************************************************************************/ +/* nega optimizations */ +/*****************************************************************************/ + + + +unsigned OptNegA1 (CodeSeg* S); +/* Check for + * + * ldx #$00 + * lda .. + * jsr bnega + * + * Remove the ldx if the lda does not use it. + */ + +unsigned OptNegA2 (CodeSeg* S); +/* Check for + * + * lda .. + * jsr bnega + * jeq/jne .. + * + * Adjust the conditional branch and remove the call to the subroutine. + */ + + + +/*****************************************************************************/ +/* negax optimizations */ +/*****************************************************************************/ + + + +unsigned OptNegAX1 (CodeSeg* S); +/* On a call to bnegax, if X is zero, the result depends only on the value in + * A, so change the call to a call to bnega. This will get further optimized + * later if possible. + */ + +unsigned OptNegAX2 (CodeSeg* S); +/* Search for the sequence: + * + * lda (xx),y + * tax + * dey + * lda (xx),y + * jsr bnegax + * jne/jeq ... + * + * and replace it by + * + * lda (xx),y + * dey + * ora (xx),y + * jeq/jne ... + */ + +unsigned OptNegAX3 (CodeSeg* S); +/* Search for the sequence: + * + * lda xx + * ldx yy + * jsr bnegax + * jne/jeq ... + * + * and replace it by + * + * lda xx + * ora xx+1 + * jeq/jne ... + */ + +unsigned OptNegAX4 (CodeSeg* S); +/* Search for the sequence: + * + * jsr xxx + * jsr bnega(x) + * jeq/jne ... + * + * and replace it by: + * + * jsr xxx + * + * jne/jeq ... + */ + + + +/* End of coptneg.h */ + +#endif + + + diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 745d42b45..728dffc90 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -463,7 +463,7 @@ static void MakeConstIntExpr (ExprDesc* Expr, long Value) { Expr->Flags = E_MCONST; Expr->Type = type_int; - Expr->ConstVal = 1; + Expr->ConstVal = Value; } @@ -813,7 +813,7 @@ static void FunctionCall (int k, ExprDesc* lval) g_space (- (int) sizeofarg (CF_PTR)); pop (CF_PTR); } - + /* Skip T_PTR */ ++lval->Type; diff --git a/src/cc65/main.c b/src/cc65/main.c index e4d0d1d8b..cc9a7d0c0 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -277,7 +277,8 @@ static void CheckSegName (const char* Seg) -static void OptAddSource (const char* Opt, const char* Arg) +static void OptAddSource (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Add source lines as comments in generated assembler file */ { AddSource = 1; @@ -285,7 +286,8 @@ static void OptAddSource (const char* Opt, const char* Arg) -static void OptAnsi (const char* Opt, const char* Arg) +static void OptAnsi (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Compile in strict ANSI mode */ { ANSI = 1; @@ -293,7 +295,7 @@ static void OptAnsi (const char* Opt, const char* Arg) -static void OptBssName (const char* Opt, const char* Arg) +static void OptBssName (const char* Opt attribute ((unused)), const char* Arg) /* Handle the --bss-name option */ { /* Check for a valid name */ @@ -305,7 +307,8 @@ static void OptBssName (const char* Opt, const char* Arg) -static void OptCheckStack (const char* Opt, const char* Arg) +static void OptCheckStack (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Handle the --check-stack option */ { CheckStack = 1; @@ -313,7 +316,7 @@ static void OptCheckStack (const char* Opt, const char* Arg) -static void OptCodeName (const char* Opt, const char* Arg) +static void OptCodeName (const char* Opt attribute ((unused)), const char* Arg) /* Handle the --code-name option */ { /* Check for a valid name */ @@ -338,7 +341,8 @@ static void OptCodeSize (const char* Opt, const char* Arg) -static void OptCreateDep (const char* Opt, const char* Arg) +static void OptCreateDep (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Handle the --create-dep option */ { CreateDep = 1; @@ -354,13 +358,13 @@ static void OptCPU (const char* Opt, const char* Arg) } else if (strcmp (Arg, "65C02") == 0) { CPU = CPU_65C02; } else { - AbEnd ("Invalid CPU: `%s'", Arg); + AbEnd ("Invalid argument for %s: `%s'", Opt, Arg); } } -static void OptDataName (const char* Opt, const char* Arg) +static void OptDataName (const char* Opt attribute ((unused)), const char* Arg) /* Handle the --data-name option */ { /* Check for a valid name */ @@ -372,7 +376,8 @@ static void OptDataName (const char* Opt, const char* Arg) -static void OptDebug (const char* Opt, const char* Arg) +static void OptDebug (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Compiler debug mode */ { Debug = 1; @@ -380,7 +385,8 @@ static void OptDebug (const char* Opt, const char* Arg) -static void OptDebugInfo (const char* Opt, const char* Arg) +static void OptDebugInfo (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Add debug info to the object file */ { DebugInfo = 1; @@ -388,7 +394,7 @@ static void OptDebugInfo (const char* Opt, const char* Arg) -static void OptDebugOpt (const char* Opt, const char* Arg) +static void OptDebugOpt (const char* Opt attribute ((unused)), const char* Arg) /* Debug optimization steps */ { char Buf [128]; @@ -455,7 +461,7 @@ static void OptDebugOpt (const char* Opt, const char* Arg) -static void OptDisableOpt (const char* Opt, const char* Arg) +static void OptDisableOpt (const char* Opt attribute ((unused)), const char* Arg) /* Disable an optimization step */ { DisableOpt (Arg); @@ -463,7 +469,7 @@ static void OptDisableOpt (const char* Opt, const char* Arg) -static void OptEnableOpt (const char* Opt, const char* Arg) +static void OptEnableOpt (const char* Opt attribute ((unused)), const char* Arg) /* Enable an optimization step */ { EnableOpt (Arg); @@ -471,7 +477,8 @@ static void OptEnableOpt (const char* Opt, const char* Arg) -static void OptHelp (const char* Opt, const char* Arg) +static void OptHelp (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Print usage information and exit */ { Usage (); @@ -480,7 +487,7 @@ static void OptHelp (const char* Opt, const char* Arg) -static void OptIncludeDir (const char* Opt, const char* Arg) +static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg) /* Add an include search path */ { AddIncludePath (Arg, INC_SYS | INC_USER); @@ -488,7 +495,8 @@ static void OptIncludeDir (const char* Opt, const char* Arg) -static void OptListOptSteps (const char* Opt, const char* Arg) +static void OptListOptSteps (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* List all optimizer steps */ { /* List the optimizer steps */ @@ -500,7 +508,7 @@ static void OptListOptSteps (const char* Opt, const char* Arg) -static void OptRodataName (const char* Opt, const char* Arg) +static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg) /* Handle the --rodata-name option */ { /* Check for a valid name */ @@ -512,7 +520,8 @@ static void OptRodataName (const char* Opt, const char* Arg) -static void OptSignedChars (const char* Opt, const char* Arg) +static void OptSignedChars (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Make default characters signed */ { SignedChars = 1; @@ -520,7 +529,8 @@ static void OptSignedChars (const char* Opt, const char* Arg) -static void OptStaticLocals (const char* Opt, const char* Arg) +static void OptStaticLocals (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Place local variables in static storage */ { StaticLocals = 1; @@ -528,7 +538,7 @@ static void OptStaticLocals (const char* Opt, const char* Arg) -static void OptTarget (const char* Opt, const char* Arg) +static void OptTarget (const char* Opt attribute ((unused)), const char* Arg) /* Set the target system */ { SetSys (Arg); @@ -536,7 +546,8 @@ static void OptTarget (const char* Opt, const char* Arg) -static void OptVerbose (const char* Opt, const char* Arg) +static void OptVerbose (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Increase verbosity */ { ++Verbosity; @@ -544,7 +555,8 @@ static void OptVerbose (const char* Opt, const char* Arg) -static void OptVersion (const char* Opt, const char* Arg) +static void OptVersion (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) /* Print the assembler version */ { fprintf (stderr, diff --git a/src/cc65/make/gcc.mak b/src/cc65/make/gcc.mak index f0848f198..e3e28f9e8 100644 --- a/src/cc65/make/gcc.mak +++ b/src/cc65/make/gcc.mak @@ -14,7 +14,7 @@ COMMON = ../common # Default for the compiler lib search path as compiler define CDEFS=-DCC65_INC=\"/usr/lib/cc65/include/\" -CFLAGS = -O2 -g -Wall -W -Wno-unused-parameter -I$(COMMON) $(CDEFS) +CFLAGS = -O2 -g -Wall -W -I$(COMMON) $(CDEFS) CC=gcc EBIND=emxbind LDFLAGS= @@ -36,6 +36,7 @@ OBJS = anonname.o \ coptadd.o \ coptcmp.o \ coptind.o \ + coptneg.o \ coptstop.o \ coptsub.o \ copttest.o \ diff --git a/src/cc65/make/watcom.mak b/src/cc65/make/watcom.mak index 270998fe9..2bb9a4326 100644 --- a/src/cc65/make/watcom.mak +++ b/src/cc65/make/watcom.mak @@ -81,6 +81,7 @@ OBJS = anonname.obj \ coptadd.obj \ coptcmp.obj \ coptind.obj \ + coptneg.obj \ coptstop.obj \ coptsub.obj \ copttest.obj \ @@ -155,6 +156,7 @@ FILE compile.obj FILE coptadd.obj FILE coptcmp.obj FILE coptind.obj +FILE coptneg.obj FILE coptstop.obj FILE coptsub.obj FILE copttest.obj diff --git a/src/cc65/stdfunc.c b/src/cc65/stdfunc.c index d3fc5ddab..ff554a393 100644 --- a/src/cc65/stdfunc.c +++ b/src/cc65/stdfunc.c @@ -107,7 +107,7 @@ static struct StdFuncDesc* FindFunc (const char* Name) -static void StdFunc_strlen (ExprDesc* lval) +static void StdFunc_strlen (ExprDesc* lval attribute ((unused))) /* Handle the strlen function */ { ExprDesc pval;