From: Richard Sandiford Date: Sat, 25 May 2013 16:00:12 +0000 (+0000) Subject: re PR rtl-optimization/53916 ([mips16] divide operation compiled result incorrect... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3b8597040b32e22a6defa8f642364500a45d953b;p=gcc.git re PR rtl-optimization/53916 ([mips16] divide operation compiled result incorrect with GCC-4.6.3 '-O2' option) gcc/ PR target/53916 * config/mips/constraints.md (kl): New constraint. * config/mips/mips.md (divmod4, udivmod4): Delete. (divmod4_internal): Rename to divmod4. Use "kl" as the constraint for operand 0. Split after CSE for MIPS16. Emit a move from LO for MIPS16. (udivmod4_internal): Likewise udivmod4. gcc/testsuite/ PR target/53916 * gcc.target/mips/div-13.c: New test. From-SVN: r199329 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 89936afd71d..e2879fc338f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2013-05-25 Richard Sandiford + + PR target/53916 + * config/mips/constraints.md (kl): New constraint. + * config/mips/mips.md (divmod4, udivmod4): Delete. + (divmod4_internal): Rename to divmod4. Use "kl" as the + constraint for operand 0. Split after CSE for MIPS16. Emit a move + from LO for MIPS16. + (udivmod4_internal): Likewise udivmod4. + 2013-05-25 Richard Sandiford PR target/55777 diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md index ddef8cc495d..1fe6119d075 100644 --- a/gcc/config/mips/constraints.md +++ b/gcc/config/mips/constraints.md @@ -92,6 +92,12 @@ ;; but the DSP version allows any accumulator target. (define_register_constraint "ka" "ISA_HAS_DSP_MULT ? ACC_REGS : MD_REGS") +;; The register class to use for an allocatable division result. +;; MIPS16 uses M16_REGS because LO is fixed. +(define_register_constraint "kl" + "TARGET_MIPS16 ? M16_REGS : TARGET_BIG_ENDIAN ? MD1_REG : MD0_REG" + "@internal") + (define_constraint "kf" "@internal" (match_operand 0 "force_to_mem_operand")) diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 7284e5f3384..6f6484b0d8c 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -2560,80 +2560,50 @@ ;; VR4120 errata MD(A1): signed division instructions do not work correctly ;; with negative operands. We use special libgcc functions instead. -(define_expand "divmod4" - [(set (match_operand:GPR 0 "register_operand") - (div:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand"))) - (set (match_operand:GPR 3 "register_operand") - (mod:GPR (match_dup 1) - (match_dup 2)))] - "!TARGET_FIX_VR4120" -{ - if (TARGET_MIPS16) - { - emit_insn (gen_divmod4_split (operands[3], operands[1], - operands[2])); - emit_move_insn (operands[0], gen_rtx_REG (mode, LO_REGNUM)); - } - else - emit_insn (gen_divmod4_internal (operands[0], operands[1], - operands[2], operands[3])); - DONE; -}) - -(define_insn_and_split "divmod4_internal" - [(set (match_operand:GPR 0 "muldiv_target_operand" "=l") +;; +;; Expand generates divmod instructions for individual division and modulus +;; operations. We then rely on CSE to reuse earlier divmods where possible. +;; This means that, when generating MIPS16 code, it is better not to expose +;; the fixed LO register until after CSE has finished. However, it's still +;; better to split before register allocation, so that we don't allocate +;; one of the scarce MIPS16 registers to an unused result. +(define_insn_and_split "divmod4" + [(set (match_operand:GPR 0 "register_operand" "=kl") (div:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) (set (match_operand:GPR 3 "register_operand" "=d") (mod:GPR (match_dup 1) (match_dup 2)))] - "!TARGET_FIX_VR4120 && !TARGET_MIPS16" + "!TARGET_FIX_VR4120" "#" - "&& reload_completed" + "&& ((TARGET_MIPS16 && cse_not_expected) || reload_completed)" [(const_int 0)] { emit_insn (gen_divmod4_split (operands[3], operands[1], operands[2])); + if (TARGET_MIPS16) + emit_move_insn (operands[0], gen_rtx_REG (mode, LO_REGNUM)); DONE; } [(set_attr "type" "idiv") (set_attr "mode" "") (set_attr "length" "8")]) -(define_expand "udivmod4" - [(set (match_operand:GPR 0 "register_operand") - (udiv:GPR (match_operand:GPR 1 "register_operand") - (match_operand:GPR 2 "register_operand"))) - (set (match_operand:GPR 3 "register_operand") - (umod:GPR (match_dup 1) - (match_dup 2)))] - "" -{ - if (TARGET_MIPS16) - { - emit_insn (gen_udivmod4_split (operands[3], operands[1], - operands[2])); - emit_move_insn (operands[0], gen_rtx_REG (mode, LO_REGNUM)); - } - else - emit_insn (gen_udivmod4_internal (operands[0], operands[1], - operands[2], operands[3])); - DONE; -}) - -(define_insn_and_split "udivmod4_internal" - [(set (match_operand:GPR 0 "muldiv_target_operand" "=l") +;; See the comment above "divmod4" for the MIPS16 handling. +(define_insn_and_split "udivmod4" + [(set (match_operand:GPR 0 "register_operand" "=kl") (udiv:GPR (match_operand:GPR 1 "register_operand" "d") (match_operand:GPR 2 "register_operand" "d"))) (set (match_operand:GPR 3 "register_operand" "=d") (umod:GPR (match_dup 1) (match_dup 2)))] - "!TARGET_MIPS16" + "" "#" - "reload_completed" + "(TARGET_MIPS16 && cse_not_expected) || reload_completed" [(const_int 0)] { emit_insn (gen_udivmod4_split (operands[3], operands[1], operands[2])); + if (TARGET_MIPS16) + emit_move_insn (operands[0], gen_rtx_REG (mode, LO_REGNUM)); DONE; } [(set_attr "type" "idiv") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index fbc87164103..38985d6119a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2013-05-25 Richard Sandiford + + PR target/53916 + * gcc.target/mips/div-13.c: New test. + 2013-05-25 Richard Sandiford PR target/55777 diff --git a/gcc/testsuite/gcc.target/mips/div-13.c b/gcc/testsuite/gcc.target/mips/div-13.c new file mode 100644 index 00000000000..cf746a66306 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/div-13.c @@ -0,0 +1,17 @@ +/* { dg-options "(-mips16) -mgp64" } */ +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ + +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +MIPS16 int32_t f1 (int32_t x, int32_t y) { return x / y + x % y; } +MIPS16 uint32_t f2 (uint32_t x, uint32_t y) { return x / y + x % y; } +MIPS16 int64_t f3 (int64_t x, int64_t y) { return x / y + x % y; } +MIPS16 uint64_t f4 (uint64_t x, uint64_t y) { return x / y + x % y; } + +/* { dg-final { scan-assembler-times "\tdiv\t" 1 } } */ +/* { dg-final { scan-assembler-times "\tdivu\t" 1 } } */ +/* { dg-final { scan-assembler-times "\tddiv\t" 1 } } */ +/* { dg-final { scan-assembler-times "\tddivu\t" 1 } } */