1e8d8bef9SDimitry Andric//===-- int_mulo_impl.inc - Implement __mulo[sdt]i4 ---------------*- C -*-===// 2e8d8bef9SDimitry Andric// 3e8d8bef9SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric// 7e8d8bef9SDimitry Andric//===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric// 9e8d8bef9SDimitry Andric// Helper used by __mulosi4, __mulodi4 and __muloti4. 10e8d8bef9SDimitry Andric// 11e8d8bef9SDimitry Andric//===----------------------------------------------------------------------===// 12e8d8bef9SDimitry Andric 13e8d8bef9SDimitry Andric#include "int_lib.h" 14e8d8bef9SDimitry Andric 15e8d8bef9SDimitry Andric// Returns: a * b 16e8d8bef9SDimitry Andric 17e8d8bef9SDimitry Andric// Effects: sets *overflow to 1 if a * b overflows 18e8d8bef9SDimitry Andric 19e8d8bef9SDimitry Andricstatic __inline fixint_t __muloXi4(fixint_t a, fixint_t b, int *overflow) { 20e8d8bef9SDimitry Andric const int N = (int)(sizeof(fixint_t) * CHAR_BIT); 21*06c3fb27SDimitry Andric const fixint_t MIN = (fixint_t)((fixuint_t)1 << (N - 1)); 22e8d8bef9SDimitry Andric const fixint_t MAX = ~MIN; 23e8d8bef9SDimitry Andric *overflow = 0; 24*06c3fb27SDimitry Andric fixint_t result = (fixuint_t)a * b; 25e8d8bef9SDimitry Andric if (a == MIN) { 26e8d8bef9SDimitry Andric if (b != 0 && b != 1) 27e8d8bef9SDimitry Andric *overflow = 1; 28e8d8bef9SDimitry Andric return result; 29e8d8bef9SDimitry Andric } 30e8d8bef9SDimitry Andric if (b == MIN) { 31e8d8bef9SDimitry Andric if (a != 0 && a != 1) 32e8d8bef9SDimitry Andric *overflow = 1; 33e8d8bef9SDimitry Andric return result; 34e8d8bef9SDimitry Andric } 35e8d8bef9SDimitry Andric fixint_t sa = a >> (N - 1); 36e8d8bef9SDimitry Andric fixint_t abs_a = (a ^ sa) - sa; 37e8d8bef9SDimitry Andric fixint_t sb = b >> (N - 1); 38e8d8bef9SDimitry Andric fixint_t abs_b = (b ^ sb) - sb; 39e8d8bef9SDimitry Andric if (abs_a < 2 || abs_b < 2) 40e8d8bef9SDimitry Andric return result; 41e8d8bef9SDimitry Andric if (sa == sb) { 42e8d8bef9SDimitry Andric if (abs_a > MAX / abs_b) 43e8d8bef9SDimitry Andric *overflow = 1; 44e8d8bef9SDimitry Andric } else { 45e8d8bef9SDimitry Andric if (abs_a > MIN / -abs_b) 46e8d8bef9SDimitry Andric *overflow = 1; 47e8d8bef9SDimitry Andric } 48e8d8bef9SDimitry Andric return result; 49e8d8bef9SDimitry Andric} 50