+
+ /* Check, if the address of this load is used more than once.
+ * If not, this load cannot be removed in any case. */
+ if (get_irn_out_n(ptr) <= 1)
+ return 0;
+
+ /* follow the memory chain as long as there are only Loads */
+ for (pred = skip_Proj(mem); ; pred = skip_Proj(get_Load_mem(pred))) {
+
+ /*
+ * BEWARE: one might think that checking the modes is useless, because
+ * if the pointers are identical, they refer to the same object.
+ * This is only true in strong typed languages, not is C were the following
+ * is possible a = *(type1 *)p; b = *(type2 *)p ...
+ */
+
+ if (get_irn_op(pred) == op_Store && get_Store_ptr(pred) == ptr &&
+ get_irn_mode(get_Store_value(pred)) == load_mode) {
+ ldst_info_t *pred_info = get_irn_link(pred);
+
+ /*
+ * a Load immediately after a Store -- a read after write.
+ * We may remove the Load, if both Load & Store does not have an exception handler
+ * OR they are in the same block. In the latter case the Load cannot
+ * throw an exception when the previous Store was quiet.
+ *
+ * Why we need to check for Store Exc? If the Store cannot be executed (ROM)
+ * the exception handler might simply jump into the load block :-(
+ * We could make it a little bit better if we would know that the exception
+ * handler of the Store jumps directly to the end...
+ */
+ if ((!pred_info->projs[pn_Store_X_except] && !info->projs[pn_Load_X_except]) ||
+ get_nodes_block(load) == get_nodes_block(pred)) {
+ DBG_OPT_RAW(load, pred);
+ exchange( info->projs[pn_Load_res], get_Store_value(pred) );
+
+ if (info->projs[pn_Load_M])
+ exchange(info->projs[pn_Load_M], mem);
+
+ /* no exception */
+ if (info->projs[pn_Load_X_except])
+ exchange( info->projs[pn_Load_X_except], new_Bad());
+ return 1;
+ }
+ }
+ else if (get_irn_op(pred) == op_Load && get_Load_ptr(pred) == ptr &&
+ get_Load_mode(pred) == load_mode) {
+ /*
+ * a Load after a Load -- a read after read.
+ * We may remove the second Load, if it does not have an exception handler
+ * OR they are in the same block. In the later case the Load cannot
+ * throw an exception when the previous Load was quiet.
+ *
+ * Here, there is no need to check if the previos Load has an exception hander because
+ * they would have exact the same exception...
+ */
+ if (! info->projs[pn_Load_X_except] || get_nodes_block(load) == get_nodes_block(pred)) {
+ ldst_info_t *pred_info = get_irn_link(pred);
+
+ DBG_OPT_RAR(load, pred);
+
+ if (pred_info->projs[pn_Load_res]) {
+ /* we need a data proj from the previous load for this optimization */
+ exchange( info->projs[pn_Load_res], pred_info->projs[pn_Load_res] );
+ if (info->projs[pn_Load_M])
+ exchange(info->projs[pn_Load_M], mem);
+ }
+ else {
+ if (info->projs[pn_Load_res]) {
+ set_Proj_pred(info->projs[pn_Load_res], pred);
+ set_nodes_block(info->projs[pn_Load_res], get_nodes_block(pred));
+ }
+ if (info->projs[pn_Load_M]) {
+ /* Actually, this if should not be necessary. Construct the Loads
+ properly!!! */
+ exchange(info->projs[pn_Load_M], mem);
+ }
+ }
+
+ /* no exception */
+ if (info->projs[pn_Load_X_except])
+ exchange(info->projs[pn_Load_X_except], new_Bad());
+
+ return 1;
+ }
+ }
+
+ /* follow only Load chains */
+ if (get_irn_op(pred) != op_Load)
+ break;
+ }