From: Maarten B. <sou...@ds...> - 2012-06-27 10:34:25
|
Philipp, > Dear sdcc developers, > > in sdcc there currently are 3 string functions, which do not have > standard-compliant prototypes for some ports. The functions are > > strchr(), strrchr() and memset(). > > the ports are > > mcs51, hc08, ds390, pic14 and pic16. > > These ports define __SDCC_BROKEN_STRING_FUNCTIONS. > The non-compliance is in the type of parameter c being char instead of int. > > For full standard compliance, which I would prefer, the type of c should > be changed to int for these ports. > > On the other hand using char saves a byte of parameter passing, which > can make a small difference in code size and speed. When your memory is small 1 byte is not a small difference. For mcs51-small there are about 100 bytes in DSEG and this extra parameter byte consumes it. And when will this byte ever be used? It is useless by definition. > However, I think I have now come up with a solution, which provides > standard-compliance, reduces code size and increases code speed over the > current situation. > > Looking at typical source code, out of these three functions, only > memset() is common. E.g. in the source code of the NuttX operating > system there are 26 occourances of strchr(), 6 occourances of strrchr() > and 224 occourances of memset(). For memset(), nearly all occourances > have an integer constant as the second and third parameter. The third > parameter is nearly always smaller than 256. > In our regression test suite the situation is similar: strchr() and > strrchr() occour only in the tests specifically designed to test them > (exception: one strchr() call in gcc-torture-execute-20000910-2.c). > memset() on the other hand is used frequently, and the parameters c and > n are often constant, with the latter typically less than 256. > > My proposal is to make all ports behave as the z80 port does: Provide a > builtin for memset() and change the type for all three functions. For > strchr() and strrchr() the difference in code size and speed doesn't > really matter, since they are rarely used. The often-used memset() gets > faster by being a builtin, and the resulting code is smaller than the > call overhead would be. > > Here are some examples: > > For hc08 / s08 with a constant parameter c and constant parameter n at > most 256: > > %1 > mov ,x+, c > dbnza %1 > > Just 4 bytes of code. > > For mcs51, with constant parameter n at most 256: > > %1: > lcall __gptrput > inc dptr > djnz r6,%1 > > Just 6 bytes of code. > > They get a bit bigger if one wants to handle non-constant n or > non-constant c, or bigger n, but it still seems to be less than the call > overhead (alternatively, these relatively rare cases can be handled > through the normal memset() function). > > For the z80-related ports (except gbz80) this is already implemented: > For constant parameter n they have a builtin memset() that uses the ldir > instruction, which in code size is smaller than the call overhead (the > smallopts branch contains an improved version which is even better for > small n). > > Philipp I can see how a builtin memset could give smaller and faster code. However I don't see this as a high priority thing. Maarten |