From patchwork Fri Feb 15 19:22:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158536 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1061123jaa; Fri, 15 Feb 2019 11:23:30 -0800 (PST) X-Google-Smtp-Source: AHgI3IZ0dBwHXrAu+kmi5oIrYuE2/nlZd79Oy/u/J44tur1fe1d0OPZBLpmf7ejMAmLOV7PL5Vcb X-Received: by 2002:a25:bbd1:: with SMTP id c17mr9402020ybk.519.1550258610531; Fri, 15 Feb 2019 11:23:30 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258610; cv=none; d=google.com; s=arc-20160816; b=HVNtU52maCZPCoLfBTT2OWI3fyMCnQ0kkZqgOAPUDibgjM61MVRgt20rIV/9U2pc8k LHnmiy2NLKITEGRsK2RBFqw5DdUB+8rYvLiT12rFiBdimpR0pU0mXAx+LMWcnCMHpZWo pOdEBhUqVyEfgNMkNabiw8LSg9LvF2aTslBiaQztwz1970p4hfP1O4yLFS7KtkjIsztJ cIumod22+ahbsH4PUz/Jxrrgczu33u18nEBxq14j9ZJgclKb4vFaTu4r/Id4idD/BssT Xv/lZsiB4mE3joswbjufHE5EsDt8an6nyaZbA88vniDD7oPV8a/l54pTqP88oa7tO2C0 vj5g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=3oH383gg4Bjb4JyarPs8/S+LBRYRoxcsv9/An4O0Kgc=; b=LCjAPS8SnLFKbK/zuoThGKqPbcOUux7QXQWbqDtwQOudoI6b3iafrX3XVwgqjkK7s2 MXsQrjWa34uFo23DT6j+atXJZw9mEzvpWlIBP9x6XZEH5GH4vPC+VgLncZMmjHhUP4jL gjaFPC08LNNzAsVgq7ZoAYDwr5m3zjIoFbgGxhXMOnfP2RoBXxpRpzYJzZCcAMCXgmQr 8KlxvFY1GwWaJmBMEUtQXDzMwEQXBfGjkfPBw2WNJO3IGmZWi86+wgg8oYYrerL2F6lh eI46Y/hhRvn1W9XLyltsJu4QjBQkRznF19Hk9VoROZde1ll1ydxvgtWJFNzowHccsJbk HECQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b="XjA3/xwc"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id n184si1959112ybc.172.2019.02.15.11.23.30 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:23:30 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b="XjA3/xwc"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45028 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj57-0005KR-W6 for patch@linaro.org; Fri, 15 Feb 2019 14:23:30 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33299) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4m-0005JD-Fw for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:09 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4l-00035g-Io for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:08 -0500 Received: from mail-pg1-x52d.google.com ([2607:f8b0:4864:20::52d]:40245) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4l-00034b-Cx for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:07 -0500 Received: by mail-pg1-x52d.google.com with SMTP id u9so1716117pgo.7 for ; Fri, 15 Feb 2019 11:23:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=3oH383gg4Bjb4JyarPs8/S+LBRYRoxcsv9/An4O0Kgc=; b=XjA3/xwc7rx+m/fy0WuMRZlhYEq1IlYZamyU2MTD7iJvUTbVjMWOunXxfZEf+hL/Kn AOhb2sjXHbiTWY4ZzVDM4dW/VBC3gROK5B/1TPmHPiSUUQ5VhoQoiyYekDkb3yHmrcDE /YZgLfoME6OB8Oa6iJssVLNv2tbXcXEwhLyyOGjrep8tqcX0/dGm61IUXPeh4QoJXKdQ TarlY+b8YmvMxyZ2fldApv8HaGtWdiCwNgjnH/HS2K25wsByOeOAY7aDOLAw8XBE6e2q pMYd7gD+94BVR7afKeVnJiF2GGDOBQEHur13joALQscQ16oCIGpa/4ffQtLOXhdEM3qg 2JMw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=3oH383gg4Bjb4JyarPs8/S+LBRYRoxcsv9/An4O0Kgc=; b=HKwCEQ0mE/aHBmiKbz5TUkWNlucjUZXVtohhO05kn9MOCPGKGqFIK6QTD22+nPq4kJ QOu/XZacRoYGaIep9YTBAWS8XYbLGTOOZ+id1gOMroqthKi1LmA/9otFW5iKufE7kOxP 982SHhvS31+dMIyOCWOLqQEaeGbHD289EOJ224HxbNavCXW/tomvIB+A1ToE1mhnBfIa oZ9uP693mlvKQvCFy3bBUerUHUtwjS/yLUlMf2U23FpKzsCvx4P8Lw7H56ikEovpp+c9 vDRGzqShLQJ1Zy8GR5AeJn1YONlL1FRKNanJFTtZNFZfTcv7wmeVKGcRIhcfaFbx+I9n QCJg== X-Gm-Message-State: AHQUAuYDukb4CP21rulSQSLBOpUD3i5tRECaPGbPIityXfLESY81NEAz Rnj8y9AKjUMR1tOD4aK93DsN7QdiRuo= X-Received: by 2002:a62:5f07:: with SMTP id t7mr11282528pfb.108.1550258585945; Fri, 15 Feb 2019 11:23:05 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.04 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:05 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:22:55 -0800 Message-Id: <20190215192302.27855-2-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::52d Subject: [Qemu-devel] [PATCH v4 1/8] target/arm: Restructure disas_fp_int_conv X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" For opcodes 0-5, move some if conditions into the structure of a switch statement. For opcodes 6 & 7, decode everything at once with a second switch. Signed-off-by: Richard Henderson --- target/arm/translate-a64.c | 94 ++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 45 deletions(-) -- 2.17.2 Reviewed-by: Peter Maydell diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index af8e4fd4be..dbce24fe32 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -6541,68 +6541,72 @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn) int type = extract32(insn, 22, 2); bool sbit = extract32(insn, 29, 1); bool sf = extract32(insn, 31, 1); + bool itof = false; if (sbit) { - unallocated_encoding(s); - return; + goto do_unallocated; } - if (opcode > 5) { - /* FMOV */ - bool itof = opcode & 1; - - if (rmode >= 2) { - unallocated_encoding(s); - return; - } - - switch (sf << 3 | type << 1 | rmode) { - case 0x0: /* 32 bit */ - case 0xa: /* 64 bit */ - case 0xd: /* 64 bit to top half of quad */ - break; - case 0x6: /* 16-bit float, 32-bit int */ - case 0xe: /* 16-bit float, 64-bit int */ - if (dc_isar_feature(aa64_fp16, s)) { - break; - } - /* fallthru */ - default: - /* all other sf/type/rmode combinations are invalid */ - unallocated_encoding(s); - return; - } - - if (!fp_access_check(s)) { - return; - } - handle_fmov(s, rd, rn, type, itof); - } else { - /* actual FP conversions */ - bool itof = extract32(opcode, 1, 1); - - if (rmode != 0 && opcode > 1) { - unallocated_encoding(s); - return; + switch (opcode) { + case 2: /* SCVTF */ + case 3: /* UCVTF */ + itof = true; + /* fallthru */ + case 4: /* FCVTAS */ + case 5: /* FCVTAU */ + if (rmode != 0) { + goto do_unallocated; } + /* fallthru */ + case 0: /* FCVT[NPMZ]S */ + case 1: /* FCVT[NPMZ]U */ switch (type) { case 0: /* float32 */ case 1: /* float64 */ break; case 3: /* float16 */ - if (dc_isar_feature(aa64_fp16, s)) { - break; + if (!dc_isar_feature(aa64_fp16, s)) { + goto do_unallocated; } - /* fallthru */ + break; default: - unallocated_encoding(s); - return; + goto do_unallocated; } - if (!fp_access_check(s)) { return; } handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type); + break; + + default: + switch (sf << 7 | type << 5 | rmode << 3 | opcode) { + case 0b01100110: /* FMOV half <-> 32-bit int */ + case 0b01100111: + case 0b11100110: /* FMOV half <-> 64-bit int */ + case 0b11100111: + if (!dc_isar_feature(aa64_fp16, s)) { + goto do_unallocated; + } + /* fallthru */ + case 0b00000110: /* FMOV 32-bit */ + case 0b00000111: + case 0b10100110: /* FMOV 64-bit */ + case 0b10100111: + case 0b11001110: /* FMOV top half of 128-bit */ + case 0b11001111: + if (!fp_access_check(s)) { + return; + } + itof = opcode & 1; + handle_fmov(s, rd, rn, type, itof); + break; + + default: + do_unallocated: + unallocated_encoding(s); + return; + } + break; } } From patchwork Fri Feb 15 19:22:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158544 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1067562jaa; Fri, 15 Feb 2019 11:31:51 -0800 (PST) X-Google-Smtp-Source: AHgI3IbFgCha34RvudNYNrp9pOoE6VCoVaxmMXUm7VPmpxVPCmpUEWWL1OZ5zuBW+VjbpIDVUDzt X-Received: by 2002:a81:6d8b:: with SMTP id i133mr9124261ywc.231.1550259111235; Fri, 15 Feb 2019 11:31:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550259111; cv=none; d=google.com; s=arc-20160816; b=V7AO8nFsoF6xn+8t+d9RuQPJQd2lJL4FbJZAl8Qq0LVSRdE+XRDb8hVPnrGSQw/cRf RQKUOjIN/Pp8fXKRb9LI++pbH7Tkb8kRs+lb7NyFPWxMx3ACtcdU4BcmYcGY/S7N4Uql FQ/g2WkGx+4J9K+sAoQ7g1/znbd4wVODoygEg6QspNfbQ+pyjcroRTajG0k5pfogR0Bf x+Z+HommYfnp6w6tt89JGwV2UgA+kGQ36l9dl1tNuF9a/CgFHOqeWAkRb7edgjqfZLzi C3akjhAtlvWqmUH7iYt+up3g6WJMnVLpQ7AZ+xrGDlWu+uUbofyWyw6WITTLUvoOSvPM BgqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=pThEVQxsBJppKxvCKAE4/1sjD6NqpHWUeosNekbZAeU=; b=Ec/oRidSiFz6vOPICz3HuacgBFsFvjwET4uL4XTpycDOLude1ZKj/MUfIpbgQfoC09 uciTJNL66tXyl2ebBWdjxxcvaZWzjNq342s4x15fqAj6m0ZSNW6mcwM/OvZKRo8V74Vs fVbf6t3MLF2k177dWpFJYMfLSuZvcnD6YbrU3mWJ4S6BllmShEzASBS+jLrG3GGzXFI/ NL4KBppx6pQAi9se7eRZkOAw15N49Rwa4P2Vz8y0TGDFRRfBPRUarROKyT49rt94CfRJ IPuKwZfRqwhlMFHLU/GB/lxwK5tcK+pIieuob/oeEZ4tZLJbJ4uvH6bKqMO3IIUv4F5K a7Jw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b="scYQzK/7"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id z81si3816346ywb.302.2019.02.15.11.31.51 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:31:51 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b="scYQzK/7"; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45164 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gujDC-0002wu-Mo for patch@linaro.org; Fri, 15 Feb 2019 14:31:50 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33365) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4u-0005P2-1f for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4o-00039N-7X for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:16 -0500 Received: from mail-pg1-x541.google.com ([2607:f8b0:4864:20::541]:34141) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4n-00037C-P6 for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:10 -0500 Received: by mail-pg1-x541.google.com with SMTP id i130so5260515pgd.1 for ; Fri, 15 Feb 2019 11:23:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=pThEVQxsBJppKxvCKAE4/1sjD6NqpHWUeosNekbZAeU=; b=scYQzK/7mQ0hWeLf5P1SZMjxyyD0enevqYdcII58ZWkFCSY3nLhFaI9R5GUahsmnHz g72daTnbodjbFw6lZQcwaXIxjFjqfwU31V48LGro3xfwBBEanA0bWUNhBDWibWCkifhn oLl+IAoVqHzgzg7VdfHjMVvp0Y7Enu/GMZQBCWmrRSyck0V8aIUYtpi/m/2E/qGqkMsc b0BxSzms0CizKbpWue5xBwsA+VzizculFqJO+ahb9TZXfBaAKmu5X/Jgtes8xpPMDF1v K4bBwjkpDIanoGgnrwFSFEiTuSoS/T9POCQEl6MH4E17R0mi/U5QN3jtbSHD9iEwgO8F /5Jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=pThEVQxsBJppKxvCKAE4/1sjD6NqpHWUeosNekbZAeU=; b=udoVa0S/VQMXQIbbyFnMajt8Q3HTRD2ACWfza7EQOACYFxlq71nIfHk7OsctypRTyt ABFalFErResmang7ZXCPr9x0vhxhZ4ce5NP5uOsXiTFQRlFyic7qGICplCMr54DahmsQ 8IUsxQaSfqj6JgGWritzwfSrO1PUWnS8S1YqQGCydWFD++J9Dk4pnY1EKofPw9586cff /zR3RxntrbP5Cyi7mlhgkQydsGBGiEbK7Db83VDzmmILbc2XCy8Tuwyjz8RIcbEbDORp kFD84RpabACru3+h2yToHkLEkqLhBbiwX+QA/vhY3kEVoCDGAcoO/fqC/yiAvNtTIc/T /kiw== X-Gm-Message-State: AHQUAub0RqMdCxMHy0qPdzmIp2eFCjzjTsIX0KBN+KuORg6261kYKicQ mo4mZCp8Vn0xyEenGJXcTcbjHadn7zE= X-Received: by 2002:a63:83:: with SMTP id 125mr6754582pga.343.1550258587313; Fri, 15 Feb 2019 11:23:07 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.06 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:06 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:22:56 -0800 Message-Id: <20190215192302.27855-3-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::541 Subject: [Qemu-devel] [PATCH v4 2/8] target/arm: Split out vfp_helper.c X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Move all of the fp helpers out of helper.c into a new file. This is code movement only. Since helper.c has no copyright header, take the one from cpu.h for the new file. Signed-off-by: Richard Henderson --- target/arm/helper.c | 1062 ------------------------------------- target/arm/vfp_helper.c | 1088 ++++++++++++++++++++++++++++++++++++++ target/arm/Makefile.objs | 2 +- 3 files changed, 1089 insertions(+), 1063 deletions(-) create mode 100644 target/arm/vfp_helper.c -- 2.17.2 Reviewed-by: Peter Maydell diff --git a/target/arm/helper.c b/target/arm/helper.c index 55e9b77bb1..9fd97fbf31 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12678,1068 +12678,6 @@ uint32_t HELPER(sel_flags)(uint32_t flags, uint32_t a, uint32_t b) return (a & mask) | (b & ~mask); } -/* VFP support. We follow the convention used for VFP instructions: - Single precision routines have a "s" suffix, double precision a - "d" suffix. */ - -/* Convert host exception flags to vfp form. */ -static inline int vfp_exceptbits_from_host(int host_bits) -{ - int target_bits = 0; - - if (host_bits & float_flag_invalid) - target_bits |= 1; - if (host_bits & float_flag_divbyzero) - target_bits |= 2; - if (host_bits & float_flag_overflow) - target_bits |= 4; - if (host_bits & (float_flag_underflow | float_flag_output_denormal)) - target_bits |= 8; - if (host_bits & float_flag_inexact) - target_bits |= 0x10; - if (host_bits & float_flag_input_denormal) - target_bits |= 0x80; - return target_bits; -} - -uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) -{ - uint32_t i, fpscr; - - fpscr = env->vfp.xregs[ARM_VFP_FPSCR] - | (env->vfp.vec_len << 16) - | (env->vfp.vec_stride << 20); - - i = get_float_exception_flags(&env->vfp.fp_status); - i |= get_float_exception_flags(&env->vfp.standard_fp_status); - /* FZ16 does not generate an input denormal exception. */ - i |= (get_float_exception_flags(&env->vfp.fp_status_f16) - & ~float_flag_input_denormal); - fpscr |= vfp_exceptbits_from_host(i); - - i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3]; - fpscr |= i ? FPCR_QC : 0; - - return fpscr; -} - -uint32_t vfp_get_fpscr(CPUARMState *env) -{ - return HELPER(vfp_get_fpscr)(env); -} - -/* Convert vfp exception flags to target form. */ -static inline int vfp_exceptbits_to_host(int target_bits) -{ - int host_bits = 0; - - if (target_bits & 1) - host_bits |= float_flag_invalid; - if (target_bits & 2) - host_bits |= float_flag_divbyzero; - if (target_bits & 4) - host_bits |= float_flag_overflow; - if (target_bits & 8) - host_bits |= float_flag_underflow; - if (target_bits & 0x10) - host_bits |= float_flag_inexact; - if (target_bits & 0x80) - host_bits |= float_flag_input_denormal; - return host_bits; -} - -void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) -{ - int i; - uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR]; - - /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */ - if (!cpu_isar_feature(aa64_fp16, arm_env_get_cpu(env))) { - val &= ~FPCR_FZ16; - } - - /* - * We don't implement trapped exception handling, so the - * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!) - * - * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC - * (which are stored in fp_status), and the other RES0 bits - * in between, then we clear all of the low 16 bits. - */ - env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000; - env->vfp.vec_len = (val >> 16) & 7; - env->vfp.vec_stride = (val >> 20) & 3; - - /* - * The bit we set within fpscr_q is arbitrary; the register as a - * whole being zero/non-zero is what counts. - */ - env->vfp.qc[0] = val & FPCR_QC; - env->vfp.qc[1] = 0; - env->vfp.qc[2] = 0; - env->vfp.qc[3] = 0; - - changed ^= val; - if (changed & (3 << 22)) { - i = (val >> 22) & 3; - switch (i) { - case FPROUNDING_TIEEVEN: - i = float_round_nearest_even; - break; - case FPROUNDING_POSINF: - i = float_round_up; - break; - case FPROUNDING_NEGINF: - i = float_round_down; - break; - case FPROUNDING_ZERO: - i = float_round_to_zero; - break; - } - set_float_rounding_mode(i, &env->vfp.fp_status); - set_float_rounding_mode(i, &env->vfp.fp_status_f16); - } - if (changed & FPCR_FZ16) { - bool ftz_enabled = val & FPCR_FZ16; - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status_f16); - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status_f16); - } - if (changed & FPCR_FZ) { - bool ftz_enabled = val & FPCR_FZ; - set_flush_to_zero(ftz_enabled, &env->vfp.fp_status); - set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status); - } - if (changed & FPCR_DN) { - bool dnan_enabled = val & FPCR_DN; - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status); - set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16); - } - - /* The exception flags are ORed together when we read fpscr so we - * only need to preserve the current state in one of our - * float_status values. - */ - i = vfp_exceptbits_to_host(val); - set_float_exception_flags(i, &env->vfp.fp_status); - set_float_exception_flags(0, &env->vfp.fp_status_f16); - set_float_exception_flags(0, &env->vfp.standard_fp_status); -} - -void vfp_set_fpscr(CPUARMState *env, uint32_t val) -{ - HELPER(vfp_set_fpscr)(env, val); -} - -#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) - -#define VFP_BINOP(name) \ -float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \ -{ \ - float_status *fpst = fpstp; \ - return float32_ ## name(a, b, fpst); \ -} \ -float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \ -{ \ - float_status *fpst = fpstp; \ - return float64_ ## name(a, b, fpst); \ -} -VFP_BINOP(add) -VFP_BINOP(sub) -VFP_BINOP(mul) -VFP_BINOP(div) -VFP_BINOP(min) -VFP_BINOP(max) -VFP_BINOP(minnum) -VFP_BINOP(maxnum) -#undef VFP_BINOP - -float32 VFP_HELPER(neg, s)(float32 a) -{ - return float32_chs(a); -} - -float64 VFP_HELPER(neg, d)(float64 a) -{ - return float64_chs(a); -} - -float32 VFP_HELPER(abs, s)(float32 a) -{ - return float32_abs(a); -} - -float64 VFP_HELPER(abs, d)(float64 a) -{ - return float64_abs(a); -} - -float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env) -{ - return float32_sqrt(a, &env->vfp.fp_status); -} - -float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env) -{ - return float64_sqrt(a, &env->vfp.fp_status); -} - -static void softfloat_to_vfp_compare(CPUARMState *env, int cmp) -{ - uint32_t flags; - switch (cmp) { - case float_relation_equal: - flags = 0x6; - break; - case float_relation_less: - flags = 0x8; - break; - case float_relation_greater: - flags = 0x2; - break; - case float_relation_unordered: - flags = 0x3; - break; - default: - g_assert_not_reached(); - } - env->vfp.xregs[ARM_VFP_FPSCR] = - deposit32(env->vfp.xregs[ARM_VFP_FPSCR], 28, 4, flags); -} - -/* XXX: check quiet/signaling case */ -#define DO_VFP_cmp(p, type) \ -void VFP_HELPER(cmp, p)(type a, type b, CPUARMState *env) \ -{ \ - softfloat_to_vfp_compare(env, \ - type ## _compare_quiet(a, b, &env->vfp.fp_status)); \ -} \ -void VFP_HELPER(cmpe, p)(type a, type b, CPUARMState *env) \ -{ \ - softfloat_to_vfp_compare(env, \ - type ## _compare(a, b, &env->vfp.fp_status)); \ -} -DO_VFP_cmp(s, float32) -DO_VFP_cmp(d, float64) -#undef DO_VFP_cmp - -/* Integer to float and float to integer conversions */ - -#define CONV_ITOF(name, ftype, fsz, sign) \ -ftype HELPER(name)(uint32_t x, void *fpstp) \ -{ \ - float_status *fpst = fpstp; \ - return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \ -} - -#define CONV_FTOI(name, ftype, fsz, sign, round) \ -sign##int32_t HELPER(name)(ftype x, void *fpstp) \ -{ \ - float_status *fpst = fpstp; \ - if (float##fsz##_is_any_nan(x)) { \ - float_raise(float_flag_invalid, fpst); \ - return 0; \ - } \ - return float##fsz##_to_##sign##int32##round(x, fpst); \ -} - -#define FLOAT_CONVS(name, p, ftype, fsz, sign) \ - CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \ - CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \ - CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero) - -FLOAT_CONVS(si, h, uint32_t, 16, ) -FLOAT_CONVS(si, s, float32, 32, ) -FLOAT_CONVS(si, d, float64, 64, ) -FLOAT_CONVS(ui, h, uint32_t, 16, u) -FLOAT_CONVS(ui, s, float32, 32, u) -FLOAT_CONVS(ui, d, float64, 64, u) - -#undef CONV_ITOF -#undef CONV_FTOI -#undef FLOAT_CONVS - -/* floating point conversion */ -float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env) -{ - return float32_to_float64(x, &env->vfp.fp_status); -} - -float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env) -{ - return float64_to_float32(x, &env->vfp.fp_status); -} - -/* VFP3 fixed point conversion. */ -#define VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \ -float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \ - void *fpstp) \ -{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); } - -#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, ROUND, suff) \ -uint##isz##_t HELPER(vfp_to##name##p##suff)(float##fsz x, uint32_t shift, \ - void *fpst) \ -{ \ - if (unlikely(float##fsz##_is_any_nan(x))) { \ - float_raise(float_flag_invalid, fpst); \ - return 0; \ - } \ - return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \ -} - -#define VFP_CONV_FIX(name, p, fsz, isz, itype) \ -VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \ -VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \ - float_round_to_zero, _round_to_zero) \ -VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \ - get_float_rounding_mode(fpst), ) - -#define VFP_CONV_FIX_A64(name, p, fsz, isz, itype) \ -VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \ -VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \ - get_float_rounding_mode(fpst), ) - -VFP_CONV_FIX(sh, d, 64, 64, int16) -VFP_CONV_FIX(sl, d, 64, 64, int32) -VFP_CONV_FIX_A64(sq, d, 64, 64, int64) -VFP_CONV_FIX(uh, d, 64, 64, uint16) -VFP_CONV_FIX(ul, d, 64, 64, uint32) -VFP_CONV_FIX_A64(uq, d, 64, 64, uint64) -VFP_CONV_FIX(sh, s, 32, 32, int16) -VFP_CONV_FIX(sl, s, 32, 32, int32) -VFP_CONV_FIX_A64(sq, s, 32, 64, int64) -VFP_CONV_FIX(uh, s, 32, 32, uint16) -VFP_CONV_FIX(ul, s, 32, 32, uint32) -VFP_CONV_FIX_A64(uq, s, 32, 64, uint64) - -#undef VFP_CONV_FIX -#undef VFP_CONV_FIX_FLOAT -#undef VFP_CONV_FLOAT_FIX_ROUND -#undef VFP_CONV_FIX_A64 - -uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst) -{ - return int32_to_float16_scalbn(x, -shift, fpst); -} - -uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst) -{ - return uint32_to_float16_scalbn(x, -shift, fpst); -} - -uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst) -{ - return int64_to_float16_scalbn(x, -shift, fpst); -} - -uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst) -{ - return uint64_to_float16_scalbn(x, -shift, fpst); -} - -uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst) -{ - if (unlikely(float16_is_any_nan(x))) { - float_raise(float_flag_invalid, fpst); - return 0; - } - return float16_to_int16_scalbn(x, get_float_rounding_mode(fpst), - shift, fpst); -} - -uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst) -{ - if (unlikely(float16_is_any_nan(x))) { - float_raise(float_flag_invalid, fpst); - return 0; - } - return float16_to_uint16_scalbn(x, get_float_rounding_mode(fpst), - shift, fpst); -} - -uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst) -{ - if (unlikely(float16_is_any_nan(x))) { - float_raise(float_flag_invalid, fpst); - return 0; - } - return float16_to_int32_scalbn(x, get_float_rounding_mode(fpst), - shift, fpst); -} - -uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst) -{ - if (unlikely(float16_is_any_nan(x))) { - float_raise(float_flag_invalid, fpst); - return 0; - } - return float16_to_uint32_scalbn(x, get_float_rounding_mode(fpst), - shift, fpst); -} - -uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst) -{ - if (unlikely(float16_is_any_nan(x))) { - float_raise(float_flag_invalid, fpst); - return 0; - } - return float16_to_int64_scalbn(x, get_float_rounding_mode(fpst), - shift, fpst); -} - -uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst) -{ - if (unlikely(float16_is_any_nan(x))) { - float_raise(float_flag_invalid, fpst); - return 0; - } - return float16_to_uint64_scalbn(x, get_float_rounding_mode(fpst), - shift, fpst); -} - -/* Set the current fp rounding mode and return the old one. - * The argument is a softfloat float_round_ value. - */ -uint32_t HELPER(set_rmode)(uint32_t rmode, void *fpstp) -{ - float_status *fp_status = fpstp; - - uint32_t prev_rmode = get_float_rounding_mode(fp_status); - set_float_rounding_mode(rmode, fp_status); - - return prev_rmode; -} - -/* Set the current fp rounding mode in the standard fp status and return - * the old one. This is for NEON instructions that need to change the - * rounding mode but wish to use the standard FPSCR values for everything - * else. Always set the rounding mode back to the correct value after - * modifying it. - * The argument is a softfloat float_round_ value. - */ -uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env) -{ - float_status *fp_status = &env->vfp.standard_fp_status; - - uint32_t prev_rmode = get_float_rounding_mode(fp_status); - set_float_rounding_mode(rmode, fp_status); - - return prev_rmode; -} - -/* Half precision conversions. */ -float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode) -{ - /* Squash FZ16 to 0 for the duration of conversion. In this case, - * it would affect flushing input denormals. - */ - float_status *fpst = fpstp; - flag save = get_flush_inputs_to_zero(fpst); - set_flush_inputs_to_zero(false, fpst); - float32 r = float16_to_float32(a, !ahp_mode, fpst); - set_flush_inputs_to_zero(save, fpst); - return r; -} - -uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode) -{ - /* Squash FZ16 to 0 for the duration of conversion. In this case, - * it would affect flushing output denormals. - */ - float_status *fpst = fpstp; - flag save = get_flush_to_zero(fpst); - set_flush_to_zero(false, fpst); - float16 r = float32_to_float16(a, !ahp_mode, fpst); - set_flush_to_zero(save, fpst); - return r; -} - -float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode) -{ - /* Squash FZ16 to 0 for the duration of conversion. In this case, - * it would affect flushing input denormals. - */ - float_status *fpst = fpstp; - flag save = get_flush_inputs_to_zero(fpst); - set_flush_inputs_to_zero(false, fpst); - float64 r = float16_to_float64(a, !ahp_mode, fpst); - set_flush_inputs_to_zero(save, fpst); - return r; -} - -uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode) -{ - /* Squash FZ16 to 0 for the duration of conversion. In this case, - * it would affect flushing output denormals. - */ - float_status *fpst = fpstp; - flag save = get_flush_to_zero(fpst); - set_flush_to_zero(false, fpst); - float16 r = float64_to_float16(a, !ahp_mode, fpst); - set_flush_to_zero(save, fpst); - return r; -} - -#define float32_two make_float32(0x40000000) -#define float32_three make_float32(0x40400000) -#define float32_one_point_five make_float32(0x3fc00000) - -float32 HELPER(recps_f32)(float32 a, float32 b, CPUARMState *env) -{ - float_status *s = &env->vfp.standard_fp_status; - if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) || - (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) { - if (!(float32_is_zero(a) || float32_is_zero(b))) { - float_raise(float_flag_input_denormal, s); - } - return float32_two; - } - return float32_sub(float32_two, float32_mul(a, b, s), s); -} - -float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUARMState *env) -{ - float_status *s = &env->vfp.standard_fp_status; - float32 product; - if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) || - (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) { - if (!(float32_is_zero(a) || float32_is_zero(b))) { - float_raise(float_flag_input_denormal, s); - } - return float32_one_point_five; - } - product = float32_mul(a, b, s); - return float32_div(float32_sub(float32_three, product, s), float32_two, s); -} - -/* NEON helpers. */ - -/* Constants 256 and 512 are used in some helpers; we avoid relying on - * int->float conversions at run-time. */ -#define float64_256 make_float64(0x4070000000000000LL) -#define float64_512 make_float64(0x4080000000000000LL) -#define float16_maxnorm make_float16(0x7bff) -#define float32_maxnorm make_float32(0x7f7fffff) -#define float64_maxnorm make_float64(0x7fefffffffffffffLL) - -/* Reciprocal functions - * - * The algorithm that must be used to calculate the estimate - * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate - */ - -/* See RecipEstimate() - * - * input is a 9 bit fixed point number - * input range 256 .. 511 for a number from 0.5 <= x < 1.0. - * result range 256 .. 511 for a number from 1.0 to 511/256. - */ - -static int recip_estimate(int input) -{ - int a, b, r; - assert(256 <= input && input < 512); - a = (input * 2) + 1; - b = (1 << 19) / a; - r = (b + 1) >> 1; - assert(256 <= r && r < 512); - return r; -} - -/* - * Common wrapper to call recip_estimate - * - * The parameters are exponent and 64 bit fraction (without implicit - * bit) where the binary point is nominally at bit 52. Returns a - * float64 which can then be rounded to the appropriate size by the - * callee. - */ - -static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac) -{ - uint32_t scaled, estimate; - uint64_t result_frac; - int result_exp; - - /* Handle sub-normals */ - if (*exp == 0) { - if (extract64(frac, 51, 1) == 0) { - *exp = -1; - frac <<= 2; - } else { - frac <<= 1; - } - } - - /* scaled = UInt('1':fraction<51:44>) */ - scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); - estimate = recip_estimate(scaled); - - result_exp = exp_off - *exp; - result_frac = deposit64(0, 44, 8, estimate); - if (result_exp == 0) { - result_frac = deposit64(result_frac >> 1, 51, 1, 1); - } else if (result_exp == -1) { - result_frac = deposit64(result_frac >> 2, 50, 2, 1); - result_exp = 0; - } - - *exp = result_exp; - - return result_frac; -} - -static bool round_to_inf(float_status *fpst, bool sign_bit) -{ - switch (fpst->float_rounding_mode) { - case float_round_nearest_even: /* Round to Nearest */ - return true; - case float_round_up: /* Round to +Inf */ - return !sign_bit; - case float_round_down: /* Round to -Inf */ - return sign_bit; - case float_round_to_zero: /* Round to Zero */ - return false; - } - - g_assert_not_reached(); -} - -uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp) -{ - float_status *fpst = fpstp; - float16 f16 = float16_squash_input_denormal(input, fpst); - uint32_t f16_val = float16_val(f16); - uint32_t f16_sign = float16_is_neg(f16); - int f16_exp = extract32(f16_val, 10, 5); - uint32_t f16_frac = extract32(f16_val, 0, 10); - uint64_t f64_frac; - - if (float16_is_any_nan(f16)) { - float16 nan = f16; - if (float16_is_signaling_nan(f16, fpst)) { - float_raise(float_flag_invalid, fpst); - nan = float16_silence_nan(f16, fpst); - } - if (fpst->default_nan_mode) { - nan = float16_default_nan(fpst); - } - return nan; - } else if (float16_is_infinity(f16)) { - return float16_set_sign(float16_zero, float16_is_neg(f16)); - } else if (float16_is_zero(f16)) { - float_raise(float_flag_divbyzero, fpst); - return float16_set_sign(float16_infinity, float16_is_neg(f16)); - } else if (float16_abs(f16) < (1 << 8)) { - /* Abs(value) < 2.0^-16 */ - float_raise(float_flag_overflow | float_flag_inexact, fpst); - if (round_to_inf(fpst, f16_sign)) { - return float16_set_sign(float16_infinity, f16_sign); - } else { - return float16_set_sign(float16_maxnorm, f16_sign); - } - } else if (f16_exp >= 29 && fpst->flush_to_zero) { - float_raise(float_flag_underflow, fpst); - return float16_set_sign(float16_zero, float16_is_neg(f16)); - } - - f64_frac = call_recip_estimate(&f16_exp, 29, - ((uint64_t) f16_frac) << (52 - 10)); - - /* result = sign : result_exp<4:0> : fraction<51:42> */ - f16_val = deposit32(0, 15, 1, f16_sign); - f16_val = deposit32(f16_val, 10, 5, f16_exp); - f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10)); - return make_float16(f16_val); -} - -float32 HELPER(recpe_f32)(float32 input, void *fpstp) -{ - float_status *fpst = fpstp; - float32 f32 = float32_squash_input_denormal(input, fpst); - uint32_t f32_val = float32_val(f32); - bool f32_sign = float32_is_neg(f32); - int f32_exp = extract32(f32_val, 23, 8); - uint32_t f32_frac = extract32(f32_val, 0, 23); - uint64_t f64_frac; - - if (float32_is_any_nan(f32)) { - float32 nan = f32; - if (float32_is_signaling_nan(f32, fpst)) { - float_raise(float_flag_invalid, fpst); - nan = float32_silence_nan(f32, fpst); - } - if (fpst->default_nan_mode) { - nan = float32_default_nan(fpst); - } - return nan; - } else if (float32_is_infinity(f32)) { - return float32_set_sign(float32_zero, float32_is_neg(f32)); - } else if (float32_is_zero(f32)) { - float_raise(float_flag_divbyzero, fpst); - return float32_set_sign(float32_infinity, float32_is_neg(f32)); - } else if (float32_abs(f32) < (1ULL << 21)) { - /* Abs(value) < 2.0^-128 */ - float_raise(float_flag_overflow | float_flag_inexact, fpst); - if (round_to_inf(fpst, f32_sign)) { - return float32_set_sign(float32_infinity, f32_sign); - } else { - return float32_set_sign(float32_maxnorm, f32_sign); - } - } else if (f32_exp >= 253 && fpst->flush_to_zero) { - float_raise(float_flag_underflow, fpst); - return float32_set_sign(float32_zero, float32_is_neg(f32)); - } - - f64_frac = call_recip_estimate(&f32_exp, 253, - ((uint64_t) f32_frac) << (52 - 23)); - - /* result = sign : result_exp<7:0> : fraction<51:29> */ - f32_val = deposit32(0, 31, 1, f32_sign); - f32_val = deposit32(f32_val, 23, 8, f32_exp); - f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23)); - return make_float32(f32_val); -} - -float64 HELPER(recpe_f64)(float64 input, void *fpstp) -{ - float_status *fpst = fpstp; - float64 f64 = float64_squash_input_denormal(input, fpst); - uint64_t f64_val = float64_val(f64); - bool f64_sign = float64_is_neg(f64); - int f64_exp = extract64(f64_val, 52, 11); - uint64_t f64_frac = extract64(f64_val, 0, 52); - - /* Deal with any special cases */ - if (float64_is_any_nan(f64)) { - float64 nan = f64; - if (float64_is_signaling_nan(f64, fpst)) { - float_raise(float_flag_invalid, fpst); - nan = float64_silence_nan(f64, fpst); - } - if (fpst->default_nan_mode) { - nan = float64_default_nan(fpst); - } - return nan; - } else if (float64_is_infinity(f64)) { - return float64_set_sign(float64_zero, float64_is_neg(f64)); - } else if (float64_is_zero(f64)) { - float_raise(float_flag_divbyzero, fpst); - return float64_set_sign(float64_infinity, float64_is_neg(f64)); - } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) { - /* Abs(value) < 2.0^-1024 */ - float_raise(float_flag_overflow | float_flag_inexact, fpst); - if (round_to_inf(fpst, f64_sign)) { - return float64_set_sign(float64_infinity, f64_sign); - } else { - return float64_set_sign(float64_maxnorm, f64_sign); - } - } else if (f64_exp >= 2045 && fpst->flush_to_zero) { - float_raise(float_flag_underflow, fpst); - return float64_set_sign(float64_zero, float64_is_neg(f64)); - } - - f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac); - - /* result = sign : result_exp<10:0> : fraction<51:0>; */ - f64_val = deposit64(0, 63, 1, f64_sign); - f64_val = deposit64(f64_val, 52, 11, f64_exp); - f64_val = deposit64(f64_val, 0, 52, f64_frac); - return make_float64(f64_val); -} - -/* The algorithm that must be used to calculate the estimate - * is specified by the ARM ARM. - */ - -static int do_recip_sqrt_estimate(int a) -{ - int b, estimate; - - assert(128 <= a && a < 512); - if (a < 256) { - a = a * 2 + 1; - } else { - a = (a >> 1) << 1; - a = (a + 1) * 2; - } - b = 512; - while (a * (b + 1) * (b + 1) < (1 << 28)) { - b += 1; - } - estimate = (b + 1) / 2; - assert(256 <= estimate && estimate < 512); - - return estimate; -} - - -static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac) -{ - int estimate; - uint32_t scaled; - - if (*exp == 0) { - while (extract64(frac, 51, 1) == 0) { - frac = frac << 1; - *exp -= 1; - } - frac = extract64(frac, 0, 51) << 1; - } - - if (*exp & 1) { - /* scaled = UInt('01':fraction<51:45>) */ - scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7)); - } else { - /* scaled = UInt('1':fraction<51:44>) */ - scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); - } - estimate = do_recip_sqrt_estimate(scaled); - - *exp = (exp_off - *exp) / 2; - return extract64(estimate, 0, 8) << 44; -} - -uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp) -{ - float_status *s = fpstp; - float16 f16 = float16_squash_input_denormal(input, s); - uint16_t val = float16_val(f16); - bool f16_sign = float16_is_neg(f16); - int f16_exp = extract32(val, 10, 5); - uint16_t f16_frac = extract32(val, 0, 10); - uint64_t f64_frac; - - if (float16_is_any_nan(f16)) { - float16 nan = f16; - if (float16_is_signaling_nan(f16, s)) { - float_raise(float_flag_invalid, s); - nan = float16_silence_nan(f16, s); - } - if (s->default_nan_mode) { - nan = float16_default_nan(s); - } - return nan; - } else if (float16_is_zero(f16)) { - float_raise(float_flag_divbyzero, s); - return float16_set_sign(float16_infinity, f16_sign); - } else if (f16_sign) { - float_raise(float_flag_invalid, s); - return float16_default_nan(s); - } else if (float16_is_infinity(f16)) { - return float16_zero; - } - - /* Scale and normalize to a double-precision value between 0.25 and 1.0, - * preserving the parity of the exponent. */ - - f64_frac = ((uint64_t) f16_frac) << (52 - 10); - - f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac); - - /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */ - val = deposit32(0, 15, 1, f16_sign); - val = deposit32(val, 10, 5, f16_exp); - val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8)); - return make_float16(val); -} - -float32 HELPER(rsqrte_f32)(float32 input, void *fpstp) -{ - float_status *s = fpstp; - float32 f32 = float32_squash_input_denormal(input, s); - uint32_t val = float32_val(f32); - uint32_t f32_sign = float32_is_neg(f32); - int f32_exp = extract32(val, 23, 8); - uint32_t f32_frac = extract32(val, 0, 23); - uint64_t f64_frac; - - if (float32_is_any_nan(f32)) { - float32 nan = f32; - if (float32_is_signaling_nan(f32, s)) { - float_raise(float_flag_invalid, s); - nan = float32_silence_nan(f32, s); - } - if (s->default_nan_mode) { - nan = float32_default_nan(s); - } - return nan; - } else if (float32_is_zero(f32)) { - float_raise(float_flag_divbyzero, s); - return float32_set_sign(float32_infinity, float32_is_neg(f32)); - } else if (float32_is_neg(f32)) { - float_raise(float_flag_invalid, s); - return float32_default_nan(s); - } else if (float32_is_infinity(f32)) { - return float32_zero; - } - - /* Scale and normalize to a double-precision value between 0.25 and 1.0, - * preserving the parity of the exponent. */ - - f64_frac = ((uint64_t) f32_frac) << 29; - - f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac); - - /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(15) */ - val = deposit32(0, 31, 1, f32_sign); - val = deposit32(val, 23, 8, f32_exp); - val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8)); - return make_float32(val); -} - -float64 HELPER(rsqrte_f64)(float64 input, void *fpstp) -{ - float_status *s = fpstp; - float64 f64 = float64_squash_input_denormal(input, s); - uint64_t val = float64_val(f64); - bool f64_sign = float64_is_neg(f64); - int f64_exp = extract64(val, 52, 11); - uint64_t f64_frac = extract64(val, 0, 52); - - if (float64_is_any_nan(f64)) { - float64 nan = f64; - if (float64_is_signaling_nan(f64, s)) { - float_raise(float_flag_invalid, s); - nan = float64_silence_nan(f64, s); - } - if (s->default_nan_mode) { - nan = float64_default_nan(s); - } - return nan; - } else if (float64_is_zero(f64)) { - float_raise(float_flag_divbyzero, s); - return float64_set_sign(float64_infinity, float64_is_neg(f64)); - } else if (float64_is_neg(f64)) { - float_raise(float_flag_invalid, s); - return float64_default_nan(s); - } else if (float64_is_infinity(f64)) { - return float64_zero; - } - - f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac); - - /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */ - val = deposit64(0, 61, 1, f64_sign); - val = deposit64(val, 52, 11, f64_exp); - val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8)); - return make_float64(val); -} - -uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp) -{ - /* float_status *s = fpstp; */ - int input, estimate; - - if ((a & 0x80000000) == 0) { - return 0xffffffff; - } - - input = extract32(a, 23, 9); - estimate = recip_estimate(input); - - return deposit32(0, (32 - 9), 9, estimate); -} - -uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp) -{ - int estimate; - - if ((a & 0xc0000000) == 0) { - return 0xffffffff; - } - - estimate = do_recip_sqrt_estimate(extract32(a, 23, 9)); - - return deposit32(0, 23, 9, estimate); -} - -/* VFPv4 fused multiply-accumulate */ -float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp) -{ - float_status *fpst = fpstp; - return float32_muladd(a, b, c, 0, fpst); -} - -float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp) -{ - float_status *fpst = fpstp; - return float64_muladd(a, b, c, 0, fpst); -} - -/* ARMv8 round to integral */ -float32 HELPER(rints_exact)(float32 x, void *fp_status) -{ - return float32_round_to_int(x, fp_status); -} - -float64 HELPER(rintd_exact)(float64 x, void *fp_status) -{ - return float64_round_to_int(x, fp_status); -} - -float32 HELPER(rints)(float32 x, void *fp_status) -{ - int old_flags = get_float_exception_flags(fp_status), new_flags; - float32 ret; - - ret = float32_round_to_int(x, fp_status); - - /* Suppress any inexact exceptions the conversion produced */ - if (!(old_flags & float_flag_inexact)) { - new_flags = get_float_exception_flags(fp_status); - set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); - } - - return ret; -} - -float64 HELPER(rintd)(float64 x, void *fp_status) -{ - int old_flags = get_float_exception_flags(fp_status), new_flags; - float64 ret; - - ret = float64_round_to_int(x, fp_status); - - new_flags = get_float_exception_flags(fp_status); - - /* Suppress any inexact exceptions the conversion produced */ - if (!(old_flags & float_flag_inexact)) { - new_flags = get_float_exception_flags(fp_status); - set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); - } - - return ret; -} - -/* Convert ARM rounding mode to softfloat */ -int arm_rmode_to_sf(int rmode) -{ - switch (rmode) { - case FPROUNDING_TIEAWAY: - rmode = float_round_ties_away; - break; - case FPROUNDING_ODD: - /* FIXME: add support for TIEAWAY and ODD */ - qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n", - rmode); - /* fall through for now */ - case FPROUNDING_TIEEVEN: - default: - rmode = float_round_nearest_even; - break; - case FPROUNDING_POSINF: - rmode = float_round_up; - break; - case FPROUNDING_NEGINF: - rmode = float_round_down; - break; - case FPROUNDING_ZERO: - rmode = float_round_to_zero; - break; - } - return rmode; -} - /* CRC helpers. * The upper bytes of val (above the number specified by 'bytes') must have * been zeroed out by the caller. diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c new file mode 100644 index 0000000000..74d3030c47 --- /dev/null +++ b/target/arm/vfp_helper.c @@ -0,0 +1,1088 @@ +/* + * ARM VFP floating-point operations + * + * Copyright (c) 2003 Fabrice Bellard + * + * This 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. + * + * This 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 this library; if not, see . + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "cpu.h" +#include "exec/helper-proto.h" +#include "fpu/softfloat.h" +#include "internals.h" + + +/* VFP support. We follow the convention used for VFP instructions: + Single precision routines have a "s" suffix, double precision a + "d" suffix. */ + +/* Convert host exception flags to vfp form. */ +static inline int vfp_exceptbits_from_host(int host_bits) +{ + int target_bits = 0; + + if (host_bits & float_flag_invalid) + target_bits |= 1; + if (host_bits & float_flag_divbyzero) + target_bits |= 2; + if (host_bits & float_flag_overflow) + target_bits |= 4; + if (host_bits & (float_flag_underflow | float_flag_output_denormal)) + target_bits |= 8; + if (host_bits & float_flag_inexact) + target_bits |= 0x10; + if (host_bits & float_flag_input_denormal) + target_bits |= 0x80; + return target_bits; +} + +uint32_t HELPER(vfp_get_fpscr)(CPUARMState *env) +{ + uint32_t i, fpscr; + + fpscr = env->vfp.xregs[ARM_VFP_FPSCR] + | (env->vfp.vec_len << 16) + | (env->vfp.vec_stride << 20); + + i = get_float_exception_flags(&env->vfp.fp_status); + i |= get_float_exception_flags(&env->vfp.standard_fp_status); + /* FZ16 does not generate an input denormal exception. */ + i |= (get_float_exception_flags(&env->vfp.fp_status_f16) + & ~float_flag_input_denormal); + fpscr |= vfp_exceptbits_from_host(i); + + i = env->vfp.qc[0] | env->vfp.qc[1] | env->vfp.qc[2] | env->vfp.qc[3]; + fpscr |= i ? FPCR_QC : 0; + + return fpscr; +} + +uint32_t vfp_get_fpscr(CPUARMState *env) +{ + return HELPER(vfp_get_fpscr)(env); +} + +/* Convert vfp exception flags to target form. */ +static inline int vfp_exceptbits_to_host(int target_bits) +{ + int host_bits = 0; + + if (target_bits & 1) + host_bits |= float_flag_invalid; + if (target_bits & 2) + host_bits |= float_flag_divbyzero; + if (target_bits & 4) + host_bits |= float_flag_overflow; + if (target_bits & 8) + host_bits |= float_flag_underflow; + if (target_bits & 0x10) + host_bits |= float_flag_inexact; + if (target_bits & 0x80) + host_bits |= float_flag_input_denormal; + return host_bits; +} + +void HELPER(vfp_set_fpscr)(CPUARMState *env, uint32_t val) +{ + int i; + uint32_t changed = env->vfp.xregs[ARM_VFP_FPSCR]; + + /* When ARMv8.2-FP16 is not supported, FZ16 is RES0. */ + if (!cpu_isar_feature(aa64_fp16, arm_env_get_cpu(env))) { + val &= ~FPCR_FZ16; + } + + /* + * We don't implement trapped exception handling, so the + * trap enable bits, IDE|IXE|UFE|OFE|DZE|IOE are all RAZ/WI (not RES0!) + * + * If we exclude the exception flags, IOC|DZC|OFC|UFC|IXC|IDC + * (which are stored in fp_status), and the other RES0 bits + * in between, then we clear all of the low 16 bits. + */ + env->vfp.xregs[ARM_VFP_FPSCR] = val & 0xf7c80000; + env->vfp.vec_len = (val >> 16) & 7; + env->vfp.vec_stride = (val >> 20) & 3; + + /* + * The bit we set within fpscr_q is arbitrary; the register as a + * whole being zero/non-zero is what counts. + */ + env->vfp.qc[0] = val & FPCR_QC; + env->vfp.qc[1] = 0; + env->vfp.qc[2] = 0; + env->vfp.qc[3] = 0; + + changed ^= val; + if (changed & (3 << 22)) { + i = (val >> 22) & 3; + switch (i) { + case FPROUNDING_TIEEVEN: + i = float_round_nearest_even; + break; + case FPROUNDING_POSINF: + i = float_round_up; + break; + case FPROUNDING_NEGINF: + i = float_round_down; + break; + case FPROUNDING_ZERO: + i = float_round_to_zero; + break; + } + set_float_rounding_mode(i, &env->vfp.fp_status); + set_float_rounding_mode(i, &env->vfp.fp_status_f16); + } + if (changed & FPCR_FZ16) { + bool ftz_enabled = val & FPCR_FZ16; + set_flush_to_zero(ftz_enabled, &env->vfp.fp_status_f16); + set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status_f16); + } + if (changed & FPCR_FZ) { + bool ftz_enabled = val & FPCR_FZ; + set_flush_to_zero(ftz_enabled, &env->vfp.fp_status); + set_flush_inputs_to_zero(ftz_enabled, &env->vfp.fp_status); + } + if (changed & FPCR_DN) { + bool dnan_enabled = val & FPCR_DN; + set_default_nan_mode(dnan_enabled, &env->vfp.fp_status); + set_default_nan_mode(dnan_enabled, &env->vfp.fp_status_f16); + } + + /* The exception flags are ORed together when we read fpscr so we + * only need to preserve the current state in one of our + * float_status values. + */ + i = vfp_exceptbits_to_host(val); + set_float_exception_flags(i, &env->vfp.fp_status); + set_float_exception_flags(0, &env->vfp.fp_status_f16); + set_float_exception_flags(0, &env->vfp.standard_fp_status); +} + +void vfp_set_fpscr(CPUARMState *env, uint32_t val) +{ + HELPER(vfp_set_fpscr)(env, val); +} + +#define VFP_HELPER(name, p) HELPER(glue(glue(vfp_,name),p)) + +#define VFP_BINOP(name) \ +float32 VFP_HELPER(name, s)(float32 a, float32 b, void *fpstp) \ +{ \ + float_status *fpst = fpstp; \ + return float32_ ## name(a, b, fpst); \ +} \ +float64 VFP_HELPER(name, d)(float64 a, float64 b, void *fpstp) \ +{ \ + float_status *fpst = fpstp; \ + return float64_ ## name(a, b, fpst); \ +} +VFP_BINOP(add) +VFP_BINOP(sub) +VFP_BINOP(mul) +VFP_BINOP(div) +VFP_BINOP(min) +VFP_BINOP(max) +VFP_BINOP(minnum) +VFP_BINOP(maxnum) +#undef VFP_BINOP + +float32 VFP_HELPER(neg, s)(float32 a) +{ + return float32_chs(a); +} + +float64 VFP_HELPER(neg, d)(float64 a) +{ + return float64_chs(a); +} + +float32 VFP_HELPER(abs, s)(float32 a) +{ + return float32_abs(a); +} + +float64 VFP_HELPER(abs, d)(float64 a) +{ + return float64_abs(a); +} + +float32 VFP_HELPER(sqrt, s)(float32 a, CPUARMState *env) +{ + return float32_sqrt(a, &env->vfp.fp_status); +} + +float64 VFP_HELPER(sqrt, d)(float64 a, CPUARMState *env) +{ + return float64_sqrt(a, &env->vfp.fp_status); +} + +static void softfloat_to_vfp_compare(CPUARMState *env, int cmp) +{ + uint32_t flags; + switch (cmp) { + case float_relation_equal: + flags = 0x6; + break; + case float_relation_less: + flags = 0x8; + break; + case float_relation_greater: + flags = 0x2; + break; + case float_relation_unordered: + flags = 0x3; + break; + default: + g_assert_not_reached(); + } + env->vfp.xregs[ARM_VFP_FPSCR] = + deposit32(env->vfp.xregs[ARM_VFP_FPSCR], 28, 4, flags); +} + +/* XXX: check quiet/signaling case */ +#define DO_VFP_cmp(p, type) \ +void VFP_HELPER(cmp, p)(type a, type b, CPUARMState *env) \ +{ \ + softfloat_to_vfp_compare(env, \ + type ## _compare_quiet(a, b, &env->vfp.fp_status)); \ +} \ +void VFP_HELPER(cmpe, p)(type a, type b, CPUARMState *env) \ +{ \ + softfloat_to_vfp_compare(env, \ + type ## _compare(a, b, &env->vfp.fp_status)); \ +} +DO_VFP_cmp(s, float32) +DO_VFP_cmp(d, float64) +#undef DO_VFP_cmp + +/* Integer to float and float to integer conversions */ + +#define CONV_ITOF(name, ftype, fsz, sign) \ +ftype HELPER(name)(uint32_t x, void *fpstp) \ +{ \ + float_status *fpst = fpstp; \ + return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \ +} + +#define CONV_FTOI(name, ftype, fsz, sign, round) \ +sign##int32_t HELPER(name)(ftype x, void *fpstp) \ +{ \ + float_status *fpst = fpstp; \ + if (float##fsz##_is_any_nan(x)) { \ + float_raise(float_flag_invalid, fpst); \ + return 0; \ + } \ + return float##fsz##_to_##sign##int32##round(x, fpst); \ +} + +#define FLOAT_CONVS(name, p, ftype, fsz, sign) \ + CONV_ITOF(vfp_##name##to##p, ftype, fsz, sign) \ + CONV_FTOI(vfp_to##name##p, ftype, fsz, sign, ) \ + CONV_FTOI(vfp_to##name##z##p, ftype, fsz, sign, _round_to_zero) + +FLOAT_CONVS(si, h, uint32_t, 16, ) +FLOAT_CONVS(si, s, float32, 32, ) +FLOAT_CONVS(si, d, float64, 64, ) +FLOAT_CONVS(ui, h, uint32_t, 16, u) +FLOAT_CONVS(ui, s, float32, 32, u) +FLOAT_CONVS(ui, d, float64, 64, u) + +#undef CONV_ITOF +#undef CONV_FTOI +#undef FLOAT_CONVS + +/* floating point conversion */ +float64 VFP_HELPER(fcvtd, s)(float32 x, CPUARMState *env) +{ + return float32_to_float64(x, &env->vfp.fp_status); +} + +float32 VFP_HELPER(fcvts, d)(float64 x, CPUARMState *env) +{ + return float64_to_float32(x, &env->vfp.fp_status); +} + +/* VFP3 fixed point conversion. */ +#define VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \ +float##fsz HELPER(vfp_##name##to##p)(uint##isz##_t x, uint32_t shift, \ + void *fpstp) \ +{ return itype##_to_##float##fsz##_scalbn(x, -shift, fpstp); } + +#define VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, ROUND, suff) \ +uint##isz##_t HELPER(vfp_to##name##p##suff)(float##fsz x, uint32_t shift, \ + void *fpst) \ +{ \ + if (unlikely(float##fsz##_is_any_nan(x))) { \ + float_raise(float_flag_invalid, fpst); \ + return 0; \ + } \ + return float##fsz##_to_##itype##_scalbn(x, ROUND, shift, fpst); \ +} + +#define VFP_CONV_FIX(name, p, fsz, isz, itype) \ +VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \ +VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \ + float_round_to_zero, _round_to_zero) \ +VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \ + get_float_rounding_mode(fpst), ) + +#define VFP_CONV_FIX_A64(name, p, fsz, isz, itype) \ +VFP_CONV_FIX_FLOAT(name, p, fsz, isz, itype) \ +VFP_CONV_FLOAT_FIX_ROUND(name, p, fsz, isz, itype, \ + get_float_rounding_mode(fpst), ) + +VFP_CONV_FIX(sh, d, 64, 64, int16) +VFP_CONV_FIX(sl, d, 64, 64, int32) +VFP_CONV_FIX_A64(sq, d, 64, 64, int64) +VFP_CONV_FIX(uh, d, 64, 64, uint16) +VFP_CONV_FIX(ul, d, 64, 64, uint32) +VFP_CONV_FIX_A64(uq, d, 64, 64, uint64) +VFP_CONV_FIX(sh, s, 32, 32, int16) +VFP_CONV_FIX(sl, s, 32, 32, int32) +VFP_CONV_FIX_A64(sq, s, 32, 64, int64) +VFP_CONV_FIX(uh, s, 32, 32, uint16) +VFP_CONV_FIX(ul, s, 32, 32, uint32) +VFP_CONV_FIX_A64(uq, s, 32, 64, uint64) + +#undef VFP_CONV_FIX +#undef VFP_CONV_FIX_FLOAT +#undef VFP_CONV_FLOAT_FIX_ROUND +#undef VFP_CONV_FIX_A64 + +uint32_t HELPER(vfp_sltoh)(uint32_t x, uint32_t shift, void *fpst) +{ + return int32_to_float16_scalbn(x, -shift, fpst); +} + +uint32_t HELPER(vfp_ultoh)(uint32_t x, uint32_t shift, void *fpst) +{ + return uint32_to_float16_scalbn(x, -shift, fpst); +} + +uint32_t HELPER(vfp_sqtoh)(uint64_t x, uint32_t shift, void *fpst) +{ + return int64_to_float16_scalbn(x, -shift, fpst); +} + +uint32_t HELPER(vfp_uqtoh)(uint64_t x, uint32_t shift, void *fpst) +{ + return uint64_to_float16_scalbn(x, -shift, fpst); +} + +uint32_t HELPER(vfp_toshh)(uint32_t x, uint32_t shift, void *fpst) +{ + if (unlikely(float16_is_any_nan(x))) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_int16_scalbn(x, get_float_rounding_mode(fpst), + shift, fpst); +} + +uint32_t HELPER(vfp_touhh)(uint32_t x, uint32_t shift, void *fpst) +{ + if (unlikely(float16_is_any_nan(x))) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_uint16_scalbn(x, get_float_rounding_mode(fpst), + shift, fpst); +} + +uint32_t HELPER(vfp_toslh)(uint32_t x, uint32_t shift, void *fpst) +{ + if (unlikely(float16_is_any_nan(x))) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_int32_scalbn(x, get_float_rounding_mode(fpst), + shift, fpst); +} + +uint32_t HELPER(vfp_toulh)(uint32_t x, uint32_t shift, void *fpst) +{ + if (unlikely(float16_is_any_nan(x))) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_uint32_scalbn(x, get_float_rounding_mode(fpst), + shift, fpst); +} + +uint64_t HELPER(vfp_tosqh)(uint32_t x, uint32_t shift, void *fpst) +{ + if (unlikely(float16_is_any_nan(x))) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_int64_scalbn(x, get_float_rounding_mode(fpst), + shift, fpst); +} + +uint64_t HELPER(vfp_touqh)(uint32_t x, uint32_t shift, void *fpst) +{ + if (unlikely(float16_is_any_nan(x))) { + float_raise(float_flag_invalid, fpst); + return 0; + } + return float16_to_uint64_scalbn(x, get_float_rounding_mode(fpst), + shift, fpst); +} + +/* Set the current fp rounding mode and return the old one. + * The argument is a softfloat float_round_ value. + */ +uint32_t HELPER(set_rmode)(uint32_t rmode, void *fpstp) +{ + float_status *fp_status = fpstp; + + uint32_t prev_rmode = get_float_rounding_mode(fp_status); + set_float_rounding_mode(rmode, fp_status); + + return prev_rmode; +} + +/* Set the current fp rounding mode in the standard fp status and return + * the old one. This is for NEON instructions that need to change the + * rounding mode but wish to use the standard FPSCR values for everything + * else. Always set the rounding mode back to the correct value after + * modifying it. + * The argument is a softfloat float_round_ value. + */ +uint32_t HELPER(set_neon_rmode)(uint32_t rmode, CPUARMState *env) +{ + float_status *fp_status = &env->vfp.standard_fp_status; + + uint32_t prev_rmode = get_float_rounding_mode(fp_status); + set_float_rounding_mode(rmode, fp_status); + + return prev_rmode; +} + +/* Half precision conversions. */ +float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, void *fpstp, uint32_t ahp_mode) +{ + /* Squash FZ16 to 0 for the duration of conversion. In this case, + * it would affect flushing input denormals. + */ + float_status *fpst = fpstp; + flag save = get_flush_inputs_to_zero(fpst); + set_flush_inputs_to_zero(false, fpst); + float32 r = float16_to_float32(a, !ahp_mode, fpst); + set_flush_inputs_to_zero(save, fpst); + return r; +} + +uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, void *fpstp, uint32_t ahp_mode) +{ + /* Squash FZ16 to 0 for the duration of conversion. In this case, + * it would affect flushing output denormals. + */ + float_status *fpst = fpstp; + flag save = get_flush_to_zero(fpst); + set_flush_to_zero(false, fpst); + float16 r = float32_to_float16(a, !ahp_mode, fpst); + set_flush_to_zero(save, fpst); + return r; +} + +float64 HELPER(vfp_fcvt_f16_to_f64)(uint32_t a, void *fpstp, uint32_t ahp_mode) +{ + /* Squash FZ16 to 0 for the duration of conversion. In this case, + * it would affect flushing input denormals. + */ + float_status *fpst = fpstp; + flag save = get_flush_inputs_to_zero(fpst); + set_flush_inputs_to_zero(false, fpst); + float64 r = float16_to_float64(a, !ahp_mode, fpst); + set_flush_inputs_to_zero(save, fpst); + return r; +} + +uint32_t HELPER(vfp_fcvt_f64_to_f16)(float64 a, void *fpstp, uint32_t ahp_mode) +{ + /* Squash FZ16 to 0 for the duration of conversion. In this case, + * it would affect flushing output denormals. + */ + float_status *fpst = fpstp; + flag save = get_flush_to_zero(fpst); + set_flush_to_zero(false, fpst); + float16 r = float64_to_float16(a, !ahp_mode, fpst); + set_flush_to_zero(save, fpst); + return r; +} + +#define float32_two make_float32(0x40000000) +#define float32_three make_float32(0x40400000) +#define float32_one_point_five make_float32(0x3fc00000) + +float32 HELPER(recps_f32)(float32 a, float32 b, CPUARMState *env) +{ + float_status *s = &env->vfp.standard_fp_status; + if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) || + (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) { + if (!(float32_is_zero(a) || float32_is_zero(b))) { + float_raise(float_flag_input_denormal, s); + } + return float32_two; + } + return float32_sub(float32_two, float32_mul(a, b, s), s); +} + +float32 HELPER(rsqrts_f32)(float32 a, float32 b, CPUARMState *env) +{ + float_status *s = &env->vfp.standard_fp_status; + float32 product; + if ((float32_is_infinity(a) && float32_is_zero_or_denormal(b)) || + (float32_is_infinity(b) && float32_is_zero_or_denormal(a))) { + if (!(float32_is_zero(a) || float32_is_zero(b))) { + float_raise(float_flag_input_denormal, s); + } + return float32_one_point_five; + } + product = float32_mul(a, b, s); + return float32_div(float32_sub(float32_three, product, s), float32_two, s); +} + +/* NEON helpers. */ + +/* Constants 256 and 512 are used in some helpers; we avoid relying on + * int->float conversions at run-time. */ +#define float64_256 make_float64(0x4070000000000000LL) +#define float64_512 make_float64(0x4080000000000000LL) +#define float16_maxnorm make_float16(0x7bff) +#define float32_maxnorm make_float32(0x7f7fffff) +#define float64_maxnorm make_float64(0x7fefffffffffffffLL) + +/* Reciprocal functions + * + * The algorithm that must be used to calculate the estimate + * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate + */ + +/* See RecipEstimate() + * + * input is a 9 bit fixed point number + * input range 256 .. 511 for a number from 0.5 <= x < 1.0. + * result range 256 .. 511 for a number from 1.0 to 511/256. + */ + +static int recip_estimate(int input) +{ + int a, b, r; + assert(256 <= input && input < 512); + a = (input * 2) + 1; + b = (1 << 19) / a; + r = (b + 1) >> 1; + assert(256 <= r && r < 512); + return r; +} + +/* + * Common wrapper to call recip_estimate + * + * The parameters are exponent and 64 bit fraction (without implicit + * bit) where the binary point is nominally at bit 52. Returns a + * float64 which can then be rounded to the appropriate size by the + * callee. + */ + +static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac) +{ + uint32_t scaled, estimate; + uint64_t result_frac; + int result_exp; + + /* Handle sub-normals */ + if (*exp == 0) { + if (extract64(frac, 51, 1) == 0) { + *exp = -1; + frac <<= 2; + } else { + frac <<= 1; + } + } + + /* scaled = UInt('1':fraction<51:44>) */ + scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); + estimate = recip_estimate(scaled); + + result_exp = exp_off - *exp; + result_frac = deposit64(0, 44, 8, estimate); + if (result_exp == 0) { + result_frac = deposit64(result_frac >> 1, 51, 1, 1); + } else if (result_exp == -1) { + result_frac = deposit64(result_frac >> 2, 50, 2, 1); + result_exp = 0; + } + + *exp = result_exp; + + return result_frac; +} + +static bool round_to_inf(float_status *fpst, bool sign_bit) +{ + switch (fpst->float_rounding_mode) { + case float_round_nearest_even: /* Round to Nearest */ + return true; + case float_round_up: /* Round to +Inf */ + return !sign_bit; + case float_round_down: /* Round to -Inf */ + return sign_bit; + case float_round_to_zero: /* Round to Zero */ + return false; + } + + g_assert_not_reached(); +} + +uint32_t HELPER(recpe_f16)(uint32_t input, void *fpstp) +{ + float_status *fpst = fpstp; + float16 f16 = float16_squash_input_denormal(input, fpst); + uint32_t f16_val = float16_val(f16); + uint32_t f16_sign = float16_is_neg(f16); + int f16_exp = extract32(f16_val, 10, 5); + uint32_t f16_frac = extract32(f16_val, 0, 10); + uint64_t f64_frac; + + if (float16_is_any_nan(f16)) { + float16 nan = f16; + if (float16_is_signaling_nan(f16, fpst)) { + float_raise(float_flag_invalid, fpst); + nan = float16_silence_nan(f16, fpst); + } + if (fpst->default_nan_mode) { + nan = float16_default_nan(fpst); + } + return nan; + } else if (float16_is_infinity(f16)) { + return float16_set_sign(float16_zero, float16_is_neg(f16)); + } else if (float16_is_zero(f16)) { + float_raise(float_flag_divbyzero, fpst); + return float16_set_sign(float16_infinity, float16_is_neg(f16)); + } else if (float16_abs(f16) < (1 << 8)) { + /* Abs(value) < 2.0^-16 */ + float_raise(float_flag_overflow | float_flag_inexact, fpst); + if (round_to_inf(fpst, f16_sign)) { + return float16_set_sign(float16_infinity, f16_sign); + } else { + return float16_set_sign(float16_maxnorm, f16_sign); + } + } else if (f16_exp >= 29 && fpst->flush_to_zero) { + float_raise(float_flag_underflow, fpst); + return float16_set_sign(float16_zero, float16_is_neg(f16)); + } + + f64_frac = call_recip_estimate(&f16_exp, 29, + ((uint64_t) f16_frac) << (52 - 10)); + + /* result = sign : result_exp<4:0> : fraction<51:42> */ + f16_val = deposit32(0, 15, 1, f16_sign); + f16_val = deposit32(f16_val, 10, 5, f16_exp); + f16_val = deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10)); + return make_float16(f16_val); +} + +float32 HELPER(recpe_f32)(float32 input, void *fpstp) +{ + float_status *fpst = fpstp; + float32 f32 = float32_squash_input_denormal(input, fpst); + uint32_t f32_val = float32_val(f32); + bool f32_sign = float32_is_neg(f32); + int f32_exp = extract32(f32_val, 23, 8); + uint32_t f32_frac = extract32(f32_val, 0, 23); + uint64_t f64_frac; + + if (float32_is_any_nan(f32)) { + float32 nan = f32; + if (float32_is_signaling_nan(f32, fpst)) { + float_raise(float_flag_invalid, fpst); + nan = float32_silence_nan(f32, fpst); + } + if (fpst->default_nan_mode) { + nan = float32_default_nan(fpst); + } + return nan; + } else if (float32_is_infinity(f32)) { + return float32_set_sign(float32_zero, float32_is_neg(f32)); + } else if (float32_is_zero(f32)) { + float_raise(float_flag_divbyzero, fpst); + return float32_set_sign(float32_infinity, float32_is_neg(f32)); + } else if (float32_abs(f32) < (1ULL << 21)) { + /* Abs(value) < 2.0^-128 */ + float_raise(float_flag_overflow | float_flag_inexact, fpst); + if (round_to_inf(fpst, f32_sign)) { + return float32_set_sign(float32_infinity, f32_sign); + } else { + return float32_set_sign(float32_maxnorm, f32_sign); + } + } else if (f32_exp >= 253 && fpst->flush_to_zero) { + float_raise(float_flag_underflow, fpst); + return float32_set_sign(float32_zero, float32_is_neg(f32)); + } + + f64_frac = call_recip_estimate(&f32_exp, 253, + ((uint64_t) f32_frac) << (52 - 23)); + + /* result = sign : result_exp<7:0> : fraction<51:29> */ + f32_val = deposit32(0, 31, 1, f32_sign); + f32_val = deposit32(f32_val, 23, 8, f32_exp); + f32_val = deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23)); + return make_float32(f32_val); +} + +float64 HELPER(recpe_f64)(float64 input, void *fpstp) +{ + float_status *fpst = fpstp; + float64 f64 = float64_squash_input_denormal(input, fpst); + uint64_t f64_val = float64_val(f64); + bool f64_sign = float64_is_neg(f64); + int f64_exp = extract64(f64_val, 52, 11); + uint64_t f64_frac = extract64(f64_val, 0, 52); + + /* Deal with any special cases */ + if (float64_is_any_nan(f64)) { + float64 nan = f64; + if (float64_is_signaling_nan(f64, fpst)) { + float_raise(float_flag_invalid, fpst); + nan = float64_silence_nan(f64, fpst); + } + if (fpst->default_nan_mode) { + nan = float64_default_nan(fpst); + } + return nan; + } else if (float64_is_infinity(f64)) { + return float64_set_sign(float64_zero, float64_is_neg(f64)); + } else if (float64_is_zero(f64)) { + float_raise(float_flag_divbyzero, fpst); + return float64_set_sign(float64_infinity, float64_is_neg(f64)); + } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) { + /* Abs(value) < 2.0^-1024 */ + float_raise(float_flag_overflow | float_flag_inexact, fpst); + if (round_to_inf(fpst, f64_sign)) { + return float64_set_sign(float64_infinity, f64_sign); + } else { + return float64_set_sign(float64_maxnorm, f64_sign); + } + } else if (f64_exp >= 2045 && fpst->flush_to_zero) { + float_raise(float_flag_underflow, fpst); + return float64_set_sign(float64_zero, float64_is_neg(f64)); + } + + f64_frac = call_recip_estimate(&f64_exp, 2045, f64_frac); + + /* result = sign : result_exp<10:0> : fraction<51:0>; */ + f64_val = deposit64(0, 63, 1, f64_sign); + f64_val = deposit64(f64_val, 52, 11, f64_exp); + f64_val = deposit64(f64_val, 0, 52, f64_frac); + return make_float64(f64_val); +} + +/* The algorithm that must be used to calculate the estimate + * is specified by the ARM ARM. + */ + +static int do_recip_sqrt_estimate(int a) +{ + int b, estimate; + + assert(128 <= a && a < 512); + if (a < 256) { + a = a * 2 + 1; + } else { + a = (a >> 1) << 1; + a = (a + 1) * 2; + } + b = 512; + while (a * (b + 1) * (b + 1) < (1 << 28)) { + b += 1; + } + estimate = (b + 1) / 2; + assert(256 <= estimate && estimate < 512); + + return estimate; +} + + +static uint64_t recip_sqrt_estimate(int *exp , int exp_off, uint64_t frac) +{ + int estimate; + uint32_t scaled; + + if (*exp == 0) { + while (extract64(frac, 51, 1) == 0) { + frac = frac << 1; + *exp -= 1; + } + frac = extract64(frac, 0, 51) << 1; + } + + if (*exp & 1) { + /* scaled = UInt('01':fraction<51:45>) */ + scaled = deposit32(1 << 7, 0, 7, extract64(frac, 45, 7)); + } else { + /* scaled = UInt('1':fraction<51:44>) */ + scaled = deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); + } + estimate = do_recip_sqrt_estimate(scaled); + + *exp = (exp_off - *exp) / 2; + return extract64(estimate, 0, 8) << 44; +} + +uint32_t HELPER(rsqrte_f16)(uint32_t input, void *fpstp) +{ + float_status *s = fpstp; + float16 f16 = float16_squash_input_denormal(input, s); + uint16_t val = float16_val(f16); + bool f16_sign = float16_is_neg(f16); + int f16_exp = extract32(val, 10, 5); + uint16_t f16_frac = extract32(val, 0, 10); + uint64_t f64_frac; + + if (float16_is_any_nan(f16)) { + float16 nan = f16; + if (float16_is_signaling_nan(f16, s)) { + float_raise(float_flag_invalid, s); + nan = float16_silence_nan(f16, s); + } + if (s->default_nan_mode) { + nan = float16_default_nan(s); + } + return nan; + } else if (float16_is_zero(f16)) { + float_raise(float_flag_divbyzero, s); + return float16_set_sign(float16_infinity, f16_sign); + } else if (f16_sign) { + float_raise(float_flag_invalid, s); + return float16_default_nan(s); + } else if (float16_is_infinity(f16)) { + return float16_zero; + } + + /* Scale and normalize to a double-precision value between 0.25 and 1.0, + * preserving the parity of the exponent. */ + + f64_frac = ((uint64_t) f16_frac) << (52 - 10); + + f64_frac = recip_sqrt_estimate(&f16_exp, 44, f64_frac); + + /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(2) */ + val = deposit32(0, 15, 1, f16_sign); + val = deposit32(val, 10, 5, f16_exp); + val = deposit32(val, 2, 8, extract64(f64_frac, 52 - 8, 8)); + return make_float16(val); +} + +float32 HELPER(rsqrte_f32)(float32 input, void *fpstp) +{ + float_status *s = fpstp; + float32 f32 = float32_squash_input_denormal(input, s); + uint32_t val = float32_val(f32); + uint32_t f32_sign = float32_is_neg(f32); + int f32_exp = extract32(val, 23, 8); + uint32_t f32_frac = extract32(val, 0, 23); + uint64_t f64_frac; + + if (float32_is_any_nan(f32)) { + float32 nan = f32; + if (float32_is_signaling_nan(f32, s)) { + float_raise(float_flag_invalid, s); + nan = float32_silence_nan(f32, s); + } + if (s->default_nan_mode) { + nan = float32_default_nan(s); + } + return nan; + } else if (float32_is_zero(f32)) { + float_raise(float_flag_divbyzero, s); + return float32_set_sign(float32_infinity, float32_is_neg(f32)); + } else if (float32_is_neg(f32)) { + float_raise(float_flag_invalid, s); + return float32_default_nan(s); + } else if (float32_is_infinity(f32)) { + return float32_zero; + } + + /* Scale and normalize to a double-precision value between 0.25 and 1.0, + * preserving the parity of the exponent. */ + + f64_frac = ((uint64_t) f32_frac) << 29; + + f64_frac = recip_sqrt_estimate(&f32_exp, 380, f64_frac); + + /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(15) */ + val = deposit32(0, 31, 1, f32_sign); + val = deposit32(val, 23, 8, f32_exp); + val = deposit32(val, 15, 8, extract64(f64_frac, 52 - 8, 8)); + return make_float32(val); +} + +float64 HELPER(rsqrte_f64)(float64 input, void *fpstp) +{ + float_status *s = fpstp; + float64 f64 = float64_squash_input_denormal(input, s); + uint64_t val = float64_val(f64); + bool f64_sign = float64_is_neg(f64); + int f64_exp = extract64(val, 52, 11); + uint64_t f64_frac = extract64(val, 0, 52); + + if (float64_is_any_nan(f64)) { + float64 nan = f64; + if (float64_is_signaling_nan(f64, s)) { + float_raise(float_flag_invalid, s); + nan = float64_silence_nan(f64, s); + } + if (s->default_nan_mode) { + nan = float64_default_nan(s); + } + return nan; + } else if (float64_is_zero(f64)) { + float_raise(float_flag_divbyzero, s); + return float64_set_sign(float64_infinity, float64_is_neg(f64)); + } else if (float64_is_neg(f64)) { + float_raise(float_flag_invalid, s); + return float64_default_nan(s); + } else if (float64_is_infinity(f64)) { + return float64_zero; + } + + f64_frac = recip_sqrt_estimate(&f64_exp, 3068, f64_frac); + + /* result = sign : result_exp<4:0> : estimate<7:0> : Zeros(44) */ + val = deposit64(0, 61, 1, f64_sign); + val = deposit64(val, 52, 11, f64_exp); + val = deposit64(val, 44, 8, extract64(f64_frac, 52 - 8, 8)); + return make_float64(val); +} + +uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp) +{ + /* float_status *s = fpstp; */ + int input, estimate; + + if ((a & 0x80000000) == 0) { + return 0xffffffff; + } + + input = extract32(a, 23, 9); + estimate = recip_estimate(input); + + return deposit32(0, (32 - 9), 9, estimate); +} + +uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp) +{ + int estimate; + + if ((a & 0xc0000000) == 0) { + return 0xffffffff; + } + + estimate = do_recip_sqrt_estimate(extract32(a, 23, 9)); + + return deposit32(0, 23, 9, estimate); +} + +/* VFPv4 fused multiply-accumulate */ +float32 VFP_HELPER(muladd, s)(float32 a, float32 b, float32 c, void *fpstp) +{ + float_status *fpst = fpstp; + return float32_muladd(a, b, c, 0, fpst); +} + +float64 VFP_HELPER(muladd, d)(float64 a, float64 b, float64 c, void *fpstp) +{ + float_status *fpst = fpstp; + return float64_muladd(a, b, c, 0, fpst); +} + +/* ARMv8 round to integral */ +float32 HELPER(rints_exact)(float32 x, void *fp_status) +{ + return float32_round_to_int(x, fp_status); +} + +float64 HELPER(rintd_exact)(float64 x, void *fp_status) +{ + return float64_round_to_int(x, fp_status); +} + +float32 HELPER(rints)(float32 x, void *fp_status) +{ + int old_flags = get_float_exception_flags(fp_status), new_flags; + float32 ret; + + ret = float32_round_to_int(x, fp_status); + + /* Suppress any inexact exceptions the conversion produced */ + if (!(old_flags & float_flag_inexact)) { + new_flags = get_float_exception_flags(fp_status); + set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); + } + + return ret; +} + +float64 HELPER(rintd)(float64 x, void *fp_status) +{ + int old_flags = get_float_exception_flags(fp_status), new_flags; + float64 ret; + + ret = float64_round_to_int(x, fp_status); + + new_flags = get_float_exception_flags(fp_status); + + /* Suppress any inexact exceptions the conversion produced */ + if (!(old_flags & float_flag_inexact)) { + new_flags = get_float_exception_flags(fp_status); + set_float_exception_flags(new_flags & ~float_flag_inexact, fp_status); + } + + return ret; +} + +/* Convert ARM rounding mode to softfloat */ +int arm_rmode_to_sf(int rmode) +{ + switch (rmode) { + case FPROUNDING_TIEAWAY: + rmode = float_round_ties_away; + break; + case FPROUNDING_ODD: + /* FIXME: add support for TIEAWAY and ODD */ + qemu_log_mask(LOG_UNIMP, "arm: unimplemented rounding mode: %d\n", + rmode); + /* fall through for now */ + case FPROUNDING_TIEEVEN: + default: + rmode = float_round_nearest_even; + break; + case FPROUNDING_POSINF: + rmode = float_round_up; + break; + case FPROUNDING_NEGINF: + rmode = float_round_down; + break; + case FPROUNDING_ZERO: + rmode = float_round_to_zero; + break; + } + return rmode; +} diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs index 1a4fc06448..6bdcc65c2c 100644 --- a/target/arm/Makefile.objs +++ b/target/arm/Makefile.objs @@ -5,7 +5,7 @@ obj-$(call land,$(CONFIG_KVM),$(call lnot,$(TARGET_AARCH64))) += kvm32.o obj-$(call land,$(CONFIG_KVM),$(TARGET_AARCH64)) += kvm64.o obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o obj-y += translate.o op_helper.o helper.o cpu.o -obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o +obj-y += neon_helper.o iwmmxt_helper.o vec_helper.o vfp_helper.o obj-y += gdbstub.o obj-$(TARGET_AARCH64) += cpu64.o translate-a64.o helper-a64.o gdbstub64.o obj-$(TARGET_AARCH64) += pauth_helper.o From patchwork Fri Feb 15 19:22:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158540 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1065046jaa; Fri, 15 Feb 2019 11:28:38 -0800 (PST) X-Google-Smtp-Source: AHgI3IakQo1I2AoIwQ6YrqxGZMhRDcT52W8pZlIdp1LTSNBwxvWUbeTnf9vfS2dBwev0D5kyMwXk X-Received: by 2002:a25:ce12:: with SMTP id x18mr9810023ybe.210.1550258918762; Fri, 15 Feb 2019 11:28:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258918; cv=none; d=google.com; s=arc-20160816; b=sHLgirWFwnzpdsezvb7rZNytYv2DwCY7D3qrMa+X3PhTVreDGfuXFhTqlroXZ80+4m 3E2ZuOMIgAhes6Q2sVN066mcaCbJfHF5yJfwvrGapvSD4mqDoFTEqmafWU2L+1R8koBe fiVN1Q2Ia7t+p4gGsSAytH8pNX/yLR+RbpAqXIVP/RG3zmVFdxD9opUvT/kjMtYEpETj zlT5zPPK22Du6C3kFwyCET/j3hDnTV0o5tSJmRE3II206Ko7KKFqouJP8NfMb0Etl8qV HQdGzBYwEmMJIQ/XCxOwpPD8x5b0/4KNtDdi2QoOVCCB/RiGohXeCP+12cYDFsLaybmr NXjQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=51gyUTatbU7IQN+lMo9A7UI7Kfsg4nJW3Mx9lUPNAFU=; b=BsljZ8ekYkb+GnQvPZ2kTQCyD9YTFrmHLobfIhdAHTZFg+wIK+HJsXkZdEriacxnEx /AN01ExDK9Gw9sySdCgDyMVCwfLsQrKpUXU4Yz91gnFV3XiFFY63zaCfGTtiQRAPu/A/ +nJ+ws/Zo9MWuoQ3MSmncbpU9nuDx9ofu8S5vSOCjsi6fPRBynDENdHDaG9jPivoFPxi iSvoyIuGuKhVfpgbVwmJR+WCfKVQiPyt4bn2+Dr5rTWMiaMyouORLW30tvJ/5qGzDLUb XZLfDDGPRQ8SDHSn9GQXz/qnHstTDESp9kI+fIx/RuadAvx4cJpLYFOIur872XPuCoNH 3scQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=pkKxQtIx; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id u7si3663878ybp.73.2019.02.15.11.28.38 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:28:38 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=pkKxQtIx; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45100 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gujA6-0000S9-4F for patch@linaro.org; Fri, 15 Feb 2019 14:28:38 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33317) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4p-0005LO-Rk for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:13 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4o-0003A2-DL for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:11 -0500 Received: from mail-pg1-x52c.google.com ([2607:f8b0:4864:20::52c]:35296) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4o-00037z-4E for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:10 -0500 Received: by mail-pg1-x52c.google.com with SMTP id s198so5256513pgs.2 for ; Fri, 15 Feb 2019 11:23:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=51gyUTatbU7IQN+lMo9A7UI7Kfsg4nJW3Mx9lUPNAFU=; b=pkKxQtIxBbzt9R0xbFDpLHxnu4M141FxYxX0p+nXAaMDAGJ9XNl4XQ01NJe4ehHop3 4VVQ9r7eLtxQfmX7ePNpgVRw7tPmjpCaJvn5MqvgAg6yS92BQBvB1LQ27J4/ocQFvFU0 0PvwZVkHaA53Visb613NDYk2USvwSn06kG6JBoFVQhTWA6pA4BdmsPFtzatmE4In7Z8t /zUZjfolcEs2bV3+KvSTX3pxqfNgD53MyEeoax3QLljiRdss6KUToTPRnr1/Pszx81QB 0wZ1XfCQOPGWzpVlk/xqsyDvk3t2m49g4JCsgr0e5+WDAEvDfTtsIUana7Y2f2EaYgmg oGDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=51gyUTatbU7IQN+lMo9A7UI7Kfsg4nJW3Mx9lUPNAFU=; b=U3StA7vlUQtKlW93zDxHVDdBkJ04YT1OvwsgzlLBPZTZGWTFl0xXjvz1poSNcTP1Pf B+4xvmaFBQu8X+7rAiK3wBRHePeNkUCwY/uDh2xDT+UigjQKpixtX0nb4f4PyoxgGiL3 Wmthquf2ZDn/+BUf5rFt6v5wtMW4kV3S+g8vEP6L0ga1fexYFhWsMZuVLhHtvNzkFJqJ eI2rmH0BlKPF8EzzRRCgbIvxik7IvT/Lw3UiGsL5uC4Of7iG4EPyPNwIEWDNzC6d3sRT MTiAevgHG2X/LPhZTjy4Yl0xhBvzb4DatHyjYK7phXz4kRYasdiF08GveVIfWMCyqfJm Oazw== X-Gm-Message-State: AHQUAuZCGRhxfkO6CjeK8BZqFzMENzD/vXnlkv/gWOQbNsjezxVqEpXX 1IkLXJvbG8L6+4FoE28I3OF+5rh+0LE= X-Received: by 2002:a62:6303:: with SMTP id x3mr11628743pfb.110.1550258588654; Fri, 15 Feb 2019 11:23:08 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.07 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:07 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:22:57 -0800 Message-Id: <20190215192302.27855-4-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::52c Subject: [Qemu-devel] [PATCH v4 3/8] target/arm: Rearrange Floating-point data-processing (2 regs) X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" There are lots of special cases within these insns. Split the major argument decode/loading/saving into no_output (compares), rd_is_dp, and rm_is_dp. We still need to special case argument load for compare (rd as input, rm as zero) and vcvt fixed (rd as input+output), but lots of special cases do disappear. Now that we have a full switch at the beginning, hoist the ISA checks from the code generation. Signed-off-by: Richard Henderson --- target/arm/translate.c | 227 ++++++++++++++++++++--------------------- 1 file changed, 111 insertions(+), 116 deletions(-) -- 2.17.2 Reviewed-by: Peter Maydell diff --git a/target/arm/translate.c b/target/arm/translate.c index dac737f6ca..64c5fe0df3 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3639,52 +3639,108 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) } } else { /* data processing */ + bool rd_is_dp = dp; + bool rm_is_dp = dp; + bool no_output = false; + /* The opcode is in bits 23, 21, 20 and 6. */ op = ((insn >> 20) & 8) | ((insn >> 19) & 6) | ((insn >> 6) & 1); - if (dp) { - if (op == 15) { - /* rn is opcode */ - rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1); - } else { - /* rn is register number */ - VFP_DREG_N(rn, insn); - } + rn = VFP_SREG_N(insn); - if (op == 15 && (rn == 15 || ((rn & 0x1c) == 0x18) || - ((rn & 0x1e) == 0x6))) { - /* Integer or single/half precision destination. */ - rd = VFP_SREG_D(insn); - } else { - VFP_DREG_D(rd, insn); - } - if (op == 15 && - (((rn & 0x1c) == 0x10) || ((rn & 0x14) == 0x14) || - ((rn & 0x1e) == 0x4))) { - /* VCVT from int or half precision is always from S reg - * regardless of dp bit. VCVT with immediate frac_bits - * has same format as SREG_M. + if (op == 15) { + /* rn is opcode, encoded as per VFP_SREG_N. */ + switch (rn) { + case 0x00: /* vmov */ + case 0x01: /* vabs */ + case 0x02: /* vneg */ + case 0x03: /* vsqrt */ + break; + + case 0x04: /* vcvtb.f64.f16, vcvtb.f32.f16 */ + case 0x05: /* vcvtt.f64.f16, vcvtt.f32.f16 */ + /* + * VCVTB, VCVTT: only present with the halfprec extension + * UNPREDICTABLE if bit 8 is set prior to ARMv8 + * (we choose to UNDEF) */ - rm = VFP_SREG_M(insn); - } else { - VFP_DREG_M(rm, insn); + if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) || + !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) { + return 1; + } + rm_is_dp = false; + break; + case 0x06: /* vcvtb.f16.f32, vcvtb.f16.f64 */ + case 0x07: /* vcvtt.f16.f32, vcvtt.f16.f64 */ + if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) || + !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) { + return 1; + } + rd_is_dp = false; + break; + + case 0x08: case 0x0a: /* vcmp, vcmpz */ + case 0x09: case 0x0b: /* vcmpe, vcmpez */ + no_output = true; + break; + + case 0x0c: /* vrintr */ + case 0x0d: /* vrintz */ + case 0x0e: /* vrintx */ + break; + + case 0x0f: /* vcvt double<->single */ + rd_is_dp = !dp; + break; + + case 0x10: /* vcvt.fxx.u32 */ + case 0x11: /* vcvt.fxx.s32 */ + rm_is_dp = false; + break; + case 0x18: /* vcvtr.u32.fxx */ + case 0x19: /* vcvtz.u32.fxx */ + case 0x1a: /* vcvtr.s32.fxx */ + case 0x1b: /* vcvtz.s32.fxx */ + rd_is_dp = false; + break; + + case 0x14: /* vcvt fp <-> fixed */ + case 0x15: + case 0x16: + case 0x17: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { + return 1; + } + /* Immediate frac_bits has same format as SREG_M. */ + rm_is_dp = false; + break; + + default: + return 1; } + } else if (dp) { + /* rn is register number */ + VFP_DREG_N(rn, insn); + } + + if (rd_is_dp) { + VFP_DREG_D(rd, insn); + } else { + rd = VFP_SREG_D(insn); + } + if (rm_is_dp) { + VFP_DREG_M(rm, insn); } else { - rn = VFP_SREG_N(insn); - if (op == 15 && rn == 15) { - /* Double precision destination. */ - VFP_DREG_D(rd, insn); - } else { - rd = VFP_SREG_D(insn); - } - /* NB that we implicitly rely on the encoding for the frac_bits - * in VCVT of fixed to float being the same as that of an SREG_M - */ rm = VFP_SREG_M(insn); } veclen = s->vec_len; - if (op == 15 && rn > 3) + if (op == 15 && rn > 3) { veclen = 0; + } /* Shut up compiler warnings. */ delta_m = 0; @@ -3720,55 +3776,28 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) /* Load the initial operands. */ if (op == 15) { switch (rn) { - case 16: - case 17: - /* Integer source */ - gen_mov_F0_vreg(0, rm); - break; - case 8: - case 9: - /* Compare */ + case 0x08: case 0x09: /* Compare */ gen_mov_F0_vreg(dp, rd); gen_mov_F1_vreg(dp, rm); break; - case 10: - case 11: - /* Compare with zero */ + case 0x0a: case 0x0b: /* Compare with zero */ gen_mov_F0_vreg(dp, rd); gen_vfp_F1_ld0(dp); break; - case 20: - case 21: - case 22: - case 23: - case 28: - case 29: - case 30: - case 31: + case 0x14: /* vcvt fp <-> fixed */ + case 0x15: + case 0x16: + case 0x17: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* Source and destination the same. */ gen_mov_F0_vreg(dp, rd); break; - case 4: - case 5: - case 6: - case 7: - /* VCVTB, VCVTT: only present with the halfprec extension - * UNPREDICTABLE if bit 8 is set prior to ARMv8 - * (we choose to UNDEF) - */ - if ((dp && !arm_dc_feature(s, ARM_FEATURE_V8)) || - !arm_dc_feature(s, ARM_FEATURE_VFP_FP16)) { - return 1; - } - if (!extract32(rn, 1, 1)) { - /* Half precision source. */ - gen_mov_F0_vreg(0, rm); - break; - } - /* Otherwise fall through */ default: /* One source operand. */ - gen_mov_F0_vreg(dp, rm); + gen_mov_F0_vreg(rm_is_dp, rm); break; } } else { @@ -4047,10 +4076,11 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) break; } case 15: /* single<->double conversion */ - if (dp) + if (dp) { gen_helper_vfp_fcvtsd(cpu_F0s, cpu_F0d, cpu_env); - else + } else { gen_helper_vfp_fcvtds(cpu_F0d, cpu_F0s, cpu_env); + } break; case 16: /* fuito */ gen_vfp_uito(dp, 0); @@ -4059,27 +4089,15 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) gen_vfp_sito(dp, 0); break; case 20: /* fshto */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_shto(dp, 16 - rm, 0); break; case 21: /* fslto */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_slto(dp, 32 - rm, 0); break; case 22: /* fuhto */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_uhto(dp, 16 - rm, 0); break; case 23: /* fulto */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_ulto(dp, 32 - rm, 0); break; case 24: /* ftoui */ @@ -4095,57 +4113,34 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) gen_vfp_tosiz(dp, 0); break; case 28: /* ftosh */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_tosh(dp, 16 - rm, 0); break; case 29: /* ftosl */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_tosl(dp, 32 - rm, 0); break; case 30: /* ftouh */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_touh(dp, 16 - rm, 0); break; case 31: /* ftoul */ - if (!arm_dc_feature(s, ARM_FEATURE_VFP3)) { - return 1; - } gen_vfp_toul(dp, 32 - rm, 0); break; default: /* undefined */ - return 1; + g_assert_not_reached(); } break; default: /* undefined */ return 1; } - /* Write back the result. */ - if (op == 15 && (rn >= 8 && rn <= 11)) { - /* Comparison, do nothing. */ - } else if (op == 15 && dp && ((rn & 0x1c) == 0x18 || - (rn & 0x1e) == 0x6)) { - /* VCVT double to int: always integer result. - * VCVT double to half precision is always a single - * precision result. - */ - gen_mov_vreg_F0(0, rd); - } else if (op == 15 && rn == 15) { - /* conversion */ - gen_mov_vreg_F0(!dp, rd); - } else { - gen_mov_vreg_F0(dp, rd); + /* Write back the result, if any. */ + if (!no_output) { + gen_mov_vreg_F0(rd_is_dp, rd); } /* break out of the loop if we have finished */ - if (veclen == 0) + if (veclen == 0) { break; + } if (op == 15 && delta_m == 0) { /* single source one-many */ From patchwork Fri Feb 15 19:22:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158537 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1063224jaa; Fri, 15 Feb 2019 11:26:15 -0800 (PST) X-Google-Smtp-Source: AHgI3IZTB26kOF/Z5+dQxGGg19Vrg37bo3Nkeln7AClubL54sgIw9qI4QVSg+XBZfYdCXkLh+m10 X-Received: by 2002:a0d:c644:: with SMTP id i65mr9445662ywd.68.1550258775500; Fri, 15 Feb 2019 11:26:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258775; cv=none; d=google.com; s=arc-20160816; b=ua1oOG/fQs3eLUFUNFOzFCW1XswANv7gOpGcCKckOl4SP+9cppNbvg7Iluba0BW4Ub A7XSGeT7bjMGukk7421SOg0jxfNIV8Z+s5uxTM869gsKf963G3fphg+kero3gVdRmZFX g/x73jkQ0RbnFM1gpnvEc9Z/Xk+zRQfw69rMHDvcljuh1/2BVC/yKcO2cZluHaOhacpH zPdbcVC3O4UAoA4K4+FDchXfi/iZANtDZ3GHiikIUsOeSaqexn0jQJ3k+7KY+EXDzmap e1Qetpt+uD/e6gSIQ2FQsoVl3CJrgBPACGMMIQONs7qBhgkLyGZSUKfw7fh7KaoyrvuA eklg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=39OtVN4TBh0vnLaX14yGpOPlnWbzD5AK+QSStyaip3k=; b=Lhv5onOHol6kZdGTNZ/hKL4kGrk2Wh31E8ITORTb+fFIrHoY/nwuJ3p0OdJPeXsDsb Wb8P1RLdkkacyvoI1l1KB6K6gLP7eWU92VxmYwMQhuZBATR46uqWbtjsZI8Et6NbKuG+ rmTGJr/qoz0rYBtRjCyIDABtwwiS9SyMYV2/d+BQDbLlVSa+A4iRNBA9SN4b0qf8ra/p MMb8vY50sumD3yhJzO1/43hSkSs9bAr+nanmpGuwGPJKZKUYFvhBe7B9Z7VU1pbkMjKE NnS097JEZ2IS8QylVmgUpnpeJExuAX4WR2cb75XR5pPdDmwChakBOfHZ8EH+ny0nYN6P rMnw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=OPG9NOjR; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id o6si3770978ybq.235.2019.02.15.11.26.15 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:26:15 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=OPG9NOjR; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45044 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj7m-0006a5-IR for patch@linaro.org; Fri, 15 Feb 2019 14:26:14 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33331) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4r-0005Mg-6v for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:14 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4p-0003Dn-UI for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:13 -0500 Received: from mail-pf1-x434.google.com ([2607:f8b0:4864:20::434]:44542) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4p-0003C9-Ke for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:11 -0500 Received: by mail-pf1-x434.google.com with SMTP id u6so5266910pfh.11 for ; Fri, 15 Feb 2019 11:23:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=39OtVN4TBh0vnLaX14yGpOPlnWbzD5AK+QSStyaip3k=; b=OPG9NOjRyY6vzV+d8nxIRretMLaT84rWRIkrLHQCrwNSH2oMRdru4XDLhdAJNSId/+ UoYbYRC5tYKA7P08cZl/DaWuFvuvqVJwSX7R7EtG1Uu0Py7+ZL6xEDbDS3eDuxkQrTIx RHf5E02gqmOz/XVnwqPjUSodxMiPtYGNIykZn5nAdYk7rN+rz09uvtEmdcPfxghc002C kSM/2TaQRK2jXcdkb2Bzpmq0UsvQv8tGdhtoGrPvH1siQlaUqUnfd7IfTB+nsOkQiPqF wst3KI7VyHnW+ytOgDQ63J3PoD9IXA7hj+9biL36zbsO5smb78ZKxw++3NQ7vRXTqIy+ pq7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=39OtVN4TBh0vnLaX14yGpOPlnWbzD5AK+QSStyaip3k=; b=G5J3D2WjgqCTsPjtoopkd1aBEmTpcm60g6lXGET/Mb+LRPBAMel4Lax4op4bxwCx6t 2+lM7HwCc8akVG/NRHEEPHu5S66GbsxLFfOkrBZ1RzDYM+TjzTcSz1Y69vYMX1wvACJe c6QZwsMZsBklReUhtTxkckAytDzm8xn1IG0lzPILuqctjfmcR2w71TJhDPYXvqcZ/Xpv 9HD4rmF2E84nlok+S6pMpxuaKokQv+iGCExPU1DG9LL6fIBZkQfIeWog9uwUByyR3YbR 9zfdFM0lff2OlrX/LCbGZRUfnJEXjWdNpRB9Ir6Ackp0eIkxtqOlLDPZnemtHD+1OAkA 57LQ== X-Gm-Message-State: AHQUAuYGTFOhKbx120C7sMXwolpayZ+OmIQDVsVDYHn7ORAl6D9FAnwC qg2Vj5ytukj27k0wUmshTy1nnHcY4vc= X-Received: by 2002:a62:48c1:: with SMTP id q62mr7891330pfi.113.1550258589994; Fri, 15 Feb 2019 11:23:09 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.08 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:09 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:22:58 -0800 Message-Id: <20190215192302.27855-5-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::434 Subject: [Qemu-devel] [PATCH v4 4/8] target/arm: Implement ARMv8.3-JSConv X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Richard Henderson --- v2: Return 0 for NaN v3: Return aa32 flags in FPSCR.NZCV. --- target/arm/cpu.h | 10 +++++ target/arm/helper.h | 3 ++ target/arm/cpu.c | 1 + target/arm/cpu64.c | 2 + target/arm/translate-a64.c | 26 +++++++++++ target/arm/translate.c | 10 +++++ target/arm/vfp_helper.c | 88 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 140 insertions(+) -- 2.17.2 Reviewed-by: Peter Maydell diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 84ae6849c2..1eea1a408b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3273,6 +3273,11 @@ static inline bool isar_feature_aa32_vcma(const ARMISARegisters *id) return FIELD_EX32(id->id_isar5, ID_ISAR5, VCMA) != 0; } +static inline bool isar_feature_aa32_jscvt(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_isar6, ID_ISAR6, JSCVT) != 0; +} + static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) { return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; @@ -3351,6 +3356,11 @@ static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; } +static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; +} + static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FCMA) != 0; diff --git a/target/arm/helper.h b/target/arm/helper.h index 923e8e1525..747cb64d29 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -218,6 +218,9 @@ DEF_HELPER_FLAGS_2(rintd_exact, TCG_CALL_NO_RWG, f64, f64, ptr) DEF_HELPER_FLAGS_2(rints, TCG_CALL_NO_RWG, f32, f32, ptr) DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, ptr) +DEF_HELPER_FLAGS_2(vjcvt, TCG_CALL_NO_RWG, i32, f64, env) +DEF_HELPER_FLAGS_2(fjcvtzs, TCG_CALL_NO_RWG, i64, f64, ptr) + /* neon_helper.c */ DEF_HELPER_FLAGS_3(neon_qadd_u8, TCG_CALL_NO_RWG, i32, env, i32, i32) DEF_HELPER_FLAGS_3(neon_qadd_s8, TCG_CALL_NO_RWG, i32, env, i32, i32) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index edf6e0e1f1..8ea6569088 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2001,6 +2001,7 @@ static void arm_max_initfn(Object *obj) cpu->isar.id_isar5 = t; t = cpu->isar.id_isar6; + t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); t = FIELD_DP32(t, ID_ISAR6, DP, 1); cpu->isar.id_isar6 = t; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index eff0f164dd..69e4134f79 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -311,6 +311,7 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_aa64isar0 = t; t = cpu->isar.id_aa64isar1; + t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1); t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1); t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */ t = FIELD_DP64(t, ID_AA64ISAR1, API, 0); @@ -344,6 +345,7 @@ static void aarch64_max_initfn(Object *obj) cpu->isar.id_isar5 = u; u = cpu->isar.id_isar6; + u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); u = FIELD_DP32(u, ID_ISAR6, DP, 1); cpu->isar.id_isar6 = u; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index dbce24fe32..c56e878787 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -6526,6 +6526,24 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof) } } +static void handle_fjcvtzs(DisasContext *s, int rd, int rn) +{ + TCGv_i64 t = read_fp_dreg(s, rn); + TCGv_ptr fpstatus = get_fpstatus_ptr(false); + + gen_helper_fjcvtzs(t, t, fpstatus); + + tcg_temp_free_ptr(fpstatus); + + tcg_gen_ext32u_i64(cpu_reg(s, rd), t); + tcg_gen_extrh_i64_i32(cpu_ZF, t); + tcg_gen_movi_i32(cpu_CF, 0); + tcg_gen_movi_i32(cpu_NF, 0); + tcg_gen_movi_i32(cpu_VF, 0); + + tcg_temp_free_i64(t); +} + /* Floating point <-> integer conversions * 31 30 29 28 24 23 22 21 20 19 18 16 15 10 9 5 4 0 * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+ @@ -6601,6 +6619,14 @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn) handle_fmov(s, rd, rn, type, itof); break; + case 0b00111110: /* FJCVTZS */ + if (!dc_isar_feature(aa64_jscvt, s)) { + goto do_unallocated; + } else if (fp_access_check(s)) { + handle_fjcvtzs(s, rd, rn); + } + break; + default: do_unallocated: unallocated_encoding(s); diff --git a/target/arm/translate.c b/target/arm/translate.c index 64c5fe0df3..c1175798ac 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -3718,6 +3718,13 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) rm_is_dp = false; break; + case 0x13: /* vjcvt */ + if (!dp || !dc_isar_feature(aa32_jscvt, s)) { + return 1; + } + rd_is_dp = false; + break; + default: return 1; } @@ -4088,6 +4095,9 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) case 17: /* fsito */ gen_vfp_sito(dp, 0); break; + case 19: /* vjcvt */ + gen_helper_vjcvt(cpu_F0s, cpu_F0d, cpu_env); + break; case 20: /* fshto */ gen_vfp_shto(dp, 16 - rm, 0); break; diff --git a/target/arm/vfp_helper.c b/target/arm/vfp_helper.c index 74d3030c47..f19c0606c2 100644 --- a/target/arm/vfp_helper.c +++ b/target/arm/vfp_helper.c @@ -1086,3 +1086,91 @@ int arm_rmode_to_sf(int rmode) } return rmode; } + +/* + * Implement float64 to int32_t conversion without saturation; + * the result is supplied modulo 2^32. + */ +uint64_t HELPER(fjcvtzs)(float64 value, void *vstatus) +{ + float_status *status = vstatus; + uint32_t exp, sign; + uint64_t frac; + uint32_t inexact = 1; /* !Z */ + + sign = extract64(value, 63, 1); + exp = extract64(value, 52, 11); + frac = extract64(value, 0, 52); + + if (exp == 0) { + /* While not inexact for IEEE FP, -0.0 is inexact for JavaScript. */ + inexact = sign; + if (frac != 0) { + if (status->flush_inputs_to_zero) { + float_raise(float_flag_input_denormal, status); + } else { + float_raise(float_flag_inexact, status); + inexact = 1; + } + } + frac = 0; + } else if (exp == 0x7ff) { + /* This operation raises Invalid for both NaN and overflow (Inf). */ + float_raise(float_flag_invalid, status); + frac = 0; + } else { + int true_exp = exp - 1023; + int shift = true_exp - 52; + + /* Restore implicit bit. */ + frac |= 1ull << 52; + + /* Shift the fraction into place. */ + if (shift >= 0) { + /* The number is so large we must shift the fraction left. */ + if (shift >= 64) { + /* The the fraction is shifted out entirely. */ + frac = 0; + } else { + frac <<= shift; + } + } else if (shift > -64) { + /* Normal case -- shift right and notice if bits shift out. */ + inexact = (frac << (64 + shift)) != 0; + frac >>= -shift; + } else { + /* The fraction is shifted out entirely. */ + frac = 0; + } + + /* Notice overflow or inexact exceptions. */ + if (true_exp > 31 || frac > (sign ? 0x80000000ull : 0x7fffffff)) { + /* Overflow, for which this operation raises invalid. */ + float_raise(float_flag_invalid, status); + inexact = 1; + } else if (inexact) { + float_raise(float_flag_inexact, status); + } + + /* Honor the sign. */ + if (sign) { + frac = -frac; + } + } + + /* Pack the result and the env->ZF representation of Z together. */ + return deposit64(frac, 32, 32, inexact); +} + +uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env) +{ + uint64_t pair = HELPER(fjcvtzs)(value, &env->vfp.fp_status); + uint32_t result = pair; + uint32_t z = (pair >> 32) == 0; + + /* Store Z, clear NCV, in FPSCR.NZCF. */ + env->vfp.xregs[ARM_VFP_FPSCR] + = (env->vfp.xregs[ARM_VFP_FPSCR] & ~CPSR_NZCV) | (z * CPSR_Z); + + return result; +} From patchwork Fri Feb 15 19:22:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158542 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1065287jaa; Fri, 15 Feb 2019 11:29:00 -0800 (PST) X-Google-Smtp-Source: AHgI3IZJ1sHxIaPNBJhAngrvrkk/AnLfe+Etb3GnDKvsYXYz1k2oVn2UVlfuBGug4tRKbnD0rLI5 X-Received: by 2002:a25:2417:: with SMTP id k23mr9213220ybk.454.1550258940444; Fri, 15 Feb 2019 11:29:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258940; cv=none; d=google.com; s=arc-20160816; b=rMgsKZ0DLOJybPLjMcpeiiMAakXVv5W70kE3YcMVu1DeCbnvmNT78PQEum1L4tOe55 ZFeEAtA05zOMwC6XLcIzxfmxe2awLSG52NKku3cz9vJsfgfl7hj1f3lMc+n10xYZa43i HCtl5NyAXg2YornRd6yN6pKNL/pWPAzIxJ5vtw3K7ULbH+//RMVup7LoILz4ha7SDwxN Cn0BajfqrwPvsePNxOU0pDOvtItTwjl9o8V5VwvWXz2L9dFvsZRkhgHfyKYFTcUABytn EwyCn3XRc5bVNJ4SDwLR2JRSoB5R0tMK9IFUmx+XHAjgyGUmlR0olSLf60+lj4HK8ewt Lelw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=y5Stu1HfbXPLKVYHkJvn73UH8fPmTrC6pSpjgP9O8jo=; b=Fevjs2WoIyewusQfYZSigiyupjycUrdON8OueDVm5xGUzO+OCOi8INyBInr8U7CMqj v7iI2CvdT7mpkYI6hb2oXMUtcy/iAplaFGiSPXBE2pq3oNUiEeFlrXjOdQWOOBHP04PG CFj32ggAGZNqlfwnawHPzaYfjBwUiSWmmKb2hzBmDrj5OprljtRAky3FMPzB/AWkY+GW PMNrzV+NTsUS40fMNR0Lr1xL2v3e9KPu7USTA4kqNBcOoE0oYvkaLAGs+jqprNqtTJlC lNrwq8LIxXEZKU6+SSdfsRw7KQCjj5V92hwxej6rxpfhfLJHjzeqQR0hfzRcMcC0bUya V5Uw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=AIMl9KtX; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id p145si2551400ybc.329.2019.02.15.11.29.00 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:29:00 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=AIMl9KtX; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45108 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gujAR-0001QJ-VB for patch@linaro.org; Fri, 15 Feb 2019 14:28:59 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33339) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4s-0005NM-3w for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4r-0003Fs-1F for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:14 -0500 Received: from mail-pg1-x541.google.com ([2607:f8b0:4864:20::541]:45974) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4q-0003FR-RR for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:12 -0500 Received: by mail-pg1-x541.google.com with SMTP id y4so5233420pgc.12 for ; Fri, 15 Feb 2019 11:23:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=y5Stu1HfbXPLKVYHkJvn73UH8fPmTrC6pSpjgP9O8jo=; b=AIMl9KtXDk+hy9hp6aMc9QbwIxlnUdGk096zx6IdiSHzryoVMDQ7+G21Iy6jcg6eoN c5N2Ib2AbIvgn2OSYHDiBFKXl45qI4PBMYKtTo9o1DhLveiClg6pTq/VbpW7TzSYhK9b 3GjhsfLsazb2NbeG5TmRAQzgir92xEUodgdt+1G3A66BRuuHT5swNbakAaKQL4c4YV/w dJu1srhEw2xNpfe7uyLLhwl05wnkqk7nGkrSaaMS//HH7zcWqdNuaHLVe5s2Hi5jJIuC cYSA4M9UlKhEq5Gq9TcwD2QcWuc21VH7gmEQ5E1lucrpECPUNTd5rq58R3TSKIb/feIy mCgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=y5Stu1HfbXPLKVYHkJvn73UH8fPmTrC6pSpjgP9O8jo=; b=T69mfpznh33gcWjs4x3tVqAC1DRINZyQSfANajDu4IwaqGn5tEtszvZTdIghTnIoz8 5mMkTHuHMg/tAnTpWSVs8ot2RLNq1Wzx4KuuTj0Pqdn9ii15qjlDwRgP1a2t1KWdbhFv 7g/zKZfXwNU/wdwdjEWaDiwYROQ3Fx4jRgY2zjxLEWe/hip6HDlzV4lO8fAM9DN60PW4 tQgjw2DJQ0wi6apYbSenO/i4VyohsBGt627gVUpEU8LfZ7RCnIGzoBlzP7eR+Fkm4o9p VHjpPnqhXWDV16SabPJ1gdqL29nFB958ymOa+wc9+ecaDsfOL5WXZujCnIlhXDwxJPVD bPFA== X-Gm-Message-State: AHQUAuZbBH9DV67U7Gs19CzJb0n01WUPycdOP6zBDLVTEXo5TWkdRXZB xJe/yfboSUrH3i4Oij8mh6mPMY0AdpA= X-Received: by 2002:a63:c948:: with SMTP id y8mr6958197pgg.263.1550258591391; Fri, 15 Feb 2019 11:23:11 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.10 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:10 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:22:59 -0800 Message-Id: <20190215192302.27855-6-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::541 Subject: [Qemu-devel] [PATCH v4 5/8] target/arm: Add helpers for FMLAL X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Note that float16_to_float32 rightly squashes SNaN to QNaN. But of course pickNaNMulAdd, for ARM, selects SNaNs first. So we have to preserve SNaN long enough for the correct NaN to be selected. Thus float16_to_float32_by_bits. Signed-off-by: Richard Henderson --- target/arm/helper.h | 5 ++ target/arm/vec_helper.c | 114 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) -- 2.17.2 diff --git a/target/arm/helper.h b/target/arm/helper.h index 747cb64d29..03a613a00b 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -677,6 +677,11 @@ DEF_HELPER_FLAGS_5(gvec_sqsub_s, TCG_CALL_NO_RWG, DEF_HELPER_FLAGS_5(gvec_sqsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + #ifdef TARGET_AARCH64 #include "helper-a64.h" #include "helper-sve.h" diff --git a/target/arm/vec_helper.c b/target/arm/vec_helper.c index dfc635cf9a..224e5315b1 100644 --- a/target/arm/vec_helper.c +++ b/target/arm/vec_helper.c @@ -898,3 +898,117 @@ void HELPER(gvec_sqsub_d)(void *vd, void *vq, void *vn, } clear_tail(d, oprsz, simd_maxsz(desc)); } + +/* + * Convert float16 to float32, raising no exceptions and + * preserving exceptional values, including SNaN. + * This is effectively an unpack+repack operation. + */ +static float32 float16_to_float32_by_bits(uint32_t f16) +{ + const int f16_bias = 15; + const int f32_bias = 127; + uint32_t sign = extract32(f16, 15, 1); + uint32_t exp = extract32(f16, 10, 5); + uint32_t frac = extract32(f16, 0, 10); + + if (exp == 0x1f) { + /* Inf or NaN */ + exp = 0xff; + } else if (exp == 0) { + /* Zero or denormal. */ + if (frac != 0) { + /* + * Denormal; these are all normal float32. + * Shift the fraction so that the msb is at bit 11, + * then remove bit 11 as the implicit bit of the + * normalized float32. Note that we still go through + * the shift for normal numbers below, to put the + * float32 fraction at the right place. + */ + int shift = clz32(frac) - 21; + frac = (frac << shift) & 0x3ff; + exp = f32_bias - f16_bias - shift + 1; + } + } else { + /* Normal number; adjust the bias. */ + exp += f32_bias - f16_bias; + } + sign <<= 31; + exp <<= 23; + frac <<= 23 - 10; + + return sign | exp | frac; +} + +static uint64_t load4_f16(uint64_t *ptr, int is_q, int is_2) +{ + /* + * Branchless load of u32[0], u64[0], u32[1], or u64[1]. + * Load the 2nd qword iff is_q & is_2. + * Shift to the 2nd dword iff !is_q & is_2. + * For !is_q & !is_2, the upper bits of the result are garbage. + */ + return ptr[is_q & is_2] >> ((is_2 & ~is_q) << 5); +} + +/* + * Note that FMLAL requires oprsz == 8 or oprsz == 16, + * as there is not yet SVE versions that might use blocking. + */ + +void HELPER(gvec_fmlal_h)(void *vd, void *vn, void *vm, + void *fpst, uint32_t desc) +{ + intptr_t i, oprsz = simd_oprsz(desc); + int is_s = extract32(desc, SIMD_DATA_SHIFT, 1); + int is_2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1); + int is_q = oprsz == 16; + float32 *d = vd; + uint64_t n_4, m_4; + + /* Pre-load all of the f16 data, avoiding overlap issues. */ + n_4 = load4_f16(vn, is_q, is_2); + m_4 = load4_f16(vm, is_q, is_2); + + /* Negate all inputs for FMLSL at once. */ + if (is_s) { + n_4 ^= 0x8000800080008000ull; + } + + for (i = 0; i < oprsz / 4; i++) { + float32 n_1 = float16_to_float32_by_bits(n_4 >> (i * 16)); + float32 m_1 = float16_to_float32_by_bits(m_4 >> (i * 16)); + d[H4(i)] = float32_muladd(n_1, m_1, d[H4(i)], 0, fpst); + } + clear_tail(d, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fmlal_idx_h)(void *vd, void *vn, void *vm, + void *fpst, uint32_t desc) +{ + intptr_t i, oprsz = simd_oprsz(desc); + int is_s = extract32(desc, SIMD_DATA_SHIFT, 1); + int is_2 = extract32(desc, SIMD_DATA_SHIFT + 1, 1); + int index = extract32(desc, SIMD_DATA_SHIFT + 2, 3); + int is_q = oprsz == 16; + float32 *d = vd; + uint64_t n_4; + float32 m_1; + + /* Pre-load all of the f16 data, avoiding overlap issues. */ + n_4 = load4_f16(vn, is_q, is_2); + + /* Negate all inputs for FMLSL at once. */ + if (is_s) { + n_4 ^= 0x8000800080008000ull; + } + + m_1 = float16_to_float32_by_bits(((float16 *)vm)[H2(index)]); + + for (i = 0; i < oprsz / 4; i++) { + float32 n_1 = float16_to_float32_by_bits(n_4 >> (i * 16)); + d[H4(i)] = float32_muladd(n_1, m_1, d[H4(i)], 0, fpst); + } + clear_tail(d, oprsz, simd_maxsz(desc)); +} From patchwork Fri Feb 15 19:23:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158543 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1065636jaa; Fri, 15 Feb 2019 11:29:29 -0800 (PST) X-Google-Smtp-Source: AHgI3IapMmpb7dE4eYG2j1KtfuJwowubujPxzdYY/dAJz/j65EnBlz75grMd2Uqq2etbMNB0PSay X-Received: by 2002:a0d:dc07:: with SMTP id f7mr8910632ywe.440.1550258969220; Fri, 15 Feb 2019 11:29:29 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258969; cv=none; d=google.com; s=arc-20160816; b=hEhfcbmwRfOdd1eUikUMKp1HizI7VgYcyDesSjZ/7vBJYEzrb5s+PckBpbWG+zQW0r q/Q2SiGK6Na0bTEpEvO6/P1sonONI0zUa2SGJMfkWhHDF3Uxc7TGOVrplHxWQlK81fwc zFHM4y2t2msrHtFj2hi7ICJY7cNL2w90J0pQhQm5Y99E22UQIj9q+S9wG3gDFoGqNAdi JMzU0SjrgyEYF3PhALNdMyZE2H4MBmtijkkynLIigDAvAE7bNPl4829MbeN0HHMkAUOK xHqyDzWt2UklMcjrmOVxnkNS0jlst1X5GEf9yiMD9laRCVRMW/x9l4b++cZ2YwfgkwNQ Qu8w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=BU/ewC8+prSMkfZW9PvJmy7JChgMnIDyBTrL1xlJ2p4=; b=BD1RUVQ1dimHqQalD+JKLM3YLNRN+xO8Wi/jgTLEYgyo8bLy8SWb/ghPaKKIyvT2qa JVUiAzpkKNj1cC91vGM1rQqa0Y0DzhPL/5lQeAcd2KVozkswbMygoaOBxsuCeV8u5Ce3 CJmgFlvqUCZvVZ2sGkL9qa7ldXHXfkA0XAkvHgebNBrB+2n78zgnBl/71dSzwzxyXTdP atZUclMFpWL7xV959YBww/xI0AKX9VhTHsJbaIyfgLpoPc53T4pHFFxDcWq7CuwdobDM GEfsGsc/19k1tmCrRN38AG+Wgnkhn215ovshZOhiGKwxOEXyLxIp4x+QNWqs/oOVYz4u +0RA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=V1l+BJ5g; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id t8si3698961yba.36.2019.02.15.11.29.29 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:29:29 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=V1l+BJ5g; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45104 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gujAu-0001IF-Od for patch@linaro.org; Fri, 15 Feb 2019 14:29:28 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33354) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4t-0005O9-4E for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:16 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4s-0003Is-90 for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:15 -0500 Received: from mail-pl1-x643.google.com ([2607:f8b0:4864:20::643]:38534) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4s-0003GJ-2c for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:14 -0500 Received: by mail-pl1-x643.google.com with SMTP id e5so5410696plb.5 for ; Fri, 15 Feb 2019 11:23:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BU/ewC8+prSMkfZW9PvJmy7JChgMnIDyBTrL1xlJ2p4=; b=V1l+BJ5gpJMFk9bdScaDkEo7q/JbrcmHxoUoOp4vkFfsNuLA/QWCGoqM30RspchHyW G4fLG7Y3pGHTTGBIFj7jwo82nnRYW+x35lLFdP6/El1qY4Hm0oVMzlfTtOxEUXHvvs0Y TWX23ZOMhGcPIFlr25noBZPjTB+vw9KOOeXNR6VQQrXt4o4oyLcl2yOlBtnBLEB4FIBe P3BFs8NyJFvS+C45D0P0BtRTJydD8HC9c1ppGbMAQ6v75i5XJY/WE6YXIXqMzMDFsyYk RE8NdYlWmE9gUz9TaOh39Q83QEI0wtRJYRewy8E1gsQKNL75Rc36AffIW7VHmFP8Bx2G W5MQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=BU/ewC8+prSMkfZW9PvJmy7JChgMnIDyBTrL1xlJ2p4=; b=tUSm4dARZUJ9gQMtBBXA1rbSAhmr8jjgbaIHcspWok0E5pKtpwr7UKUqs+psTzb/r3 9dHhiNC1LDnC0XaaPxNyenP1ZArHmUnNGo/wjDVOqyrPIMlmBt4LVSYjR8EXmEJbF2Ys oa0nGv4yc6EXRBONFtFWbW2ifIGlKPi2m8MIUwL38q3mcoSSEG9lYxUV64XNSbB76pzV Hy1/KwKKT/Vx9HMfOPKgoEqUNfXkR0Moahy6sqwOFsJ0+p+SA2gopc+V9MohesZszi3H SrLl8Ei2/YLKxHy7X6/eGWZSyindLDHov4dgb6IrTeQQYof1MRpHYz92Z2rm9KfavdHd faKA== X-Gm-Message-State: AHQUAuaUi3ME9KOVsF2ACUmXuyIgjDhMQzCX1LAELGTczi5geGFqZhzi GzUkwmiaMi3cW5lC9G0LCpPzdkLWeXA= X-Received: by 2002:a17:902:34a:: with SMTP id 68mr11996183pld.268.1550258592691; Fri, 15 Feb 2019 11:23:12 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.11 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:11 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:23:00 -0800 Message-Id: <20190215192302.27855-7-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::643 Subject: [Qemu-devel] [PATCH v4 6/8] target/arm: Implement FMLAL and FMLSL for aarch64 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Richard Henderson --- target/arm/cpu.h | 5 ++++ target/arm/translate-a64.c | 50 +++++++++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) -- 2.17.2 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 1eea1a408b..69589573e4 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3356,6 +3356,11 @@ static inline bool isar_feature_aa64_dp(const ARMISARegisters *id) return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, DP) != 0; } +static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id) +{ + return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0; +} + static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id) { return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0; diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index c56e878787..9a4c561982 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -10917,9 +10917,26 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn) if (!fp_access_check(s)) { return; } - handle_3same_float(s, size, elements, fpopcode, rd, rn, rm); return; + + case 0x1d: /* FMLAL */ + case 0x3d: /* FMLSL */ + case 0x59: /* FMLAL2 */ + case 0x79: /* FMLSL2 */ + if (size & 1 || !dc_isar_feature(aa64_fhm, s)) { + unallocated_encoding(s); + return; + } + if (fp_access_check(s)) { + int is_s = extract32(insn, 23, 1); + int is_2 = extract32(insn, 29, 1); + int data = (is_2 << 1) | is_s; + gen_gvec_op3_fpst(s, is_q, rd, rn, rm, false, data, + gen_helper_gvec_fmlal_h); + } + return; + default: unallocated_encoding(s); return; @@ -12739,6 +12756,17 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } is_fp = 2; break; + case 0x00: /* FMLAL */ + case 0x04: /* FMLSL */ + case 0x18: /* FMLAL2 */ + case 0x1c: /* FMLSL2 */ + if (is_scalar || size != MO_32 || !dc_isar_feature(aa64_fhm, s)) { + unallocated_encoding(s); + return; + } + size = MO_16; + is_fp = 3; + break; default: unallocated_encoding(s); return; @@ -12780,6 +12808,9 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) } break; + case 3: /* other fp, size already set and verified. */ + break; + default: /* integer */ switch (size) { case MO_8: @@ -12849,6 +12880,23 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn) tcg_temp_free_ptr(fpst); } return; + + case 0x00: /* FMLAL */ + case 0x04: /* FMLSL */ + case 0x18: /* FMLAL2 */ + case 0x1c: /* FMLSL2 */ + { + int is_s = extract32(opcode, 2, 1); + int is_2 = u; + int data = (index << 2) | (is_2 << 1) | is_s; + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), fpst, + is_q ? 16 : 8, vec_full_reg_size(s), data, + gen_helper_gvec_fmlal_idx_h); + tcg_temp_free_ptr(fpst); + } + return; } if (size == 3) { From patchwork Fri Feb 15 19:23:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158538 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1063290jaa; Fri, 15 Feb 2019 11:26:21 -0800 (PST) X-Google-Smtp-Source: AHgI3IZRNtCXU+gO4bzM3cZ3XmQEVYxS6NJ+b2HgFX5yIa4ZGaHRgSGhJ6beVIw8aiUJYLC82uIV X-Received: by 2002:a25:8544:: with SMTP id f4mr9422595ybn.484.1550258781062; Fri, 15 Feb 2019 11:26:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258781; cv=none; d=google.com; s=arc-20160816; b=bpAd3CmcNJExi33BLVNHcSjtTujuzTNBc+lwwsa9weSEoJcYDsLlOLRWU9dLrLa9+4 JKOyW4imy2TyKd0Xux+axtEAqWIUxxrDqkGAhbDA+uT36AdvRYJfn3PzHf+6KYIv+AWw 8mUFKLZl2Pjz5/LlFrvKHXZP/+vrPwipAQlhCuOzhWqxluOLvu09DCsSnrpiyNHT546m hDQSpeo7MBIp6ZqqL0GYQ9e53eCTy31CfjVDF+Op0fvL23U5nT99DXo8fjf23vcmQ5Gm 5R2E+XpIdRVy00svKEDFmy2mb+Fj4Ouejq9iU1+sw3+1De2N4kAMW32yctqMUobe4053 GqfA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=IN48ZCboVTZ5+/mYADGaGur2BX1ffq1za679/1MZfgM=; b=Dswnzf+7D1NAo3z0L3P6WXu7qHG8wjumqZj4KlxFuHSiSUy+XfxhW4ad6otRC9Ddxa DAhdF+Kzaqa9js/hTVWuOxQNFegZpeUBsoywX73RPVSsjCkuzZIfH90+pv4oyP3vonch e5I+JAqetUsVAMFnRnGDZqDg8Xl370dQ42g4P9Pvj4QaAGbQETKAfkHD5JCUrDKPhNXB 4/CzI55Ie2/uGH74rxZAn28s5cOLbb0QnH+qWXQuO7PyYS+3UomMmWRjne1XgveFq6/n Id/yaB1siu4VuGj/Ozvg9hGU2QWwfOi5TZmReywojqXgPbRJnzA3gA3BpxudmtFi+Yia fBjA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=Wv5SVhOL; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id 134si3557355ybc.79.2019.02.15.11.26.20 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:26:21 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=Wv5SVhOL; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45046 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj7s-0006eR-G9 for patch@linaro.org; Fri, 15 Feb 2019 14:26:20 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33374) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4v-0005Qv-WC for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:19 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4u-0003R3-7t for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:17 -0500 Received: from mail-pf1-x441.google.com ([2607:f8b0:4864:20::441]:44286) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4t-0003MS-VO for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:16 -0500 Received: by mail-pf1-x441.google.com with SMTP id u6so5266991pfh.11 for ; Fri, 15 Feb 2019 11:23:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=IN48ZCboVTZ5+/mYADGaGur2BX1ffq1za679/1MZfgM=; b=Wv5SVhOLODmWZvfchEvXDLLat07m7PNRMS6zaCTFuRO5MnpUpG5WMiW0hX3RopRmf1 1BvYSKwToIgeioQ3ucbhjK3N6aH6Z1Lkv5tKOcLcVDnDsbekzymcxgI9kP+dRvsJzZ1R cusuUiayUF1oX3RfwD/qU+FN8NsUbrqmazF3T/IhysKhoPZKEnJ2O2JLrhhaWQVWEMjK paOHozDdN8USXvsJeNDnkNwkr4hW4GB5Iaci+dOVz+qPMTId1P+ddgSX2OLoTOBVvj5A 2qMTINHUQDx59DLACVIHt9HH2nRfgjOqPVtK7a04moaDtaGB7ZpAPE/I/vfIusUmAwRs dsTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=IN48ZCboVTZ5+/mYADGaGur2BX1ffq1za679/1MZfgM=; b=kGbDjJeYT1smreZi9/WKFLSc8rc61ueuKmVWg/SCeiLuw/4oRiQIW9nkwyZA0vyrCi f6Kinu7CnJPPVhvbu94TLiu/ujEbOcUQ1aA4lOYodXHX02RE2scryckgE4AH37d47nUU eJHFPcFWSWIn+c2oTOoaorI9skY5FsZQju1Oh+w2v16Ap1FKwCPBNwFwE+D8JBXmbabs QAO0o5gcuyYo6LnozyrMlFS7W1vgiSAnEBxyDPNXC0RWfeOyddgzKJJWHnkRKf8wTACq hO+p5pWMWLiZFxPaeVwKxptJn2e9ZjeoWYmQ5ACZp99URfQy3nwqWXrdMh8uqvSYW7pU kAjA== X-Gm-Message-State: AHQUAub/QCBF897p7cKVsYexRyNPKRPV9yfnL0EzUlBxMPHl9BRWNRss /JTNZsoReZWve9Pliij2xCx4epn2wts= X-Received: by 2002:a62:4181:: with SMTP id g1mr11260193pfd.45.1550258594611; Fri, 15 Feb 2019 11:23:14 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.12 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:13 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:23:01 -0800 Message-Id: <20190215192302.27855-8-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::441 Subject: [Qemu-devel] [PATCH v4 7/8] target/arm: Implement VFMAL and VFMSL for aarch32 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Richard Henderson --- target/arm/cpu.h | 5 ++ target/arm/translate.c | 103 +++++++++++++++++++++++++++++------------ 2 files changed, 79 insertions(+), 29 deletions(-) -- 2.17.2 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 69589573e4..9cf439fb8d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3283,6 +3283,11 @@ static inline bool isar_feature_aa32_dp(const ARMISARegisters *id) return FIELD_EX32(id->id_isar6, ID_ISAR6, DP) != 0; } +static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id) +{ + return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0; +} + static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) { /* diff --git a/target/arm/translate.c b/target/arm/translate.c index c1175798ac..c319ba9aae 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -8372,15 +8372,8 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL; int rd, rn, rm, opr_sz; int data = 0; - bool q; - - q = extract32(insn, 6, 1); - VFP_DREG_D(rd, insn); - VFP_DREG_N(rn, insn); - VFP_DREG_M(rm, insn); - if ((rd | rn | rm) & q) { - return 1; - } + int off_rn, off_rm; + bool is_long = false, q = extract32(insn, 6, 1); if ((insn & 0xfe200f10) == 0xfc200800) { /* VCMLA -- 1111 110R R.1S .... .... 1000 ...0 .... */ @@ -8407,10 +8400,38 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) return 1; } fn_gvec = u ? gen_helper_gvec_udot_b : gen_helper_gvec_sdot_b; + } else if ((insn & 0xff300f10) == 0xfc200810) { + /* VFM[AS]L -- 1111 1100 S.10 .... .... 1000 .Q.1 .... */ + int is_s = extract32(insn, 23, 1); + if (!dc_isar_feature(aa32_fhm, s)) { + return 1; + } + is_long = true; + fn_gvec_ptr = gen_helper_gvec_fmlal_h; + data = is_s; /* is_2 == 0 */ } else { return 1; } + VFP_DREG_D(rd, insn); + if (rd & q) { + return 1; + } + if (q || !is_long) { + VFP_DREG_N(rn, insn); + VFP_DREG_M(rm, insn); + if ((rn | rm) & q & !is_long) { + return 1; + } + off_rn = vfp_reg_offset(1, rn); + off_rm = vfp_reg_offset(1, rm); + } else { + rn = VFP_SREG_N(insn); + rm = VFP_SREG_M(insn); + off_rn = vfp_reg_offset(0, rn); + off_rm = vfp_reg_offset(0, rm); + } + if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); @@ -8423,15 +8444,11 @@ static int disas_neon_insn_3same_ext(DisasContext *s, uint32_t insn) opr_sz = (1 + q) * 8; if (fn_gvec_ptr) { TCGv_ptr fpst = get_fpstatus_ptr(1); - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), fpst, + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, fpst, opr_sz, opr_sz, data, fn_gvec_ptr); tcg_temp_free_ptr(fpst); } else { - tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), + tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm, opr_sz, opr_sz, data, fn_gvec); } return 0; @@ -8450,14 +8467,8 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) gen_helper_gvec_3 *fn_gvec = NULL; gen_helper_gvec_3_ptr *fn_gvec_ptr = NULL; int rd, rn, rm, opr_sz, data; - bool q; - - q = extract32(insn, 6, 1); - VFP_DREG_D(rd, insn); - VFP_DREG_N(rn, insn); - if ((rd | rn) & q) { - return 1; - } + int off_rn, off_rm; + bool is_long = false, q = extract32(insn, 6, 1); if ((insn & 0xff000f10) == 0xfe000800) { /* VCMLA (indexed) -- 1111 1110 S.RR .... .... 1000 ...0 .... */ @@ -8486,6 +8497,7 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) } else if ((insn & 0xffb00f00) == 0xfe200d00) { /* V[US]DOT -- 1111 1110 0.10 .... .... 1101 .Q.U .... */ int u = extract32(insn, 4, 1); + if (!dc_isar_feature(aa32_dp, s)) { return 1; } @@ -8493,10 +8505,47 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) /* rm is just Vm, and index is M. */ data = extract32(insn, 5, 1); /* index */ rm = extract32(insn, 0, 4); + } else if ((insn & 0xffa00f10) == 0xfe000810) { + /* VFM[AS]L -- 1111 1110 0.0S .... .... 1000 .Q.1 .... */ + int is_s = extract32(insn, 20, 1); + int vm20 = extract32(insn, 0, 3); + int vm3 = extract32(insn, 3, 1); + int m = extract32(insn, 5, 1); + int index; + + if (!dc_isar_feature(aa32_fhm, s)) { + return 1; + } + if (q) { + rm = vm20; + index = m * 2 + vm3; + } else { + rm = vm20 * 2 + m; + index = vm3; + } + is_long = true; + data = (index << 2) | is_s; /* is_2 == 0 */ + fn_gvec_ptr = gen_helper_gvec_fmlal_idx_h; } else { return 1; } + VFP_DREG_D(rd, insn); + if (rd & q) { + return 1; + } + if (q || !is_long) { + VFP_DREG_N(rn, insn); + if (rn & q & !is_long) { + return 1; + } + off_rn = vfp_reg_offset(1, rn); + off_rm = vfp_reg_offset(1, rm); + } else { + rn = VFP_SREG_N(insn); + off_rn = vfp_reg_offset(0, rn); + off_rm = vfp_reg_offset(0, rm); + } if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, syn_simd_access_trap(1, 0xe, false), s->fp_excp_el); @@ -8509,15 +8558,11 @@ static int disas_neon_insn_2reg_scalar_ext(DisasContext *s, uint32_t insn) opr_sz = (1 + q) * 8; if (fn_gvec_ptr) { TCGv_ptr fpst = get_fpstatus_ptr(1); - tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), fpst, + tcg_gen_gvec_3_ptr(vfp_reg_offset(1, rd), off_rn, off_rm, fpst, opr_sz, opr_sz, data, fn_gvec_ptr); tcg_temp_free_ptr(fpst); } else { - tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), - vfp_reg_offset(1, rn), - vfp_reg_offset(1, rm), + tcg_gen_gvec_3_ool(vfp_reg_offset(1, rd), off_rn, off_rm, opr_sz, opr_sz, data, fn_gvec); } return 0; From patchwork Fri Feb 15 19:23:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Henderson X-Patchwork-Id: 158541 Delivered-To: patch@linaro.org Received: by 2002:a02:48:0:0:0:0:0 with SMTP id 69csp1065166jaa; Fri, 15 Feb 2019 11:28:48 -0800 (PST) X-Google-Smtp-Source: AHgI3IZaX6RyNxAWeL6GNlIncNWpWNXOUsACIwoviqEMkA55N+IeOxOhfAjfTveGz3kXlLQd1zEy X-Received: by 2002:a25:90a:: with SMTP id 10mr9430136ybj.48.1550258928638; Fri, 15 Feb 2019 11:28:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550258928; cv=none; d=google.com; s=arc-20160816; b=NczpIbbQf5IWQuNYuTPdDYo8OCvKqEEFSNLGcVuG0LSi9/TClsYNKvZ/EIYVQiF4fH 7NYXQ7gVn0/7oY4G09H+FCQAPw7vi7UAzu+icmRaX6bM88BYrxs+Zw54SWGXMgLEiYWi 7miebZ6IE0riPnPZ4vl4sBAfA9UcJdFEdgpMWo4MGUxX68lFXjmoI3J0Jg8Kp7DHr7/d nEPkifC7LlwqLKm7K6zI/nJS4uH37HXFvGdxae3DvAc3HEJVxBukJmmsdh+iu/lH58BF 3mckabDuAg35KECoqfymCpf2pTs8niUxzRm9RQ2AikBO2nl2BIH5VucOf4yqqS5jiwCc QXxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:subject:references:in-reply-to :message-id:date:to:from:dkim-signature; bh=tsK9dzCgm1k++raud5hkUWeOig3LDz798qJnPSIBFOQ=; b=1LiUdGwfm8EuxsrYVF6fJSyga2hFLDDJ9rK9jC+AWS1pZDpE/22udvJ+3MkGit0Mx6 OVzNE4rQbLjYTJ8tUY8cgnocMuE6I+d7t8VlGfJrbO5gdT1uzv5a/g2F+Rc9D0arIySA KNeeDth4vWA2z2lGkh8YHHUZbReqLtBY+6R1koXh9T1R49fMgjU6PxpYkt30sJR4K8Vp DQ/YaOLrA9whmzQv6hGXMok7skzwUURDECP46UNOgzHtzF1EsI4pGy4TnPTSejqHWwNp RepBB9T+vNMs1yTpqy+LjRsm6n86YkiWrf26EtiHYAYX1LHNNrXnpM2LIQQd6sHt/xLS bYLw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=mXbn3NIS; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org. [209.51.188.17]) by mx.google.com with ESMTPS id a185si3663325ybb.46.2019.02.15.11.28.48 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 15 Feb 2019 11:28:48 -0800 (PST) Received-SPF: pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; Authentication-Results: mx.google.com; dkim=fail header.i=@linaro.org header.s=google header.b=mXbn3NIS; spf=pass (google.com: domain of qemu-devel-bounces+patch=linaro.org@nongnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom="qemu-devel-bounces+patch=linaro.org@nongnu.org"; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from localhost ([127.0.0.1]:45102 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gujAG-0000Zl-57 for patch@linaro.org; Fri, 15 Feb 2019 14:28:48 -0500 Received: from eggs.gnu.org ([209.51.188.92]:33385) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1guj4y-0005Tt-LR for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1guj4w-0003VA-3G for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:18 -0500 Received: from mail-pl1-x644.google.com ([2607:f8b0:4864:20::644]:41893) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1guj4v-0003Sh-GW for qemu-devel@nongnu.org; Fri, 15 Feb 2019 14:23:17 -0500 Received: by mail-pl1-x644.google.com with SMTP id k15so5404441pls.8 for ; Fri, 15 Feb 2019 11:23:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tsK9dzCgm1k++raud5hkUWeOig3LDz798qJnPSIBFOQ=; b=mXbn3NISbqXKs3F38ylBAPtDsTfnkjFJ2Co8ukpv5GfEF48Z3kkbK+FANO9ALckYgJ Mykuu9a607EiFseZ9rjS/zshJAiiwPbekEC6GL5ub1vhlNyyG7U6afvjGCtPD7B4N/g1 7YJtBaendv1mZwugCOnBHDvrlxHv1QhiKTjy+v3vcD2vh5uk8JgGQKgQoRr4/1iURpk3 9DTfnuennuBZzuF/47jh55TfpGUiJqhjMje0Ho42AQ6zRg/l1UnHj/wRZhz5f0cnyLRk 8AdkVYf4yn9oDUytriqUkvenadGFYkUHuBWXLCbp0tRQpEoo7Cn6draT2FX+k8F/fKok nINg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tsK9dzCgm1k++raud5hkUWeOig3LDz798qJnPSIBFOQ=; b=LV4oefb4sZ2CNKgCBLIkRnUDBa7Qrlg86YwmKpTwIqe4YeklprQTCo/P+NqwNRm65j NXwjDO6o9o5qN9vYFSoiZ5TEpPzVtBWY8byPSjBDe6tYZ8LtHhmWUjag6LTRkHCB4IJu VRTBiVo9AAz7g5k82ZpKoxqwwRs7yzP3E3RwyOfZMaypyRKecM+UZAU4+QIOZF6A4Hiy DTgceNtfC9CqTQZ0TrmBDwYUNKrRDAUsdlUaBAQzmaChfhgrPZPRgJr8uFOG4om3XSoT BA2xN1Smk6Cwr3GGu48Wx1MZLWDWeHoYHsDaowhmRLkW8Vc4B2URpQZMsaT9sCJRn2Am 5CZQ== X-Gm-Message-State: AHQUAuaBuWAFgz1Lkza6hO/wsSEOatCQI3wjWJhmiD29esmVzMJ1EEZY MtvL8YDji575KP2gGus/ibcWJMO7m2E= X-Received: by 2002:a17:902:930b:: with SMTP id bc11mr11954740plb.101.1550258596085; Fri, 15 Feb 2019 11:23:16 -0800 (PST) Received: from cloudburst.twiddle.net (97-113-188-82.tukw.qwest.net. [97.113.188.82]) by smtp.gmail.com with ESMTPSA id o85sm15161596pfi.105.2019.02.15.11.23.14 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Fri, 15 Feb 2019 11:23:15 -0800 (PST) From: Richard Henderson To: qemu-devel@nongnu.org Date: Fri, 15 Feb 2019 11:23:02 -0800 Message-Id: <20190215192302.27855-9-richard.henderson@linaro.org> X-Mailer: git-send-email 2.17.2 In-Reply-To: <20190215192302.27855-1-richard.henderson@linaro.org> References: <20190215192302.27855-1-richard.henderson@linaro.org> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::644 Subject: [Qemu-devel] [PATCH v4 8/8] target/arm: Enable ARMv8.2-FHM for -cpu max X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org Errors-To: qemu-devel-bounces+patch=linaro.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Richard Henderson --- target/arm/cpu.c | 1 + target/arm/cpu64.c | 2 ++ 2 files changed, 3 insertions(+) -- 2.17.2 Reviewed-by: Peter Maydell diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 8ea6569088..b9fa548718 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2003,6 +2003,7 @@ static void arm_max_initfn(Object *obj) t = cpu->isar.id_isar6; t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1); t = FIELD_DP32(t, ID_ISAR6, DP, 1); + t = FIELD_DP32(t, ID_ISAR6, FHM, 1); cpu->isar.id_isar6 = t; t = cpu->id_mmfr4; diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 69e4134f79..1b0c427277 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -308,6 +308,7 @@ static void aarch64_max_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR0, SM3, 1); t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1); t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1); + t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1); cpu->isar.id_aa64isar0 = t; t = cpu->isar.id_aa64isar1; @@ -347,6 +348,7 @@ static void aarch64_max_initfn(Object *obj) u = cpu->isar.id_isar6; u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1); u = FIELD_DP32(u, ID_ISAR6, DP, 1); + u = FIELD_DP32(u, ID_ISAR6, FHM, 1); cpu->isar.id_isar6 = u; /*