mulvsi3.c revision 276789
1133362Sobrien/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===
2234449Sobrien *
3133362Sobrien *                     The LLVM Compiler Infrastructure
4298107Sgjb *
5133365Sobrien * This file is dual licensed under the MIT and the University of Illinois Open
6267897Sdelphij * Source Licenses. See LICENSE.TXT for details.
7267897Sdelphij *
8133362Sobrien * ===----------------------------------------------------------------------===
9133362Sobrien *
10195767Skensmith * This file implements __mulvsi3 for the compiler_rt library.
11275024Sbapt *
12133362Sobrien * ===----------------------------------------------------------------------===
13133362Sobrien */
14191771Sobrien
15298192Sdelphij#include "int_lib.h"
16191771Sobrien
17137887Sobrien/* Returns: a * b */
18133362Sobrien
19133370Sobrien/* Effects: aborts if a * b overflows */
20133362Sobrien
21159769SobrienCOMPILER_RT_ABI si_int
22302222Sdelphij__mulvsi3(si_int a, si_int b)
23133362Sobrien{
24208342Smarius    const int N = (int)(sizeof(si_int) * CHAR_BIT);
25201381Sed    const si_int MIN = (si_int)1 << (N-1);
26186693Sobrien    const si_int MAX = ~MIN;
27133362Sobrien    if (a == MIN)
28186693Sobrien    {
29133362Sobrien        if (b == 0 || b == 1)
30133362Sobrien            return a * b;
31267897Sdelphij        compilerrt_abort();
32267897Sdelphij    }
33267897Sdelphij    if (b == MIN)
34133362Sobrien    {
35133362Sobrien        if (a == 0 || a == 1)
36265464Sdelphij            return a * b;
37133362Sobrien        compilerrt_abort();
38133362Sobrien    }
39299289Sbdrewery    si_int sa = a >> (N - 1);
40133362Sobrien    si_int abs_a = (a ^ sa) - sa;
41133362Sobrien    si_int sb = b >> (N - 1);
42133362Sobrien    si_int abs_b = (b ^ sb) - sb;
43302222Sdelphij    if (abs_a < 2 || abs_b < 2)
44302222Sdelphij        return a * b;
45240377Sobrien    if (sa == sb)
46133362Sobrien    {
47136681Sru        if (abs_a > MAX / abs_b)
48136681Sru            compilerrt_abort();
49133362Sobrien    }
50133362Sobrien    else
51133362Sobrien    {
52133362Sobrien        if (abs_a > MIN / -abs_b)
53133362Sobrien            compilerrt_abort();
54133362Sobrien    }
55133362Sobrien    return a * b;
56133362Sobrien}
57302221Sdelphij