12#ifdef OT_PLATFORM_RV32
13#define OT_PREFIX_IF_NOT_RV32(name) name
15#define OT_PREFIX_IF_NOT_RV32(name) ot_##name
18static size_t compute_num_leading_bytes(
const void *left,
const void *right,
20 if (len <
alignof(uint32_t)) {
23 const size_t left_ahead =
OT_UNSIGNED(misalignment32_of((uintptr_t)left));
24 const size_t right_ahead =
OT_UNSIGNED(misalignment32_of((uintptr_t)right));
25 if (right == NULL || left_ahead == right_ahead) {
26 return (4 - left_ahead) & 0x3;
46static void compute_alignment(
const void *left,
const void *right,
size_t len,
47 size_t *out_body_offset,
48 size_t *out_tail_offset) {
49 const size_t num_leading_bytes = compute_num_leading_bytes(left, right, len);
50 *out_body_offset = num_leading_bytes;
52 const size_t num_words = (len - num_leading_bytes) /
sizeof(uint32_t);
53 *out_tail_offset = num_leading_bytes + num_words *
sizeof(uint32_t);
56static uint32_t repeat_byte_to_u32(uint8_t
byte) {
57 const uint32_t word = byte;
58 return word << 24 | word << 16 | word << 8 | word;
61void *OT_PREFIX_IF_NOT_RV32(memcpy)(
void *restrict dest,
62 const void *restrict src,
size_t len) {
63 unsigned char *dest8 = (
unsigned char *)dest;
64 const unsigned char *src8 = (
const unsigned char *)src;
65 size_t body_offset, tail_offset;
66 compute_alignment(dest, src, len, &body_offset, &tail_offset);
68 for (; i < body_offset; ++i) {
71 for (; i < tail_offset; i +=
sizeof(uint32_t)) {
72 uint32_t word = read_32(&src8[i]);
73 write_32(word, &dest8[i]);
75 for (; i < len; ++i) {
81void *OT_PREFIX_IF_NOT_RV32(memset)(
void *dest,
int value,
size_t len) {
82 unsigned char *dest8 = (
unsigned char *)dest;
83 const uint8_t value8 = (uint8_t)value;
85 size_t body_offset, tail_offset;
86 compute_alignment(dest, NULL, len, &body_offset, &tail_offset);
88 for (; i < body_offset; ++i) {
91 const uint32_t value32 = repeat_byte_to_u32(value8);
92 for (; i < tail_offset; i +=
sizeof(uint32_t)) {
93 write_32(value32, &dest8[i]);
95 for (; i < len; ++i) {
107int OT_PREFIX_IF_NOT_RV32(memcmp)(
const void *lhs,
const void *rhs,
109 const unsigned char *lhs8 = (
const unsigned char *)lhs;
110 const unsigned char *rhs8 = (
const unsigned char *)rhs;
111 size_t body_offset, tail_offset;
112 compute_alignment(lhs, rhs, len, &body_offset, &tail_offset);
114 for (; i < body_offset; ++i) {
115 if (lhs8[i] < rhs8[i]) {
117 }
else if (lhs8[i] > rhs8[i]) {
121 for (; i < tail_offset; i +=
sizeof(uint32_t)) {
122#if OT_BUILD_FOR_STATIC_ANALYZER
123 assert(&lhs8[i] != NULL);
124 assert(&rhs8[i] != NULL);
126 uint32_t word_left = __builtin_bswap32(read_32(&lhs8[i]));
127 uint32_t word_right = __builtin_bswap32(read_32(&rhs8[i]));
128 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
129 "memcmp assumes that the system is little endian.");
130 if (word_left < word_right) {
132 }
else if (word_left > word_right) {
136 for (; i < len; ++i) {
137 if (lhs8[i] < rhs8[i]) {
139 }
else if (lhs8[i] > rhs8[i]) {
146int memrcmp(
const void *lhs,
const void *rhs,
size_t len) {
147 const unsigned char *lhs8 = (
const unsigned char *)lhs;
148 const unsigned char *rhs8 = (
const unsigned char *)rhs;
149 size_t body_offset, tail_offset;
150 compute_alignment(lhs, rhs, len, &body_offset, &tail_offset);
152 for (; end > tail_offset; --end) {
153 const size_t i = end - 1;
154 if (lhs8[i] < rhs8[i]) {
156 }
else if (lhs8[i] > rhs8[i]) {
160 for (; end > body_offset; end -=
sizeof(uint32_t)) {
161 const size_t i = end -
sizeof(uint32_t);
162#if OT_BUILD_FOR_STATIC_ANALYZER
163 assert(&lhs8[i] != NULL);
164 assert(&rhs8[i] != NULL);
166 uint32_t word_left = read_32(&lhs8[i]);
167 uint32_t word_right = read_32(&rhs8[i]);
168 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
169 "memrcmp assumes that the system is little endian.");
170 if (word_left < word_right) {
172 }
else if (word_left > word_right) {
176 for (; end > 0; --end) {
177 const size_t i = end - 1;
178 if (lhs8[i] < rhs8[i]) {
180 }
else if (lhs8[i] > rhs8[i]) {
187void *OT_PREFIX_IF_NOT_RV32(memchr)(
const void *ptr,
int value,
size_t len) {
188 const unsigned char *ptr8 = (
const unsigned char *)ptr;
189 const uint8_t value8 = (uint8_t)value;
191 size_t body_offset, tail_offset;
192 compute_alignment(ptr, NULL, len, &body_offset, &tail_offset);
194 for (; i < body_offset; ++i) {
195 if (ptr8[i] == value8) {
196 return (
void *)&ptr8[i];
199 const uint32_t value32 = repeat_byte_to_u32(value8);
200 for (; i < tail_offset; i +=
sizeof(uint32_t)) {
201 uint32_t word = read_32(&ptr8[i]);
202 uint32_t bits_eq = ~(word ^ value32);
203 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
204 "memchr assumes that the system is little endian.");
205 if ((bits_eq & UINT8_MAX) == UINT8_MAX) {
206 return (
void *)&ptr8[i];
208 if (((bits_eq >> 8) & UINT8_MAX) == UINT8_MAX) {
209 return (
void *)&ptr8[i + 1];
211 if (((bits_eq >> 16) & UINT8_MAX) == UINT8_MAX) {
212 return (
void *)&ptr8[i + 2];
214 if (((bits_eq >> 24) & UINT8_MAX) == UINT8_MAX) {
215 return (
void *)&ptr8[i + 3];
218 for (; i < len; ++i) {
219 if (ptr8[i] == value8) {
220 return (
void *)&ptr8[i];
226void *OT_PREFIX_IF_NOT_RV32(memrchr)(
const void *ptr,
int value,
size_t len) {
227 const unsigned char *ptr8 = (
const unsigned char *)ptr;
228 const uint8_t value8 = (uint8_t)value;
230 size_t body_offset, tail_offset;
231 compute_alignment(ptr, NULL, len, &body_offset, &tail_offset);
234 for (; end > tail_offset; --end) {
235 const size_t i = end - 1;
236 if (ptr8[i] == value8) {
237 return (
void *)&ptr8[i];
240 const uint32_t value32 = repeat_byte_to_u32(value8);
241 for (; end > body_offset; end -=
sizeof(uint32_t)) {
242 const size_t i = end -
sizeof(uint32_t);
243 uint32_t word = read_32(&ptr8[i]);
244 uint32_t bits_eq = ~(word ^ value32);
245 static_assert(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__,
246 "memrchr assumes that the system is little endian.");
247 if (((bits_eq >> 24) & UINT8_MAX) == UINT8_MAX) {
248 return (
void *)&ptr8[i + 3];
250 if (((bits_eq >> 16) & UINT8_MAX) == UINT8_MAX) {
251 return (
void *)&ptr8[i + 2];
253 if (((bits_eq >> 8) & UINT8_MAX) == UINT8_MAX) {
254 return (
void *)&ptr8[i + 1];
256 if ((bits_eq & UINT8_MAX) == UINT8_MAX) {
257 return (
void *)&ptr8[i];
260 for (; end > 0; --end) {
261 const size_t i = end - 1;
262 if (ptr8[i] == value8) {
263 return (
void *)&ptr8[i];
272extern ptrdiff_t misalignment32_of(uintptr_t);
273extern uint32_t read_32(
const void *);
274extern void write_32(uint32_t,
void *);
275extern uint64_t read_64(
const void *);
276extern void write_64(uint64_t,
void *);
278#undef OT_PREFIX_IF_NOT_RV32