From nobody Sun May 5 23:15:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1593129641; cv=none; d=zohomail.com; s=zohoarc; b=iF3P7JKf3po4KjUgkO5ATFLHDjv96PjEJJCFywlxCDVJR9gTkMwAoiqvnWkont9VBykrCsTU5RzwBxf4+6jyOK5Flz1ScATGHkP1CQp/Gek6MkQBiV9hkTNdkEKhwFT2ejNtNqfzTReaUyJ+SMPhVLwZJB53Tn/u/AuPpdH43Kk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1593129641; h=Content-Type:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=B6NRdCYeWpTSvy/eQNR7GA1h/H9t19PzUWStvNPZI9k=; b=GLijA/TRi0DME1wyBEHBimpDZRDqMekigNm7YY2U+3InFVERHFGHllXonmu8kC3M2tFMDxGCgXT4/q+sZ1DUfXlCFJxX3Sb6sbKwmiLKB/xXOIS8zZgUWiimQkZS8T8hNRh85srvc/RAK7XvjfJmAqft8AkUMkr+qxD++GnJx9Q= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1593129641247876.9560554132106; Thu, 25 Jun 2020 17:00:41 -0700 (PDT) Received: from localhost ([::1]:46586 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jobnL-0003fc-TZ for importer@patchew.org; Thu, 25 Jun 2020 20:00:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:55448) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jobkf-0002T7-WF for qemu-devel@nongnu.org; Thu, 25 Jun 2020 19:57:54 -0400 Received: from esa4.mentor.iphmx.com ([68.232.137.252]:7874) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jobkd-0001K2-Py for qemu-devel@nongnu.org; Thu, 25 Jun 2020 19:57:53 -0400 Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 25 Jun 2020 15:57:49 -0800 IronPort-SDR: aDEKSapLTGe1aVDuTMqBj1K84F73VJPJR9d8AFLCWjsgpZhLa7BP6HvxE3/LvCfGvKJSEhM6ie MUnA8/FzkyioRzPOOLKNxmPGaCe5C+zheFSKxlMXSOpxOgWHbCyTfw5gtzeFyLDDFnAX0MYkFE hy61GwNPH98yNQyGyD47T+Hs3nuH8dlgPSXD3+UGu8tQxmb/x8zd0Q2H1Tz0GhFbA6SPTKoB3v n9JbB5vFye23V48cHmBJElWyv76KNT0l1JULZE0p91lSjSt2jn8ReKs8lrexlOmpo2aAIjua3P nC4= X-IronPort-AV: E=Sophos;i="5.75,281,1589270400"; d="scan'208";a="50332679" IronPort-SDR: WNt7BuIQ6juNauqa6WyUyv2kR95Jf8O/tKapbJ534X7aSKzaR5125uVQdWhHRlBexBgqZoFuBa 2JFMwDIJ8ipOmrFxpSc/QICzIUq70OybZyfUGnp3L56BnghhTlv0WUerFvXElU2Xh3Bo17i9kR 4M8LXBsS22xL6vHKNjIkOFuHA/6+fxVUYF0rMm8mweC19ESBy1lWQ8DTooD7O/fl02ZKMgKV/A fm+wFyo4n/xVj00aNAUbPe0IQQFy8SDbLbSfkz5apgPdJZ6QgpAfr+OjqCiPYbX4iBsAiKjTZU ZF8= Date: Thu, 25 Jun 2020 23:57:44 +0000 From: Joseph Myers X-X-Sender: jsm28@digraph.polyomino.org.uk To: , , , Subject: [PATCH 1/2] target/i386: set SSE FTZ in correct floating-point state In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) To SVR-IES-MBX-03.mgc.mentorg.com (139.181.222.3) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=68.232.137.252; envelope-from=joseph_myers@mentor.com; helo=esa4.mentor.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/25 19:57:50 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -31 X-Spam_score: -3.2 X-Spam_bar: --- X-Spam_report: (-3.2 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The code to set floating-point state when MXCSR changes calls set_flush_to_zero on &env->fp_status, so affecting the x87 floating-point state rather than the SSE state. Fix to call it for &env->sse_status instead. Signed-off-by: Joseph Myers --- target/i386/fpu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 8ef5b463ea..6590ce482f 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1830,7 +1830,7 @@ void update_mxcsr_status(CPUX86State *env) set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status); =20 /* set flush to zero */ - set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->fp_status); + set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } =20 void helper_ldmxcsr(CPUX86State *env, uint32_t val) --=20 2.17.1 --=20 Joseph S. Myers joseph@codesourcery.com From nobody Sun May 5 23:15:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1593129661; cv=none; d=zohomail.com; s=zohoarc; b=FPiGnzeD9+fsFqWtPv+ZomxvY5GINtvJ/V6uYfe1eB5bNPAe8ZrP8adzB2wQsW/n8vJC1K3AzOgxOl4Tq0eoeMl9u6FU4Wlfr9MehQ56ms3tD38e1rv/fLng/jXOW//4IGk30c3tK/BzTJY8LTOhB2s3ehQQ9XcbT68NQlKhlfM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1593129661; h=Content-Type:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=kpAmkBiGyJxY4XJnvtRFUGBpras+m/0CiPX8owAUVgY=; b=gKLmeHr7W1mjP4LnPoiOtqDjxRJchxU//cQlikbicA61n/XdN1jFUG7zLBFw4iqkZeLRxS4naZbKEyX+ZosbTQt4/hnLQUgcapN9RI3pU7JJHSkd6u1pclYJJ6jt06m4t44sNT2qgE9457FHHUAzWgLzRKoDR/EMHCg0eJ7W3DQ= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1593129661557306.00676344550857; Thu, 25 Jun 2020 17:01:01 -0700 (PDT) Received: from localhost ([::1]:47080 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jobng-0003tJ-7P for importer@patchew.org; Thu, 25 Jun 2020 20:01:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:55566) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1joblX-0002xo-QL for qemu-devel@nongnu.org; Thu, 25 Jun 2020 19:58:47 -0400 Received: from esa1.mentor.iphmx.com ([68.232.129.153]:22983) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1joblQ-0001eJ-7b for qemu-devel@nongnu.org; Thu, 25 Jun 2020 19:58:47 -0400 Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa1.mentor.iphmx.com with ESMTP; 25 Jun 2020 15:58:37 -0800 IronPort-SDR: gn5JL3YoeCG2kUjbZRkzSfieweXkvZiCjI1zBmAKtAxcY3VRJwsoYqYoIe9QmPgk1jKt9vSqZ8 Y3QpS4GtU7oEN1ML9F+75lMT78nYPKPU9dO9HhtZiwCE5X9ILfnh6IvuLVpX9LrzdL0QgFORu2 SFxJ4ZrKJvyFxkOJECFB0WtbitEFVUcZWbx8VLGwVFeWQDLoYlthk1UrCTl6+QPslUBvxHfEUC GkwEtrJTYP06cH3zyZxwZZyUP7U/a0//EYwP0pxM4lwce6m/CHMKDE2/Uf6InIpvwPZ8r0qW4Y ZE0= X-IronPort-AV: E=Sophos;i="5.75,281,1589270400"; d="scan'208";a="52348936" IronPort-SDR: 89dCPXUYYGA4e8siVoJd1A/PdMxTR2KgDpUvCQqusb4x4NwTbkw2lxvhSZi/b8ftCJuyywEN2l M1D1n7gwGKRUNamsJuACPguciBiV45xnlBkjXpaKPW1mw2rybuseb/o8vcVDTIZ2XyfVpPFCRa Q1qrXi1SkPOm07pJoll3xs5NFG6mt4F54qDn9a+F99MG44/NgfNp2k6LyVzS9Egu9sx2PD2aZX ahsuTl5r3A/G2t1PDxJ/i3px5ije5UaS9TBXm4IAIL5Vikiq9eV4uqbxlwhZm1iDEK6Ij6ucIh P5M= Date: Thu, 25 Jun 2020 23:58:31 +0000 From: Joseph Myers X-X-Sender: jsm28@digraph.polyomino.org.uk To: , , , Subject: [PATCH 2/2] target/i386: fix IEEE SSE floating-point exception raising In-Reply-To: Message-ID: References: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-06.mgc.mentorg.com (139.181.222.6) To SVR-IES-MBX-03.mgc.mentorg.com (139.181.222.3) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=68.232.129.153; envelope-from=joseph_myers@mentor.com; helo=esa1.mentor.iphmx.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/06/25 19:58:38 X-ACL-Warn: Detected OS = FreeBSD 9.x or newer [fuzzy] X-Spam_score_int: -31 X-Spam_score: -3.2 X-Spam_bar: --- X-Spam_report: (-3.2 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=1, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001 autolearn=_AUTOLEARN X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The SSE instruction implementations all fail to raise the expected IEEE floating-point exceptions because they do nothing to convert the exception state from the softfloat machinery into the exception flags in MXCSR. Fix this by adding such conversions. Unlike for x87, emulated SSE floating-point operations might be optimized using hardware floating point on the host, and so a different approach is taken that is compatible with such optimizations. The required invariant is that all exceptions set in env->sse_status (other than "denormal operand", for which the SSE semantics are different from those in the softfloat code) are ones that are set in the MXCSR; the emulated MXCSR is updated lazily when code reads MXCSR, while when code sets MXCSR, the exceptions in env->sse_status are set accordingly. A few instructions do not raise all the exceptions that would be raised by the softfloat code, and those instructions are made to save and restore the softfloat exception state accordingly. Nothing is done about "denormal operand"; setting that (only for the case when input denormals are *not* flushed to zero, the opposite of the logic in the softfloat code for such an exception) will require custom code for relevant instructions, or else architecture-specific conditionals in the softfloat code for when to set such an exception together with custom code for various SSE conversion and rounding instructions that do not set that exception. Nothing is done about trapping exceptions (for which there is minimal and largely broken support in QEMU's emulation in the x87 case and no support at all in the SSE case). Signed-off-by: Joseph Myers --- target/i386/cpu.h | 1 + target/i386/fpu_helper.c | 33 + target/i386/gdbstub.c | 1 + target/i386/helper.c | 1 + target/i386/helper.h | 1 + target/i386/ops_sse.h | 28 +- target/i386/translate.c | 1 + tests/tcg/i386/Makefile.target | 4 + tests/tcg/i386/test-i386-sse-exceptions.c | 813 ++++++++++++++++++++++ 9 files changed, 871 insertions(+), 12 deletions(-) create mode 100644 tests/tcg/i386/test-i386-sse-exceptions.c diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7d77efd9e4..06b2e3a5c6 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2143,6 +2143,7 @@ static inline bool cpu_vmx_maybe_enabled(CPUX86State = *env) /* fpu_helper.c */ void update_fp_status(CPUX86State *env); void update_mxcsr_status(CPUX86State *env); +void update_mxcsr_from_sse_status(CPUX86State *env); =20 static inline void cpu_set_mxcsr(CPUX86State *env, uint32_t mxcsr) { diff --git a/target/i386/fpu_helper.c b/target/i386/fpu_helper.c index 6590ce482f..bc79812fe3 100644 --- a/target/i386/fpu_helper.c +++ b/target/i386/fpu_helper.c @@ -1397,6 +1397,7 @@ static void do_xsave_fpu(CPUX86State *env, target_ulo= ng ptr, uintptr_t ra) =20 static void do_xsave_mxcsr(CPUX86State *env, target_ulong ptr, uintptr_t r= a) { + update_mxcsr_from_sse_status(env); cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr), env->mxcsr, ra); cpu_stl_data_ra(env, ptr + XO(legacy.mxcsr_mask), 0x0000ffff, ra); } @@ -1826,6 +1827,14 @@ void update_mxcsr_status(CPUX86State *env) } set_float_rounding_mode(rnd_type, &env->sse_status); =20 + /* Set exception flags. */ + set_float_exception_flags((mxcsr & FPUS_IE ? float_flag_invalid : 0) | + (mxcsr & FPUS_ZE ? float_flag_divbyzero : 0)= | + (mxcsr & FPUS_OE ? float_flag_overflow : 0) | + (mxcsr & FPUS_UE ? float_flag_underflow : 0)= | + (mxcsr & FPUS_PE ? float_flag_inexact : 0), + &env->sse_status); + /* set denormals are zero */ set_flush_inputs_to_zero((mxcsr & SSE_DAZ) ? 1 : 0, &env->sse_status); =20 @@ -1833,6 +1842,30 @@ void update_mxcsr_status(CPUX86State *env) set_flush_to_zero((mxcsr & SSE_FZ) ? 1 : 0, &env->sse_status); } =20 +void update_mxcsr_from_sse_status(CPUX86State *env) +{ + uint8_t flags =3D get_float_exception_flags(&env->sse_status); + /* + * The MXCSR denormal flag has opposite semantics to + * float_flag_input_denormal (the softfloat code sets that flag + * only when flushing input denormals to zero, but SSE sets it + * only when not flushing them to zero), so is not converted + * here. + */ + env->mxcsr |=3D ((flags & float_flag_invalid ? FPUS_IE : 0) | + (flags & float_flag_divbyzero ? FPUS_ZE : 0) | + (flags & float_flag_overflow ? FPUS_OE : 0) | + (flags & float_flag_underflow ? FPUS_UE : 0) | + (flags & float_flag_inexact ? FPUS_PE : 0) | + (flags & float_flag_output_denormal ? FPUS_UE | FPUS_PE= : + 0)); +} + +void helper_update_mxcsr(CPUX86State *env) +{ + update_mxcsr_from_sse_status(env); +} + void helper_ldmxcsr(CPUX86State *env, uint32_t val) { cpu_set_mxcsr(env, val); diff --git a/target/i386/gdbstub.c b/target/i386/gdbstub.c index b98a99500a..9ae43bda0f 100644 --- a/target/i386/gdbstub.c +++ b/target/i386/gdbstub.c @@ -184,6 +184,7 @@ int x86_cpu_gdb_read_register(CPUState *cs, GByteArray = *mem_buf, int n) return gdb_get_reg32(mem_buf, 0); /* fop */ =20 case IDX_MXCSR_REG: + update_mxcsr_from_sse_status(env); return gdb_get_reg32(mem_buf, env->mxcsr); =20 case IDX_CTL_CR0_REG: diff --git a/target/i386/helper.c b/target/i386/helper.c index c3a6e4fabe..fa2a1dcdda 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -544,6 +544,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flag= s) for(i =3D 0; i < 8; i++) { fptag |=3D ((!env->fptags[i]) << i); } + update_mxcsr_from_sse_status(env); qemu_fprintf(f, "FCW=3D%04x FSW=3D%04x [ST=3D%d] FTW=3D%02x MXCSR= =3D%08x\n", env->fpuc, (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11, diff --git a/target/i386/helper.h b/target/i386/helper.h index 8f9e1905c3..c2ae2f7e61 100644 --- a/target/i386/helper.h +++ b/target/i386/helper.h @@ -207,6 +207,7 @@ DEF_HELPER_FLAGS_2(pext, TCG_CALL_NO_RWG_SE, tl, tl, tl) /* MMX/SSE */ =20 DEF_HELPER_2(ldmxcsr, void, env, i32) +DEF_HELPER_1(update_mxcsr, void, env) DEF_HELPER_1(enter_mmx, void, env) DEF_HELPER_1(emms, void, env) DEF_HELPER_3(movq, void, env, ptr, ptr) diff --git a/target/i386/ops_sse.h b/target/i386/ops_sse.h index 14f2b16abd..c7614f8b0b 100644 --- a/target/i386/ops_sse.h +++ b/target/i386/ops_sse.h @@ -843,6 +843,7 @@ int64_t helper_cvttsd2sq(CPUX86State *env, ZMMReg *s) =20 void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); d->ZMM_S(0) =3D float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); @@ -855,26 +856,33 @@ void helper_rsqrtps(CPUX86State *env, ZMMReg *d, ZMMR= eg *s) d->ZMM_S(3) =3D float32_div(float32_one, float32_sqrt(s->ZMM_S(3), &env->sse_status), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } =20 void helper_rsqrtss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); d->ZMM_S(0) =3D float32_div(float32_one, float32_sqrt(s->ZMM_S(0), &env->sse_status), &env->sse_status); + set_float_exception_flags(old_flags, &env->sse_status); } =20 void helper_rcpps(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); d->ZMM_S(0) =3D float32_div(float32_one, s->ZMM_S(0), &env->sse_status= ); d->ZMM_S(1) =3D float32_div(float32_one, s->ZMM_S(1), &env->sse_status= ); d->ZMM_S(2) =3D float32_div(float32_one, s->ZMM_S(2), &env->sse_status= ); d->ZMM_S(3) =3D float32_div(float32_one, s->ZMM_S(3), &env->sse_status= ); + set_float_exception_flags(old_flags, &env->sse_status); } =20 void helper_rcpss(CPUX86State *env, ZMMReg *d, ZMMReg *s) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); d->ZMM_S(0) =3D float32_div(float32_one, s->ZMM_S(0), &env->sse_status= ); + set_float_exception_flags(old_flags, &env->sse_status); } =20 static inline uint64_t helper_extrq(uint64_t src, int shift, int len) @@ -1764,6 +1772,7 @@ void glue(helper_phminposuw, SUFFIX)(CPUX86State *env= , Reg *d, Reg *s) void glue(helper_roundps, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; =20 prev_rounding_mode =3D env->sse_status.float_rounding_mode; @@ -1789,19 +1798,18 @@ void glue(helper_roundps, SUFFIX)(CPUX86State *env,= Reg *d, Reg *s, d->ZMM_S(2) =3D float32_round_to_int(s->ZMM_S(2), &env->sse_status); d->ZMM_S(3) =3D float32_round_to_int(s->ZMM_S(3), &env->sse_status); =20 -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_stat= us) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode =3D prev_rounding_mode; } =20 void glue(helper_roundpd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; =20 prev_rounding_mode =3D env->sse_status.float_rounding_mode; @@ -1825,19 +1833,18 @@ void glue(helper_roundpd, SUFFIX)(CPUX86State *env,= Reg *d, Reg *s, d->ZMM_D(0) =3D float64_round_to_int(s->ZMM_D(0), &env->sse_status); d->ZMM_D(1) =3D float64_round_to_int(s->ZMM_D(1), &env->sse_status); =20 -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_stat= us) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode =3D prev_rounding_mode; } =20 void glue(helper_roundss, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; =20 prev_rounding_mode =3D env->sse_status.float_rounding_mode; @@ -1860,19 +1867,18 @@ void glue(helper_roundss, SUFFIX)(CPUX86State *env,= Reg *d, Reg *s, =20 d->ZMM_S(0) =3D float32_round_to_int(s->ZMM_S(0), &env->sse_status); =20 -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_stat= us) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode =3D prev_rounding_mode; } =20 void glue(helper_roundsd, SUFFIX)(CPUX86State *env, Reg *d, Reg *s, uint32_t mode) { + uint8_t old_flags =3D get_float_exception_flags(&env->sse_status); signed char prev_rounding_mode; =20 prev_rounding_mode =3D env->sse_status.float_rounding_mode; @@ -1895,13 +1901,11 @@ void glue(helper_roundsd, SUFFIX)(CPUX86State *env,= Reg *d, Reg *s, =20 d->ZMM_D(0) =3D float64_round_to_int(s->ZMM_D(0), &env->sse_status); =20 -#if 0 /* TODO */ - if (mode & (1 << 3)) { + if (mode & (1 << 3) && !(old_flags & float_flag_inexact)) { set_float_exception_flags(get_float_exception_flags(&env->sse_stat= us) & ~float_flag_inexact, &env->sse_status); } -#endif env->sse_status.float_rounding_mode =3D prev_rounding_mode; } =20 diff --git a/target/i386/translate.c b/target/i386/translate.c index 5e5dbb41b0..b3fea54411 100644 --- a/target/i386/translate.c +++ b/target/i386/translate.c @@ -8157,6 +8157,7 @@ static target_ulong disas_insn(DisasContext *s, CPUSt= ate *cpu) gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); break; } + gen_helper_update_mxcsr(cpu_env); gen_lea_modrm(env, s, modrm); tcg_gen_ld32u_tl(s->T0, cpu_env, offsetof(CPUX86State, mxcsr)); gen_op_st_v(s, MO_32, s->T0, s->A0); diff --git a/tests/tcg/i386/Makefile.target b/tests/tcg/i386/Makefile.target index 1a6463a7dc..a66232a67d 100644 --- a/tests/tcg/i386/Makefile.target +++ b/tests/tcg/i386/Makefile.target @@ -10,6 +10,10 @@ ALL_X86_TESTS=3D$(I386_SRCS:.c=3D) SKIP_I386_TESTS=3Dtest-i386-ssse3 X86_64_TESTS:=3D$(filter test-i386-ssse3, $(ALL_X86_TESTS)) =20 +test-i386-sse-exceptions: CFLAGS +=3D -msse4.1 -mfpmath=3Dsse +run-test-i386-sse-exceptions: QEMU_OPTS +=3D -cpu max +run-plugin-test-i386-sse-exceptions-%: QEMU_OPTS +=3D -cpu max + test-i386-pcmpistri: CFLAGS +=3D -msse4.2 run-test-i386-pcmpistri: QEMU_OPTS +=3D -cpu max run-plugin-test-i386-pcmpistri-%: QEMU_OPTS +=3D -cpu max diff --git a/tests/tcg/i386/test-i386-sse-exceptions.c b/tests/tcg/i386/tes= t-i386-sse-exceptions.c new file mode 100644 index 0000000000..a104f46c11 --- /dev/null +++ b/tests/tcg/i386/test-i386-sse-exceptions.c @@ -0,0 +1,813 @@ +/* Test SSE exceptions. */ + +#include +#include +#include + +volatile float f_res; +volatile double d_res; + +volatile float f_snan =3D __builtin_nansf(""); +volatile float f_half =3D 0.5f; +volatile float f_third =3D 1.0f / 3.0f; +volatile float f_nan =3D __builtin_nanl(""); +volatile float f_inf =3D __builtin_inff(); +volatile float f_ninf =3D -__builtin_inff(); +volatile float f_one =3D 1.0f; +volatile float f_two =3D 2.0f; +volatile float f_zero =3D 0.0f; +volatile float f_nzero =3D -0.0f; +volatile float f_min =3D FLT_MIN; +volatile float f_true_min =3D 0x1p-149f; +volatile float f_max =3D FLT_MAX; +volatile float f_nmax =3D -FLT_MAX; + +volatile double d_snan =3D __builtin_nans(""); +volatile double d_half =3D 0.5; +volatile double d_third =3D 1.0 / 3.0; +volatile double d_nan =3D __builtin_nan(""); +volatile double d_inf =3D __builtin_inf(); +volatile double d_ninf =3D -__builtin_inf(); +volatile double d_one =3D 1.0; +volatile double d_two =3D 2.0; +volatile double d_zero =3D 0.0; +volatile double d_nzero =3D -0.0; +volatile double d_min =3D DBL_MIN; +volatile double d_true_min =3D 0x1p-1074; +volatile double d_max =3D DBL_MAX; +volatile double d_nmax =3D -DBL_MAX; + +volatile int32_t i32_max =3D INT32_MAX; + +#define IE (1 << 0) +#define ZE (1 << 2) +#define OE (1 << 3) +#define UE (1 << 4) +#define PE (1 << 5) +#define EXC (IE | ZE | OE | UE | PE) + +uint32_t mxcsr_default =3D 0x1f80; +uint32_t mxcsr_ftz =3D 0x9f80; + +int main(void) +{ + uint32_t mxcsr; + int32_t i32_res; + int ret =3D 0; + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D f_snan; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: widen float snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D d_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: narrow float underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D d_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: narrow float overflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: narrow float inexact\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D d_snan; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: narrow float snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $4, %0, %0" : "=3Dx" (f_res) : "0" (f_min)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: roundss min\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $12, %0, %0" : "=3Dx" (f_res) : "0" (f_min)= ); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: roundss no-inexact min\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $4, %0, %0" : "=3Dx" (f_res) : "0" (f_snan)= ); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: roundss snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundss $12, %0, %0" : "=3Dx" (f_res) : "0" (f_snan= )); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: roundss no-inexact snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $4, %0, %0" : "=3Dx" (d_res) : "0" (d_min)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: roundsd min\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $12, %0, %0" : "=3Dx" (d_res) : "0" (d_min)= ); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: roundsd no-inexact min\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $4, %0, %0" : "=3Dx" (d_res) : "0" (d_snan)= ); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: roundsd snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("roundsd $12, %0, %0" : "=3Dx" (d_res) : "0" (d_snan= )); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: roundsd no-inexact snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("comiss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: comiss nan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomiss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: ucomiss nan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomiss %1, %0" : : "x" (f_snan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: ucomiss snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("comisd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: comisd nan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomisd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: ucomisd nan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("ucomisd %1, %0" : : "x" (d_snan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: ucomisd snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_max + f_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: float add overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_max + f_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: float add inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_inf + f_ninf; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float add inf -inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_snan + f_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float add snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res =3D f_true_min + f_true_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: float add FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_max + d_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: double add overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_max + d_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: double add inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_inf + d_ninf; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double add inf -inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_snan + d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double add snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res =3D d_true_min + d_true_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: double add FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_max - f_nmax; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: float sub overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_max - f_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: float sub inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_inf - f_inf; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float sub inf inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_snan - f_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float sub snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res =3D f_min - f_true_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: float sub FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_max - d_nmax; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: double sub overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_max - d_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: double sub inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_inf - d_inf; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double sub inf inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_snan - d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double sub snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res =3D d_min - d_true_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: double sub FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_max * f_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: float mul overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_third * f_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: float mul inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_min * f_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: float mul underflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_inf * f_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float mul inf 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_snan * f_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float mul snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res =3D f_min * f_half; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: float mul FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_max * d_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: double mul overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_third * d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: double mul inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_min * d_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: double mul underflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_inf * d_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double mul inf 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_snan * d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double mul snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res =3D d_min * d_half; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: double mul FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_max / f_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: float div overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_one / f_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: float div inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_min / f_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: float div underflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_one / f_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D ZE) { + printf("FAIL: float div 1 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_inf / f_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: float div inf 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_nan / f_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: float div nan 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_zero / f_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float div 0 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_inf / f_inf; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float div inf inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + f_res =3D f_snan / f_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: float div snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + f_res =3D f_min / f_two; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: float div FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_max / d_min; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (OE | PE)) { + printf("FAIL: double div overflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_one / d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: double div inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_min / d_max; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: double div underflow\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_one / d_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D ZE) { + printf("FAIL: double div 1 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_inf / d_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: double div inf 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_nan / d_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: double div nan 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_zero / d_zero; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double div 0 0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_inf / d_inf; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double div inf inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + d_res =3D d_snan / d_third; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: double div snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_ftz)); + d_res =3D d_min / d_two; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D (UE | PE)) { + printf("FAIL: double div FTZ underflow\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=3Dx" (f_res) : "0" (f_max)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: sqrtss inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=3Dx" (f_res) : "0" (f_nmax)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: sqrtss -max\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=3Dx" (f_res) : "0" (f_ninf)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: sqrtss -inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=3Dx" (f_res) : "0" (f_snan)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: sqrtss snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=3Dx" (f_res) : "0" (f_nzero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: sqrtss -0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtss %0, %0" : "=3Dx" (f_res) : + "0" (-__builtin_nanf(""))); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: sqrtss -nan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=3Dx" (d_res) : "0" (d_max)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: sqrtsd inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=3Dx" (d_res) : "0" (d_nmax)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: sqrtsd -max\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=3Dx" (d_res) : "0" (d_ninf)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: sqrtsd -inf\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=3Dx" (d_res) : "0" (d_snan)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: sqrtsd snan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=3Dx" (d_res) : "0" (d_nzero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: sqrtsd -0\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("sqrtsd %0, %0" : "=3Dx" (d_res) : + "0" (-__builtin_nan(""))); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: sqrtsd -nan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("maxss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: maxss nan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("minss %1, %0" : : "x" (f_nan), "x" (f_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: minss nan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("maxsd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: maxsd nan\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("minsd %1, %0" : : "x" (d_nan), "x" (d_zero)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: minsd nan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsi2ss %1, %0" : "=3Dx" (f_res) : "m" (i32_max)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: cvtsi2ss inexact\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsi2sd %1, %0" : "=3Dx" (d_res) : "m" (i32_max)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: cvtsi2sd exact\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=3Dr" (i32_res) : "x" (1.5f)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: cvtss2si inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=3Dr" (i32_res) : "x" (0x1p31f)= ); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvtss2si 0x1p31\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtss2si %1, %0" : "=3Dr" (i32_res) : "x" (f_inf)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvtss2si inf\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=3Dr" (i32_res) : "x" (1.5)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: cvtsd2si inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=3Dr" (i32_res) : "x" (0x1p31)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvtsd2si 0x1p31\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvtsd2si %1, %0" : "=3Dr" (i32_res) : "x" (d_inf)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvtsd2si inf\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=3Dr" (i32_res) : "x" (1.5f)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: cvttss2si inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=3Dr" (i32_res) : "x" (0x1p31f= )); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvttss2si 0x1p31\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttss2si %1, %0" : "=3Dr" (i32_res) : "x" (f_inf)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvttss2si inf\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=3Dr" (i32_res) : "x" (1.5)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D PE) { + printf("FAIL: cvttsd2si inexact\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=3Dr" (i32_res) : "x" (0x1p31)= ); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvttsd2si 0x1p31\n"); + ret =3D 1; + } + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("cvttsd2si %1, %0" : "=3Dr" (i32_res) : "x" (d_inf)); + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D IE) { + printf("FAIL: cvttsd2si inf\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("rcpss %0, %0" : "=3Dx" (f_res) : "0" (f_snan)); + f_res +=3D f_one; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: rcpss snan\n"); + ret =3D 1; + } + + __asm__ volatile ("ldmxcsr %0" : : "m" (mxcsr_default)); + __asm__ volatile ("rsqrtss %0, %0" : "=3Dx" (f_res) : "0" (f_snan)); + f_res +=3D f_one; + __asm__ volatile ("stmxcsr %0" : "=3Dm" (mxcsr)); + if ((mxcsr & EXC) !=3D 0) { + printf("FAIL: rsqrtss snan\n"); + ret =3D 1; + } + + return ret; +} --=20 2.17.1 --=20 Joseph S. Myers joseph@codesourcery.com