From: Matthias Braun Date: Tue, 25 Sep 2007 13:57:17 +0000 (+0000) Subject: - never use (broken) sequential load/store in abi X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=2892108ce9c2eee86306057c3142e16c156bd62c;p=libfirm - never use (broken) sequential load/store in abi - more sophisticated address mode code selection, brings huge speedups in 164.gzip [r15918] --- diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 598a0fbea..8be3441cc 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -1774,11 +1774,9 @@ static void ia32_get_call_abi(const void *self, ir_type *method_type, be_abi_cal int n, i, regnum; be_abi_call_flags_t call_flags = be_abi_call_get_flags(abi); - unsigned use_push = !IS_P6_ARCH(isa->opt_arch); - /* set abi flags for calls */ call_flags.bits.left_to_right = 0; /* always last arg first on stack */ - call_flags.bits.store_args_sequential = use_push; + call_flags.bits.store_args_sequential = 0; /* call_flags.bits.try_omit_fp not changed: can handle both settings */ call_flags.bits.fp_free = 0; /* the frame pointer is fixed in IA32 */ call_flags.bits.call_has_imm = 1; /* IA32 calls can have immediate address */ diff --git a/ir/be/ia32/ia32_address_mode.c b/ir/be/ia32/ia32_address_mode.c index d18a2bcba..3fa5a4fff 100644 --- a/ir/be/ia32/ia32_address_mode.c +++ b/ir/be/ia32/ia32_address_mode.c @@ -29,21 +29,25 @@ #endif #include "ia32_address_mode.h" +#include "ia32_transform.h" #include "irtypes.h" #include "irnode_t.h" #include "irprintf.h" #include "error.h" #include "iredges_t.h" +#include "irgwalk.h" #include "../benode_t.h" -#undef AGGRESSIVE_AM +#define AGGRESSIVE_AM /* gas/ld don't support negative symconsts :-( */ #undef SUPPORT_NEGATIVE_SYMCONSTS -static int is_immediate_2(const ir_node *node, int *symconsts, int negate) +static bitset_t *non_address_mode_nodes; + +static int do_is_immediate(const ir_node *node, int *symconsts, int negate) { ir_node *left; ir_node *right; @@ -74,11 +78,14 @@ static int is_immediate_2(const ir_node *node, int *symconsts, int negate) return 1; case iro_Add: case iro_Sub: + if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) + return 0; + left = get_binop_left(node); right = get_binop_right(node); - if(!is_immediate_2(left, symconsts, negate)) + if(!do_is_immediate(left, symconsts, negate)) return 0; - if(!is_immediate_2(right, symconsts, is_Sub(node) ? !negate : negate)) + if(!do_is_immediate(right, symconsts, is_Sub(node) ? !negate : negate)) return 0; return 1; @@ -89,13 +96,19 @@ static int is_immediate_2(const ir_node *node, int *symconsts, int negate) return 0; } +static int is_immediate_simple(const ir_node *node) +{ + int symconsts = 0; + return do_is_immediate(node, &symconsts, 0); +} + static int is_immediate(ia32_address_t *addr, const ir_node *node, int negate) { int symconsts = 0; if(addr->symconst_ent != NULL) symconsts = 1; - return is_immediate_2(node, &symconsts, negate); + return do_is_immediate(node, &symconsts, negate); } static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate) @@ -107,10 +120,11 @@ static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate) switch(get_irn_opcode(node)) { case iro_Const: tv = get_Const_tarval(node); + long val = get_tarval_long(tv); if(negate) { - addr->offset -= get_tarval_long(tv); + addr->offset -= val; } else { - addr->offset += get_tarval_long(tv); + addr->offset += val; } break; case iro_SymConst: @@ -125,12 +139,14 @@ static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate) addr->symconst_sign = negate; break; case iro_Add: + assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node))); left = get_Add_left(node); right = get_Add_right(node); eat_immediate(addr, left, negate); eat_immediate(addr, right, negate); break; case iro_Sub: + assert(!bitset_is_set(non_address_mode_nodes, get_irn_idx(node))); left = get_Sub_left(node); right = get_Sub_right(node); eat_immediate(addr, left, negate); @@ -141,19 +157,22 @@ static void eat_immediate(ia32_address_t *addr, ir_node *node, int negate) } } -static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node) +static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node, int force) { + if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) + return node; + if(is_Add(node)) { ir_node *left = get_Add_left(node); ir_node *right = get_Add_right(node); if(is_immediate(addr, left, 0)) { eat_immediate(addr, left, 0); - return eat_immediates(addr, right); + return eat_immediates(addr, right, 0); } if(is_immediate(addr, right, 0)) { eat_immediate(addr, right, 0); - return eat_immediates(addr, left); + return eat_immediates(addr, left, 0); } } else if(is_Sub(node)) { ir_node *left = get_Sub_left(node); @@ -161,7 +180,7 @@ static ir_node *eat_immediates(ia32_address_t *addr, ir_node *node) if(is_immediate(addr, right, 1)) { eat_immediate(addr, right, 1); - return eat_immediates(addr, left); + return eat_immediates(addr, left, 0); } } @@ -190,6 +209,8 @@ static int eat_shl(ia32_address_t *addr, ir_node *node) if(val == 0) { ir_fprintf(stderr, "Optimisation warning: unoptimized Shl(,0) found\n"); } + if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) + return 0; #ifndef AGGRESSIVE_AM if(get_irn_n_edges(node) > 1) @@ -197,7 +218,7 @@ static int eat_shl(ia32_address_t *addr, ir_node *node) #endif addr->scale = val; - addr->index = eat_immediates(addr, get_Shl_left(node)); + addr->index = eat_immediates(addr, get_Shl_left(node), 0); return 1; } @@ -218,7 +239,12 @@ void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force) } #endif - eat_imms = eat_immediates(addr, node); + if(!force && bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) { + addr->base = node; + return; + } + + eat_imms = eat_immediates(addr, node, force); if(eat_imms != node) { res = 1; node = eat_imms; @@ -228,6 +254,10 @@ void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force) return; } #endif + if(bitset_is_set(non_address_mode_nodes, get_irn_idx(node))) { + addr->base = node; + return; + } } /* starting point Add, Sub or Shl, FrameAddr */ @@ -255,14 +285,16 @@ void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force) } else if(is_Shl(right) && eat_shl(addr, right)) { right = NULL; } - if(left != NULL && be_is_FrameAddr(left)) { + if(left != NULL && be_is_FrameAddr(left) + && !bitset_is_set(non_address_mode_nodes, get_irn_idx(left))) { assert(addr->base == NULL); assert(addr->frame_entity == NULL); addr->base = be_get_FrameAddr_frame(left); addr->use_frame = 1; addr->frame_entity = be_get_FrameAddr_entity(left); left = NULL; - } else if(right != NULL && be_is_FrameAddr(right)) { + } else if(right != NULL && be_is_FrameAddr(right) + && !bitset_is_set(non_address_mode_nodes, get_irn_idx(right))) { assert(addr->base == NULL); assert(addr->frame_entity == NULL); addr->base = be_get_FrameAddr_frame(right); @@ -295,37 +327,66 @@ void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force) } -typedef struct mark_evn_t mark_evn_t; -struct mark_evn_t { - bitset_t *non_address_nodes; -}; - -static void mark_non_address_nodes(mark_evn_t *env, ir_node *node) +static void mark_non_address_nodes(ir_node *node, void *env) { - bitset_set(env->non_address_nodes, get_irn_idx(node)); - - if(is_Load(node)) { - ir_node *ptr = get_Load_ptr(node); - ir_node *mem = get_Load_mem(node); - - mark_non_address_nodes(env, mem); - (void) ptr; - } else if(is_Store(node)) { - ir_node *val = get_Store_value(node); - ir_node *ptr = get_Store_ptr(node); - ir_node *mem = get_Store_mem(node); - - mark_non_address_nodes(env, val); - mark_non_address_nodes(env, mem); - (void) ptr; - } else { - int i; - int arity = get_irn_arity(node); + int i, arity; + ir_node *ptr; + ir_node *mem; + ir_node *val; + ir_node *left; + ir_node *right; + (void) env; + + switch(get_irn_opcode(node)) { + case iro_Load: + ptr = get_Load_ptr(node); + mem = get_Load_mem(node); + + bitset_set(non_address_mode_nodes, get_irn_idx(mem)); + break; + + case iro_Store: + val = get_Store_value(node); + ptr = get_Store_ptr(node); + mem = get_Store_mem(node); + + bitset_set(non_address_mode_nodes, get_irn_idx(val)); + bitset_set(non_address_mode_nodes, get_irn_idx(mem)); + break; + + case iro_Add: + left = get_Add_left(node); + right = get_Add_right(node); + /* if we can do source address mode then we will never fold the add + * into address mode */ + if(is_immediate_simple(right) || + (!use_source_address_mode(get_nodes_block(node), left, right) + && !use_source_address_mode(get_nodes_block(node), right, left))) { + break; + } + bitset_set(non_address_mode_nodes, get_irn_idx(node)); + /* fallthrough */ + + default: + arity = get_irn_arity(node); for(i = 0; i < arity; ++i) { ir_node *in = get_irn_n(node, i); - mark_non_address_nodes(env, in); + bitset_set(non_address_mode_nodes, get_irn_idx(in)); } + break; } } + +void calculate_non_address_mode_nodes(ir_graph *irg) +{ + non_address_mode_nodes = bitset_malloc(get_irg_last_idx(irg)); + + irg_walk_graph(irg, NULL, mark_non_address_nodes, NULL); +} + +void free_non_address_mode_nodes(void) +{ + bitset_free(non_address_mode_nodes); +} diff --git a/ir/be/ia32/ia32_address_mode.h b/ir/be/ia32/ia32_address_mode.h index fba3c0cdb..2f19db0b9 100644 --- a/ir/be/ia32/ia32_address_mode.h +++ b/ir/be/ia32/ia32_address_mode.h @@ -44,4 +44,8 @@ struct ia32_address_t { void ia32_create_address_mode(ia32_address_t *addr, ir_node *node, int force); +void calculate_non_address_mode_nodes(ir_graph *irg); + +void free_non_address_mode_nodes(void); + #endif diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 7c356ecf1..7881584fd 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -1313,9 +1313,11 @@ void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node) be_emit_ident(env, id); } if(attr->symconst == NULL || attr->offset != 0) { - if(attr->symconst != NULL) - be_emit_char(env, '+'); - be_emit_irprintf(env->emit, "0x%X", attr->offset); + if(attr->symconst != NULL) { + be_emit_irprintf(env->emit, "%+d", attr->offset); + } else { + be_emit_irprintf(env->emit, "0x%X", attr->offset); + } } } diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 8144253bd..6585e73c9 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -447,8 +447,7 @@ const char *ia32_get_old_node_name(ia32_code_gen_t *cg, ir_node *irn) { } #endif /* NDEBUG */ -static int use_source_address_mode(ir_node *block, ir_node *node, - ir_node *other) +int use_source_address_mode(ir_node *block, ir_node *node, ir_node *other) { ir_mode *mode; ir_node *load; @@ -1620,8 +1619,8 @@ static ir_node *gen_Load(ir_node *node) { /* create a conv node with address mode for smaller modes */ if(get_mode_size_bits(mode) < 32) { - new_op = new_rd_ia32_Conv_I2I(dbgi, irg, block, base, index, new_mem, - noreg, mode); + new_op = new_rd_ia32_Conv_I2I(dbgi, irg, block, base, index, + new_mem, noreg, mode); } else { new_op = new_rd_ia32_Load(dbgi, irg, block, base, index, new_mem); } @@ -2561,7 +2560,7 @@ static ir_node *create_I2I_Conv(ir_mode *src_mode, ir_mode *tgt_mode, new_op = noreg; am.op_type = ia32_AddrModeS; } else { - new_op = be_transform_node(op); + new_op = be_transform_node(op); am.op_type = ia32_Normal; } if(addr->base == NULL) @@ -4654,14 +4653,18 @@ void ia32_add_missing_keeps(ia32_code_gen_t *cg) /* do the transformation */ void ia32_transform_graph(ia32_code_gen_t *cg) { + ir_graph *irg = cg->irg; + register_transformers(); env_cg = cg; initial_fpcw = NULL; - heights = heights_new(cg->irg); + heights = heights_new(irg); + calculate_non_address_mode_nodes(irg); be_transform_graph(cg->birg, ia32_pretransform_node, cg); + free_non_address_mode_nodes(); heights_free(heights); heights = NULL; } diff --git a/ir/be/ia32/ia32_transform.h b/ir/be/ia32/ia32_transform.h index fda2b411e..c3512d84e 100644 --- a/ir/be/ia32/ia32_transform.h +++ b/ir/be/ia32/ia32_transform.h @@ -61,4 +61,12 @@ ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct); void ia32_add_missing_keeps(ia32_code_gen_t *cg); +/** + * return true if the node is a Proj(Load) and could be used in source address + * mode for another node. Will return only true if the @p other node is not + * dependent on the memory of the Load (for binary operations use the other + * input here, for unary operations use NULL). + */ +int use_source_address_mode(ir_node *block, ir_node *node, ir_node *other); + #endif /* FIRM_BE_IA32_IA32_TRANSFORM_H */