diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index ff4557c1325..78c16adee98 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -4162,6 +4162,62 @@ } ) +;; These are forms of (x << C1) + C2, potentially canonicalized from +;; ((x + C2') << C1. Depending on the cost to load C2 vs C2' we may +;; want to go ahead and recognize this form as C2 may be cheaper to +;; synthesize than C2'. +;; +;; It might be better to refactor riscv_const_insns a bit so that we +;; can have an API that passes integer values around rather than +;; constructing a lot of garbage RTL. +;; +;; The mvconst_internal pattern in effect requires this pattern to +;; also be a define_insn_and_split due to insn count costing when +;; splitting in combine. +(define_insn_and_split "" + [(set (match_operand:DI 0 "register_operand" "=r") + (plus:DI (ashift:DI (match_operand:DI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "n")) + (match_operand 3 "const_int_operand" "n"))) + (clobber (match_scratch:DI 4 "=&r"))] + "(TARGET_64BIT + && riscv_const_insns (operands[3]) + && ((riscv_const_insns (operands[3]) + < riscv_const_insns (GEN_INT (INTVAL (operands[3]) >> INTVAL (operands[2])))) + || riscv_const_insns (GEN_INT (INTVAL (operands[3]) >> INTVAL (operands[2]))) == 0))" + "#" + "&& reload_completed" + [(set (match_dup 0) (ashift:DI (match_dup 1) (match_dup 2))) + (set (match_dup 4) (match_dup 3)) + (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))] + "" + [(set_attr "type" "arith")]) + +(define_insn_and_split "" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI (plus:SI (ashift:SI + (match_operand:SI 1 "register_operand" "r") + (match_operand 2 "const_int_operand" "n")) + (match_operand 3 "const_int_operand" "n")))) + (clobber (match_scratch:DI 4 "=&r"))] + "(TARGET_64BIT + && riscv_const_insns (operands[3]) + && ((riscv_const_insns (operands[3]) + < riscv_const_insns (GEN_INT (INTVAL (operands[3]) >> INTVAL (operands[2])))) + || riscv_const_insns (GEN_INT (INTVAL (operands[3]) >> INTVAL (operands[2]))) == 0))" + "#" + "&& reload_completed" + [(set (match_dup 0) (ashift:DI (match_dup 1) (match_dup 2))) + (set (match_dup 4) (match_dup 3)) + (set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 5) (match_dup 6))))] + "{ + operands[1] = gen_lowpart (DImode, operands[1]); + operands[5] = gen_lowpart (SImode, operands[0]); + operands[6] = gen_lowpart (SImode, operands[4]); + }" + [(set_attr "type" "arith")]) + + (include "bitmanip.md") (include "crypto.md") (include "sync.md") diff --git a/gcc/testsuite/gcc.target/riscv/shift-add-1.c b/gcc/testsuite/gcc.target/riscv/shift-add-1.c new file mode 100644 index 00000000000..d98875c3271 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/shift-add-1.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zba_zbb_zbs -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ + +int composeFromSurrogate(const unsigned short high) { + + return ((high - 0xD800) << 10) ; +} + + +long composeFromSurrogate_2(const unsigned long high) { + + return ((high - 0xD800) << 10) ; +} + + +/* { dg-final { scan-assembler-times "\tli\t" 2 } } */ +/* { dg-final { scan-assembler-times "\tslli\t" 2 } } */ +/* { dg-final { scan-assembler-times "\taddw\t" 1 } } */ +/* { dg-final { scan-assembler-times "\tadd\t" 1 } } */ +