+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) {
+ static ident *prefix = NULL;
+ ir_type *res;
+ pmap_entry *e = pmap_find(mtp_map, tp);
+
+ if (e)
+ return e->value;
+
+ if (prefix == NULL)
+ prefix = new_id_from_chars("C", 1);
+
+ res = clone_type_method(tp, prefix);
+ pmap_insert(mtp_map, tp, res);
+ DB((dbgcall, LEVEL_2, "cloned type %+F into %+F\n", 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);
+ set_method_additional_property(ctp, mtp_property_private);
+ set_Call_type(call, ctp);
+ DB((dbgcall, LEVEL_1, "changed call to private method %+F\n", ent));
+ }
+ }
+ }
+ }
+} /* 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 an entity is sticky, it might be called from external
+ places (like inline assembler), so do NOT mark it as private. */
+ if (get_entity_visibility(ent) == visibility_local &&
+ !(flags & ir_usage_address_taken) &&
+ get_entity_stickyness(ent) != stickyness_sticky) {
+ ir_type *mtp = get_entity_type(ent);
+
+ set_entity_additional_property(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);
+ set_entity_type(ent, mtp);
+ set_method_additional_property(mtp, mtp_property_private);
+ changed = 1;
+ }
+ }
+ }
+
+ if (changed)
+ all_irg_walk(NULL, update_calls_to_private, NULL);
+
+ pmap_destroy(mtp_map);
+} /* mark_private_methods */