/*
 * Large integer functions
 *
 * Copyright 2000 Alexandre Julliard
 */

#include "winnt.h"
#include "winternl.h"

/*
 * Note: we use LONGLONG instead of LARGE_INTEGER, because
 * the latter is a structure and the calling convention for
 * returning a structure would not be binary-compatible.
 *
 * FIXME: for platforms that don't have a native LONGLONG type,
 * we should define LONGLONG as a structure similar to LARGE_INTEGER
 * and do everything by hand. You are welcome to do it...
 */

/******************************************************************************
 *        RtlLargeIntegerAdd   (NTDLL.@)
 */
LONGLONG WINAPI RtlLargeIntegerAdd( LONGLONG a, LONGLONG b )
{
    return a + b;
}


/******************************************************************************
 *        RtlLargeIntegerSubtract   (NTDLL.@)
 */
LONGLONG WINAPI RtlLargeIntegerSubtract( LONGLONG a, LONGLONG b )
{
    return a - b;
}


/******************************************************************************
 *        RtlLargeIntegerNegate   (NTDLL.@)
 */
LONGLONG WINAPI RtlLargeIntegerNegate( LONGLONG a )
{
    return -a;
}


/******************************************************************************
 *        RtlLargeIntegerShiftLeft   (NTDLL.@)
 */
LONGLONG WINAPI RtlLargeIntegerShiftLeft( LONGLONG a, INT count )
{
    return a << count;
}


/******************************************************************************
 *        RtlLargeIntegerShiftRight   (NTDLL.@)
 */
LONGLONG WINAPI RtlLargeIntegerShiftRight( LONGLONG a, INT count )
{
    return (ULONGLONG)a >> count;
}


/******************************************************************************
 *        RtlLargeIntegerArithmeticShift   (NTDLL.@)
 */
LONGLONG WINAPI RtlLargeIntegerArithmeticShift( LONGLONG a, INT count )
{
    /* FIXME: gcc does arithmetic shift here, but it may not be true on all platforms */
    return a >> count;
}


/******************************************************************************
 *        RtlLargeIntegerDivide   (NTDLL.@)
 *
 * FIXME: should it be signed division instead?
 */
ULONGLONG WINAPI RtlLargeIntegerDivide( ULONGLONG a, ULONGLONG b, ULONGLONG *rem )
{
    ULONGLONG ret = a / b;
    if (rem) *rem = a - ret * b;
    return ret;
}


/******************************************************************************
 *        RtlConvertLongToLargeInteger   (NTDLL.@)
 */
LONGLONG WINAPI RtlConvertLongToLargeInteger( LONG a )
{
    return a;
}


/******************************************************************************
 *        RtlConvertUlongToLargeInteger   (NTDLL.@)
 */
ULONGLONG WINAPI RtlConvertUlongToLargeInteger( ULONG a )
{
    return a;
}


/******************************************************************************
 *        RtlEnlargedIntegerMultiply   (NTDLL.@)
 */
LONGLONG WINAPI RtlEnlargedIntegerMultiply( INT a, INT b )
{
    return (LONGLONG)a * b;
}


/******************************************************************************
 *        RtlEnlargedUnsignedMultiply   (NTDLL.@)
 */
ULONGLONG WINAPI RtlEnlargedUnsignedMultiply( UINT a, UINT b )
{
    return (ULONGLONG)a * b;
}


/******************************************************************************
 *        RtlEnlargedUnsignedDivide   (NTDLL.@)
 */
UINT WINAPI RtlEnlargedUnsignedDivide( ULONGLONG a, UINT b, UINT *remptr )
{
#if defined(__i386__) && defined(__GNUC__)
    UINT ret, rem;
    UINT uHigh = a >> 32;
    UINT uLow  = a & 0xFFFFFFFF;

    __asm__("div %4,%%eax"
            : "=a" (ret), "=d" (rem)
            : "0" (uHigh), "1" (uLow), "g" (b) );

    if (remptr) *remptr = rem;
    return ret;
#else
    UINT ret = a / b;
    if (remptr) *remptr = a % b;
    return ret;
#endif
}


/******************************************************************************
 *        RtlExtendedLargeIntegerDivide   (NTDLL.@)
 */
LONGLONG WINAPI RtlExtendedLargeIntegerDivide( LONGLONG a, INT b, INT *rem )
{
    LONGLONG ret = a / b;
    if (rem) *rem = a - b * ret;
    return ret;
}


/******************************************************************************
 *        RtlExtendedIntegerMultiply   (NTDLL.@)
 */
LONGLONG WINAPI RtlExtendedIntegerMultiply( LONGLONG a, INT b )
{
    return a * b;
}


/******************************************************************************
 *        RtlExtendedMagicDivide   (NTDLL.@)
 *
 * This function computes (a * b) >> (64 + shift)
 *
 * This allows replacing a division by a longlong constant
 * by a multiplication by the inverse constant.
 *
 * If 'c' is the constant divisor, the constants 'b' and 'shift'
 * must be chosen such that b = 2^(64+shift) / c.
 * Then we have RtlExtendedMagicDivide(a,b,shift) == a * b / 2^(64+shift) == a / c.
 *
 * I'm too lazy to implement it right now...
 */
/* LONGLONG WINAPI RtlExtendedMagicDivide( LONGLONG a, LONGLONG b, INT shift )
 * {
 *     return 0;
 * }
 */


/******************************************************************************
 *        _alldiv   (NTDLL.@)
 */
LONGLONG WINAPI _alldiv( LONGLONG a, LONGLONG b )
{
    return a / b;
}


/******************************************************************************
 *        _allmul   (NTDLL.@)
 */
LONGLONG WINAPI _allmul( LONGLONG a, LONGLONG b )
{
    return a * b;
}


/******************************************************************************
 *        _allrem   (NTDLL.@)
 */
LONGLONG WINAPI _allrem( LONGLONG a, LONGLONG b )
{
    return a % b;
}


/******************************************************************************
 *        _aulldiv   (NTDLL.@)
 */
ULONGLONG WINAPI _aulldiv( ULONGLONG a, ULONGLONG b )
{
    return a / b;
}


/******************************************************************************
 *        _aullrem   (NTDLL.@)
 */
ULONGLONG WINAPI _aullrem( ULONGLONG a, ULONGLONG b )
{
    return a % b;
}
