11fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===
21fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan *
31fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan *                     The LLVM Compiler Infrastructure
41fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan *
59ad441ffec97db647fee3725b3424284fb913e14Howard Hinnant * This file is dual licensed under the MIT and the University of Illinois Open
69ad441ffec97db647fee3725b3424284fb913e14Howard Hinnant * Source Licenses. See LICENSE.TXT for details.
71fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan *
81fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan * ===----------------------------------------------------------------------===
91fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan *
101fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan * This file implements __mulvsi3 for the compiler_rt library.
111fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan *
121fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan * ===----------------------------------------------------------------------===
131fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan */
14b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar
15b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar#include "int_lib.h"
16b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar
171fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan/* Returns: a * b */
18b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar
191fcb40b79d8fbfcc9acb0966d5f9bba09431f832Edward O'Callaghan/* Effects: aborts if a * b overflows */
20b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesCOMPILER_RT_ABI si_int
22b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar__mulvsi3(si_int a, si_int b)
23b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar{
24b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    const int N = (int)(sizeof(si_int) * CHAR_BIT);
25b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    const si_int MIN = (si_int)1 << (N-1);
26b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    const si_int MAX = ~MIN;
27b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    if (a == MIN)
28b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    {
29b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar        if (b == 0 || b == 1)
30b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar            return a * b;
3148f46ac1d9a82210f6e469567cb60aa7e7cd2f3bDaniel Dunbar        compilerrt_abort();
32b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    }
33b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    if (b == MIN)
34b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    {
35b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar        if (a == 0 || a == 1)
36b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar            return a * b;
3748f46ac1d9a82210f6e469567cb60aa7e7cd2f3bDaniel Dunbar        compilerrt_abort();
38b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    }
39b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    si_int sa = a >> (N - 1);
40b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    si_int abs_a = (a ^ sa) - sa;
41b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    si_int sb = b >> (N - 1);
42b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    si_int abs_b = (b ^ sb) - sb;
43b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    if (abs_a < 2 || abs_b < 2)
44b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar        return a * b;
45b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    if (sa == sb)
46b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    {
47b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar        if (abs_a > MAX / abs_b)
4848f46ac1d9a82210f6e469567cb60aa7e7cd2f3bDaniel Dunbar            compilerrt_abort();
49b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    }
50b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    else
51b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    {
52b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar        if (abs_a > MIN / -abs_b)
5348f46ac1d9a82210f6e469567cb60aa7e7cd2f3bDaniel Dunbar            compilerrt_abort();
54b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    }
55b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar    return a * b;
56b3a6901e66f55b35aa9e01bcb24134e6a65ea004Daniel Dunbar}
57