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"
32 #include "ia32_transform.h"
38 #include "iredges_t.h"
41 #include "../benode_t.h"
45 /* gas/ld don't support negative symconsts :-( */
46 #undef SUPPORT_NEGATIVE_SYMCONSTS
48 static bitset_t *non_address_mode_nodes;
50 static int do_is_immediate(const ir_node *node, int *symconsts, int negate)
55 switch(get_irn_opcode(node)) {
57 if(!tarval_is_long(get_Const_tarval(node))) {
59 ir_fprintf(stderr, "Optimisation warning tarval of %+F(%+F) is not "
60 "a long.\n", node, current_ir_graph);
66 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
67 /* unfortunately the assembler/linker doesn't support -symconst */
72 if(get_SymConst_kind(node) != symconst_addr_ent)
81 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
84 left = get_binop_left(node);
85 right = get_binop_right(node);
86 if(!do_is_immediate(left, symconsts, negate))
88 if(!do_is_immediate(right, symconsts, is_Sub(node) ? !negate : negate))
99 static int is_immediate_simple(const ir_node *node)
102 return do_is_immediate(node, &symconsts, 0);
105 static int is_immediate(ia32_address_t *addr, const ir_node *node, int negate)
108 if(addr->symconst_ent != NULL)
111 return do_is_immediate(node, &symconsts, negate);
114 static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate)
121 switch(get_irn_opcode(node)) {
123 tv = get_Const_tarval(node);
124 val = get_tarval_long(tv);
132 if(addr->symconst_ent != NULL) {
133 panic("Internal error: more than 1 symconst in address "
136 addr->symconst_ent = get_SymConst_entity(node);
137 #ifndef SUPPORT_NEGATIVE_SYMCONSTS
140 addr->symconst_sign = negate;
143 assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node)));
144 left = get_Add_left(node);
145 right = get_Add_right(node);
146 eat_immediate(addr, left, negate);
147 eat_immediate(addr, right, negate);
150 assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node)));
151 left = get_Sub_left(node);
152 right = get_Sub_right(node);
153 eat_immediate(addr, left, negate);
154 eat_immediate(addr, right, !negate);
157 panic("Internal error in immediate address calculation");
161 static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force)
163 if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
167 ir_node *left = get_Add_left(node);
168 ir_node *right = get_Add_right(node);
170 if(is_immediate(addr, left, 0)) {
171 eat_immediate(addr, left, 0);
172 return eat_immediates(addr, right, 0);
174 if(is_immediate(addr, right, 0)) {
175 eat_immediate(addr, right, 0);
176 return eat_immediates(addr, left, 0);
178 } else if(is_Sub(node)) {
179 ir_node *left = get_Sub_left(node);
180 ir_node *right = get_Sub_right(node);
182 if(is_immediate(addr, right, 1)) {
183 eat_immediate(addr, right, 1);
184 return eat_immediates(addr, left, 0);
191 static int eat_shl(ia32_address_t *addr, ir_node *node)
193 ir_node *right = get_Shl_right(node);
197 /* we can only eat a shl if we don't have a scale or index set */
198 if(addr->scale != 0 || addr->index != NULL)
201 /* we can use shl with 1, 2 or 3 shift */
204 tv = get_Const_tarval(right);
205 if(!tarval_is_long(tv))
207 val = get_tarval_long(tv);
208 if(val < 0 || val > 3)
211 ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n");
213 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node)))
216 #ifndef AGGRESSIVE_AM
217 if(get_irn_n_edges(node) > 1)
222 addr->index = eat_immediates(addr, get_Shl_left(node), 0);
226 static INLINE int mode_needs_gp_reg(ir_mode *mode) {
227 if(mode == mode_fpcw)
229 if(get_mode_size_bits(mode) > 32)
231 return mode_is_int(mode) || mode_is_reference(mode) || mode == mode_b;
234 static int is_downconv(const ir_node *node)
242 /* we only want to skip the conv when we're the only user
243 * (not optimal but for now...)
245 if(get_irn_n_edges(node) > 1)
248 src_mode = get_irn_mode(get_Conv_op(node));
249 dest_mode = get_irn_mode(node);
250 return mode_needs_gp_reg(src_mode)
251 && mode_needs_gp_reg(dest_mode)
252 && get_mode_size_bits(dest_mode) < get_mode_size_bits(src_mode);
255 static ir_node *skip_downconv(ir_node *node)
258 while(is_downconv(node))
259 node = get_Conv_op(node);
265 void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force)
270 if(is_immediate(addr, node, 0)) {
271 eat_immediate(addr, node, 0);
275 #ifndef AGGRESSIVE_AM
276 if(!force && get_irn_n_edges(node) > 1) {
282 if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) {
287 eat_imms = eat_immediates(addr, node, force);
288 if(eat_imms != node) {
290 eat_imms = skip_downconv(eat_imms);
295 #ifndef AGGRESSIVE_AM
296 if(get_irn_n_edges(node) > 1) {
301 if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) {
307 /* starting point Add, Sub or Shl, FrameAddr */
309 if(eat_shl(addr, node))
311 } else if(is_immediate(addr, node, 0)) {
312 eat_immediate(addr, node, 0);
314 } else if(be_is_FrameAddr(node)) {
315 assert(addr->base == NULL);
316 assert(addr->frame_entity == NULL);
317 addr->base = be_get_FrameAddr_frame(node);
319 addr->frame_entity = be_get_FrameAddr_entity(node);
321 } else if(is_Add(node)) {
322 ir_node *left = get_Add_left(node);
323 ir_node *right = get_Add_right(node);
326 left = skip_downconv(left);
327 right = skip_downconv(right);
330 assert(force || !is_immediate(addr, left, 0));
331 assert(force || !is_immediate(addr, right, 0));
333 if(is_Shl(left) && eat_shl(addr, left)) {
335 } else if(is_Shl(right) && eat_shl(addr, right)) {
338 if(left != NULL && be_is_FrameAddr(left)
339 && !bitset_is_set(non_address_mode_nodes, get_irn_idx(left))) {
340 assert(addr->base == NULL);
341 assert(addr->frame_entity == NULL);
342 addr->base = be_get_FrameAddr_frame(left);
344 addr->frame_entity = be_get_FrameAddr_entity(left);
346 } else if(right != NULL && be_is_FrameAddr(right)
347 && !bitset_is_set(non_address_mode_nodes, get_irn_idx(right))) {
348 assert(addr->base == NULL);
349 assert(addr->frame_entity == NULL);
350 addr->base = be_get_FrameAddr_frame(right);
352 addr->frame_entity = be_get_FrameAddr_entity(right);
357 if(addr->base != NULL) {
358 assert(addr->index == NULL && addr->scale == 0);
359 assert(right == NULL);
366 if(addr->base == NULL) {
369 assert(addr->index == NULL && addr->scale == 0);
381 static void mark_non_address_nodes(ir_node *node, void *env)
391 switch(get_irn_opcode(node)) {
393 ptr = get_Load_ptr(node);
394 mem = get_Load_mem(node);
396 bitset_set(non_address_mode_nodes, get_irn_idx(mem));
400 val = get_Store_value(node);
401 ptr = get_Store_ptr(node);
402 mem = get_Store_mem(node);
404 bitset_set(non_address_mode_nodes, get_irn_idx(val));
405 bitset_set(non_address_mode_nodes, get_irn_idx(mem));
409 left = get_Add_left(node);
410 right = get_Add_right(node);
411 /* if we can do source address mode then we will never fold the add
412 * into address mode */
413 if(!mode_is_float(get_irn_mode(node)) && (is_immediate_simple(right) ||
414 (!use_source_address_mode(get_nodes_block(node), left, right)
415 && !use_source_address_mode(get_nodes_block(node), right, left))))
419 bitset_set(non_address_mode_nodes, get_irn_idx(node));
423 arity = get_irn_arity(node);
425 for(i = 0; i < arity; ++i) {
426 ir_node *in = get_irn_n(node, i);
427 bitset_set(non_address_mode_nodes, get_irn_idx(in));
433 void calculate_non_address_mode_nodes(ir_graph *irg)
435 non_address_mode_nodes = bitset_malloc(get_irg_last_idx(irg));
437 irg_walk_graph(irg, NULL, mark_non_address_nodes, NULL);
440 void free_non_address_mode_nodes(void)
442 bitset_free(non_address_mode_nodes);