void
fma_node::dump_info (ATTRIBUTE_UNUSED fma_forest *forest)
{
  struct du_chain *chain;
  std::list<fma_node *>::iterator fma_child;

  gcc_assert (dump_file);

  if (this->get_children ()->empty ())
    return;

  fprintf (dump_file, "Instruction(s)");
  for (chain = this->m_head->first; chain; chain = chain->next_use)
    {
      if (!is_fmul_fmac_insn (chain->insn, true))
	continue;

      if (chain->loc != &SET_DEST (PATTERN (chain->insn)))
	continue;

      fprintf (dump_file, " %d", INSN_UID (chain->insn));
    }

  fprintf (dump_file, " is(are) accumulator dependency of instructions");
  for (fma_child = this->get_children ()->begin ();
       fma_child != this->get_children ()->end (); fma_child++)
    fprintf (dump_file, " %d", INSN_UID ((*fma_child)->m_insn));
  fprintf (dump_file, "\n");
}
void
func_fma_steering::analyze ()
{
  int i, n_blocks, *bb_dfs_preorder;
  basic_block bb;
  rtx_insn *insn;

  bb_dfs_preorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
  n_blocks = pre_and_rev_post_order_compute (bb_dfs_preorder, NULL, false);

  /* Browse the graph of basic blocks looking for FMUL or FMADD/FMSUB
     instructions.  */
  for (i = 0; i < n_blocks; i++)
    {
      bb = BASIC_BLOCK_FOR_FN (cfun, bb_dfs_preorder[i]);
      FOR_BB_INSNS (bb, insn)
	{
	  operand_rr_info *dest_op_info;
	  struct du_chain *chain;
	  unsigned dest_regno;
	  fma_forest *forest;
	  du_head_p head;
	  int i;

	  if (!is_fmul_fmac_insn (insn, true))
	    continue;

	  /* Search the chain where this instruction is (one of) the root.  */
	  dest_op_info = insn_rr[INSN_UID (insn)].op_info;
	  dest_regno = REGNO (SET_DEST (PATTERN (insn)));
	  for (i = 0; i < dest_op_info->n_chains; i++)
	    {
	      /* The register tracked by this chain does not match the
		 destination register of insn.  */
	      if (dest_op_info->heads[i]->regno != dest_regno)
		continue;

	      head = dest_op_info->heads[i];
	      /* The chain was merged in another, find the new head.  */
	      if (!head->first)
		head = regrename_chain_from_id (head->id);

	      /* Search the chain element for this instruction and, if another
		 FMUL or FMADD/FMSUB instruction was already processed, note
		 the forest of its tree.  */
	      forest = NULL;
	      for (chain = head->first; chain; chain = chain->next_use)
		{
		  fma_node **fma_slot;

		  if (!is_fmul_fmac_insn (chain->insn, true))
		    continue;

		  /* This is a use, continue.  */
		  if (chain->loc != &SET_DEST (PATTERN (chain->insn)))
		    continue;

		  if (chain->insn == insn)
		    break;

		  fma_slot = this->m_insn_fma_head_map->get (chain->insn);
		  if (fma_slot && (*fma_slot)->get_children ())
		    forest = (*fma_slot)->get_forest ();
		}
	      if (chain)
		break;
	    }

	  /* We didn't find a chain with a def for this instruction.  */
	  gcc_assert (i < dest_op_info->n_chains);

	  this->analyze_fma_fmul_insn (forest, chain, head);
	}
    }
void
func_fma_steering::analyze_fma_fmul_insn (fma_forest *ref_forest,
					  du_chain *chain, du_head_p head)
{
  fma_forest *forest;
  fma_node *node = this->get_fma_node (chain->insn);

  /* This is a root node.  */
  if (!node)
    {
      fma_root_node *root_node;

      root_node = new fma_root_node (this, chain, this->m_next_forest_id++);
      forest = root_node->get_forest ();
      node = root_node;

      /* Until proved otherwise, assume this root is not part of an existing
	 forest and thus add its forest to the list of forests.  */
      this->m_fma_forests.push_back (forest);
    }
  else
    forest = node->get_forest ();

  node->set_head (head);

  /* fma_node is part of a chain with several defs, one of them having already
     been processed.  The root of that already processed def is the canonical
     one and the root of fma_node is added to its forest.  No need to process
     the children nodes as they were already processed when the other def was
     processed.  */
  if (ref_forest)
    {
      ref_forest->merge_forest (forest);
      return;
    }

  for (chain = head->first; chain; chain = chain->next_use)
    {
      fma_node *child_fma;
      rtx fma_rtx, *accum_rtx_p;

      if (!is_fmul_fmac_insn (chain->insn, false))
	continue;

      /* Get FMA rtx.  */
      fma_rtx = SET_SRC (PATTERN (chain->insn));
      /* FMA is negated.  */
      if (GET_CODE (fma_rtx) == NEG)
	fma_rtx = XEXP (fma_rtx, 0);
      /* Get accumulator rtx.  */
      accum_rtx_p = &XEXP (fma_rtx, 2);
      /* Accumulator is negated.  */
      if (!REG_P (*accum_rtx_p))
	accum_rtx_p = &XEXP (*accum_rtx_p, 0);

      /* This du_chain structure is not for the accumulator register.  */
      if (accum_rtx_p != chain->loc)
	continue;

      /* If object already created, this is a loop carried dependency.  We
	 don't include this object in the children as we want trees for
	 rename_fma_trees to not be an infinite loop.  */
      if (this->get_fma_node (chain->insn))
	continue;

      child_fma = new fma_node (node, chain);

      /* Memorize the mapping of this instruction to its fma_node object
	 as it will be processed for the chain starting at its destination
	 register later.  */

      /* Link to siblings.  */
      node->add_child (child_fma);
    }
}
void
func_fma_steering::analyze ()
{
  int i, n_blocks, *bb_dfs_preorder;
  basic_block bb;
  rtx_insn *insn;

  bb_dfs_preorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
  n_blocks = pre_and_rev_post_order_compute (bb_dfs_preorder, NULL, false);

  /* Browse the graph of basic blocks looking for FMUL or FMADD/FMSUB
     instructions.  */
  for (i = 0; i < n_blocks; i++)
    {
      bb = BASIC_BLOCK_FOR_FN (cfun, bb_dfs_preorder[i]);
      FOR_BB_INSNS (bb, insn)
	{
	  operand_rr_info *dest_op_info;
	  struct du_chain *chain = NULL;
	  unsigned dest_regno;
	  fma_forest *forest = NULL;
	  du_head_p head = NULL;
	  int i;

	  if (!is_fmul_fmac_insn (insn, true))
	    continue;

	  /* Search the chain where this instruction is (one of) the root.  */
	  dest_op_info = insn_rr[INSN_UID (insn)].op_info;
	  dest_regno = REGNO (SET_DEST (PATTERN (insn)));
	  for (i = 0; i < dest_op_info->n_chains; i++)
	    {
	      /* The register tracked by this chain does not match the
		 destination register of insn.  */
	      if (dest_op_info->heads[i]->regno != dest_regno)
		continue;

	      head = dest_op_info->heads[i];
	      /* The chain was merged in another, find the new head.  */
	      if (!head->first)
		head = regrename_chain_from_id (head->id);

	      /* Search the chain element for this instruction and, if another
		 FMUL or FMADD/FMSUB instruction was already processed, note
		 the forest of its tree.  */
	      forest = NULL;
	      for (chain = head->first; chain; chain = chain->next_use)
		{
		  fma_node **fma_slot;

		  if (!is_fmul_fmac_insn (chain->insn, true))
		    continue;

		  /* This is a use, continue.  */
		  if (chain->loc != &SET_DEST (PATTERN (chain->insn)))
		    continue;

		  if (chain->insn == insn)
		    break;

		  fma_slot = this->m_insn_fma_head_map->get (chain->insn);
		  if (fma_slot && (*fma_slot)->get_children ())
		    forest = (*fma_slot)->get_forest ();
		}
	      if (chain)
		break;
	    }

	  /* Due to implementation of regrename, dest register can slip away
	     from regrename's analysis.  As a result, there is no chain for
	     the destination register of insn.  We simply skip the insn even
	     it is a fmul/fmac instruction.  This can happen when the dest
	     register is also a source register of insn and one of the below
	     conditions is satisfied:
	       1) the source reg is setup in larger mode than this insn;
	       2) the source reg is uninitialized;
	       3) the source reg is passed in as parameter.  */
	  if (i < dest_op_info->n_chains)
	    this->analyze_fma_fmul_insn (forest, chain, head);
	}
    }