Indentation are updated accordingly and no regress found. gcc/ChangeLog:
*config/riscv/riscv-cores.def(RISCV_CORE): Updated the supported march. *config/riscv/riscv-ext-mips.def(DEFINE_RISCV_EXT): New file added for mips conditional mov extension. *config/riscv/riscv-ext.def: Likewise. *config/riscv/t-riscv: Generates riscv-ext.opt *config/riscv/riscv-ext.opt: Generated file. *config/riscv/riscv.cc(riscv_expand_conditional_move): Updated for mips cmov and outlined some code that handle arch cond move. *config/riscv/riscv.md(mov<mode>cc): updated expand for MIPS CCMOV. *config/riscv/mips-insn.md: New file for mips-p8700 ccmov insn. *gcc/doc/riscv-ext.texi: Updated for mips cmov. gcc/testsuite/ChangeLog: *testsuite/gcc.target/riscv/mipscondmov.c: Test file for mips.ccmov insn. --- gcc/config/riscv/mips-insn.md | 36 +++++++ gcc/config/riscv/riscv-cores.def | 3 +- gcc/config/riscv/riscv-ext-mips.def | 35 ++++++ gcc/config/riscv/riscv-ext.def | 1 + gcc/config/riscv/riscv-ext.opt | 4 + gcc/config/riscv/riscv.cc | 107 +++++++++++++------ gcc/config/riscv/riscv.md | 3 +- gcc/config/riscv/t-riscv | 3 +- gcc/doc/riscv-ext.texi | 4 + gcc/testsuite/gcc.target/riscv/mipscondmov.c | 30 ++++++ 10 files changed, 189 insertions(+), 37 deletions(-) create mode 100644 gcc/config/riscv/mips-insn.md create mode 100644 gcc/config/riscv/riscv-ext-mips.def create mode 100644 gcc/testsuite/gcc.target/riscv/mipscondmov.c diff --git a/gcc/config/riscv/mips-insn.md b/gcc/config/riscv/mips-insn.md new file mode 100644 index 00000000000..de53638d587 --- /dev/null +++ b/gcc/config/riscv/mips-insn.md @@ -0,0 +1,36 @@ +;; Machine description for MIPS custom instructions. +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; GCC 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 General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +(define_insn "*mov<GPR:mode><X:mode>cc_bitmanip" + [(set (match_operand:GPR 0 "register_operand" "=r") + (if_then_else:GPR + (any_eq:X (match_operand:X 1 "register_operand" "r") + (match_operand:X 2 "const_0_operand" "J")) + (match_operand:GPR 3 "reg_or_0_operand" "rJ") + (match_operand:GPR 4 "reg_or_0_operand" "rJ")))] + "TARGET_XMIPSCMOV" +{ + enum rtx_code code = <CODE>; + if (code == NE) + return "mips.ccmov\t%0,%1,%z3,%z4"; + else + return "mips.ccmov\t%0,%1,%z4,%z3"; +} +[(set_attr "type" "condmove") + (set_attr "mode" "<GPR:MODE>")]) diff --git a/gcc/config/riscv/riscv-cores.def b/gcc/config/riscv/riscv-cores.def index 2096c0095d4..98f347034fb 100644 --- a/gcc/config/riscv/riscv-cores.def +++ b/gcc/config/riscv/riscv-cores.def @@ -169,7 +169,6 @@ RISCV_CORE("xiangshan-kunminghu", "rv64imafdcbvh_sdtrig_sha_shcounterenw_" "zvfhmin_zvkt_zvl128b_zvl32b_zvl64b", "xiangshan-kunminghu") -RISCV_CORE("mips-p8700", "rv64imafd_zicsr_zmmul_" - "zaamo_zalrsc_zba_zbb", +RISCV_CORE("mips-p8700", "rv64imfd_zicsr_zifencei_zalrsc_zba_zbb", "mips-p8700") #undef RISCV_CORE diff --git a/gcc/config/riscv/riscv-ext-mips.def b/gcc/config/riscv/riscv-ext-mips.def new file mode 100644 index 00000000000..f24507139f6 --- /dev/null +++ b/gcc/config/riscv/riscv-ext-mips.def @@ -0,0 +1,35 @@ +/* MIPS extension definition file for RISC-V. + Copyright (C) 2025 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. + +Please run `make riscv-regen` in build folder to make sure updated anything. + +Format of DEFINE_RISCV_EXT, please refer to riscv-ext.def. */ + +DEFINE_RISCV_EXT( + /* NAME */ xmipscmov, + /* UPPERCASE_NAME */ XMIPSCMOV, + /* FULL_NAME */ "Mips conditional move extension", + /* DESC */ "", + /* URL */ , + /* DEP_EXTS */ ({}), + /* SUPPORTED_VERSIONS */ ({{1, 0}}), + /* FLAG_GROUP */ xmips, + /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED, + /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED, + /* EXTRA_EXTENSION_FLAGS */ 0) diff --git a/gcc/config/riscv/riscv-ext.def b/gcc/config/riscv/riscv-ext.def index 816acaa34f4..6fc6d388635 100644 --- a/gcc/config/riscv/riscv-ext.def +++ b/gcc/config/riscv/riscv-ext.def @@ -2082,3 +2082,4 @@ DEFINE_RISCV_EXT( #include "riscv-ext-sifive.def" #include "riscv-ext-thead.def" #include "riscv-ext-ventana.def" +#include "riscv-ext-mips.def" diff --git a/gcc/config/riscv/riscv-ext.opt b/gcc/config/riscv/riscv-ext.opt index 9f8c5451d49..26d6e683acd 100644 --- a/gcc/config/riscv/riscv-ext.opt +++ b/gcc/config/riscv/riscv-ext.opt @@ -46,6 +46,9 @@ int riscv_sv_subext TargetVariable int riscv_xcv_subext +TargetVariable +int riscv_xmips_subext + TargetVariable int riscv_xsf_subext @@ -445,3 +448,4 @@ Mask(XTHEADVECTOR) Var(riscv_xthead_subext) Mask(XVENTANACONDOPS) Var(riscv_xventana_subext) +Mask(XMIPSCMOV) Var(riscv_xmips_subext) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index bbc7547d385..fa94bb2948a 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -87,6 +87,10 @@ along with GCC; see the file COPYING3. If not see #include "riscv-vector-costs.h" #include "riscv-subset.h" +/* Target variants that support full conditional move. */ +#define TARGET_COND_MOV \ + (TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_XMIPSCMOV) + /* True if X is an UNSPEC wrapper around a SYMBOL_REF or LABEL_REF. */ #define UNSPEC_ADDRESS_P(X) \ (GET_CODE (X) == UNSPEC \ @@ -4150,7 +4154,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN return false; case IF_THEN_ELSE: - if ((TARGET_SFB_ALU || TARGET_XTHEADCONDMOV) + if (TARGET_COND_MOV && reg_or_0_operand (XEXP (x, 1), mode) && sfb_alu_operand (XEXP (x, 2), mode) && comparison_operator (XEXP (x, 0), VOIDmode)) @@ -5468,6 +5472,68 @@ riscv_expand_conditional_branch (rtx label, rtx_code code, rtx op0, rtx op1) emit_jump_insn (gen_condjump (condition, label)); } +/* canonicalization of the comparands. */ +void +canonicalize_comparands (rtx_code code, rtx *op0, rtx *op1) +{ + /* An integer comparison must be comparing WORD_MODE objects. + Extend the comparison arguments as necessary. */ + if ((INTEGRAL_MODE_P (GET_MODE (*op0)) && GET_MODE (*op0) != word_mode) + || (INTEGRAL_MODE_P (GET_MODE (*op1)) && GET_MODE (*op1) != word_mode)) + riscv_extend_comparands (code, op0, op1); + + /* We might have been handed back a SUBREG. Just to make things + easy, force it into a REG. */ + if (!REG_P (*op0) && !CONST_INT_P (*op0)) + *op0 = force_reg (word_mode, *op0); + if (!REG_P (*op1) && !CONST_INT_P (*op1)) + *op1 = force_reg (word_mode, *op1); +} + +/* Emit target specific conditional move like TARGET_XMIPSCMOV etc. */ +bool +riscv_target_conditional_move (rtx dest, rtx op0, rtx op1, rtx_code code, + rtx cons, rtx alt) +{ + machine_mode dst_mode = GET_MODE (dest); + rtx target; + + /* force the operands to the register. */ + cons = force_reg (dst_mode, cons); + alt = force_reg (dst_mode, alt); + + if (TARGET_XMIPSCMOV) + { + if (code == EQ || code == NE) + { + op0 = riscv_zero_if_equal (op0, op1); + op1 = const0_rtx; + } + else + { + target = gen_reg_rtx (GET_MODE (op0)); + riscv_emit_int_order_test (code, 0, target, op0, op1); + op0 = target; + op1 = const0_rtx; + code = NE; + } + riscv_emit_int_compare (&code, &op0, &op1); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (dst_mode, + cond, cons, alt))); + return true; + } + /* TARGET_SFB_ALU || TARGET_XTHEADCONDMOV. */ + else + { + riscv_emit_int_compare (&code, &op0, &op1, !TARGET_SFB_ALU); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (dst_mode, cond, + cons, alt))); + return true; + } +} + /* Emit a cond move: If OP holds, move CONS to DEST; else move ALT to DEST. Return 0 if expansion failed. */ @@ -5520,34 +5586,22 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt) /* If we need more special cases, add them here. */ } + if (((TARGET_ZICOND_LIKE || (arith_operand (cons, dst_mode) && arith_operand (alt, dst_mode))) && GET_MODE_CLASS (dst_mode) == MODE_INT && GET_MODE_CLASS (cond_mode) == MODE_INT) - || TARGET_SFB_ALU || TARGET_XTHEADCONDMOV) + || TARGET_COND_MOV) { machine_mode mode0 = GET_MODE (op0); - machine_mode mode1 = GET_MODE (op1); - /* An integer comparison must be comparing WORD_MODE objects. - Extend the comparison arguments as necessary. */ - if ((INTEGRAL_MODE_P (mode0) && mode0 != word_mode) - || (INTEGRAL_MODE_P (mode1) && mode1 != word_mode)) - riscv_extend_comparands (code, &op0, &op1); - - /* We might have been handed back a SUBREG. Just to make things - easy, force it into a REG. */ - if (!REG_P (op0) && !CONST_INT_P (op0)) - op0 = force_reg (word_mode, op0); - if (!REG_P (op1) && !CONST_INT_P (op1)) - op1 = force_reg (word_mode, op1); + canonicalize_comparands (code,&op0,&op1); /* In the fallback generic case use DST_MODE rather than WORD_MODE for the output of the SCC instruction, to match the mode of the NEG operation below. The output of SCC is 0 or 1 boolean, so it is valid for input in any scalar integer mode. */ - rtx tmp = gen_reg_rtx ((TARGET_ZICOND_LIKE - || TARGET_SFB_ALU || TARGET_XTHEADCONDMOV) + rtx tmp = gen_reg_rtx ((TARGET_ZICOND_LIKE || TARGET_COND_MOV) ? word_mode : dst_mode); bool invert = false; @@ -5584,25 +5638,12 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt) op0 = XEXP (op, 0); op1 = XEXP (op, 1); } - else if (!TARGET_ZICOND_LIKE && !TARGET_SFB_ALU && !TARGET_XTHEADCONDMOV) + else if (!TARGET_ZICOND_LIKE && !TARGET_COND_MOV) riscv_expand_int_scc (tmp, code, op0, op1, &invert); - if (TARGET_SFB_ALU || TARGET_XTHEADCONDMOV) - { - riscv_emit_int_compare (&code, &op0, &op1, !TARGET_SFB_ALU); - rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + if (TARGET_COND_MOV) + return riscv_target_conditional_move (dest, op0, op1, code, cons, alt); - /* The expander is a bit loose in its specification of the true - arm of the conditional move. That allows us to support more - cases for extensions which are more general than SFB. But - does mean we need to force CONS into a register at this point. */ - cons = force_reg (dst_mode, cons); - /* With XTheadCondMov we need to force ALT into a register too. */ - alt = force_reg (dst_mode, alt); - emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (dst_mode, cond, - cons, alt))); - return true; - } else if (!TARGET_ZICOND_LIKE) { if (invert) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 893c925b6b9..8500cac98d9 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -3298,7 +3298,7 @@ (match_operand:GPR 2 "movcc_operand") (match_operand:GPR 3 "movcc_operand")))] "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND_LIKE - || TARGET_MOVCC" + || TARGET_MOVCC || TARGET_XMIPSCMOV" { if (riscv_expand_conditional_move (operands[0], operands[1], operands[2], operands[3])) @@ -4886,3 +4886,4 @@ (include "sifive-p600.md") (include "generic-vector-ooo.md") (include "generic-ooo.md") +(include "mips-insn.md") diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv index 32092d85687..7aac56ac86c 100644 --- a/gcc/config/riscv/t-riscv +++ b/gcc/config/riscv/t-riscv @@ -194,7 +194,8 @@ RISCV_EXT_DEFS = \ $(srcdir)/config/riscv/riscv-ext.def \ $(srcdir)/config/riscv/riscv-ext-sifive.def \ $(srcdir)/config/riscv/riscv-ext-thead.def \ - $(srcdir)/config/riscv/riscv-ext-ventana.def + $(srcdir)/config/riscv/riscv-ext-ventana.def \ + $(srcdir)/config/riscv/riscv-ext-mips.def $(srcdir)/config/riscv/riscv-ext.opt: $(RISCV_EXT_DEFS) diff --git a/gcc/doc/riscv-ext.texi b/gcc/doc/riscv-ext.texi index c3ed1bfb593..572b70e20fa 100644 --- a/gcc/doc/riscv-ext.texi +++ b/gcc/doc/riscv-ext.texi @@ -714,4 +714,8 @@ @tab 1.0 @tab Ventana integer conditional operations extension +@item xmipscmov +@tab 1.0 +@tab Mips conditional move extension + @end multitable diff --git a/gcc/testsuite/gcc.target/riscv/mipscondmov.c b/gcc/testsuite/gcc.target/riscv/mipscondmov.c new file mode 100644 index 00000000000..144a6b718ef --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/mipscondmov.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64imafd_xmipscmov -mabi=lp64d" { target { rv64 } } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ + +#define MYTEST(name, mytype) \ +mytype test1_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a == b) ? c : d; } \ +mytype test2_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a != b) ? c : d; } \ +mytype test3_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a > b) ? c : d; } \ +mytype test4_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a >= b) ? c : d; } \ +mytype test5_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a < b) ? c : d; } \ +mytype test6_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a <= b) ? c : d; } \ +mytype test7_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a == 1) ? c : d; } \ +mytype test8_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a != 1) ? c : d; } \ +mytype test9_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a > 1) ? c : d; } \ +mytype test10_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a >= 1) ? c : d; } \ +mytype test11_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a < 1) ? c : d; } \ +mytype test12_ ## name (mytype a, mytype b, mytype c, mytype d) { return (a <= 1) ? c : d; } + +MYTEST(1, long long); +MYTEST(2, unsigned long long); +MYTEST(3, long); +MYTEST(4, unsigned long); +MYTEST(5, int); +MYTEST(6, unsigned int); +MYTEST(7, short); +MYTEST(8, unsigned short); +MYTEST(9, signed char); +MYTEST(10, unsigned char); + +/* { dg-final { scan-assembler-times "mips.ccmov" 120 } } */ base-commit: 2609a7a5971aa8a2ef1bafbf5581dcabd68a466e -- 2.43.0