memcmp.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* Copyright (C) 1991-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Torbjorn Granlund (tege@sics.se).
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #ifdef HAVE_CONFIG_H
  16. # include "config.h"
  17. #endif
  18. #if defined HAVE_STRING_H || defined _LIBC
  19. # include <string.h>
  20. #endif
  21. #undef memcmp
  22. #ifndef MEMCMP
  23. # define MEMCMP memcmp
  24. #endif
  25. #ifdef _LIBC
  26. # include <memcopy.h>
  27. # include <endian.h>
  28. # if __BYTE_ORDER == __BIG_ENDIAN
  29. # define WORDS_BIGENDIAN
  30. # endif
  31. #else /* Not in the GNU C library. */
  32. # include <sys/types.h>
  33. /* Type to use for aligned memory operations.
  34. This should normally be the biggest type supported by a single load
  35. and store. Must be an unsigned type. */
  36. # define OPSIZ (sizeof (op_t))
  37. /* Type to use for unaligned operations. */
  38. typedef unsigned char byte;
  39. # ifndef WORDS_BIGENDIAN
  40. # define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
  41. # else
  42. # define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2)))
  43. # endif
  44. #endif /* In the GNU C library. */
  45. #ifdef WORDS_BIGENDIAN
  46. # define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1)
  47. #else
  48. # define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b))
  49. #endif
  50. /* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */
  51. /* The strategy of this memcmp is:
  52. 1. Compare bytes until one of the block pointers is aligned.
  53. 2. Compare using memcmp_common_alignment or
  54. memcmp_not_common_alignment, regarding the alignment of the other
  55. block after the initial byte operations. The maximum number of
  56. full words (of type op_t) are compared in this way.
  57. 3. Compare the few remaining bytes. */
  58. #ifndef WORDS_BIGENDIAN
  59. /* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine.
  60. A and B are known to be different.
  61. This is needed only on little-endian machines. */
  62. static int memcmp_bytes (op_t, op_t) __THROW;
  63. static int
  64. memcmp_bytes (op_t a, op_t b)
  65. {
  66. long int srcp1 = (long int) &a;
  67. long int srcp2 = (long int) &b;
  68. op_t a0, b0;
  69. do
  70. {
  71. a0 = ((byte *) srcp1)[0];
  72. b0 = ((byte *) srcp2)[0];
  73. srcp1 += 1;
  74. srcp2 += 1;
  75. }
  76. while (a0 == b0);
  77. return a0 - b0;
  78. }
  79. #endif
  80. static int memcmp_common_alignment (long, long, size_t) __THROW;
  81. /* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t'
  82. objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for
  83. memory operations on `op_t's. */
  84. static int
  85. memcmp_common_alignment (long int srcp1, long int srcp2, size_t len)
  86. {
  87. op_t a0, a1;
  88. op_t b0, b1;
  89. switch (len % 4)
  90. {
  91. default: /* Avoid warning about uninitialized local variables. */
  92. case 2:
  93. a0 = ((op_t *) srcp1)[0];
  94. b0 = ((op_t *) srcp2)[0];
  95. srcp1 -= 2 * OPSIZ;
  96. srcp2 -= 2 * OPSIZ;
  97. len += 2;
  98. goto do1;
  99. case 3:
  100. a1 = ((op_t *) srcp1)[0];
  101. b1 = ((op_t *) srcp2)[0];
  102. srcp1 -= OPSIZ;
  103. srcp2 -= OPSIZ;
  104. len += 1;
  105. goto do2;
  106. case 0:
  107. if (OP_T_THRES <= 3 * OPSIZ && len == 0)
  108. return 0;
  109. a0 = ((op_t *) srcp1)[0];
  110. b0 = ((op_t *) srcp2)[0];
  111. goto do3;
  112. case 1:
  113. a1 = ((op_t *) srcp1)[0];
  114. b1 = ((op_t *) srcp2)[0];
  115. srcp1 += OPSIZ;
  116. srcp2 += OPSIZ;
  117. len -= 1;
  118. if (OP_T_THRES <= 3 * OPSIZ && len == 0)
  119. goto do0;
  120. /* Fall through. */
  121. }
  122. do
  123. {
  124. a0 = ((op_t *) srcp1)[0];
  125. b0 = ((op_t *) srcp2)[0];
  126. if (a1 != b1)
  127. return CMP_LT_OR_GT (a1, b1);
  128. do3:
  129. a1 = ((op_t *) srcp1)[1];
  130. b1 = ((op_t *) srcp2)[1];
  131. if (a0 != b0)
  132. return CMP_LT_OR_GT (a0, b0);
  133. do2:
  134. a0 = ((op_t *) srcp1)[2];
  135. b0 = ((op_t *) srcp2)[2];
  136. if (a1 != b1)
  137. return CMP_LT_OR_GT (a1, b1);
  138. do1:
  139. a1 = ((op_t *) srcp1)[3];
  140. b1 = ((op_t *) srcp2)[3];
  141. if (a0 != b0)
  142. return CMP_LT_OR_GT (a0, b0);
  143. srcp1 += 4 * OPSIZ;
  144. srcp2 += 4 * OPSIZ;
  145. len -= 4;
  146. }
  147. while (len != 0);
  148. /* This is the right position for do0. Please don't move
  149. it into the loop. */
  150. do0:
  151. if (a1 != b1)
  152. return CMP_LT_OR_GT (a1, b1);
  153. return 0;
  154. }
  155. static int memcmp_not_common_alignment (long, long, size_t) __THROW;
  156. /* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN
  157. `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory
  158. operations on `op_t', but SRCP1 *should be unaligned*. */
  159. static int
  160. memcmp_not_common_alignment (long int srcp1, long int srcp2, size_t len)
  161. {
  162. op_t a0, a1, a2, a3;
  163. op_t b0, b1, b2, b3;
  164. op_t x;
  165. int shl, shr;
  166. /* Calculate how to shift a word read at the memory operation
  167. aligned srcp1 to make it aligned for comparison. */
  168. shl = 8 * (srcp1 % OPSIZ);
  169. shr = 8 * OPSIZ - shl;
  170. /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t'
  171. it points in the middle of. */
  172. srcp1 &= -OPSIZ;
  173. switch (len % 4)
  174. {
  175. default: /* Avoid warning about uninitialized local variables. */
  176. case 2:
  177. a1 = ((op_t *) srcp1)[0];
  178. a2 = ((op_t *) srcp1)[1];
  179. b2 = ((op_t *) srcp2)[0];
  180. srcp1 -= 1 * OPSIZ;
  181. srcp2 -= 2 * OPSIZ;
  182. len += 2;
  183. goto do1;
  184. case 3:
  185. a0 = ((op_t *) srcp1)[0];
  186. a1 = ((op_t *) srcp1)[1];
  187. b1 = ((op_t *) srcp2)[0];
  188. srcp2 -= 1 * OPSIZ;
  189. len += 1;
  190. goto do2;
  191. case 0:
  192. if (OP_T_THRES <= 3 * OPSIZ && len == 0)
  193. return 0;
  194. a3 = ((op_t *) srcp1)[0];
  195. a0 = ((op_t *) srcp1)[1];
  196. b0 = ((op_t *) srcp2)[0];
  197. srcp1 += 1 * OPSIZ;
  198. goto do3;
  199. case 1:
  200. a2 = ((op_t *) srcp1)[0];
  201. a3 = ((op_t *) srcp1)[1];
  202. b3 = ((op_t *) srcp2)[0];
  203. srcp1 += 2 * OPSIZ;
  204. srcp2 += 1 * OPSIZ;
  205. len -= 1;
  206. if (OP_T_THRES <= 3 * OPSIZ && len == 0)
  207. goto do0;
  208. /* Fall through. */
  209. }
  210. do
  211. {
  212. a0 = ((op_t *) srcp1)[0];
  213. b0 = ((op_t *) srcp2)[0];
  214. x = MERGE(a2, shl, a3, shr);
  215. if (x != b3)
  216. return CMP_LT_OR_GT (x, b3);
  217. do3:
  218. a1 = ((op_t *) srcp1)[1];
  219. b1 = ((op_t *) srcp2)[1];
  220. x = MERGE(a3, shl, a0, shr);
  221. if (x != b0)
  222. return CMP_LT_OR_GT (x, b0);
  223. do2:
  224. a2 = ((op_t *) srcp1)[2];
  225. b2 = ((op_t *) srcp2)[2];
  226. x = MERGE(a0, shl, a1, shr);
  227. if (x != b1)
  228. return CMP_LT_OR_GT (x, b1);
  229. do1:
  230. a3 = ((op_t *) srcp1)[3];
  231. b3 = ((op_t *) srcp2)[3];
  232. x = MERGE(a1, shl, a2, shr);
  233. if (x != b2)
  234. return CMP_LT_OR_GT (x, b2);
  235. srcp1 += 4 * OPSIZ;
  236. srcp2 += 4 * OPSIZ;
  237. len -= 4;
  238. }
  239. while (len != 0);
  240. /* This is the right position for do0. Please don't move
  241. it into the loop. */
  242. do0:
  243. x = MERGE(a2, shl, a3, shr);
  244. if (x != b3)
  245. return CMP_LT_OR_GT (x, b3);
  246. return 0;
  247. }
  248. int
  249. MEMCMP (const void *s1, const void *s2, size_t len)
  250. {
  251. op_t a0;
  252. op_t b0;
  253. long int srcp1 = (long int) s1;
  254. long int srcp2 = (long int) s2;
  255. op_t res;
  256. if (len >= OP_T_THRES)
  257. {
  258. /* There are at least some bytes to compare. No need to test
  259. for LEN == 0 in this alignment loop. */
  260. while (srcp2 % OPSIZ != 0)
  261. {
  262. a0 = ((byte *) srcp1)[0];
  263. b0 = ((byte *) srcp2)[0];
  264. srcp1 += 1;
  265. srcp2 += 1;
  266. res = a0 - b0;
  267. if (res != 0)
  268. return res;
  269. len -= 1;
  270. }
  271. /* SRCP2 is now aligned for memory operations on `op_t'.
  272. SRCP1 alignment determines if we can do a simple,
  273. aligned compare or need to shuffle bits. */
  274. if (srcp1 % OPSIZ == 0)
  275. res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ);
  276. else
  277. res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ);
  278. if (res != 0)
  279. return res;
  280. /* Number of bytes remaining in the interval [0..OPSIZ-1]. */
  281. srcp1 += len & -OPSIZ;
  282. srcp2 += len & -OPSIZ;
  283. len %= OPSIZ;
  284. }
  285. /* There are just a few bytes to compare. Use byte memory operations. */
  286. while (len != 0)
  287. {
  288. a0 = ((byte *) srcp1)[0];
  289. b0 = ((byte *) srcp2)[0];
  290. srcp1 += 1;
  291. srcp2 += 1;
  292. res = a0 - b0;
  293. if (res != 0)
  294. return res;
  295. len -= 1;
  296. }
  297. return 0;
  298. }
  299. libc_hidden_builtin_def(memcmp)
  300. #ifdef weak_alias
  301. # undef bcmp
  302. weak_alias (memcmp, bcmp)
  303. #endif
  304. #undef __memcmpeq
  305. strong_alias (memcmp, __memcmpeq)
  306. libc_hidden_def(__memcmpeq)