This patch recognizes Zicond patterns when the select pattern with condition eq or neq to 0 (using eq as an example), namely:
1 rd = (rs2 == 0) ? non-imm : 0 2 rd = (rs2 == 0) ? non-imm : non-imm 3 rd = (rs2 == 0) ? reg : non-imm 4 rd = (rs2 == 0) ? reg : reg gcc/ChangeLog: * config/riscv/riscv.cc (riscv_expand_conditional_move): Recognize Zicond patterns * config/riscv/riscv.md: Recognize Zicond patterns through mov<mode>cc gcc/testsuite/ChangeLog: * gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c: New test. * gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c: New test. * gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c: New test. * gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c: New test. --- gcc/config/riscv/riscv.cc | 144 ++++++++++++++++++ gcc/config/riscv/riscv.md | 4 +- .../zicond-primitiveSemantics_return_0_imm.c | 65 ++++++++ ...zicond-primitiveSemantics_return_imm_imm.c | 73 +++++++++ ...zicond-primitiveSemantics_return_imm_reg.c | 65 ++++++++ ...zicond-primitiveSemantics_return_reg_reg.c | 65 ++++++++ 6 files changed, 414 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c create mode 100644 gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 941ea25e1f2..6ac39f63dd7 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -3516,6 +3516,150 @@ riscv_expand_conditional_move (rtx dest, rtx op, rtx cons, rtx alt) cond, cons, alt))); return true; } + else if (TARGET_ZICOND + && (code == EQ || code == NE) + && GET_MODE_CLASS (mode) == MODE_INT) + { + need_eq_ne_p = true; + /* 0 + imm */ + if (GET_CODE (cons) == CONST_INT && cons == const0_rtx + && GET_CODE (alt) == CONST_INT && alt != const0_rtx) + { + riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + alt = force_reg (mode, alt); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond, + cons, alt))); + return true; + } + /* imm + imm */ + else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx + && GET_CODE (alt) == CONST_INT && alt != const0_rtx) + { + riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + rtx reg = gen_reg_rtx (mode); + rtx temp = GEN_INT (INTVAL (alt) - INTVAL (cons)); + emit_insn (gen_rtx_SET (reg, temp)); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond, + CONST0_RTX (mode), + reg))); + riscv_emit_binary (PLUS, dest, dest, cons); + return true; + } + /* imm + reg */ + else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx + && GET_CODE (alt) == REG) + { + /* Optimize for register value of 0. */ + if (op0 == alt && op1 == const0_rtx) + { + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + cons = force_reg (mode, cons); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond, + cons, alt))); + return true; + } + /* Handle the special situation of: -2048 == INTVAL (alt) + to avoid failure due to an unrecognized insn. Let the costing + model determine if the conditional move sequence is better + than the branching sequence. */ + if (-2048 == INTVAL (cons)) + { + rtx reg = gen_reg_rtx (mode); + emit_insn (gen_rtx_SET (reg, cons)); + return riscv_expand_conditional_move (dest, op, reg, alt); + } + riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + rtx temp = GEN_INT (-1 * INTVAL (cons)); + riscv_emit_binary (PLUS, alt, alt, temp); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond, + CONST0_RTX (mode), + alt))); + riscv_emit_binary (PLUS, dest, dest, cons); + return true; + } + /* imm + 0 */ + else if (GET_CODE (cons) == CONST_INT && cons != const0_rtx + && GET_CODE (alt) == CONST_INT && alt == const0_rtx) + { + riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + cons = force_reg (mode, cons); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond, + cons, alt))); + return true; + } + /* reg + imm */ + else if (GET_CODE (cons) == REG + && GET_CODE (alt) == CONST_INT && alt != const0_rtx) + { + /* Optimize for register value of 0. */ + if (op0 == cons && op1 == const0_rtx) + { + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + alt = force_reg (mode, alt); + emit_insn (gen_rtx_SET (dest, gen_rtx_IF_THEN_ELSE (mode, cond, + cons, alt))); + return true; + } + if (-2048 == INTVAL (alt)) + { + rtx reg = gen_reg_rtx (mode); + emit_insn (gen_rtx_SET (reg, alt)); + return riscv_expand_conditional_move (dest, op, cons, reg); + } + riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p); + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + rtx temp = GEN_INT (-1 * INTVAL (alt)); + riscv_emit_binary (PLUS, cons, cons, temp); + emit_insn (gen_rtx_SET (dest, + gen_rtx_IF_THEN_ELSE (mode, cond, cons, + CONST0_RTX (mode)))); + riscv_emit_binary (PLUS, dest, dest, alt); + return true; + } + /* reg + reg */ + else if (GET_CODE (cons) == REG && GET_CODE (alt) == REG) + { + /* Optimize for op0 == cons && op1 == const0_rtx. */ + if (op0 == cons && op1 == const0_rtx) + { + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + emit_insn (gen_rtx_SET (dest, + gen_rtx_IF_THEN_ELSE (mode, cond, + CONST0_RTX (mode), + alt))); + return true; + } + /* Optimize for op0 == alt && op1 == const0_rtx. */ + if (op0 == alt && op1 == const0_rtx) + { + rtx cond = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + emit_insn (gen_rtx_SET (dest, + gen_rtx_IF_THEN_ELSE (mode, cond, cons, + CONST0_RTX (mode)))); + return true; + } + rtx reg1 = gen_reg_rtx (mode); + rtx reg2 = gen_reg_rtx (mode); + riscv_emit_int_compare (&code, &op0, &op1, need_eq_ne_p); + rtx cond1 = gen_rtx_fmt_ee (code, GET_MODE (op0), op0, op1); + rtx cond2 = gen_rtx_fmt_ee (code == NE ? EQ : NE, + GET_MODE (op0), op0, op1); + emit_insn (gen_rtx_SET (reg2, + gen_rtx_IF_THEN_ELSE (mode, cond2, + CONST0_RTX (mode), + cons))); + emit_insn (gen_rtx_SET (reg1, + gen_rtx_IF_THEN_ELSE (mode, cond1, + CONST0_RTX (mode), + alt))); + riscv_emit_binary (IOR, dest, reg1, reg2); + return true; + } + } return false; } diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 8d8fc93bb14..4b6875aa340 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -2484,9 +2484,9 @@ (define_expand "mov<mode>cc" [(set (match_operand:GPR 0 "register_operand") (if_then_else:GPR (match_operand 1 "comparison_operator") - (match_operand:GPR 2 "reg_or_0_operand") + (match_operand:GPR 2 "sfb_alu_operand") (match_operand:GPR 3 "sfb_alu_operand")))] - "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV" + "TARGET_SFB_ALU || TARGET_XTHEADCONDMOV || TARGET_ZICOND" { if (riscv_expand_conditional_move (operands[0], operands[1], operands[2], operands[3])) diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c new file mode 100644 index 00000000000..6e45b3f8ae5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_0_imm.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */ + +long primitiveSemantics_return_0_imm_00(long a, long b) { + return a == 0 ? 0 : 3; +} + +long primitiveSemantics_return_0_imm_01(long a, long b) { + return a != 0 ? 0 : 3; +} + +long primitiveSemantics_return_0_imm_02(long a, long b) { + return a == 0 ? 3 : 0; +} + +long primitiveSemantics_return_0_imm_03(long a, long b) { + return a != 0 ? 3 : 0; +} + +long primitiveSemantics_return_0_imm_04(long a, long b) { + if (a) + b = 0; + else + b = 3; + return b; +} + +long primitiveSemantics_return_0_imm_05(long a, long b) { + if (!a) + b = 0; + else + b = 3; + return b; +} + +int primitiveSemantics_return_0_imm_06(int a, int b) { return a == 0 ? 0 : 3; } + +int primitiveSemantics_return_0_imm_07(int a, int b) { return a != 0 ? 0 : 3; } + +int primitiveSemantics_return_0_imm_08(int a, int b) { return a == 0 ? 3 : 0; } + +int primitiveSemantics_return_0_imm_09(int a, int b) { return a != 0 ? 3 : 0; } + +int primitiveSemantics_return_0_imm_10(int a, int b) { + if (a) + b = 0; + else + b = 3; + return b; +} + +int primitiveSemantics_return_0_imm_11(int a, int b) { + if (!a) + b = 0; + else + b = 3; + return b; +} + +/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */ +/* { dg-final { scan-assembler-times "czero.nez" 6 } } */ +/* { dg-final { scan-assembler-not "beq" } } */ +/* { dg-final { scan-assembler-not "bne" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c new file mode 100644 index 00000000000..ebdca521373 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_imm.c @@ -0,0 +1,73 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */ + +long primitiveSemantics_return_imm_imm_00(long a, long b) { + return a == 0 ? 4 : 6; +} + +long primitiveSemantics_return_imm_imm_01(long a, long b) { + return a != 0 ? 4 : 6; +} + +long primitiveSemantics_return_imm_imm_02(long a, long b) { + return a == 0 ? 6 : 4; +} + +long primitiveSemantics_return_imm_imm_03(long a, long b) { + return a != 0 ? 6 : 4; +} + +long primitiveSemantics_return_imm_imm_04(long a, long b) { + if (a) + b = 4; + else + b = 6; + return b; +} + +long primitiveSemantics_return_imm_imm_05(long a, long b) { + if (!a) + b = 4; + else + b = 6; + return b; +} + +int primitiveSemantics_return_imm_imm_06(int a, int b) { + return a == 0 ? 4 : 6; +} + +int primitiveSemantics_return_imm_imm_07(int a, int b) { + return a != 0 ? 4 : 6; +} + +int primitiveSemantics_return_imm_imm_08(int a, int b) { + return a == 0 ? 6 : 4; +} + +int primitiveSemantics_return_imm_imm_09(int a, int b) { + return a != 0 ? 6 : 4; +} + +int primitiveSemantics_return_imm_imm_10(int a, int b) { + if (a) + b = 4; + else + b = 6; + return b; +} + +int primitiveSemantics_return_imm_imm_11(int a, int b) { + if (!a) + b = 4; + else + b = 6; + return b; +} + +/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */ +/* { dg-final { scan-assembler-times "czero.nez" 6 } } */ +/* { dg-final { scan-assembler-not "beq" } } */ +/* { dg-final { scan-assembler-not "bne" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c new file mode 100644 index 00000000000..12c351dbc16 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_imm_reg.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */ + +long primitiveSemantics_return_imm_reg_00(long a, long b) { + return a == 0 ? 1 : b; +} + +long primitiveSemantics_return_imm_reg_01(long a, long b) { + return a != 0 ? 1 : b; +} + +long primitiveSemantics_return_imm_reg_02(long a, long b) { + return a == 0 ? b : 1; +} + +long primitiveSemantics_return_imm_reg_03(long a, long b) { + return a != 0 ? b : 1; +} + +long primitiveSemantics_return_imm_reg_04(long a, long b) { + if (a) + b = 1; + return b; +} + +long primitiveSemantics_return_imm_reg_05(long a, long b) { + if (!a) + b = 1; + return b; +} + +int primitiveSemantics_return_imm_reg_06(int a, int b) { + return a == 0 ? 1 : b; +} + +int primitiveSemantics_return_imm_reg_07(int a, int b) { + return a != 0 ? 1 : b; +} + +int primitiveSemantics_return_imm_reg_08(int a, int b) { + return a == 0 ? b : 1; +} + +int primitiveSemantics_return_imm_reg_09(int a, int b) { + return a != 0 ? b : 1; +} + +int primitiveSemantics_return_imm_reg_10(int a, int b) { + if (a) + b = 1; + return b; +} + +int primitiveSemantics_return_imm_reg_11(int a, int b) { + if (!a) + b = 1; + return b; +} + +/* { dg-final { scan-assembler-times "czero.eqz" 6 } } */ +/* { dg-final { scan-assembler-times "czero.nez" 6 } } */ +/* { dg-final { scan-assembler-not "beq" } } */ +/* { dg-final { scan-assembler-not "bne" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c new file mode 100644 index 00000000000..4708afa645b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-primitiveSemantics_return_reg_reg.c @@ -0,0 +1,65 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zicond -mabi=lp64d" { target { rv64 } } } */ +/* { dg-options "-march=rv32gc_zicond -mabi=ilp32f" { target { rv32 } } } */ +/* { dg-skip-if "" { *-*-* } {"-O0" "-Os"} } */ + +long primitiveSemantics_return_reg_reg_00(long a, long b, long c) { + return a == 0 ? c : b; +} + +long primitiveSemantics_return_reg_reg_01(long a, long b, long c) { + return a != 0 ? c : b; +} + +long primitiveSemantics_return_reg_reg_02(long a, long b, long c) { + return a == 0 ? b : c; +} + +long primitiveSemantics_return_reg_reg_03(long a, long b, long c) { + return a != 0 ? b : c; +} + +long primitiveSemantics_return_reg_reg_04(long a, long b, long c) { + if (a) + b = c; + return b; +} + +long primitiveSemantics_return_reg_reg_05(long a, long b, long c) { + if (!a) + b = c; + return b; +} + +int primitiveSemantics_return_reg_reg_06(int a, int b, int c) { + return a == 0 ? c : b; +} + +int primitiveSemantics_return_reg_reg_07(int a, int b, int c) { + return a != 0 ? c : b; +} + +int primitiveSemantics_return_reg_reg_08(int a, int b, int c) { + return a == 0 ? b : c; +} + +int primitiveSemantics_return_reg_reg_09(int a, int b, int c) { + return a != 0 ? b : c; +} + +int primitiveSemantics_return_reg_reg_10(int a, int b, int c) { + if (a) + b = c; + return b; +} + +int primitiveSemantics_return_reg_reg_11(int a, int b, int c) { + if (!a) + b = c; + return b; +} + +/* { dg-final { scan-assembler-times "czero.eqz" 12 } } */ +/* { dg-final { scan-assembler-times "czero.nez" 12 } } */ +/* { dg-final { scan-assembler-not "beq" } } */ +/* { dg-final { scan-assembler-not "bne" } } */ -- 2.17.1