- ir_node *copy, *new_call;
- int n_params;
-
- n_params = get_Call_n_params(call);
- copy = get_irn_link(call);
-
- /* We iterate the list of the "call".*/
- for( ; copy; copy = get_irn_link(copy)){
- if(!is_ir_node(copy) ||
- get_irn_irg(copy) == get_irn_irg(call))
- break;
- /* A clone exist and the copy of "call" in this
- * clon graph must be exchanged with new one.*/
- new_call = new_cl_Call(copy, new_entity, pos);
- exchange(copy, new_call);
- /* The list muss be updatet too.*/
- set_irn_link(call, new_call);
- call = new_call;
- }
+ size_t pos = q->pos;
+ ir_node *new_call, *call;
+ size_t i;
+
+ /* We iterate the list of the "call".*/
+ for (i = 0; i < ARR_LEN(q->calls); ++i) {
+ call = q->calls[i];
+
+ /* A clone exist and the copy of "call" in this
+ * clone graph must be exchanged with new one.*/
+ new_call = new_cl_Call(call, cloned_ent, pos);
+ exchange(call, new_call);
+ }
+}
+
+/**
+ * The weight formula:
+ * We save one instruction in every caller and param_weight instructions
+ * in the callee.
+ */
+static float calculate_weight(const entry_t *entry)
+{
+ return ARR_LEN(entry->q.calls) *
+ (float)(get_method_param_weight(entry->q.ent, entry->q.pos) + 1);
+}
+
+/**
+ * After we exchanged all calls, some entries on the list for
+ * the next cloned entity may get invalid, so we have to check
+ * them and may even update the list of heavy uses.
+ */
+static void reorder_weights(q_set *hmap, float threshold)
+{
+ entry_t **adr, *p, *entry;
+ size_t i, len;
+ ir_entity *callee;
+
+restart:
+ entry = hmap->heavy_uses;
+ if (! entry)
+ return;
+
+ len = ARR_LEN(entry->q.calls);
+ for (i = 0; i < len; ++i) {
+ ir_node *ptr, *call = entry->q.calls[i];
+
+ /* might be exchanged, so skip Id nodes here. */
+ call = skip_Id(call);
+
+ /* we know, that a SymConst is here */
+ ptr = get_Call_ptr(call);
+ assert(is_SymConst(ptr));
+
+ callee = get_SymConst_entity(ptr);
+ if (callee != entry->q.ent) {
+ /*
+ * This call is already changed because of a previous
+ * optimization. Remove it from the list.
+ */
+ --len;
+ entry->q.calls[i] = entry->q.calls[len];
+ entry->q.calls[len] = NULL;
+
+ /* the new call should be processed */
+ process_call(call, callee, hmap);
+ --i;
+ }
+ }
+
+ /* the length might be changed */
+ ARR_SHRINKLEN(entry->q.calls, len);
+
+ /* recalculate the weight and resort the heavy uses map */
+ entry->weight = calculate_weight(entry);
+
+ if (len <= 0 || entry->weight < threshold) {
+ hmap->heavy_uses = entry->next;
+ kill_entry(entry);
+
+ /* we have changed the list, check the next one */
+ goto restart;
+ }
+
+ adr = NULL;
+ for (p = entry->next; p && entry->weight < p->weight; p = p->next) {
+ adr = &p->next;
+ }
+
+ if (adr) {
+ hmap->heavy_uses = entry->next;
+ entry->next = *adr;
+ *adr = entry;
+ entry = hmap->heavy_uses;
+
+ /* we have changed the list, check the next one */
+ goto restart;
+ }