11ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher/*===-- mulodi4.c - Implement __mulodi4 -----------------------------------===
21ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher *
31ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher *                     The LLVM Compiler Infrastructure
41ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher *
51ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher * This file is dual licensed under the MIT and the University of Illinois Open
61ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher * Source Licenses. See LICENSE.TXT for details.
71ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher *
81ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher * ===----------------------------------------------------------------------===
91ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher *
101ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher * This file implements __mulodi4 for the compiler_rt library.
111ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher *
121ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher * ===----------------------------------------------------------------------===
131ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher */
141ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher
151ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher#include "int_lib.h"
161ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher
171ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher/* Returns: a * b */
181ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher
191ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher/* Effects: sets *overflow to 1  if a * b overflows */
201ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher
212d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen HinesCOMPILER_RT_ABI di_int
221ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher__mulodi4(di_int a, di_int b, int* overflow)
231ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher{
241ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    const int N = (int)(sizeof(di_int) * CHAR_BIT);
251ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    const di_int MIN = (di_int)1 << (N-1);
261ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    const di_int MAX = ~MIN;
271ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    *overflow = 0;
281ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    di_int result = a * b;
291ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    if (a == MIN)
301ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    {
311ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher        if (b != 0 && b != 1)
321ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher	    *overflow = 1;
331ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher	return result;
341ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    }
351ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    if (b == MIN)
361ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    {
371ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher        if (a != 0 && a != 1)
381ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher	    *overflow = 1;
391ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher        return result;
401ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    }
411ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    di_int sa = a >> (N - 1);
421ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    di_int abs_a = (a ^ sa) - sa;
431ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    di_int sb = b >> (N - 1);
441ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    di_int abs_b = (b ^ sb) - sb;
451ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    if (abs_a < 2 || abs_b < 2)
461ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher        return result;
471ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    if (sa == sb)
481ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    {
491ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher        if (abs_a > MAX / abs_b)
501ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher            *overflow = 1;
511ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    }
521ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    else
531ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    {
541ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher        if (abs_a > MIN / -abs_b)
551ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher            *overflow = 1;
561ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    }
571ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher    return result;
581ace4055f79f304750839d73c46bbcaeb994f1b5Eric Christopher}
59