+static ir_node *find_copy(constraint_env_t *env, ir_node *irn, ir_node *op) {
+ const arch_env_t *arch_env = be_get_birg_arch_env(env->birg);
+ ir_node *block = get_nodes_block(irn);
+ ir_node *cur_node;
+
+ for (cur_node = sched_prev(irn);
+ ! is_Block(cur_node) && be_is_Copy(cur_node) && get_nodes_block(cur_node) == block;
+ cur_node = sched_prev(cur_node))
+ {
+ if (be_get_Copy_op(cur_node) == op && arch_irn_is(arch_env, cur_node, dont_spill))
+ return cur_node;
+ }
+
+ return NULL;
+}
+
+static void gen_assure_different_pattern(ir_node *irn, ir_node *other_different, constraint_env_t *env) {
+ be_irg_t *birg = env->birg;
+ ir_graph *irg = be_get_birg_irg(birg);
+ pset *op_set = env->op_set;
+ const arch_env_t *arch_env = be_get_birg_arch_env(birg);
+ ir_node *block = get_nodes_block(irn);
+ const arch_register_class_t *cls = arch_get_irn_reg_class(arch_env, other_different, -1);
+ ir_node *in[2], *keep, *cpy;
+ op_copy_assoc_t key, *entry;
+ DEBUG_ONLY(firm_dbg_module_t *mod = env->dbg;)
+
+ if (arch_irn_is(arch_env, other_different, ignore) || ! mode_is_datab(get_irn_mode(other_different))) {
+ DBG((mod, LEVEL_1, "ignore constraint for %+F because other_irn is ignore or not a datab node\n", irn));
+ return;
+ }
+
+ /* Make a not spillable copy of the different node */
+ /* this is needed because the different irn could be */
+ /* in block far far away */
+ /* The copy is optimized later if not needed */
+
+ /* check if already exists such a copy in the schedule immediatly before */
+ cpy = find_copy(env, belower_skip_proj(irn), other_different);
+ if (! cpy) {
+ cpy = be_new_Copy(cls, irg, block, other_different);
+ be_node_set_flags(cpy, BE_OUT_POS(0), arch_irn_flags_dont_spill);
+ DBG((mod, LEVEL_1, "created non-spillable %+F for value %+F\n", cpy, other_different));
+ }
+ else {
+ DBG((mod, LEVEL_1, "using already existing %+F for value %+F\n", cpy, other_different));
+ }
+
+ in[0] = irn;
+ in[1] = cpy;
+
+ /* Add the Keep resp. CopyKeep and reroute the users */
+ /* of the other_different irn in case of CopyKeep. */
+ if (get_n_out_edges(other_different) == 0) {
+ keep = be_new_Keep(cls, irg, block, 2, in);
+ }
+ else {
+ keep = be_new_CopyKeep_single(cls, irg, block, cpy, irn, get_irn_mode(other_different));
+ be_node_set_reg_class(keep, 1, cls);
+ }
+
+ DBG((mod, LEVEL_1, "created %+F(%+F, %+F)\n\n", keep, irn, cpy));
+
+ /* insert copy and keep into schedule */
+ assert(sched_is_scheduled(irn) && "need schedule to assure constraints");
+ if (! sched_is_scheduled(cpy))
+ sched_add_before(belower_skip_proj(irn), cpy);
+ sched_add_after(irn, keep);
+
+ /* insert the other different and it's copies into the set */
+ key.op = other_different;
+ entry = pset_find(op_set, &key, hash_irn(other_different));
+
+ if (! entry) {
+ entry = obstack_alloc(&env->obst, sizeof(*entry));
+ ir_nodeset_init(&entry->copies);
+ entry->op = other_different;
+ entry->cls = cls;
+ }
+
+ /* insert copy */
+ ir_nodeset_insert(&entry->copies, cpy);
+
+ /* insert keep in case of CopyKeep */
+ if (be_is_CopyKeep(keep)) {
+ ir_nodeset_insert(&entry->copies, keep);
+ }
+
+ pset_insert(op_set, entry, hash_irn(other_different));
+}