Merge pull request #4702 from SparkiDev/sp_int_div_arm

SP int: transplant the div_word from SP into SP int for ARM64 and ARM32
This commit is contained in:
David Garske
2022-01-09 17:54:39 -08:00
committed by GitHub

View File

@ -436,7 +436,7 @@ This library provides single precision (SP) integer math functions.
* @param [in] hi SP integer digit. High digit of the dividend.
* @param [in] lo SP integer digit. Lower digit of the dividend.
* @param [in] d SP integer digit. Number to divide by.
* @reutrn The division result.
* @return The division result.
*/
static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
sp_int_digit d)
@ -621,7 +621,7 @@ static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
* @param [in] hi SP integer digit. High digit of the dividend.
* @param [in] lo SP integer digit. Lower digit of the dividend.
* @param [in] d SP integer digit. Number to divide by.
* @reutrn The division result.
* @return The division result.
*/
static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
sp_int_digit d)
@ -784,6 +784,71 @@ static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
: "cc" \
)
#ifndef WOLFSSL_SP_DIV_WORD_HALF
/* Divide a two digit number by a digit number and return. (hi | lo) / d
*
* Using divl instruction on Intel x64.
*
* @param [in] hi SP integer digit. High digit of the dividend.
* @param [in] lo SP integer digit. Lower digit of the dividend.
* @param [in] d SP integer digit. Number to divide by.
* @return The division result.
*/
static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
sp_int_digit d)
{
sp_int_digit r;
__asm__ __volatile__ (
"lsr x5, %[d], 32\n\t"
"add x5, x5, 1\n\t"
"udiv x3, %[hi], x5\n\t"
"lsl x6, x3, 32\n\t"
"mul x4, %[d], x6\n\t"
"umulh x3, %[d], x6\n\t"
"subs %[lo], %[lo], x4\n\t"
"sbc %[hi], %[hi], x3\n\t"
"udiv x3, %[hi], x5\n\t"
"lsl x3, x3, 32\n\t"
"add x6, x6, x3\n\t"
"mul x4, %[d], x3\n\t"
"umulh x3, %[d], x3\n\t"
"subs %[lo], %[lo], x4\n\t"
"sbc %[hi], %[hi], x3\n\t"
"lsr x3, %[lo], 32\n\t"
"orr x3, x3, %[hi], lsl 32\n\t"
"udiv x3, x3, x5\n\t"
"add x6, x6, x3\n\t"
"mul x4, %[d], x3\n\t"
"umulh x3, %[d], x3\n\t"
"subs %[lo], %[lo], x4\n\t"
"sbc %[hi], %[hi], x3\n\t"
"lsr x3, %[lo], 32\n\t"
"orr x3, x3, %[hi], lsl 32\n\t"
"udiv x3, x3, x5\n\t"
"add x6, x6, x3\n\t"
"mul x4, %[d], x3\n\t"
"sub %[lo], %[lo], x4\n\t"
"udiv x3, %[lo], %[d]\n\t"
"add %[r], x6, x3\n\t"
: [r] "=r" (r)
: [hi] "r" (hi), [lo] "r" (lo), [d] "r" (d)
: "x3", "x4", "x5", "x6"
);
return r;
}
#define SP_ASM_DIV_WORD
#endif
#define SP_INT_ASM_AVAILABLE
#endif /* WOLFSSL_SP_ARM64 && SP_WORD_SIZE == 64 */
@ -918,6 +983,72 @@ static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
: "cc" \
)
#ifndef WOLFSSL_SP_DIV_WORD_HALF
/* Divide a two digit number by a digit number and return. (hi | lo) / d
*
* Using divl instruction on Intel x64.
*
* @param [in] hi SP integer digit. High digit of the dividend.
* @param [in] lo SP integer digit. Lower digit of the dividend.
* @param [in] d SP integer digit. Number to divide by.
* @return The division result.
*/
static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
sp_int_digit d)
{
sp_digit r = 0;
__asm__ __volatile__ (
"lsr r5, %[d], #1\n\t"
"add r5, r5, #1\n\t"
"mov r6, %[lo]\n\t"
"mov r7, %[hi]\n\t"
"# Do top 32\n\t"
"subs r8, r5, r7\n\t"
"sbc r8, r8, r8\n\t"
"add %[r], %[r], %[r]\n\t"
"sub %[r], %[r], r8\n\t"
"and r8, r8, r5\n\t"
"subs r7, r7, r8\n\t"
"# Next 30 bits\n\t"
"mov r4, #29\n\t"
"1:\n\t"
"movs r6, r6, lsl #1\n\t"
"adc r7, r7, r7\n\t"
"subs r8, r5, r7\n\t"
"sbc r8, r8, r8\n\t"
"add %[r], %[r], %[r]\n\t"
"sub %[r], %[r], r8\n\t"
"and r8, r8, r5\n\t"
"subs r7, r7, r8\n\t"
"subs r4, r4, #1\n\t"
"bpl 1b\n\t"
"add %[r], %[r], %[r]\n\t"
"add %[r], %[r], #1\n\t"
"umull r4, r5, %[r], %[d]\n\t"
"subs r4, %[lo], r4\n\t"
"sbc r5, %[hi], r5\n\t"
"add %[r], %[r], r5\n\t"
"umull r4, r5, %[r], %[d]\n\t"
"subs r4, %[lo], r4\n\t"
"sbc r5, %[hi], r5\n\t"
"add %[r], %[r], r5\n\t"
"umull r4, r5, %[r], %[d]\n\t"
"subs r4, %[lo], r4\n\t"
"sbc r5, %[hi], r5\n\t"
"add %[r], %[r], r5\n\t"
"subs r8, %[d], r4\n\t"
"sbc r8, r8, r8\n\t"
"sub %[r], %[r], r8\n\t"
: [r] "+r" (r)
: [hi] "r" (hi), [lo] "r" (lo), [d] "r" (d)
: "r4", "r5", "r6", "r7", "r8"
);
return r;
}
#define SP_ASM_DIV_WORD
#endif
#define SP_INT_ASM_AVAILABLE
#endif /* (WOLFSSL_SP_ARM32 || ARM_CORTEX_M) && SP_WORD_SIZE == 32 */
@ -3394,7 +3525,7 @@ int sp_mul_d(sp_int* a, sp_int_digit d, sp_int* r)
* @param [in] hi SP integer digit. High digit of the dividend.
* @param [in] lo SP integer digit. Lower digit of the dividend.
* @param [in] d SP integer digit. Number to divide by.
* @reutrn The division result.
* @return The division result.
*/
static WC_INLINE sp_int_digit sp_div_word(sp_int_digit hi, sp_int_digit lo,
sp_int_digit d)