@@ -3,66 +3,73 @@ use core::intrinsics::likely;
3
3
const WORD_SIZE : usize = core:: mem:: size_of :: < usize > ( ) ;
4
4
const WORD_MASK : usize = WORD_SIZE - 1 ;
5
5
6
+ // If the number of bytes involved exceed this threshold we will opt in word-wise copy.
7
+ // The value here selected is max(2 * WORD_SIZE, 16):
8
+ // * We need at least 2 * WORD_SIZE bytes to guarantee that at least 1 word will be copied through
9
+ // word-wise copy.
10
+ // * The word-wise copy logic needs to perform some checks so it has some small overhead.
11
+ // ensures that even on 32-bit platforms we have copied at least 8 bytes through
12
+ // word-wise copy so the saving of word-wise copy outweights the fixed overhead.
6
13
const WORD_COPY_THRESHOLD : usize = if 2 * WORD_SIZE > 16 {
7
14
2 * WORD_SIZE
8
15
} else {
9
16
16
10
17
} ;
11
18
12
19
#[ inline( always) ]
13
- unsafe fn copy_forward_bytes ( mut dest : * mut u8 , mut src : * const u8 , n : usize ) {
14
- let dest_end = dest. add ( n) ;
15
- while dest < dest_end {
16
- * dest = * src;
17
- dest = dest. add ( 1 ) ;
18
- src = src. add ( 1 ) ;
20
+ pub unsafe fn copy_forward ( mut dest : * mut u8 , mut src : * const u8 , mut n : usize ) {
21
+ #[ inline( always) ]
22
+ unsafe fn copy_forward_bytes ( mut dest : * mut u8 , mut src : * const u8 , n : usize ) {
23
+ let dest_end = dest. add ( n) ;
24
+ while dest < dest_end {
25
+ * dest = * src;
26
+ dest = dest. add ( 1 ) ;
27
+ src = src. add ( 1 ) ;
28
+ }
19
29
}
20
- }
21
30
22
- #[ inline( always) ]
23
- unsafe fn copy_forward_aligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
24
- let mut dest_usize = dest as * mut usize ;
25
- let mut src_usize = src as * mut usize ;
26
- let dest_end = dest. add ( n) as * mut usize ;
27
-
28
- while dest_usize < dest_end {
29
- * dest_usize = * src_usize;
30
- dest_usize = dest_usize. add ( 1 ) ;
31
- src_usize = src_usize. add ( 1 ) ;
31
+ #[ inline( always) ]
32
+ unsafe fn copy_forward_aligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
33
+ let mut dest_usize = dest as * mut usize ;
34
+ let mut src_usize = src as * mut usize ;
35
+ let dest_end = dest. add ( n) as * mut usize ;
36
+
37
+ while dest_usize < dest_end {
38
+ * dest_usize = * src_usize;
39
+ dest_usize = dest_usize. add ( 1 ) ;
40
+ src_usize = src_usize. add ( 1 ) ;
41
+ }
32
42
}
33
- }
34
43
35
- #[ inline( always) ]
36
- unsafe fn copy_forward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
37
- let mut dest_usize = dest as * mut usize ;
38
- let dest_end = dest. add ( n) as * mut usize ;
39
-
40
- // Calculate the misalignment offset and shift needed to reassemble value.
41
- let offset = src as usize & WORD_MASK ;
42
- let shift = offset * 8 ;
43
-
44
- // Realign src
45
- let mut src_aligned = ( src as usize & !WORD_MASK ) as * mut usize ;
46
- // XXX: Could this possibly be UB?
47
- let mut prev_word = * src_aligned;
48
-
49
- while dest_usize < dest_end {
50
- src_aligned = src_aligned. add ( 1 ) ;
51
- let cur_word = * src_aligned;
52
- #[ cfg( target_endian = "little" ) ]
53
- let resembled = prev_word >> shift | cur_word << ( WORD_SIZE * 8 - shift) ;
54
- #[ cfg( target_endian = "big" ) ]
55
- let resembled = prev_word << shift | cur_word >> ( WORD_SIZE * 8 - shift) ;
56
- prev_word = cur_word;
57
-
58
- * dest_usize = resembled;
59
- dest_usize = dest_usize. add ( 1 ) ;
44
+ #[ inline( always) ]
45
+ unsafe fn copy_forward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
46
+ let mut dest_usize = dest as * mut usize ;
47
+ let dest_end = dest. add ( n) as * mut usize ;
48
+
49
+ // Calculate the misalignment offset and shift needed to reassemble value.
50
+ let offset = src as usize & WORD_MASK ;
51
+ let shift = offset * 8 ;
52
+
53
+ // Realign src
54
+ let mut src_aligned = ( src as usize & !WORD_MASK ) as * mut usize ;
55
+ // XXX: Could this possibly be UB?
56
+ let mut prev_word = * src_aligned;
57
+
58
+ while dest_usize < dest_end {
59
+ src_aligned = src_aligned. add ( 1 ) ;
60
+ let cur_word = * src_aligned;
61
+ #[ cfg( target_endian = "little" ) ]
62
+ let resembled = prev_word >> shift | cur_word << ( WORD_SIZE * 8 - shift) ;
63
+ #[ cfg( target_endian = "big" ) ]
64
+ let resembled = prev_word << shift | cur_word >> ( WORD_SIZE * 8 - shift) ;
65
+ prev_word = cur_word;
66
+
67
+ * dest_usize = resembled;
68
+ dest_usize = dest_usize. add ( 1 ) ;
69
+ }
60
70
}
61
- }
62
71
63
- #[ inline( always) ]
64
- pub unsafe fn copy_forward ( mut dest : * mut u8 , mut src : * const u8 , mut n : usize ) {
65
- if likely ( n >= WORD_COPY_THRESHOLD ) {
72
+ if n >= WORD_COPY_THRESHOLD {
66
73
// Align dest
67
74
// Because of n >= 2 * WORD_SIZE, dst_misalignment < n
68
75
let dest_misalignment = ( dest as usize ) . wrapping_neg ( ) & WORD_MASK ;
@@ -85,66 +92,65 @@ pub unsafe fn copy_forward(mut dest: *mut u8, mut src: *const u8, mut n: usize)
85
92
copy_forward_bytes ( dest, src, n) ;
86
93
}
87
94
88
- // The following backward copy helper functions except the public-facing copy_backward
89
- // uses the pointers past the end as their inputs instead of pointers to the start!
90
-
91
95
#[ inline( always) ]
92
- unsafe fn copy_backward_bytes ( mut dest : * mut u8 , mut src : * const u8 , n : usize ) {
93
- let dest_start = dest. sub ( n) ;
94
- while dest_start < dest {
95
- dest = dest. sub ( 1 ) ;
96
- src = src. sub ( 1 ) ;
97
- * dest = * src;
96
+ pub unsafe fn copy_backward ( dest : * mut u8 , src : * const u8 , mut n : usize ) {
97
+ // The following backward copy helper functions uses the pointers past the end
98
+ // as their inputs instead of pointers to the start!
99
+ #[ inline( always) ]
100
+ unsafe fn copy_backward_bytes ( mut dest : * mut u8 , mut src : * const u8 , n : usize ) {
101
+ let dest_start = dest. sub ( n) ;
102
+ while dest_start < dest {
103
+ dest = dest. sub ( 1 ) ;
104
+ src = src. sub ( 1 ) ;
105
+ * dest = * src;
106
+ }
98
107
}
99
- }
100
108
101
- #[ inline( always) ]
102
- unsafe fn copy_backward_aligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
103
- let mut dest_usize = dest as * mut usize ;
104
- let mut src_usize = src as * mut usize ;
105
- let dest_start = dest. sub ( n) as * mut usize ;
106
-
107
- while dest_start < dest_usize {
108
- dest_usize = dest_usize. sub ( 1 ) ;
109
- src_usize = src_usize. sub ( 1 ) ;
110
- * dest_usize = * src_usize;
109
+ #[ inline( always) ]
110
+ unsafe fn copy_backward_aligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
111
+ let mut dest_usize = dest as * mut usize ;
112
+ let mut src_usize = src as * mut usize ;
113
+ let dest_start = dest. sub ( n) as * mut usize ;
114
+
115
+ while dest_start < dest_usize {
116
+ dest_usize = dest_usize. sub ( 1 ) ;
117
+ src_usize = src_usize. sub ( 1 ) ;
118
+ * dest_usize = * src_usize;
119
+ }
111
120
}
112
- }
113
121
114
- #[ inline( always) ]
115
- unsafe fn copy_backward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
116
- let mut dest_usize = dest as * mut usize ;
117
- let dest_start = dest. sub ( n) as * mut usize ;
118
-
119
- // Calculate the misalignment offset and shift needed to reassemble value.
120
- let offset = src as usize & WORD_MASK ;
121
- let shift = offset * 8 ;
122
-
123
- // Realign src_aligned
124
- let mut src_aligned = ( src as usize & !WORD_MASK ) as * mut usize ;
125
- // XXX: Could this possibly be UB?
126
- let mut prev_word = * src_aligned;
127
-
128
- while dest_start < dest_usize {
129
- src_aligned = src_aligned. sub ( 1 ) ;
130
- let cur_word = * src_aligned;
131
- #[ cfg( target_endian = "little" ) ]
132
- let resembled = prev_word << ( WORD_SIZE * 8 - shift) | cur_word >> shift;
133
- #[ cfg( target_endian = "big" ) ]
134
- let resembled = prev_word >> ( WORD_SIZE * 8 - shift) | cur_word << shift;
135
- prev_word = cur_word;
136
-
137
- dest_usize = dest_usize. sub ( 1 ) ;
138
- * dest_usize = resembled;
122
+ #[ inline( always) ]
123
+ unsafe fn copy_backward_misaligned_words ( dest : * mut u8 , src : * const u8 , n : usize ) {
124
+ let mut dest_usize = dest as * mut usize ;
125
+ let dest_start = dest. sub ( n) as * mut usize ;
126
+
127
+ // Calculate the misalignment offset and shift needed to reassemble value.
128
+ let offset = src as usize & WORD_MASK ;
129
+ let shift = offset * 8 ;
130
+
131
+ // Realign src_aligned
132
+ let mut src_aligned = ( src as usize & !WORD_MASK ) as * mut usize ;
133
+ // XXX: Could this possibly be UB?
134
+ let mut prev_word = * src_aligned;
135
+
136
+ while dest_start < dest_usize {
137
+ src_aligned = src_aligned. sub ( 1 ) ;
138
+ let cur_word = * src_aligned;
139
+ #[ cfg( target_endian = "little" ) ]
140
+ let resembled = prev_word << ( WORD_SIZE * 8 - shift) | cur_word >> shift;
141
+ #[ cfg( target_endian = "big" ) ]
142
+ let resembled = prev_word >> ( WORD_SIZE * 8 - shift) | cur_word << shift;
143
+ prev_word = cur_word;
144
+
145
+ dest_usize = dest_usize. sub ( 1 ) ;
146
+ * dest_usize = resembled;
147
+ }
139
148
}
140
- }
141
149
142
- #[ inline( always) ]
143
- pub unsafe fn copy_backward ( dest : * mut u8 , src : * const u8 , mut n : usize ) {
144
150
let mut dest = dest. add ( n) ;
145
151
let mut src = src. add ( n) ;
146
152
147
- if likely ( n >= WORD_COPY_THRESHOLD ) {
153
+ if n >= WORD_COPY_THRESHOLD {
148
154
// Align dest
149
155
// Because of n >= 2 * WORD_SIZE, dst_misalignment < n
150
156
let dest_misalignment = dest as usize & WORD_MASK ;
@@ -168,44 +174,36 @@ pub unsafe fn copy_backward(dest: *mut u8, src: *const u8, mut n: usize) {
168
174
}
169
175
170
176
#[ inline( always) ]
171
- pub unsafe fn set_bytes_bytes ( mut s : * mut u8 , c : u8 , n : usize ) {
172
- let end = s. add ( n) ;
173
- while s < end {
174
- * s = c;
175
- s = s. add ( 1 ) ;
177
+ pub unsafe fn set_bytes ( mut s : * mut u8 , c : u8 , mut n : usize ) {
178
+ #[ inline( always) ]
179
+ pub unsafe fn set_bytes_bytes ( mut s : * mut u8 , c : u8 , n : usize ) {
180
+ let end = s. add ( n) ;
181
+ while s < end {
182
+ * s = c;
183
+ s = s. add ( 1 ) ;
184
+ }
176
185
}
177
- }
178
186
179
- #[ inline( always) ]
180
- pub unsafe fn set_bytes_words ( s : * mut u8 , c : u8 , n : usize ) {
181
- let mut broadcast = c as usize ;
182
- broadcast |= broadcast << 8 ;
183
- #[ cfg( not( target_pointer_width = "16" ) ) ]
184
- {
185
- broadcast |= broadcast << 16 ;
186
- #[ cfg( not( target_pointer_width = "32" ) ) ]
187
- {
188
- broadcast |= broadcast << 32 ;
189
- #[ cfg( not( target_pointer_width = "64" ) ) ]
190
- {
191
- broadcast |= broadcast << 64 ;
192
- }
187
+ #[ inline( always) ]
188
+ pub unsafe fn set_bytes_words ( s : * mut u8 , c : u8 , n : usize ) {
189
+ let mut broadcast = c as usize ;
190
+ let mut bits = 8 ;
191
+ while bits < WORD_SIZE * 8 {
192
+ broadcast |= broadcast << bits;
193
+ bits *= 2 ;
193
194
}
194
- }
195
195
196
- let mut s_usize = s as * mut usize ;
197
- let end = s. add ( n) as * mut usize ;
196
+ let mut s_usize = s as * mut usize ;
197
+ let end = s. add ( n) as * mut usize ;
198
198
199
- while s_usize < end {
200
- * s_usize = broadcast;
201
- s_usize = s_usize. add ( 1 ) ;
199
+ while s_usize < end {
200
+ * s_usize = broadcast;
201
+ s_usize = s_usize. add ( 1 ) ;
202
+ }
202
203
}
203
- }
204
204
205
- #[ inline( always) ]
206
- pub unsafe fn set_bytes ( mut s : * mut u8 , c : u8 , mut n : usize ) {
207
205
if likely ( n >= WORD_COPY_THRESHOLD ) {
208
- // Bec// Align dest
206
+ // Align s
209
207
// Because of n >= 2 * WORD_SIZE, dst_misalignment < n
210
208
let misalignment = ( s as usize ) . wrapping_neg ( ) & WORD_MASK ;
211
209
set_bytes_bytes ( s, c, misalignment) ;
0 commit comments