static void arc_init_simd_builtins (void);
static bool arc_vector_mode_supported_p (enum machine_mode);
+static bool arc_can_use_doloop_p (const widest_int &, const widest_int &,
+ unsigned int, bool);
static const char *arc_invalid_within_doloop (const_rtx);
static void output_short_suffix (FILE *file);
#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
|| TREE_ADDRESSABLE (type)));
}
+/* Implement TARGET_CAN_USE_DOLOOP_P. */
+
+static bool
+arc_can_use_doloop_p (const widest_int &iterations, const widest_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
+ && wi::gtu_p (iterations, 0)
+ && wi::leu_p (iterations, 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. */
})
; 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
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;
)
; 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
; 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;
})
#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;
\f
;; 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"
"
{
rtx insn;
rtx cmp;
- /* Only use this on innermost loops. */
- if (INTVAL (operands[3]) > 1)
- FAIL;
-
if (GET_MODE (operands[0]) != SImode)
FAIL;
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)));
return insn;
}
\f
+/* Implement TARGET_CAN_USE_DOLOOP_P. */
+
+static bool
+bfin_can_use_doloop_p (const widest_int &, const widest_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
+ && wi::geu_p (iterations_max, 0xFFFFFFFF))
+ return false;
+ return true;
+}
+
/* Increment the counter for the number of loop instructions in the
current function. */
#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;
;; 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"
;; -------------------------------------------------------------------------
; 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"
#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
(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;
})
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));
}
#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;
(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;
")
(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;
#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
\f
/* Processor table. */
(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;
}")
(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;
})
; 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;
})
#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"
;; 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
""
"
{
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)));
#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;
;; 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)
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;
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)));
#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;
;; 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)
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;
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)));
#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"
(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;
}
(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;
@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}
body must be generated.
@end deftypefn
+@deftypefn {Target Hook} bool TARGET_CAN_USE_DOLOOP_P (const widest_int @var{&iterations}, const widest_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
@hook TARGET_GENERATE_VERSION_DISPATCHER_BODY
+@hook TARGET_CAN_USE_DOLOOP_P
+
@hook TARGET_INVALID_WITHIN_DOLOOP
@hook TARGET_LEGITIMATE_COMBINED_INSN
return false;
}
+bool
+hook_bool_wint_wint_uint_bool_true (const widest_int &, const widest_int &,
+ unsigned int, bool)
+{
+ return true;
+}
+
/* Generic hook that takes an rtx and returns it. */
rtx
hook_rtx_rtx_identity (rtx x)
#define GCC_HOOKS_H
#include "machmode.h"
+#include "wide-int.h"
extern bool hook_bool_void_false (void);
extern bool hook_bool_void_true (void);
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_wint_wint_uint_bool_true (const widest_int &,
+ const widest_int &,
+ unsigned int, bool);
extern void hook_void_void (void);
extern void hook_void_constcharptr (const char *);
#ifdef HAVE_doloop_begin
{
rtx init;
- unsigned level = get_loop_level (loop) + 1;
- widest_int iter;
- rtx iter_rtx;
-
- if (!get_max_loop_iterations (loop, &iter)
- || !wi::fits_shwi_p (iter))
- 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 ();
{
enum machine_mode mode;
rtx doloop_seq, doloop_pat, doloop_reg;
- rtx iterations, count;
- rtx iterations_max;
+ rtx count;
+ widest_int iterations, iterations_max;
rtx start_label;
rtx condition;
unsigned level, est_niter;
struct niter_desc *desc;
unsigned word_mode_size;
unsigned HOST_WIDE_INT word_mode_max;
- widest_int iter;
int entered_at_top;
if (dump_file)
return false;
}
- count = copy_rtx (desc->niter_expr);
- iterations = desc->const_iter ? desc->niter_expr : const0_rtx;
- if (!get_max_loop_iterations (loop, &iter)
- || !wi::fits_shwi_p (iter))
- iterations_max = const0_rtx;
+ if (desc->const_iter)
+ iterations = widest_int::from (std::make_pair (desc->niter_expr, mode),
+ UNSIGNED);
else
- iterations_max = GEN_INT (iter.to_shwi ());
+ iterations = 0;
+ if (!get_max_loop_iterations (loop, &iterations_max))
+ iterations_max = 0;
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
computed, we must be sure that the number of iterations fits into
the new mode. */
&& (word_mode_size >= GET_MODE_PRECISION (mode)
- || wi::leu_p (iter, word_mode_max)))
+ || wi::leu_p (iterations_max, 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)
{
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, (const widest_int &iterations, const widest_int &iterations_max,
+ unsigned int loop_depth, bool entered_at_top),
+ hook_bool_wint_wint_uint_bool_true)
+
/* Returns NULL if target supports the insn within a doloop block,
otherwise it returns an error message. */
DEFHOOK
#include "insn-modes.h"
#include "insn-codes.h"
+#include "wide-int.h"
#ifdef ENABLE_CHECKING
return long_long_integer_type_node;
}
+/* An implementation of TARGET_CAN_USE_DOLOOP_P for targets that do
+ not support nested low-overhead loops. */
+
+bool
+can_use_doloop_if_innermost (const widest_int &, const widest_int &,
+ unsigned int loop_depth, bool)
+{
+ return loop_depth == 1;
+}
/* Returns the size of the cookie to use when allocating an array
whose elements have the indicated TYPE. Assumes that it is already
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 (const widest_int &,
+ const widest_int &,
+ unsigned int, bool);