From 512d9edf00e8663acd7346a64c2f24a125cd47b1 Mon Sep 17 00:00:00 2001 From: krebbel Date: Fri, 27 Feb 2009 14:56:19 +0000 Subject: [PATCH] 2009-02-27 Andreas Krebbel * gcc/config/s390/s390.c: (s390_swap_cmp): Look for conditional jumps if COND is NULL. (find_cond_jump): New function. (s390_z10_optimize_cmp): Handling for reg-reg compares added. * gcc/config/s390/s390.md: Remove z10_cobra attribute value. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@144466 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 8 +++ gcc/config/s390/s390.c | 187 +++++++++++++++++++++++++++++++++--------------- gcc/config/s390/s390.md | 11 ++- 3 files changed, 144 insertions(+), 62 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9aef9cb..27ccf26 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2009-02-27 Andreas Krebbel + + * gcc/config/s390/s390.c: (s390_swap_cmp): Look for conditional + jumps if COND is NULL. + (find_cond_jump): New function. + (s390_z10_optimize_cmp): Handling for reg-reg compares added. + * gcc/config/s390/s390.md: Remove z10_cobra attribute value. + 2009-02-26 Uros Bizjak * config/alpha/alpha.h (alpha_expand_mov): Return false if diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index 7ad230e..eb08828 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -9589,21 +9589,6 @@ s390_optimize_prologue (void) } } - -/* Exchange the two operands of COND, and swap its mask so that the - semantics does not change. */ -static void -s390_swap_cmp (rtx cond) -{ - enum rtx_code code = swap_condition (GET_CODE (cond)); - rtx tmp = XEXP (cond, 0); - - XEXP (cond, 0) = XEXP (cond, 1); - XEXP (cond, 1) = tmp; - PUT_CODE (cond, code); -} - - /* Returns 1 if INSN reads the value of REG for purposes not related to addressing of memory, and 0 otherwise. */ static int @@ -9613,6 +9598,71 @@ s390_non_addr_reg_read_p (rtx reg, rtx insn) && !reg_used_in_mem_p (REGNO (reg), PATTERN (insn)); } +/* Starting from INSN find_cond_jump looks downwards in the insn + stream for a single jump insn which is the last user of the + condition code set in INSN. */ +static rtx +find_cond_jump (rtx insn) +{ + for (; insn; insn = NEXT_INSN (insn)) + { + rtx ite, cc; + + if (LABEL_P (insn)) + break; + + if (!JUMP_P (insn)) + { + if (reg_mentioned_p (gen_rtx_REG (CCmode, CC_REGNUM), insn)) + break; + continue; + } + + /* This will be triggered by a return. */ + if (GET_CODE (PATTERN (insn)) != SET) + break; + + gcc_assert (SET_DEST (PATTERN (insn)) == pc_rtx); + ite = SET_SRC (PATTERN (insn)); + + if (GET_CODE (ite) != IF_THEN_ELSE) + break; + + cc = XEXP (XEXP (ite, 0), 0); + if (!REG_P (cc) || !CC_REGNO_P (REGNO (cc))) + break; + + if (find_reg_note (insn, REG_DEAD, cc)) + return insn; + break; + } + + return NULL_RTX; +} + +/* Swap the condition in COND and the operands in OP0 and OP1 so that + the semantics does not change. If NULL_RTX is passed as COND the + function tries to find the conditional jump starting with INSN. */ +static void +s390_swap_cmp (rtx cond, rtx *op0, rtx *op1, rtx insn) +{ + rtx tmp = *op0; + + if (cond == NULL_RTX) + { + rtx jump = find_cond_jump (NEXT_INSN (insn)); + jump = jump ? single_set (jump) : NULL_RTX; + + if (jump == NULL_RTX) + return; + + cond = XEXP (XEXP (jump, 1), 0); + } + + *op0 = *op1; + *op1 = tmp; + PUT_CODE (cond, swap_condition (GET_CODE (cond))); +} /* On z10, instructions of the compare-and-branch family have the property to access the register occurring as second operand with @@ -9622,7 +9672,7 @@ s390_non_addr_reg_read_p (rtx reg, rtx insn) pipeline recycles, thereby causing significant performance decline. This function locates such situations and exchanges the two operands of the compare. */ -static void +static void s390_z10_optimize_cmp (void) { rtx insn, prev_insn, next_insn; @@ -9630,54 +9680,79 @@ s390_z10_optimize_cmp (void) for (insn = get_insns (); insn; insn = NEXT_INSN (insn)) { + rtx cond, *op0, *op1; + if (!INSN_P (insn) || INSN_CODE (insn) <= 0) continue; - if (get_attr_z10prop (insn) == Z10PROP_Z10_COBRA) + if (GET_CODE (PATTERN (insn)) == PARALLEL) { - rtx op0, op1, pattern, jump_expr, cond; + /* Handle compare and branch and branch on count + instructions. */ + rtx pattern = single_set (insn); - /* Extract the comparison´s condition and its operands. */ - pattern = single_set (insn); - gcc_assert (GET_CODE (pattern) == SET); - jump_expr = XEXP (pattern, 1); - gcc_assert (GET_CODE (jump_expr) == IF_THEN_ELSE); - cond = XEXP (jump_expr, 0); - op0 = XEXP (cond, 0); - op1 = XEXP (cond, 1); + if (!pattern + || SET_DEST (pattern) != pc_rtx + || GET_CODE (SET_SRC (pattern)) != IF_THEN_ELSE) + continue; - /* Swap the COMPARE´s arguments and its mask if there is a - conflicting access in the previous insn. */ - prev_insn = PREV_INSN (insn); - if (prev_insn != NULL_RTX && INSN_P (prev_insn) - && reg_referenced_p (op1, PATTERN (prev_insn))) - { - s390_swap_cmp (cond); - op0 = XEXP (cond, 0); - op1 = XEXP (cond, 1); - } + cond = XEXP (SET_SRC (pattern), 0); + op0 = &XEXP (cond, 0); + op1 = &XEXP (cond, 1); + } + else if (GET_CODE (PATTERN (insn)) == SET) + { + rtx src, dest; - /* Check if there is a conflict with the next insn. If there - was no conflict with the previous insn, then swap the - COMPARE´s arguments and its mask. If we already swapped - the operands, or if swapping them would cause a conflict - with the previous insn, issue a NOP after the COMPARE in - order to separate the two instuctions. */ - next_insn = NEXT_INSN (insn); - if (next_insn != NULL_RTX && INSN_P (next_insn) - && s390_non_addr_reg_read_p (op1, next_insn)) - { - if (s390_non_addr_reg_read_p (op0, prev_insn)) - { - if (REGNO(op1) == 0) - emit_insn_after (gen_nop1 (), insn); - else - emit_insn_after (gen_nop (), insn); - added_NOPs = 1; - } + /* Handle normal compare instructions. */ + src = SET_SRC (PATTERN (insn)); + dest = SET_DEST (PATTERN (insn)); + + if (!REG_P (dest) + || !CC_REGNO_P (REGNO (dest)) + || GET_CODE (src) != COMPARE) + continue; + + /* s390_swap_cmp will try to find the conditional + jump when passing NULL_RTX as condition. */ + cond = NULL_RTX; + op0 = &XEXP (src, 0); + op1 = &XEXP (src, 1); + } + else + continue; + + if (!REG_P (*op0) || !REG_P (*op1)) + continue; + + /* Swap the COMPARE arguments and its mask if there is a + conflicting access in the previous insn. */ + prev_insn = PREV_INSN (insn); + if (prev_insn != NULL_RTX && INSN_P (prev_insn) + && reg_referenced_p (*op1, PATTERN (prev_insn))) + s390_swap_cmp (cond, op0, op1, insn); + + /* Check if there is a conflict with the next insn. If there + was no conflict with the previous insn, then swap the + COMPARE arguments and its mask. If we already swapped + the operands, or if swapping them would cause a conflict + with the previous insn, issue a NOP after the COMPARE in + order to separate the two instuctions. */ + next_insn = NEXT_INSN (insn); + if (next_insn != NULL_RTX && INSN_P (next_insn) + && s390_non_addr_reg_read_p (*op1, next_insn)) + { + if (prev_insn != NULL_RTX && INSN_P (prev_insn) + && s390_non_addr_reg_read_p (*op0, prev_insn)) + { + if (REGNO (*op1) == 0) + emit_insn_after (gen_nop1 (), insn); else - s390_swap_cmp (cond); + emit_insn_after (gen_nop (), insn); + added_NOPs = 1; } + else + s390_swap_cmp (cond, op0, op1, insn); } } @@ -9799,7 +9874,7 @@ s390_reorg (void) /* Eliminate z10-specific pipeline recycles related to some compare instructions. */ - if (TARGET_Z10) + if (s390_tune == PROCESSOR_2097_Z10) s390_z10_optimize_cmp (); } diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index 3d628d8..7ecc3cc 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -235,7 +235,6 @@ ;; can immediately read the new value. ;; z10_fr: union of Z10_fwd and z10_rec. ;; z10_c: second operand of instruction is a register and read with complemented bits. -;; z10_cobra: its a compare and branch instruction ;; ;; An additional suffix A1, A3, or E1 indicates the respective AGI bypass. @@ -245,7 +244,7 @@ z10_fwd, z10_fwd_A1, z10_fwd_A3, z10_fwd_E1, z10_rec, z10_fr, z10_fr_A3, z10_fr_E1, - z10_c, z10_cobra" + z10_c" (const_string "none")) @@ -774,7 +773,7 @@ cy\t%0,%1 #" [(set_attr "op_type" "RR,RI,RIL,RX,RXY,SS") - (set_attr "z10prop" "z10_super,z10_super,z10_super,z10_super,z10_super,*")]) + (set_attr "z10prop" "z10_super_c,z10_super,z10_super,z10_super,z10_super,*")]) ; Compare (signed) instructions @@ -1043,7 +1042,7 @@ } [(set_attr "op_type" "RIE") (set_attr "type" "branch") - (set_attr "z10prop" "z10_cobra,z10_super") + (set_attr "z10prop" "z10_super_c,z10_super") (set (attr "length") (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) (const_int 6) (const_int 12)))]) ; 8 byte for cr/jg @@ -1071,7 +1070,7 @@ } [(set_attr "op_type" "RIE") (set_attr "type" "branch") - (set_attr "z10prop" "z10_cobra,z10_super") + (set_attr "z10prop" "z10_super_c,z10_super") (set (attr "length") (if_then_else (lt (abs (minus (pc) (match_dup 3))) (const_int 60000)) (const_int 6) (const_int 12)))]) ; 8 byte for clr/jg @@ -7679,7 +7678,7 @@ (const_string "RR") (const_string "RX"))) (set_attr "type" "branch") (set_attr "atype" "agen") - (set_attr "z10prop" "z10_cobra")]) + (set_attr "z10prop" "z10_c")]) (define_insn_and_split "doloop_di" [(set (pc) -- 2.7.4