Commit 3b859704 by Richard Sandiford Committed by Richard Sandiford

re PR rtl-optimization/53916 ([mips16] divide operation compiled result…

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 (divmod<mode>4, udivmod<mode>4): Delete.
	(divmod<mode>4_internal): Rename to divmod<mode>4.  Use "kl" as the
	constraint for operand 0.  Split after CSE for MIPS16.  Emit a move
	from LO for MIPS16.
	(udivmod<mode>4_internal): Likewise udivmod<mode>4.

gcc/testsuite/
	PR target/53916
	* gcc.target/mips/div-13.c: New test.

From-SVN: r199329
parent c979d5f5
2013-05-25 Richard Sandiford <rdsandiford@googlemail.com> 2013-05-25 Richard Sandiford <rdsandiford@googlemail.com>
PR target/53916
* config/mips/constraints.md (kl): New constraint.
* config/mips/mips.md (divmod<mode>4, udivmod<mode>4): Delete.
(divmod<mode>4_internal): Rename to divmod<mode>4. Use "kl" as the
constraint for operand 0. Split after CSE for MIPS16. Emit a move
from LO for MIPS16.
(udivmod<mode>4_internal): Likewise udivmod<mode>4.
2013-05-25 Richard Sandiford <rdsandiford@googlemail.com>
PR target/55777 PR target/55777
* config/mips/mips.c (mips_can_inline_p): New function. * config/mips/mips.c (mips_can_inline_p): New function.
(TARGET_CAN_INLINE_P): Define. (TARGET_CAN_INLINE_P): Define.
......
...@@ -92,6 +92,12 @@ ...@@ -92,6 +92,12 @@
;; but the DSP version allows any accumulator target. ;; but the DSP version allows any accumulator target.
(define_register_constraint "ka" "ISA_HAS_DSP_MULT ? ACC_REGS : MD_REGS") (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" (define_constraint "kf"
"@internal" "@internal"
(match_operand 0 "force_to_mem_operand")) (match_operand 0 "force_to_mem_operand"))
......
...@@ -2560,80 +2560,50 @@ ...@@ -2560,80 +2560,50 @@
;; VR4120 errata MD(A1): signed division instructions do not work correctly ;; VR4120 errata MD(A1): signed division instructions do not work correctly
;; with negative operands. We use special libgcc functions instead. ;; with negative operands. We use special libgcc functions instead.
(define_expand "divmod<mode>4" ;;
[(set (match_operand:GPR 0 "register_operand") ;; Expand generates divmod instructions for individual division and modulus
(div:GPR (match_operand:GPR 1 "register_operand") ;; operations. We then rely on CSE to reuse earlier divmods where possible.
(match_operand:GPR 2 "register_operand"))) ;; This means that, when generating MIPS16 code, it is better not to expose
(set (match_operand:GPR 3 "register_operand") ;; the fixed LO register until after CSE has finished. However, it's still
(mod:GPR (match_dup 1) ;; better to split before register allocation, so that we don't allocate
(match_dup 2)))] ;; one of the scarce MIPS16 registers to an unused result.
"!TARGET_FIX_VR4120" (define_insn_and_split "divmod<mode>4"
{ [(set (match_operand:GPR 0 "register_operand" "=kl")
if (TARGET_MIPS16)
{
emit_insn (gen_divmod<mode>4_split (operands[3], operands[1],
operands[2]));
emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, LO_REGNUM));
}
else
emit_insn (gen_divmod<mode>4_internal (operands[0], operands[1],
operands[2], operands[3]));
DONE;
})
(define_insn_and_split "divmod<mode>4_internal"
[(set (match_operand:GPR 0 "muldiv_target_operand" "=l")
(div:GPR (match_operand:GPR 1 "register_operand" "d") (div:GPR (match_operand:GPR 1 "register_operand" "d")
(match_operand:GPR 2 "register_operand" "d"))) (match_operand:GPR 2 "register_operand" "d")))
(set (match_operand:GPR 3 "register_operand" "=d") (set (match_operand:GPR 3 "register_operand" "=d")
(mod:GPR (match_dup 1) (mod:GPR (match_dup 1)
(match_dup 2)))] (match_dup 2)))]
"!TARGET_FIX_VR4120 && !TARGET_MIPS16" "!TARGET_FIX_VR4120"
"#" "#"
"&& reload_completed" "&& ((TARGET_MIPS16 && cse_not_expected) || reload_completed)"
[(const_int 0)] [(const_int 0)]
{ {
emit_insn (gen_divmod<mode>4_split (operands[3], operands[1], operands[2])); emit_insn (gen_divmod<mode>4_split (operands[3], operands[1], operands[2]));
if (TARGET_MIPS16)
emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, LO_REGNUM));
DONE; DONE;
} }
[(set_attr "type" "idiv") [(set_attr "type" "idiv")
(set_attr "mode" "<MODE>") (set_attr "mode" "<MODE>")
(set_attr "length" "8")]) (set_attr "length" "8")])
(define_expand "udivmod<mode>4" ;; See the comment above "divmod<mode>4" for the MIPS16 handling.
[(set (match_operand:GPR 0 "register_operand") (define_insn_and_split "udivmod<mode>4"
(udiv:GPR (match_operand:GPR 1 "register_operand") [(set (match_operand:GPR 0 "register_operand" "=kl")
(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_udivmod<mode>4_split (operands[3], operands[1],
operands[2]));
emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, LO_REGNUM));
}
else
emit_insn (gen_udivmod<mode>4_internal (operands[0], operands[1],
operands[2], operands[3]));
DONE;
})
(define_insn_and_split "udivmod<mode>4_internal"
[(set (match_operand:GPR 0 "muldiv_target_operand" "=l")
(udiv:GPR (match_operand:GPR 1 "register_operand" "d") (udiv:GPR (match_operand:GPR 1 "register_operand" "d")
(match_operand:GPR 2 "register_operand" "d"))) (match_operand:GPR 2 "register_operand" "d")))
(set (match_operand:GPR 3 "register_operand" "=d") (set (match_operand:GPR 3 "register_operand" "=d")
(umod:GPR (match_dup 1) (umod:GPR (match_dup 1)
(match_dup 2)))] (match_dup 2)))]
"!TARGET_MIPS16" ""
"#" "#"
"reload_completed" "(TARGET_MIPS16 && cse_not_expected) || reload_completed"
[(const_int 0)] [(const_int 0)]
{ {
emit_insn (gen_udivmod<mode>4_split (operands[3], operands[1], operands[2])); emit_insn (gen_udivmod<mode>4_split (operands[3], operands[1], operands[2]));
if (TARGET_MIPS16)
emit_move_insn (operands[0], gen_rtx_REG (<MODE>mode, LO_REGNUM));
DONE; DONE;
} }
[(set_attr "type" "idiv") [(set_attr "type" "idiv")
......
2013-05-25 Richard Sandiford <rdsandiford@googlemail.com> 2013-05-25 Richard Sandiford <rdsandiford@googlemail.com>
PR target/53916
* gcc.target/mips/div-13.c: New test.
2013-05-25 Richard Sandiford <rdsandiford@googlemail.com>
PR target/55777 PR target/55777
* gcc.target/mips/mips16-attributes-5.c, * gcc.target/mips/mips16-attributes-5.c,
* gcc.target/mips/mips16-attributes-6.c: New tests. * gcc.target/mips/mips16-attributes-6.c: New tests.
......
/* { 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 } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment