/**
 * This file has no copyright assigned and is placed in the Public Domain.
 * This file is part of the mingw-w64 runtime package.
 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
 */

#include "internal.h"

#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
/* Internal MinGW version of MS __control87_2 with following differences:
 * - Availability:
 *   - MinGW provides both i386 and x64 implementation
 *   - MS provides only i386 implementation and only for msvcr80+
 * - Usage of x87 fwait instruction which triggers pending x87 exceptions:
 *   - MinGW does not call it
 *   - MS calls it before reading x87 cw
 */
int __mingw_control87_2( unsigned int newval, unsigned int mask,
                         unsigned int *x86_cw, unsigned int *sse2_cw )
{
    if (x86_cw)
    {
        *x86_cw = newval;
        __mingw_setfp(x86_cw, mask, NULL, 0);
    }

    if (!sse2_cw) return 1;

    if (__mingw_has_sse())
    {
        *sse2_cw = newval;
        __mingw_setfp_sse(sse2_cw, mask, NULL, 0);
    }
    else *sse2_cw = 0;

    return 1;
}
#endif

/* Internal MinGW version of MS _control87 with following differences:
 * - Usage of x87 fwait instruction which triggers pending x87 exceptions:
 *   - MinGW does not call it
 *   - MS x64 does not call it
 *   - MS i386 calls it before reading x87 cw
 * - Source of the flags:
 *   - MinGW i386 and x64 returns from both x87 and SSE2
 *   - MS i386 msvcrt from Vista+ and msvcr80+ returns from both x87 and SSE2
 *   - MS i386 msvcrt before Vista and pre-msvcr80 returns from x87
 *   - MS x64 returns from SSE2
 * This makes behavior of MinGW version same for all builds,
 * always returns information from both x87 and SSE2 and
 * never triggers pending x87 exceptions.
 */
unsigned int __mingw_controlfp(unsigned int newval, unsigned int mask)
{
    unsigned int flags = 0;
#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
    unsigned int sse2_cw;

    __mingw_control87_2( newval, mask, &flags, &sse2_cw );

    if (__mingw_has_sse())
    {
        if ((flags ^ sse2_cw) & (_MCW_EM | _MCW_RC)) flags |= _EM_AMBIGUOUS;
        flags |= sse2_cw;
    }
#else
    flags = newval;
    __mingw_setfp(&flags, mask, NULL, 0);
#endif
    return flags;
}

