+2009-01-04 Philipp Klaus Krause <pkk AT spth.de>
+
+ * src/z80/peeph-z80.def:
+ Peephole improvements.
+ * src/z80/gen.c,
+ src/z80/main.c,
+ device/include/string.h,
+ device/lib/z80/memmove.s:
+ Minor code cleanup.
+ * device/lib/z80/Makefile.in,
+ device/lib/Makefile.in,
+ support/regression/tests/memory.c,
+ device/lib/z80/strlen.s:
+ Partially implemented RFE #2471534.
+
2009-01-04 Borut Razem <borut.razem AT siol.net>
* .version, doc/sdccman.lyx: bumped sdcc version to 2.8.6
extern int strlen (char * ) ;
extern char *strtok (char *, char *) ;
extern void *memcpy (void *, void *, size_t ) ;
-#ifdef SDCC_z80
-#define memcpy(dst, src, n) __builtin_memcpy(dst, src, n)
-#endif
extern int memcmp (void *, void *, size_t ) ;
extern void *memset (void *, unsigned char , size_t ) ;
extern void *memmove (void *, void *, size_t ) ;
extern void __xdata * memcpyx(void __xdata *, void __xdata *, int) __naked;
#endif
+#ifdef SDCC_z80
+#define memcpy(dst, src, n) __builtin_memcpy(dst, src, n)
+#endif
#endif
_islower.c _isupper.c _isxdigit.c \
_startup.c \
_strcat.c _strchr.c _strcmp.c _strcpy.c \
- _strcspn.c _strlen.c _strncat.c _strncmp.c \
+ _strcspn.c _strncat.c _strncmp.c \
_strncpy.c _strpbrk.c _strrchr.c _strspn.c \
_strstr.c _strtok.c \
_memcmp.c _memcpy.c _memset.c \
SCC = $(TOPDIR)/bin/sdcc -mz80
SAS = $(TOPDIR)/bin/as-z80
-OBJ = div.o mul.o putchar.o shift.o stubs.o crt0_rle.o heap.o fstubs.o memmove.o
+OBJ = div.o mul.o putchar.o shift.o stubs.o crt0_rle.o heap.o fstubs.o memmove.o strlen.o
LIB = z80.lib
CC = $(SCC)
_memmove:
push ix
- ld ix,#0
- add ix,sp
+ ld ix, #0
+ add ix, sp
ld c, 8(ix)
ld b, 9(ix)
ld a, c
--- /dev/null
+ .area _CODE
+
+ .globl _strlen
+
+; The Z80 has the cpir instruction, which is perfect for implementing strlen().
+
+_strlen:
+ push ix
+ ld ix, #0
+ add ix, sp
+ ld l, 4(ix)
+ ld h, 5(ix)
+ xor a, a
+ ld b, a
+ ld c, a
+ cpir
+ ld hl, #-1
+ sbc hl, bc ; C flag still cleared from xor above.
+ pop ix
+ ret
+
}
static void
-setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
+setupForMemcpy (iCode *ic, int nparams, operand **pparams)
{
PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
PAIR_ID dest[3] = {
}
}
-/*static void
-genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
-{
- operand *from, *to;
- symbol *label;
- bool deInUse;
-
- wassertl (nParams == 2, "Built-in strcpy must have two parameters");
- to = pparams[0];
- from = pparams[1];
-
- deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
-
- _saveRegsForCall (ic, 0);
-
- setupForBuiltin3 (ic, nParams, pparams);
-
- label = newiTempLabel(NULL);
-
- emitLabel (label->key);
- emit2 ("ld a,(hl)");
- emit2 ("ldi");
- emit2 ("or a");
- emit2 ("!shortjp NZ,!tlabel ; 1", label->key);
-
- freeAsmop (from, NULL, ic->next);
- freeAsmop (to, NULL, ic);
-}*/
-
static void
genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
{
operand *from, *to, *count;
- wassertl (nParams == 3, "Built-in memcpy must have three parameters");
+ wassertl (nParams == 3, "Built-in memcpy() must have three parameters");
to = pparams[2];
from = pparams[1];
count = pparams[0];
_saveRegsForCall (ic, 0);
- setupForBuiltin3 (ic, nParams, pparams);
+ setupForMemcpy (ic, nParams, pparams);
emit2 ("ldir");
freeAsmop (count, NULL, ic->next->next);
freeAsmop (from, NULL, ic);
+ spillPair (PAIR_HL);
+
_restoreRegsAfterCall();
/* if we need assign a result value */
/* which function is it */
bif = OP_SYMBOL(IC_LEFT(bi_iCode));
- /*if (strcmp(bif->name,"__builtin_strcpy")==0)
- {
- genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
- }
- else*/ if (strcmp(bif->name,"__builtin_memcpy")==0)
+ if (strcmp(bif->name,"__builtin_memcpy")==0)
{
genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
}
#include "mappings.i"
static builtins _z80_builtins[] = {
- /* Disabled for now.
- { "__builtin_strcpy", "v", 2, {"cg*", "cg*" } },*/
{ "__builtin_memcpy", "vg*", 3, {"vg*", "vg*", "ui" } },
- { NULL , NULL,0, {NULL}}
+ { NULL , NULL, 0, {NULL}}
};
static void
ex de,hl
push de
} by {
- ; peephole 0k' pushed de directly instead of going through hl.
+ ; peephole 0k' pushed hl directly instead of going through de.
push hl
} if notUsed('de'), notUsed('hl')
+replace restart {
+ ld l,%1
+ ld h,d
+ push hl
+} by {
+ ; peephole 0k'' pushed de instead of hl removing a load.
+ ld e,%1
+ push de
+} if notUsed('hl'), notUsed('e')
+
replace restart {
ex de,hl
push bc
push bc
} if notUsed('hl')
+replace restart {
+ ld l,%1
+ ld h,b
+ push hl
+} by {
+ ; peephole 0m' pushed bc instead of hl removing a load.
+ ld c,%1
+ push bc
+} if notUsed('hl'), notUsed('c')
+
replace restart {
ld c,a
push de
//add %3, %4
} by {
add a, a
- ; peephole 42b shifts in accumulator insted of %1
+ ; peephole 42b shifted in accumulator insted of %1
+ ld %1, a
+ ld a, %2
+ //add %3, %4
+}
+
+// sdcc does not use the H flag. sla resets it, while add sets it.
+// To ensure that the state of the H flag is not changed by this
+// peephole uncomment the add %3, %4 at the end (since it overwrite the H flag).
+replace restart {
+ ld %1, a
+ sla %1
+ sla %1
+ ld a, %2
+ //add %3, %4
+} by {
+ add a, a
+ add a, a
+ ; peephole 42b' shifted in accumulator insted of %1
ld %1, a
ld a, %2
//add %3, %4
; peephole 78 removed addition and loads exploiting commutativity of addition.
} if notUsed('de')
+replace restart {
+ ex de, hl
+ ld hl, #%1
+ add hl, de
+} by {
+ ; peephole 78a removed ex exploiting commutativity of addition.
+ ld de, #%1
+ add hl, de
+} if notUsed('de')
+
+replace restart {
+ ld hl, #%1
+ add hl, %2
+ ex de, hl
+ inc de
+} by {
+ ld hl, #%1+1
+ ; peephole 79 moved increment to constant.
+ add hl, %2
+ ex de, hl
+} if notUsed('hl')
+
// These ex-generating rules should be among the last ones since ex counts as a read from both hl and de for notUsed().
replace restart {
ld d,h
ASSERT(NULL == memchr(destination, 5, 4));
ASSERT(destination == memchr(destination, 0, 4));
ASSERT(destination + 3 == memchr(destination, 3, 4));*/
+
+ ASSERT(strlen("test") == 4);
+ ASSERT(strlen("t") == 1);
+ ASSERT(strlen("") == 0);
}