📄 sys_float.c
字号:
#if defined(__x86_64__) if ((opcode & 0xF0) == 0x40) opcode = *pc++;#endif do { switch (opcode) { case 0x0F: opcode = *pc++; switch (opcode) { case 0x2A: /* cvtpi2ps,cvtsi2sd,cvtsi2ss /r */ case 0x2C: /* cvttpd2pi,cvttps2pi,cvttsd2si,cvtss2si /r */ case 0x2D: /* cvtpd2pi,cvtps2pi,cvtsd2si,cvtss2si /r */ case 0x2E: /* ucomisd,ucomiss /r */ case 0x2F: /* comisd,comiss /r */ case 0x51: /* sqrtpd,sqrtps,sqrtsd,sqrtss /r */ case 0x58: /* addpd,addps,addsd,addss /r */ case 0x59: /* mulpd,mulps,mulsd,mulss /r */ case 0x5A: /* cvtpd2ps,cvtps2pd,cvtsd2ss,cvtss2sd /r */ case 0x5B: /* cvtdq2ps,cvtps2dq,cvttps2dq /r */ case 0x5C: /* subpd,subps,subsd,subss /r */ case 0x5D: /* minpd,minps,minsd,minss /r */ case 0x5E: /* divpd,divps,divsd,divss /r */ case 0x5F: /* maxpd,maxps,maxsd,maxss /r */ case 0xE6: /* cvtpd2dq,cvttpd2dq /r */ nr_skip_bytes = 0; continue; case 0xC2: /* cmppd,cmpps,cmpsd,cmpss /r /ib */ nr_skip_bytes = 1; continue; } } fprintf(stderr, "%s: unexpected code at %p:", __FUNCTION__, pc0); do { fprintf(stderr, " %02X", *pc0++); } while (pc0 < pc); fprintf(stderr, "\r\n"); abort(); } while (0); /* Past the opcode. Parse and skip the mod/rm and sib bytes. */ opcode = *pc++; switch ((opcode >> 6) & 3) { /* inspect mod */ case 0: switch (opcode & 7) { /* inspect r/m */ case 4: opcode = *pc++; /* sib */ switch (opcode & 7) { /* inspect base */ case 5: nr_skip_bytes += 4; /* disp32 */ break; } break; case 5: nr_skip_bytes += 4; /* disp32 */ break; } break; case 1: nr_skip_bytes += 1; /* disp8 */ switch (opcode & 7) { /* inspect r/m */ case 4: pc += 1; /* sib */ break; } break; case 2: nr_skip_bytes += 4; /* disp32 */ switch (opcode & 7) { /* inspect r/m */ case 4: pc += 1; /* sib */ break; } break; case 3: break; } /* Past mod/rm and sib. Skip any disp, and /ib for cmp{pd,ps,sd,ss}. */ pc += nr_skip_bytes; /* The longest instruction handled above is 11 bytes. So there is no need to check the 15-byte instruction length limit here. */ /* Done. */ mc_pc(mc) = (long)pc;}#endif /* (__linux__ && (__x86_64__ || __i386__)) || (__DARWIN__ && __i386__) || (__FreeBSD__ && (__x86_64__ || __i386__)) || (__OpenBSD__ && __x86_64__) || (__sun__ && __x86_64__) */#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || (defined(__OpenBSD__) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__))#if defined(__linux__) && defined(__i386__)#include <asm/sigcontext.h>#elif defined(__FreeBSD__) && defined(__x86_64__)#include <sys/types.h>#include <machine/fpu.h>#elif defined(__FreeBSD__) && defined(__i386__)#include <sys/types.h>#include <machine/npx.h>#elif defined(__OpenBSD__) && defined(__x86_64__)#include <sys/types.h>#include <machine/fpu.h>#endif#if !(defined(__OpenBSD__) && defined(__x86_64__))#include <ucontext.h>#endif#include <string.h>static void fpe_sig_action(int sig, siginfo_t *si, void *puc){ ucontext_t *uc = puc;#if defined(__linux__)#if defined(__x86_64__) mcontext_t *mc = &uc->uc_mcontext; fpregset_t fpstate = mc->fpregs; /* A failed SSE2 instruction will restart. To avoid looping, we must update RIP to skip the instruction (leaving garbage in the destination). The alternative is to mask SSE2 exceptions now and unmask them again later in erts_check_fpe(), but that relies too much on other code being cooperative. */ if (fpstate->mxcsr & 0x000D) { /* OE|ZE|IE; see unmask_sse2() */ fpstate->mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(mc); } fpstate->swd &= ~0xFF;#elif defined(__i386__) mcontext_t *mc = &uc->uc_mcontext; fpregset_t fpstate = mc->fpregs; if ((fpstate->status >> 16) == X86_FXSR_MAGIC && ((struct _fpstate*)fpstate)->mxcsr & 0x000D) { ((struct _fpstate*)fpstate)->mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(mc); } fpstate->sw &= ~0xFF;#elif defined(__sparc__) /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */ struct sigcontext *sc = (struct sigcontext*)puc; sc->si_regs.pc = sc->si_regs.npc; sc->si_regs.npc = (unsigned long)sc->si_regs.npc + 4;#elif defined(__powerpc__)#if defined(__powerpc64__) mcontext_t *mc = &uc->uc_mcontext; unsigned long *regs = &mc->gp_regs[0];#else mcontext_t *mc = uc->uc_mcontext.uc_regs; unsigned long *regs = &mc->gregs[0];#endif regs[PT_NIP] += 4; regs[PT_FPSCR] = 0x80|0x40|0x10; /* VE, OE, ZE; not UE or XE */#endif#elif defined(__DARWIN__) && defined(__i386__) mcontext_t mc = uc->uc_mcontext; if (mc->fs.fpu_mxcsr & 0x000D) { mc->fs.fpu_mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(mc); } *(unsigned short *)&mc->fs.fpu_fsw &= ~0xFF;#elif defined(__DARWIN__) && defined(__ppc__) mcontext_t mc = uc->uc_mcontext; mc->ss.srr0 += 4; mc->fs.fpscr = 0x80|0x40|0x10;#elif defined(__FreeBSD__) && defined(__x86_64__) mcontext_t *mc = &uc->uc_mcontext; struct savefpu *savefpu = (struct savefpu*)&mc->mc_fpstate; struct envxmm *envxmm = &savefpu->sv_env; if (envxmm->en_mxcsr & 0x000D) { envxmm->en_mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(mc); } envxmm->en_sw &= ~0xFF;#elif defined(__FreeBSD__) && defined(__i386__) mcontext_t *mc = &uc->uc_mcontext; union savefpu *savefpu = (union savefpu*)&mc->mc_fpstate; if (mc->mc_fpformat == _MC_FPFMT_XMM) { struct envxmm *envxmm = &savefpu->sv_xmm.sv_env; if (envxmm->en_mxcsr & 0x000D) { envxmm->en_mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(mc); } envxmm->en_sw &= ~0xFF; } else { struct env87 *env87 = &savefpu->sv_87.sv_env; env87->en_sw &= ~0xFF; }#elif defined(__OpenBSD__) && defined(__x86_64__) struct fxsave64 *fxsave = uc->sc_fpstate; if (fxsave->fx_mxcsr & 0x000D) { fxsave->fx_mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(uc); } fxsave->fx_fsw &= ~0xFF;#elif defined(__sun__) && defined(__x86_64__) mcontext_t *mc = &uc->uc_mcontext; struct fpchip_state *fpstate = &mc->fpregs.fp_reg_set.fpchip_state; if (fpstate->mxcsr & 0x000D) { fpstate->mxcsr &= ~(0x003F|0x0680); skip_sse2_insn(mc); } fpstate->sw &= ~0xFF;#endif set_current_fp_exception();}static void erts_thread_catch_fp_exceptions(void){ struct sigaction act; memset(&act, 0, sizeof act); act.sa_sigaction = fpe_sig_action; act.sa_flags = SA_SIGINFO; sigaction(SIGFPE, &act, NULL); unmask_fpe();}#else /* !((__linux__ && (__i386__ || __x86_64__ || __powerpc__)) || (__DARWIN__ && (__i386__ || __ppc__))) */static void fpe_sig_handler(int sig){ set_current_fp_exception();}static void erts_thread_catch_fp_exceptions(void){ sys_sigset(SIGFPE, fpe_sig_handler); unmask_fpe();}#endif /* (__linux__ && (__i386__ || __x86_64__ || __powerpc__)) || (__DARWIN__ && (__i386__ || __ppc__))) *//* once-only initialisation early in the main thread */void erts_sys_init_float(void){ erts_init_fp_exception(); erts_thread_catch_fp_exceptions();}#endif /* NO_FPE_SIGNALS */void erts_thread_init_float(void){#ifdef ERTS_SMP /* This allows Erlang schedulers to leave Erlang-process context and still have working FP exceptions. XXX: is this needed? */ erts_thread_init_fp_exception();#endif#if !defined(NO_FPE_SIGNALS) && (defined(__DARWIN__) || defined(__FreeBSD__)) /* Darwin (7.9.0) does not appear to propagate FP exception settings to a new thread from its parent. So if we want FP exceptions, we must manually re-enable them in each new thread. FreeBSD 6.1 appears to suffer from a similar issue. */ erts_thread_catch_fp_exceptions();#endif}/* The following check is incorporated from the Vee machine */ #define ISDIGIT(d) ((d) >= '0' && (d) <= '9')/* ** Convert a double to ascii format 0.dddde[+|-]ddd ** return number of characters converted ** ** These two functions should maybe use localeconv() to pick up ** the current radix character, but since it is uncertain how ** expensive such a system call is, and since no-one has heard ** of other radix characters than '.' and ',' an ad-hoc ** low execution time solution is used instead. */intsys_double_to_chars(double fp, char *buf){ char *s = buf; (void) sprintf(buf, "%.20e", fp); /* Search upto decimal point */ if (*s == '+' || *s == '-') s++; while (ISDIGIT(*s)) s++; if (*s == ',') *s++ = '.'; /* Replace ',' with '.' */ /* Scan to end of string */ while (*s) s++; return s-buf; /* i.e strlen(buf) */}/* Float conversion */intsys_chars_to_double(char* buf, double* fp){ volatile int *fpexnp = erts_get_current_fp_exception(); char *s = buf, *t, *dp; /* Robert says that something like this is what he really wanted: * (The [.,] radix test is NOT what Robert wanted - it was added later) * * 7 == sscanf(Tbuf, "%[+-]%[0-9][.,]%[0-9]%[eE]%[+-]%[0-9]%s", ....); * if (*s2 == 0 || *s3 == 0 || *s4 == 0 || *s6 == 0 || *s7) * break; */ /* Scan string to check syntax. */ if (*s == '+' || *s == '-') s++; if (!ISDIGIT(*s)) /* Leading digits. */ return -1; while (ISDIGIT(*s)) s++; if (*s != '.' && *s != ',') /* Decimal part. */ return -1; dp = s++; /* Remember decimal point pos just in case */ if (!ISDIGIT(*s)) return -1; while (ISDIGIT(*s)) s++; if (*s == 'e' || *s == 'E') { /* There is an exponent. */ s++; if (*s == '+' || *s == '-') s++; if (!ISDIGIT(*s)) return -1; while (ISDIGIT(*s)) s++; } if (*s) /* That should be it */ return -1;#ifdef NO_FPE_SIGNALS errno = 0;#endif __ERTS_FP_CHECK_INIT(fpexnp); *fp = strtod(buf, &t); __ERTS_FP_ERROR_THOROUGH(fpexnp, *fp, return -1); if (t != s) { /* Whole string not scanned */ /* Try again with other radix char */ *dp = (*dp == '.') ? ',' : '.'; errno = 0; __ERTS_FP_CHECK_INIT(fpexnp); *fp = strtod(buf, &t); __ERTS_FP_ERROR_THOROUGH(fpexnp, *fp, return -1); }#ifdef DEBUG if (errno == ERANGE) fprintf(stderr, "errno = ERANGE in list_to_float\n\r");#endif#ifdef NO_FPE_SIGNALS if (errno == ERANGE) return -1;#endif/*** Replaces following code:** if (errno == ERANGE) {** *fp = 1.2e300; ** *fp = *fp / 1.5e-100; ** } */ return 0;}intmatherr(struct exception *exc){ set_current_fp_exception(); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -