lower_copyb.c 4.66 KB
Newer Older
Michael Beck's avatar
Michael Beck committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

/**
 * @file
 * @brief   Lower small CopyB nodes into a series of Load/store
Michael Beck's avatar
Michael Beck committed
23
 * @author  Michael Beck, Matthias Braun
Michael Beck's avatar
Michael Beck committed
24
25
 * @version $Id$
 */
Matthias Braun's avatar
Matthias Braun committed
26
#include "config.h"
Michael Beck's avatar
Michael Beck committed
27

Michael Beck's avatar
Michael Beck committed
28
#include "adt/list.h"
Michael Beck's avatar
Michael Beck committed
29
30
31
#include "ircons.h"
#include "lowering.h"
#include "irprog_t.h"
32
#include "irgwalk.h"
Michael Beck's avatar
Michael Beck committed
33
34
35
#include "irnode_t.h"
#include "type_t.h"
#include "irtools.h"
36
37
38
#include "irgmod.h"
#include "error.h"

Michael Beck's avatar
Michael Beck committed
39
40
41
42
43
44
45
46
47
48
49
typedef struct entry entry_t;
struct entry {
	struct list_head list;
	ir_node *copyb;
};

typedef struct walk_env {
	unsigned         max_size;
	struct obstack   obst;              /**< the obstack where data is allocated on */
	struct list_head list;              /**< the list of copyb nodes */
} walk_env_t;
50
51
52

static ir_mode *get_ir_mode(unsigned bytes)
{
Michael Beck's avatar
Michael Beck committed
53
	switch (bytes) {
54
55
56
57
58
59
60
	case 1:	 return mode_Bu;
	case 2:  return mode_Hu;
	case 4:  return mode_Iu;
	case 8:  return mode_Lu;
	case 16: return mode_LLu;
	default:
		panic("unexpected mode size requested in copyb lowering");
Michael Beck's avatar
Michael Beck committed
61
62
63
64
	}
}

/**
Michael Beck's avatar
Michael Beck committed
65
 * lower a CopyB node.
Michael Beck's avatar
Michael Beck committed
66
 */
Michael Beck's avatar
Michael Beck committed
67
static void lower_copyb_nodes(ir_node *irn, unsigned mode_bytes) {
68
69
70
71
72
73
74
75
76
	ir_graph        *irg = current_ir_graph;
	unsigned         size;
	unsigned         offset;
	ir_mode         *mode;
	ir_mode         *addr_mode;
	ir_node         *mem;
	ir_node         *addr_src;
	ir_node         *addr_dst;
	ir_node         *block;
Michael Beck's avatar
Michael Beck committed
77
	ir_type         *tp;
Michael Beck's avatar
Michael Beck committed
78

79
80
81
82
83
84
	addr_src  = get_CopyB_src(irn);
	addr_dst  = get_CopyB_dst(irn);
	mem       = get_CopyB_mem(irn);
	addr_mode = get_irn_mode(addr_src);
	block     = get_nodes_block(irn);

Michael Beck's avatar
Michael Beck committed
85
86
87
	tp   = get_CopyB_type(irn);
	size = get_type_size_bytes(tp);

88
	offset     = 0;
Michael Beck's avatar
Michael Beck committed
89
	while (offset < size) {
90
		mode = get_ir_mode(mode_bytes);
Michael Beck's avatar
Michael Beck committed
91
		for (; offset + mode_bytes <= size; offset += mode_bytes) {
92
93
94
95
96
97
98
99
100
			/* construct offset */
			ir_node *addr_const;
			ir_node *add;
			ir_node *load;
			ir_node *load_res;
			ir_node *load_mem;
			ir_node *store;
			ir_node *store_mem;

101
			addr_const = new_r_Const_long(irg, mode_Iu, offset);
102
103
			add        = new_r_Add(irg, block, addr_src, addr_const, addr_mode);

104
			load     = new_r_Load(irg, block, mem, add, mode, 0);
105
106
107
			load_res = new_r_Proj(irg, block, load, mode, pn_Load_res);
			load_mem = new_r_Proj(irg, block, load, mode_M, pn_Load_M);

108
			addr_const = new_r_Const_long(irg, mode_Iu, offset);
109
110
			add        = new_r_Add(irg, block, addr_dst, addr_const, addr_mode);

111
			store     = new_r_Store(irg, block, mem, add, load_res, 0);
112
113
114
115
116
117
			store_mem = new_r_Proj(irg, block, store, mode_M, pn_Store_M);

			mem = store_mem;
		}

		mode_bytes /= 2;
Michael Beck's avatar
Michael Beck committed
118
	}
119

Michael Beck's avatar
Michael Beck committed
120
121
122
123
124
	turn_into_tuple(irn, pn_CopyB_max);
	set_Tuple_pred(irn, pn_CopyB_M_regular, mem);
	set_Tuple_pred(irn, pn_CopyB_X_regular, get_irg_bad(irg));
	set_Tuple_pred(irn, pn_CopyB_X_except,  get_irg_bad(irg));
	set_Tuple_pred(irn, pn_CopyB_M_except,  get_irg_bad(irg));
125
126
}

Michael Beck's avatar
Michael Beck committed
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
 * Post-Walker: find small CopyB nodes.
 */
static void find_copyb_nodes(ir_node *irn, void *ctx) {
	walk_env_t *env = ctx;
	ir_type    *tp;
	unsigned   size;
	entry_t    *entry;

	if (is_Proj(irn)) {
		ir_node *pred = get_Proj_pred(irn);

		if (is_CopyB(pred) && get_Proj_proj(irn) != pn_CopyB_M_regular) {
			/* found an exception Proj: remove it from the list again */
			entry = 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);
	if (size > env->max_size)
		return;

	/* ok, link it in */
	entry = obstack_alloc(&env->obst, sizeof(*entry));
	entry->copyb = irn;
	INIT_LIST_HEAD(&entry->list);
	set_irn_link(irn, entry);
	list_add_tail(&entry->list, &env->list);
}

void lower_CopyB(ir_graph *irg, unsigned max_size, unsigned native_mode_bytes)
167
{
Michael Beck's avatar
Michael Beck committed
168
169
170
	walk_env_t env;
	entry_t  *entry;
	ir_graph *rem = current_ir_graph;
171

Michael Beck's avatar
Michael Beck committed
172
	current_ir_graph = irg;
173

Michael Beck's avatar
Michael Beck committed
174
175
176
177
178
179
180
181
	obstack_init(&env.obst);
	env.max_size = max_size;
	INIT_LIST_HEAD(&env.list);
	irg_walk_graph(irg, NULL, find_copyb_nodes, &env);

	list_for_each_entry(entry_t, entry, &env.list, list) {
		lower_copyb_nodes(entry->copyb, native_mode_bytes);
	}
182

Michael Beck's avatar
Michael Beck committed
183
184
	obstack_free(&env.obst, NULL);
	current_ir_graph = rem;
Michael Beck's avatar
Michael Beck committed
185
}