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 /* gas/ld don't support negative symconsts :-( */
44 #undef SUPPORT_NEGATIVE_SYMCONSTS
46 static int is_immediate_2(const ir_node *node, int *symconsts, int negate)
51 switch(get_irn_opcode(node)) {
53 if(!tarval_is_long(get_Const_tarval(node))) {
55 ir_fprintf(stderr, "Optimisation warning tarval of %+F is not a "
62 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
63 /* unfortunately the assembler/linker doesn't support -symconst */
68 if(get_SymConst_kind(node) != symconst_addr_ent)
77 left = get_binop_left(node);
78 right = get_binop_right(node);
79 if(!is_immediate_2(left, symconsts, negate))
81 if(!is_immediate_2(right, symconsts, is_Sub(node) ? !negate : negate))
92 static int is_immediate(ia32_address_t *addr, const ir_node *node, int negate)
95 if(addr->symconst_ent != NULL)
98 return is_immediate_2(node, &symconsts, negate);
101 static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate)
107 switch(get_irn_opcode(node)) {
109 tv = get_Const_tarval(node);
111 addr->offset -= get_tarval_long(tv);
113 addr->offset += get_tarval_long(tv);
117 if(addr->symconst_ent != NULL) {
118 panic("Internal error: more than 1 symconst in address "
121 addr->symconst_ent = get_SymConst_entity(node);
122 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
125 addr->symconst_sign = negate;
128 left = get_Add_left(node);
129 right = get_Add_right(node);
130 eat_immediate(addr, left, negate);
131 eat_immediate(addr, right, negate);
134 left = get_Sub_left(node);
135 right = get_Sub_right(node);
136 eat_immediate(addr, left, negate);
137 eat_immediate(addr, right, !negate);
140 panic("Internal error in immediate address calculation");
144 static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node)
147 ir_node *left = get_Add_left(node);
148 ir_node *right = get_Add_right(node);
150 if(is_immediate(addr, left, 0)) {
151 eat_immediate(addr, left, 0);
152 return eat_immediates(addr, right);
154 if(is_immediate(addr, right, 0)) {
155 eat_immediate(addr, right, 0);
156 return eat_immediates(addr, left);
158 } else if(is_Sub(node)) {
159 ir_node *left = get_Sub_left(node);
160 ir_node *right = get_Sub_right(node);
162 if(is_immediate(addr, right, 1)) {
163 eat_immediate(addr, right, 1);
164 return eat_immediates(addr, left);
171 static int eat_shl(ia32_address_t *addr, ir_node *node)
173 ir_node *right = get_Shl_right(node);
177 /* we can only eat a shl if we don't have a scale or index set */
178 if(addr->scale != 0 || addr->index != NULL)
181 /* we can use shl with 1, 2 or 3 shift */
184 tv = get_Const_tarval(right);
185 if(!tarval_is_long(tv))
187 val = get_tarval_long(tv);
188 if(val < 0 || val > 3)
191 ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n");
194 #ifndef AGGRESSIVE_AM
195 if(get_irn_n_edges(node) > 1)
200 addr->index = eat_immediates(addr, get_Shl_left(node));
204 void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force)
209 if(is_immediate(addr, node, 0)) {
210 eat_immediate(addr, node, 0);
214 #ifndef AGGRESSIVE_AM
215 if(!force && get_irn_n_edges(node) > 1) {
221 eat_imms = eat_immediates(addr, node);
222 if(eat_imms != node) {
225 #ifndef AGGRESSIVE_AM
226 if(get_irn_n_edges(node) > 1) {
233 /* starting point Add, Sub or Shl, FrameAddr */
235 if(eat_shl(addr, node))
237 } else if(is_immediate(addr, node, 0)) {
238 eat_immediate(addr, node, 0);
240 } else if(be_is_FrameAddr(node)) {
241 assert(addr->base == NULL);
242 assert(addr->frame_entity == NULL);
243 addr->base = be_get_FrameAddr_frame(node);
245 addr->frame_entity = be_get_FrameAddr_entity(node);
247 } else if(is_Add(node)) {
248 ir_node *left = get_Add_left(node);
249 ir_node *right = get_Add_right(node);
250 assert(force || !is_immediate(addr, left, 0));
251 assert(force || !is_immediate(addr, right, 0));
253 if(is_Shl(left) && eat_shl(addr, left)) {
255 } else if(is_Shl(right) && eat_shl(addr, right)) {
258 if(left != NULL && be_is_FrameAddr(left)) {
259 assert(addr->base == NULL);
260 assert(addr->frame_entity == NULL);
261 addr->base = be_get_FrameAddr_frame(left);
263 addr->frame_entity = be_get_FrameAddr_entity(left);
265 } else if(right != NULL && be_is_FrameAddr(right)) {
266 assert(addr->base == NULL);
267 assert(addr->frame_entity == NULL);
268 addr->base = be_get_FrameAddr_frame(right);
270 addr->frame_entity = be_get_FrameAddr_entity(right);
275 if(addr->base != NULL) {
276 assert(addr->index == NULL && addr->scale == 0);
277 assert(right == NULL);
284 if(addr->base == NULL) {
287 assert(addr->index == NULL && addr->scale == 0);
298 typedef struct mark_evn_t mark_evn_t;
300 bitset_t *non_address_nodes;
304 static void mark_non_address_nodes(mark_evn_t *env, ir_node *node)
306 bitset_set(env->non_address_nodes, get_irn_idx(node));
309 ir_node *ptr = get_Load_ptr(node);
310 ir_node *mem = get_Load_mem(node);
312 mark_non_address_nodes(env, mem);
314 } else if(is_Store(node)) {
315 ir_node *val = get_Store_value(node);
316 ir_node *ptr = get_Store_ptr(node);
317 ir_node *mem = get_Store_mem(node);
319 mark_non_address_nodes(env, val);
320 mark_non_address_nodes(env, mem);
324 int arity = get_irn_arity(node);
326 for(i = 0; i < arity; ++i) {
327 ir_node *in = get_irn_n(node, i);
328 mark_non_address_nodes(env, in);