arm32_aeabi_divmod.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. /*
  7. * Form ABI specifications:
  8. * int __aeabi_idiv(int numerator, int denominator);
  9. * unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator);
  10. *
  11. * typedef struct { int quot; int rem; } idiv_return;
  12. * typedef struct { unsigned quot; unsigned rem; } uidiv_return;
  13. *
  14. * __value_in_regs idiv_return __aeabi_idivmod(int numerator,
  15. * int *denominator);
  16. * __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator,
  17. * unsigned denominator);
  18. */
  19. /* struct qr - stores quotient/remainder to handle divmod EABI interfaces. */
  20. struct qr {
  21. unsigned int q; /* computed quotient */
  22. unsigned int r; /* computed remainder */
  23. unsigned int q_n; /* specifies if quotient shall be negative */
  24. unsigned int r_n; /* specifies if remainder shall be negative */
  25. };
  26. static void uint_div_qr(unsigned int numerator, unsigned int denominator,
  27. struct qr *qr);
  28. /* returns in R0 and R1 by tail calling an asm function */
  29. unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator);
  30. unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator);
  31. /* returns in R0 and R1 by tail calling an asm function */
  32. signed int __aeabi_idivmod(signed int numerator, signed int denominator);
  33. signed int __aeabi_idiv(signed int numerator, signed int denominator);
  34. /*
  35. * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator)
  36. * Numerator and Denominator are received in R0 and R1.
  37. * Where __ste_idivmod_ret_t is returned in R0 and R1.
  38. *
  39. * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator,
  40. * unsigned denominator)
  41. * Numerator and Denominator are received in R0 and R1.
  42. * Where __ste_uidivmod_ret_t is returned in R0 and R1.
  43. */
  44. #ifdef __GNUC__
  45. signed int ret_idivmod_values(signed int quotient, signed int remainder);
  46. unsigned int ret_uidivmod_values(unsigned int quotient, unsigned int remainder);
  47. #else
  48. #error "Compiler not supported"
  49. #endif
  50. static void division_qr(unsigned int n, unsigned int p, struct qr *qr)
  51. {
  52. unsigned int i = 1, q = 0;
  53. if (p == 0) {
  54. qr->r = 0xFFFFFFFF; /* division by 0 */
  55. return;
  56. }
  57. while ((p >> 31) == 0) {
  58. i = i << 1; /* count the max division steps */
  59. p = p << 1; /* increase p until it has maximum size*/
  60. }
  61. while (i > 0) {
  62. q = q << 1; /* write bit in q at index (size-1) */
  63. if (n >= p) {
  64. n -= p;
  65. q++;
  66. }
  67. p = p >> 1; /* decrease p */
  68. i = i >> 1; /* decrease remaining size in q */
  69. }
  70. qr->r = n;
  71. qr->q = q;
  72. }
  73. static void uint_div_qr(unsigned int numerator, unsigned int denominator,
  74. struct qr *qr)
  75. {
  76. division_qr(numerator, denominator, qr);
  77. /* negate quotient and/or remainder according to requester */
  78. if (qr->q_n)
  79. qr->q = -qr->q;
  80. if (qr->r_n)
  81. qr->r = -qr->r;
  82. }
  83. unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator)
  84. {
  85. struct qr qr = { .q_n = 0, .r_n = 0 };
  86. uint_div_qr(numerator, denominator, &qr);
  87. return qr.q;
  88. }
  89. unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator)
  90. {
  91. struct qr qr = { .q_n = 0, .r_n = 0 };
  92. uint_div_qr(numerator, denominator, &qr);
  93. return ret_uidivmod_values(qr.q, qr.r);
  94. }
  95. signed int __aeabi_idiv(signed int numerator, signed int denominator)
  96. {
  97. struct qr qr = { .q_n = 0, .r_n = 0 };
  98. if (((numerator < 0) && (denominator > 0)) ||
  99. ((numerator > 0) && (denominator < 0)))
  100. qr.q_n = 1; /* quotient shall be negate */
  101. if (numerator < 0) {
  102. numerator = -numerator;
  103. qr.r_n = 1; /* remainder shall be negate */
  104. }
  105. if (denominator < 0)
  106. denominator = -denominator;
  107. uint_div_qr(numerator, denominator, &qr);
  108. return qr.q;
  109. }
  110. signed int __aeabi_idivmod(signed int numerator, signed int denominator)
  111. {
  112. struct qr qr = { .q_n = 0, .r_n = 0 };
  113. if (((numerator < 0) && (denominator > 0)) ||
  114. ((numerator > 0) && (denominator < 0)))
  115. qr.q_n = 1; /* quotient shall be negate */
  116. if (numerator < 0) {
  117. numerator = -numerator;
  118. qr.r_n = 1; /* remainder shall be negate */
  119. }
  120. if (denominator < 0)
  121. denominator = -denominator;
  122. uint_div_qr(numerator, denominator, &qr);
  123. return ret_idivmod_values(qr.q, qr.r);
  124. }