[PATCH v2 4/4] RISC-V: define_insn_and_split for multiply-add and bit-extract fusion
Luis Silva <[email protected]> Wed, 5 Aug 2026 11:02:12 +0100
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <LO6P265MB6224F724A261C7B5BD9BC484B4D32@LO6P265MB6224.GBRP265.PROD.OUTLOOK.COM> |
From: Luis Silva <[email protected]> Introduce RTL patterns for multiply-add fusion. On RV32 the expanders emit madd_fused (mul+add). On RV64 they emit madd_fused_extended (mulw+addw). Also cheapen zero_extract / sign_extract in riscv_rtx_costs when RISCV_FUSE_BFEXT_SRLI / RISCV_FUSE_BFEXT_SRAI is enabled. gcc/ChangeLog: * config/riscv/riscv.cc (riscv_rtx_costs): Cheapen zero_extract / sign_extract when BFEXT_SRLI / BFEXT_SRAI is enabled. * config/riscv/riscv.md (maddhisi4): Emit madd_fused / madd_fused_extended when RISCV_FUSE_MULT_ADD and not TARGET_XTHEADMAC. (umaddhisi4): New expand. On TARGET_64BIT, zero-extend HI operands to DI and pass SI lowparts to madd_fused_extended. (madd_fused): New insn_and_split. (madd_fused_extended): New insn_and_split. gcc/testsuite/ChangeLog: * gcc.target/riscv/fusion-bfext-2.c: New test. * gcc.target/riscv/fusion-limm-condbr.c: New test. * gcc.target/riscv/fusion-madd.c: New test. Co-authored-by: Artemiy Volkov <[email protected]> Co-authored-by: Michiel Derhaeg <[email protected]> Signed-off-by: Luis Silva <[email protected]> --- gcc/config/riscv/riscv.cc | 15 ++- gcc/config/riscv/riscv.md | 122 +++++++++++++++++- .../gcc.target/riscv/fusion-bfext-2.c | 14 ++ .../gcc.target/riscv/fusion-limm-condbr.c | 12 ++ gcc/testsuite/gcc.target/riscv/fusion-madd.c | 13 ++ 5 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c create mode 100644 gcc/testsuite/gcc.target/riscv/fusion-madd.c diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index dd80da2d55a..4a23c734bdf 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -4712,11 +4712,22 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); return true; } + if (riscv_fusion_enabled_p (RISCV_FUSE_BFEXT_SRLI) + && outer_code == SET + && CONST_INT_P (XEXP (x, 1)) + && CONST_INT_P (XEXP (x, 2))) + { + *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); + return true; + } gcc_fallthrough (); case SIGN_EXTRACT: - if (TARGET_XTHEADBB && outer_code == SET + if (outer_code == SET && CONST_INT_P (XEXP (x, 1)) - && CONST_INT_P (XEXP (x, 2))) + && CONST_INT_P (XEXP (x, 2)) + && ((GET_CODE (x) == SIGN_EXTRACT + && riscv_fusion_enabled_p (RISCV_FUSE_BFEXT_SRAI)) + || TARGET_XTHEADBB)) { *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); return true; diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 6f66f983d87..71d2ce09899 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -4792,8 +4792,69 @@ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand")) (sign_extend:SI (match_operand:HI 2 "register_operand"))) (match_operand:SI 3 "register_operand")))] - "TARGET_XTHEADMAC" -) + "TARGET_XTHEADMAC || (riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && (TARGET_ZMMUL || TARGET_MUL))" +{ + if (riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && !TARGET_XTHEADMAC) + { + rtx tmp0 = gen_reg_rtx (SImode), tmp1 = gen_reg_rtx (SImode); + emit_insn (gen_extendhisi2 (tmp0, operands[1])); + emit_insn (gen_extendhisi2 (tmp1, operands[2])); + + if (TARGET_64BIT) + { + rtx op0 = gen_reg_rtx (DImode); + emit_insn (gen_madd_fused_extended (op0, tmp0, tmp1, operands[3])); + op0 = gen_lowpart (SImode, op0); + SUBREG_PROMOTED_VAR_P (op0) = 1; + SUBREG_PROMOTED_SET (op0, SRP_SIGNED); + emit_move_insn (operands[0], op0); + } + else + { + emit_insn (gen_madd_fused (operands[0], tmp0, tmp1, operands[3])); + } + + DONE; + } +}) + +(define_expand "umaddhisi4" + [(set (match_operand:SI 0 "register_operand") + (plus:SI + (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand")) + (zero_extend:SI (match_operand:HI 2 "register_operand"))) + (match_operand:SI 3 "register_operand")))] + "riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && (TARGET_ZMMUL || TARGET_MUL)" +{ + if (TARGET_64BIT) + { + rtx tmp0 = gen_reg_rtx (DImode), tmp1 = gen_reg_rtx (DImode); + emit_insn (gen_zero_extendhidi2 (tmp0, operands[1])); + emit_insn (gen_zero_extendhidi2 (tmp1, operands[2])); + + rtx op0 = gen_reg_rtx (DImode); + emit_insn (gen_madd_fused_extended (op0, + gen_lowpart (SImode, tmp0), + gen_lowpart (SImode, tmp1), + operands[3])); + op0 = gen_lowpart (SImode, op0); + SUBREG_PROMOTED_VAR_P (op0) = 1; + SUBREG_PROMOTED_SET (op0, SRP_SIGNED); + emit_move_insn (operands[0], op0); + } + else + { + rtx tmp0 = gen_reg_rtx (SImode), tmp1 = gen_reg_rtx (SImode); + emit_insn (gen_zero_extendhisi2 (tmp0, operands[1])); + emit_insn (gen_zero_extendhisi2 (tmp1, operands[2])); + emit_insn (gen_madd_fused (operands[0], tmp0, tmp1, operands[3])); + } + + DONE; +}) (define_expand "msubhisi4" [(set (match_operand:SI 0 "register_operand") @@ -4804,6 +4865,63 @@ "TARGET_XTHEADMAC" ) +(define_insn_and_split "madd_fused" + [(set (match_operand:SI 0 "register_operand" "=&r") + (plus:SI + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "register_operand" "r")))] + "riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && !TARGET_XTHEADMAC + && !TARGET_64BIT && (TARGET_ZMMUL || TARGET_MUL)" + "#" + "&& 1" + [(const_int 0)] + "{ + rtx addend = operands[3]; + if (can_create_pseudo_p () + && reg_overlap_mentioned_p (operands[0], operands[3])) + { + addend = gen_reg_rtx (SImode); + emit_move_insn (addend, operands[3]); + } + + emit_insn (gen_mulsi3 (operands[0], operands[1], operands[2])); + emit_insn (gen_addsi3 (operands[0], operands[0], addend)); + DONE; + }" + [(set_attr "type" "imul")]) + +(define_insn_and_split "madd_fused_extended" + [(set (match_operand:DI 0 "register_operand" "=&r") + (sign_extend:DI + (plus:SI + (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "register_operand" "r"))))] + "riscv_fusion_enabled_p (RISCV_FUSE_MULT_ADD) + && !TARGET_XTHEADMAC + && TARGET_64BIT && (TARGET_ZMMUL || TARGET_MUL)" + "#" + "&& 1" + [(const_int 0)] + "{ + rtx addend = operands[3]; + if (can_create_pseudo_p () + && reg_overlap_mentioned_p (operands[0], operands[3])) + { + addend = gen_reg_rtx (SImode); + emit_move_insn (addend, operands[3]); + } + + emit_insn (gen_mulsi3_extended (operands[0], operands[1], operands[2])); + emit_insn (gen_addsi3_extended (operands[0], + gen_lowpart (SImode, operands[0]), + addend)); + DONE; + }" + [(set_attr "type" "imul")]) + ;; String compare with length insn. ;; Argument 0 is the target (result) ;; Argument 1 is the source1 diff --git a/gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c b/gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c new file mode 100644 index 00000000000..b471c20ae57 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-bfext-2.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target rv32 } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-Oz" "-Os" } } */ +/* { dg-options "-mtune=arc-v-rhx-100-series -march=rv32im_zbs -mabi=ilp32" } */ + +#define bit_extract(x,start,amt) (((x)>>(start)) & (~(0xffffffff << (amt)))) + +int +f (int x) +{ + return bit_extract(x,10,14) + bit_extract(x,1,1); +} + +/* { dg-final { scan-assembler {\sslli\s([ast][0-9]+),a0,8\n\ssrli\s([ast][0-9]+),\1,18\n\sbexti\sa0,a0,1.*\n\sadd\sa0,\2,a0.*\n} } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c b/gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c new file mode 100644 index 00000000000..cc2a56a2e08 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-limm-condbr.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mtune=arc-v-rhx-100-series" } */ + +int +f (int x) +{ + begin: + if (x <= 3) + goto begin; +} + +/* { dg-final { scan-assembler "\\sli\\sa5,3\n\\sble\\sa0,a5,.L\[0-9\]+\n" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/fusion-madd.c b/gcc/testsuite/gcc.target/riscv/fusion-madd.c new file mode 100644 index 00000000000..e58fc830e47 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/fusion-madd.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-skip-if "" { *-*-* } { "-g" "-flto" "-O0" "-O1" "-O3" "-Oz" "-Os" } } */ +/* { dg-options "-mtune=arc-v-rhx-100-series -march=rv32im -mabi=ilp32" { target { rv32 } } } */ +/* { dg-options "-mtune=arc-v-rhx-100-series -march=rv64im -mabi=lp64" { target { rv64 } } } */ + +int +f (int x, short y, short z, short v, short w) +{ + return x + (int) y * (int) z + (int) v * (int) w; +} + +/* { dg-final { scan-assembler {\smul\s([ast][0-9]+),a1,a2\n\sadd\s\1,\1,a0\n\smul\sa0,a3,a4\n\sadd\sa0,a0,\1\n} { target rv32 } } } */ +/* { dg-final { scan-assembler {\smulw\sa2,a2,a1\n\saddw\sa2,a2,a0\n\smulw\sa0,a4,a3\n\saddw\sa0,a0,a2\n} { target rv64 } } } */ -- 2.47.3