+/* List node for an inserted pass instance. We need to keep track of all
+ the newly-added pass instances (with 'added_pass_nodes' defined below)
+ so that we can register their dump files after pass-positioning is finished.
+ Registering dumping files needs to be post-processed or the
+ static_pass_number of the opt_pass object would be modified and mess up
+ the dump file names of future pass instances to be added. */
+
+struct pass_list_node
+{
+ struct opt_pass *pass;
+ struct pass_list_node *next;
+};
+
+static struct pass_list_node *added_pass_nodes = NULL;
+static struct pass_list_node *prev_added_pass_node;
+
+/* Insert the pass at the proper position. Return true if the pass
+ is successfully added.
+
+ NEW_PASS_INFO - new pass to be inserted
+ PASS_LIST - root of the pass list to insert the new pass to */
+
+static bool
+position_pass (struct register_pass_info *new_pass_info,
+ struct opt_pass **pass_list)
+{
+ struct opt_pass *pass = *pass_list, *prev_pass = NULL;
+ bool success = false;
+
+ for ( ; pass; prev_pass = pass, pass = pass->next)
+ {
+ /* Check if the current pass is of the same type as the new pass and
+ matches the name and the instance number of the reference pass. */
+ if (pass->type == new_pass_info->pass->type
+ && pass->name
+ && !strcmp (pass->name, new_pass_info->reference_pass_name)
+ && ((new_pass_info->ref_pass_instance_number == 0)
+ || (new_pass_info->ref_pass_instance_number ==
+ pass->static_pass_number)
+ || (new_pass_info->ref_pass_instance_number == 1
+ && pass->todo_flags_start & TODO_mark_first_instance)))
+ {
+ struct opt_pass *new_pass;
+ struct pass_list_node *new_pass_node;
+
+ new_pass = make_pass_instance (new_pass_info->pass, true);
+
+ /* Insert the new pass instance based on the positioning op. */
+ switch (new_pass_info->pos_op)
+ {
+ case PASS_POS_INSERT_AFTER:
+ new_pass->next = pass->next;
+ pass->next = new_pass;
+
+ /* Skip newly inserted pass to avoid repeated
+ insertions in the case where the new pass and the
+ existing one have the same name. */
+ pass = new_pass;
+ break;
+ case PASS_POS_INSERT_BEFORE:
+ new_pass->next = pass;
+ if (prev_pass)
+ prev_pass->next = new_pass;
+ else
+ *pass_list = new_pass;
+ break;
+ case PASS_POS_REPLACE:
+ new_pass->next = pass->next;
+ if (prev_pass)
+ prev_pass->next = new_pass;
+ else
+ *pass_list = new_pass;
+ new_pass->sub = pass->sub;
+ new_pass->tv_id = pass->tv_id;
+ pass = new_pass;
+ break;
+ default:
+ error ("Invalid pass positioning operation");
+ return false;
+ }
+
+ /* Save the newly added pass (instance) in the added_pass_nodes
+ list so that we can register its dump file later. Note that
+ we cannot register the dump file now because doing so will modify
+ the static_pass_number of the opt_pass object and therefore
+ mess up the dump file name of future instances. */
+ new_pass_node = XCNEW (struct pass_list_node);
+ new_pass_node->pass = new_pass;
+ if (!added_pass_nodes)
+ added_pass_nodes = new_pass_node;
+ else
+ prev_added_pass_node->next = new_pass_node;
+ prev_added_pass_node = new_pass_node;
+
+ success = true;
+ }
+
+ if (pass->sub && position_pass (new_pass_info, &pass->sub))
+ success = true;
+ }
+
+ return success;
+}
+
+/* Hooks a new pass into the pass lists.
+
+ PASS_INFO - pass information that specifies the opt_pass object,
+ reference pass, instance number, and how to position
+ the pass */
+
+void
+register_pass (struct register_pass_info *pass_info)
+{
+ bool all_instances, success;
+
+ /* The checks below could fail in buggy plugins. Existing GCC
+ passes should never fail these checks, so we mention plugin in
+ the messages. */
+ if (!pass_info->pass)
+ fatal_error ("plugin cannot register a missing pass");
+
+ if (!pass_info->pass->name)
+ fatal_error ("plugin cannot register an unnamed pass");
+
+ if (!pass_info->reference_pass_name)
+ fatal_error
+ ("plugin cannot register pass %qs without reference pass name",
+ pass_info->pass->name);
+
+ /* Try to insert the new pass to the pass lists. We need to check
+ all five lists as the reference pass could be in one (or all) of
+ them. */
+ all_instances = pass_info->ref_pass_instance_number == 0;
+ success = position_pass (pass_info, &all_lowering_passes);
+ if (!success || all_instances)
+ success |= position_pass (pass_info, &all_small_ipa_passes);
+ if (!success || all_instances)
+ success |= position_pass (pass_info, &all_regular_ipa_passes);
+ if (!success || all_instances)
+ success |= position_pass (pass_info, &all_lto_gen_passes);
+ if (!success || all_instances)
+ success |= position_pass (pass_info, &all_passes);
+ if (!success)
+ fatal_error
+ ("pass %qs not found but is referenced by new pass %qs",
+ pass_info->reference_pass_name, pass_info->pass->name);
+
+ /* OK, we have successfully inserted the new pass. We need to register
+ the dump files for the newly added pass and its duplicates (if any).
+ Because the registration of plugin/backend passes happens after the
+ command-line options are parsed, the options that specify single
+ pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
+ passes. Therefore we currently can only enable dumping of
+ new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
+ are specified. While doing so, we also delete the pass_list_node
+ objects created during pass positioning. */
+ while (added_pass_nodes)
+ {
+ struct pass_list_node *next_node = added_pass_nodes->next;
+ enum tree_dump_index tdi;
+ register_one_dump_file (added_pass_nodes->pass);
+ if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
+ || added_pass_nodes->pass->type == IPA_PASS)
+ tdi = TDI_ipa_all;
+ else if (added_pass_nodes->pass->type == GIMPLE_PASS)
+ tdi = TDI_tree_all;
+ else
+ tdi = TDI_rtl_all;
+ /* Check if dump-all flag is specified. */
+ if (get_dump_file_info (tdi)->state)
+ get_dump_file_info (added_pass_nodes->pass->static_pass_number)
+ ->state = get_dump_file_info (tdi)->state;
+ XDELETE (added_pass_nodes);
+ added_pass_nodes = next_node;
+ }
+}