3 * File name: ir/opt/scalar_replace.c
4 * Purpose: scalar replacement of arrays and compounds
5 * Author: Beyhan Veliev
6 * Modified by: Michael Beck
9 * Copyright: (c) 1998-2005 Universität Karlsruhe
10 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
28 #include "data_flow_scalar_replace.h"
40 #include "analyze_irg_args.h"
43 #define SET_ENT_VNUM(ent, vnum) set_entity_link(ent, INT_TO_PTR(vnum))
44 #define GET_ENT_VNUM(ent) (unsigned)PTR_TO_INT(get_entity_link(ent))
45 #define SET_IRN_VNUM(irn, vnum) set_irn_link(irn, INT_TO_PTR(vnum))
46 #define GET_IRN_VNUM(irn) (unsigned)PTR_TO_INT(get_irn_link(irn))
49 /* To save for an entity all leaves for that the memory
51 typedef struct _ent_leaves_t{
56 typedef struct _sels_t {
61 typedef struct _call_access_t {
63 unsigned int access_type;
66 typedef struct _fixlist_entry_t {
71 typedef struct _syncs_fixlist_entry_t {
74 }syncs_fixlist_entry_t;
76 /* A entry, that save the memory
77 * edge state and the access state for this leave
78 * int the array,that is created for every block.*/
79 typedef struct _leave_t {
80 ir_node *mem_edge_state; /**< memory state for this scalar.*/
81 unsigned int access_type; /**< access state for this scalar.*/
82 set *calls; /**< call nodes,that change this scalar.*/
86 * environment for memory walker
88 typedef struct _env_t {
89 struct obstack obst; /**< a obstack for the memory edge */
90 set *set_sels; /**< a set with all sels, that are reachable from an entity with a scalar.*/
91 set *set_ent; /**< a set with all entities that have one or more scalars.*/
92 fixlist_entry_t *fix_phis; /**< list of all Phi nodes that must be fixed */
93 fixlist_entry_t *fix_ls; /**< list of all Load or Store nodes that must be fixed */
94 syncs_fixlist_entry_t *fix_syncs; /**< list of all Sync nodes that must be fixed */
95 unsigned int nvals; /**< to save the number of scalars.*/
96 unsigned int gl_mem_vnum; /**< indicate the position of the globule memory edge state in var_arr.*/
97 unsigned int vnum_state; /**< indicate the position of the value number state in var_arr.*/
98 unsigned int changes; /**< to save if by anlyse_calls is changed anything.*/
102 * A path element entry: it is either an entity
103 * or a tarval, because we evaluate only constant array
104 * accesses like a.b.c[8].d
112 * An access path, used to assign value numbers
113 * to variables that will be scalar replaced
115 typedef struct _path_t {
116 unsigned vnum; /**< the value number */
117 unsigned path_len; /**< the length of the access path */
118 path_elem_t path[1]; /**< the path */
121 /* we need a special address that serves as an address stored. */
123 static void *ADDRESS_STORED = &_s;
127 * Compare two elements of the ent_leaves_t set.
129 * @return 0 if they are identically
131 static int ent_leaves_t_cmp(const void *elt, const void *key, size_t size)
133 const ent_leaves_t *c1 = elt;
134 const ent_leaves_t *c2 = key;
136 return c1->ent != c2->ent;
140 * Compare two elements of the ent_access_t set.
142 * @return 0 if they are identically
144 static int ent_cmp(const void *elt, const void *key, size_t size)
146 const entity *c1 = elt;
147 const entity *c2 = key;
153 * Compare two elements of the sels_t set.
155 * @return 0 if they are identically
157 static int sels_cmp(const void *elt, const void *key, size_t size)
159 const sels_t *c1 = elt;
160 const sels_t *c2 = key;
162 return c1->sel != c2->sel;
166 * Compare two elements of the leave_t set.
168 * @return 0 if they are identically
170 static int leave_cmp(const void *elt, const void *key, size_t size)
172 const ir_node *c1 = elt;
173 const ir_node *c2 = key;
179 * Compare two elements of the call_access_t set.
181 * @return 0 if they are identically
183 static int call_cmp(const void *elt, const void *key, size_t size)
185 const call_access_t *c1 = elt;
186 const call_access_t *c2 = key;
188 return c1->call != c2->call;
194 * @return 0 if they are identically
196 static int path_cmp(const void *elt, const void *key, size_t size)
198 const path_t *p1 = elt;
199 const path_t *p2 = key;
201 /* we can use memcmp here, because identical tarvals should have identical addresses */
202 return memcmp(p1->path, p2->path, p1->path_len * sizeof(p1->path[0]));
206 * Calculate a hash value for a path.
208 static unsigned path_hash(const path_t *path)
213 for (i = 0; i < path->path_len; ++i)
214 hash ^= (unsigned)PTR_TO_INT(path->path[i].ent);
220 * Returns non-zero, if all induces of a Sel node are constants.
222 * @param sel the Sel node that will be checked
224 static int is_const_sel(ir_node *sel) {
225 int i, n = get_Sel_n_indexs(sel);
227 for (i = 0; i < n; ++i) {
228 ir_node *idx = get_Sel_index(sel, i);
230 if (get_irn_op(idx) != op_Const)
237 * Returns non-zero, if the address of an entity
238 * represented by a Sel node (or it's successor Sels) is taken.
240 static int is_address_taken(ir_node *sel)
244 if (! is_const_sel(sel))
247 for (i = get_irn_n_outs(sel) - 1; i >= 0; --i) {
248 ir_node *succ = get_irn_out(sel, i);
250 switch (get_irn_opcode(succ)) {
252 /* ok, we just load from that entity */
256 /* check that Sel is not the Store's value */
257 if (get_Store_value(succ) == sel)
262 /* Check the Sel successor of Sel */
263 int res = is_address_taken(succ);
271 /* The address of an entity is given as a parameter.
272 * We analyzes that later and optimizes this scalar
278 /* another op, the address is taken */
286 * Link all Sels with the entity.
288 * @param ent the entity that will be scalar replaced
289 * @param sel a Sel node that selects some fields of this entity
291 static void link_all_leave_sels(entity *ent, ir_node *sel)
295 n = get_irn_n_outs(sel);
296 for (i = 0; i < n; ++i) {
297 ir_node *succ = get_irn_out(sel, i);
299 if (get_irn_op(succ) == op_Sel)
300 link_all_leave_sels(ent, succ);
304 /* if Sel nodes with memory inputs are used, a entity can be
305 * visited more than once causing a ring here, so we use the
306 * node flag to mark linked nodes
308 if (irn_visited(sel))
312 * we link the sels to the entity.
314 set_irn_link(sel, get_entity_link(ent));
315 set_entity_link(ent, sel);
317 mark_irn_visited(sel);
320 /* we need a special address that serves as an address taken marker */
322 static void *ADDRESS_TAKEN = &_x;
325 * Find possible scalar replacements.
327 * @param irg an IR graph
329 * This function finds variables on the (members of the) frame type
330 * that can be scalar replaced, because their address is never taken.
331 * If such a variable is found, it's entity link will hold a list of all
332 * Sel nodes, that selects anythings of this entity.
333 * Otherwise, the link will be ADDRESS_TAKEN or NULL.
335 * @return non-zero if at least one entity could be replaced
338 static int find_possible_replacements(ir_graph *irg)
340 ir_node *irg_frame = get_irg_frame(irg);
344 inc_irg_visited(irg);
346 n = get_irn_n_outs(irg_frame);
349 * First, clear the link field of all interestingentities.
350 * Note that we did not rely on the fact that there is only
351 * one Sel node per entity, so we might access one entity
352 * more than once here.
353 * That's why we have need two loops.
355 for (i = 0; i < n; ++i) {
356 ir_node *succ = get_irn_out(irg_frame, i);
358 if (get_irn_op(succ) == op_Sel) {
359 entity *ent = get_Sel_entity(succ);
360 set_entity_link(ent, NULL);
365 * Check the ir_graph for Sel nodes. If the entity of Sel
366 * isn't a scalar replacement set the link of this entity
367 * equal ADDRESS_TAKEN.
369 for (i = 0; i < n; ++i) {
370 ir_node *succ = get_irn_out(irg_frame, i);
372 if (get_irn_op(succ) == op_Sel) {
373 entity *ent = get_Sel_entity(succ);
376 if (get_entity_link(ent) == ADDRESS_TAKEN)
379 ent_type = get_entity_type(ent);
381 /* we can handle arrays, structs and atomic types yet */
382 if (is_Array_type(ent_type) || is_Struct_type(ent_type) || is_atomic_type(ent_type)) {
383 if (is_address_taken(succ)) {
384 if (get_entity_link(ent)) /* killing one */
386 set_entity_link(ent, ADDRESS_TAKEN);
389 /* possible found one */
390 if (get_entity_link(ent) == NULL)
392 link_all_leave_sels(ent, succ);
401 static int is_leave_sel(ir_node *sel) {
405 for(i = get_irn_n_outs(sel) - 1; i >= 0; i--) {
406 succ = get_irn_out(sel, i);
407 if(get_irn_op(succ) == op_Sel)
415 * Return a path from the Sel node sel to it's root.
417 * @param sel the Sel node
418 * @param len the length of the path so far
420 static path_t *find_path(ir_node *sel, unsigned len)
424 ir_node *pred = get_Sel_ptr(sel);
426 /* the current Sel node will add some path elements */
427 n = get_Sel_n_indexs(sel);
430 if (get_irn_op(pred) != op_Sel) {
431 /* we found the root */
433 res = xmalloc(sizeof(*res) + (len - 1) * sizeof(res->path));
437 res = find_path(pred, len);
439 pos = res->path_len - len;
441 res->path[pos++].ent = get_Sel_entity(sel);
442 for (i = 0; i < n; ++i) {
443 ir_node *index = get_Sel_index(sel, i);
445 res->path[pos++].tv = get_Const_tarval(index);
451 * Allocate value numbers for the leaves
452 * in our found entities.
454 * @param sels a set that will contain all Sels that have a value number
455 * @param ent the entity that will be scalar replaced
456 * @param vnum the first value number we can assign
457 * @param modes a flexible array, containing all the modes of
460 * @return the next free value number
462 static unsigned allocate_value_numbers(set *set_sels, pset *leaves, entity *ent, unsigned vnum)
467 set *pathes = new_set(path_cmp, 8);
469 /* visit all Sel nodes in the chain of the entity */
470 for (sel = get_entity_link(ent); sel; sel = next) {
471 next = get_irn_link(sel);
473 /* we save for every sel it root entity, why
474 * we need this information, when we split the memory edge,
475 * and we must mark this sel for later. */
478 set_insert(set_sels, &key_sels, sizeof(key_sels), HASH_PTR(sel));
480 if(! is_leave_sel(sel))
483 /* We have found a leave and we add it to the pset of this entity.*/
484 pset_insert_ptr(leaves, sel);
486 key = find_path(sel, 0);
487 path = set_find(pathes, key, sizeof(*key) + sizeof(key->path[0]) * key->path_len, path_hash(key));
490 SET_IRN_VNUM(sel, path->vnum);
495 set_insert(pathes, key, sizeof(*key) + sizeof(key->path[0]) * key->path_len, path_hash(key));
497 SET_IRN_VNUM(sel, key->vnum);
503 set_entity_link(ent, NULL);
506 /* Analyze if this scalar was stored in this block
508 static int is_scalar_stored(ir_node *call_blk, int ent_vnum) {
510 value_arr_entry_t *val_arr, *val_arr_pred;
514 val_arr = get_irn_link(call_blk);
516 if(val_arr[ent_vnum].access_type == 0)
519 n = get_Block_n_cfgpreds(call_blk) - 1;
521 for( ; n >= 0; n--) {
522 pred = get_Block_cfgpred(call_blk, n);
523 pred = get_nodes_block(pred);
524 val_arr_pred = get_irn_link(pred);
526 if(val_arr_pred[ent_vnum].access_type != 0)
527 /* This scalar wasn't stored in this block.*/
534 /* The function handles the call nodes, that have
535 * as parameter a scalar*/
536 static void handle_call(env_t *env, ir_node *call, pset *accessed_entities) {
538 ent_leaves_t key_ent, *value_ent;
539 value_arr_entry_t *val_arr;
540 call_access_t key_call, *value_call;
541 ir_node *call_blk, *new_mem_state, *leave;
545 syncs_fixlist_entry_t *s;
546 int fix_irn = 0, *accessed_leaves_vnum = NULL;
549 call_blk = get_nodes_block(call);
550 val_arr = get_irn_link(call_blk);
551 /* To save the memory edges, that must be
553 in = NEW_ARR_F(ir_node *, 1);
554 /* To save the value numbers of the memory
555 * edges that must be repaired.*/
556 accessed_leaves_vnum = NEW_ARR_F(int, 0);
558 /* We get the memory successor of the call node.
559 * It is the new memory state for all synced memory
561 new_mem_state = get_irn_out(call, 0);
562 if(get_irn_mode(new_mem_state) != mode_M)
563 new_mem_state = get_irn_out(call,1);
565 if(val_arr[env->gl_mem_vnum].mem_edge_state == NULL) {
566 in[0] = new_Unknown(mode_M);
569 in[0] = val_arr[env->gl_mem_vnum].mem_edge_state;
571 for(ent = pset_first(accessed_entities); ent; ent = pset_next(accessed_entities)) {
572 /* Whit this loop we iterate all accessed entities an collect
573 * all memory edges, that we must sync.*/
574 ent_vnum = GET_ENT_VNUM(ent);
576 key_call.call = call;
577 value_call = set_find(val_arr[ent_vnum].calls, &key_call, sizeof(key_call), HASH_PTR(key_call.call));
580 value_ent = set_find(env->set_ent, &key_ent, sizeof(key_ent), HASH_PTR(key_ent.ent));
582 if(!is_scalar_stored(call_blk, ent_vnum)) {
583 /* This scalar's address wasn't stored in this block.*/
584 switch(value_call->access_type) {
586 case ptr_access_none :
587 /* In this case we have nothing to do.*/
590 case ptr_access_read:
591 case ptr_access_write:
595 /* All this cases must be traded equal.*/
597 for(leave = pset_first(value_ent->leaves); leave; leave = pset_next(value_ent->leaves)){
598 /* All this memory edges must be synced.*/
599 if(val_arr[GET_IRN_VNUM(leave)].mem_edge_state != NULL)
600 ARR_APP1(ir_node *, in, val_arr[GET_IRN_VNUM(leave)].mem_edge_state);
602 ARR_APP1(int, accessed_leaves_vnum, GET_IRN_VNUM(leave));
603 ARR_APP1(ir_node *, in, new_Unknown(mode_M));
606 /* We update the memory state of this leave.*/
607 if(value_call->access_type != ptr_access_read)
608 val_arr[GET_IRN_VNUM(leave)].mem_edge_state = new_mem_state;
617 /* We must update the global memory state.*/
618 val_arr[env->gl_mem_vnum].mem_edge_state = new_mem_state;
620 if(ARR_LEN(in) == 1) {
621 /* we must set the call memory to gobale momory*/
622 set_Call_mem(call,in[0]);
625 /* We add this call node to the call fix list..*/
626 l = obstack_alloc(&env->obst, sizeof(*l));
628 l->vnum = env->gl_mem_vnum;
629 set_irn_link(l->irn, env->fix_ls);
633 /* We create the sync and set it as memory predecessor of the call node.*/
634 sync = new_r_Sync(current_ir_graph, call_blk, ARR_LEN(in), in);
635 set_Call_mem(call, sync);
638 /* We add this sync node to the sync's fix list.*/
639 s = obstack_alloc(&env->obst, sizeof(*s));
641 s->accessed_vnum = accessed_leaves_vnum;
642 set_irn_link(sync, env->fix_syncs);
649 /* The function split the memory edge.*/
650 static void split_memory_edge(ir_node *irn, void *ctx) {
653 ir_node *new_mem_state, *mem_state, *unk;
654 ir_node *leave, *sel, *irn_blk, **in;
656 sels_t key_sels, *value_sels;
657 ent_leaves_t key_ent, *value_ent;
658 value_arr_entry_t *val_arr;
660 pset *accessed_entities;
661 unsigned ent_vnum, sel_vnum;
665 op = get_irn_op(irn);
667 if(op == op_Load || op == op_Store) {
670 key_sels.sel = get_Load_ptr(irn);
672 key_sels.sel = get_Store_ptr(irn);
674 value_sels = set_find(env->set_sels, &key_sels, sizeof(key_sels), HASH_PTR(key_sels.sel));
676 if(value_sels != NULL) {
677 /* we have found a load or store, that use a sel of our set
678 * and we must split or extend, if the memory edge have been
679 * split for this sel, the memory edge.*/
681 key_ent.ent = value_sels->ent;
682 value_ent = set_find(env->set_ent, &key_ent, sizeof(key_ent), HASH_PTR(key_ent.ent));
683 assert(value_ent && " This sel's entity isn't int the entity set.");
685 leave = pset_find_ptr(value_ent->leaves, key_sels.sel);
687 assert(leave && "Anything in data_flow_scalar_replacment algorithm is wrong.");
689 ent_vnum = GET_ENT_VNUM(value_ent->ent);
690 sel_vnum = GET_IRN_VNUM(leave);
692 irn_blk = get_nodes_block(irn);
693 val_arr = get_irn_link(irn_blk);
695 if(val_arr[ent_vnum].access_type == 0)
696 /* We have found a scalar, that address i not stored as jet.*/
699 /* This scalar have been stored.*/
700 i = env->gl_mem_vnum;
702 if(val_arr[i].mem_edge_state == NULL) {
703 /* We split now for this sel the memory edge in this block.*/
704 mem_state = new_Unknown(mode_M);
705 /* We must mark this node to fix later*/
706 l = obstack_alloc(&env->obst, sizeof(*l));
710 set_irn_link(irn, env->fix_ls);
713 /* We have split the memory edge and the current state is saved.*/
714 mem_state = val_arr[i].mem_edge_state;
716 /* We set this Load or Store to the memory edge of this
719 set_Load_mem(irn, mem_state);
721 set_Store_mem(irn, mem_state);
723 /* When we have split or extended the memory edge we must
724 * update the memory_edge_state of this sel*/
725 new_mem_state = get_irn_out(irn, 0);
726 if(get_irn_mode(new_mem_state) == mode_M)
727 val_arr[i].mem_edge_state = new_mem_state;
729 val_arr[i].mem_edge_state = get_irn_out(irn, 1);
733 if (op == op_Phi && get_irn_mode(irn) == mode_M) {
735 * found a memory Phi: Here, we must create new Phi nodes
737 irn_blk = get_nodes_block(irn);
738 val_arr = get_irn_link(irn_blk);
740 n = get_Block_n_cfgpreds(irn_blk);
742 in = alloca(sizeof(*in) * n);
744 for (i = val_arr[env->gl_mem_vnum].access_type - 1; i >= 0; --i) {
745 unk = new_Unknown(mode_M);
746 for (j = n - 1; j >= 0; --j)
749 val_arr[i].mem_edge_state = new_r_Phi(current_ir_graph, irn_blk, n, in, mode_M);
751 l = obstack_alloc(&env->obst, sizeof(*l));
752 l->irn = val_arr[i].mem_edge_state;
755 set_irn_link(val_arr[i].mem_edge_state, env->fix_phis);
760 /* We save in this set all entities,
761 * that are accessed from this call node.*/
762 accessed_entities = new_pset(ent_cmp, 8);
764 for ( i = get_Call_n_params(irn) - 1; i >= 0; i--) {
765 sel = get_Call_param(irn, i);
766 if(get_irn_op(sel) == op_Sel) {
768 value_sels = set_find(env->set_sels, &key_sels, sizeof(key_sels), HASH_PTR(key_sels.sel));
771 if(value_sels != NULL)
772 /* We save in this set all accessed entities from this call node.*/
773 pset_insert(accessed_entities, value_sels->ent, HASH_PTR(value_sels->ent));
775 if(pset_count(accessed_entities))
776 handle_call(env, irn, accessed_entities);
781 * searches through blocks beginning from block for value
782 * vnum and return it.
784 static ir_node *find_value(ir_node *block, unsigned vnum)
786 value_arr_entry_t *val_arr;
790 if (Block_not_block_visited(block)) {
791 mark_Block_block_visited(block);
793 val_arr = get_irn_link(block);
795 if (val_arr[vnum].mem_edge_state)
796 return val_arr[vnum].mem_edge_state;
798 for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
799 ir_node *pred = get_Block_cfgpred(block, i);
801 res = find_value(get_nodes_block(pred), vnum);
810 * fix the Load/Store or Call list
812 static void fix_ls(env_t *env)
815 ir_node *irn, *block, *pred, *val;
819 for (l = env->fix_ls; l; l = get_irn_link(irn)) {
822 op = get_irn_op(irn);
823 block = get_nodes_block(irn);
824 for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
825 pred = get_Block_cfgpred(block, i);
826 pred = get_nodes_block(pred);
828 inc_irg_block_visited(current_ir_graph);
829 val = find_value(pred, l->vnum);
836 set_Store_mem(irn, val);
839 set_Load_mem(irn, val);
841 set_Call_mem(irn, val);
848 static void fix_phis(env_t *env)
851 ir_node *phi, *block, *pred, *val;
854 for (l = env->fix_phis; l; l = get_irn_link(phi)) {
857 block = get_nodes_block(phi);
858 for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
860 pred = get_Block_cfgpred(block, i);
861 pred = get_nodes_block(pred);
863 inc_irg_block_visited(current_ir_graph);
864 val = find_value(pred, l->vnum);
867 set_irn_n(phi, i, val);
876 static void fix_syncs(env_t *env)
878 syncs_fixlist_entry_t *l;
879 ir_node *sync, *block, *pred, *val;
883 for (l = env->fix_syncs; l; l = get_irn_link(sync)) {
886 /* The sync block must have one predecessor, when it
887 have unknown nodes as predecessor.*/
888 block = get_nodes_block(sync);
889 pred = get_Block_cfgpred(block, 0);
890 pred = get_nodes_block(pred);
892 /* We first repair the global memory edge at the first position of sync predecessors.*/
893 if(get_irn_op(get_irn_n(sync, 0)) == op_Unknown) {
894 inc_irg_block_visited(current_ir_graph);
895 val = find_value(pred, env->gl_mem_vnum);
896 set_irn_n(sync, 0, val);
899 for (i = get_irn_arity(sync) - 1; i >= 0; --i) {
900 /* We repair the leaves*/
901 if(get_irn_op(get_irn_n(sync, i)) == op_Unknown) {
902 inc_irg_block_visited(current_ir_graph);
903 val = find_value(pred, l->accessed_vnum[k++]);
904 set_irn_n(sync, i, val);
909 /* For the end node we must sync all memory edges.*/
910 static void sync_mem_edges(env_t *env) {
912 ent_leaves_t *entry_ent;
914 value_arr_entry_t *val_arr;
915 ir_node **in, *sync, *Return, *Return_blk;
918 Return = get_Block_cfgpred(get_irg_end_block(current_ir_graph), 0);
919 Return_blk = get_nodes_block(Return);
920 val_arr = get_irn_link(Return_blk);
921 /* We allocate the memory, that we need for the successors of the sync.*/
922 in = malloc(sizeof(ir_node*) *val_arr[env->vnum_state].access_type);
923 /* The global memory edge is the first predecessor of this sync node.*/
924 if(val_arr[env->gl_mem_vnum].mem_edge_state == NULL) {
925 /* We must search through blocks for this memory state.*/
926 inc_irg_block_visited(current_ir_graph);
927 in[0] = find_value(Return_blk, env->gl_mem_vnum);
930 in[0] = val_arr[env->gl_mem_vnum].mem_edge_state;
933 for(entry_ent = set_first(env->set_ent); entry_ent; entry_ent = set_next(env->set_ent)) {
934 if(val_arr[GET_ENT_VNUM(entry_ent->ent)].access_type ==0)
935 /* The address of this entity was not stored. We must sync the memory edges of it's scalars.*/
936 for(leave = pset_first(entry_ent->leaves); leave; leave = pset_next(entry_ent->leaves)) {
937 if(val_arr[GET_IRN_VNUM(leave)].mem_edge_state == NULL) {
938 /* We must search through blocks for this memory state.*/
939 inc_irg_block_visited(current_ir_graph);
940 in[i] = find_value(Return_blk, GET_IRN_VNUM(leave));
943 in[i] = val_arr[GET_IRN_VNUM(leave)].mem_edge_state;
948 //assert(i < env->nvals && "Our nvals algorithm is baggy." );
950 sync = new_r_Sync(current_ir_graph, Return_blk, val_arr[env->vnum_state].access_type, in);
951 set_Return_mem(Return, sync);
957 * Walker: allocate the value array for every block.
959 static void alloc_value_arr(ir_node *block, void *ctx)
963 value_arr_entry_t *var_arr = obstack_alloc(&env->obst, sizeof(value_arr_entry_t) *(env->nvals + set_count(env->set_ent) + 1));
965 /* the value array is empty at start */
966 memset(var_arr, 0, sizeof(value_arr_entry_t) * (env->nvals + set_count(env->set_ent) + 1));
967 set_irn_link(block, var_arr);
968 /* We set the block value number state to optimal and later we update this.*/
969 var_arr[env->vnum_state].access_type = env->nvals;
971 if(get_irg_start_block(current_ir_graph) == block)
972 for(i = (env->nvals + set_count(env->set_ent)) ; i >=0; i--)
973 var_arr[i].mem_edge_state = get_irg_initial_mem(current_ir_graph);
977 /* Analyze call nodes to get information, if they store the address of a scalar. */
978 static void analyse_calls(ir_node *irn, void *ctx) {
981 unsigned int acces_type;
983 ir_node *param, *call_ptr, *blk;
986 sels_t key_sels, *value_sels;
987 call_access_t key_call, *value_call;
988 value_arr_entry_t *val_arr;
989 ent_leaves_t key_ent, *value_ent;
991 if(get_irn_op(irn) != op_Call)
994 for ( i = get_Call_n_params(irn) - 1; i >= 0; i--) {
995 param = get_Call_param(irn, i);
996 if(get_irn_op(param) == op_Sel) {
998 key_sels.sel = param;
999 value_sels = set_find(env->set_sels, &key_sels, sizeof(key_sels), HASH_PTR(key_sels.sel));
1000 if(value_sels != NULL ) {
1001 /* We have found a call, that have as parameter a sel from our set_sels.*/
1002 call_ptr = get_Call_ptr(irn);
1003 op = get_irn_op(call_ptr);
1005 if(op == op_SymConst && get_SymConst_kind(call_ptr) == symconst_addr_ent)
1006 meth_ent = get_SymConst_entity(call_ptr);
1009 /* we get the access type for our sel.*/
1010 acces_type = get_method_param_access(meth_ent, i);
1011 /* we save the access type and this call in the array allocated for this block.
1012 * The value number of this entity get us the position in the array to save this
1013 * information. Why we expect more calls as one we allocate a set.*/
1014 vnum = GET_ENT_VNUM(value_sels->ent);
1015 blk = get_nodes_block(irn);
1016 val_arr = get_irn_link(blk);
1018 if(val_arr[vnum].access_type > 3)
1019 /* The address of this entity have been stored.*/
1022 if(val_arr[vnum].calls == NULL)
1023 /* for this entity i have found the firs call in this block and we must allocate the set.*/
1024 val_arr[vnum].calls = new_set(call_cmp, 8);
1026 /* This call performs anything with the scalar and we must mark it.*/
1027 key_call.call = irn;
1028 key_call.access_type = acces_type;
1029 value_call = set_insert(val_arr[vnum].calls, &key_call, sizeof(key_call), HASH_PTR(key_call.call));
1031 if(value_call->access_type < acces_type)
1032 /* this case tread, when a call access an entity more at once.
1033 * Than we must save the highest access type.*/
1034 value_call->access_type = acces_type;
1036 if(acces_type > 3) {
1037 /* This call save the address of our scalar and we can't
1038 * use the scalars of this entity for optimization as from now.
1040 val_arr[vnum].access_type = acces_type;
1041 /* We must update our scalars number.*/
1042 key_ent.ent = value_sels->ent;
1043 value_ent = set_find(env->set_ent, &key_ent, sizeof(key_ent), HASH_PTR(key_ent.ent));
1044 val_arr[env->vnum_state].access_type -= pset_count(value_ent->leaves);
1050 /* Update the access information of a block if a predecessor of
1051 * this black have a store access for an entity.*/
1052 static void set_block_access(ir_node *irn, void *ctx){
1054 value_arr_entry_t *val_arr, *val_arr_pred;
1055 ent_leaves_t *value_leaves;
1057 ir_node *pred, *pred_blk;
1060 val_arr = get_irn_link(irn);
1062 for( i = get_Block_n_cfgpreds(irn) - 1; i >= 0; i--) {
1063 /* We analyze the predecessors of this block to see if this block must
1065 pred = get_Block_cfgpred(irn, i);
1066 pred_blk = get_nodes_block(pred);
1067 val_arr_pred = get_irn_link(pred_blk);
1069 for(value_leaves = set_first(env->set_ent); value_leaves; value_leaves = set_next(env->set_ent)) {
1070 vnum = GET_ENT_VNUM(value_leaves->ent);
1072 if((val_arr_pred[vnum].access_type > 3) && (val_arr[vnum].access_type < 3)) {
1073 /* We have found a block for update it access and value number information.*/
1074 val_arr[vnum].access_type = val_arr_pred[vnum].access_type;
1075 val_arr[env->vnum_state].access_type = val_arr_pred[env->vnum_state].access_type;
1082 static void print_block_state(ir_node *irn, void *ctx) {
1085 value_arr_entry_t *val_arr;
1086 ent_leaves_t *value_leaves;
1087 call_access_t *value_calls;
1090 val_arr = get_irn_link(irn);
1092 ir_printf("\n\nThe actual value number state of this block is: %i \n", val_arr[env->vnum_state].access_type - 1);
1094 for(value_leaves = set_first(env->set_ent); value_leaves; value_leaves = set_next(env->set_ent)) {
1095 vnum = GET_ENT_VNUM(value_leaves->ent);
1096 ir_printf("The entity %F access type in the block with nr %u is %i \n", value_leaves->ent, get_irn_node_nr(irn),
1097 val_arr[vnum].access_type);
1098 if(val_arr[vnum].calls != NULL)
1099 for(value_calls = set_first(val_arr[vnum].calls); value_calls; value_calls = set_next(val_arr[vnum].calls))
1100 ir_printf("A call with nr %i acess a element of this entity with access %u \n",
1101 get_irn_node_nr(value_calls->call), value_calls->access_type);
1106 /** Optimize the found scalar replacements.
1108 * @param sels A pset with all sels nodes,
1109 * that belong to our scalars.
1111 static void do_data_flow_scalar_replacement(set *set_ent, set *set_sels, int vnum) {
1115 obstack_init(&env.obst);
1116 env.set_ent = set_ent;
1117 env.set_sels = set_sels;
1119 env.fix_phis = NULL;
1120 env.fix_syncs = NULL;
1121 env.gl_mem_vnum = vnum - 2;
1122 env.vnum_state = vnum - 1;
1123 /* nvals are vnum - 1, why we indicate with nvals the number
1124 * of memory edges we will produce. For vnum_state we don't
1125 * need to produce a memory edge.*/
1126 env.nvals = vnum - 1;
1129 /* first step: allocate the value arrays for every block */
1130 irg_block_walk_graph(current_ir_graph, NULL, alloc_value_arr, &env);
1132 /* second step: we analyze all calls, that have as parameter scalar(s)
1133 * and we mark this calls. If the call save the address of a scalar we
1134 * mark the entity owner of this scalar as not optimizeble by now.*/
1135 irg_walk_graph(current_ir_graph, NULL, analyse_calls, &env);
1137 while(env.changes) {
1142 * third step: walk over the blocks of a graph and update
1143 * the information for the access of our scalars.
1145 irg_block_walk_graph(current_ir_graph, NULL, set_block_access, &env);
1148 /* Debug info to see if analyse_calls work properly.*/
1149 irg_block_walk_graph(current_ir_graph, NULL, print_block_state, &env);
1151 * fourth step: walk over the graph blockwise in topological order
1152 * and split the memrory edge.
1154 irg_walk_blkwise_graph(current_ir_graph, NULL, split_memory_edge, &env);
1156 /* fifth step: fix all nodes, that have as predecessor Unknown.*/
1161 sync_mem_edges(&env);
1165 * Find possible scalar replacements
1167 * @param irg The current ir graph.
1169 void data_flow_scalar_replacement_opt(ir_graph *irg)
1176 ent_leaves_t key_leaves, *value_leaves;
1179 if (! get_opt_scalar_replacement())
1182 rem = current_ir_graph;
1183 set_sels = new_set(sels_cmp, 8);
1184 set_ent = new_set(ent_leaves_t_cmp, 8);
1186 /* Call algorithm that computes the out edges */
1187 if (get_irg_outs_state(irg) != outs_consistent)
1188 compute_irg_outs(irg);
1190 /* Find possible scalar replacements */
1191 if (find_possible_replacements(irg)) {
1193 if (get_opt_scalar_replacement_verbose()) {
1194 printf("Scalar Replacement: %s\n", get_entity_name(get_irg_entity(irg)));
1197 /* Insert in set the scalar replacements. */
1198 irg_frame = get_irg_frame(irg);
1200 for (i = 0 ; i < get_irn_n_outs(irg_frame); i++) {
1201 ir_node *succ = get_irn_out(irg_frame, i);
1203 if (get_irn_op(succ) == op_Sel) {
1204 entity *ent = get_Sel_entity(succ);
1206 if (get_entity_link(ent) == NULL || get_entity_link(ent) == ADDRESS_TAKEN)
1208 /* we have found a entity, that have scalars and we insert it to our set_ent*/
1209 key_leaves.ent = ent;
1210 key_leaves.leaves = new_pset(leave_cmp, 8);
1211 value_leaves = set_insert(set_ent, &key_leaves, sizeof(key_leaves), HASH_PTR(ent));
1213 /* We allocate for every leave sel a vnum.*/
1214 vnum = allocate_value_numbers(set_sels, value_leaves->leaves, ent, vnum);
1217 printf("vnumber in data flow= %i\n", vnum);
1219 /* Allocate value number for the globule memory edge.
1220 * and a value number for the value numbers state.*/
1223 /* Allocate value numbers for the entities .*/
1224 for(i = vnum,value_leaves = set_first(set_ent); value_leaves; i++, value_leaves = set_next(set_ent))
1225 SET_ENT_VNUM(value_leaves->ent, i);
1228 do_data_flow_scalar_replacement(set_ent, set_sels, vnum);