+ turn_into_tuple(irn, pn_CopyB_max+1);
+ set_Tuple_pred(irn, pn_CopyB_M, mem);
+ set_Tuple_pred(irn, pn_CopyB_X_regular, new_r_Bad(irg, mode_X));
+ set_Tuple_pred(irn, pn_CopyB_X_except, new_r_Bad(irg, mode_X));
+}
+
+static ir_type *get_memcpy_methodtype(void)
+{
+ ir_type *tp = new_type_method(3, 1);
+ ir_mode *size_t_mode = get_ir_mode(native_mode_bytes);
+
+ set_method_param_type(tp, 0, get_type_for_mode(mode_P));
+ set_method_param_type(tp, 1, get_type_for_mode(mode_P));
+ set_method_param_type(tp, 2, get_type_for_mode(size_t_mode));
+ set_method_res_type (tp, 0, get_type_for_mode(mode_P));
+
+ return tp;
+}
+
+static ir_node *get_memcpy_symconst(ir_graph *irg)
+{
+ ident *id = new_id_from_str("memcpy");
+ ir_type *mt = get_memcpy_methodtype();
+ ir_entity *ent = create_compilerlib_entity(id, mt);
+ symconst_symbol sym;
+
+ sym.entity_p = ent;
+ return new_r_SymConst(irg, mode_P_code, sym, symconst_addr_ent);
+}
+
+/**
+ * Turn a large CopyB node into a memcpy call.
+ */
+static void lower_large_copyb_node(ir_node *irn)
+{
+ ir_graph *irg = get_irn_irg(irn);
+ ir_node *block = get_nodes_block(irn);
+ dbg_info *dbgi = get_irn_dbg_info(irn);
+ ir_node *mem = get_CopyB_mem(irn);
+ ir_node *addr_src = get_CopyB_src(irn);
+ ir_node *addr_dst = get_CopyB_dst(irn);
+ ir_type *copyb_tp = get_CopyB_type(irn);
+ unsigned size = get_type_size_bytes(copyb_tp);
+
+ ir_node *symconst = get_memcpy_symconst(irg);
+ ir_type *call_tp = get_memcpy_methodtype();
+ ir_mode *mode_size_t = get_ir_mode(native_mode_bytes);
+ ir_node *in[3];
+ ir_node *call;
+ ir_node *call_mem;
+
+ in[0] = addr_dst;
+ in[1] = addr_src;
+ in[2] = new_r_Const_long(irg, mode_size_t, size);
+ call = new_rd_Call(dbgi, block, mem, symconst, 3, in, call_tp);
+ call_mem = new_r_Proj(call, mode_M, pn_Call_M);
+
+ turn_into_tuple(irn, 1);
+ set_irn_n(irn, pn_CopyB_M, call_mem);
+}
+
+static void lower_copyb_node(ir_node *irn)
+{
+ ir_type *tp = get_CopyB_type(irn);
+ unsigned size = get_type_size_bytes(tp);
+
+ if (size <= max_small_size)
+ lower_small_copyb_node(irn);
+ else if (size >= min_large_size)
+ lower_large_copyb_node(irn);
+ else
+ assert(!"CopyB of invalid size handed to lower_copyb_node");
+}
+
+/**
+ * Post-Walker: find CopyB nodes.
+ */
+static void find_copyb_nodes(ir_node *irn, void *ctx)
+{
+ walk_env_t *env = (walk_env_t*)ctx;
+ ir_type *tp;
+ unsigned size;
+ entry_t *entry;
+ bool medium_sized;
+
+ if (is_Proj(irn)) {
+ ir_node *pred = get_Proj_pred(irn);
+
+ if (is_CopyB(pred) && get_Proj_proj(irn) != pn_CopyB_M) {
+ /* found an exception Proj: remove it from the list again */
+ entry = (entry_t*)get_irn_link(pred);
+ list_del(&entry->list);
+ }
+ return;
+ }
+
+ if (! is_CopyB(irn))
+ return;
+
+ tp = get_CopyB_type(irn);
+ if (get_type_state(tp) != layout_fixed)
+ return;
+
+ size = get_type_size_bytes(tp);
+ medium_sized = max_small_size < size && size < min_large_size;
+ if (medium_sized)
+ return; /* Nothing to do for medium-sized CopyBs. */
+
+ /* Okay, either small or large CopyB, so link it in and lower it later. */
+ entry = OALLOC(&env->obst, entry_t);
+ entry->copyb = irn;
+ INIT_LIST_HEAD(&entry->list);
+ set_irn_link(irn, entry);
+ list_add_tail(&entry->list, &env->list);