Beispiel #1
0
static void
erase_matching_seqs (void)
{
  seq_block sb;
  matching_seq mseq;
  rtx insn;
  basic_block bb;
  rtx retlabel, saveinsn, callinsn;
  int i;

  for (sb = seq_blocks; sb; sb = sb->next_seq_block)
    {
      for (mseq = sb->matching_seqs; mseq; mseq = mseq->next_matching_seq)
        {
          insn = mseq->insn;
          bb = BLOCK_FOR_INSN (insn);

          /* Get the label after the sequence. This will be the return
             address. The label will be referenced using a symbol_ref so
             protect it from deleting.  */
          retlabel = block_label_after (insn);
          LABEL_PRESERVE_P (retlabel) = 1;

          /* Delete the insns of the sequence.  */
          for (i = 0; i < sb->length; i++)
            insn = prev_insn_in_block (insn);
          delete_basic_block (split_block_and_df_analyze (bb, insn));

          /* Emit an insn saving the return address to the link register
             before the deleted sequence.  */
          saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
                                      gen_symbol_ref_rtx_for_label
                                      (retlabel)),
                                      BB_END (bb));
          BLOCK_FOR_INSN (saveinsn) = bb;

          /* Emit a jump to the appropriate part of the pattern sequence
             after the save insn. Also update the basic block.  */
          callinsn = emit_jump_insn_after (gen_jump (sb->label), saveinsn);
          JUMP_LABEL (callinsn) = sb->label;
          LABEL_NUSES (sb->label)++;
          BLOCK_FOR_INSN (callinsn) = bb;
          BB_END (bb) = callinsn;

          /* Maintain control flow and liveness information.  */
          SET_REGNO_REG_SET (df_get_live_out (bb),
                             REGNO (pattern_seqs->link_reg));
          emit_barrier_after (BB_END (bb));
          make_single_succ_edge (bb, BLOCK_FOR_INSN (sb->label), 0);
          IOR_REG_SET (df_get_live_out (bb),
		       df_get_live_in (BLOCK_FOR_INSN (sb->label)));

          make_edge (BLOCK_FOR_INSN (seq_blocks->label),
                     BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);
        }
    }
}
Beispiel #2
0
static void
split_pattern_seq (void)
{
  rtx insn;
  basic_block bb;
  rtx retlabel, retjmp, saveinsn;
  int i;
  seq_block sb;

  insn = pattern_seqs->insn;
  bb = BLOCK_FOR_INSN (insn);

  /* Get the label after the sequence. This will be the return address. The
     label will be referenced using a symbol_ref so protect it from
     deleting.  */
  retlabel = block_label_after (insn);
  LABEL_PRESERVE_P (retlabel) = 1;

  /* Emit an indirect jump via the link register after the sequence acting
     as the return insn.  Also emit a barrier and update the basic block.  */
  if (!find_reg_note (BB_END (bb), REG_NORETURN, NULL))
    retjmp = emit_jump_insn_after (gen_indirect_jump (pattern_seqs->link_reg),
                                   BB_END (bb));
  emit_barrier_after (BB_END (bb));

  /* Replace all outgoing edges with a new one to the block of RETLABEL.  */
  while (EDGE_COUNT (bb->succs) != 0)
    remove_edge (EDGE_SUCC (bb, 0));
  make_edge (bb, BLOCK_FOR_INSN (retlabel), EDGE_ABNORMAL);

  /* Split the sequence according to SEQ_BLOCKS and cache the label of the
     resulting basic blocks.  */
  i = 0;
  for (sb = seq_blocks; sb; sb = sb->next_seq_block)
    {
      for (; i < sb->length; i++)
        insn = prev_insn_in_block (insn);

      sb->label = block_label (split_block_and_df_analyze (bb, insn));
    }

  /* Emit an insn saving the return address to the link register before the
     sequence.  */
  saveinsn = emit_insn_after (gen_move_insn (pattern_seqs->link_reg,
                              gen_symbol_ref_rtx_for_label
                              (retlabel)), BB_END (bb));
  /* Update liveness info.  */
  SET_REGNO_REG_SET (df_get_live_out (bb),
                     REGNO (pattern_seqs->link_reg));
}
Beispiel #3
0
static void
doloop_modify (struct loop *loop, struct niter_desc *desc,
               rtx doloop_seq, rtx condition, rtx count)
{
    rtx counter_reg;
    rtx tmp, noloop = NULL_RTX;
    rtx sequence;
    rtx jump_insn;
    rtx jump_label;
    int nonneg = 0, irr;
    bool increment_count;
    basic_block loop_end = desc->out_edge->src;
    enum machine_mode mode;

    jump_insn = BB_END (loop_end);

    if (dump_file)
    {
        fprintf (dump_file, "Doloop: Inserting doloop pattern (");
        if (desc->const_iter)
            fprintf (dump_file, HOST_WIDEST_INT_PRINT_DEC, desc->niter);
        else
            fputs ("runtime", dump_file);
        fputs (" iterations).\n", dump_file);
    }

    /* Discard original jump to continue loop.  The original compare
       result may still be live, so it cannot be discarded explicitly.  */
    delete_insn (jump_insn);

    counter_reg = XEXP (condition, 0);
    if (GET_CODE (counter_reg) == PLUS)
        counter_reg = XEXP (counter_reg, 0);
    mode = GET_MODE (counter_reg);

    increment_count = false;
    switch (GET_CODE (condition))
    {
    case NE:
        /* Currently only NE tests against zero and one are supported.  */
        if (XEXP (condition, 1) == const1_rtx)
        {
            increment_count = true;
            noloop = const1_rtx;
        }
        else if (XEXP (condition, 1) == const0_rtx)
            noloop = const0_rtx;
        else
            abort ();
        break;

    case GE:
        /* Currently only GE tests against zero are supported.  */
        if (XEXP (condition, 1) != const0_rtx)
            abort ();

        noloop = constm1_rtx;

        /* The iteration count does not need incrementing for a GE test.  */
        increment_count = false;

        /* Determine if the iteration counter will be non-negative.
        Note that the maximum value loaded is iterations_max - 1.  */
        if (desc->niter_max
                <= ((unsigned HOST_WIDEST_INT) 1
                    << (GET_MODE_BITSIZE (mode) - 1)))
            nonneg = 1;
        break;

    /* Abort if an invalid doloop pattern has been generated.  */
    default:
        abort ();
    }

    if (increment_count)
        count = simplify_gen_binary (PLUS, mode, count, const1_rtx);

    /* Insert initialization of the count register into the loop header.  */
    start_sequence ();
    tmp = force_operand (count, counter_reg);
    convert_move (counter_reg, tmp, 1);
    sequence = get_insns ();
    end_sequence ();
    emit_insn_after (sequence, BB_END (loop_preheader_edge (loop)->src));

    if (desc->noloop_assumptions)
    {
        rtx ass = copy_rtx (desc->noloop_assumptions);
        basic_block preheader = loop_preheader_edge (loop)->src;
        basic_block set_zero
            = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
        basic_block new_preheader
            = loop_split_edge_with (loop_preheader_edge (loop), NULL_RTX);
        basic_block bb;
        edge te;
        gcov_type cnt;

        /* Expand the condition testing the assumptions and if it does not pass,
        reset the count register to 0.  */
        add_test (XEXP (ass, 0), preheader, set_zero);
        EDGE_SUCC (preheader, 0)->flags &= ~EDGE_FALLTHRU;
        cnt = EDGE_SUCC (preheader, 0)->count;
        EDGE_SUCC (preheader, 0)->probability = 0;
        EDGE_SUCC (preheader, 0)->count = 0;
        irr = EDGE_SUCC (preheader, 0)->flags & EDGE_IRREDUCIBLE_LOOP;
        te = make_edge (preheader, new_preheader, EDGE_FALLTHRU | irr);
        te->probability = REG_BR_PROB_BASE;
        te->count = cnt;
        set_immediate_dominator (CDI_DOMINATORS, new_preheader, preheader);

        set_zero->count = 0;
        set_zero->frequency = 0;

        for (ass = XEXP (ass, 1); ass; ass = XEXP (ass, 1))
        {
            bb = loop_split_edge_with (te, NULL_RTX);
            te = EDGE_SUCC (bb, 0);
            add_test (XEXP (ass, 0), bb, set_zero);
            make_edge (bb, set_zero, irr);
        }

        start_sequence ();
        convert_move (counter_reg, noloop, 0);
        sequence = get_insns ();
        end_sequence ();
        emit_insn_after (sequence, BB_END (set_zero));
    }

    /* Some targets (eg, C4x) need to initialize special looping
       registers.  */
#ifdef HAVE_doloop_begin
    {
        rtx init;
        unsigned level = get_loop_level (loop) + 1;
        init = gen_doloop_begin (counter_reg,
                                 desc->const_iter ? desc->niter_expr : const0_rtx,
                                 desc->niter_max,
                                 GEN_INT (level));
        if (init)
        {
            start_sequence ();
            emit_insn (init);
            sequence = get_insns ();
            end_sequence ();
            emit_insn_after (sequence, BB_END (loop_preheader_edge (loop)->src));
        }
    }
#endif

    /* Insert the new low-overhead looping insn.  */
    emit_jump_insn_after (doloop_seq, BB_END (loop_end));
    jump_insn = BB_END (loop_end);
    jump_label = block_label (desc->in_edge->dest);
    JUMP_LABEL (jump_insn) = jump_label;
    LABEL_NUSES (jump_label)++;

    /* Ensure the right fallthru edge is marked, for case we have reversed
       the condition.  */
    desc->in_edge->flags &= ~EDGE_FALLTHRU;
    desc->out_edge->flags |= EDGE_FALLTHRU;

    /* Add a REG_NONNEG note if the actual or estimated maximum number
       of iterations is non-negative.  */
    if (nonneg)
    {
        REG_NOTES (jump_insn)
            = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX, REG_NOTES (jump_insn));
    }
}