diff --git a/compiler-rt/lib/builtins/fp_lib.h b/compiler-rt/lib/builtins/fp_lib.h index 8404d98c935081..5658f80cfd0efe 100644 --- a/compiler-rt/lib/builtins/fp_lib.h +++ b/compiler-rt/lib/builtins/fp_lib.h @@ -180,8 +180,11 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) { (sum2 & Word_FullMask) + ((sum3 << 32) & Word_HiMask); *lo = r0 + (r1 << 64); + // The addition above can overflow, in which case `*lo` will be less than + // `r0`. Carry any overflow into `hi`. + const bool carry = *lo < r0; *hi = (r1 >> 64) + (sum1 >> 96) + (sum2 >> 64) + (sum3 >> 32) + sum4 + - (sum5 << 32) + (sum6 << 64); + (sum5 << 32) + (sum6 << 64) + carry; } #undef Word_1 #undef Word_2 diff --git a/compiler-rt/test/builtins/Unit/multf3_test.c b/compiler-rt/test/builtins/Unit/multf3_test.c index 543b55899ce82a..0e561551d35342 100644 --- a/compiler-rt/test/builtins/Unit/multf3_test.c +++ b/compiler-rt/test/builtins/Unit/multf3_test.c @@ -77,6 +77,12 @@ int main() UINT64_C(0x0), UINT64_C(0x0))) return 1; + // test carry between lo and hi in widening multiply + if (test__multf3(0x0.7fffffffffffffffffffffffffffp-16382L, + 0x1.7fffffffffffffffffffffffffffp+1L, + UINT64_C(0x00017fffffffffff), + UINT64_C(0xfffffffffffffffc))) + return 1; #else printf("skipped\n");