From 662c03f4601e31aaf76e8fe2b6ebbd421156ebab Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 4 May 2011 10:08:09 +0000 Subject: [PATCH] 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 --- gcc/ChangeLog | 25 +++++ gcc/config/mn10300/mn10300.c | 182 ++++++++++++++++++++++++++++++++- gcc/config/mn10300/mn10300.h | 2 + gcc/config/mn10300/mn10300.md | 48 ++++++++- gcc/config/mn10300/mn10300.opt | 4 + 5 files changed, 256 insertions(+), 5 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 97c6bcb1cfd..6f30c3113ac 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2011-05-04 Nick Clifton + + * 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 PR target/48860 diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 1bae9f30eef..53714673ac8 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -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 diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index a0e17d845db..a15615653b5 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -54,6 +54,8 @@ builtin_define (TARGET_ALLOW_LIW ? \ "__LIW__" : "__NO_LIW__");\ \ + builtin_define (TARGET_ALLOW_SETLB ? \ + "__SETLB__" : "__NO_SETLB__");\ } \ while (0) diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index f3f23e7fa37..81e4a4153d8 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -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)))] +) diff --git a/gcc/config/mn10300/mn10300.opt b/gcc/config/mn10300/mn10300.opt index 676e434e0ef..ba67582f4f2 100644 --- a/gcc/config/mn10300/mn10300.opt +++ b/gcc/config/mn10300/mn10300.opt @@ -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 -- 2.30.2