From 294e72e9acbd0ff15ef5b18895de62cc173464ca Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Thu, 26 Nov 2020 16:38:35 +0100 Subject: Fix PR target/96607 After 15 years trying to find out what can go into the delay slot of the call to __tls_get_addr with the Solaris linker, it's now time to concede defeat and consider it as not to be filled. gcc/ChangeLog: PR target/96607 * config/sparc/sparc-protos.h (eligible_for_call_delay): Delete. * config/sparc/sparc.c (eligible_for_call_delay): Likewise. * config/sparc/sparc.md (in_call_delay): Likewise. (tls_delay_slot): New attribute. (define_delay [call]): Use in_branch_delay. (tgd_call): Set type to call_no_delay_slot when tls_delay_slot is false. (tldm_call): Likewise. --- gcc/config/sparc/sparc-protos.h | 1 - gcc/config/sparc/sparc.c | 35 ----------------------------------- gcc/config/sparc/sparc.md | 37 +++++++++++++++++++------------------ 3 files changed, 19 insertions(+), 54 deletions(-) (limited to 'gcc/config/sparc') diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h index f525cd7..5f9999a 100644 --- a/gcc/config/sparc/sparc-protos.h +++ b/gcc/config/sparc/sparc-protos.h @@ -86,7 +86,6 @@ extern int mems_ok_for_ldd_peep (rtx, rtx, rtx); extern rtx widen_mem_for_ldd_peep (rtx, rtx, machine_mode); extern int empty_delay_slot (rtx_insn *); extern int emit_cbcond_nop (rtx_insn *); -extern int eligible_for_call_delay (rtx_insn *); extern int eligible_for_return_delay (rtx_insn *); extern int eligible_for_sibcall_delay (rtx_insn *); extern int emit_move_sequence (rtx, machine_mode); diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 2780b42..02138c5 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -3949,41 +3949,6 @@ emit_cbcond_nop (rtx_insn *insn) return 1; } -/* Return nonzero if TRIAL can go into the call delay slot. */ - -int -eligible_for_call_delay (rtx_insn *trial) -{ - rtx pat; - - if (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_FALSE) - return 0; - - /* The only problematic cases are TLS sequences with Sun as/ld. */ - if ((TARGET_GNU_TLS && HAVE_GNU_LD) || !TARGET_TLS) - return 1; - - pat = PATTERN (trial); - - /* We must reject tgd_add{32|64}, i.e. - (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD))) - and tldm_add{32|64}, i.e. - (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM))) - for Sun as/ld. */ - if (GET_CODE (pat) == SET - && GET_CODE (SET_SRC (pat)) == PLUS) - { - rtx unspec = XEXP (SET_SRC (pat), 1); - - if (GET_CODE (unspec) == UNSPEC - && (XINT (unspec, 1) == UNSPEC_TLSGD - || XINT (unspec, 1) == UNSPEC_TLSLDM)) - return 0; - } - - return 1; -} - /* Return nonzero if TRIAL, an insn, can be combined with a 'restore' instruction. RETURN_P is true if the v9 variant 'return' is to be considered in the test too. diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 231c0d8..edfb635 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -561,9 +561,9 @@ (set_attr "type" "multi")]) ;; Attributes for branch scheduling -(define_attr "in_call_delay" "false,true" - (symbol_ref "(eligible_for_call_delay (insn) - ? IN_CALL_DELAY_TRUE : IN_CALL_DELAY_FALSE)")) +(define_attr "tls_delay_slot" "false,true" + (symbol_ref "((TARGET_GNU_TLS && HAVE_GNU_LD) != 0 + ? TLS_DELAY_SLOT_TRUE : TLS_DELAY_SLOT_FALSE)")) (define_attr "in_sibcall_delay" "false,true" (symbol_ref "(eligible_for_sibcall_delay (insn) @@ -613,27 +613,24 @@ (const_string "true") ] (const_string "false"))) -(define_delay (eq_attr "type" "call") - [(eq_attr "in_call_delay" "true") (nil) (nil)]) - (define_delay (eq_attr "type" "sibcall") [(eq_attr "in_sibcall_delay" "true") (nil) (nil)]) (define_delay (eq_attr "type" "return") [(eq_attr "in_return_delay" "true") (nil) (nil)]) -(define_delay (and (eq_attr "type" "branch") - (not (eq_attr "branch_type" "icc"))) - [(eq_attr "in_branch_delay" "true") (nil) (eq_attr "in_branch_delay" "true")]) - -(define_delay (and (eq_attr "type" "branch") - (eq_attr "branch_type" "icc")) - [(eq_attr "in_branch_delay" "true") (nil) - (eq_attr "in_integer_branch_annul_delay" "true")]) - -(define_delay (eq_attr "type" "uncond_branch") +(define_delay (ior (eq_attr "type" "call") (eq_attr "type" "uncond_branch")) [(eq_attr "in_branch_delay" "true") (nil) (nil)]) +(define_delay (and (eq_attr "type" "branch") (not (eq_attr "branch_type" "icc"))) + [(eq_attr "in_branch_delay" "true") + (nil) + (eq_attr "in_branch_delay" "true")]) + +(define_delay (and (eq_attr "type" "branch") (eq_attr "branch_type" "icc")) + [(eq_attr "in_branch_delay" "true") + (nil) + (eq_attr "in_integer_branch_annul_delay" "true")]) ;; Include SPARC DFA schedulers @@ -7935,7 +7932,9 @@ visl") (clobber (reg:P O7_REG))] "TARGET_TLS" "call\t%a1, %%tgd_call(%a2)%#" - [(set_attr "type" "call")]) + [(set (attr "type") (if_then_else (eq_attr "tls_delay_slot" "true") + (const_string "call") + (const_string "call_no_delay_slot")))]) (define_insn "tldm_hi22" [(set (match_operand:P 0 "register_operand" "=r") @@ -7966,7 +7965,9 @@ visl") (clobber (reg:P O7_REG))] "TARGET_TLS" "call\t%a1, %%tldm_call(%&)%#" - [(set_attr "type" "call")]) + [(set (attr "type") (if_then_else (eq_attr "tls_delay_slot" "true") + (const_string "call") + (const_string "call_no_delay_slot")))]) (define_insn "tldo_hix22" [(set (match_operand:P 0 "register_operand" "=r") -- cgit v1.1 From c04bd12b06a21ad4a9c432c109ec2a543725ad1b Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Sat, 28 Nov 2020 12:54:48 +0100 Subject: Fix PR target/97939 The little dance around 4096 that add/sub instructions do on the SPARC needs to be taken into account for the overflow arithmetic operations. It cannot be done for unsigned overflow, but it can be done for signed overflow. gcc/ChangeLog: PR target/97939 * config/sparc/predicates.md (arith_double_add_operand): Comment. * config/sparc/sparc.md (uaddvdi4): Use arith_double_operand. (addvdi4): Use arith_double_add_operand. (addsi3): Remove useless attributes. (addvsi4): Use arith_add_operand. (*cmp_ccv_plus): Likewise and add second alternative accordingly. (*cmp_ccxv_plus): Likewise. (*cmp_ccv_plus_set): Likewise. (*cmp_ccxv_plus_set): Likewise. (*cmp_ccv_plus_sltu_set): Likewise. (usubvdi4): Use arith_double_operand. (subvdi4): Use arith_double_add_operand. (subsi3): Remove useless attributes. (subvsi4): Use arith_add_operand. (*cmp_ccv_minus): Likewise and add second alternative accordingly. (*cmp_ccxv_minus): Likewise. (*cmp_ccv_minus_set): Likewise. (*cmp_ccxv_minus_set): Likewise. (*cmp_ccv_minus_sltu_set): Likewise. (negsi2): Use register_operand. (unegvsi3): Likewise. (negvsi3) Likewise. (*cmp_ccnz_neg): Likewise. (*cmp_ccxnz_neg): Likewise. (*cmp_ccnz_neg_set): Likewise. (*cmp_ccxnz_neg_set): Likewise. (*cmp_ccc_neg_set): Likewise. (*cmp_ccxc_neg_set): Likewise. (*cmp_ccc_neg_sltu_set): Likewise. (*cmp_ccv_neg): Likewise. (*cmp_ccxv_neg): Likewise. (*cmp_ccv_neg_set): Likewise. (*cmp_ccxv_neg_set): Likewise. (*cmp_ccv_neg_sltu_set): Likewise. gcc/testsuite/ChangeLog: * gcc.target/sparc/overflow-6.c: New test. --- gcc/config/sparc/predicates.md | 2 + gcc/config/sparc/sparc.md | 146 +++++++++++++++++++++++++---------------- 2 files changed, 93 insertions(+), 55 deletions(-) (limited to 'gcc/config/sparc') diff --git a/gcc/config/sparc/predicates.md b/gcc/config/sparc/predicates.md index 3d49972..42316ad 100644 --- a/gcc/config/sparc/predicates.md +++ b/gcc/config/sparc/predicates.md @@ -296,6 +296,8 @@ if (arith_double_operand (op, mode)) return true; + /* Turning an add/sub instruction into the other changes the Carry flag + so the 4096 trick cannot be used for double operations in 32-bit mode. */ return TARGET_ARCH64 && const_4096_operand (op, mode); }) diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index edfb635..6e9ccb4 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -3768,10 +3768,13 @@ visl") } }) +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCXCmode. + (define_expand "uaddvdi4" [(parallel [(set (reg:CCXC CC_REG) (compare:CCXC (plus:DI (match_operand:DI 1 "register_operand") - (match_operand:DI 2 "arith_add_operand")) + (match_operand:DI 2 "arith_double_operand")) (match_dup 1))) (set (match_operand:DI 0 "register_operand") (plus:DI (match_dup 1) (match_dup 2)))]) @@ -3790,10 +3793,13 @@ visl") } }) +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCXVmode. + (define_expand "addvdi4" [(parallel [(set (reg:CCXV CC_REG) (compare:CCXV (plus:DI (match_operand:DI 1 "register_operand") - (match_operand:DI 2 "arith_add_operand")) + (match_operand:DI 2 "arith_double_add_operand")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) (set (match_operand:DI 0 "register_operand") @@ -3966,9 +3972,10 @@ visl") "" "@ add\t%1, %2, %0 - sub\t%1, -%2, %0" - [(set_attr "type" "*,*") - (set_attr "fptype" "*,*")]) + sub\t%1, -%2, %0") + +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCCmode. (define_expand "uaddvsi4" [(parallel [(set (reg:CCC CC_REG) @@ -3982,10 +3989,13 @@ visl") (pc)))] "") +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCVmode. + (define_expand "addvsi4" [(parallel [(set (reg:CCV CC_REG) (compare:CCV (plus:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "arith_operand")) + (match_operand:SI 2 "arith_add_operand")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) (set (match_operand:SI 0 "register_operand") @@ -4094,42 +4104,50 @@ visl") (define_insn "*cmp_ccv_plus" [(set (reg:CCV CC_REG) - (compare:CCV (plus:SI (match_operand:SI 0 "register_operand" "%r") - (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCV (plus:SI (match_operand:SI 0 "register_operand" "%r,r") + (match_operand:SI 1 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_ADDV)))] "" - "addcc\t%0, %1, %%g0" + "@ + addcc\t%0, %1, %%g0 + subcc\t%0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_plus" [(set (reg:CCXV CC_REG) - (compare:CCXV (plus:DI (match_operand:DI 0 "register_operand" "%r") - (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXV (plus:DI (match_operand:DI 0 "register_operand" "%r,r") + (match_operand:DI 1 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 0) (match_dup 1)] UNSPEC_ADDV)))] "TARGET_ARCH64" - "addcc\t%0, %1, %%g0" + "@ + addcc\t%0, %1, %%g0 + subcc\t%0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_plus_set" [(set (reg:CCV CC_REG) - (compare:CCV (plus:SI (match_operand:SI 1 "register_operand" "%r") - (match_operand:SI 2 "arith_operand" "rI")) + (compare:CCV (plus:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) - (set (match_operand:SI 0 "register_operand" "=r") + (set (match_operand:SI 0 "register_operand" "=r,r") (plus:SI (match_dup 1) (match_dup 2)))] "" - "addcc\t%1, %2, %0" + "@ + addcc\t%1, %2, %0 + subcc\t%1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_plus_set" [(set (reg:CCXV CC_REG) - (compare:CCXV (plus:DI (match_operand:DI 1 "register_operand" "%r") - (match_operand:DI 2 "arith_operand" "rI")) + (compare:CCXV (plus:DI (match_operand:DI 1 "register_operand" "%r,r") + (match_operand:DI 2 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_ADDV))) - (set (match_operand:DI 0 "register_operand" "=r") + (set (match_operand:DI 0 "register_operand" "=r,r") (plus:DI (match_dup 1) (match_dup 2)))] "TARGET_ARCH64" - "addcc\t%1, %2, %0" + "@ + addcc\t%1, %2, %0 + subcc\t%1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_plus_sltu_set" @@ -4161,10 +4179,13 @@ visl") } }) +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCXmode. + (define_expand "usubvdi4" [(parallel [(set (reg:CCX CC_REG) (compare:CCX (match_operand:DI 1 "register_or_zero_operand") - (match_operand:DI 2 "arith_add_operand"))) + (match_operand:DI 2 "arith_double_operand"))) (set (match_operand:DI 0 "register_operand") (minus:DI (match_dup 1) (match_dup 2)))]) (set (pc) (if_then_else (ltu (reg:CCX CC_REG) (const_int 0)) @@ -4188,10 +4209,13 @@ visl") } }) +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCXVmode. + (define_expand "subvdi4" [(parallel [(set (reg:CCXV CC_REG) (compare:CCXV (minus:DI (match_operand:DI 1 "register_operand") - (match_operand:DI 2 "arith_add_operand")) + (match_operand:DI 2 "arith_double_add_operand")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) (set (match_operand:DI 0 "register_operand") @@ -4362,9 +4386,10 @@ visl") "" "@ sub\t%1, %2, %0 - add\t%1, -%2, %0" - [(set_attr "type" "*,*") - (set_attr "fptype" "*,*")]) + add\t%1, -%2, %0") + +;; Turning an add/sub instruction into the other changes the Carry flag +;; so the 4096 trick cannot be used for operations in CCmode. (define_expand "usubvsi4" [(parallel [(set (reg:CC CC_REG) @@ -4384,10 +4409,13 @@ visl") } }) +;; Turning an add/sub instruction into the other does not change the Overflow +;; flag so the 4096 trick can be used for operations in CCVmode. + (define_expand "subvsi4" [(parallel [(set (reg:CCV CC_REG) (compare:CCV (minus:SI (match_operand:SI 1 "register_operand") - (match_operand:SI 2 "arith_operand")) + (match_operand:SI 2 "arith_add_operand")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) (set (match_operand:SI 0 "register_operand") @@ -4480,42 +4508,50 @@ visl") (define_insn "*cmp_ccv_minus" [(set (reg:CCV CC_REG) - (compare:CCV (minus:SI (match_operand:SI 0 "register_or_zero_operand" "rJ") - (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCV (minus:SI (match_operand:SI 0 "register_or_zero_operand" "rJ,rJ") + (match_operand:SI 1 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 0) (match_dup 1)] UNSPEC_SUBV)))] "" - "subcc\t%r0, %1, %%g0" + "@ + subcc\t%r0, %1, %%g0 + addcc\t%r0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_minus" [(set (reg:CCXV CC_REG) - (compare:CCXV (minus:DI (match_operand:DI 0 "register_or_zero_operand" "rJ") - (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXV (minus:DI (match_operand:DI 0 "register_or_zero_operand" "rJ,rJ") + (match_operand:DI 1 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 0) (match_dup 1)] UNSPEC_SUBV)))] "TARGET_ARCH64" - "subcc\t%r0, %1, %%g0" + "@ + subcc\t%r0, %1, %%g0 + addcc\t%r0, -%1, %%g0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_minus_set" [(set (reg:CCV CC_REG) - (compare:CCV (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ") - (match_operand:SI 2 "arith_operand" "rI")) + (compare:CCV (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ,rJ") + (match_operand:SI 2 "arith_add_operand" "rI,O")) (unspec:SI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) - (set (match_operand:SI 0 "register_operand" "=r") + (set (match_operand:SI 0 "register_operand" "=r,r") (minus:SI (match_dup 1) (match_dup 2)))] "" - "subcc\t%r1, %2, %0" + "@ + subcc\t%r1, %2, %0 + addcc\t%r1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccxv_minus_set" [(set (reg:CCXV CC_REG) - (compare:CCXV (minus:DI (match_operand:DI 1 "register_or_zero_operand" "rJ") - (match_operand:DI 2 "arith_operand" "rI")) + (compare:CCXV (minus:DI (match_operand:DI 1 "register_or_zero_operand" "rJ,rJ") + (match_operand:DI 2 "arith_add_operand" "rI,O")) (unspec:DI [(match_dup 1) (match_dup 2)] UNSPEC_SUBV))) - (set (match_operand:DI 0 "register_operand" "=r") + (set (match_operand:DI 0 "register_operand" "=r,r") (minus:DI (match_dup 1) (match_dup 2)))] "TARGET_ARCH64" - "subcc\t%r1, %2, %0" + "@ + subcc\t%r1, %2, %0 + addcc\t%r1, -%2, %0" [(set_attr "type" "compare")]) (define_insn "*cmp_ccv_minus_sltu_set" @@ -5766,13 +5802,13 @@ visl") (define_insn "negsi2" [(set (match_operand:SI 0 "register_operand" "=r") - (neg:SI (match_operand:SI 1 "arith_operand" "rI")))] + (neg:SI (match_operand:SI 1 "register_operand" "r")))] "" "sub\t%%g0, %1, %0") (define_expand "unegvsi3" [(parallel [(set (reg:CCC CC_REG) - (compare:CCC (not:SI (match_operand:SI 1 "arith_operand" "")) + (compare:CCC (not:SI (match_operand:SI 1 "register_operand" "")) (const_int -1))) (set (match_operand:SI 0 "register_operand" "") (neg:SI (match_dup 1)))]) @@ -5784,7 +5820,7 @@ visl") (define_expand "negvsi3" [(parallel [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (match_operand:SI 1 "arith_operand" "")) + (compare:CCV (neg:SI (match_operand:SI 1 "register_operand" "")) (unspec:SI [(match_dup 1)] UNSPEC_NEGV))) (set (match_operand:SI 0 "register_operand" "") (neg:SI (match_dup 1)))]) @@ -5796,7 +5832,7 @@ visl") (define_insn "*cmp_ccnz_neg" [(set (reg:CCNZ CC_REG) - (compare:CCNZ (neg:SI (match_operand:SI 0 "arith_operand" "rI")) + (compare:CCNZ (neg:SI (match_operand:SI 0 "register_operand" "r")) (const_int 0)))] "" "subcc\t%%g0, %0, %%g0" @@ -5804,7 +5840,7 @@ visl") (define_insn "*cmp_ccxnz_neg" [(set (reg:CCXNZ CC_REG) - (compare:CCXNZ (neg:DI (match_operand:DI 0 "arith_operand" "rI")) + (compare:CCXNZ (neg:DI (match_operand:DI 0 "register_operand" "r")) (const_int 0)))] "TARGET_ARCH64" "subcc\t%%g0, %0, %%g0" @@ -5812,7 +5848,7 @@ visl") (define_insn "*cmp_ccnz_neg_set" [(set (reg:CCNZ CC_REG) - (compare:CCNZ (neg:SI (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCNZ (neg:SI (match_operand:SI 1 "register_operand" "r")) (const_int 0))) (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] @@ -5822,7 +5858,7 @@ visl") (define_insn "*cmp_ccxnz_neg_set" [(set (reg:CCXNZ CC_REG) - (compare:CCXNZ (neg:DI (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXNZ (neg:DI (match_operand:DI 1 "register_operand" "r")) (const_int 0))) (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] @@ -5832,7 +5868,7 @@ visl") (define_insn "*cmp_ccc_neg_set" [(set (reg:CCC CC_REG) - (compare:CCC (not:SI (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCC (not:SI (match_operand:SI 1 "register_operand" "r")) (const_int -1))) (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] @@ -5842,7 +5878,7 @@ visl") (define_insn "*cmp_ccxc_neg_set" [(set (reg:CCXC CC_REG) - (compare:CCXC (not:DI (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXC (not:DI (match_operand:DI 1 "register_operand" "r")) (const_int -1))) (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] @@ -5853,7 +5889,7 @@ visl") (define_insn "*cmp_ccc_neg_sltu_set" [(set (reg:CCC CC_REG) (compare:CCC (zero_extend:DI - (neg:SI (plus:SI (match_operand:SI 1 "arith_operand" "rI") + (neg:SI (plus:SI (match_operand:SI 1 "register_operand" "r") (ltu:SI (reg:CCC CC_REG) (const_int 0))))) (neg:DI (plus:DI (zero_extend:DI (match_dup 1)) @@ -5868,7 +5904,7 @@ visl") (define_insn "*cmp_ccv_neg" [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (match_operand:SI 0 "arith_operand" "rI")) + (compare:CCV (neg:SI (match_operand:SI 0 "register_operand" "r")) (unspec:SI [(match_dup 0)] UNSPEC_NEGV)))] "" "subcc\t%%g0, %0, %%g0" @@ -5876,7 +5912,7 @@ visl") (define_insn "*cmp_ccxv_neg" [(set (reg:CCXV CC_REG) - (compare:CCXV (neg:DI (match_operand:DI 0 "arith_operand" "rI")) + (compare:CCXV (neg:DI (match_operand:DI 0 "register_operand" "r")) (unspec:DI [(match_dup 0)] UNSPEC_NEGV)))] "TARGET_ARCH64" "subcc\t%%g0, %0, %%g0" @@ -5884,7 +5920,7 @@ visl") (define_insn "*cmp_ccv_neg_set" [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (match_operand:SI 1 "arith_operand" "rI")) + (compare:CCV (neg:SI (match_operand:SI 1 "register_operand" "r")) (unspec:SI [(match_dup 1)] UNSPEC_NEGV))) (set (match_operand:SI 0 "register_operand" "=r") (neg:SI (match_dup 1)))] @@ -5894,7 +5930,7 @@ visl") (define_insn "*cmp_ccxv_neg_set" [(set (reg:CCXV CC_REG) - (compare:CCXV (neg:DI (match_operand:DI 1 "arith_operand" "rI")) + (compare:CCXV (neg:DI (match_operand:DI 1 "register_operand" "r")) (unspec:DI [(match_dup 1)] UNSPEC_NEGV))) (set (match_operand:DI 0 "register_operand" "=r") (neg:DI (match_dup 1)))] @@ -5904,7 +5940,7 @@ visl") (define_insn "*cmp_ccv_neg_sltu_set" [(set (reg:CCV CC_REG) - (compare:CCV (neg:SI (plus:SI (match_operand:SI 1 "arith_operand" "rI") + (compare:CCV (neg:SI (plus:SI (match_operand:SI 1 "register_operand" "r") (ltu:SI (reg:CCC CC_REG) (const_int 0)))) (unspec:SI [(plus:SI (match_dup 1) (ltu:SI (reg:CCC CC_REG) -- cgit v1.1 From b3147c02dc772ad77eb7e1d5d6e14a8f222d1e65 Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Tue, 1 Dec 2020 21:12:54 +0100 Subject: Make -fzero-call-used-regs work on the SPARC This contains both a generic fixlet for targets implementing the leaf register optimization (SPARC and Xtensa) and the implementation of the target hook TARGET_ZERO_CALL_USED_REGS which is needed to make this work on the SPARC. gcc/ChangeLog: * function.c (gen_call_used_regs_seq): In a function subject to the leaf register optimization, skip registers that are not present. * config/sparc/sparc.c (TARGET_ZERO_CALL_USED_REGS): Define to... (sparc_zero_call_used_regs): ...this. New function. --- gcc/config/sparc/sparc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'gcc/config/sparc') diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 02138c5..ec0921b 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -708,6 +708,7 @@ static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT); static bool sparc_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx, const vec_perm_indices &); static bool sparc_can_follow_jump (const rtx_insn *, const rtx_insn *); +static HARD_REG_SET sparc_zero_call_used_regs (HARD_REG_SET); #ifdef SUBTARGET_ATTRIBUTE_TABLE /* Table of valid machine attributes. */ @@ -959,6 +960,9 @@ char sparc_hard_reg_printed[8]; #undef TARGET_CAN_FOLLOW_JUMP #define TARGET_CAN_FOLLOW_JUMP sparc_can_follow_jump +#undef TARGET_ZERO_CALL_USED_REGS +#define TARGET_ZERO_CALL_USED_REGS sparc_zero_call_used_regs + struct gcc_target targetm = TARGET_INITIALIZER; /* Return the memory reference contained in X if any, zero otherwise. */ @@ -13810,4 +13814,50 @@ sparc_constant_alignment (const_tree exp, HOST_WIDE_INT align) return align; } +/* Implement TARGET_ZERO_CALL_USED_REGS. + + Generate a sequence of instructions that zero registers specified by + NEED_ZEROED_HARDREGS. Return the ZEROED_HARDREGS that are actually + zeroed. */ + +static HARD_REG_SET +sparc_zero_call_used_regs (HARD_REG_SET need_zeroed_hardregs) +{ + for (unsigned int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (TEST_HARD_REG_BIT (need_zeroed_hardregs, regno)) + { + /* Do not touch the CC registers or the FP registers if no VIS. */ + if (regno >= SPARC_FCC_REG + || (regno >= SPARC_FIRST_FP_REG && !TARGET_VIS)) + CLEAR_HARD_REG_BIT (need_zeroed_hardregs, regno); + + /* Do not access the odd upper FP registers individually. */ + else if (regno >= SPARC_FIRST_V9_FP_REG && (regno & 1)) + ; + + /* Use the most natural mode for the registers, which is not given by + regno_reg_rtx/reg_raw_mode for the FP registers on the SPARC. */ + else + { + machine_mode mode; + rtx reg; + + if (regno < SPARC_FIRST_FP_REG) + { + reg = regno_reg_rtx[regno]; + mode = GET_MODE (reg); + } + else + { + mode = regno < SPARC_FIRST_V9_FP_REG ? SFmode : DFmode; + reg = gen_raw_REG (mode, regno); + } + + emit_move_insn (reg, CONST0_RTX (mode)); + } + } + + return need_zeroed_hardregs; +} + #include "gt-sparc.h" -- cgit v1.1