diff options
Diffstat (limited to 'src/recompiler/Sun')
-rw-r--r-- | src/recompiler/Sun/Makefile.kup | 0 | ||||
-rw-r--r-- | src/recompiler/Sun/config-host.h | 46 | ||||
-rw-r--r-- | src/recompiler/Sun/config.h | 44 | ||||
-rw-r--r-- | src/recompiler/Sun/crt/stdio.h | 73 | ||||
-rw-r--r-- | src/recompiler/Sun/deftoimp.sed | 37 | ||||
-rw-r--r-- | src/recompiler/Sun/e_powl-amd64.S | 371 | ||||
-rw-r--r-- | src/recompiler/Sun/e_powl-x86.S | 413 | ||||
-rw-r--r-- | src/recompiler/Sun/kvm.h | 28 | ||||
-rw-r--r-- | src/recompiler/Sun/testmath.c | 828 |
9 files changed, 1840 insertions, 0 deletions
diff --git a/src/recompiler/Sun/Makefile.kup b/src/recompiler/Sun/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/recompiler/Sun/Makefile.kup diff --git a/src/recompiler/Sun/config-host.h b/src/recompiler/Sun/config-host.h new file mode 100644 index 00000000..a18a147e --- /dev/null +++ b/src/recompiler/Sun/config-host.h @@ -0,0 +1,46 @@ +/* $Id: config-host.h $ */ +/** @file + * Sun host config - maintained by hand + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +#if defined(RT_ARCH_AMD64) +# define HOST_X86_64 1 +# define HOST_LONG_BITS 64 +#else +# define HOST_I386 1 +# define HOST_LONG_BITS 32 +#endif + +#ifndef IPRT_NO_CRT +# ifdef RT_OS_WINDOWS +# define CONFIG_WIN32 1 +# elif defined(RT_OS_OS2) +# define CONFIG_OS2 +# elif defined(RT_OS_DARWIN) +# define CONFIG_DARWIN +# elif defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD) +# define HAVE_MACHINE_BSWAP_H +/*# define CONFIG_BSD*/ +# elif defined(RT_OS_SOLARIS) +# define CONFIG_SOLARIS +# else +# define HAVE_BYTESWAP_H 1 +# endif +#endif +#define QEMU_VERSION "0.13.0" +#define CONFIG_UNAME_RELEASE "" +#define CONFIG_QEMU_SHAREDIR "." + diff --git a/src/recompiler/Sun/config.h b/src/recompiler/Sun/config.h new file mode 100644 index 00000000..173b660d --- /dev/null +++ b/src/recompiler/Sun/config.h @@ -0,0 +1,44 @@ +/* $Id: config.h $ */ +/** @file + * Sun config - Maintained by hand + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include "config-host.h" +#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386" +#define TARGET_ARCH "i386" +#define TARGET_I386 1 +#define CONFIG_SOFTMMU 1 +#define TARGET_PHYS_ADDR_BITS 64 + +#ifdef VBOX_WITH_64_BITS_GUESTS +# if defined(__x86_64__) || defined (VBOX_ENABLE_VBOXREM64) +# define TARGET_X86_64 +# endif +#endif + +/* Uncomment to see all phys memory accesses */ +/* #define VBOX_DEBUG_PHYS */ +/* Uncomment to see emulated CPU state changes */ +/* #define VBOX_DUMP_STATE */ +/* Uncomment to see QEMU logging, goes to /tmp/vbox-qemu.log */ +/* #define DEBUG_ALL_LOGGING */ +/* Uncomment to see generated code */ +/* #define DEBUG_DISAS */ + +#if 0 /*defined(RT_ARCH_AMD64) && defined(VBOX_STRICT)*/ +# define VBOX_CHECK_ADDR(ptr) do { if ((uintptr_t)(ptr) >= _4G) __asm__("int3"); } while (0) +#else +# define VBOX_CHECK_ADDR(ptr) do { } while (0) +#endif diff --git a/src/recompiler/Sun/crt/stdio.h b/src/recompiler/Sun/crt/stdio.h new file mode 100644 index 00000000..5c73fb1a --- /dev/null +++ b/src/recompiler/Sun/crt/stdio.h @@ -0,0 +1,73 @@ +/* $Id: stdio.h $ */ +/** @file + * Our minimal stdio + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ___Sun_stdio_h +#define ___Sun_stdio_h + +#ifndef LOG_GROUP +# define UNDO_LOG_GROUP +#endif + +#include <VBox/log.h> + +#ifdef UNDO_LOG_GROUP +# undef UNDO_LOG_GROUP +# undef LOG_GROUP +#endif + +#ifndef LOG_USE_C99 +# error "LOG_USE_C99 isn't defined." +#endif + +RT_C_DECLS_BEGIN + +typedef struct FILE FILE; + +#if defined(RT_OS_SOLARIS) +/** @todo Check solaris' floatingpoint.h as to why we do this */ +# define _FILEDEFED +#endif + +DECLINLINE(int) fprintf(FILE *ignored, const char *pszFormat, ...) +{ +/** @todo We don't support wrapping calls taking a va_list yet. It's not worth it yet, + * since there are only a couple of cases where this fprintf implementation is used. + * (The macro below will deal with the majority of the fprintf calls.) */ +#if 0 /*def LOG_ENABLED*/ + if (LogIsItEnabled(NULL, 0, LOG_GROUP_REM_PRINTF)) + { + va_list va; + va_start(va, pszFormat); + RTLogLoggerExV(NULL, 0, LOG_GROUP_REM_PRINTF, pszFormat, va); + va_end(va); + } +#endif + return 0; +} + +#define fflush(file) RTLogFlush(NULL) +#define printf(...) LogIt(0, LOG_GROUP_REM_PRINTF, (__VA_ARGS__)) +#define fprintf(logfile, ...) LogIt(0, LOG_GROUP_REM_PRINTF, (__VA_ARGS__)) + +#ifdef DEBUG_TMP_LOGGING +# error "DEBUG_TMP_LOGGING doesn't work with the Sun/crt/stdio.h wrapper." +#endif + +RT_C_DECLS_END + +#endif + diff --git a/src/recompiler/Sun/deftoimp.sed b/src/recompiler/Sun/deftoimp.sed new file mode 100644 index 00000000..3e35efa1 --- /dev/null +++ b/src/recompiler/Sun/deftoimp.sed @@ -0,0 +1,37 @@ +# $Id: deftoimp.sed $ +## @file +# SED script for generating a dummy .so from a windows .def file. +# + +# +# Copyright (C) 2006-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# + +s/;.*$//g +s/^[[:space:]][[:space:]]*//g +s/[[:space:]][[:space:]]*$//g +/^$/d + +# Handle text after EXPORTS +/EXPORTS/,//{ +s/^EXPORTS$// +/^$/b end + +s/^\(.*\)$/EXPORT\nvoid \1(void);\nvoid \1(void){}/ +b end +} +d +b end + + +# next expression +:end + diff --git a/src/recompiler/Sun/e_powl-amd64.S b/src/recompiler/Sun/e_powl-amd64.S new file mode 100644 index 00000000..5e0353e7 --- /dev/null +++ b/src/recompiler/Sun/e_powl-amd64.S @@ -0,0 +1,371 @@ +/* ix87 specific implementation of pow function. + Copyright (C) 1996, 1997, 1998, 1999, 2001, 2004 Free Software Foundation + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice + * other than GPL or LGPL is available it will apply instead, Oracle elects to use only + * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the language indicating + * that LGPLv2 or any later version may be used, or where a choice of which version + * of the LGPL is applied is otherwise unspecified. + */ + +/*#include <machine/asm.h>*/ +#include <iprt/cdefs.h> + +#define ALIGNARG(log2) 1<<log2 +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name; +#define ASM_GLOBAL_DIRECTIVE .global + +#define C_LABEL(name) name: +#define C_SYMBOL_NAME(name) name + +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(4); \ + C_LABEL(name) + +#undef END +#define END(name) \ + ASM_SIZE_DIRECTIVE(name) + + +#ifdef __ELF__ + .section .rodata +#else + .text +#endif + + .align ALIGNARG(4) + ASM_TYPE_DIRECTIVE(infinity,@object) +inf_zero: +infinity: + .byte 0, 0, 0, 0, 0, 0, 0xf0, 0x7f + ASM_SIZE_DIRECTIVE(infinity) + ASM_TYPE_DIRECTIVE(zero,@object) +zero: .double 0.0 + ASM_SIZE_DIRECTIVE(zero) + ASM_TYPE_DIRECTIVE(minf_mzero,@object) +minf_mzero: +minfinity: + .byte 0, 0, 0, 0, 0, 0, 0xf0, 0xff +mzero: + .byte 0, 0, 0, 0, 0, 0, 0, 0x80 + ASM_SIZE_DIRECTIVE(minf_mzero) + ASM_TYPE_DIRECTIVE(one,@object) +one: .double 1.0 + ASM_SIZE_DIRECTIVE(one) + ASM_TYPE_DIRECTIVE(limit,@object) +limit: .double 0.29 + ASM_SIZE_DIRECTIVE(limit) + ASM_TYPE_DIRECTIVE(p63,@object) +p63: + .byte 0, 0, 0, 0, 0, 0, 0xe0, 0x43 + ASM_SIZE_DIRECTIVE(p63) + +//#ifdef PIC +//#define MO(op) op##(%rip) +//#else +#define MO(op) op +//#endif + + .text +/*ENTRY(__ieee754_powl)*/ +ENTRY(RT_NOCRT(powl)) + + fldt 24(%rsp) // y + fxam + + + fnstsw + movb %ah, %dl + andb $0x45, %ah + cmpb $0x40, %ah // is y == 0 ? + je 11f + + cmpb $0x05, %ah // is y == ±inf ? + je 12f + + cmpb $0x01, %ah // is y == NaN ? + je 30f + + fldt 8(%rsp) // x : y + + fxam + fnstsw + movb %ah, %dh + andb $0x45, %ah + cmpb $0x40, %ah + je 20f // x is ±0 + + cmpb $0x05, %ah + je 15f // x is ±inf + + fxch // y : x + + /* fistpll raises invalid exception for |y| >= 1L<<63. */ + fldl MO(p63) // 1L<<63 : y : x + fld %st(1) // y : 1L<<63 : y : x + fabs // |y| : 1L<<63 : y : x + fcomip %st(1), %st // 1L<<63 : y : x + fstp %st(0) // y : x + jnc 2f + + /* First see whether `y' is a natural number. In this case we + can use a more precise algorithm. */ + fld %st // y : y : x + fistpll -8(%rsp) // y : x + fildll -8(%rsp) // int(y) : y : x + fucomip %st(1),%st // y : x + jne 2f + + /* OK, we have an integer value for y. */ + mov -8(%rsp),%eax + mov -4(%rsp),%edx + orl $0, %edx + fstp %st(0) // x + jns 4f // y >= 0, jump + fdivrl MO(one) // 1/x (now referred to as x) + negl %eax + adcl $0, %edx + negl %edx +4: fldl MO(one) // 1 : x + fxch + +6: shrdl $1, %edx, %eax + jnc 5f + fxch + fmul %st(1) // x : ST*x + fxch +5: fmul %st(0), %st // x*x : ST*x + shrl $1, %edx + movl %eax, %ecx + orl %edx, %ecx + jnz 6b + fstp %st(0) // ST*x + ret + + /* y is ±NAN */ +30: fldt 8(%rsp) // x : y + fldl MO(one) // 1.0 : x : y + fucomip %st(1),%st // x : y + je 31f + fxch // y : x +31: fstp %st(1) + ret + + .align ALIGNARG(4) +2: /* y is a real number. */ + fxch // x : y + fldl MO(one) // 1.0 : x : y + fld %st(1) // x : 1.0 : x : y + fsub %st(1) // x-1 : 1.0 : x : y + fabs // |x-1| : 1.0 : x : y + fcompl MO(limit) // 1.0 : x : y + fnstsw + fxch // x : 1.0 : y + test $4500,%eax + jz 7f + fsub %st(1) // x-1 : 1.0 : y + fyl2xp1 // log2(x) : y + jmp 8f + +7: fyl2x // log2(x) : y +8: fmul %st(1) // y*log2(x) : y + fxam + fnstsw + andb $0x45, %ah + cmpb $0x05, %ah // is y*log2(x) == ±inf ? + je 28f + fst %st(1) // y*log2(x) : y*log2(x) + frndint // int(y*log2(x)) : y*log2(x) + fsubr %st, %st(1) // int(y*log2(x)) : fract(y*log2(x)) + fxch // fract(y*log2(x)) : int(y*log2(x)) + f2xm1 // 2^fract(y*log2(x))-1 : int(y*log2(x)) + faddl MO(one) // 2^fract(y*log2(x)) : int(y*log2(x)) + fscale // 2^fract(y*log2(x))*2^int(y*log2(x)) : int(y*log2(x)) + fstp %st(1) // 2^fract(y*log2(x))*2^int(y*log2(x)) + ret + +28: fstp %st(1) // y*log2(x) + fldl MO(one) // 1 : y*log2(x) + fscale // 2^(y*log2(x)) : y*log2(x) + fstp %st(1) // 2^(y*log2(x)) + ret + + // pow(x,±0) = 1 + .align ALIGNARG(4) +11: fstp %st(0) // pop y + fldl MO(one) + ret + + // y == ±inf + .align ALIGNARG(4) +12: fstp %st(0) // pop y + fldt 8(%rsp) // x + fabs + fcompl MO(one) // < 1, == 1, or > 1 + fnstsw + andb $0x45, %ah + cmpb $0x45, %ah + je 13f // jump if x is NaN + + cmpb $0x40, %ah + je 14f // jump if |x| == 1 + + shlb $1, %ah + xorb %ah, %dl + andl $2, %edx +#ifdef PIC + lea inf_zero(%rip),%rcx + fldl (%rcx, %rdx, 4) +#else + fldl inf_zero(,%rdx, 4) +#endif + ret + + .align ALIGNARG(4) +14: fldl MO(one) + ret + + .align ALIGNARG(4) +13: fldt 8(%rsp) // load x == NaN + ret + + .align ALIGNARG(4) + // x is ±inf +15: fstp %st(0) // y + testb $2, %dh + jz 16f // jump if x == +inf + + // We must find out whether y is an odd integer. + fld %st // y : y + fistpll -8(%rsp) // y + fildll -8(%rsp) // int(y) : y + fucomip %st(1),%st + ffreep %st // <empty> + jne 17f + + // OK, the value is an integer, but is it odd? + mov -8(%rsp), %eax + mov -4(%rsp), %edx + andb $1, %al + jz 18f // jump if not odd + // It's an odd integer. + shrl $31, %edx +#ifdef PIC + lea minf_mzero(%rip),%rcx + fldl (%rcx, %rdx, 8) +#else + fldl minf_mzero(,%rdx, 8) +#endif + ret + + .align ALIGNARG(4) +16: fcompl MO(zero) + fnstsw + shrl $5, %eax + andl $8, %eax +#ifdef PIC + lea inf_zero(%rip),%rcx + fldl (%rcx, %rax, 1) +#else + fldl inf_zero(,%rax, 1) +#endif + ret + + .align ALIGNARG(4) +17: shll $30, %edx // sign bit for y in right position +18: shrl $31, %edx +#ifdef PIC + lea inf_zero(%rip),%rcx + fldl (%rcx, %rdx, 8) +#else + fldl inf_zero(,%rdx, 8) +#endif + ret + + .align ALIGNARG(4) + // x is ±0 +20: fstp %st(0) // y + testb $2, %dl + jz 21f // y > 0 + + // x is ±0 and y is < 0. We must find out whether y is an odd integer. + testb $2, %dh + jz 25f + + fld %st // y : y + fistpll -8(%rsp) // y + fildll -8(%rsp) // int(y) : y + fucomip %st(1),%st + ffreep %st // <empty> + jne 26f + + // OK, the value is an integer, but is it odd? + mov -8(%rsp),%eax + mov -4(%rsp),%edx + andb $1, %al + jz 27f // jump if not odd + // It's an odd integer. + // Raise divide-by-zero exception and get minus infinity value. + fldl MO(one) + fdivl MO(zero) + fchs + ret + +25: fstp %st(0) +26: +27: // Raise divide-by-zero exception and get infinity value. + fldl MO(one) + fdivl MO(zero) + ret + + .align ALIGNARG(4) + // x is ±0 and y is > 0. We must find out whether y is an odd integer. +21: testb $2, %dh + jz 22f + + fld %st // y : y + fistpll -8(%rsp) // y + fildll -8(%rsp) // int(y) : y + fucomip %st(1),%st + ffreep %st // <empty> + jne 23f + + // OK, the value is an integer, but is it odd? + mov -8(%rsp),%eax + mov -4(%rsp),%edx + andb $1, %al + jz 24f // jump if not odd + // It's an odd integer. + fldl MO(mzero) + ret + +22: fstp %st(0) +23: +24: fldl MO(zero) + ret + +/*END(__ieee754_powl)*/ +END(RT_NOCRT(powl)) + diff --git a/src/recompiler/Sun/e_powl-x86.S b/src/recompiler/Sun/e_powl-x86.S new file mode 100644 index 00000000..cbc99256 --- /dev/null +++ b/src/recompiler/Sun/e_powl-x86.S @@ -0,0 +1,413 @@ +/* ix87 specific implementation of pow function. + Copyright (C) 1996, 1997, 1998, 1999, 2001, 2004, 2005 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice + * other than GPL or LGPL is available it will apply instead, Oracle elects to use only + * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the language indicating + * that LGPLv2 or any later version may be used, or where a choice of which version + * of the LGPL is applied is otherwise unspecified. + */ + +/*#include <machine/asm.h>*/ +#include <iprt/cdefs.h> + +#ifdef __MINGW32__ +# define ASM_TYPE_DIRECTIVE(name,typearg) +# define ASM_SIZE_DIRECTIVE(name) +# define cfi_adjust_cfa_offset(a) +# define C_LABEL(name) _ ## name: +# define C_SYMBOL_NAME(name) _ ## name +# define ASM_GLOBAL_DIRECTIVE .global +# define ALIGNARG(log2) 1<<log2 +#elif __APPLE__ +# define ASM_TYPE_DIRECTIVE(name,typearg) +# define ASM_SIZE_DIRECTIVE(name) +# define cfi_adjust_cfa_offset(a) +# define C_LABEL(name) _ ## name: +# define C_SYMBOL_NAME(name) _ ## name +# define ASM_GLOBAL_DIRECTIVE .globl +# define ALIGNARG(log2) log2 +#else +# define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +# define ASM_SIZE_DIRECTIVE(name) .size name,.-name; +# define C_LABEL(name) name: +# define C_SYMBOL_NAME(name) name +# /* figure this one out. */ +# define cfi_adjust_cfa_offset(a) +# define ASM_GLOBAL_DIRECTIVE .global +# define ALIGNARG(log2) 1<<log2 +#endif + +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(4); \ + C_LABEL(name) + +#undef END +#define END(name) \ + ASM_SIZE_DIRECTIVE(name) + +#ifdef __ELF__ + .section .rodata +#else + .text +#endif + + .align ALIGNARG(4) + ASM_TYPE_DIRECTIVE(infinity,@object) +inf_zero: +infinity: + .byte 0, 0, 0, 0, 0, 0, 0xf0, 0x7f + ASM_SIZE_DIRECTIVE(infinity) + ASM_TYPE_DIRECTIVE(zero,@object) +zero: .double 0.0 + ASM_SIZE_DIRECTIVE(zero) + ASM_TYPE_DIRECTIVE(minf_mzero,@object) +minf_mzero: +minfinity: + .byte 0, 0, 0, 0, 0, 0, 0xf0, 0xff +mzero: + .byte 0, 0, 0, 0, 0, 0, 0, 0x80 + ASM_SIZE_DIRECTIVE(minf_mzero) + ASM_TYPE_DIRECTIVE(one,@object) +one: .double 1.0 + ASM_SIZE_DIRECTIVE(one) + ASM_TYPE_DIRECTIVE(limit,@object) +limit: .double 0.29 + ASM_SIZE_DIRECTIVE(limit) + ASM_TYPE_DIRECTIVE(p63,@object) +p63: .byte 0, 0, 0, 0, 0, 0, 0xe0, 0x43 + ASM_SIZE_DIRECTIVE(p63) + +#ifdef PIC +#define MO(op) op##@GOTOFF(%ecx) +#define MOX(op,x,f) op##@GOTOFF(%ecx,x,f) +#else +#define MO(op) op +#define MOX(op,x,f) op(,x,f) +#endif + + .text +//ENTRY(__ieee754_powl) +ENTRY(RT_NOCRT(powl)) +#ifdef RT_OS_DARWIN /* 16-byte long double with 8 byte alignment requirements */ + fldt 20(%esp) // y +#else + fldt 16(%esp) // y +#endif + fxam + +#ifdef PIC + LOAD_PIC_REG (cx) +#endif + + fnstsw + movb %ah, %dl + andb $0x45, %ah + cmpb $0x40, %ah // is y == 0 ? + je .L11 + + cmpb $0x05, %ah // is y == ±inf ? + je .L12 + + cmpb $0x01, %ah // is y == NaN ? + je .L30 + + fldt 4(%esp) // x : y + + subl $8,%esp + cfi_adjust_cfa_offset (8) + + fxam + fnstsw + movb %ah, %dh + andb $0x45, %ah + cmpb $0x40, %ah + je .L20 // x is ±0 + + cmpb $0x05, %ah + je .L15 // x is ±inf + + fxch // y : x + + /* fistpll raises invalid exception for |y| >= 1L<<63. */ + fld %st // y : y : x + fabs // |y| : y : x + fcompl MO(p63) // y : x + fnstsw + sahf + jnc .L2 + + /* First see whether `y' is a natural number. In this case we + can use a more precise algorithm. */ + fld %st // y : y : x + fistpll (%esp) // y : x + fildll (%esp) // int(y) : y : x + fucomp %st(1) // y : x + fnstsw + sahf + jne .L2 + + /* OK, we have an integer value for y. */ + popl %eax + cfi_adjust_cfa_offset (-4) + popl %edx + cfi_adjust_cfa_offset (-4) + orl $0, %edx + fstp %st(0) // x + jns .L4 // y >= 0, jump + fdivrl MO(one) // 1/x (now referred to as x) + negl %eax + adcl $0, %edx + negl %edx +.L4: fldl MO(one) // 1 : x + fxch + +.L6: shrdl $1, %edx, %eax + jnc .L5 + fxch + fmul %st(1) // x : ST*x + fxch +.L5: fmul %st(0), %st // x*x : ST*x + shrl $1, %edx + movl %eax, %ecx + orl %edx, %ecx + jnz .L6 + fstp %st(0) // ST*x + ret + + /* y is ±NAN */ +.L30: fldt 4(%esp) // x : y + fldl MO(one) // 1.0 : x : y + fucomp %st(1) // x : y + fnstsw + sahf + je .L31 + fxch // y : x +.L31: fstp %st(1) + ret + + cfi_adjust_cfa_offset (8) + .align ALIGNARG(4) +.L2: /* y is a real number. */ + fxch // x : y + fldl MO(one) // 1.0 : x : y + fld %st(1) // x : 1.0 : x : y + fsub %st(1) // x-1 : 1.0 : x : y + fabs // |x-1| : 1.0 : x : y + fcompl MO(limit) // 1.0 : x : y + fnstsw + fxch // x : 1.0 : y + sahf + ja .L7 + fsub %st(1) // x-1 : 1.0 : y + fyl2xp1 // log2(x) : y + jmp .L8 + +.L7: fyl2x // log2(x) : y +.L8: fmul %st(1) // y*log2(x) : y + fxam + fnstsw + andb $0x45, %ah + cmpb $0x05, %ah // is y*log2(x) == ±inf ? + je .L28 + fst %st(1) // y*log2(x) : y*log2(x) + frndint // int(y*log2(x)) : y*log2(x) + fsubr %st, %st(1) // int(y*log2(x)) : fract(y*log2(x)) + fxch // fract(y*log2(x)) : int(y*log2(x)) + f2xm1 // 2^fract(y*log2(x))-1 : int(y*log2(x)) + faddl MO(one) // 2^fract(y*log2(x)) : int(y*log2(x)) + fscale // 2^fract(y*log2(x))*2^int(y*log2(x)) : int(y*log2(x)) + addl $8, %esp + cfi_adjust_cfa_offset (-8) + fstp %st(1) // 2^fract(y*log2(x))*2^int(y*log2(x)) + ret + + cfi_adjust_cfa_offset (8) +.L28: fstp %st(1) // y*log2(x) + fldl MO(one) // 1 : y*log2(x) + fscale // 2^(y*log2(x)) : y*log2(x) + addl $8, %esp + cfi_adjust_cfa_offset (-8) + fstp %st(1) // 2^(y*log2(x)) + ret + + // pow(x,±0) = 1 + .align ALIGNARG(4) +.L11: fstp %st(0) // pop y + fldl MO(one) + ret + + // y == ±inf + .align ALIGNARG(4) +.L12: fstp %st(0) // pop y + fldt 4(%esp) // x + fabs + fcompl MO(one) // < 1, == 1, or > 1 + fnstsw + andb $0x45, %ah + cmpb $0x45, %ah + je .L13 // jump if x is NaN + + cmpb $0x40, %ah + je .L14 // jump if |x| == 1 + + shlb $1, %ah + xorb %ah, %dl + andl $2, %edx + fldl MOX(inf_zero, %edx, 4) + ret + + .align ALIGNARG(4) +.L14: fldl MO(one) + ret + + .align ALIGNARG(4) +.L13: fldt 4(%esp) // load x == NaN + ret + + cfi_adjust_cfa_offset (8) + .align ALIGNARG(4) + // x is ±inf +.L15: fstp %st(0) // y + testb $2, %dh + jz .L16 // jump if x == +inf + + // We must find out whether y is an odd integer. + fld %st // y : y + fistpll (%esp) // y + fildll (%esp) // int(y) : y + fucompp // <empty> + fnstsw + sahf + jne .L17 + + // OK, the value is an integer, but is it odd? + popl %eax + cfi_adjust_cfa_offset (-4) + popl %edx + cfi_adjust_cfa_offset (-4) + andb $1, %al + jz .L18 // jump if not odd + // It's an odd integer. + shrl $31, %edx + fldl MOX(minf_mzero, %edx, 8) + ret + + cfi_adjust_cfa_offset (8) + .align ALIGNARG(4) +.L16: fcompl MO(zero) + addl $8, %esp + cfi_adjust_cfa_offset (-8) + fnstsw + shrl $5, %eax + andl $8, %eax + fldl MOX(inf_zero, %eax, 1) + ret + + cfi_adjust_cfa_offset (8) + .align ALIGNARG(4) +.L17: shll $30, %edx // sign bit for y in right position + addl $8, %esp + cfi_adjust_cfa_offset (-8) +.L18: shrl $31, %edx + fldl MOX(inf_zero, %edx, 8) + ret + + cfi_adjust_cfa_offset (8) + .align ALIGNARG(4) + // x is ±0 +.L20: fstp %st(0) // y + testb $2, %dl + jz .L21 // y > 0 + + // x is ±0 and y is < 0. We must find out whether y is an odd integer. + testb $2, %dh + jz .L25 + + fld %st // y : y + fistpll (%esp) // y + fildll (%esp) // int(y) : y + fucompp // <empty> + fnstsw + sahf + jne .L26 + + // OK, the value is an integer, but is it odd? + popl %eax + cfi_adjust_cfa_offset (-4) + popl %edx + cfi_adjust_cfa_offset (-4) + andb $1, %al + jz .L27 // jump if not odd + // It's an odd integer. + // Raise divide-by-zero exception and get minus infinity value. + fldl MO(one) + fdivl MO(zero) + fchs + ret + + cfi_adjust_cfa_offset (8) +.L25: fstp %st(0) +.L26: addl $8, %esp + cfi_adjust_cfa_offset (-8) +.L27: // Raise divide-by-zero exception and get infinity value. + fldl MO(one) + fdivl MO(zero) + ret + + cfi_adjust_cfa_offset (8) + .align ALIGNARG(4) + // x is ±0 and y is > 0. We must find out whether y is an odd integer. +.L21: testb $2, %dh + jz .L22 + + fld %st // y : y + fistpll (%esp) // y + fildll (%esp) // int(y) : y + fucompp // <empty> + fnstsw + sahf + jne .L23 + + // OK, the value is an integer, but is it odd? + popl %eax + cfi_adjust_cfa_offset (-4) + popl %edx + cfi_adjust_cfa_offset (-4) + andb $1, %al + jz .L24 // jump if not odd + // It's an odd integer. + fldl MO(mzero) + ret + + cfi_adjust_cfa_offset (8) +.L22: fstp %st(0) +.L23: addl $8, %esp // Don't use 2 x pop + cfi_adjust_cfa_offset (-8) +.L24: fldl MO(zero) + ret + +END(RT_NOCRT(powl)) +//END(__ieee754_powl) diff --git a/src/recompiler/Sun/kvm.h b/src/recompiler/Sun/kvm.h new file mode 100644 index 00000000..0403e3e4 --- /dev/null +++ b/src/recompiler/Sun/kvm.h @@ -0,0 +1,28 @@ +/* $Id: kvm.h $ */ +/** @file + * VBox Recompiler - kvm stub header. + */ + +/* + * Copyright (C) 2011-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#ifndef ___kvm_stub_h___ +#define ___kvm_stub_h___ + +#define kvm_enabled() false +#define kvm_update_guest_debug(a, b) AssertFailed() +#define kvm_set_phys_mem(a, b, c) AssertFailed() +#define kvm_arch_get_registers(a) AssertFailed() +#define cpu_synchronize_state(a) do { } while (0) + +#endif + diff --git a/src/recompiler/Sun/testmath.c b/src/recompiler/Sun/testmath.c new file mode 100644 index 00000000..b1650753 --- /dev/null +++ b/src/recompiler/Sun/testmath.c @@ -0,0 +1,828 @@ +/* $Id: testmath.c $ */ +/** @file + * Testcase for the no-crt math stuff. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#ifndef MATHTEST_STANDALONE +# include <iprt/assert.h> +# include <math.h> +# undef printf +# define printf RTAssertMsg2Weak +#else +# include <stdio.h> +# include <math.h> +#endif + +/* gcc starting with version 4.3 uses the MPFR library which results in more accurate results. gcc-4.3.1 seems to emit the less accurate result. So just allow both results. */ +#define SIN180a -0.8011526357338304777463731115L +#define SIN180b -0.801152635733830477871L + +static void bitch(const char *pszWhat, const long double *plrdResult, const long double *plrdExpected) +{ + const unsigned char *pach1 = (const unsigned char *)plrdResult; + const unsigned char *pach2 = (const unsigned char *)plrdExpected; +#ifndef MATHTEST_STANDALONE + printf("error: %s - %d instead of %d\n", pszWhat, (int)(*plrdResult * 100000), (int)(*plrdExpected * 100000)); +#else + printf("error: %s - %.25f instead of %.25f\n", pszWhat, (double)*plrdResult, (double)*plrdExpected); +#endif + printf(" %02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x\n", pach1[0], pach1[1], pach1[2], pach1[3], pach1[4], pach1[5], pach1[6], pach1[7], pach1[8], pach1[9]); + printf(" %02x%02x%02x%02x-%02x%02x%02x%02x-%02x%02x\n", pach2[0], pach2[1], pach2[2], pach2[3], pach2[4], pach2[5], pach2[6], pach2[7], pach2[8], pach2[9]); +} + +static void bitchll(const char *pszWhat, long long llResult, long long llExpected) +{ +#if defined(__MINGW32__) && !defined(Assert) + printf("error: %s - %I64d instead of %I64d\n", pszWhat, llResult, llExpected); +#else + printf("error: %s - %lld instead of %lld\n", pszWhat, llResult, llExpected); +#endif +} + +static void bitchl(const char *pszWhat, long lResult, long lExpected) +{ + printf("error: %s - %ld instead of %ld\n", pszWhat, lResult, lExpected); +} + +extern int testsin(void) +{ + return sinl(180.0L) == SIN180a || sinl(180.0L) == SIN180b; +} + +extern int testremainder(void) +{ + static double s_rd1 = 2.5; + static double s_rd2 = 2.0; + static double s_rd3 = 0.5; + return remainder(s_rd1, s_rd2) == s_rd3; +} + +static __inline__ void set_cw(unsigned cw) +{ + __asm __volatile("fldcw %0" : : "m" (cw)); +} + +static __inline__ unsigned get_cw(void) +{ + unsigned cw; + __asm __volatile("fstcw %0" : "=m" (cw)); + return cw & 0xffff; +} + +static long double check_lrd(const long double lrd, const unsigned long long ull, const unsigned short us) +{ + static volatile long double lrd2; + lrd2 = lrd; + if ( *(unsigned long long *)&lrd2 != ull + || ((unsigned short *)&lrd2)[4] != us) + { +#if defined(__MINGW32__) && !defined(Assert) + printf("%I64x:%04x instead of %I64x:%04x\n", *(unsigned long long *)&lrd2, ((unsigned short *)&lrd2)[4], ull, us); +#else + printf("%llx:%04x instead of %llx:%04x\n", *(unsigned long long *)&lrd2, ((unsigned short *)&lrd2)[4], ull, us); +#endif + __asm__("int $3\n"); + } + return lrd; +} + + +static long double make_lrd(const unsigned long long ull, const unsigned short us) +{ + union + { + long double lrd; + struct + { + unsigned long long ull; + unsigned short us; + } i; + } u; + + u.i.ull = ull; + u.i.us = us; + return u.lrd; +} + +static long double check_lrd_cw(const long double lrd, const unsigned long long ull, const unsigned short us, const unsigned cw) +{ + set_cw(cw); + if (cw != get_cw()) + { + printf("get_cw() -> %#x expected %#x\n", get_cw(), cw); + __asm__("int $3\n"); + } + return check_lrd(lrd, ull, us); +} + +static long double make_lrd_cw(unsigned long long ull, unsigned short us, unsigned cw) +{ + set_cw(cw); + return check_lrd_cw(make_lrd(ull, us), ull, us, cw); +} + +extern int testmath(void) +{ + unsigned cErrors = 0; + long double lrdResult; + long double lrdExpect; + long double lrd; +#define CHECK(operation, expect) \ + do { \ + lrdExpect = expect; \ + lrdResult = operation; \ + if (lrdResult != lrdExpect) \ + { \ + bitch(#operation, &lrdResult, &lrdExpect); \ + cErrors++; \ + } \ + } while (0) + + long long llResult; + long long llExpect; +#define CHECKLL(operation, expect) \ + do { \ + llExpect = expect; \ + llResult = operation; \ + if (llResult != llExpect) \ + { \ + bitchll(#operation, llResult, llExpect); \ + cErrors++; \ + } \ + } while (0) + + long lResult; + long lExpect; +#define CHECKL(operation, expect) \ + do { \ + lExpect = expect; \ + lResult = operation; \ + if (lResult != lExpect) \ + { \ + bitchl(#operation, lResult, lExpect); \ + cErrors++; \ + } \ + } while (0) + + CHECK(atan2l(1.0L, 1.0L), 0.785398163397448309603L); + CHECK(atan2l(2.3L, 3.3L), 0.608689307327411694890L); + + CHECK(ceill(1.9L), 2.0L); + CHECK(ceill(4.5L), 5.0L); + CHECK(ceill(3.3L), 4.0L); + CHECK(ceill(6.1L), 7.0L); + + CHECK(floorl(1.9L), 1.0L); + CHECK(floorl(4.5L), 4.0L); + CHECK(floorl(7.3L), 7.0L); + CHECK(floorl(1234.1L), 1234.0L); + CHECK(floor(1233.1), 1233.0); + CHECK(floor(1239.98989898), 1239.0); + CHECK(floorf(9999.999), 9999.0); + + CHECK(ldexpl(1.0L, 1), 2.0L); + CHECK(ldexpl(1.0L, 10), 1024.0L); + CHECK(ldexpl(2.25L, 10), 2304.0L); + + CHECKLL(llrintl(1.0L), 1); + CHECKLL(llrintl(1.3L), 1); + CHECKLL(llrintl(1.5L), 2); + CHECKLL(llrintl(1.9L), 2); + CHECKLL(llrintf(123.34), 123); + CHECKLL(llrintf(-123.50), -124); + CHECKLL(llrint(42.42), 42); + CHECKLL(llrint(-2147483648.12343), -2147483648LL); +#if !defined(RT_ARCH_AMD64) + CHECKLL(lrint(-21474836499.12343), -2147483648LL); + CHECKLL(lrint(-2147483649932412.12343), -2147483648LL); +#else + CHECKLL(lrint(-21474836499.12343), -21474836499L); + CHECKLL(lrint(-2147483649932412.12343), -2147483649932412L); +#endif + +// __asm__("int $3"); + CHECKL(lrintl(make_lrd_cw(000000000000000000ULL,000000,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x067f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x067f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0a7f)), 1L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0a7f)), 1L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x3ffe,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x067f)), -1L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x067f)), -1L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0a7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0a7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0xbffe,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x067f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x067f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0a7f)), 1L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0a7f)), 1L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x9249249249249000ULL,0x3ffc,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x027f)), 0L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x067f)), -1L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x067f)), -1L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0a7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0a7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0xe38e38e38e38e000ULL,0xbffb,0x0e7f)), 0L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x027f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x027f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x067f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x067f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0a7f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0a7f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0e7f)), 32768L); + CHECKL(lrintl(make_lrd_cw(0x8000000000000000ULL,0x400e,0x0e7f)), 32768L); +#if !defined(RT_ARCH_AMD64) + /* c90 says that the constant is 2147483648 (which is not representable as a signed 32-bit + * value). To that constant you've then applied the negation operation. c90 doesn't have + * negative constants, only positive ones that have been negated. */ + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x027f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x027f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x067f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x067f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0a7f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0a7f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0e7f)), (long)(-2147483647L - 1)); + CHECKL(lrintl(make_lrd_cw(0xad78ebc5ac620000ULL,0xc041,0x0e7f)), (long)(-2147483647L - 1)); +#endif + set_cw(0x27f); + + CHECK(logl(2.7182818284590452353602874713526625L), 1.0); + + CHECK(remainderl(1.0L, 1.0L), 0.0); + CHECK(remainderl(1.0L, 1.5L), -0.5); + CHECK(remainderl(42.0L, 34.25L), 7.75); + CHECK(remainderf(43.0, 34.25), 8.75); + CHECK(remainder(44.25, 34.25), 10.00); + double rd1 = 44.25; + double rd2 = 34.25; + CHECK(remainder(rd1, rd2), 10.00); + CHECK(remainder(2.5, 2.0), 0.5); + CHECK(remainder(2.5, 2.0), 0.5); + CHECK(remainder(2.5, 2.0), 0.5); + CHECKLL(testremainder(), 1); + + + /* Only works in extended precision, while double precision is default on BSD (including Darwin) */ + set_cw(0x37f); + CHECK(rintl(1.0L), 1.0); + CHECK(rintl(1.4L), 1.0); + CHECK(rintl(1.3L), 1.0); + CHECK(rintl(0.9L), 1.0); + CHECK(rintl(3123.1232L), 3123.0); + CHECK(rint(3985.13454), 3985.0); + CHECK(rintf(9999.999), 10000.0); + set_cw(0x27f); + + CHECK(sinl(1.0L), 0.84147098480789650664L); +#if 0 + lrd = 180.0L; + CHECK(sinl(lrd), -0.801152635733830477871L); +#else + lrd = 180.0L; + lrdExpect = SIN180a; + lrdResult = sinl(lrd); + if (lrdResult != lrdExpect) + { + lrdExpect = SIN180b; + if (lrdResult != lrdExpect) + { + bitch("sinl(lrd)", &lrdResult, &lrdExpect); + cErrors++; + } + } +#endif +#if 0 + CHECK(sinl(180.0L), SIN180); +#else + lrdExpect = SIN180a; + lrdResult = sinl(180.0L); + if (lrdResult != lrdExpect) + { + lrdExpect = SIN180b; + if (lrdResult != lrdExpect) + { + bitch("sinl(180.0L)", &lrdResult, &lrdExpect); + cErrors++; + } + } +#endif + CHECKLL(testsin(), 1); + + CHECK(sqrtl(1.0L), 1.0); + CHECK(sqrtl(4.0L), 2.0); + CHECK(sqrtl(1525225.0L), 1235.0); + + CHECK(tanl(0.0L), 0.0); + CHECK(tanl(0.7853981633974483096156608458198757L), 1.0); + + CHECK(powl(0.0, 0.0), 1.0); + CHECK(powl(2.0, 2.0), 4.0); + CHECK(powl(3.0, 3.0), 27.0); + + return cErrors; +} + + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +#if 0 + +#define floatx_to_int32 floatx80_to_int32 +#define floatx_to_int64 floatx80_to_int64 +#define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero +#define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero +#define floatx_abs floatx80_abs +#define floatx_chs floatx80_chs +#define floatx_round_to_int(foo, bar) floatx80_round_to_int(foo, NULL) +#define floatx_compare floatx80_compare +#define floatx_compare_quiet floatx80_compare_quiet +#undef sin +#undef cos +#undef sqrt +#undef pow +#undef log +#undef tan +#undef atan2 +#undef floor +#undef ceil +#undef ldexp +#define sin sinl +#define cos cosl +#define sqrt sqrtl +#define pow powl +#define log logl +#define tan tanl +#define atan2 atan2l +#define floor floorl +#define ceil ceill +#define ldexp ldexpl + + +typedef long double CPU86_LDouble; + +typedef union { + long double d; + struct { + unsigned long long lower; + unsigned short upper; + } l; +} CPU86_LDoubleU; + +/* the following deal with x86 long double-precision numbers */ +#define MAXEXPD 0x7fff +#define EXPBIAS 16383 +#define EXPD(fp) (fp.l.upper & 0x7fff) +#define SIGND(fp) ((fp.l.upper) & 0x8000) +#define MANTD(fp) (fp.l.lower) +#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS + +typedef long double floatx80; +#define STATUS_PARAM , void *pv + +static floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM) +{ + return rintl(a); +} + + + +struct myenv +{ + unsigned int fpstt; /* top of stack index */ + unsigned int fpus; + unsigned int fpuc; + unsigned char fptags[8]; /* 0 = valid, 1 = empty */ + union { +#ifdef USE_X86LDOUBLE + CPU86_LDouble d __attribute__((aligned(16))); +#else + CPU86_LDouble d; +#endif + } fpregs[8]; + +} my_env, env_org, env_res, *env = &my_env; + + +#define ST0 (env->fpregs[env->fpstt].d) +#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d) +#define ST1 ST(1) +#define MAXTAN 9223372036854775808.0 + + +static inline void fpush(void) +{ + env->fpstt = (env->fpstt - 1) & 7; + env->fptags[env->fpstt] = 0; /* validate stack entry */ +} + +static inline void fpop(void) +{ + env->fptags[env->fpstt] = 1; /* invalidate stack entry */ + env->fpstt = (env->fpstt + 1) & 7; +} + +static void helper_f2xm1(void) +{ + ST0 = pow(2.0,ST0) - 1.0; +} + +static void helper_fyl2x(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp>0.0){ + fptemp = log(fptemp)/log(2.0); /* log2(ST) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +static void helper_fptan(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = tan(fptemp); + fpush(); + ST0 = 1.0; + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**52 only */ + } +} + +static void helper_fpatan(void) +{ + CPU86_LDouble fptemp, fpsrcop; + + fpsrcop = ST1; + fptemp = ST0; + ST1 = atan2(fpsrcop,fptemp); + fpop(); +} + +static void helper_fxtract(void) +{ + CPU86_LDoubleU temp; + unsigned int expdif; + + temp.d = ST0; + expdif = EXPD(temp) - EXPBIAS; + /*DP exponent bias*/ + ST0 = expdif; + fpush(); + BIASEXPONENT(temp); + ST0 = temp.d; +} + +static void helper_fprem1(void) +{ + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if (expdif < 53) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by rounding to the nearest */ + fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? + floor(fpsrcop): ceil(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +} + +static void helper_fprem(void) +{ +#if 0 +LogFlow(("helper_fprem: ST0=%.*Rhxs ST1=%.*Rhxs fpus=%#x\n", sizeof(ST0), &ST0, sizeof(ST1), &ST1, env->fpus)); + + __asm__ __volatile__("fldt (%2)\n" + "fldt (%1)\n" + "fprem \n" + "fnstsw (%0)\n" + "fstpt (%1)\n" + "fstpt (%2)\n" + : : "r" (&env->fpus), "r" (&ST0), "r" (&ST1) : "memory"); + +LogFlow(("helper_fprem: -> ST0=%.*Rhxs fpus=%#x c\n", sizeof(ST0), &ST0, env->fpus)); +#else + CPU86_LDouble dblq, fpsrcop, fptemp; + CPU86_LDoubleU fpsrcop1, fptemp1; + int expdif; + int q; + + fpsrcop = ST0; + fptemp = ST1; + fpsrcop1.d = fpsrcop; + fptemp1.d = fptemp; + + expdif = EXPD(fpsrcop1) - EXPD(fptemp1); + if ( expdif < 53 ) { + dblq = fpsrcop / fptemp; + dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); + ST0 = fpsrcop - fptemp*dblq; + q = (int)dblq; /* cutting off top bits is assumed here */ + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + /* (C0,C1,C3) <-- (q2,q1,q0) */ + env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ + env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ + env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ + } else { + env->fpus |= 0x400; /* C2 <-- 1 */ + fptemp = pow(2.0, expdif-50); + fpsrcop = (ST0 / ST1) / fptemp; + /* fpsrcop = integer obtained by chopping */ + fpsrcop = (fpsrcop < 0.0)? + -(floor(fabs(fpsrcop))): floor(fpsrcop); + ST0 -= (ST1 * fpsrcop * fptemp); + } +#endif +} + +static void helper_fyl2xp1(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp+1.0)>0.0) { + fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ + ST1 *= fptemp; + fpop(); + } else { + env->fpus &= (~0x4700); + env->fpus |= 0x400; + } +} + +static void helper_fsqrt(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if (fptemp<0.0) { + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + env->fpus |= 0x400; + } + ST0 = sqrt(fptemp); +} + +static void helper_fsincos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + fpush(); + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**63 only */ + } +} + +static void helper_frndint(void) +{ + ST0 = floatx_round_to_int(ST0, &env->fp_status); +} + +static void helper_fscale(void) +{ + ST0 = ldexp (ST0, (int)(ST1)); +} + +static void helper_fsin(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = sin(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg| < 2**53 only */ + } +} + +static void helper_fcos(void) +{ + CPU86_LDouble fptemp; + + fptemp = ST0; + if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { + env->fpus |= 0x400; + } else { + ST0 = cos(fptemp); + env->fpus &= (~0x400); /* C2 <-- 0 */ + /* the above code is for |arg5 < 2**63 only */ + } +} + +static void helper_fxam_ST0(void) +{ + CPU86_LDoubleU temp; + int expdif; + + temp.d = ST0; + + env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ + if (SIGND(temp)) + env->fpus |= 0x200; /* C1 <-- 1 */ + + /* XXX: test fptags too */ + expdif = EXPD(temp); + if (expdif == MAXEXPD) { +#ifdef USE_X86LDOUBLE + if (MANTD(temp) == 0x8000000000000000ULL) +#else + if (MANTD(temp) == 0) +#endif + env->fpus |= 0x500 /*Infinity*/; + else + env->fpus |= 0x100 /*NaN*/; + } else if (expdif == 0) { + if (MANTD(temp) == 0) + env->fpus |= 0x4000 /*Zero*/; + else + env->fpus |= 0x4400 /*Denormal*/; + } else { + env->fpus |= 0x400; + } +} + + +void check_env(void) +{ + int i; + for (i = 0; i < 8; i++) + { + CPU86_LDoubleU my, res; + my.d = env->fpregs[i].d; + res.d = env_res.fpregs[i].d; + + if ( my.l.lower != res.l.lower + || my.l.upper != res.l.upper) + printf("register %i: %#018llx:%#06x\n" + " expected %#018llx:%#06x\n", + i, + my.l.lower, my.l.upper, + res.l.lower, res.l.upper); + } + for (i = 0; i < 8; i++) + if (env->fptags[i] != env_res.fptags[i]) + printf("tag %i: %d != %d\n", i, env->fptags[i], env_res.fptags[i]); + if (env->fpstt != env_res.fpstt) + printf("fpstt: %#06x != %#06x\n", env->fpstt, env_res.fpstt); + if (env->fpuc != env_res.fpuc) + printf("fpuc: %#06x != %#06x\n", env->fpuc, env_res.fpuc); + if (env->fpus != env_res.fpus) + printf("fpus: %#06x != %#06x\n", env->fpus, env_res.fpus); +} +#endif /* not used. */ + +#if 0 /* insert this into helper.c */ +/* FPU helpers */ +CPU86_LDoubleU my_st[8]; +unsigned int my_fpstt; +unsigned int my_fpus; +unsigned int my_fpuc; +unsigned char my_fptags[8]; + +void hlp_fpu_enter(void) +{ + int i; + for (i = 0; i < 8; i++) + my_st[i].d = env->fpregs[i].d; + my_fpstt = env->fpstt; + my_fpus = env->fpus; + my_fpuc = env->fpuc; + memcpy(&my_fptags, &env->fptags, sizeof(my_fptags)); +} + +void hlp_fpu_leave(const char *psz) +{ + int i; + Log(("/*code*/ \n")); + for (i = 0; i < 8; i++) + Log(("/*code*/ *(unsigned long long *)&env_org.fpregs[%d] = %#018llxULL; ((unsigned short *)&env_org.fpregs[%d])[4] = %#06x; env_org.fptags[%d]=%d;\n", + i, my_st[i].l.lower, i, my_st[i].l.upper, i, my_fptags[i])); + Log(("/*code*/ env_org.fpstt=%#x;\n", my_fpstt)); + Log(("/*code*/ env_org.fpus=%#x;\n", my_fpus)); + Log(("/*code*/ env_org.fpuc=%#x;\n", my_fpuc)); + for (i = 0; i < 8; i++) + { + CPU86_LDoubleU u; + u.d = env->fpregs[i].d; + Log(("/*code*/ *(unsigned long long *)&env_res.fpregs[%d] = %#018llxULL; ((unsigned short *)&env_res.fpregs[%d])[4] = %#06x; env_res.fptags[%d]=%d;\n", + i, u.l.lower, i, u.l.upper, i, env->fptags[i])); + } + Log(("/*code*/ env_res.fpstt=%#x;\n", env->fpstt)); + Log(("/*code*/ env_res.fpus=%#x;\n", env->fpus)); + Log(("/*code*/ env_res.fpuc=%#x;\n", env->fpuc)); + + Log(("/*code*/ my_env = env_org;\n")); + Log(("/*code*/ %s();\n", psz)); + Log(("/*code*/ check_env();\n")); +} +#endif /* helper.c */ + +extern void testmath2(void ) +{ +#if 0 +#include "/tmp/code.h" +#endif +} + + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +#ifdef MATHTEST_STANDALONE + +void test_fops(double a, double b) +{ + printf("a=%f b=%f a+b=%f\n", a, b, a + b); + printf("a=%f b=%f a-b=%f\n", a, b, a - b); + printf("a=%f b=%f a*b=%f\n", a, b, a * b); + printf("a=%f b=%f a/b=%f\n", a, b, a / b); + printf("a=%f b=%f fmod(a, b)=%f\n", a, b, (double)fmod(a, b)); + printf("a=%f sqrt(a)=%f\n", a, (double)sqrtl(a)); + printf("a=%f sin(a)=%f\n", a, (double)sinl(a)); + printf("a=%f cos(a)=%f\n", a, (double)cos(a)); + printf("a=%f tan(a)=%f\n", a, (double)tanl(a)); + printf("a=%f log(a)=%f\n", a, (double)log(a)); + printf("a=%f exp(a)=%f\n", a, (double)exp(a)); + printf("a=%f b=%f atan2(a, b)=%f\n", a, b, atan2(a, b)); + /* just to test some op combining */ + printf("a=%f asin(sinl(a))=%f\n", a, (double)asin(sinl(a))); + printf("a=%f acos(cos(a))=%f\n", a, (double)acos(cos(a))); + printf("a=%f atan(tanl(a))=%f\n", a, (double)atan(tanl(a))); +} + +int main() +{ + unsigned cErrors = testmath(); + + testmath2(); + test_fops(2, 3); + test_fops(1.4, -5); + + printf("cErrors=%u\n", cErrors); + return cErrors; +} +#endif + |