~ubuntu-branches/ubuntu/hoary/kvirc/hoary

« back to all changes in this revision

Viewing changes to src/kvilib/core/kvi_memmove.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Robin Verduijn
  • Date: 2004-12-14 15:32:19 UTC
  • mfrom: (0.2.1 upstream) (1.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20041214153219-fdink3gyp2s20b6g
Tags: 2:2.1.3.1-2
* Change Recommends on xmms to a Suggests.
* Rebuild against KDE 3.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// =============================================================================
 
2
//
 
3
//      --- kvi_memmove.cpp ---
 
4
//
 
5
//   This file is part of the KVIrc IRC client distribution
 
6
//   Copyright (C) 1999-2000 Szymon Stefanek (stefanek@tin.it)
 
7
//
 
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.
 
12
//
 
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.
 
17
//
 
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.
 
21
//
 
22
// =============================================================================
 
23
 
 
24
#include "kvi_debug.h"
 
25
#include "kvi_settings.h"
 
26
 
 
27
#define _KVI_MEMMOVE_CPP_
 
28
 
 
29
#ifdef COMPILE_i386_ASM_CODE
 
30
 
 
31
void *kvi_memmove(void *dst_ptr, const void *src_ptr, int len)
 
32
{
 
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
 
39
        // Load arguments
 
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
 
46
        // dst_ptr > src_ptr
 
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
 
69
        // dst_ptr <= src_ptr
 
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
 
89
 
 
90
        return dst_ptr;
 
91
}
 
92
 
 
93
#else // COMPILE_i386_ASM_CODE
 
94
 
 
95
void *kvi_memmove(void *dst_ptr, const void *src_ptr, int len)
 
96
{
 
97
        __range_valid(dst_ptr);
 
98
        __range_valid(src_ptr);
 
99
        __range_valid(len >= 0);
 
100
        register char *dst;
 
101
        register char *src;
 
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--;
 
106
        } else {
 
107
                // It is valid even if dst_ptr == src_ptr
 
108
                dst = (char *) dst_ptr;
 
109
                src = (char *) src_ptr;
 
110
                while( len-- ) {
 
111
                        *dst = *src;
 
112
                        dst++;
 
113
                        src++;
 
114
                }
 
115
        }
 
116
        return dst_ptr;
 
117
}
 
118
 
 
119
void kvi_fastmove(void *dst_ptr, const void *src_ptr, int len)
 
120
{
 
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;
 
126
        while( len-- ) {
 
127
                *dst = *src;
 
128
                dst++;
 
129
                src++;
 
130
        }
 
131
}
 
132
 
 
133
#endif // COMPILE_i386_ASM_CODE