diff options
34 files changed, 239 insertions, 224 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9387646a7a0..f91e443e88b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,47 @@ +2013-11-09 Richard Sandiford <rdsandiford@googlemail.com> + + * target.def (can_use_doloop_p): New hook. + * doc/tm.texi.in (TARGET_CAN_USE_DOLOOP_P): Add. + * doc/tm.texi: Regenerate. + * doc/md.texi (doloop_begin, doloop_end): Update documentation. + * hooks.h (hook_bool_dint_dint_uint_true): Declare. + * hooks.c (hook_bool_dint_dint_uint_true): New function. + * targhooks.h (can_use_doloop_if_innermost): Declare. + * targhooks.c (can_use_doloop_if_innermost): New function. + * target.h: Include double-int.h. + * loop-doloop.c (doloop_optimize): Call targetm.can_use_doloop_p. + Remove iteration count, maximum iteration count, loop depth and + enter-at-top inputs from doloop_begin and doloop_end. + * config/arc/arc.md (doloop_begin, doloop_end): Update for new + interface. + * config/arc/arc.c (arc_can_use_doloop_p): New function. + (TARGET_CAN_USE_DOLOOP_P): Define. + * config/arm/thumb2.md (doloop_end): Update for new interface. + * config/arm/arm.c (TARGET_CAN_USE_DOLOOP_P): Define. + * config/bfin/bfin.md (doloop_end): Update for new interface. + * config/bfin/bfin.c (bfin_can_use_doloop_p): New function. + (TARGET_CAN_USE_DOLOOP_P): Define. + * config/c6x/c6x.md (doloop_end): Update for new interface. + * config/ia64/ia64.md (doloop_end): Update for new interface. + * config/ia64/ia64.c (TARGET_CAN_USE_DOLOOP_P): Define. + * config/mep/mep.md (doloop_begin, doloop_end): Update for new + interface. + * config/mep/mep.c (mep_emit_doloop): Likewise. + (TARGET_CAN_USE_DOLOOP_P): Define. + * config/rs6000/rs6000.md (doloop_end): Update for new interface. + * config/rs6000/rs6000.c (TARGET_CAN_USE_DOLOOP_P): Define. + * config/s390/s390.md (doloop_end): Update for new interface. + * config/sh/sh.md (doloop_end): Likewise. + * config/spu/spu.md (doloop_end): Likewise. + * config/spu/spu.c (TARGET_CAN_USE_DOLOOP_P): Define. + * config/tilegx/tilegx.md (doloop_end): Update for new interface. + * config/tilegx/tilegx.c (TARGET_CAN_USE_DOLOOP_P): Define. + * config/tilepro/tilepro.md (doloop_end): Update for new interface. + * config/tilepro/tilepro.c (TARGET_CAN_USE_DOLOOP_P): Define. + * config/v850/v850.md (doloop_begin, doloop_end): Update for new + interface. + * config/v850/v850.c (TARGET_CAN_USE_DOLOOP_P): Define. + 2013-11-08 H.J. Lu <hongjiu.lu@intel.com> PR other/59055 diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c index 1e0c25e833d..7b1853b7f9b 100644 --- a/gcc/config/arc/arc.c +++ b/gcc/config/arc/arc.c @@ -388,6 +388,7 @@ static bool arc_return_in_memory (const_tree, const_tree); static void arc_init_simd_builtins (void); static bool arc_vector_mode_supported_p (enum machine_mode); +static bool arc_can_use_doloop_p (double_int, double_int, unsigned int, bool); static const char *arc_invalid_within_doloop (const_rtx); static void output_short_suffix (FILE *file); @@ -493,6 +494,9 @@ static void arc_finalize_pic (void); #undef TARGET_VECTOR_MODE_SUPPORTED_P #define TARGET_VECTOR_MODE_SUPPORTED_P arc_vector_mode_supported_p +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P arc_can_use_doloop_p + #undef TARGET_INVALID_WITHIN_DOLOOP #define TARGET_INVALID_WITHIN_DOLOOP arc_invalid_within_doloop @@ -5638,6 +5642,23 @@ arc_pass_by_reference (cumulative_args_t ca_v ATTRIBUTE_UNUSED, || TREE_ADDRESSABLE (type))); } +/* Implement TARGET_CAN_USE_DOLOOP_P. */ + +static bool +arc_can_use_doloop_p (double_int iterations, double_int, + unsigned int loop_depth, bool entered_at_top) +{ + if (loop_depth > 1) + return false; + /* Setting up the loop with two sr instructions costs 6 cycles. */ + if (TARGET_ARC700 + && !entered_at_top + && iterations.high == 0 + && iterations.low > 0 + && iterations.low <= (flag_pic ? 6 : 3)) + return false; + return true; +} /* NULL if INSN insn is valid within a low-overhead loop. Otherwise return why doloop cannot be applied. */ diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md index aa8243a8c83..baf347876be 100644 --- a/gcc/config/arc/arc.md +++ b/gcc/config/arc/arc.md @@ -4706,16 +4706,10 @@ }) ; operand 0 is the loop count pseudo register -; operand 1 is the number of loop iterations or 0 if it is unknown -; operand 2 is the maximum number of loop iterations -; operand 3 is the number of levels of enclosed loops -; operand 4 is the loop end pattern +; operand 1 is the loop end pattern (define_expand "doloop_begin" [(use (match_operand 0 "register_operand" "")) - (use (match_operand:QI 1 "const_int_operand" "")) - (use (match_operand:QI 2 "const_int_operand" "")) - (use (match_operand:QI 3 "const_int_operand" "")) - (use (match_operand 4 "" ""))] + (use (match_operand 1 "" ""))] "" { /* Using the INSN_UID of the loop end pattern to identify it causes @@ -4725,10 +4719,8 @@ still be able to tell what kind of number this is. */ static HOST_WIDE_INT loop_end_id = 0; - if (INTVAL (operands[3]) > 1) - FAIL; rtx id = GEN_INT (--loop_end_id); - XEXP (XVECEXP (PATTERN (operands[4]), 0, 4), 0) = id; + XEXP (XVECEXP (PATTERN (operands[1]), 0, 4), 0) = id; emit_insn (gen_doloop_begin_i (operands[0], const0_rtx, id, const0_rtx, const0_rtx)); DONE; @@ -4907,11 +4899,7 @@ ) ; operand 0 is the loop count pseudo register -; operand 1 is the number of loop iterations or 0 if it is unknown -; operand 2 is the maximum number of loop iterations -; operand 3 is the number of levels of enclosed loops -; operand 4 is the label to jump to at the top of the loop -; operand 5 is nonzero if the loop is entered at its top. +; operand 1 is the label to jump to at the top of the loop ; Use this for the ARC600 and ARC700. For ARCtangent-A5, this is unsafe ; without further checking for nearby branches etc., and without proper ; annotation of shift patterns that clobber lp_count @@ -4919,24 +4907,14 @@ ; single insn - loop setup is expensive then. (define_expand "doloop_end" [(use (match_operand 0 "register_operand" "")) - (use (match_operand:QI 1 "const_int_operand" "")) - (use (match_operand:QI 2 "const_int_operand" "")) - (use (match_operand:QI 3 "const_int_operand" "")) - (use (label_ref (match_operand 4 "" ""))) - (use (match_operand:QI 5 "const_int_operand" ""))] + (use (label_ref (match_operand 1 "" "")))] "TARGET_ARC600 || TARGET_ARC700" { - if (INTVAL (operands[3]) > 1) - FAIL; - /* Setting up the loop with two sr isntructions costs 6 cycles. */ - if (TARGET_ARC700 && !INTVAL (operands[5]) - && INTVAL (operands[1]) && INTVAL (operands[1]) <= (flag_pic ? 6 : 3)) - FAIL; /* We could do smaller bivs with biv widening, and wider bivs by having a high-word counter in an outer loop - but punt on this for now. */ if (GET_MODE (operands[0]) != SImode) FAIL; - emit_jump_insn (gen_doloop_end_i (operands[0], operands[4], const0_rtx)); + emit_jump_insn (gen_doloop_end_i (operands[0], operands[1], const0_rtx)); DONE; }) diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 930bdf67826..acb1c166e77 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -667,6 +667,8 @@ static const struct attribute_spec arm_attribute_table[] = #undef MAX_INSN_PER_IT_BLOCK #define MAX_INSN_PER_IT_BLOCK (arm_restrict_it ? 1 : 4) +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md index 3b5944a014a..b8b49fe7aee 100644 --- a/gcc/config/arm/thumb2.md +++ b/gcc/config/arm/thumb2.md @@ -1449,11 +1449,7 @@ ;; knows what to generate. (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" "")) ; label - (use (match_operand 5 "" ""))] ; flag: 1 if loop entered at top, else 0 + (use (match_operand 1 "" ""))] ; label "TARGET_32BIT" " { @@ -1472,10 +1468,6 @@ rtx insn; rtx cmp; - /* Only use this on innermost loops. */ - if (INTVAL (operands[3]) > 1) - FAIL; - if (GET_MODE (operands[0]) != SImode) FAIL; @@ -1488,7 +1480,7 @@ cmp = XVECEXP (PATTERN (insn), 0, 0); cc_reg = SET_DEST (cmp); bcomp = gen_rtx_NE (VOIDmode, cc_reg, const0_rtx); - loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]); emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, loc_ref, pc_rtx))); diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c index 558f4c18bef..bd677f88bab 100644 --- a/gcc/config/bfin/bfin.c +++ b/gcc/config/bfin/bfin.c @@ -3366,6 +3366,22 @@ find_prev_insn_start (rtx insn) return insn; } +/* Implement TARGET_CAN_USE_DOLOOP_P. */ + +static bool +bfin_can_use_doloop_p (double_int, double_int iterations_max, + unsigned int, bool) +{ + /* Due to limitations in the hardware (an initial loop count of 0 + does not loop 2^32 times) we must avoid to generate a hardware + loops when we cannot rule out this case. */ + if (!flag_unsafe_loop_optimizations + && (iterations_max.high != 0 + || iterations_max.low >= 0xFFFFFFFF)) + return false; + return true; +} + /* Increment the counter for the number of loop instructions in the current function. */ @@ -5810,4 +5826,7 @@ bfin_conditional_register_usage (void) #undef TARGET_DELAY_VARTRACK #define TARGET_DELAY_VARTRACK true +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P bfin_can_use_doloop_p + struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/bfin/bfin.md b/gcc/config/bfin/bfin.md index 278ac602b09..e3bc6363f4a 100644 --- a/gcc/config/bfin/bfin.md +++ b/gcc/config/bfin/bfin.md @@ -1929,35 +1929,25 @@ ;; Hardware loop ; operand 0 is the loop count pseudo register -; operand 1 is the number of loop iterations or 0 if it is unknown -; operand 2 is the maximum number of loop iterations -; operand 3 is the number of levels of enclosed loops -; operand 4 is the label to jump to at the top of the loop -; operand 5 indicates if the loop is entered at the top +; operand 1 is the label to jump to at the top of the loop (define_expand "doloop_end" [(parallel [(set (pc) (if_then_else (ne (match_operand:SI 0 "" "") (const_int 1)) - (label_ref (match_operand 4 "" "")) + (label_ref (match_operand 1 "" "")) (pc))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) (unspec [(const_int 0)] UNSPEC_LSETUP_END) - (clobber (match_operand 5 ""))])] ; match_scratch + (clobber (match_dup 2))])] ; match_scratch "" { /* The loop optimizer doesn't check the predicates... */ if (GET_MODE (operands[0]) != SImode) FAIL; - /* Due to limitations in the hardware (an initial loop count of 0 - does not loop 2^32 times) we must avoid to generate a hardware - loops when we cannot rule out this case. */ - if (!flag_unsafe_loop_optimizations - && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 0xFFFFFFFF) - FAIL; bfin_hardware_loop (); - operands[5] = gen_rtx_SCRATCH (SImode); + operands[2] = gen_rtx_SCRATCH (SImode); }) (define_insn "loop_end" diff --git a/gcc/config/c6x/c6x.md b/gcc/config/c6x/c6x.md index e1c6f9aabab..d7606965cde 100644 --- a/gcc/config/c6x/c6x.md +++ b/gcc/config/c6x/c6x.md @@ -1421,27 +1421,23 @@ ;; ------------------------------------------------------------------------- ; operand 0 is the loop count pseudo register -; operand 1 is the number of loop iterations or 0 if it is unknown -; operand 2 is the maximum number of loop iterations -; operand 3 is the number of levels of enclosed loops -; operand 4 is the label to jump to at the top of the loop -; operand 5 indicates if the loop is entered at the top +; operand 1 is the label to jump to at the top of the loop (define_expand "doloop_end" [(parallel [(set (pc) (if_then_else (ne (match_operand:SI 0 "" "") (const_int 1)) - (label_ref (match_operand 4 "" "")) + (label_ref (match_operand 1 "" "")) (pc))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) - (clobber (match_operand 5 ""))])] ; match_scratch + (clobber (match_dup 2))])] ; match_scratch "TARGET_INSNS_64PLUS && optimize" { /* The loop optimizer doesn't check the predicates... */ if (GET_MODE (operands[0]) != SImode) FAIL; - operands[5] = gen_rtx_SCRATCH (SImode); + operands[2] = gen_rtx_SCRATCH (SImode); }) (define_insn "mvilc" diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 971fe2f8189..1bf3e2fe928 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -620,6 +620,8 @@ static const struct attribute_spec ia64_attribute_table[] = #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT ia64_trampoline_init +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost #undef TARGET_INVALID_WITHIN_DOLOOP #define TARGET_INVALID_WITHIN_DOLOOP hook_constcharptr_const_rtx_null diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md index a26774d7a07..4d9d4e0129f 100644 --- a/gcc/config/ia64/ia64.md +++ b/gcc/config/ia64/ia64.md @@ -3956,18 +3956,11 @@ (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" "")) ; label - (use (match_operand 5 "" ""))] ; flag: 1 if loop entered at top, else 0 + (use (match_operand 1 "" ""))] ; label "" { - /* Only use cloop on innermost loops. */ - if (INTVAL (operands[3]) > 1) - FAIL; emit_jump_insn (gen_doloop_end_internal (gen_rtx_REG (DImode, AR_LC_REGNUM), - operands[4])); + operands[1])); DONE; }) diff --git a/gcc/config/mep/mep.c b/gcc/config/mep/mep.c index d082070eef6..e67540a5611 100644 --- a/gcc/config/mep/mep.c +++ b/gcc/config/mep/mep.c @@ -5103,7 +5103,7 @@ mep_emit_doloop (rtx *operands, int is_end) tag = GEN_INT (cfun->machine->doloop_tags - 1); if (is_end) - emit_jump_insn (gen_doloop_end_internal (operands[0], operands[4], tag)); + emit_jump_insn (gen_doloop_end_internal (operands[0], operands[1], tag)); else emit_insn (gen_doloop_begin_internal (operands[0], operands[0], tag)); } @@ -7280,6 +7280,8 @@ mep_asm_init_sections (void) #define TARGET_TRAMPOLINE_INIT mep_trampoline_init #undef TARGET_LEGITIMATE_CONSTANT_P #define TARGET_LEGITIMATE_CONSTANT_P mep_legitimate_constant_p +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/mep/mep.md b/gcc/config/mep/mep.md index 3f09a235241..42542eab8bd 100644 --- a/gcc/config/mep/mep.md +++ b/gcc/config/mep/mep.md @@ -2076,14 +2076,9 @@ (define_expand "doloop_begin" [(use (match_operand 0 "register_operand" "")) - (use (match_operand:QI 1 "const_int_operand" "")) - (use (match_operand:QI 2 "const_int_operand" "")) - (use (match_operand:QI 3 "const_int_operand" "")) - (use (match_operand 4 "" ""))] + (use (match_operand 1 "" ""))] "!profile_arc_flag && TARGET_OPT_REPEAT" - "if (INTVAL (operands[3]) > 1) - FAIL; - mep_emit_doloop (operands, 0); + "mep_emit_doloop (operands, 0); DONE; ") @@ -2112,15 +2107,9 @@ (define_expand "doloop_end" [(use (match_operand 0 "nonimmediate_operand" "")) - (use (match_operand:QI 1 "const_int_operand" "")) - (use (match_operand:QI 2 "const_int_operand" "")) - (use (match_operand:QI 3 "const_int_operand" "")) - (use (label_ref (match_operand 4 "" ""))) - (use (match_operand 5 "" ""))] + (use (label_ref (match_operand 1 "" "")))] "!profile_arc_flag && TARGET_OPT_REPEAT" - "if (INTVAL (operands[3]) > 1) - FAIL; - if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode) + "if (GET_CODE (operands[0]) == REG && GET_MODE (operands[0]) != SImode) FAIL; mep_emit_doloop (operands, 1); DONE; diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index fce8f317c6a..8c8ee9fae0e 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1593,6 +1593,9 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_VECTORIZE_VEC_PERM_CONST_OK #define TARGET_VECTORIZE_VEC_PERM_CONST_OK rs6000_vectorize_vec_perm_const_ok + +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost /* Processor table. */ diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 9a0472d21a9..3f13c4603f7 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -14791,28 +14791,21 @@ (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" "")) ; label - (use (match_operand 5 "" ""))] ; flag: 1 if loop entered at top, else 0 + (use (match_operand 1 "" ""))] ; label "" " { - /* Only use this on innermost loops. */ - if (INTVAL (operands[3]) > 1) - FAIL; if (TARGET_64BIT) { if (GET_MODE (operands[0]) != DImode) FAIL; - emit_jump_insn (gen_ctrdi (operands[0], operands[4])); + emit_jump_insn (gen_ctrdi (operands[0], operands[1])); } else { if (GET_MODE (operands[0]) != SImode) FAIL; - emit_jump_insn (gen_ctrsi (operands[0], operands[4])); + emit_jump_insn (gen_ctrsi (operands[0], operands[1])); } DONE; }") diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index bb1408efd81..8354e263892 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -8412,19 +8412,15 @@ (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" "")) ; label - (use (match_operand 5 "" ""))] ; flag: 1 if loop entered at top, else 0 + (use (match_operand 1 "" ""))] ; label "" { if (GET_MODE (operands[0]) == SImode && !TARGET_CPU_ZARCH) - emit_jump_insn (gen_doloop_si31 (operands[4], operands[0], operands[0])); + emit_jump_insn (gen_doloop_si31 (operands[1], operands[0], operands[0])); else if (GET_MODE (operands[0]) == SImode && TARGET_CPU_ZARCH) - emit_jump_insn (gen_doloop_si64 (operands[4], operands[0], operands[0])); + emit_jump_insn (gen_doloop_si64 (operands[1], operands[0], operands[0])); else if (GET_MODE (operands[0]) == DImode && TARGET_ZARCH) - emit_jump_insn (gen_doloop_di (operands[4], operands[0], operands[0])); + emit_jump_insn (gen_doloop_di (operands[1], operands[0], operands[0])); else FAIL; diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index dd926893166..8cc9195c988 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -8776,25 +8776,21 @@ label: }) ; operand 0 is the loop count pseudo register -; operand 1 is the number of loop iterations or 0 if it is unknown -; operand 2 is the maximum number of loop iterations -; operand 3 is the number of levels of enclosed loops -; operand 4 is the label to jump to at the top of the loop +; operand 1 is the label to jump to at the top of the loop (define_expand "doloop_end" [(parallel [(set (pc) (if_then_else (ne:SI (match_operand:SI 0 "" "") (const_int 1)) - (label_ref (match_operand 4 "" "")) + (label_ref (match_operand 1 "" "")) (pc))) (set (match_dup 0) (plus:SI (match_dup 0) (const_int -1))) - (clobber (reg:SI T_REG))]) - (match_operand 5 "" "")] + (clobber (reg:SI T_REG))])] "TARGET_SH2" { if (GET_MODE (operands[0]) != SImode) FAIL; - emit_jump_insn (gen_doloop_end_split (operands[0], operands[4], operands[0])); + emit_jump_insn (gen_doloop_end_split (operands[0], operands[1], operands[0])); DONE; }) diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c index c32e48a6fc2..38c441d9a03 100644 --- a/gcc/config/spu/spu.c +++ b/gcc/config/spu/spu.c @@ -7328,6 +7328,9 @@ static const struct attribute_spec spu_attribute_table[] = #undef TARGET_CANONICALIZE_COMPARISON #define TARGET_CANONICALIZE_COMPARISON spu_canonicalize_comparison +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-spu.h" diff --git a/gcc/config/spu/spu.md b/gcc/config/spu/spu.md index 083dea4e668..3ca53481128 100644 --- a/gcc/config/spu/spu.md +++ b/gcc/config/spu/spu.md @@ -4487,11 +4487,7 @@ selb\t%0,%4,%0,%3" ;; knows what to generate. (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" "")) ; label - (match_operand 5 "" "")] + (use (match_operand 1 "" ""))] ; label "" " { @@ -4507,16 +4503,13 @@ selb\t%0,%4,%0,%3" rtx bcomp; rtx loc_ref; - /* Only use this on innermost loops. */ - if (INTVAL (operands[3]) > 1) - FAIL; if (GET_MODE (operands[0]) != SImode) FAIL; s0 = operands [0]; emit_move_insn (s0, gen_rtx_PLUS (SImode, s0, GEN_INT (-1))); bcomp = gen_rtx_NE(SImode, s0, const0_rtx); - loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]); emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, loc_ref, pc_rtx))); diff --git a/gcc/config/tilegx/tilegx.c b/gcc/config/tilegx/tilegx.c index f5944bc65d1..dafa44c0674 100644 --- a/gcc/config/tilegx/tilegx.c +++ b/gcc/config/tilegx/tilegx.c @@ -5578,6 +5578,8 @@ tilegx_file_end (void) #undef TARGET_ASM_ALIGNED_DI_OP #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/tilegx/tilegx.md b/gcc/config/tilegx/tilegx.md index 9c6917059a1..30dc8e628ba 100644 --- a/gcc/config/tilegx/tilegx.md +++ b/gcc/config/tilegx/tilegx.md @@ -2414,11 +2414,7 @@ ;; generate. (define_expand "doloop_end" [(use (match_operand 0 "" "")) ;; loop pseudo - (use (match_operand 1 "" "")) ;; iterations; zero if unknown - (use (match_operand 2 "" "")) ;; max iterations - (use (match_operand 3 "" "")) ;; loop level - (use (match_operand 4 "" "")) ;; label - (use (match_operand 5 "" ""))] ;; flag: 1 if loop entered at top, else 0 + (use (match_operand 1 "" ""))] ;; label "" { if (optimize > 0 && flag_modulo_sched) @@ -2428,9 +2424,6 @@ rtx loc_ref; enum machine_mode mode = GET_MODE (operands[0]); - /* only do inner loop */ - if (INTVAL (operands[3]) > 1) - FAIL; /* only deal with loop counters in SImode or DImode */ if (mode != SImode && mode != DImode) FAIL; @@ -2438,7 +2431,7 @@ s0 = operands [0]; emit_move_insn (s0, gen_rtx_PLUS (mode, s0, GEN_INT (-1))); bcomp = gen_rtx_NE(mode, s0, const0_rtx); - loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]); emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, loc_ref, pc_rtx))); diff --git a/gcc/config/tilepro/tilepro.c b/gcc/config/tilepro/tilepro.c index 12adda30e57..5e3be831fb1 100644 --- a/gcc/config/tilepro/tilepro.c +++ b/gcc/config/tilepro/tilepro.c @@ -5067,6 +5067,8 @@ tilepro_file_end (void) #undef TARGET_ASM_FILE_END #define TARGET_ASM_FILE_END tilepro_file_end +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/config/tilepro/tilepro.md b/gcc/config/tilepro/tilepro.md index ca8cf80ca18..f090f9e038b 100644 --- a/gcc/config/tilepro/tilepro.md +++ b/gcc/config/tilepro/tilepro.md @@ -1318,11 +1318,7 @@ ;; generate. (define_expand "doloop_end" [(use (match_operand 0 "" "")) ;; loop pseudo - (use (match_operand 1 "" "")) ;; iterations; zero if unknown - (use (match_operand 2 "" "")) ;; max iterations - (use (match_operand 3 "" "")) ;; loop level - (use (match_operand 4 "" "")) ;; label - (use (match_operand 5 "" ""))] ;; flag: 1 if loop entered at top, else 0 + (use (match_operand 1 "" ""))] ;; label "" { if (optimize > 0) @@ -1331,9 +1327,6 @@ rtx bcomp; rtx loc_ref; - /* only do inner loop */ - if (INTVAL (operands[3]) > 1) - FAIL; /* only deal with loop counters in SImode */ if (GET_MODE (operands[0]) != SImode) FAIL; @@ -1342,7 +1335,7 @@ emit_move_insn (s0, gen_rtx_PLUS (SImode, s0, GEN_INT (-1))); bcomp = gen_rtx_NE(SImode, s0, const0_rtx); - loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [4]); + loc_ref = gen_rtx_LABEL_REF (VOIDmode, operands [1]); emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, loc_ref, pc_rtx))); diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c index 4a746aa1424..006cff4bcdf 100644 --- a/gcc/config/v850/v850.c +++ b/gcc/config/v850/v850.c @@ -3269,6 +3269,9 @@ v850_gen_movdi (rtx * operands) #undef TARGET_LEGITIMATE_CONSTANT_P #define TARGET_LEGITIMATE_CONSTANT_P v850_legitimate_constant_p +#undef TARGET_CAN_USE_DOLOOP_P +#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-v850.h" diff --git a/gcc/config/v850/v850.md b/gcc/config/v850/v850.md index a074f651351..f56d54a91a0 100644 --- a/gcc/config/v850/v850.md +++ b/gcc/config/v850/v850.md @@ -1357,20 +1357,11 @@ (define_expand "doloop_begin" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" ""))] ; condition + (use (match_operand 1 "" ""))] ; doloop_end pattern "TARGET_V850E3V5_UP && TARGET_LOOP" { - rtx loop_cnt = operands[0]; - rtx loop_level = operands[3]; - - if (INTVAL (loop_level) > 1) - FAIL; - if (GET_MODE (loop_cnt) != SImode) - FAIL; - + rtx loop_cnt = operands[0]; + gcc_assert (GET_MODE (loop_cnt) == SImode); emit_insn (gen_fix_loop_counter (loop_cnt)); DONE; } @@ -1394,19 +1385,12 @@ (define_expand "doloop_end" [(use (match_operand 0 "" "")) ; loop pseudo - (use (match_operand 1 "" "")) ; iterations; zero if unknown - (use (match_operand 2 "" "")) ; max iterations - (use (match_operand 3 "" "")) ; loop level - (use (match_operand 4 "" "")) ; label - (use (match_operand 5 "" ""))] ; entered at top + (use (match_operand 1 "" ""))] ; label "TARGET_V850E3V5_UP && TARGET_LOOP" { - rtx loop_cnt = operands[0]; - rtx loop_level = operands[3]; - rtx label = operands[4]; + rtx loop_cnt = operands[0]; + rtx label = operands[1]; - if (INTVAL (loop_level) > 1) - FAIL; if (GET_MODE (loop_cnt) != SImode) FAIL; diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 1e22b88f608..1a06e3d6e74 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -5857,34 +5857,27 @@ reduction is enabled. @cindex @code{doloop_end} instruction pattern @item @samp{doloop_end} -Conditional branch instruction that decrements a register and jumps if -the register is nonzero. This instruction takes five operands: Operand -0 is the register to decrement and test; operand 1 is the number of loop -iterations as a @code{const_int} or @code{const0_rtx} if this cannot be -determined until run-time; operand 2 is the actual or estimated maximum -number of iterations as a @code{const_int}; operand 3 is the number of -enclosed loops as a @code{const_int} (an innermost loop has a value of -1); operand 4 is the label to jump to if the register is nonzero; -operand 5 is const1_rtx if the loop in entered at its top, const0_rtx -otherwise. +Conditional branch instruction that decrements a register and +jumps if the register is nonzero. Operand 0 is the register to +decrement and test; operand 1 is the label to jump to if the +register is nonzero. @xref{Looping Patterns}. This optional instruction pattern should be defined for machines with low-overhead looping instructions as the loop optimizer will try to -modify suitable loops to utilize it. If nested low-overhead looping is -not supported, use a @code{define_expand} (@pxref{Expander Definitions}) -and make the pattern fail if operand 3 is not @code{const1_rtx}. -Similarly, if the actual or estimated maximum number of iterations is -too large for this instruction, make it fail. +modify suitable loops to utilize it. The target hook +@code{TARGET_CAN_USE_DOLOOP_P} controls the conditions under which +low-overhead loops can be used. @cindex @code{doloop_begin} instruction pattern @item @samp{doloop_begin} Companion instruction to @code{doloop_end} required for machines that -need to perform some initialization, such as loading special registers -used by a low-overhead looping instruction. If initialization insns do -not always need to be emitted, use a @code{define_expand} -(@pxref{Expander Definitions}) and make it fail. +need to perform some initialization, such as loading a special counter +register. Operand 1 is the associated @code{doloop_end} pattern and +operand 0 is the register that it decrements. +If initialization insns do not always need to be emitted, use a +@code{define_expand} (@pxref{Expander Definitions}) and make it fail. @cindex @code{canonicalize_funcptr_for_compare} instruction pattern @item @samp{canonicalize_funcptr_for_compare} diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 5e7910bdd20..35cfa995583 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -11091,6 +11091,20 @@ function version at run-time for a given set of function versions. body must be generated. @end deftypefn +@deftypefn {Target Hook} bool TARGET_CAN_USE_DOLOOP_P (double_int @var{iterations}, double_int @var{iterations_max}, unsigned int @var{loop_depth}, bool @var{entered_at_top}) +Return true if it is possible to use low-overhead loops (@code{doloop_end} +and @code{doloop_begin}) for a particular loop. @var{iterations} gives the +exact number of iterations, or 0 if not known. @var{iterations_max} gives +the maximum number of iterations, or 0 if not known. @var{loop_depth} is +the nesting depth of the loop, with 1 for innermost loops, 2 for loops that +contain innermost loops, and so on. @var{entered_at_top} is true if the +loop is only entered from the top. + +This hook is only used if @code{doloop_end} is available. The default +implementation returns true. You can use @code{can_use_doloop_if_innermost} +if the loop must be the innermost, and if there are no other restrictions. +@end deftypefn + @deftypefn {Target Hook} {const char *} TARGET_INVALID_WITHIN_DOLOOP (const_rtx @var{insn}) Take an instruction in @var{insn} and return NULL if it is valid within a diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 4e60d48a337..b10ecd7dda8 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -8212,6 +8212,8 @@ to by @var{ce_info}. @hook TARGET_GENERATE_VERSION_DISPATCHER_BODY +@hook TARGET_CAN_USE_DOLOOP_P + @hook TARGET_INVALID_WITHIN_DOLOOP @hook TARGET_LEGITIMATE_COMBINED_INSN diff --git a/gcc/hooks.c b/gcc/hooks.c index 3259658e4f4..9f53007337d 100644 --- a/gcc/hooks.c +++ b/gcc/hooks.c @@ -331,6 +331,12 @@ hook_bool_rtx_int_int_int_intp_bool_false (rtx a ATTRIBUTE_UNUSED, return false; } +bool +hook_bool_dint_dint_uint_bool_true (double_int, double_int, unsigned int, bool) +{ + return true; +} + /* Generic hook that takes an rtx and returns it. */ rtx hook_rtx_rtx_identity (rtx x) diff --git a/gcc/hooks.h b/gcc/hooks.h index eaf4b03ebbb..38454fbe10a 100644 --- a/gcc/hooks.h +++ b/gcc/hooks.h @@ -23,6 +23,7 @@ #define GCC_HOOKS_H #include "machmode.h" +#include "double-int.h" extern bool hook_bool_void_false (void); extern bool hook_bool_void_true (void); @@ -60,6 +61,8 @@ extern bool hook_bool_rtx_int_int_int_intp_bool_false (rtx, int, int, int, extern bool hook_bool_tree_tree_false (tree, tree); extern bool hook_bool_tree_tree_true (tree, tree); extern bool hook_bool_tree_bool_false (tree, bool); +extern bool hook_bool_dint_dint_uint_bool_true (double_int, double_int, + unsigned int, bool); extern void hook_void_void (void); extern void hook_void_constcharptr (const char *); diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c index 1bc9aa392a2..82c01a54b9d 100644 --- a/gcc/loop-doloop.c +++ b/gcc/loop-doloop.c @@ -548,20 +548,8 @@ doloop_modify (struct loop *loop, struct niter_desc *desc, #ifdef HAVE_doloop_begin { rtx init; - unsigned level = get_loop_level (loop) + 1; - double_int iter; - rtx iter_rtx; - - if (!get_max_loop_iterations (loop, &iter) - || !iter.fits_shwi ()) - iter_rtx = const0_rtx; - else - iter_rtx = GEN_INT (iter.to_shwi ()); - init = gen_doloop_begin (counter_reg, - desc->const_iter ? desc->niter_expr : const0_rtx, - iter_rtx, - GEN_INT (level), - doloop_seq); + + init = gen_doloop_begin (counter_reg, doloop_seq); if (init) { start_sequence (); @@ -608,8 +596,8 @@ doloop_optimize (struct loop *loop) { enum machine_mode mode; rtx doloop_seq, doloop_pat, doloop_reg; - rtx iterations, count; - rtx iterations_max; + rtx count; + double_int iterations, iterations_max; rtx start_label; rtx condition; unsigned level, est_niter; @@ -617,7 +605,6 @@ doloop_optimize (struct loop *loop) struct niter_desc *desc; unsigned word_mode_size; unsigned HOST_WIDE_INT word_mode_max; - double_int iter; int entered_at_top; if (dump_file) @@ -667,25 +654,30 @@ doloop_optimize (struct loop *loop) return false; } - count = copy_rtx (desc->niter_expr); - iterations = desc->const_iter ? desc->niter_expr : const0_rtx; - if (!get_max_loop_iterations (loop, &iter) - || !iter.fits_shwi ()) - iterations_max = const0_rtx; + if (desc->const_iter) + iterations = rtx_to_double_int (desc->niter_expr); else - iterations_max = GEN_INT (iter.to_shwi ()); + iterations = double_int_zero; + if (!get_max_loop_iterations (loop, &iterations_max)) + iterations_max = double_int_zero; level = get_loop_level (loop) + 1; + entered_at_top = (loop->latch == desc->in_edge->dest + && contains_no_active_insn_p (loop->latch)); + if (!targetm.can_use_doloop_p (iterations, iterations_max, level, + entered_at_top)) + { + if (dump_file) + fprintf (dump_file, "Loop rejected by can_use_doloop_p.\n"); + return false; + } /* Generate looping insn. If the pattern FAILs then give up trying to modify the loop since there is some aspect the back-end does not like. */ + count = copy_rtx (desc->niter_expr); start_label = block_label (desc->in_edge->dest); doloop_reg = gen_reg_rtx (mode); - entered_at_top = (loop->latch == desc->in_edge->dest - && contains_no_active_insn_p (loop->latch)); - doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max, - GEN_INT (level), start_label, - GEN_INT (entered_at_top)); + doloop_seq = gen_doloop_end (doloop_reg, start_label); word_mode_size = GET_MODE_PRECISION (word_mode); word_mode_max @@ -696,27 +688,14 @@ doloop_optimize (struct loop *loop) computed, we must be sure that the number of iterations fits into the new mode. */ && (word_mode_size >= GET_MODE_PRECISION (mode) - || iter.ule (double_int::from_shwi (word_mode_max)))) + || iterations_max.ule (double_int::from_shwi (word_mode_max)))) { if (word_mode_size > GET_MODE_PRECISION (mode)) - { - count = simplify_gen_unary (ZERO_EXTEND, word_mode, - count, mode); - iterations = simplify_gen_unary (ZERO_EXTEND, word_mode, - iterations, mode); - iterations_max = simplify_gen_unary (ZERO_EXTEND, word_mode, - iterations_max, mode); - } + count = simplify_gen_unary (ZERO_EXTEND, word_mode, count, mode); else - { - count = lowpart_subreg (word_mode, count, mode); - iterations = lowpart_subreg (word_mode, iterations, mode); - iterations_max = lowpart_subreg (word_mode, iterations_max, mode); - } + count = lowpart_subreg (word_mode, count, mode); PUT_MODE (doloop_reg, word_mode); - doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max, - GEN_INT (level), start_label, - GEN_INT (entered_at_top)); + doloop_seq = gen_doloop_end (doloop_reg, start_label); } if (! doloop_seq) { diff --git a/gcc/target.def b/gcc/target.def index caf1cb6da6d..f6e42a17b0e 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -3597,6 +3597,23 @@ normally defined in @file{libgcc2.c}.", tree, (void), default_external_stack_protect_fail) +DEFHOOK +(can_use_doloop_p, + "Return true if it is possible to use low-overhead loops (@code{doloop_end}\n\ +and @code{doloop_begin}) for a particular loop. @var{iterations} gives the\n\ +exact number of iterations, or 0 if not known. @var{iterations_max} gives\n\ +the maximum number of iterations, or 0 if not known. @var{loop_depth} is\n\ +the nesting depth of the loop, with 1 for innermost loops, 2 for loops that\n\ +contain innermost loops, and so on. @var{entered_at_top} is true if the\n\ +loop is only entered from the top.\n\ +\n\ +This hook is only used if @code{doloop_end} is available. The default\n\ +implementation returns true. You can use @code{can_use_doloop_if_innermost}\n\ +if the loop must be the innermost, and if there are no other restrictions.", + bool, (double_int iterations, double_int iterations_max, + unsigned int loop_depth, bool entered_at_top), + hook_bool_dint_dint_uint_bool_true) + /* Returns NULL if target supports the insn within a doloop block, otherwise it returns an error message. */ DEFHOOK diff --git a/gcc/target.h b/gcc/target.h index 405e2928b73..12249ecfd5c 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -50,6 +50,7 @@ #include "insn-modes.h" #include "insn-codes.h" +#include "double-int.h" #ifdef ENABLE_CHECKING diff --git a/gcc/targhooks.c b/gcc/targhooks.c index e262fcb43ce..a671486453a 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1738,5 +1738,14 @@ default_builtin_chkp_function (unsigned int fcode ATTRIBUTE_UNUSED) return NULL_TREE; } +/* An implementation of TARGET_CAN_USE_DOLOOP_P for targets that do + not support nested low-overhead loops. */ + +bool +can_use_doloop_if_innermost (double_int, double_int, + unsigned int loop_depth, bool) +{ + return loop_depth == 1; +} #include "gt-targhooks.h" diff --git a/gcc/targhooks.h b/gcc/targhooks.h index a939fdbc6e5..1ba0c1d4e7d 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -213,3 +213,5 @@ extern tree default_fn_abi_va_list_bounds_size (tree); extern tree default_chkp_bound_type (void); extern enum machine_mode default_chkp_bound_mode (void); extern tree default_builtin_chkp_function (unsigned int); +extern bool can_use_doloop_if_innermost (double_int, double_int, + unsigned int, bool); |