2 * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @brief This file contains functions for matching firm graphs for
23 * nodes that can be used as addressmode for x86 commands
24 * @author Matthias Braun
31 #include "ia32_address_mode.h"
37 #include "iredges_t.h"
39 #include "../benode_t.h"
43 static int is_immediate_2(const ir_node *node, int *symconsts)
48 switch(get_irn_opcode(node)) {
50 if(!tarval_is_long(get_Const_tarval(node))) {
52 ir_fprintf(stderr, "Optimisation warning tarval of %+F is not a "
59 if(get_SymConst_kind(node) != symconst_addr_ent)
68 left = get_binop_left(node);
69 right = get_binop_right(node);
70 if(!is_immediate_2(left, symconsts))
72 if(!is_immediate_2(right, symconsts))
83 static int is_immediate(ia32_address_t *addr, const ir_node *node)
86 if(addr->symconst_ent != NULL)
89 return is_immediate_2(node, &symconsts);
92 static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate)
98 switch(get_irn_opcode(node)) {
100 tv = get_Const_tarval(node);
102 addr->offset -= get_tarval_long(tv);
104 addr->offset += get_tarval_long(tv);
108 if(addr->symconst_ent != NULL) {
109 panic("Internal error: more than 1 symconst in address "
112 addr->symconst_ent = get_SymConst_entity(node);
113 addr->symconst_sign = negate;
116 left = get_Add_left(node);
117 right = get_Add_right(node);
118 eat_immediate(addr, left, negate);
119 eat_immediate(addr, right, negate);
122 left = get_Sub_left(node);
123 right = get_Sub_right(node);
124 eat_immediate(addr, left, negate);
125 eat_immediate(addr, right, !negate);
128 panic("Internal error in immediate address calculation");
132 static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force)
135 ir_node *left = get_Add_left(node);
136 ir_node *right = get_Add_right(node);
139 #ifndef AGGRESSIVE_AM
140 if(!force && get_irn_n_edges(node) > 1)
147 if(is_immediate(addr, left)) {
148 eat_immediate(addr, left, 0);
149 return eat_immediates(addr, right, 0);
151 if(is_immediate(addr, right)) {
152 eat_immediate(addr, right, 0);
153 return eat_immediates(addr, left, 0);
155 } else if(is_Sub(node)) {
156 ir_node *left = get_Sub_left(node);
157 ir_node *right = get_Sub_right(node);
160 #ifndef AGGRESSIVE_AM
161 if(!force && get_irn_n_edges(node) > 1)
166 if(is_immediate(addr, right)) {
167 eat_immediate(addr, right, 1);
168 return eat_immediates(addr, left, 0);
175 static int eat_shl(ia32_address_t *addr, ir_node *node)
177 ir_node *right = get_Shl_right(node);
181 /* we can only eat a shl if we don't have a scale or index set */
182 if(addr->scale != 0 || addr->index != NULL)
185 /* we can use shl with 1, 2 or 3 shift */
188 tv = get_Const_tarval(right);
189 if(!tarval_is_long(tv))
191 val = get_tarval_long(tv);
192 if(val < 0 || val > 3)
195 ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n");
198 #ifndef AGGRESSIVE_AM
199 if(get_irn_n_edges(node) > 1)
204 addr->index = eat_immediates(addr, get_Shl_left(node), 0);
208 void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force)
213 if(is_immediate(addr, node)) {
214 eat_immediate(addr, node, 0);
218 #ifndef AGGRESSIVE_AM
219 if(!force && get_irn_n_edges(node) > 1) {
225 eat_imms = eat_immediates(addr, node, force);
226 if(eat_imms != node) {
229 #ifndef AGGRESSIVE_AM
230 if(get_irn_n_edges(node) > 1) {
237 /* starting point Add, Sub or Shl, FrameAddr */
239 if(eat_shl(addr, node))
241 } else if(is_immediate(addr, node)) {
242 eat_immediate(addr, node, 0);
244 } else if(be_is_FrameAddr(node)) {
245 assert(addr->base == NULL);
246 assert(addr->frame_entity == NULL);
247 addr->base = be_get_FrameAddr_frame(node);
249 addr->frame_entity = be_get_FrameAddr_entity(node);
251 } else if(is_Add(node)) {
252 ir_node *left = get_Add_left(node);
253 ir_node *right = get_Add_right(node);
254 assert(force || !is_immediate(addr, left));
255 assert(force || !is_immediate(addr, right));
257 if(is_Shl(left) && eat_shl(addr, left)) {
259 } else if(is_Shl(right) && eat_shl(addr, right)) {
262 if(left != NULL && be_is_FrameAddr(left)) {
263 assert(addr->base == NULL);
264 assert(addr->frame_entity == NULL);
265 addr->base = be_get_FrameAddr_frame(left);
267 addr->frame_entity = be_get_FrameAddr_entity(left);
269 } else if(right != NULL && be_is_FrameAddr(right)) {
270 assert(addr->base == NULL);
271 assert(addr->frame_entity == NULL);
272 addr->base = be_get_FrameAddr_frame(right);
274 addr->frame_entity = be_get_FrameAddr_entity(right);
279 if(addr->base != NULL) {
280 assert(addr->index == NULL && addr->scale == 0);
281 assert(right == NULL);
288 if(addr->base == NULL) {
291 assert(addr->index == NULL && addr->scale == 0);
302 typedef struct mark_evn_t mark_evn_t;
304 bitset_t *non_address_nodes;
308 static void mark_non_address_nodes(mark_evn_t *env, ir_node *node)
310 bitset_set(env->non_address_nodes, get_irn_idx(node));
313 ir_node *ptr = get_Load_ptr(node);
314 ir_node *mem = get_Load_mem(node);
316 mark_non_address_nodes(env, mem);
318 } else if(is_Store(node)) {
319 ir_node *val = get_Store_value(node);
320 ir_node *ptr = get_Store_ptr(node);
321 ir_node *mem = get_Store_mem(node);
323 mark_non_address_nodes(env, val);
324 mark_non_address_nodes(env, mem);
328 int arity = get_irn_arity(node);
330 for(i = 0; i < arity; ++i) {
331 ir_node *in = get_irn_n(node, i);
332 mark_non_address_nodes(env, in);