string.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Copyright (C) 1991,1992,1993,1997,1998,2003, 2005 Free Software Foundation, Inc.
  3. * This file is part of the GNU C Library.
  4. * Copyright (c) 2011 The Chromium OS Authors.
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. /* From glibc-2.14, sysdeps/i386/memset.c */
  9. #include <linux/types.h>
  10. #include <linux/compiler.h>
  11. #include <asm/string.h>
  12. typedef uint32_t op_t;
  13. void *memset(void *dstpp, int c, size_t len)
  14. {
  15. int d0;
  16. unsigned long int dstp = (unsigned long int) dstpp;
  17. /* This explicit register allocation improves code very much indeed. */
  18. register op_t x asm("ax");
  19. x = (unsigned char) c;
  20. /* Clear the direction flag, so filling will move forward. */
  21. asm volatile("cld");
  22. /* This threshold value is optimal. */
  23. if (len >= 12) {
  24. /* Fill X with four copies of the char we want to fill with. */
  25. x |= (x << 8);
  26. x |= (x << 16);
  27. /* Adjust LEN for the bytes handled in the first loop. */
  28. len -= (-dstp) % sizeof(op_t);
  29. /*
  30. * There are at least some bytes to set. No need to test for
  31. * LEN == 0 in this alignment loop.
  32. */
  33. /* Fill bytes until DSTP is aligned on a longword boundary. */
  34. asm volatile(
  35. "rep\n"
  36. "stosb" /* %0, %2, %3 */ :
  37. "=D" (dstp), "=c" (d0) :
  38. "0" (dstp), "1" ((-dstp) % sizeof(op_t)), "a" (x) :
  39. "memory");
  40. /* Fill longwords. */
  41. asm volatile(
  42. "rep\n"
  43. "stosl" /* %0, %2, %3 */ :
  44. "=D" (dstp), "=c" (d0) :
  45. "0" (dstp), "1" (len / sizeof(op_t)), "a" (x) :
  46. "memory");
  47. len %= sizeof(op_t);
  48. }
  49. /* Write the last few bytes. */
  50. asm volatile(
  51. "rep\n"
  52. "stosb" /* %0, %2, %3 */ :
  53. "=D" (dstp), "=c" (d0) :
  54. "0" (dstp), "1" (len), "a" (x) :
  55. "memory");
  56. return dstpp;
  57. }
  58. #define OP_T_THRES 8
  59. #define OPSIZ (sizeof(op_t))
  60. #define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \
  61. do { \
  62. int __d0; \
  63. asm volatile( \
  64. /* Clear the direction flag, so copying goes forward. */ \
  65. "cld\n" \
  66. /* Copy bytes. */ \
  67. "rep\n" \
  68. "movsb" : \
  69. "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \
  70. "0" (dst_bp), "1" (src_bp), "2" (nbytes) : \
  71. "memory"); \
  72. } while (0)
  73. #define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \
  74. do { \
  75. int __d0; \
  76. asm volatile( \
  77. /* Clear the direction flag, so copying goes forward. */ \
  78. "cld\n" \
  79. /* Copy longwords. */ \
  80. "rep\n" \
  81. "movsl" : \
  82. "=D" (dst_bp), "=S" (src_bp), "=c" (__d0) : \
  83. "0" (dst_bp), "1" (src_bp), "2" ((nbytes) / 4) : \
  84. "memory"); \
  85. (nbytes_left) = (nbytes) % 4; \
  86. } while (0)
  87. void *memcpy(void *dstpp, const void *srcpp, size_t len)
  88. {
  89. unsigned long int dstp = (long int)dstpp;
  90. unsigned long int srcp = (long int)srcpp;
  91. /* Copy from the beginning to the end. */
  92. /* If there not too few bytes to copy, use word copy. */
  93. if (len >= OP_T_THRES) {
  94. /* Copy just a few bytes to make DSTP aligned. */
  95. len -= (-dstp) % OPSIZ;
  96. BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);
  97. /* Copy from SRCP to DSTP taking advantage of the known
  98. * alignment of DSTP. Number of bytes remaining is put
  99. * in the third argument, i.e. in LEN. This number may
  100. * vary from machine to machine.
  101. */
  102. WORD_COPY_FWD(dstp, srcp, len, len);
  103. /* Fall out and copy the tail. */
  104. }
  105. /* There are just a few bytes to copy. Use byte memory operations. */
  106. BYTE_COPY_FWD(dstp, srcp, len);
  107. return dstpp;
  108. }