1
// =============================================================================
3
// --- kvi_memmove.cpp ---
5
// This file is part of the KVIrc IRC client distribution
6
// Copyright (C) 1999-2000 Szymon Stefanek (stefanek@tin.it)
8
// This program is FREE software. You can redistribute it and/or
9
// modify it under the terms of the GNU General Public License
10
// as published by the Free Software Foundation; either version 2
11
// of the License, or (at your opinion) any later version.
13
// This program is distributed in the HOPE that it will be USEFUL,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
// See the GNU General Public License for more details.
18
// You should have received a copy of the GNU General Public License
19
// along with this program. If not, write to the Free Software Foundation,
20
// Inc, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
// =============================================================================
24
#include "kvi_debug.h"
25
#include "kvi_settings.h"
27
#define _KVI_MEMMOVE_CPP_
29
#ifdef COMPILE_i386_ASM_CODE
31
void *kvi_memmove(void *dst_ptr, const void *src_ptr, int len)
33
__range_valid(dst_ptr);
34
__range_valid(src_ptr);
35
__range_valid(len >= 0);
36
// Save pointer registers
37
asm(" pushl %esi"); // Save %esi
38
asm(" pushl %edi"); // Save %edi
40
asm(" movl 16(%ebp),%ecx"); // %ecx = len
41
asm(" movl 12(%ebp),%esi"); // %esi = src
42
asm(" movl 8(%ebp),%edi"); // %edi = dst
43
// Compare src and dest
44
asm(" cmpl %esi,%edi"); // %edi - %esi
45
asm(" jbe move_from_bottom_to_top"); // If( %edi < %esi ) jump to move_from_bottom_to_top
47
asm(" addl %ecx,%esi"); // %esi += %ecx (src_ptr += len);
48
asm(" addl %ecx,%edi"); // %edi += %ecx (dst_ptr += len);
49
asm(" decl %esi"); // %esi--; (src_ptr--);
50
asm(" decl %edi"); // %edi--; (dst_ptr--);
51
asm(" std"); // Set direction flag (decrement esi and edi in movsb)
52
// Optimization : check for non-odd len (1, 3, 5, 7...)
53
asm(" shr $1,%ecx"); // %ecx >> 1, shifted bit -> CF
54
asm(" jnc move_two_bytes_top_to_bottom_directly"); // If !carry (CF == 0) skip this move
55
// Move the first byte (non-odd)
56
asm(" movsb %ds:(%esi),%es:(%edi)"); // *dst-- = *src-- if DF else *dst++ = *src++
57
asm("move_two_bytes_top_to_bottom_directly:");
58
asm(" decl %esi"); // %esi--; (src_ptr--);
59
asm(" decl %edi"); // %edi--; (dst_ptr--);
60
asm("move_two_bytes_top_to_bottom:");
61
asm(" shr $1,%ecx"); // %ecx >> 1, shifted bit -> CF
62
asm(" jnc move_the_rest_top_to_bottom_directly"); // If !carry (CF == 0) skip this move
63
// Move the next two bytes
64
asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++
65
asm("move_the_rest_top_to_bottom_directly:");
66
asm(" subl $2,%esi"); // %esi -= 2; (src -= 2);
67
asm(" subl $2,%edi"); // %edi -= 2; (dst -= 2);
68
asm(" jmp move_the_rest"); // Call last repnz movsl
70
asm("move_from_bottom_to_top:");
71
asm(" cld"); // Clear direction flag (increment esi and edi in movsb)
72
// Optimization : check for non-odd len (1, 3, 5, 7...)
73
asm(" shr $1,%ecx"); // %ecx >> 1, shifted bit -> CF
74
asm(" jnc move_two_bytes"); // If !carry (CF == 0) skip this move
75
// Move the first byte (non-odd)
76
asm(" movsb %ds:(%esi),%es:(%edi)"); // *dst-- = *src-- if DF else *dst++ = *src++
77
// Optimization : pass 2, check for %2 and %3
78
asm("move_two_bytes:");
79
asm(" shr $1,%ecx"); // %ecx >> 1, shifted bit -> CF
80
asm(" jnc move_the_rest"); // If !carry (CF == 0) skip this move
81
// Move the next two bytes
82
asm(" movsw %ds:(%esi),%es:(%edi)"); // *((word *)dst)-- = *((word)src)-- if DF else *((word *)dst)++ = *((word)src)++
83
// Main move remaining part
84
asm("move_the_rest:");
85
asm(" repnz; movsl %ds:(%esi),%es:(%edi)"); // Loop moving 4 bytes at once (increment or decrement as above)
86
// Restore pointer registers
87
asm(" popl %edi"); // Restore %edi
88
asm(" popl %esi"); // Restore %esi
93
#else // COMPILE_i386_ASM_CODE
95
void *kvi_memmove(void *dst_ptr, const void *src_ptr, int len)
97
__range_valid(dst_ptr);
98
__range_valid(src_ptr);
99
__range_valid(len >= 0);
102
if( dst_ptr > src_ptr ) {
103
dst = (char *) dst_ptr + len - 1;
104
src = (char *) src_ptr + len - 1;
105
while( len-- ) *dst-- = *src--;
107
// It is valid even if dst_ptr == src_ptr
108
dst = (char *) dst_ptr;
109
src = (char *) src_ptr;
119
void kvi_fastmove(void *dst_ptr, const void *src_ptr, int len)
121
__range_valid(dst_ptr);
122
__range_valid(src_ptr);
123
__range_valid(len >= 0);
124
register const char *src = (const char *) src_ptr;
125
register char *dst = (char *) dst_ptr;
133
#endif // COMPILE_i386_ASM_CODE