From patchwork Tue Apr 30 15:46:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Law X-Patchwork-Id: 1929695 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ventanamicro.com header.i=@ventanamicro.com header.a=rsa-sha256 header.s=google header.b=kO7DaGwr; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VTPhM0g5dz23jG for ; Wed, 1 May 2024 01:46:59 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0FFB83858429 for ; Tue, 30 Apr 2024 15:46:57 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-yw1-x112f.google.com (mail-yw1-x112f.google.com [IPv6:2607:f8b0:4864:20::112f]) by sourceware.org (Postfix) with ESMTPS id 95B1C3858D34 for ; Tue, 30 Apr 2024 15:46:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 95B1C3858D34 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=ventanamicro.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=ventanamicro.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 95B1C3858D34 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::112f ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714492000; cv=none; b=NVD5tE0fU4j1X+w+2lVIqOP79SE1YMVoKR7+RWnOCEe30jYhiaiGwXCNTsMPCXU/Lxy5X/cYQD6WvYSR5ekCdvmZTAW71ciygsI6F+2jqhmt5lU0d5W4qSdlzO0rncF2A/INLRwtIZDk1le8HwS8wWVHZCu95nZp9dk87+SsCPI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714492000; c=relaxed/simple; bh=FFieAQ3ULW2/hG6yADekmRBMcOZP2NzJN027AXlTuFQ=; h=DKIM-Signature:Message-ID:Date:MIME-Version:From:To:Subject; b=I5jixlGlhFVtGJOlwsz1IcvZS2I8RSprcGoWvnuNpEzwbbmzsXysn/u2GVT1ynJJ6SnsvfH5nOD3m1owVleV1lC2L3A0Ce4gq8+j1Vg2MrLF+bwGSM7s9yQdJTFI07Z4eLLL6XdJ1VdbkBhqyf3tUymTZvg416e0H8Ppg18ZFIA= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-yw1-x112f.google.com with SMTP id 00721157ae682-61d35d266e7so5333487b3.1 for ; Tue, 30 Apr 2024 08:46:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ventanamicro.com; s=google; t=1714491995; x=1715096795; darn=gcc.gnu.org; h=subject:cc:to:content-language:from:user-agent:mime-version:date :message-id:from:to:cc:subject:date:message-id:reply-to; bh=ImKIr7nyuBGlj6C/G2uwoWEcI0loS09emcG0eTKPbMI=; b=kO7DaGwrLfR8UJnSZ1ji0oEgPvYL5BMg46ezEL5Ptv8GVfZMtq2SZT5IJDC5P4OSPU P+uhVrmqyX7gKc9OUFmULBe64qLl4E4bC5w19Js8QxD8k40Ps/AZUFkya42gUlNz9dGI cf31bU3E7KCYGVmZfev1Jo3CdXe8F3i/xQ8+/JkzbxZHYJM7M5PAhM4MyMQM0gUrmctw WpMs2zzOtSMCPdEbopF61cq0GOmUlQbxMQewSnEYmfBKGf+TPlbVo9mTqoNJNgtuRxHt B04PLU6jzKLwLR/qlkeYrmlYbOzsunzbr8hV/Eem69rBhv5JMuUl6O6xzqvYUfY6Twhv 6J/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1714491995; x=1715096795; h=subject:cc:to:content-language:from:user-agent:mime-version:date :message-id:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=ImKIr7nyuBGlj6C/G2uwoWEcI0loS09emcG0eTKPbMI=; b=IeLeQ9KpFyHBhBJtoGoW0sFGKjezl6Fj4RCrnpXfqiCgdDya+Jy+0yui7VcYkRBxIG ssCvrIk+hNaTMuu1fjaiujubFr5+PeURsD1mO6IYe95GkXSyrBsK1jk+oeDeukbWsx61 VdPgQnryZtBPPMAK9zmflqKe7u4dsqhiHuf/ZQS5N2T1/BLQaR9aoQzxN3pPCEzOlnU+ cqc+RXrFjMQyLYWh0KXZ7sNBoOrcFIHrIjvI8hUpAxbH/HKbJGWF86hbsH+EGXu202YN m78xRhhRzIOuYyPx5dqNGEFAF7EvTxYwQ0nnagTPyFvxqSS2xRh8o68Gp8jw2cBSgYao VsHQ== X-Gm-Message-State: AOJu0Yx+A4jGVuBrn8JvgczleockZbVq0lF6Sti32JpdgtSch66ELMKE m8XHZsUnB3PiTJvjjZiASP3a5j0jFswt4BxuzAUt8u9o7a4jWIUVrsZanw4Ee3/MwTk90iZOHWh J X-Google-Smtp-Source: AGHT+IGFEy5rueT83D1xMTUdlAIwoZr6TGLChWU4zOmFFYJSAyN299buinWB+X4o74AdNwT+fQMOaQ== X-Received: by 2002:a05:690c:6311:b0:615:1ad2:1102 with SMTP id ho17-20020a05690c631100b006151ad21102mr14952890ywb.11.1714491995560; Tue, 30 Apr 2024 08:46:35 -0700 (PDT) Received: from [172.31.0.109] ([136.36.72.243]) by smtp.gmail.com with ESMTPSA id c4-20020a81e544000000b0061bed5b2c38sm226596ywm.0.2024.04.30.08.46.34 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 30 Apr 2024 08:46:35 -0700 (PDT) Message-ID: Date: Tue, 30 Apr 2024 09:46:34 -0600 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Beta From: Jeff Law Content-Language: en-US To: "gcc-patches@gcc.gnu.org" Cc: Jivan Hakobyan Subject: [committed] [RISC-V] Improve floor, ceil & related operations for RISC-V X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org This is almost exclusively Jivan's work. His original post: > https://www.mail-archive.com/gcc-patches@gcc.gnu.org/msg336483.html This patch is primarily meant to improve the code we generate for FP rounding such as ceil/floor. It also addresses some unnecessary sign extensions in the same areas. RISC-V's FP conversions have a bit of undesirable behavior that make them non-suitable as-is for ceil/floor and other related functions. These deficiencies are addressed in the Zfa extension, but there's no reason not to pick up a nice improvement when we can. Basically we can still use the basic FP conversions for floor/ceil and friends when we don't care about inexact exceptions by checking for the special cases first, then emitting the conversion when the special cases don't apply. That's still much faster than calling into glibc. The redundant sign extensions are eliminated using the same trick Jivan added last year, just in a few more places ;-) This eliminates roughly 10% of the dynamic instruction count for imagick. But more importantly it's about a 17% performance improvement for that workload within spec. This has been bootstrapped as well as regression tested in a cross environment. It's also successfully built & run specint/specfp correctly. Pushing to the trunk and the coordination branch momentarily. Jeff gcc/ * config/riscv/iterators.md (fix_ops, fix_uns): New iterators. (RINT, rint_pattern, rint_rm): Remove unused iterators. * config/riscv/riscv-protos.h (get_fp_rounding_coefficient): Prototype. * config/riscvriscv-v.cc (get_fp_rounding_coefficient): Externalize. external linkage. * config/riscv/riscv.md (UNSPEC_LROUND): Remove. (fix_trunc2): Replace with ... (_truncsi2): New expander & associated insn. (_truncsi2_ext): New insn. (_truncdi2): Likewise. (l2): Replace with ... (lrintsi2): New expander and associated insn. (lrintsi2_ext), lrintdi2): New insns. (2): Replace with.... (lsi2): New expander and associated insn. (lsi2_sext): New insn. (ldi2): Likewise. (2): New expander. gcc/testsuite/ * gcc.target/riscv/fix.c: New test. * gcc.target/riscv/round.c: New test. * gcc.target/riscv/round_32.c: New test. * gcc.target/riscv/round_64.c: New test. diff --git a/gcc/config/riscv/iterators.md b/gcc/config/riscv/iterators.md index a7694137685..75e119e407a 100644 --- a/gcc/config/riscv/iterators.md +++ b/gcc/config/riscv/iterators.md @@ -196,6 +196,13 @@ (define_code_iterator clz_ctz_pcnt [clz ctz popcount]) (define_code_iterator bitmanip_rotate [rotate rotatert]) +;; These code iterators allow the signed and unsigned fix operations to use +;; the same template. +(define_code_iterator fix_ops [fix unsigned_fix]) + +(define_code_attr fix_uns [(fix "fix") (unsigned_fix "fixuns")]) + + ;; ------------------------------------------------------------------- ;; Code Attributes ;; ------------------------------------------------------------------- @@ -312,11 +319,6 @@ (define_code_attr bitmanip_insn [(smin "min") ;; Int Iterators. ;; ------------------------------------------------------------------- -;; Iterator and attributes for floating-point rounding instructions. -(define_int_iterator RINT [UNSPEC_LRINT UNSPEC_LROUND]) -(define_int_attr rint_pattern [(UNSPEC_LRINT "rint") (UNSPEC_LROUND "round")]) -(define_int_attr rint_rm [(UNSPEC_LRINT "dyn") (UNSPEC_LROUND "rmm")]) - ;; Iterator and attributes for quiet comparisons. (define_int_iterator QUIET_COMPARISON [UNSPEC_FLT_QUIET UNSPEC_FLE_QUIET]) (define_int_attr quiet_pattern [(UNSPEC_FLT_QUIET "lt") (UNSPEC_FLE_QUIET "le")]) diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h index 5d46a29d8b7..e5aebf3fc3d 100644 --- a/gcc/config/riscv/riscv-protos.h +++ b/gcc/config/riscv/riscv-protos.h @@ -711,6 +711,7 @@ bool gather_scatter_valid_offset_p (machine_mode); HOST_WIDE_INT estimated_poly_value (poly_int64, unsigned int); bool whole_reg_to_reg_move_p (rtx *, machine_mode, int); bool splat_to_scalar_move_p (rtx *); +rtx get_fp_rounding_coefficient (machine_mode); } /* We classify builtin types into two classes: diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index 814c5febabe..c9e0feebca6 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -4494,7 +4494,7 @@ vls_mode_valid_p (machine_mode vls_mode) All double floating point will be unchanged for ceil if it is greater than and equal to 4503599627370496. */ -static rtx +rtx get_fp_rounding_coefficient (machine_mode inner_mode) { REAL_VALUE_TYPE real; diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 455715ab2f7..8f518fdbe5a 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -64,7 +64,6 @@ (define_c_enum "unspec" [ UNSPEC_ROUNDEVEN UNSPEC_NEARBYINT UNSPEC_LRINT - UNSPEC_LROUND UNSPEC_FMIN UNSPEC_FMAX UNSPEC_FMINM @@ -1919,21 +1918,48 @@ (define_insn "*movhf_softfloat_boxing" ;; ;; .................... -(define_insn "fix_trunc2" - [(set (match_operand:GPR 0 "register_operand" "=r") - (fix:GPR +(define_expand "_truncsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix_ops:SI (match_operand:ANYF 1 "register_operand" " f")))] "TARGET_HARD_FLOAT || TARGET_ZFINX" - "fcvt.. %0,%1,rtz" +{ + if (TARGET_64BIT) + { + rtx t = gen_reg_rtx (DImode); + emit_insn (gen__truncsi2_sext (t, operands[1])); + t = gen_lowpart (SImode, t); + SUBREG_PROMOTED_VAR_P (t) = 1; + SUBREG_PROMOTED_SET (t, SRP_SIGNED); + emit_move_insn (operands[0], t); + DONE; + } +}) + +(define_insn "*_truncsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix_ops:SI + (match_operand:ANYF 1 "register_operand" " f")))] + "TARGET_HARD_FLOAT || TARGET_ZFINX" + "fcvt.w. %0,%1,rtz" + [(set_attr "type" "fcvt_f2i") + (set_attr "mode" "")]) + +(define_insn "_truncsi2_sext" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (fix_ops:SI + (match_operand:ANYF 1 "register_operand" " f"))))] + "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvt.w. %0,%1,rtz" [(set_attr "type" "fcvt_f2i") (set_attr "mode" "")]) -(define_insn "fixuns_trunc2" - [(set (match_operand:GPR 0 "register_operand" "=r") - (unsigned_fix:GPR +(define_insn "_truncdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (fix_ops:DI (match_operand:ANYF 1 "register_operand" " f")))] - "TARGET_HARD_FLOAT || TARGET_ZFINX" - "fcvt.u. %0,%1,rtz" + "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvt.l. %0,%1,rtz" [(set_attr "type" "fcvt_f2i") (set_attr "mode" "")]) @@ -1955,17 +1981,170 @@ (define_insn "floatuns2" [(set_attr "type" "fcvt_i2f") (set_attr "mode" "")]) -(define_insn "l2" - [(set (match_operand:GPR 0 "register_operand" "=r") - (unspec:GPR +(define_expand "lrintsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:ANYF 1 "register_operand" " f")] - RINT))] + UNSPEC_LRINT))] "TARGET_HARD_FLOAT || TARGET_ZFINX" - "fcvt.. %0,%1," +{ + if (TARGET_64BIT) + { + rtx t = gen_reg_rtx (DImode); + emit_insn (gen_lrintsi2_sext (t, operands[1])); + t = gen_lowpart (SImode, t); + SUBREG_PROMOTED_VAR_P (t) = 1; + SUBREG_PROMOTED_SET (t, SRP_SIGNED); + emit_move_insn (operands[0], t); + DONE; + } +}) + +(define_insn "*lrintsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI + [(match_operand:ANYF 1 "register_operand" " f")] + UNSPEC_LRINT))] + "TARGET_HARD_FLOAT || TARGET_ZFINX" + "fcvt.w. %0,%1,dyn" [(set_attr "type" "fcvt_f2i") (set_attr "mode" "")]) -(define_insn "2" +(define_insn "lrintsi2_sext" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (unspec:SI + [(match_operand:ANYF 1 "register_operand" " f")] + UNSPEC_LRINT)))] + "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvt.w. %0,%1,dyn" + [(set_attr "type" "fcvt_f2i") + (set_attr "mode" "")]) + +(define_insn "lrintdi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI + [(match_operand:ANYF 1 "register_operand" " f")] + UNSPEC_LRINT))] + "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvt.l. %0,%1,dyn" + [(set_attr "type" "fcvt_f2i") + (set_attr "mode" "")]) + +(define_expand "lsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI + [(match_operand:ANYF 1 "register_operand" " f")] + ROUND))] + "TARGET_HARD_FLOAT || TARGET_ZFINX" +{ + if (TARGET_64BIT) + { + rtx t = gen_reg_rtx (DImode); + emit_insn (gen_lsi2_sext (t, operands[1])); + t = gen_lowpart (SImode, t); + SUBREG_PROMOTED_VAR_P (t) = 1; + SUBREG_PROMOTED_SET (t, SRP_SIGNED); + emit_move_insn (operands[0], t); + DONE; + } +}) + +(define_insn "*lsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI + [(match_operand:ANYF 1 "register_operand" " f")] + ROUND))] + "TARGET_HARD_FLOAT || TARGET_ZFINX" + "fcvt.w. %0,%1," + [(set_attr "type" "fcvt_f2i") + (set_attr "mode" "")]) + +(define_insn "lsi2_sext" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (unspec:SI + [(match_operand:ANYF 1 "register_operand" " f")] + ROUND)))] + "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvt.w. %0,%1," + [(set_attr "type" "fcvt_f2i") + (set_attr "mode" "")]) + +(define_insn "ldi2" + [(set (match_operand:DI 0 "register_operand" "=r") + (unspec:DI + [(match_operand:ANYF 1 "register_operand" " f")] + ROUND))] + "TARGET_64BIT && (TARGET_HARD_FLOAT || TARGET_ZFINX)" + "fcvt.l. %0,%1," + [(set_attr "type" "fcvt_f2i") + (set_attr "mode" "")]) + +(define_expand "2" + [(set (match_operand:ANYF 0 "register_operand" "=f") + (unspec:ANYF + [(match_operand:ANYF 1 "register_operand" " f")] + ROUND))] + "TARGET_HARD_FLOAT && (TARGET_ZFA + || flag_fp_int_builtin_inexact || !flag_trapping_math)" +{ + if (TARGET_ZFA) + emit_insn (gen__zfa2 (operands[0], + operands[1])); + else + { + rtx reg; + rtx label = gen_label_rtx (); + rtx end_label = gen_label_rtx (); + rtx abs_reg = gen_reg_rtx (mode); + rtx coeff_reg = gen_reg_rtx (mode); + rtx tmp_reg = gen_reg_rtx (mode); + + riscv_emit_move (tmp_reg, operands[1]); + riscv_emit_move (coeff_reg, + riscv_vector::get_fp_rounding_coefficient (mode)); + emit_insn (gen_abs2 (abs_reg, operands[1])); + + riscv_expand_conditional_branch (label, LT, abs_reg, coeff_reg); + + emit_jump_insn (gen_jump (end_label)); + emit_barrier (); + + emit_label (label); + switch (mode) + { + case SFmode: + reg = gen_reg_rtx (SImode); + emit_insn (gen_lsfsi2 (reg, operands[1])); + emit_insn (gen_floatsisf2 (abs_reg, reg)); + break; + case DFmode: + if (TARGET_64BIT) + { + reg = gen_reg_rtx (DImode); + emit_insn (gen_ldfdi2 (reg, operands[1])); + emit_insn (gen_floatdidf2 (abs_reg, reg)); + } + else + { + reg = gen_reg_rtx (SImode); + emit_insn (gen_ldfsi2 (reg, operands[1])); + emit_insn (gen_floatsidf2 (abs_reg, reg)); + } + break; + default: + gcc_unreachable (); + } + + emit_insn (gen_copysign3 (tmp_reg, abs_reg, operands[1])); + + emit_label (end_label); + riscv_emit_move (operands[0], tmp_reg); + } + + DONE; +}) + +(define_insn "_zfa2" [(set (match_operand:ANYF 0 "register_operand" "=f") (unspec:ANYF [(match_operand:ANYF 1 "register_operand" " f")] diff --git a/gcc/testsuite/gcc.target/riscv/fix.c b/gcc/testsuite/gcc.target/riscv/fix.c new file mode 100644 index 00000000000..265a7da1fc5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fix.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64d" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +int +foo (double n) +{ + return n; +} + +int +foo_1 (float n) +{ + return n; +} + +unsigned int +foo_2 (double n) +{ + return n; +} + +unsigned int +foo_3 (float n) +{ + return n; +} + +/* { dg-final { scan-assembler-times {\mfcvt.w.d} 1 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.w.s} 1 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.wu.d} 1 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.wu.s} 1 } } */ +/* { dg-final { scan-assembler-not "\\ssext.w\\s" } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/round.c b/gcc/testsuite/gcc.target/riscv/round.c new file mode 100644 index 00000000000..decfc82a390 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/round.c @@ -0,0 +1,144 @@ +#include + +extern void abort (void); +extern void exit (int); + +#define NEQ(a, b) (fabs((a) - (b)) > 0.000001) + +#define DECL_FUNC(TYPE1, TYPE2, ROUND) \ + __attribute__ ((noinline, noclone)) TYPE2 \ + convert_##TYPE1##_to_##TYPE2##_##ROUND (TYPE1 N) \ + { \ + return ROUND (N); \ + } + +#define DECL_ALL_ROUNDS_FOR(ROUND_FUNC) \ + DECL_FUNC(float, float, ROUND_FUNC) \ + DECL_FUNC(double, double, ROUND_FUNC) \ + DECL_FUNC(double, int, ROUND_FUNC) \ + DECL_FUNC(double, long, ROUND_FUNC) \ + DECL_FUNC(float, int, ROUND_FUNC) \ + DECL_FUNC(float, long, ROUND_FUNC) + + +DECL_ALL_ROUNDS_FOR(round) +DECL_ALL_ROUNDS_FOR(ceil) +DECL_ALL_ROUNDS_FOR(floor) +DECL_ALL_ROUNDS_FOR(trunc) +DECL_ALL_ROUNDS_FOR(nearbyint) + +#define TEST_ROUND(TYPE1, TYPE2, N, N_R, ROUND) \ + if (NEQ (convert_##TYPE1##_to_##TYPE2##_##ROUND (N), N_R)) \ + abort (); + + +int main () { + + /* Round */ + TEST_ROUND(double, double, -4.8, -5.0, round); + TEST_ROUND(double, double, -4.2, -4.0, round); + TEST_ROUND(double, double, 4.8, 5.0, round); + TEST_ROUND(double, double, 4.2, 4.0, round); + + TEST_ROUND(double, int, -4.8, -5, round); + TEST_ROUND(double, int, -4.2, -4, round); + TEST_ROUND(double, int, 4.8, 5, round); + TEST_ROUND(double, int, 4.2, 4, round); + + TEST_ROUND(double, long, -4.8, -5, round); + TEST_ROUND(double, long, -4.2, -4, round); + TEST_ROUND(double, long, 4.8, 5, round); + TEST_ROUND(double, long, 4.2, 4, round); + + TEST_ROUND(float, long, -4.8, -5, round); + TEST_ROUND(float, long, -4.2, -4, round); + TEST_ROUND(float, long, 4.8, 5, round); + TEST_ROUND(float, long, 4.2, 4, round); + + /* Ceil */ + TEST_ROUND(double, double, -4.8, -4.0, ceil); + TEST_ROUND(double, double, -4.2, -4.0, ceil); + TEST_ROUND(double, double, 4.8, 5.0, ceil); + TEST_ROUND(double, double, 4.2, 5.0, ceil); + + TEST_ROUND(double, int, -4.8, -4, ceil); + TEST_ROUND(double, int, -4.2, -4, ceil); + TEST_ROUND(double, int, 4.8, 5, ceil); + TEST_ROUND(double, int, 4.2, 5, ceil); + + TEST_ROUND(double, long, -4.8, -4, ceil); + TEST_ROUND(double, long, -4.2, -4, ceil); + TEST_ROUND(double, long, 4.8, 5, ceil); + TEST_ROUND(double, long, 4.2, 5, ceil); + + TEST_ROUND(float, long, -4.8, -4, ceil); + TEST_ROUND(float, long, -4.2, -4, ceil); + TEST_ROUND(float, long, 4.8, 5, ceil); + TEST_ROUND(float, long, 4.2, 5, ceil); + + /* Floor */ + TEST_ROUND(double, double, -4.8, -5.0, floor); + TEST_ROUND(double, double, -4.2, -5.0, floor); + TEST_ROUND(double, double, 4.8, 4.0, floor); + TEST_ROUND(double, double, 4.2, 4.0, floor); + + TEST_ROUND(double, int, -4.8, -5, floor); + TEST_ROUND(double, int, -4.2, -5, floor); + TEST_ROUND(double, int, 4.8, 4, floor); + TEST_ROUND(double, int, 4.2, 4, floor); + + TEST_ROUND(double, long, -4.8, -5, floor); + TEST_ROUND(double, long, -4.2, -5, floor); + TEST_ROUND(double, long, 4.8, 4, floor); + TEST_ROUND(double, long, 4.2, 4, floor); + + TEST_ROUND(float, long, -4.8, -5, floor); + TEST_ROUND(float, long, -4.2, -5, floor); + TEST_ROUND(float, long, 4.8, 4, floor); + TEST_ROUND(float, long, 4.2, 4, floor); + + /* Trunc */ + TEST_ROUND(double, double, -4.8, -4.0, trunc); + TEST_ROUND(double, double, -4.2, -4.0, trunc); + TEST_ROUND(double, double, 4.8, 4.0, trunc); + TEST_ROUND(double, double, 4.2, 4.0, trunc); + + TEST_ROUND(double, int, -4.8, -4, trunc); + TEST_ROUND(double, int, -4.2, -4, trunc); + TEST_ROUND(double, int, 4.8, 4, trunc); + TEST_ROUND(double, int, 4.2, 4, trunc); + + TEST_ROUND(double, long, -4.8, -4, trunc); + TEST_ROUND(double, long, -4.2, -4, trunc); + TEST_ROUND(double, long, 4.8, 4, trunc); + TEST_ROUND(double, long, 4.2, 4, trunc); + + TEST_ROUND(float, long, -4.8, -4, trunc); + TEST_ROUND(float, long, -4.2, -4, trunc); + TEST_ROUND(float, long, 4.8, 4, trunc); + TEST_ROUND(float, long, 4.2, 4, trunc); + + /* Nearbyint */ + TEST_ROUND(double, double, -4.8, -5.0, nearbyint); + TEST_ROUND(double, double, -4.2, -4.0, nearbyint); + TEST_ROUND(double, double, 4.8, 5.0, nearbyint); + TEST_ROUND(double, double, 4.2, 4.0, nearbyint); + + TEST_ROUND(double, int, -4.8, -5, nearbyint); + TEST_ROUND(double, int, -4.2, -4, nearbyint); + TEST_ROUND(double, int, 4.8, 5, nearbyint); + TEST_ROUND(double, int, 4.2, 4, nearbyint); + + TEST_ROUND(double, long, -4.8, -5, nearbyint); + TEST_ROUND(double, long, -4.2, -4, nearbyint); + TEST_ROUND(double, long, 4.8, 5, nearbyint); + TEST_ROUND(double, long, 4.2, 4, nearbyint); + + TEST_ROUND(float, long, -4.8, -5, nearbyint); + TEST_ROUND(float, long, -4.2, -4, nearbyint); + TEST_ROUND(float, long, 4.8, 5, nearbyint); + TEST_ROUND(float, long, 4.2, 4, nearbyint); + + exit(0); +} + diff --git a/gcc/testsuite/gcc.target/riscv/round_32.c b/gcc/testsuite/gcc.target/riscv/round_32.c new file mode 100644 index 00000000000..f9fea70ad55 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/round_32.c @@ -0,0 +1,22 @@ +/* { dg-do compile { target { riscv32*-*-* } } } */ +/* { dg-options "-march=rv32gc -mabi=ilp32d -fno-math-errno -funsafe-math-optimizations -fno-inline" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ + +#include "round.c" + +/* { dg-final { scan-assembler-times {\mfcvt.w.s} 15 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.s.w} 5 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.d.w} 65 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.w.d} 15 } } */ +/* { dg-final { scan-assembler-times {,rup} 6 } } */ +/* { dg-final { scan-assembler-times {,rmm} 6 } } */ +/* { dg-final { scan-assembler-times {,rdn} 6 } } */ +/* { dg-final { scan-assembler-times {,rtz} 6 } } */ +/* { dg-final { scan-assembler-not {\mfcvt.l.d} } } */ +/* { dg-final { scan-assembler-not {\mfcvt.d.l} } } */ +/* { dg-final { scan-assembler-not "\\sceil\\s" } } */ +/* { dg-final { scan-assembler-not "\\sfloor\\s" } } */ +/* { dg-final { scan-assembler-not "\\sround\\s" } } */ +/* { dg-final { scan-assembler-not "\\snearbyint\\s" } } */ +/* { dg-final { scan-assembler-not "\\srint\\s" } } */ +/* { dg-final { scan-assembler-not "\\stail\\s" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/round_64.c b/gcc/testsuite/gcc.target/riscv/round_64.c new file mode 100644 index 00000000000..e79690979a5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/round_64.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-march=rv64gc -mabi=lp64d -fno-math-errno -funsafe-math-optimizations -fno-inline" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ + +#include "round.c" + +/* { dg-final { scan-assembler-times {\mfcvt.w.s} 10 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.s.w} 5 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.l.d} 10 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.d.l} 45 } } */ +/* { dg-final { scan-assembler-times {\mfcvt.w.d} 5 } } */ +/* { dg-final { scan-assembler-times {,rup} 6 } } */ +/* { dg-final { scan-assembler-times {,rmm} 6 } } */ +/* { dg-final { scan-assembler-times {,rdn} 6 } } */ +/* { dg-final { scan-assembler-times {,rtz} 6 } } */ +/* { dg-final { scan-assembler-not "\\sceil\\s" } } */ +/* { dg-final { scan-assembler-not "\\sfloor\\s" } } */ +/* { dg-final { scan-assembler-not "\\sround\\s" } } */ +/* { dg-final { scan-assembler-not "\\snearbyint\\s" } } */ +/* { dg-final { scan-assembler-not "\\srint\\s" } } */ +/* { dg-final { scan-assembler-not "\\stail\\s" } } */ +/* { dg-final { scan-assembler-not "\\ssext.w\\s" } } */ +