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); } }