Commit 662c03f4 by Nick Clifton Committed by Nick Clifton

mn10300.c: Include cfgloop.h.

	* config/mn10300/mn10300.c: Include cfgloop.h.
	(DUMP): New macro.
	(mn10300_insert_setlb_lcc): New function.  Inserts a SETLB and a
	Lcc or a FLcc insn into the instruction stream.
	(mn10300_block_contains_call): New function.  Returns true if the
	given basic block contains a CALL insn.
	(mn10300_loop_contains_call_insn): New function.  Returns true if
	the given loop contains a CALL insn.
	(mn10300_scan_for_setlb_lcc): New function.  Finds opportunities
	to use the SETLB and Lcc or FLcc insns.
	(mn10300_reorg): Invoke mn10300_scan_for_setlb_lcc when optimizing.
	(TARGET_FLAGS): Add MASK_ALLOW_SETLB.
	* config/mn10300/mn10300.opt (msetlb): New option.  Used to
	disable the SETLB optimization.
	* config/mn10300/mn10300.h (TARGET_CPU_CPP_BUILTINS): Add
	__SETLB__ or __NO_SETLB__.
	* config/mn10300/mn10300.md (UNSPEC_SETLB): New constant.
	(movsf_internal): Handle MDR register.
	(cmpsi): Make visible.
	(setlb): New pattern.
	(Lcc): New pattern.
	(FLcc): New pattern.

From-SVN: r173362
parent 843b6915
2011-05-04 Nick Clifton <nickc@redhat.com>
* config/mn10300/mn10300.c: Include cfgloop.h.
(DUMP): New macro.
(mn10300_insert_setlb_lcc): New function. Inserts a SETLB and a
Lcc or a FLcc insn into the instruction stream.
(mn10300_block_contains_call): New function. Returns true if the
given basic block contains a CALL insn.
(mn10300_loop_contains_call_insn): New function. Returns true if
the given loop contains a CALL insn.
(mn10300_scan_for_setlb_lcc): New function. Finds opportunities
to use the SETLB and Lcc or FLcc insns.
(mn10300_reorg): Invoke mn10300_scan_for_setlb_lcc when optimizing.
(TARGET_FLAGS): Add MASK_ALLOW_SETLB.
* config/mn10300/mn10300.opt (msetlb): New option. Used to
disable the SETLB optimization.
* config/mn10300/mn10300.h (TARGET_CPU_CPP_BUILTINS): Add
__SETLB__ or __NO_SETLB__.
* config/mn10300/mn10300.md (UNSPEC_SETLB): New constant.
(movsf_internal): Handle MDR register.
(cmpsi): Make visible.
(setlb): New pattern.
(Lcc): New pattern.
(FLcc): New pattern.
2011-05-04 Uros Bizjak <ubizjak@gmail.com>
PR target/48860
......
......@@ -45,6 +45,7 @@
#include "target-def.h"
#include "df.h"
#include "opts.h"
#include "cfgloop.h"
/* This is used in the am33_2.0-linux-gnu port, in which global symbol
names are not prefixed by underscores, to tell whether to prefix a
......@@ -3129,11 +3130,188 @@ mn10300_bundle_liw (void)
}
}
#define DUMP(reason, insn) \
do \
{ \
if (dump_file) \
{ \
fprintf (dump_file, reason "\n"); \
if (insn != NULL_RTX) \
print_rtl_single (dump_file, insn); \
fprintf(dump_file, "\n"); \
} \
} \
while (0)
/* Replace the BRANCH insn with a Lcc insn that goes to LABEL.
Insert a SETLB insn just before LABEL. */
static void
mn10300_insert_setlb_lcc (rtx label, rtx branch)
{
rtx lcc, comparison, cmp_reg;
if (LABEL_NUSES (label) > 1)
{
rtx insn;
/* This label is used both as an entry point to the loop
and as a loop-back point for the loop. We need to separate
these two functions so that the SETLB happens upon entry,
but the loop-back does not go to the SETLB instruction. */
DUMP ("Inserting SETLB insn after:", label);
insn = emit_insn_after (gen_setlb (), label);
label = gen_label_rtx ();
emit_label_after (label, insn);
DUMP ("Created new loop-back label:", label);
}
else
{
DUMP ("Inserting SETLB insn before:", label);
emit_insn_before (gen_setlb (), label);
}
comparison = XEXP (SET_SRC (PATTERN (branch)), 0);
cmp_reg = XEXP (comparison, 0);
gcc_assert (REG_P (cmp_reg));
/* If the comparison has not already been split out of the branch
then do so now. */
gcc_assert (REGNO (cmp_reg) == CC_REG);
if (GET_MODE (cmp_reg) == CC_FLOATmode)
lcc = gen_FLcc (comparison, label);
else
lcc = gen_Lcc (comparison, label);
lcc = emit_jump_insn_before (lcc, branch);
mark_jump_label (XVECEXP (PATTERN (lcc), 0, 0), lcc, 0);
DUMP ("Replacing branch insn...", branch);
DUMP ("... with Lcc insn:", lcc);
delete_insn (branch);
}
static bool
mn10300_block_contains_call (struct basic_block_def * block)
{
rtx insn;
FOR_BB_INSNS (block, insn)
if (CALL_P (insn))
return true;
return false;
}
static bool
mn10300_loop_contains_call_insn (loop_p loop)
{
basic_block * bbs;
bool result = false;
unsigned int i;
bbs = get_loop_body (loop);
for (i = 0; i < loop->num_nodes; i++)
if (mn10300_block_contains_call (bbs[i]))
{
result = true;
break;
}
free (bbs);
return result;
}
static void
mn10300_scan_for_setlb_lcc (void)
{
struct loops loops;
loop_iterator liter;
loop_p loop;
DUMP ("Looking for loops that can use the SETLB insn", NULL_RTX);
df_analyze ();
compute_bb_for_insn ();
/* Find the loops. */
if (flow_loops_find (& loops) < 1)
DUMP ("No loops found", NULL_RTX);
current_loops = & loops;
/* FIXME: For now we only investigate innermost loops. In practice however
if an inner loop is not suitable for use with the SETLB/Lcc insns, it may
be the case that its parent loop is suitable. Thus we should check all
loops, but work from the innermost outwards. */
FOR_EACH_LOOP (liter, loop, LI_ONLY_INNERMOST)
{
const char * reason = NULL;
/* Check to see if we can modify this loop. If we cannot
then set 'reason' to describe why it could not be done. */
if (loop->latch == NULL)
reason = "it contains multiple latches";
else if (loop->header != loop->latch)
/* FIXME: We could handle loops that span multiple blocks,
but this requires a lot more work tracking down the branches
that need altering, so for now keep things simple. */
reason = "the loop spans multiple blocks";
else if (mn10300_loop_contains_call_insn (loop))
reason = "it contains CALL insns";
else
{
rtx branch = BB_END (loop->latch);
gcc_assert (JUMP_P (branch));
if (single_set (branch) == NULL_RTX || ! any_condjump_p (branch))
/* We cannot optimize tablejumps and the like. */
/* FIXME: We could handle unconditional jumps. */
reason = "it is not a simple loop";
else
{
rtx label;
if (dump_file)
flow_loop_dump (loop, dump_file, NULL, 0);
label = BB_HEAD (loop->header);
gcc_assert (LABEL_P (label));
mn10300_insert_setlb_lcc (label, branch);
}
}
if (dump_file && reason != NULL)
fprintf (dump_file, "Loop starting with insn %d is not suitable because %s\n",
INSN_UID (BB_HEAD (loop->header)),
reason);
}
#if 0 /* FIXME: We should free the storage we allocated, but
for some unknown reason this leads to seg-faults. */
FOR_EACH_LOOP (liter, loop, 0)
free_simple_loop_desc (loop);
flow_loops_free (current_loops);
#endif
current_loops = NULL;
df_finish_pass (false);
DUMP ("SETLB scan complete", NULL_RTX);
}
static void
mn10300_reorg (void)
{
if (TARGET_AM33)
/* These are optimizations, so only run them if optimizing. */
if (TARGET_AM33 && (optimize > 0 || optimize_size))
{
if (TARGET_ALLOW_SETLB)
mn10300_scan_for_setlb_lcc ();
if (TARGET_ALLOW_LIW)
mn10300_bundle_liw ();
}
......@@ -3171,7 +3349,7 @@ mn10300_reorg (void)
#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA mn10300_asm_output_addr_const_extra
#undef TARGET_DEFAULT_TARGET_FLAGS
#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW
#define TARGET_DEFAULT_TARGET_FLAGS MASK_MULT_BUG | MASK_PTR_A0D0 | MASK_ALLOW_LIW | MASK_ALLOW_SETLB
#undef TARGET_HANDLE_OPTION
#define TARGET_HANDLE_OPTION mn10300_handle_option
#undef TARGET_OPTION_OVERRIDE
......
......@@ -54,6 +54,8 @@
builtin_define (TARGET_ALLOW_LIW ? \
"__LIW__" : "__NO_LIW__");\
\
builtin_define (TARGET_ALLOW_SETLB ? \
"__SETLB__" : "__NO_SETLB__");\
} \
while (0)
......
......@@ -42,6 +42,8 @@
;; This is used to encode LIW patterns.
(UNSPEC_LIW 8)
;; This is for the low overhead loop instructions.
(UNSPEC_SETLB 9)
])
(include "predicates.md")
......@@ -501,8 +503,8 @@
})
(define_insn "*movsf_internal"
[(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q")
(match_operand:SF 1 "general_operand" " 0,F,F,r,f,f,r,m,r,Q,f"))]
[(set (match_operand:SF 0 "nonimmediate_operand" "=rf,r,f,r,f,r,f,r,m,f,Q,z,d")
(match_operand:SF 1 "general_operand" " 0,F,F,r,f,f,r,m,r,Q,f,d,z"))]
"TARGET_AM33_2
&& (register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))"
......@@ -515,6 +517,8 @@
case 3:
case 7:
case 8:
case 11:
case 12:
return "mov %1,%0";
case 2:
case 4:
......@@ -547,6 +551,8 @@
(const_int 13) (const_int 24))
(if_then_else (eq_attr "cpu" "am34")
(const_int 13) (const_int 24))
(const_int 22)
(const_int 22)
])]
)
......@@ -1385,7 +1391,7 @@
DONE;
})
(define_insn "*cmpsi"
(define_insn "cmpsi"
[(set (reg CC_REG)
(compare (match_operand:SI 0 "register_operand" "r,r,r")
(match_operand:SI 1 "nonmemory_operand" "r,O,i")))]
......@@ -2162,3 +2168,39 @@
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
(const_int 13) (const_int 12)))]
)
;; Note - in theory the doloop patterns could be used here to express
;; the SETLB and Lcc instructions. In practice this does not work because
;; the acceptable forms of the doloop patterns do not include UNSPECs
;; and without them gcc's basic block reordering code can duplicate the
;; doloop_end pattern, leading to bogus multiple decrements of the loop
;; counter.
(define_insn "setlb"
[(unspec [(const_int 0)] UNSPEC_SETLB)]
"TARGET_AM33 && TARGET_ALLOW_SETLB"
"setlb"
)
(define_insn "Lcc"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(reg:CC CC_REG) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))
(unspec [(const_int 1)] UNSPEC_SETLB)]
"TARGET_AM33 && TARGET_ALLOW_SETLB"
"L%b0 # loop back to: %1"
)
(define_insn "FLcc"
[(set (pc)
(if_then_else (match_operator 0 "comparison_operator"
[(reg:CC_FLOAT CC_REG) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))
(unspec [(const_int 2)] UNSPEC_SETLB)]
"TARGET_AM33_2 && TARGET_ALLOW_SETLB"
"FL%b0 # loop back to: %1"
[(set (attr "timings") (if_then_else (eq_attr "cpu" "am34") (const_int 44) (const_int 11)))]
)
......@@ -61,3 +61,7 @@ Return pointers in both a0 and d0
mliw
Target Report Mask(ALLOW_LIW)
Allow gcc to generate LIW instructions
msetlb
Target Report Mask(ALLOW_SETLB)
Allow gcc to generate the SETLB and Lcc instructions
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment