+void assure_irp_globals_entity_usage_computed(void)
+{
+ if (irp->globals_entity_usage_state != ir_entity_usage_not_computed)
+ return;
+
+ analyse_irp_globals_entity_usage();
+}
+
+void firm_init_memory_disambiguator(void)
+{
+ FIRM_DBG_REGISTER(dbg, "firm.ana.irmemory");
+ FIRM_DBG_REGISTER(dbgcall, "firm.opt.cc");
+}
+
+
+/** Maps method types to cloned method types. */
+static pmap *mtp_map;
+
+/**
+ * Clone a method type if not already cloned.
+ *
+ * @param tp the type to clone
+ */
+static ir_type *clone_type_and_cache(ir_type *tp)
+{
+ ir_type *res;
+ pmap_entry *e = pmap_find(mtp_map, tp);
+
+ if (e != NULL)
+ return (ir_type*) e->value;
+
+ res = clone_type_method(tp);
+ pmap_insert(mtp_map, tp, res);
+
+ return res;
+} /* clone_type_and_cache */
+
+/**
+ * Walker: clone all call types of Calls to methods having the
+ * mtp_property_private property set.
+ */
+static void update_calls_to_private(ir_node *call, void *env)
+{
+ (void) env;
+ if (is_Call(call)) {
+ ir_node *ptr = get_Call_ptr(call);
+
+ if (is_SymConst(ptr)) {
+ ir_entity *ent = get_SymConst_entity(ptr);
+ ir_type *ctp = get_Call_type(call);
+
+ if (get_entity_additional_properties(ent) & mtp_property_private) {
+ if ((get_method_additional_properties(ctp) & mtp_property_private) == 0) {
+ ctp = clone_type_and_cache(ctp);
+ add_method_additional_properties(ctp, mtp_property_private);
+ set_Call_type(call, ctp);
+ DB((dbgcall, LEVEL_1, "changed call to private method %+F using cloned type %+F\n", ent, ctp));
+ }
+ }
+ }
+ }
+} /* update_calls_to_private */
+
+/* Mark all private methods, i.e. those of which all call sites are known. */
+void mark_private_methods(void)
+{
+ int i;
+ int changed = 0;
+
+ assure_irp_globals_entity_usage_computed();
+
+ mtp_map = pmap_create();
+
+ /* first step: change the calling conventions of the local non-escaped entities */
+ for (i = get_irp_n_irgs() - 1; i >= 0; --i) {
+ ir_graph *irg = get_irp_irg(i);
+ ir_entity *ent = get_irg_entity(irg);
+ ir_entity_usage flags = get_entity_usage(ent);
+
+ if (!entity_is_externally_visible(ent) &&
+ !(flags & ir_usage_address_taken)) {
+ ir_type *mtp = get_entity_type(ent);
+
+ add_entity_additional_properties(ent, mtp_property_private);
+ DB((dbgcall, LEVEL_1, "found private method %+F\n", ent));
+ if ((get_method_additional_properties(mtp) & mtp_property_private) == 0) {
+ /* need a new type */
+ mtp = clone_type_and_cache(mtp);
+ add_method_additional_properties(mtp, mtp_property_private);
+ set_entity_type(ent, mtp);
+ DB((dbgcall, LEVEL_2, "changed entity type of %+F to %+F\n", ent, mtp));
+ changed = 1;
+ }
+ }
+ }
+
+ if (changed)
+ all_irg_walk(NULL, update_calls_to_private, NULL);
+
+ pmap_destroy(mtp_map);
+} /* mark_private_methods */
+
+/* create a pass for mark_private_methods() */
+ir_prog_pass_t *mark_private_methods_pass(const char *name)
+{
+ return def_prog_pass(name ? name : "mark_private_methods", mark_private_methods);
+} /* mark_private_methods_pass */