diff --git a/wolfcrypt/src/sp_int.c b/wolfcrypt/src/sp_int.c index e11628fcd..8202d2e8f 100644 --- a/wolfcrypt/src/sp_int.c +++ b/wolfcrypt/src/sp_int.c @@ -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)