From ecf9149175ff5ca79b571b4521c307c4c82f7c21 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Fri, 19 Sep 2014 22:14:58 +0000 Subject: [PATCH] backport: predicates.md (fusion_gpr_mem_load): Move testing for base_reg_operand to be common between LO_SUM and PLUS. 2014-09-19 Michael Meissner Back port from trunk: 2014-09-19 Michael Meissner * config/rs6000/predicates.md (fusion_gpr_mem_load): Move testing for base_reg_operand to be common between LO_SUM and PLUS. (fusion_gpr_mem_combo): New predicate to match a fused address that combines the addis and memory offset address. * config/rs6000/rs6000-protos.h (fusion_gpr_load_p): Change calling signature. (emit_fusion_gpr_load): Likewise. * config/rs6000/rs6000.c (fusion_gpr_load_p): Change calling signature to pass each argument separately, rather than using an operands array. Rewrite the insns found by peephole2 to be a single insn, rather than hoping the insns will still be together when the peephole pass is done. Drop being called via a normal peephole. (emit_fusion_gpr_load): Change calling signature to be called from the fusion_gpr_load_ insns with a combined memory address instead of the peephole pass passing the addis and offset separately. * config/rs6000/rs6000.md (UNSPEC_FUSION_GPR): New unspec for GPR fusion. (power8 fusion peephole): Drop support for doing power8 via a normal peephole that was created by the peephole2 pass. (power8 fusion peephole2): Create a new insn with the fused address, so that the fused operation is kept together after register allocation is done. (fusion_gpr_load_): Likewise. From-SVN: r215406 --- gcc/ChangeLog | 34 +++++++++ gcc/config/rs6000/predicates.md | 75 +++++++++++++++++--- gcc/config/rs6000/rs6000-protos.h | 4 +- gcc/config/rs6000/rs6000.c | 110 +++++++++--------------------- gcc/config/rs6000/rs6000.md | 39 +++++------ 5 files changed, 153 insertions(+), 109 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 829448092414..061e79fc0fc9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +2014-09-19 Michael Meissner + + Back port from trunk: + 2014-09-19 Michael Meissner + + * config/rs6000/predicates.md (fusion_gpr_mem_load): Move testing + for base_reg_operand to be common between LO_SUM and PLUS. + (fusion_gpr_mem_combo): New predicate to match a fused address + that combines the addis and memory offset address. + + * config/rs6000/rs6000-protos.h (fusion_gpr_load_p): Change + calling signature. + (emit_fusion_gpr_load): Likewise. + + * config/rs6000/rs6000.c (fusion_gpr_load_p): Change calling + signature to pass each argument separately, rather than + using an operands array. Rewrite the insns found by peephole2 to + be a single insn, rather than hoping the insns will still be + together when the peephole pass is done. Drop being called via a + normal peephole. + (emit_fusion_gpr_load): Change calling signature to be called from + the fusion_gpr_load_ insns with a combined memory address + instead of the peephole pass passing the addis and offset + separately. + + * config/rs6000/rs6000.md (UNSPEC_FUSION_GPR): New unspec for GPR + fusion. + (power8 fusion peephole): Drop support for doing power8 via a + normal peephole that was created by the peephole2 pass. + (power8 fusion peephole2): Create a new insn with the fused + address, so that the fused operation is kept together after + register allocation is done. + (fusion_gpr_load_): Likewise. + 2014-09-17 Jakub Jelinek PR debug/63284 diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index 0659e066eeef..6ee392d837f7 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1795,7 +1795,7 @@ (define_predicate "fusion_gpr_mem_load" (match_code "mem,sign_extend,zero_extend") { - rtx addr; + rtx addr, base, offset; /* Handle sign/zero extend. */ if (GET_CODE (op) == ZERO_EXTEND @@ -1825,24 +1825,79 @@ } addr = XEXP (op, 0); + if (GET_CODE (addr) != PLUS && GET_CODE (addr) != LO_SUM) + return 0; + + base = XEXP (addr, 0); + if (!base_reg_operand (base, GET_MODE (base))) + return 0; + + offset = XEXP (addr, 1); + if (GET_CODE (addr) == PLUS) + return satisfies_constraint_I (offset); + + else if (GET_CODE (addr) == LO_SUM) { - rtx base = XEXP (addr, 0); - rtx offset = XEXP (addr, 1); + if (TARGET_XCOFF || (TARGET_ELF && TARGET_POWERPC64)) + return small_toc_ref (offset, GET_MODE (offset)); - return (base_reg_operand (base, GET_MODE (base)) - && satisfies_constraint_I (offset)); + else if (TARGET_ELF && !TARGET_POWERPC64) + return CONSTANT_P (offset); } - else if (GET_CODE (addr) == LO_SUM) + return 0; +}) + +;; Match a GPR load (lbz, lhz, lwz, ld) that uses a combined address in the +;; memory field with both the addis and the memory offset. Sign extension +;; is not handled here, since lha and lwa are not fused. +(define_predicate "fusion_gpr_mem_combo" + (match_code "mem,zero_extend") +{ + rtx addr, base, offset; + + /* Handle zero extend. */ + if (GET_CODE (op) == ZERO_EXTEND) { - rtx base = XEXP (addr, 0); - rtx offset = XEXP (addr, 1); + op = XEXP (op, 0); + mode = GET_MODE (op); + } + + if (!MEM_P (op)) + return 0; - if (!base_reg_operand (base, GET_MODE (base))) + switch (mode) + { + case QImode: + case HImode: + case SImode: + break; + + case DImode: + if (!TARGET_POWERPC64) return 0; + break; - else if (TARGET_XCOFF || (TARGET_ELF && TARGET_POWERPC64)) + default: + return 0; + } + + addr = XEXP (op, 0); + if (GET_CODE (addr) != PLUS && GET_CODE (addr) != LO_SUM) + return 0; + + base = XEXP (addr, 0); + if (!fusion_gpr_addis (base, GET_MODE (base))) + return 0; + + offset = XEXP (addr, 1); + if (GET_CODE (addr) == PLUS) + return satisfies_constraint_I (offset); + + else if (GET_CODE (addr) == LO_SUM) + { + if (TARGET_XCOFF || (TARGET_ELF && TARGET_POWERPC64)) return small_toc_ref (offset, GET_MODE (offset)); else if (TARGET_ELF && !TARGET_POWERPC64) diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 02d2c3bd7270..5db8b28fec5c 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -79,9 +79,9 @@ extern int mems_ok_for_quad_peep (rtx, rtx); extern bool gpr_or_gpr_p (rtx, rtx); extern bool direct_move_p (rtx, rtx); extern bool quad_load_store_p (rtx, rtx); -extern bool fusion_gpr_load_p (rtx *, bool); +extern bool fusion_gpr_load_p (rtx, rtx, rtx, rtx); extern void expand_fusion_gpr_load (rtx *); -extern const char *emit_fusion_gpr_load (rtx *); +extern const char *emit_fusion_gpr_load (rtx, rtx); extern enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx, enum reg_class); extern enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class, diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 72fe69bc91ca..ed2df70a61ec 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -32833,25 +32833,14 @@ rs6000_split_logical (rtx operands[3], /* Return true if the peephole2 can combine a load involving a combination of an addis instruction and a load with an offset that can be fused together on - a power8. - - The operands are: - operands[0] register set with addis - operands[1] value set via addis - operands[2] target register being loaded - operands[3] D-form memory reference using operands[0]. - - In addition, we are passed a boolean that is true if this is a peephole2, - and we can use see if the addis_reg is dead after the insn and can be - replaced by the target register. */ + a power8. */ bool -fusion_gpr_load_p (rtx *operands, bool peep2_p) +fusion_gpr_load_p (rtx addis_reg, /* register set via addis. */ + rtx addis_value, /* addis value. */ + rtx target, /* target register that is loaded. */ + rtx mem) /* bottom part of the memory addr. */ { - rtx addis_reg = operands[0]; - rtx addis_value = operands[1]; - rtx target = operands[2]; - rtx mem = operands[3]; rtx addr; rtx base_reg; @@ -32865,9 +32854,6 @@ fusion_gpr_load_p (rtx *operands, bool peep2_p) if (!fusion_gpr_addis (addis_value, GET_MODE (addis_value))) return false; - if (!fusion_gpr_mem_load (mem, GET_MODE (mem))) - return false; - /* Allow sign/zero extension. */ if (GET_CODE (mem) == ZERO_EXTEND || (GET_CODE (mem) == SIGN_EXTEND && TARGET_P8_FUSION_SIGN)) @@ -32876,22 +32862,22 @@ fusion_gpr_load_p (rtx *operands, bool peep2_p) if (!MEM_P (mem)) return false; + if (!fusion_gpr_mem_load (mem, GET_MODE (mem))) + return false; + addr = XEXP (mem, 0); /* either PLUS or LO_SUM. */ if (GET_CODE (addr) != PLUS && GET_CODE (addr) != LO_SUM) return false; /* Validate that the register used to load the high value is either the - register being loaded, or we can safely replace its use in a peephole2. + register being loaded, or we can safely replace its use. - If this is a peephole2, we assume that there are 2 instructions in the - peephole (addis and load), so we want to check if the target register was - not used in the memory address and the register to hold the addis result - is dead after the peephole. */ + This function is only called from the peephole2 pass and we assume that + there are 2 instructions in the peephole (addis and load), so we want to + check if the target register was not used in the memory address and the + register to hold the addis result is dead after the peephole. */ if (REGNO (addis_reg) != REGNO (target)) { - if (!peep2_p) - return false; - if (reg_mentioned_p (target, mem)) return false; @@ -32932,9 +32918,6 @@ expand_fusion_gpr_load (rtx *operands) enum machine_mode extend_mode = target_mode; enum machine_mode ptr_mode = Pmode; enum rtx_code extend = UNKNOWN; - rtx addis_reg = ((ptr_mode == target_mode) - ? target - : simplify_subreg (ptr_mode, target, target_mode, 0)); if (GET_CODE (orig_mem) == ZERO_EXTEND || (TARGET_P8_FUSION_SIGN && GET_CODE (orig_mem) == SIGN_EXTEND)) @@ -32951,13 +32934,14 @@ expand_fusion_gpr_load (rtx *operands) gcc_assert (plus_or_lo_sum == PLUS || plus_or_lo_sum == LO_SUM); offset = XEXP (orig_addr, 1); - new_addr = gen_rtx_fmt_ee (plus_or_lo_sum, ptr_mode, addis_reg, offset); - new_mem = change_address (orig_mem, target_mode, new_addr); + new_addr = gen_rtx_fmt_ee (plus_or_lo_sum, ptr_mode, addis_value, offset); + new_mem = replace_equiv_address_nv (orig_mem, new_addr); if (extend != UNKNOWN) new_mem = gen_rtx_fmt_e (ZERO_EXTEND, extend_mode, new_mem); - emit_insn (gen_rtx_SET (VOIDmode, addis_reg, addis_value)); + new_mem = gen_rtx_UNSPEC (extend_mode, gen_rtvec (1, new_mem), + UNSPEC_FUSION_GPR); emit_insn (gen_rtx_SET (VOIDmode, target, new_mem)); if (extend == SIGN_EXTEND) @@ -32976,55 +32960,40 @@ expand_fusion_gpr_load (rtx *operands) } /* Return a string to fuse an addis instruction with a gpr load to the same - register that we loaded up the addis instruction. The code is complicated, - so we call output_asm_insn directly, and just return "". + register that we loaded up the addis instruction. The address that is used + is the logical address that was formed during peephole2: + (lo_sum (high) (low-part)) - The operands are: - operands[0] register set with addis (must be same reg as target). - operands[1] value set via addis - operands[2] target register being loaded - operands[3] D-form memory reference using operands[0]. */ + The code is complicated, so we call output_asm_insn directly, and just + return "". */ const char * -emit_fusion_gpr_load (rtx *operands) +emit_fusion_gpr_load (rtx target, rtx mem) { - rtx addis_reg = operands[0]; - rtx addis_value = operands[1]; - rtx target = operands[2]; - rtx mem = operands[3]; + rtx addis_value; rtx fuse_ops[10]; rtx addr; rtx load_offset; const char *addis_str = NULL; const char *load_str = NULL; - const char *extend_insn = NULL; const char *mode_name = NULL; char insn_template[80]; enum machine_mode mode; const char *comment_str = ASM_COMMENT_START; - bool sign_p = false; - - gcc_assert (REG_P (addis_reg) && REG_P (target)); - gcc_assert (REGNO (addis_reg) == REGNO (target)); - - if (*comment_str == ' ') - comment_str++; - /* Allow sign/zero extension. */ if (GET_CODE (mem) == ZERO_EXTEND) mem = XEXP (mem, 0); - else if (GET_CODE (mem) == SIGN_EXTEND && TARGET_P8_FUSION_SIGN) - { - sign_p = true; - mem = XEXP (mem, 0); - } + gcc_assert (REG_P (target) && MEM_P (mem)); + + if (*comment_str == ' ') + comment_str++; - gcc_assert (MEM_P (mem)); addr = XEXP (mem, 0); if (GET_CODE (addr) != PLUS && GET_CODE (addr) != LO_SUM) gcc_unreachable (); + addis_value = XEXP (addr, 0); load_offset = XEXP (addr, 1); /* Now emit the load instruction to the same register. */ @@ -33034,29 +33003,22 @@ emit_fusion_gpr_load (rtx *operands) case QImode: mode_name = "char"; load_str = "lbz"; - extend_insn = "extsb %0,%0"; break; case HImode: mode_name = "short"; load_str = "lhz"; - extend_insn = "extsh %0,%0"; break; case SImode: mode_name = "int"; load_str = "lwz"; - extend_insn = "extsw %0,%0"; break; case DImode: - if (TARGET_POWERPC64) - { - mode_name = "long"; - load_str = "ld"; - } - else - gcc_unreachable (); + gcc_assert (TARGET_POWERPC64); + mode_name = "long"; + load_str = "ld"; break; default: @@ -33200,14 +33162,6 @@ emit_fusion_gpr_load (rtx *operands) else fatal_insn ("Unable to generate load offset for fusion", load_offset); - /* Handle sign extension. The peephole2 pass generates this as a separate - insn, but we handle it just in case it got reattached. */ - if (sign_p) - { - gcc_assert (extend_insn != NULL); - output_asm_insn (extend_insn, fuse_ops); - } - return ""; } diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 8b2b769ee556..ccb24368cbd8 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -134,6 +134,7 @@ UNSPEC_UNPACK_128BIT UNSPEC_PACK_128BIT UNSPEC_LSQ + UNSPEC_FUSION_GPR ]) ;; @@ -15753,22 +15754,9 @@ ;; a GPR. The addis instruction must be adjacent to the load, and use the same ;; register that is being loaded. The fused ops must be physically adjacent. -;; We use define_peephole for the actual addis/load, and the register used to -;; hold the addis value must be the same as the register being loaded. We use -;; define_peephole2 to change the register used for addis to be the register -;; being loaded, since we can look at whether it is dead after the load insn. - -(define_peephole - [(set (match_operand:P 0 "base_reg_operand" "") - (match_operand:P 1 "fusion_gpr_addis" "")) - (set (match_operand:INT1 2 "base_reg_operand" "") - (match_operand:INT1 3 "fusion_gpr_mem_load" ""))] - "TARGET_P8_FUSION && fusion_gpr_load_p (operands, false)" -{ - return emit_fusion_gpr_load (operands); -} - [(set_attr "type" "load") - (set_attr "length" "8")]) +;; Find cases where the addis that feeds into a load instruction is either used +;; once or is the same as the target register, and replace it with the fusion +;; insn (define_peephole2 [(set (match_operand:P 0 "base_reg_operand" "") @@ -15776,15 +15764,28 @@ (set (match_operand:INT1 2 "base_reg_operand" "") (match_operand:INT1 3 "fusion_gpr_mem_load" ""))] "TARGET_P8_FUSION - && (REGNO (operands[0]) != REGNO (operands[2]) - || GET_CODE (operands[3]) == SIGN_EXTEND) - && fusion_gpr_load_p (operands, true)" + && fusion_gpr_load_p (operands[0], operands[1], operands[2], + operands[3])" [(const_int 0)] { expand_fusion_gpr_load (operands); DONE; }) +;; Fusion insn, created by the define_peephole2 above (and eventually by +;; reload) + +(define_insn "fusion_gpr_load_" + [(set (match_operand:INT1 0 "base_reg_operand" "=&b") + (unspec:INT1 [(match_operand:INT1 1 "fusion_gpr_mem_combo" "")] + UNSPEC_FUSION_GPR))] + "TARGET_P8_FUSION" +{ + return emit_fusion_gpr_load (operands[0], operands[1]); +} + [(set_attr "type" "load") + (set_attr "length" "8")]) + ;; Miscellaneous ISA 2.06 (power7) instructions (define_insn "addg6s" -- 2.47.2