3 * File name: ir/opt/ldstopt.c
4 * Purpose: load store optimizations
8 * Copyright: (c) 1998-2004 Universit
\81ät Karlsruhe
9 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
11 # include "irnode_t.h"
12 # include "irgraph_t.h"
13 # include "irmode_t.h"
15 # include "ircons_t.h"
20 # include "dbginfo_t.h"
21 # include "iropt_dbg.h"
22 # include "irflag_t.h"
24 # include "firmstat.h"
27 #define IMAX(a,b) ((a) > (b) ? (a) : (b))
29 #define MAX_PROJ IMAX(pn_Load_max, pn_Store_max)
34 typedef struct _walk_env_t {
35 struct obstack obst; /**< list of all stores */
42 typedef struct _ldst_info_t {
43 ir_node *projs[MAX_PROJ]; /**< list of Proj's of this node */
44 ir_node *exc_block; /**< the exception block if available */
45 int exc_idx; /**< predecessor index in the exception block */
49 * walker, clears all links first
51 static void init_links(ir_node *n, void *env)
53 set_irn_link(n, NULL);
57 * get the Load/Store info of a node
59 static ldst_info_t *get_info(ir_node *node, walk_env_t *env)
61 ldst_info_t *info = get_irn_link(node);
64 info = obstack_alloc(&env->obst, sizeof(*info));
66 memset(info, 0, sizeof(*info));
68 set_irn_link(node, info);
74 * update the projection info for a Load/Store
76 static int update_projs(ldst_info_t *info, ir_node *proj)
78 long nr = get_Proj_proj(proj);
80 assert(0 <= nr && nr <= MAX_PROJ && "Wrong proj from LoadStore");
82 if (info->projs[nr]) {
83 /* there is already one, do CSE */
84 exchange(proj, info->projs[nr]);
88 info->projs[nr] = proj;
94 * update the exception block info for a Load/Store
96 static int update_exc(ldst_info_t *info, ir_node *block, int pos)
98 assert(info->exc_block == NULL && "more than one exception block found");
100 info->exc_block = block;
106 * walker, collects all Load/Store/Proj nodes
108 static void collect_nodes(ir_node *node, void *env)
112 walk_env_t *wenv = env;
114 if (get_irn_op(node) == op_Proj) {
115 pred = get_Proj_pred(node);
117 if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) {
118 info = get_info(pred, wenv);
120 wenv->changes |= update_projs(info, node);
123 else if (get_irn_op(node) == op_Block) { /* check, if it's an exception block */
126 for (i = 0, n = get_Block_n_cfgpreds(node); i < n; ++i) {
127 pred = skip_Proj(get_Block_cfgpred(node, i));
129 if (get_irn_op(pred) == op_Load || get_irn_op(pred) == op_Store) {
130 info = get_info(pred, wenv);
132 wenv->changes |= update_exc(info, node, i);
141 static int optimize_load(ir_node *load)
143 ldst_info_t *info = get_irn_link(load);
144 ir_mode *load_mode = get_Load_mode(load);
145 ir_node *pred, *mem, *ptr;
148 if (get_Load_volatility(load) == volatility_is_volatile)
152 * BEWARE: one might think that checking the modes is useless, because
153 * if the pointers are identical, they refer to the same object.
154 * This is only true in strong typed languages, not is C were the following
155 * is possible a = *(type1 *)p; b = *(type2 *)p ...
158 ptr = get_Load_ptr(load);
159 mem = get_Load_mem(load);
160 pred = skip_Proj(mem);
162 if (! info->projs[pn_Load_res] && ! info->projs[pn_Load_X_except]) {
163 /* a Load which value is neither used nor exception checked, remove it */
164 exchange(info->projs[pn_Load_M], mem);
167 else if (get_irn_op(pred) == op_Store && get_Store_ptr(pred) == ptr &&
168 get_irn_mode(get_Store_value(pred)) == load_mode) {
170 * a load immediately after a store -- a read after write.
171 * We may remove the Load, if it does not have an exception handler
172 * OR they are in the same block. In the latter case the Load cannot
173 * throw an exception when the previous Store was quiet.
175 if (! info->projs[pn_Load_X_except] || get_nodes_block(load) == get_nodes_block(pred)) {
176 exchange( info->projs[pn_Load_res], get_Store_value(pred) );
177 if (info->projs[pn_Load_M])
178 exchange(info->projs[pn_Load_M], mem);
181 if (info->projs[pn_Load_X_except])
182 exchange( info->projs[pn_Load_X_except], new_Bad());
186 else if (get_irn_op(pred) == op_Load && get_Load_ptr(pred) == ptr &&
187 get_Load_mode(pred) == load_mode) {
189 * a load immediately after a load -- a read after read.
190 * We may remove the second Load, if it does not have an exception handler
191 * OR they are in the same block. In the later case the Load cannot
192 * throw an exception when the previous Load was quiet.
194 if (! info->projs[pn_Load_X_except] || get_nodes_block(load) == get_nodes_block(pred)) {
195 ldst_info_t *pred_info = get_irn_link(pred);
197 if (pred_info->projs[pn_Load_res]) {
198 /* we need a data proj from the previous load for this optimization */
199 exchange( info->projs[pn_Load_res], pred_info->projs[pn_Load_res] );
200 if (info->projs[pn_Load_M])
201 exchange(info->projs[pn_Load_M], mem);
204 if (info->projs[pn_Load_res]) {
205 set_Proj_pred(info->projs[pn_Load_res], pred);
206 set_nodes_block(info->projs[pn_Load_res], get_nodes_block(pred));
208 if (info->projs[pn_Load_M]) {
209 /* Actually, this if should not be necessary. Construct the Loads
211 exchange(info->projs[pn_Load_M], mem);
216 if (info->projs[pn_Load_X_except])
217 exchange(info->projs[pn_Load_X_except], new_Bad());
228 static int optimize_store(ir_node *store)
230 ldst_info_t *info = get_irn_link(store);
231 ir_node *pred, *mem, *ptr, *value, *block;
233 ldst_info_t *pred_info;
236 if (get_Store_volatility(store) == volatility_is_volatile)
240 * BEWARE: one might think that checking the modes is useless, because
241 * if the pointers are identical, they refer to the same object.
242 * This is only true in strong typed languages, not is C were the following
243 * is possible *(type1 *)p = a; *(type2 *)p = b ...
246 block = get_nodes_block(store);
247 ptr = get_Store_ptr(store);
248 mem = get_Store_mem(store);
249 value = get_Store_value(store);
250 pred = skip_Proj(mem);
251 mode = get_irn_mode(value);
253 pred_info = get_irn_link(pred);
255 if (get_irn_op(pred) == op_Store && get_Store_ptr(pred) == ptr &&
256 get_nodes_block(pred) == block && get_irn_mode(get_Store_value(pred)) == mode) {
258 * a store immediately after a store in the same block -- a write after write.
259 * We may remove the first Store, if it does not have an exception handler.
261 * TODO: What, if both have the same exception handler ???
263 if (get_Store_volatility(pred) != volatility_is_volatile && !pred_info->projs[pn_Store_X_except]) {
264 exchange( pred_info->projs[pn_Store_M], get_Store_mem(pred) );
268 else if (get_irn_op(pred) == op_Load && get_Load_ptr(pred) == ptr &&
269 value == pred_info->projs[pn_Load_res]) {
271 * a store a value immediately after a load -- a write after read.
272 * We may remove the second Store, if it does not have an exception handler.
274 if (! info->projs[pn_Store_X_except]) {
275 exchange( info->projs[pn_Store_M], mem );
283 * walker, optimizes Phi after Stores:
284 * Does the following optimization:
286 * val1 val2 val3 val1 val2 val3
294 * This removes teh number of stores and allows for predicated execution.
295 * Moves Stores back to the end of a function which may be bad
297 * Note: that even works, if one of the Stores is already in our current block
299 static int optimize_phi(ir_node *phi)
302 ir_node *store, *ptr, *block, *phiM, *phiD, *exc;
304 ir_node **inM, **inD;
309 /* Must be a memory Phi */
310 if (get_irn_mode(phi) != mode_M)
313 n = get_Phi_n_preds(phi);
317 store = skip_Proj(get_Phi_pred(phi, 0));
318 if (get_irn_op(store) != op_Store)
321 /* this is the address of the store */
322 ptr = get_Store_ptr(store);
323 mode = get_irn_mode(get_Store_value(store));
324 info = get_irn_link(store);
325 exc = info->exc_block;
327 for (i = 1; i < n; ++i) {
328 ir_node *pred = skip_Proj(get_Phi_pred(phi, i));
330 if (get_irn_op(pred) != op_Store)
333 if (mode != get_irn_mode(get_Store_value(pred)) || ptr != get_Store_ptr(pred))
336 info = get_irn_link(pred);
338 /* check, if all stores have the same exception flow */
339 if (exc != info->exc_block)
344 * ok, when we are here, we found all predecessors of a Phi that
345 * are Stores to the same address. That means whatever we do before
346 * we enter the block of the Phi, we do a Store.
347 * So, we can move the store to the current block:
349 * val1 val2 val3 val1 val2 val3
351 * | Str | | Str | | Str | \ | /
357 * Note: that even works, if one of the Stores is already in our current block
360 /* first step: collect all inputs */
361 NEW_ARR_A(ir_node *, inM, n);
362 NEW_ARR_A(ir_node *, inD, n);
363 NEW_ARR_A(int, idx, n);
365 for (i = 0; i < n; ++i) {
366 ir_node *pred = skip_Proj(get_Phi_pred(phi, i));
367 info = get_irn_link(pred);
369 inM[i] = get_Store_mem(pred);
370 inD[i] = get_Store_value(pred);
371 idx[i] = info->exc_idx;
373 block = get_nodes_block(phi);
375 /* second step: create a new memory Phi */
376 phiM = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inM, mode_M);
378 /* third step: create a new data Phi */
379 phiD = new_rd_Phi(get_irn_dbg_info(phi), current_ir_graph, block, n, inD, mode);
381 /* fourth step: create the Store */
382 store = new_rd_Store(db, current_ir_graph, block, phiM, ptr, phiD);
384 /* fifths step: repair exception flow */
386 ir_node *projX = new_rd_Proj(NULL, current_ir_graph, block, store, mode_X, pn_Store_X_except);
388 for (i = 0; i < n; ++i) {
389 set_Block_cfgpred(exc, idx[i], projX);
393 /* the exception block should be optimized as some inputs are identical now */
397 /* sixt step: replace old Phi */
398 exchange(phi, new_rd_Proj(NULL, current_ir_graph, block, store, mode_M, pn_Store_M));
404 * walker, collects all Load/Store/Proj nodes
406 static void do_load_store_optimize(ir_node *n, void *env)
408 walk_env_t *wenv = env;
410 switch (get_irn_opcode(n)) {
413 wenv->changes |= optimize_load(n);
417 wenv->changes |= optimize_store(n);
421 wenv->changes |= optimize_phi(n);
429 * do the load store optimization
431 void optimize_load_store(ir_graph *irg)
435 assert(get_irg_phase_state(irg) != phase_building);
437 if (!get_opt_redundant_LoadStore())
440 obstack_init(&env.obst);
443 /* init the links, then collect Loads/Stores/Proj's in lists */
444 irg_walk_graph(irg, init_links, collect_nodes, &env);
446 /* now we have collected enough information, optimize */
447 irg_walk_graph(irg, NULL, do_load_store_optimize, &env);
449 obstack_free(&env.obst, NULL);
451 /* Handle graph state */
453 if (get_irg_outs_state(current_ir_graph) == outs_consistent)
454 set_irg_outs_inconsistent(current_ir_graph);
456 /* is this really needed: Yes, as exception block may get bad but this might be tested */
457 if (get_irg_dom_state(current_ir_graph) == dom_consistent)
458 set_irg_dom_inconsistent(current_ir_graph);