From a824d376c1c37f80c7e1ebd6304665380d28fc5f Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Thu, 23 Oct 2008 18:02:53 +0000 Subject: [PATCH] - Part1 of backend reorganisation: Node flags and node registers are stored in a generic backend_info struct now instead of every part of the backend doing custom (and slow) stuff [r23142] --- ir/be/TEMPLATE/TEMPLATE_new_nodes.c | 3 - ir/be/TEMPLATE/bearch_TEMPLATE.c | 61 +- ir/be/arm/arm_new_nodes.c | 3 - ir/be/arm/arm_spec.pl | 109 +- ir/be/arm/bearch_arm.c | 100 +- ir/be/beabi.c | 163 +- ir/be/bearch.c | 82 +- ir/be/bearch.h | 26 +- ir/be/bearch_t.h | 58 +- ir/be/bechordal.c | 2 +- ir/be/becopyheur2.c | 3 +- ir/be/becopyheur4.c | 31 +- ir/be/becopyilp2.c | 6 +- ir/be/becopyopt.c | 67 +- ir/be/beifg.c | 26 +- ir/be/belower.c | 8 +- ir/be/bemain.c | 10 +- ir/be/benode.c | 283 +- ir/be/benode_t.h | 30 +- ir/be/besched.c | 21 - ir/be/besched.h | 5 +- ir/be/besched_t.h | 22 +- ir/be/beschednormal.c | 17 +- ir/be/beschedrss.c | 6 +- ir/be/beschedtrace.c | 15 +- ir/be/bespill.c | 36 +- ir/be/bespillbelady.c | 5 +- ir/be/bespillbelady2.c | 2 +- ir/be/bespillremat.c | 4617 ------------------------- ir/be/bespillremat.h | 35 - ir/be/bessadestr.c | 27 +- ir/be/bestate.c | 1 - ir/be/beverify.c | 33 +- ir/be/ia32/bearch_ia32.c | 105 +- ir/be/ia32/ia32_emitter.c | 2 +- ir/be/ia32/ia32_finish.c | 10 +- ir/be/ia32/ia32_fpu.c | 1 - ir/be/ia32/ia32_new_nodes.c | 113 +- ir/be/ia32/ia32_new_nodes.h | 27 - ir/be/ia32/ia32_nodes_attr.h | 5 - ir/be/ia32/ia32_optimize.c | 18 +- ir/be/ia32/ia32_spec.pl | 88 +- ir/be/ia32/ia32_transform.c | 33 +- ir/be/ia32/ia32_x87.c | 29 +- ir/be/mips/bearch_mips.c | 51 +- ir/be/mips/mips_new_nodes.c | 3 - ir/be/mips/mips_spec.pl | 88 +- ir/be/ppc32/bearch_ppc32.c | 71 +- ir/be/ppc32/ppc32_new_nodes.c | 3 - ir/be/ppc32/ppc32_spec.pl | 85 - ir/be/scripts/generate_new_opcodes.pl | 72 +- ir/ir/irnode.c | 5 + ir/ir/irtypes.h | 1 + 53 files changed, 646 insertions(+), 6077 deletions(-) delete mode 100644 ir/be/bespillremat.c delete mode 100644 ir/be/bespillremat.h diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c index 4333cbd84..d3ff9ba63 100644 --- a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c @@ -205,9 +205,6 @@ static int TEMPLATE_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { if (attr->flags & arch_irn_flags_rematerializable) { fprintf(F, " remat"); } - if (attr->flags & arch_irn_flags_ignore) { - fprintf(F, " ignore"); - } } fprintf(F, " (%d)\n", attr->flags); diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.c b/ir/be/TEMPLATE/bearch_TEMPLATE.c index 367ddafb7..9731e29e7 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE.c +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.c @@ -112,49 +112,6 @@ static const arch_register_req_t *TEMPLATE_get_irn_reg_req(const ir_node *node, return arch_no_register_req; } -static void TEMPLATE_set_irn_reg(ir_node *irn, const arch_register_t *reg) -{ - int pos = 0; - - if (is_Proj(irn)) { - pos = TEMPLATE_translate_proj_pos(irn); - irn = skip_Proj(irn); - } - - if (is_TEMPLATE_irn(irn)) { - const arch_register_t **slots; - - slots = get_TEMPLATE_slots(irn); - slots[pos] = reg; - } - else { - /* here we set the registers for the Phi nodes */ - TEMPLATE_set_firm_reg(irn, reg, cur_reg_set); - } -} - -static const arch_register_t *TEMPLATE_get_irn_reg(const ir_node *irn) -{ - int pos = 0; - const arch_register_t *reg = NULL; - - if (is_Proj(irn)) { - pos = TEMPLATE_translate_proj_pos(irn); - irn = skip_Proj_const(irn); - } - - if (is_TEMPLATE_irn(irn)) { - const arch_register_t * const *slots; - slots = get_TEMPLATE_slots_const(irn); - reg = slots[pos]; - } - else { - reg = TEMPLATE_get_firm_reg(irn, cur_reg_set); - } - - return reg; -} - static arch_irn_class_t TEMPLATE_classify(const ir_node *irn) { irn = skip_Proj_const(irn); @@ -166,20 +123,6 @@ static arch_irn_class_t TEMPLATE_classify(const ir_node *irn) return 0; } -static arch_irn_flags_t TEMPLATE_get_flags(const ir_node *irn) -{ - irn = skip_Proj_const(irn); - - if (is_TEMPLATE_irn(irn)) { - return get_TEMPLATE_flags(irn); - } - else if (is_Unknown(irn)) { - return arch_irn_flags_ignore; - } - - return 0; -} - static ir_entity *TEMPLATE_get_frame_entity(const ir_node *node) { (void) node; @@ -215,10 +158,7 @@ static int TEMPLATE_get_sp_bias(const ir_node *irn) static const arch_irn_ops_t TEMPLATE_irn_ops = { TEMPLATE_get_irn_reg_req, - TEMPLATE_set_irn_reg, - TEMPLATE_get_irn_reg, TEMPLATE_classify, - TEMPLATE_get_flags, TEMPLATE_get_frame_entity, TEMPLATE_set_frame_entity, TEMPLATE_set_frame_offset, @@ -664,6 +604,7 @@ static int TEMPLATE_is_valid_clobber(const void *self, const char *clobber) const arch_isa_if_t TEMPLATE_isa_if = { TEMPLATE_init, TEMPLATE_done, + NULL, /* handle intrinsics */ TEMPLATE_get_n_reg_class, TEMPLATE_get_reg_class, TEMPLATE_get_reg_class_for_mode, diff --git a/ir/be/arm/arm_new_nodes.c b/ir/be/arm/arm_new_nodes.c index 8fe748eb4..5b2a3e1cf 100644 --- a/ir/be/arm/arm_new_nodes.c +++ b/ir/be/arm/arm_new_nodes.c @@ -235,9 +235,6 @@ static int arm_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { if (attr->flags & arch_irn_flags_rematerializable) { fprintf(F, " remat"); } - if (attr->flags & arch_irn_flags_ignore) { - fprintf(F, " ignore"); - } } fprintf(F, " (%d)\n", attr->flags); diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl index 3adff6607..8e5a9d470 100644 --- a/ir/be/arm/arm_spec.pl +++ b/ir/be/arm/arm_spec.pl @@ -10,99 +10,6 @@ $new_emit_syntax = 1; # the number of additional opcodes you want to register #$additional_opcodes = 0; -# The node description is done as a perl hash initializer with the -# following structure: -# -# %nodes = ( -# -# => { -# op_flags => "N|L|C|X|I|F|Y|H|c|K", -# irn_flags => "R|N|I|S" -# arity => "0|1|2|3 ... |variable|dynamic|any", -# state => "floats|pinned|mem_pinned|exc_pinned", -# args => [ -# { type => "type 1", name => "name 1" }, -# { type => "type 2", name => "name 2" }, -# ... -# ], -# comment => "any comment for constructor", -# reg_req => { in => [ "reg_class|register" ], out => [ "reg_class|register|in_rX" ] }, -# cmp_attr => "c source code for comparing node attributes", -# outs => { "out1", "out2" } # optional, creates pn_op_out1, ... consts -# ins => { "in1", "in2" } # optional, creates n_op_in1, ... consts -# mode => "mode_Iu" # optional, predefines the mode -# emit => "emit code with templates", -# attr => "attitional attribute arguments for constructor", -# init_attr => "emit attribute initialization template", -# rd_constructor => "c source code which constructs an ir_node" -# hash_func => "name of the hash function for this operation", -# latency => "latency of this operation (can be float)" -# attr_type => "name of the attribute struct", -# }, -# -# ... # (all nodes you need to describe) -# -# ); # close the %nodes initializer - -# op_flags: flags for the operation, OPTIONAL (default is "N") -# the op_flags correspond to the firm irop_flags: -# N irop_flag_none -# L irop_flag_labeled -# C irop_flag_commutative -# X irop_flag_cfopcode -# I irop_flag_ip_cfopcode -# F irop_flag_fragile -# Y irop_flag_forking -# H irop_flag_highlevel -# c irop_flag_constlike -# K irop_flag_keep -# -# irn_flags: special node flags, OPTIONAL (default is 0) -# following irn_flags are supported: -# R rematerializeable -# N not spillable -# I ignore for register allocation -# S modifies stack pointer -# -# state: state of the operation, OPTIONAL (default is "floats") -# -# arity: arity of the operation, MUST NOT BE OMITTED -# -# args: the OPTIONAL arguments of the node constructor (debug, irg and block -# are always the first 3 arguments and are always autmatically -# created) -# If this key is missing the following arguments will be created: -# for i = 1 .. arity: ir_node *op_i -# ir_mode *mode -# -# outs: if a node defines more than one output, the names of the projections -# nodes having outs having automatically the mode mode_T -# One can also annotate some flags for each out, additional to irn_flags. -# They are separated from name with a colon ':', and concatenated by pipe '|' -# Only I and S are available at the moment (same meaning as in irn_flags). -# example: [ "frame:I", "stack:I|S", "M" ] -# -# comment: OPTIONAL comment for the node constructor -# -# rd_constructor: for every operation there will be a -# new_rd__ function with the arguments from above -# which creates the ir_node corresponding to the defined operation -# you can either put the complete source code of this function here -# -# This key is OPTIONAL. If omitted, the following constructor will -# be created: -# if (!op__) assert(0); -# for i = 1 to arity -# set in[i] = op_i -# done -# res = new_ir_node(db, irg, block, op__, mode, arity, in) -# return res -# -# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3 -# -# latency: the latency of the operation, default is 1 -# - # # Modes # @@ -232,8 +139,7 @@ $default_copy_attr = "arm_copy_attr"; Unknown_GP => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_UKNWN" ] }, + reg_req => { out => [ "gp_UKNWN:I" ] }, emit => "", mode => $mode_gp, }, @@ -241,8 +147,7 @@ Unknown_GP => { Unknown_FPA => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "fpa_UKNWN" ] }, + reg_req => { out => [ "fpa_UKNWN:I" ] }, emit => "", mode => $mode_fpa, }, @@ -1029,21 +934,19 @@ fpaDbl2GP => { }, AddSP => { - irn_flags => "I", comment => "construct Add to stack pointer", - reg_req => { in => [ "sp", "gp", "none" ], out => [ "in_r1", "none" ] }, + reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "none" ] }, emit => '. add %D0, %S0, %S1', - outs => [ "stack:I|S", "M" ], + outs => [ "stack", "M" ], }, SubSPandCopy => { -#irn_flags => "I", comment => "construct Sub from stack pointer and copy to Register", - reg_req => { in => [ "sp", "gp", "none" ], out => [ "in_r1", "gp", "none" ] }, + reg_req => { in => [ "sp", "gp", "none" ], out => [ "sp:I|S", "gp", "none" ] }, ins => [ "stack", "size", "mem" ], emit => ". sub %D0, %S0, %S1\n". ". mov sp, %D1", - outs => [ "stack:I|S", "addr", "M" ], + outs => [ "stack", "addr", "M" ], }, LdTls => { diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index a02e900c4..eeb378f51 100644 --- a/ir/be/arm/bearch_arm.c +++ b/ir/be/arm/bearch_arm.c @@ -130,58 +130,6 @@ static const arch_register_req_t *arm_get_irn_reg_req(const ir_node *node, return arch_no_register_req; } -static void arm_set_irn_reg(ir_node *irn, const arch_register_t *reg) -{ - int pos = 0; - - if (get_irn_mode(irn) == mode_X) { - return; - } - - if (is_Proj(irn)) { - pos = get_Proj_proj(irn); - irn = skip_Proj(irn); - } - - if (is_arm_irn(irn)) { - const arch_register_t **slots; - - slots = get_arm_slots(irn); - slots[pos] = reg; - } - else { - /* here we set the registers for the Phi nodes */ - arm_set_firm_reg(irn, reg, cur_reg_set); - } -} - -static const arch_register_t *arm_get_irn_reg(const ir_node *irn) -{ - int pos = 0; - const arch_register_t *reg = NULL; - - if (is_Proj(irn)) { - - if (get_irn_mode(irn) == mode_X) { - return NULL; - } - - pos = get_Proj_proj(irn); - irn = skip_Proj_const(irn); - } - - if (is_arm_irn(irn)) { - const arch_register_t **slots; - slots = get_arm_slots(irn); - reg = slots[pos]; - } - else { - reg = arm_get_firm_reg(irn, cur_reg_set); - } - - return reg; -} - static arch_irn_class_t arm_classify(const ir_node *irn) { irn = skip_Proj_const(irn); @@ -193,29 +141,6 @@ static arch_irn_class_t arm_classify(const ir_node *irn) return 0; } -static arch_irn_flags_t arm_get_flags(const ir_node *irn) -{ - arch_irn_flags_t flags = arch_irn_flags_none; - - if(is_Unknown(irn)) { - return arch_irn_flags_ignore; - } - - if (is_Proj(irn) && mode_is_datab(get_irn_mode(irn))) { - ir_node *pred = get_Proj_pred(irn); - if (is_arm_irn(pred)) { - flags = get_arm_out_flags(pred, get_Proj_proj(irn)); - } - irn = pred; - } - - if (is_arm_irn(irn)) { - flags |= get_arm_flags(irn); - } - - return flags; -} - static ir_entity *arm_get_frame_entity(const ir_node *irn) { /* we do NOT transform be_Spill or be_Reload nodes, so we never have frame access using ARM nodes. */ @@ -250,10 +175,7 @@ static int arm_get_sp_bias(const ir_node *irn) static const arch_irn_ops_t arm_irn_ops = { arm_get_irn_reg_req, - arm_set_irn_reg, - arm_get_irn_reg, arm_classify, - arm_get_flags, arm_get_frame_entity, arm_set_frame_entity, arm_set_stack_bias, @@ -908,8 +830,7 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * block = get_irg_start_block(irg); ip = be_new_Copy(gp, irg, block, sp); - arch_set_irn_register(ip, &arm_gp_regs[REG_R12]); - be_set_constr_single_reg(ip, BE_OUT_POS(0), &arm_gp_regs[REG_R12] ); + be_set_constr_single_reg_out(ip, 0, &arm_gp_regs[REG_R12], arch_register_req_type_produces_sp); store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem); @@ -918,15 +839,13 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * *mem = new_r_Proj(irg, block, store, mode_M, pn_arm_StoreStackM4Inc_M); keep = be_new_CopyKeep_single(gp, irg, block, ip, sp, get_irn_mode(ip)); - be_node_set_reg_class(keep, 1, gp); - arch_set_irn_register(keep, &arm_gp_regs[REG_R12]); - be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_gp_regs[REG_R12] ); + be_node_set_reg_class_in(keep, 1, gp); + be_set_constr_single_reg_out(keep, 0, &arm_gp_regs[REG_R12], arch_register_req_type_produces_sp); fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp), 4); arch_set_irn_register(fp, env->arch_env->bp); - fp = be_new_Copy(gp, irg, block, fp); // XXX Gammelfix: only be_ nodes can have the ignore flag set - arch_set_irn_register(fp, env->arch_env->bp); - be_node_set_flags(fp, BE_OUT_POS(0), arch_irn_flags_ignore); + fp = be_new_Copy(gp, irg, block, fp); // XXX Gammelfix: only be_ have custom register requirements + be_set_constr_single_reg_out(fp, 0, env->arch_env->bp, 0); be_abi_reg_map_set(reg_map, env->arch_env->bp, fp); be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R12], keep); @@ -952,14 +871,10 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m curr_sp = be_new_IncSP(env->arch_env->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0); curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr)); - be_node_set_reg_class(curr_lr, 1, &arm_reg_classes[CLASS_arm_gp]); - arch_set_irn_register(curr_lr, &arm_gp_regs[REG_LR]); - be_set_constr_single_reg(curr_lr, BE_OUT_POS(0), &arm_gp_regs[REG_LR] ); + be_set_constr_single_reg_out(curr_lr, 0, &arm_gp_regs[REG_LR], 0); curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr ); - arch_set_irn_register(curr_pc, &arm_gp_regs[REG_PC]); - be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_gp_regs[REG_PC] ); - be_node_set_flags(curr_pc, BE_OUT_POS(0), arch_irn_flags_ignore); + be_set_constr_single_reg_out(curr_pc, BE_OUT_POS(0), &arm_gp_regs[REG_PC], 0); } else { ir_node *sub12_node; ir_node *load_node; @@ -1243,6 +1158,7 @@ static const lc_opt_table_entry_t arm_options[] = { const arch_isa_if_t arm_isa_if = { arm_init, arm_done, + NULL, /* handle_intrinsics */ arm_get_n_reg_class, arm_get_reg_class, arm_get_reg_class_for_mode, diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 5a39c296c..8e73d0c1c 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -665,10 +665,9 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) /* create new stack pointer */ curr_sp = new_r_Proj(irg, bl, low_call, get_irn_mode(curr_sp), pn_be_Call_sp); - be_set_constr_single_reg(low_call, BE_OUT_POS(pn_be_Call_sp), sp); + be_set_constr_single_reg_out(low_call, pn_be_Call_sp, sp, + arch_register_req_type_ignore | arch_register_req_type_produces_sp); arch_set_irn_register(curr_sp, sp); - be_node_set_flags(low_call, BE_OUT_POS(pn_be_Call_sp), - arch_irn_flags_ignore | arch_irn_flags_modify_sp); for(i = 0; i < n_res; ++i) { int pn; @@ -704,7 +703,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) Set the register class of the call address to the backend provided class (default: stack pointer class) */ - be_node_set_reg_class(low_call, be_pos_Call_ptr, call->cls_addr); + be_node_set_reg_class_in(low_call, be_pos_Call_ptr, call->cls_addr); DBG((env->dbg, LEVEL_3, "\tcreated backend call %+F\n", low_call)); @@ -714,7 +713,8 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) be_abi_call_arg_t *arg = get_call_arg(call, 0, index); assert(arg->reg != NULL); - be_set_constr_single_reg(low_call, be_pos_Call_first_arg + i, arg->reg); + be_set_constr_single_reg_in(low_call, be_pos_Call_first_arg + i, + arg->reg, 0); } /* Set the register constraints of the results. */ @@ -724,7 +724,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) int pn = get_Proj_proj(proj); assert(arg->in_reg); - be_set_constr_single_reg(low_call, BE_OUT_POS(pn), arg->reg); + be_set_constr_single_reg_out(low_call, pn, arg->reg, 0); arch_set_irn_register(proj, arg->reg); } obstack_free(obst, in); @@ -755,15 +755,9 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) curr_res_proj); /* memorize the register in the link field. we need afterwards to set the register class of the keep correctly. */ - be_set_constr_single_reg(low_call, BE_OUT_POS(curr_res_proj), reg); + be_set_constr_single_reg_out(low_call, curr_res_proj, reg, 0); arch_set_irn_register(proj, reg); - /* a call can produce ignore registers, in this case set the flag and register for the Proj */ - if (arch_register_type_is(reg, ignore)) { - be_node_set_flags(low_call, BE_OUT_POS(curr_res_proj), - arch_irn_flags_ignore); - } - set_irn_link(proj, (void*) reg); obstack_ptr_grow(obst, proj); curr_res_proj++; @@ -782,7 +776,7 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp) keep = be_new_Keep(NULL, irg, bl, n, in); for (i = 0; i < n; ++i) { const arch_register_t *reg = get_irn_link(in[i]); - be_node_set_reg_class(keep, i, reg->reg_class); + be_node_set_reg_class_in(keep, i, reg->reg_class); } obstack_free(obst, in); } @@ -1246,50 +1240,6 @@ static ir_type *compute_arg_type(be_abi_irg_t *env, be_abi_call_t *call, ir_type return res; } -#if 0 -static void create_register_perms(const arch_isa_t *isa, ir_graph *irg, ir_node *bl, pmap *regs) -{ - int i, j, n; - struct obstack obst; - - obstack_init(&obst); - - /* Create a Perm after the RegParams node to delimit it. */ - for (i = 0, n = arch_isa_get_n_reg_class(isa); i < n; ++i) { - const arch_register_class_t *cls = arch_isa_get_reg_class(isa, i); - ir_node *perm; - ir_node **in; - int n_regs; - - for (n_regs = 0, j = 0; j < cls->n_regs; ++j) { - const arch_register_t *reg = &cls->regs[j]; - ir_node *irn = pmap_get(regs, (void *) reg); - - if(irn && !arch_register_type_is(reg, ignore)) { - n_regs++; - obstack_ptr_grow(&obst, irn); - set_irn_link(irn, (void *) reg); - } - } - - obstack_ptr_grow(&obst, NULL); - in = obstack_finish(&obst); - if (n_regs > 0) { - perm = be_new_Perm(cls, irg, bl, n_regs, in); - for (j = 0; j < n_regs; ++j) { - ir_node *arg = in[j]; - arch_register_t *reg = get_irn_link(arg); - pmap_insert(regs, reg, arg); - be_set_constr_single_reg(perm, BE_OUT_POS(j), reg); - } - } - obstack_free(&obst, in); - } - - obstack_free(&obst, NULL); -} -#endif - typedef struct { const arch_register_t *reg; ir_node *irn; @@ -1350,28 +1300,28 @@ static ir_node *create_barrier(be_abi_irg_t *env, ir_node *bl, ir_node **mem, pm obstack_free(&env->obst, in); for(n = 0; n < n_regs; ++n) { - const arch_register_t *reg = rm[n].reg; - int flags = 0; - int pos = BE_OUT_POS(n); - ir_node *proj; + ir_node *pred = rm[n].irn; + const arch_register_t *reg = rm[n].reg; + arch_register_type_t add_type = 0; + ir_node *proj; + + /* stupid workaround for now... as not all nodes report register + * requirements. */ + if (!is_Phi(pred)) { + const arch_register_req_t *ireq = arch_get_register_req_out(pred); + if (ireq->type & arch_register_req_type_ignore) + add_type |= arch_register_req_type_ignore; + if (ireq->type & arch_register_req_type_produces_sp) + add_type |= arch_register_req_type_produces_sp; + } - proj = new_r_Proj(irg, bl, irn, get_irn_mode(rm[n].irn), n); - be_node_set_reg_class(irn, n, reg->reg_class); + proj = new_r_Proj(irg, bl, irn, get_irn_mode(pred), n); + be_node_set_reg_class_in(irn, n, reg->reg_class); if (in_req) - be_set_constr_single_reg(irn, n, reg); - be_set_constr_single_reg(irn, pos, reg); - be_node_set_reg_class(irn, pos, reg->reg_class); + be_set_constr_single_reg_in(irn, n, reg, 0); + be_set_constr_single_reg_out(irn, n, reg, add_type); arch_set_irn_register(proj, reg); - /* if the proj projects a ignore register or a node which is set to ignore, propagate this property. */ - if (arch_register_type_is(reg, ignore) || arch_irn_is(in[n], ignore)) - flags |= arch_irn_flags_ignore; - - if (arch_irn_is(in[n], modify_sp)) - flags |= arch_irn_flags_modify_sp; - - be_node_set_flags(irn, pos, flags); - pmap_insert(regs, (void *) reg, proj); } @@ -1490,9 +1440,12 @@ static ir_node *create_be_return(be_abi_irg_t *env, ir_node *irn, ir_node *bl, ret = be_new_Return(dbgi, env->birg->irg, bl, n_res, pop, n, in); /* Set the register classes of the return's parameter accordingly. */ - for (i = 0; i < n; ++i) - if (regs[i]) - be_node_set_reg_class(ret, i, regs[i]->reg_class); + for (i = 0; i < n; ++i) { + if (regs[i] == NULL) + continue; + + be_node_set_reg_class_in(ret, i, regs[i]->reg_class); + } /* Free the space of the Epilog's in array and the register <-> proj map. */ obstack_free(&env->obst, in); @@ -1824,33 +1777,22 @@ static void modify_irg(be_abi_irg_t *env) rm = reg_map_to_arr(&env->obst, env->regs); for (i = 0, n = pmap_count(env->regs); i < n; ++i) { - arch_register_t *reg = (void *) rm[i].reg; - ir_mode *mode = reg->reg_class->mode; - long nr = i; - int pos = BE_OUT_POS((int) nr); - int flags = 0; + arch_register_t *reg = (void *) rm[i].reg; + ir_mode *mode = reg->reg_class->mode; + long nr = i; + arch_register_req_type_t add_type = 0; + ir_node *proj; - ir_node *proj; + if (reg == sp) + add_type |= arch_register_req_type_produces_sp | arch_register_req_type_ignore; assert(nr >= 0); bitset_set(used_proj_nr, nr); proj = new_r_Proj(irg, reg_params_bl, env->reg_params, mode, nr); pmap_insert(env->regs, (void *) reg, proj); - be_set_constr_single_reg(env->reg_params, pos, reg); + be_set_constr_single_reg_out(env->reg_params, nr, reg, add_type); arch_set_irn_register(proj, reg); - /* - * If the register is an ignore register, - * The Proj for that register shall also be ignored during register allocation. - */ - if (arch_register_type_is(reg, ignore)) - flags |= arch_irn_flags_ignore; - - if (reg == sp) - flags |= arch_irn_flags_modify_sp; - - be_node_set_flags(env->reg_params, pos, flags); - DBG((dbg, LEVEL_2, "\tregister save proj #%d -> reg %s\n", nr, reg->name)); } obstack_free(&env->obst, rm); @@ -1863,7 +1805,7 @@ static void modify_irg(be_abi_irg_t *env) mem = new_mem_proj; /* Generate the Prologue */ - fp_reg = call->cb->prologue(env->cb, &mem, env->regs, &env->frame.initial_bias); + fp_reg = call->cb->prologue(env->cb, &mem, env->regs, &env->frame.initial_bias); /* do the stack allocation BEFORE the barrier, or spill code might be added before it */ @@ -2188,6 +2130,9 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) limited_bitset = rbitset_obstack_alloc(&env->obst, env->sp_req.cls->n_regs); rbitset_set(limited_bitset, arch_register_get_index(env->arch_env->sp)); env->sp_req.limited = limited_bitset; + if (env->arch_env->sp->type & arch_register_type_ignore) { + env->sp_req.type |= arch_register_req_type_ignore; + } env->sp_cls_req.type = arch_register_req_type_normal; env->sp_cls_req.cls = arch_register_get_class(env->arch_env->sp); @@ -2310,12 +2255,17 @@ typedef struct fix_stack_walker_env_t { */ static void collect_stack_nodes_walker(ir_node *node, void *data) { - fix_stack_walker_env_t *env = data; + fix_stack_walker_env_t *env = data; + const arch_register_req_t *req; - if (arch_irn_is(node, modify_sp)) { - assert(get_irn_mode(node) != mode_M && get_irn_mode(node) != mode_T); - ARR_APP1(ir_node*, env->sp_nodes, node); - } + if (get_irn_mode(node) == mode_T) + return; + + req = arch_get_register_req_out(node); + if (! (req->type & arch_register_req_type_produces_sp)) + return; + + ARR_APP1(ir_node*, env->sp_nodes, node); } void be_abi_fix_stack_nodes(be_abi_irg_t *env) @@ -2345,7 +2295,7 @@ void be_abi_fix_stack_nodes(be_abi_irg_t *env) be_ssa_construction_add_copies(&senv, walker_env.sp_nodes, ARR_LEN(walker_env.sp_nodes)); be_ssa_construction_fix_users_array(&senv, walker_env.sp_nodes, - ARR_LEN(walker_env.sp_nodes)); + ARR_LEN(walker_env.sp_nodes)); if(lv != NULL) { len = ARR_LEN(walker_env.sp_nodes); @@ -2361,8 +2311,7 @@ void be_abi_fix_stack_nodes(be_abi_irg_t *env) len = ARR_LEN(phis); for(i = 0; i < len; ++i) { ir_node *phi = phis[i]; - be_set_phi_reg_req(phi, &env->sp_req); - be_set_phi_flags(phi, arch_irn_flags_ignore | arch_irn_flags_modify_sp); + be_set_phi_reg_req(phi, &env->sp_req, arch_register_req_type_produces_sp); arch_set_irn_register(phi, env->arch_env->sp); } be_ssa_construction_destroy(&senv); diff --git a/ir/be/bearch.c b/ir/be/bearch.c index bf7598498..700115c40 100644 --- a/ir/be/bearch.c +++ b/ir/be/bearch.c @@ -29,6 +29,7 @@ #include "bearch_t.h" #include "benode_t.h" +#include "beinfo.h" #include "ircons_t.h" #include "irnode_t.h" @@ -176,28 +177,78 @@ const arch_register_class_t *arch_get_irn_reg_class(const ir_node *irn, int pos) return req->cls; } -const arch_register_t *arch_get_irn_register(const ir_node *irn) +static inline reg_out_info_t *get_out_info(const ir_node *node) { - const arch_irn_ops_t *ops = get_irn_ops(irn); - return ops->get_irn_reg(irn); + int pos = 0; + const backend_info_t *info; + + assert(get_irn_mode(node) != mode_T); + if (is_Proj(node)) { + pos = get_Proj_proj(node); + node = get_Proj_pred(node); + } + + info = be_get_info(node); + assert(pos >= 0 && pos < ARR_LEN(info->out_infos)); + return &info->out_infos[pos]; } -void arch_set_irn_register(ir_node *irn, const arch_register_t *reg) + +static inline reg_out_info_t *get_out_info_n(const ir_node *node, int pos) { - const arch_irn_ops_t *ops = get_irn_ops(irn); - ops->set_irn_reg(irn, reg); + const backend_info_t *info = be_get_info(node); + assert(!is_Proj(node)); + assert(pos >= 0 && pos < ARR_LEN(info->out_infos)); + return &info->out_infos[pos]; } -arch_irn_class_t arch_irn_classify(const ir_node *irn) + +const arch_register_t *arch_get_irn_register(const ir_node *node) { - const arch_irn_ops_t *ops = get_irn_ops(irn); - return ops->classify(irn); + const reg_out_info_t *out = get_out_info(node); + return out->reg; } -arch_irn_flags_t arch_irn_get_flags(const ir_node *irn) +const arch_register_t *arch_irn_get_register(const ir_node *node, int pos) { - const arch_irn_ops_t *ops = get_irn_ops(irn); - return ops->get_flags(irn); + const reg_out_info_t *out = get_out_info_n(node, pos); + return out->reg; +} + +void arch_irn_set_register(ir_node *node, int pos, const arch_register_t *reg) +{ + reg_out_info_t *out = get_out_info_n(node, pos); + out->reg = reg; +} + +void arch_set_irn_register(ir_node *node, const arch_register_t *reg) +{ + reg_out_info_t *out = get_out_info(node); + out->reg = reg; +} + +arch_irn_class_t arch_irn_classify(const ir_node *node) +{ + const arch_irn_ops_t *ops = get_irn_ops(node); + return ops->classify(node); +} + +arch_irn_flags_t arch_irn_get_flags(const ir_node *node) +{ + backend_info_t *info = be_get_info(node); + return info->flags; +} + +void arch_irn_set_flags(ir_node *node, arch_irn_flags_t flags) +{ + backend_info_t *info = be_get_info(node); + info->flags = flags; +} + +void arch_irn_add_flags(ir_node *node, arch_irn_flags_t flags) +{ + backend_info_t *info = be_get_info(node); + info->flags |= flags; } extern char *arch_register_req_format(char *buf, size_t len, @@ -247,6 +298,13 @@ extern char *arch_register_req_format(char *buf, size_t len, } } + if (arch_register_req_is(req, ignore)) { + strncat(buf, " ignore", len); + } + if (arch_register_req_is(req, produces_sp)) { + strncat(buf, " produces_sp", len); + } + return buf; } diff --git a/ir/be/bearch.h b/ir/be/bearch.h index db991331d..e72e5bfc8 100644 --- a/ir/be/bearch.h +++ b/ir/be/bearch.h @@ -26,6 +26,8 @@ #ifndef FIRM_BE_BEARCH_H #define FIRM_BE_BEARCH_H +#include + #include "firm_types.h" #include "bitset.h" #include "be.h" @@ -68,11 +70,13 @@ typedef enum arch_register_type_t { * Different types of register allocation requirements. */ typedef enum arch_register_req_type_t { - arch_register_req_type_none = 0, /**< No register requirement. */ - arch_register_req_type_normal = 1, /**< All registers in the class are allowed. */ - arch_register_req_type_limited = 2, /**< Only a real subset of the class is allowed. */ - arch_register_req_type_should_be_same = 4, /**< The register should be equal to another one at the node. */ - arch_register_req_type_must_be_different = 8, /**< The register must be unequal from some other at the node. */ + arch_register_req_type_none = 0, /**< No register requirement. */ + arch_register_req_type_normal = 1U << 0, /**< All registers in the class are allowed. */ + arch_register_req_type_limited = 1U << 1, /**< Only a real subset of the class is allowed. */ + arch_register_req_type_should_be_same = 1U << 2, /**< The register should be equal to another one at the node. */ + arch_register_req_type_must_be_different = 1U << 3, /**< The register must be unequal from some other at the node. */ + arch_register_req_type_ignore = 1U << 4, /**< ignore while allocating registers */ + arch_register_req_type_produces_sp = 1U << 5, /**< the output produces a new value for the stack pointer */ } arch_register_req_type_t; extern const arch_register_req_t *arch_no_register_req; @@ -105,9 +109,7 @@ typedef enum arch_irn_flags_t { arch_irn_flags_none = 0, /**< Node flags. */ arch_irn_flags_dont_spill = 1U << 0, /**< This must not be spilled. */ arch_irn_flags_rematerializable = 1U << 1, /**< This can be replicated instead of spilled/reloaded. */ - arch_irn_flags_ignore = 1U << 2, /**< Ignore node during register allocation. */ - arch_irn_flags_modify_sp = 1U << 3, /**< I modify the stack pointer. */ - arch_irn_flags_modify_flags = 1U << 4 /**< I modify flags. */ + arch_irn_flags_modify_flags = 1U << 2 /**< I modify flags. */ } arch_irn_flags_t; void arch_set_frame_offset(ir_node *irn, int bias); @@ -168,6 +170,7 @@ const arch_register_class_t *arch_get_irn_reg_class(const ir_node *irn, int pos) * @return The register allocated for this operand */ const arch_register_t *arch_get_irn_register(const ir_node *irn); +const arch_register_t *arch_irn_get_register(const ir_node *irn, int pos); /** * Set the register for a certain output operand. @@ -175,6 +178,7 @@ const arch_register_t *arch_get_irn_register(const ir_node *irn); * @param reg The register. */ void arch_set_irn_register(ir_node *irn, const arch_register_t *reg); +void arch_irn_set_register(ir_node *irn, int pos, const arch_register_t *reg); /** * Classify a node. @@ -192,10 +196,10 @@ arch_irn_class_t arch_irn_classify(const ir_node *irn); */ arch_irn_flags_t arch_irn_get_flags(const ir_node *irn); -#define arch_irn_is(irn, flag) ((arch_irn_get_flags(irn) & arch_irn_flags_ ## flag) != 0) +void arch_irn_set_flags(ir_node *node, arch_irn_flags_t flags); +void arch_irn_add_flags(ir_node *node, arch_irn_flags_t flags); -#define arch_irn_consider_in_reg_alloc(cls, irn) \ - (arch_get_irn_reg_class_out(irn) == (cls) && !arch_irn_is(irn, ignore)) +#define arch_irn_is(irn, flag) ((arch_irn_get_flags(irn) & arch_irn_flags_ ## flag) != 0) /** * Get the operations of an irn. diff --git a/ir/be/bearch_t.h b/ir/be/bearch_t.h index f1cfc1eaf..f4bc0fcf7 100644 --- a/ir/be/bearch_t.h +++ b/ir/be/bearch_t.h @@ -32,6 +32,7 @@ #include "beilpsched.h" #include "bemachine.h" #include "beirg.h" +#include "beinfo.h" #include "beabi.h" #include "raw_bitset.h" @@ -184,32 +185,12 @@ struct arch_irn_ops_t { * Get the register requirements for a given operand. * @param self The self pointer. * @param irn The node. - * @param pos The operand's position - * (-1 for the result of the node, 0..n for the input operands). + * @param pos The operand's position (0..n for the input operands). * @return The register requirements for the selected operand. * The pointer returned is never NULL. */ const arch_register_req_t *(*get_irn_reg_req)(const ir_node *irn, int pos); - /** - * Set the register for an output operand. - * @param irn The node. - * @param reg The register allocated to that operand. - * @note If the operand is not a register operand, - * the call is ignored. - */ - void (*set_irn_reg)(ir_node *irn, const arch_register_t *reg); - - /** - * Get the register allocated for an output operand. - * @param irn The node. - * @return The register allocated at that operand. NULL, if - * the operand was no register operand or - * @c arch_register_invalid, if no register has yet been - * allocated for this node. - */ - const arch_register_t *(*get_irn_reg)(const ir_node *irn); - /** * Classify the node. * @param irn The node. @@ -217,14 +198,6 @@ struct arch_irn_ops_t { */ arch_irn_class_t (*classify)(const ir_node *irn); - /** - * Get the flags of a node. - * @param self The irn ops themselves. - * @param irn The node. - * @return A set of flags. - */ - arch_irn_flags_t (*get_flags)(const ir_node *irn); - /** * Get the entity on the stack frame this node depends on. * @param self The this pointer. @@ -416,6 +389,8 @@ struct arch_isa_if_t { */ void (*done)(void *self); + void (*handle_intrinsics)(void); + /** * Get the the number of register classes in the isa. * @return The number of register classes. @@ -536,6 +511,8 @@ struct arch_isa_if_t { }; #define arch_env_done(env) ((env)->impl->done(env)) +#define arch_env_handle_intrinsics(env) \ + do { if((env)->impl->handle_intrinsics != NULL) (env)->impl->handle_intrinsics(); } while(0) #define arch_env_get_n_reg_class(env) ((env)->impl->get_n_reg_class(env)) #define arch_env_get_reg_class(env,i) ((env)->impl->get_reg_class(env, i)) #define arch_env_get_reg_class_for_mode(env,mode) ((env)->impl->get_reg_class_for_mode((env), (mode))) @@ -571,4 +548,25 @@ struct arch_env_t { #define arch_env_sp(env) ((env)->sp) #define arch_env_bp(env) ((env)->bp) -#endif /* FIRM_BE_BEARCH_T_H */ +static inline unsigned arch_irn_get_n_outs(const ir_node *node) +{ + backend_info_t *info = be_get_info(node); + return ARR_LEN(info->out_infos); +} + +static inline bool arch_irn_consider_in_reg_alloc( + const arch_register_class_t *cls, const ir_node *node) +{ + const arch_register_req_t *req = arch_get_register_req_out(node); + return + req->cls == cls && + !(req->type & arch_register_req_type_ignore); +} + +static inline bool arch_irn_is_ignore(const ir_node *irn) +{ + const arch_register_req_t *req = arch_get_register_req_out(irn); + return !!(req->type & arch_register_req_type_ignore); +} + +#endif diff --git a/ir/be/bechordal.c b/ir/be/bechordal.c index ade971731..6d32c1c06 100644 --- a/ir/be/bechordal.c +++ b/ir/be/bechordal.c @@ -921,7 +921,7 @@ static void assign(ir_node *block, void *env_ptr) list_for_each_entry_reverse(border_t, b, head, list) { ir_node *irn = b->irn; int nr = get_irn_idx(irn); - int ignore = arch_irn_is(irn, ignore); + int ignore = arch_irn_is_ignore(irn); /* * Assign a color, if it is a local def. Global defs already have a diff --git a/ir/be/becopyheur2.c b/ir/be/becopyheur2.c index 411646e90..8f257c005 100644 --- a/ir/be/becopyheur2.c +++ b/ir/be/becopyheur2.c @@ -1173,8 +1173,9 @@ static void ifg_dump_graph_attr(FILE *f, void *self) static int ifg_is_dump_node(void *self, ir_node *irn) { + const arch_register_req_t *req = arch_get_register_req_out(irn); (void)self; - return !arch_irn_is(irn, ignore); + return !(req->type & arch_register_req_type_ignore); } static void ifg_dump_node_attr(FILE *f, void *self, ir_node *irn) diff --git a/ir/be/becopyheur4.c b/ir/be/becopyheur4.c index bc33dd4e8..76a19306f 100644 --- a/ir/be/becopyheur4.c +++ b/ir/be/becopyheur4.c @@ -396,7 +396,7 @@ static void *co_mst_irn_init(ir_phase *ph, const ir_node *irn, void *old) { /* build list of interfering neighbours */ len = 0; be_ifg_foreach_neighbour(env->ifg, nodes_it, irn, neigh) { - if (!arch_irn_is(neigh, ignore)) { + if (!arch_irn_is_ignore(neigh)) { obstack_ptr_grow(phase_obst(ph), neigh); ++len; } @@ -552,10 +552,9 @@ static void aff_chunk_assure_weight(co_mst_env_t *env, aff_chunk_t *c) { if (an != NULL) { neighb_t *neigh; co_gs_foreach_neighb(an, neigh) { - const ir_node *m = neigh->irn; + const ir_node *m = neigh->irn; - /* skip ignore nodes */ - if (arch_irn_is(m, ignore)) + if (arch_irn_is_ignore(m)) continue; w += node_contains(c->n, m) ? neigh->costs : 0; @@ -585,8 +584,7 @@ static int count_interfering_aff_neighs(co_mst_env_t *env, const affinity_node_t const ir_node *n = neigh->irn; int i; - /* skip ignore nodes */ - if (arch_irn_is(n, ignore)) + if (arch_irn_is_ignore(n)) continue; /* check if the affinity neighbour interfere */ @@ -621,8 +619,7 @@ static void build_affinity_chunks(co_mst_env_t *env) { co_mst_irn_t *n1; affinity_node_t *an; - /* skip ignore nodes */ - if (arch_irn_is(n, ignore)) + if (arch_irn_is_ignore(n)) continue; n1 = get_co_mst_irn(env, n); @@ -645,7 +642,7 @@ static void build_affinity_chunks(co_mst_env_t *env) { aff_edge_t edge; /* skip ignore nodes */ - if (arch_irn_is(m, ignore)) + if (arch_irn_is_ignore(m)) continue; edge.src = n; @@ -721,7 +718,7 @@ static __attribute__((unused)) void chunk_order_nodes(co_mst_env_t *env, aff_chu int w = 0; neighb_t *neigh; - if (arch_irn_is(irn, ignore)) + if (arch_irn_is_ignore(irn)) continue; if (an) { @@ -747,9 +744,9 @@ static __attribute__((unused)) void chunk_order_nodes(co_mst_env_t *env, aff_chu while (!pqueue_empty(grow)) { ir_node *irn = pqueue_pop_front(grow); affinity_node_t *an = get_affinity_info(env->co, irn); - neighb_t *neigh; + neighb_t *neigh; - if (arch_irn_is(irn, ignore)) + if (arch_irn_is_ignore(irn)) continue; assert(i <= ARR_LEN(chunk->n)); @@ -802,8 +799,7 @@ static void expand_chunk_from(co_mst_env_t *env, co_mst_irn_t *node, bitset_t *v int m_idx = get_irn_idx(m); co_mst_irn_t *n2; - /* skip ignore nodes */ - if (arch_irn_is(m, ignore)) + if (arch_irn_is_ignore(m)) continue; n2 = get_co_mst_irn(env, m); @@ -1046,8 +1042,7 @@ static int recolor_nodes(co_mst_env_t *env, co_mst_irn_t *node, col_cost_t *cost neigh = node->int_neighs[j]; - /* skip ignore nodes */ - if (arch_irn_is(neigh, ignore)) + if (arch_irn_is_ignore(neigh)) continue; nn = get_co_mst_irn(env, neigh); @@ -1444,10 +1439,10 @@ int co_solve_heuristic_mst(copy_opt_t *co) { /* apply coloring */ foreach_phase_irn(&mst_env.ph, irn) { - co_mst_irn_t *mirn; + co_mst_irn_t *mirn; const arch_register_t *reg; - if (arch_irn_is(irn, ignore)) + if (arch_irn_is_ignore(irn)) continue; mirn = get_co_mst_irn(&mst_env, irn); diff --git a/ir/be/becopyilp2.c b/ir/be/becopyilp2.c index b0cd699d4..e3d7963ad 100644 --- a/ir/be/becopyilp2.c +++ b/ir/be/becopyilp2.c @@ -293,7 +293,7 @@ static void build_clique_star_cstr(ilp_env_t *ienv) { set *edges; int i, o, n_nodes, n_edges; - if (arch_irn_is(aff->irn, ignore)) + if (arch_irn_is_ignore(aff->irn)) continue; obstack_init(&ob); @@ -302,7 +302,7 @@ static void build_clique_star_cstr(ilp_env_t *ienv) { /* get all affinity neighbours */ n_nodes = 0; co_gs_foreach_neighb(aff, nbr) { - if (!arch_irn_is(nbr->irn, ignore)) { + if (!arch_irn_is_ignore(nbr->irn)) { obstack_ptr_grow(&ob, nbr->irn); ++n_nodes; } @@ -406,7 +406,7 @@ static void extend_path(ilp_env_t *ienv, pdeq *path, const ir_node *irn) { if (pdeq_contains(path, irn)) return; - if (arch_irn_is(irn, ignore)) + if (arch_irn_is_ignore(irn)) return; /* insert the new irn */ diff --git a/ir/be/becopyopt.c b/ir/be/becopyopt.c index 917b2ca58..20f7f4bcd 100644 --- a/ir/be/becopyopt.c +++ b/ir/be/becopyopt.c @@ -220,9 +220,9 @@ void free_copy_opt(copy_opt_t *co) { static int co_is_optimizable_root(ir_node *irn) { const arch_register_req_t *req; - const arch_register_t *reg; + const arch_register_t *reg; - if (arch_irn_is(irn, ignore)) + if (arch_irn_is_ignore(irn)) return 0; reg = arch_get_irn_register(irn); @@ -422,26 +422,27 @@ static void co_collect_units(ir_node *irn, void *env) /* Else insert the argument of the phi to the members of this ou */ DBG((dbg, LEVEL_1, "\t Member: %+F\n", arg)); - if (!arch_irn_is(arg, ignore)) { - /* Check if arg has occurred at a prior position in the arg/list */ - arg_pos = 0; - for (o=1; onode_count; ++o) { - if (unit->nodes[o] == arg) { - arg_pos = o; - break; - } - } + if (arch_irn_is_ignore(arg)) + continue; - if (!arg_pos) { /* a new argument */ - /* insert node, set costs */ - unit->nodes[unit->node_count] = arg; - unit->costs[unit->node_count] = co->get_costs(co, irn, arg, i); - unit->node_count++; - } else { /* arg has occurred before in same phi */ - /* increase costs for existing arg */ - unit->costs[arg_pos] += co->get_costs(co, irn, arg, i); + /* Check if arg has occurred at a prior position in the arg/list */ + arg_pos = 0; + for (o=1; onode_count; ++o) { + if (unit->nodes[o] == arg) { + arg_pos = o; + break; } } + + if (!arg_pos) { /* a new argument */ + /* insert node, set costs */ + unit->nodes[unit->node_count] = arg; + unit->costs[unit->node_count] = co->get_costs(co, irn, arg, i); + unit->node_count++; + } else { /* arg has occurred before in same phi */ + /* increase costs for existing arg */ + unit->costs[arg_pos] += co->get_costs(co, irn, arg, i); + } } unit->nodes = XREALLOC(unit->nodes, ir_node*, unit->node_count); unit->costs = XREALLOC(unit->costs, int, unit->node_count); @@ -464,10 +465,11 @@ static void co_collect_units(ir_node *irn, void *env) for (i = 0; (1U << i) <= other; ++i) { if (other & (1U << i)) { ir_node *o = get_irn_n(skip_Proj(irn), i); - if (!arch_irn_is(o, ignore) && - !nodes_interfere(co->cenv, irn, o)) { - ++count; - } + if (arch_irn_is_ignore(o)) + continue; + if (nodes_interfere(co->cenv, irn, o)) + continue; + ++count; } } @@ -482,7 +484,7 @@ static void co_collect_units(ir_node *irn, void *env) for (i = 0; 1U << i <= other; ++i) { if (other & (1U << i)) { ir_node *o = get_irn_n(skip_Proj(irn), i); - if (!arch_irn_is(o, ignore) && + if (!arch_irn_is_ignore(o) && !nodes_interfere(co->cenv, irn, o)) { unit->nodes[k] = o; unit->costs[k] = co->get_costs(co, irn, o, -1); @@ -777,7 +779,7 @@ static void build_graph_walker(ir_node *irn, void *env) { int pos, max; const arch_register_t *reg; - if (req->cls != co->cls || arch_irn_is(irn, ignore)) + if (req->cls != co->cls || arch_irn_is_ignore(irn)) return; reg = arch_get_irn_register(irn); @@ -800,7 +802,7 @@ static void build_graph_walker(ir_node *irn, void *env) { for (i = 0; 1U << i <= other; ++i) { if (other & (1U << i)) { ir_node *other = get_irn_n(skip_Proj(irn), i); - if (!arch_irn_is(other, ignore)) + if (!arch_irn_is_ignore(other)) add_edges(co, irn, other, co->get_costs(co, irn, other, 0)); } } @@ -886,14 +888,15 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) n = n_regs; be_ifg_foreach_node(ifg, it, irn) { - if (!arch_irn_is(irn, ignore)) - node_map[get_irn_idx(irn)] = n++; + if (arch_irn_is_ignore(irn)) + continue; + node_map[get_irn_idx(irn)] = n++; } fprintf(f, "%d %d\n", n, n_regs); be_ifg_foreach_node(ifg, it, irn) { - if (!arch_irn_is(irn, ignore)) { + if (!arch_irn_is_ignore(irn)) { int idx = node_map[get_irn_idx(irn)]; affinity_node_t *a = get_affinity_info(co, irn); const arch_register_req_t *req = arch_get_register_req_out(irn); @@ -907,7 +910,7 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) } be_ifg_foreach_neighbour(ifg, nit, irn, adj) { - if (!arch_irn_is(adj, ignore) && + if (!arch_irn_is_ignore(adj) && !co_dump_appel_disjoint_constraints(co, irn, adj)) { int adj_idx = node_map[get_irn_idx(adj)]; if(idx < adj_idx) @@ -919,7 +922,7 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) neighb_t *n; co_gs_foreach_neighb(a, n) { - if (!arch_irn_is(n->irn, ignore)) { + if (!arch_irn_is_ignore(n->irn)) { int n_idx = node_map[get_irn_idx(n->irn)]; if(idx < n_idx) fprintf(f, "%d %d %d\n", idx, n_idx, (int) n->costs); @@ -994,7 +997,7 @@ static void ifg_dump_graph_attr(FILE *f, void *self) static int ifg_is_dump_node(void *self, ir_node *irn) { (void)self; - return !arch_irn_is(irn, ignore); + return !arch_irn_is_ignore(irn); } static void ifg_dump_node_attr(FILE *f, void *self, ir_node *irn) diff --git a/ir/be/beifg.c b/ir/be/beifg.c index 666954f9b..f7f173c4e 100644 --- a/ir/be/beifg.c +++ b/ir/be/beifg.c @@ -642,10 +642,14 @@ static void int_comp_rec(be_ifg_t *ifg, ir_node *n, bitset_t *seen) ir_node *m; be_ifg_foreach_neighbour(ifg, neigh_it, n, m) { - if (!bitset_contains_irn(seen, m) && !arch_irn_is(m, ignore)) { - bitset_add_irn(seen, m); - int_comp_rec(ifg, m, seen); - } + if (bitset_contains_irn(seen, m)) + continue; + + if (arch_get_register_req_out(m)->type & arch_register_req_type_ignore) + continue; + + bitset_add_irn(seen, m); + int_comp_rec(ifg, m, seen); } } @@ -659,11 +663,15 @@ static int int_component_stat(be_irg_t *birg, be_ifg_t *ifg) ir_node *n; be_ifg_foreach_node(ifg, nodes_it, n) { - if (!bitset_contains_irn(seen, n) && !arch_irn_is(n, ignore)) { - ++n_comp; - bitset_add_irn(seen, n); - int_comp_rec(ifg, n, seen); - } + if (bitset_contains_irn(seen, n)) + continue; + + if (arch_get_register_req_out(n)->type & arch_register_req_type_ignore) + continue; + + ++n_comp; + bitset_add_irn(seen, n); + int_comp_rec(ifg, n, seen); } free(seen); diff --git a/ir/be/belower.c b/ir/be/belower.c index 24bc66351..46f6bb30d 100644 --- a/ir/be/belower.c +++ b/ir/be/belower.c @@ -504,7 +504,7 @@ static void gen_assure_different_pattern(ir_node *irn, ir_node *other_different, ir_node *keep, *cpy; op_copy_assoc_t *entry; - if (arch_irn_is(other_different, ignore) || + if (arch_irn_is_ignore(other_different) || !mode_is_datab(get_irn_mode(other_different))) { DBG((dbg_constr, LEVEL_1, "ignore constraint for %+F because other_irn is ignore or not a datab node\n", irn)); return; @@ -524,7 +524,7 @@ static void gen_assure_different_pattern(ir_node *irn, ir_node *other_different, cpy = find_copy(skip_Proj(irn), other_different); if (! cpy) { cpy = be_new_Copy(cls, irg, block, other_different); - be_node_set_flags(cpy, BE_OUT_POS(0), arch_irn_flags_dont_spill); + arch_irn_set_flags(cpy, arch_irn_flags_dont_spill); DBG((dbg_constr, LEVEL_1, "created non-spillable %+F for value %+F\n", cpy, other_different)); } else { DBG((dbg_constr, LEVEL_1, "using already existing %+F for value %+F\n", cpy, other_different)); @@ -534,7 +534,7 @@ static void gen_assure_different_pattern(ir_node *irn, ir_node *other_different, /* of the other_different irn in case of CopyKeep. */ if (has_irn_users(other_different)) { keep = be_new_CopyKeep_single(cls, irg, block, cpy, irn, get_irn_mode(other_different)); - be_node_set_reg_class(keep, 1, cls); + be_node_set_reg_class_in(keep, 1, cls); } else { ir_node *in[2]; @@ -736,7 +736,7 @@ static void melt_copykeeps(constraint_env_t *cenv) { /* set register class for all kept inputs */ for (j = 1; j <= n_melt; ++j) - be_node_set_reg_class(new_ck, j, entry->cls); + be_node_set_reg_class_in(new_ck, j, entry->cls); ir_nodeset_insert(&entry->copies, new_ck); diff --git a/ir/be/bemain.c b/ir/be/bemain.c index a44121ffe..371b4f9a6 100644 --- a/ir/be/bemain.c +++ b/ir/be/bemain.c @@ -473,6 +473,7 @@ static void initialize_birg(be_irg_t *birg, ir_graph *irg, be_main_env_t *env) edges_assure(irg); set_irg_phase_state(irg, phase_backend); + be_info_init_irg(irg); dump(DUMP_INITIAL, irg, "-prepared", dump_ir_block_graph); } @@ -567,11 +568,14 @@ static void be_main_loop(FILE *file_handle, const char *cup_name) num_birgs = backend_irg_list ? ARR_LEN(backend_irg_list) : get_irp_n_irgs(); birgs = ALLOCAN(be_irg_t, num_birgs + 1); + be_info_init(); + /* First: initialize all birgs */ for(i = 0; i < num_birgs; ++i) { ir_graph *irg = backend_irg_list ? backend_irg_list[i] : get_irp_irg(i); initialize_birg(&birgs[i], irg, &env); } + arch_env_handle_intrinsics(arch_env); DEL_ARR_F(irg_list); /* @@ -604,8 +608,6 @@ static void be_main_loop(FILE *file_handle, const char *cup_name) /* set the current graph (this is important for several firm functions) */ current_ir_graph = irg; - be_sched_init_phase(irg); - /* reset the phi handler. */ be_phi_handler_reset(); @@ -859,13 +861,13 @@ static void be_main_loop(FILE *file_handle, const char *cup_name) ); #undef LC_EMIT - be_sched_free_phase(irg); - be_free_birg(birg); stat_ev_ctx_pop("bemain_irg"); } ir_profile_free(); be_done_env(&env); + + be_info_free(); } /* Main interface to the frontend. */ diff --git a/ir/be/benode.c b/ir/be/benode.c index 2ec36cead..769e8ce32 100644 --- a/ir/be/benode.c +++ b/ir/be/benode.c @@ -59,20 +59,16 @@ #include "beirgmod.h" -#define OUT_POS(x) (-((x) + 1)) - #define get_irn_attr(irn) get_irn_generic_attr(irn) #define get_irn_attr_const(irn) get_irn_generic_attr_const(irn) typedef struct { arch_register_req_t req; - arch_irn_flags_t flags; } be_req_t; typedef struct { - const arch_register_t *reg; - be_req_t req; - be_req_t in_req; + be_req_t req; + be_req_t in_req; } be_reg_data_t; /** The generic be nodes attribute type. */ @@ -152,8 +148,6 @@ static int be_reqs_equal(const be_req_t *req1, const be_req_t *req2) { if(!reg_reqs_equal(&req1->req, &req2->req)) return 0; - if(req1->flags != req2->flags) - return 0; return 1; } @@ -171,8 +165,7 @@ static int _node_cmp_attr(const be_node_attr_t *a, const be_node_attr_t *b) { len = ARR_LEN(a->reg_data); for (i = 0; i < len; ++i) { - if (a->reg_data[i].reg != b->reg_data[i].reg || - !be_reqs_equal(&a->reg_data[i].in_req, &b->reg_data[i].in_req) || + if (!be_reqs_equal(&a->reg_data[i].in_req, &b->reg_data[i].in_req) || !be_reqs_equal(&a->reg_data[i].req, &b->reg_data[i].req)) return 1; } @@ -189,7 +182,10 @@ static int node_cmp_attr(ir_node *a, ir_node *b) { const be_node_attr_t *a_attr = get_irn_attr_const(a); const be_node_attr_t *b_attr = get_irn_attr_const(b); - return _node_cmp_attr(a_attr, b_attr); + if(_node_cmp_attr(a_attr, b_attr) != 0) + return 1; + + return !be_info_equal(a, b); } /** @@ -296,9 +292,16 @@ static void *init_node_attr(ir_node *node, int max_reg_data) memset(a, 0, sizeof(get_op_attr_size(get_irn_op(node)))); if(max_reg_data >= 0) { + backend_info_t *info = be_get_info(node); + info->out_infos = NEW_ARR_D(reg_out_info_t, obst, max_reg_data); + memset(info->out_infos, 0, max_reg_data * sizeof(info->out_infos[0])); + a->reg_data = NEW_ARR_D(be_reg_data_t, obst, max_reg_data); memset(a->reg_data, 0, max_reg_data * sizeof(a->reg_data[0])); } else { + backend_info_t *info = be_get_info(node); + info->out_infos = NEW_ARR_F(reg_out_info_t, 0); + a->reg_data = NEW_ARR_F(be_reg_data_t, 0); } @@ -307,10 +310,14 @@ static void *init_node_attr(ir_node *node, int max_reg_data) static void add_register_req(ir_node *node) { - be_node_attr_t *a = get_irn_attr(node); - be_reg_data_t regreq; + backend_info_t *info = be_get_info(node); + be_node_attr_t *a = get_irn_attr(node); + be_reg_data_t regreq; + reg_out_info_t out_info; memset(®req, 0, sizeof(regreq)); + memset(&out_info, 0, sizeof(out_info)); ARR_APP1(be_reg_data_t, a->reg_data, regreq); + ARR_APP1(reg_out_info_t, info->out_infos, out_info); } /** @@ -340,30 +347,6 @@ static int redir_proj(const ir_node **node) return 0; } -static be_reg_data_t *retrieve_reg_data(const ir_node *node) -{ - const be_node_attr_t *attr; - int pos = 0; - - if(is_Proj(node)) { - pos = get_Proj_proj(node); - node = get_Proj_pred(node); - } - - assert(is_be_node(node)); - attr = get_irn_attr_const(node); - assert(pos >= 0 && pos < ARR_LEN(attr->reg_data) && "illegal proj number"); - - return &attr->reg_data[pos]; -} - -static void -be_node_set_irn_reg(ir_node *irn, const arch_register_t *reg) -{ - be_reg_data_t *r = retrieve_reg_data(irn); - r->reg = reg; -} - ir_node *be_new_Spill(const arch_register_class_t *cls, const arch_register_class_t *cls_frame, ir_graph *irg, ir_node *bl, ir_node *frame, ir_node *to_spill) { @@ -378,25 +361,26 @@ ir_node *be_new_Spill(const arch_register_class_t *cls, const arch_register_clas a->ent = NULL; a->offset = 0; - be_node_set_reg_class(res, be_pos_Spill_frame, cls_frame); - be_node_set_reg_class(res, be_pos_Spill_val, cls); + be_node_set_reg_class_in(res, be_pos_Spill_frame, cls_frame); + be_node_set_reg_class_in(res, be_pos_Spill_val, cls); return res; } -ir_node *be_new_Reload(const arch_register_class_t *cls, const arch_register_class_t *cls_frame, - ir_graph *irg, ir_node *bl, ir_node *frame, ir_node *mem, ir_mode *mode) +ir_node *be_new_Reload(const arch_register_class_t *cls, + const arch_register_class_t *cls_frame, ir_graph *irg, ir_node *block, + ir_node *frame, ir_node *mem, ir_mode *mode) { ir_node *in[2]; ir_node *res; in[0] = frame; in[1] = mem; - res = new_ir_node(NULL, irg, bl, op_be_Reload, mode, 2, in); + res = new_ir_node(NULL, irg, block, op_be_Reload, mode, 2, in); init_node_attr(res, 2); - be_node_set_reg_class(res, -1, cls); - be_node_set_reg_class(res, be_pos_Reload_frame, cls_frame); - be_node_set_flags(res, -1, arch_irn_flags_rematerializable); + be_node_set_reg_class_out(res, 0, cls); + be_node_set_reg_class_in(res, be_pos_Reload_frame, cls_frame); + arch_irn_set_flags(res, arch_irn_flags_rematerializable); return res; } @@ -424,14 +408,15 @@ ir_node *be_get_Spill_frame(const ir_node *irn) return get_irn_n(irn, be_pos_Spill_frame); } -ir_node *be_new_Perm(const arch_register_class_t *cls, ir_graph *irg, ir_node *bl, int n, ir_node *in[]) +ir_node *be_new_Perm(const arch_register_class_t *cls, ir_graph *irg, + ir_node *block, int n, ir_node *in[]) { int i; - ir_node *irn = new_ir_node(NULL, irg, bl, op_be_Perm, mode_T, n, in); + ir_node *irn = new_ir_node(NULL, irg, block, op_be_Perm, mode_T, n, in); init_node_attr(irn, n); for(i = 0; i < n; ++i) { - be_node_set_reg_class(irn, i, cls); - be_node_set_reg_class(irn, OUT_POS(i), cls); + be_node_set_reg_class_in(irn, i, cls); + be_node_set_reg_class_out(irn, i, cls); } return irn; @@ -439,9 +424,11 @@ ir_node *be_new_Perm(const arch_register_class_t *cls, ir_graph *irg, ir_node *b void be_Perm_reduce(ir_node *perm, int new_size, int *map) { - int arity = get_irn_arity(perm); - be_reg_data_t *old_data = ALLOCAN(be_reg_data_t, arity); - be_node_attr_t *attr = get_irn_attr(perm); + int arity = get_irn_arity(perm); + be_reg_data_t *old_data = ALLOCAN(be_reg_data_t, arity); + reg_out_info_t *old_infos = ALLOCAN(reg_out_info_t, arity); + be_node_attr_t *attr = get_irn_attr(perm); + backend_info_t *info = be_get_info(perm); ir_node **new_in; int i; @@ -449,16 +436,18 @@ void be_Perm_reduce(ir_node *perm, int new_size, int *map) assert(be_is_Perm(perm)); assert(new_size <= arity); - NEW_ARR_A(ir_node *, new_in, new_size); + new_in = alloca(new_size * sizeof(*new_in)); /* save the old register data */ memcpy(old_data, attr->reg_data, arity * sizeof(old_data[0])); + memcpy(old_infos, info->out_infos, arity * sizeof(old_infos[0])); /* compose the new in array and set the new register data directly in place */ for (i = 0; i < new_size; ++i) { int idx = map[i]; - new_in[i] = get_irn_n(perm, idx); - attr->reg_data[i] = old_data[idx]; + new_in[i] = get_irn_n(perm, idx); + attr->reg_data[i] = old_data[idx]; + info->out_infos[i] = old_infos[idx]; } set_irn_in(perm, new_size, new_in); @@ -481,10 +470,10 @@ ir_node *be_new_MemPerm(const arch_env_t *arch_env, ir_graph *irg, ir_node *bl, irn = new_ir_node(NULL, irg, bl, op_be_MemPerm, mode_T, n+1, real_in); init_node_attr(irn, n + 1); - be_node_set_reg_class(irn, 0, sp->reg_class); + be_node_set_reg_class_in(irn, 0, sp->reg_class); for (i = 0; i < n; ++i) { - be_node_set_reg_class(irn, i + 1, cls_frame); - be_node_set_reg_class(irn, OUT_POS(i), cls_frame); + be_node_set_reg_class_in(irn, i + 1, cls_frame); + be_node_set_reg_class_out(irn, i, cls_frame); } attr = get_irn_attr(irn); @@ -507,10 +496,10 @@ ir_node *be_new_Copy(const arch_register_class_t *cls, ir_graph *irg, ir_node *b in[0] = op; res = new_ir_node(NULL, irg, bl, op_be_Copy, get_irn_mode(op), 1, in); init_node_attr(res, 1); - be_node_set_reg_class(res, 0, cls); - be_node_set_reg_class(res, OUT_POS(0), cls); + be_node_set_reg_class_in(res, 0, cls); + be_node_set_reg_class_out(res, 0, cls); - req = get_req(res, OUT_POS(0)); + req = get_req(res, BE_OUT_POS(0)); req->cls = cls; req->type = arch_register_req_type_should_be_same; req->other_same = 1U << 0; @@ -537,7 +526,7 @@ ir_node *be_new_Keep(const arch_register_class_t *cls, ir_graph *irg, ir_node *b for(i = 0; i < n; ++i) { add_irn_n(res, in[i]); add_register_req(res); - be_node_set_reg_class(res, i, cls); + be_node_set_reg_class_in(res, i, cls); } keep_alive(res); @@ -551,7 +540,7 @@ void be_Keep_add_node(ir_node *keep, const arch_register_class_t *cls, ir_node * assert(be_is_Keep(keep)); n = add_irn_n(keep, node); add_register_req(keep); - be_node_set_reg_class(keep, n, cls); + be_node_set_reg_class_in(keep, n, cls); } /* creates a be_Call */ @@ -685,12 +674,9 @@ ir_node *be_new_IncSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, a->offset = offset; a->align = align; - be_node_set_flags(irn, -1, arch_irn_flags_ignore | arch_irn_flags_modify_sp); - /* Set output constraint to stack register. */ - be_node_set_reg_class(irn, 0, sp->reg_class); - be_set_constr_single_reg(irn, BE_OUT_POS(0), sp); - be_node_set_irn_reg(irn, sp); + be_node_set_reg_class_in(irn, 0, sp->reg_class); + be_set_constr_single_reg_out(irn, 0, sp, arch_register_req_type_produces_sp); return irn; } @@ -708,17 +694,12 @@ ir_node *be_new_AddSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_ irn = new_ir_node(NULL, irg, bl, op_be_AddSP, mode_T, be_pos_AddSP_last, in); a = init_node_attr(irn, be_pos_AddSP_last); - be_node_set_flags(irn, OUT_POS(pn_be_AddSP_sp), - arch_irn_flags_ignore | arch_irn_flags_modify_sp); - /* Set output constraint to stack register. */ - be_set_constr_single_reg(irn, be_pos_AddSP_old_sp, sp); - be_node_set_reg_class(irn, be_pos_AddSP_size, arch_register_get_class(sp)); - be_set_constr_single_reg(irn, OUT_POS(pn_be_AddSP_sp), sp); - a->reg_data[pn_be_AddSP_sp].reg = sp; + be_set_constr_single_reg_in(irn, be_pos_AddSP_old_sp, sp, 0); + be_node_set_reg_class_in(irn, be_pos_AddSP_size, arch_register_get_class(sp)); + be_set_constr_single_reg_out(irn, pn_be_AddSP_sp, sp, arch_register_req_type_produces_sp); cls = arch_register_get_class(sp); - be_node_set_reg_class(irn, OUT_POS(pn_be_AddSP_res), cls); return irn; } @@ -735,14 +716,10 @@ ir_node *be_new_SubSP(const arch_register_t *sp, ir_graph *irg, ir_node *bl, ir_ irn = new_ir_node(NULL, irg, bl, op_be_SubSP, mode_T, be_pos_SubSP_last, in); a = init_node_attr(irn, be_pos_SubSP_last); - be_node_set_flags(irn, OUT_POS(pn_be_SubSP_sp), - arch_irn_flags_ignore | arch_irn_flags_modify_sp); - /* Set output constraint to stack register. */ - be_set_constr_single_reg(irn, be_pos_SubSP_old_sp, sp); - be_node_set_reg_class(irn, be_pos_SubSP_size, arch_register_get_class(sp)); - be_set_constr_single_reg(irn, OUT_POS(pn_be_SubSP_sp), sp); - a->reg_data[pn_be_SubSP_sp].reg = sp; + be_set_constr_single_reg_in(irn, be_pos_SubSP_old_sp, sp, 0); + be_node_set_reg_class_in(irn, be_pos_SubSP_size, arch_register_get_class(sp)); + be_set_constr_single_reg_out(irn, pn_be_SubSP_sp, sp, arch_register_req_type_produces_sp); return irn; } @@ -771,8 +748,8 @@ ir_node *be_new_FrameAddr(const arch_register_class_t *cls_frame, ir_graph *irg, a = init_node_attr(irn, 1); a->ent = ent; a->offset = 0; - be_node_set_reg_class(irn, 0, cls_frame); - be_node_set_reg_class(irn, OUT_POS(0), cls_frame); + be_node_set_reg_class_in(irn, 0, cls_frame); + be_node_set_reg_class_out(irn, 0, cls_frame); return optimize_node(irn); } @@ -797,8 +774,8 @@ ir_node *be_new_CopyKeep(const arch_register_class_t *cls, ir_graph *irg, ir_nod memcpy(&in[1], in_keep, n * sizeof(in[0])); irn = new_ir_node(NULL, irg, bl, op_be_CopyKeep, mode, n + 1, in); init_node_attr(irn, n + 1); - be_node_set_reg_class(irn, OUT_POS(0), cls); - be_node_set_reg_class(irn, 0, cls); + be_node_set_reg_class_in(irn, 0, cls); + be_node_set_reg_class_out(irn, 0, cls); return irn; } @@ -935,24 +912,45 @@ int be_get_MemPerm_entity_arity(const ir_node *irn) return get_irn_arity(irn) - 1; } -void be_set_constr_single_reg(ir_node *node, int pos, const arch_register_t *reg) +static void set_req_single(struct obstack *obst, arch_register_req_t *req, + const arch_register_t *reg, arch_register_req_type_t additional_types) { - arch_register_req_t *req = get_req(node, pos); const arch_register_class_t *cls = arch_register_get_class(reg); - ir_graph *irg = get_irn_irg(node); - struct obstack *obst = get_irg_obstack(irg); - unsigned *limited_bitset; - - assert(req->cls == NULL || req->cls == cls); - assert(! (req->type & arch_register_req_type_limited)); - assert(req->limited == NULL); + unsigned *limited_bitset; limited_bitset = rbitset_obstack_alloc(obst, arch_register_class_n_regs(cls)); rbitset_set(limited_bitset, arch_register_get_index(reg)); req->cls = cls; - req->type |= arch_register_req_type_limited; + req->type |= arch_register_req_type_limited | additional_types; req->limited = limited_bitset; + +} + +void be_set_constr_single_reg_in(ir_node *node, int pos, + const arch_register_t *reg, arch_register_req_type_t additional_types) +{ + arch_register_req_t *req = get_req(node, pos); + ir_graph *irg = get_irn_irg(node); + struct obstack *obst = get_irg_obstack(irg); + + set_req_single(obst, req, reg, additional_types); +} + +void be_set_constr_single_reg_out(ir_node *node, int pos, + const arch_register_t *reg, arch_register_req_type_t additional_types) +{ + arch_register_req_t *req = get_req(node, BE_OUT_POS(pos)); + ir_graph *irg = get_irn_irg(node); + struct obstack *obst = get_irg_obstack(irg); + + /* if we have an ignore register, add ignore flag and just assign it */ + if (reg->type & arch_register_type_ignore) { + additional_types |= arch_register_req_type_ignore; + } + + arch_irn_set_register(node, pos, reg); + set_req_single(obst, req, reg, additional_types); } void be_set_constr_limited(ir_node *node, int pos, const arch_register_req_t *req) @@ -967,21 +965,22 @@ void be_set_constr_limited(ir_node *node, int pos, const arch_register_req_t *re r->limited = rbitset_duplicate_obstack_alloc(obst, req->limited, req->cls->n_regs); } -void be_node_set_flags(ir_node *irn, int pos, arch_irn_flags_t flags) +void be_node_set_reg_class_in(ir_node *irn, int pos, const arch_register_class_t *cls) { - be_req_t *bereq = get_be_req(irn, pos); - bereq->flags = flags; -} + arch_register_req_t *req = get_req(irn, pos); -void be_node_add_flags(ir_node *irn, int pos, arch_irn_flags_t flags) -{ - be_req_t *bereq = get_be_req(irn, pos); - bereq->flags |= flags; + req->cls = cls; + + if (cls == NULL) { + req->type = arch_register_req_type_none; + } else if (req->type == arch_register_req_type_none) { + req->type = arch_register_req_type_normal; + } } -void be_node_set_reg_class(ir_node *irn, int pos, const arch_register_class_t *cls) +void be_node_set_reg_class_out(ir_node *irn, int pos, const arch_register_class_t *cls) { - arch_register_req_t *req = get_req(irn, pos); + arch_register_req_t *req = get_req(irn, BE_OUT_POS(pos)); req->cls = cls; @@ -1125,17 +1124,6 @@ be_node_get_irn_reg_req(const ir_node *irn, int pos) return arch_no_register_req; } -const arch_register_t * -be_node_get_irn_reg(const ir_node *irn) -{ - be_reg_data_t *r; - - if (get_irn_mode(irn) == mode_T) - return NULL; - r = retrieve_reg_data(irn); - return r->reg; -} - static arch_irn_class_t be_node_classify(const ir_node *irn) { restart: @@ -1160,21 +1148,6 @@ restart: } } -static arch_irn_flags_t be_node_get_flags(const ir_node *node) -{ - be_req_t *bereq; - int pos = -1; - - if(is_Proj(node)) { - pos = OUT_POS(get_Proj_proj(node)); - node = skip_Proj_const(node); - } - - bereq = get_be_req(node, pos); - - return bereq->flags; -} - static ir_entity *be_node_get_frame_entity(const ir_node *irn) { return be_get_frame_entity(irn); @@ -1219,10 +1192,7 @@ static int be_node_get_sp_bias(const ir_node *irn) static const arch_irn_ops_t be_node_irn_ops = { be_node_get_irn_reg_req, - be_node_set_irn_reg, - be_node_get_irn_reg, be_node_classify, - be_node_get_flags, be_node_get_frame_entity, be_node_set_frame_entity, be_node_set_frame_offset, @@ -1327,7 +1297,7 @@ const arch_register_req_t *phi_get_irn_reg_req(const ir_node *irn, int pos) const arch_register_req_t *req; req = get_Phi_reg_req_recursive(irn, &visited); - memcpy(&attr->req, req, sizeof(req[0])); + attr->req = *req; assert(attr->req.cls != NULL); attr->req.type = arch_register_req_type_normal; @@ -1338,14 +1308,16 @@ const arch_register_req_t *phi_get_irn_reg_req(const ir_node *irn, int pos) return &attr->req; } -void be_set_phi_reg_req(ir_node *node, const arch_register_req_t *req) +void be_set_phi_reg_req(ir_node *node, const arch_register_req_t *req, + arch_register_req_type_t additional_types) { phi_attr_t *attr; assert(mode_is_datab(get_irn_mode(node))); - attr = get_Phi_attr(node); - memcpy(&attr->req, req, sizeof(req[0])); + attr = get_Phi_attr(node); + attr->req = *req; + attr->req.type |= additional_types; } void be_set_phi_flags(ir_node *node, arch_irn_flags_t flags) @@ -1358,30 +1330,12 @@ void be_set_phi_flags(ir_node *node, arch_irn_flags_t flags) attr->flags = flags; } -static void phi_set_irn_reg(ir_node *irn, const arch_register_t *reg) -{ - phi_attr_t *attr = get_Phi_attr(irn); - attr->reg = reg; -} - -static const arch_register_t *phi_get_irn_reg(const ir_node *irn) -{ - phi_attr_t *attr = get_Phi_attr(irn); - return attr->reg; -} - static arch_irn_class_t phi_classify(const ir_node *irn) { (void) irn; return 0; } -static arch_irn_flags_t phi_get_flags(const ir_node *irn) -{ - phi_attr_t *attr = get_Phi_attr(irn); - return attr->flags; -} - static ir_entity *phi_get_frame_entity(const ir_node *irn) { (void) irn; @@ -1410,10 +1364,7 @@ static int phi_get_sp_bias(const ir_node *irn) static const arch_irn_ops_t phi_irn_ops = { phi_get_irn_reg_req, - phi_set_irn_reg, - phi_get_irn_reg, phi_classify, - phi_get_flags, phi_get_frame_entity, phi_set_frame_entity, phi_set_frame_offset, @@ -1489,9 +1440,8 @@ static void dump_node_reqs(FILE *f, ir_node *node) fprintf(f, "registers: \n"); for(i = 0; i < len; ++i) { - be_reg_data_t *rd = &a->reg_data[i]; - if(rd->reg) - fprintf(f, "#%d: %s\n", i, rd->reg->name); + const arch_register_t *reg = arch_irn_get_register(node, i); + fprintf(f, "#%d: %s\n", i, reg != NULL ? reg->name : "n/a"); } fprintf(f, "in requirements:\n"); @@ -1607,6 +1557,8 @@ static void copy_attr(const ir_node *old_node, ir_node *new_node) const be_node_attr_t *old_attr = get_irn_attr_const(old_node); be_node_attr_t *new_attr = get_irn_attr(new_node); struct obstack *obst = get_irg_obstack(get_irn_irg(new_node)); + backend_info_t *old_info = be_get_info(old_node); + backend_info_t *new_info = be_get_info(new_node); unsigned i, len; assert(is_be_node(old_node)); @@ -1623,12 +1575,15 @@ static void copy_attr(const ir_node *old_node, ir_node *new_node) if(get_irn_op(old_node)->opar == oparity_dynamic || be_is_RegParams(old_node)) { new_attr->reg_data = NEW_ARR_F(be_reg_data_t, len); + new_info->out_infos = NEW_ARR_F(reg_out_info_t, len); } else { new_attr->reg_data = NEW_ARR_D(be_reg_data_t, obst, len); + new_info->out_infos = NEW_ARR_D(reg_out_info_t, obst, len); } if(len > 0) { memcpy(new_attr->reg_data, old_attr->reg_data, len * sizeof(be_reg_data_t)); + memcpy(new_info->out_infos, old_info->out_infos, len * sizeof(new_info->out_infos[0])); for(i = 0; i < len; ++i) { const be_reg_data_t *rd = &old_attr->reg_data[i]; be_reg_data_t *newrd = &new_attr->reg_data[i]; diff --git a/ir/be/benode_t.h b/ir/be/benode_t.h index 3a1104d8f..2cad672bf 100644 --- a/ir/be/benode_t.h +++ b/ir/be/benode_t.h @@ -452,10 +452,13 @@ int be_get_MemPerm_entity_arity(const ir_node *irn); /** * Impose a register constraint on a backend node. * @param irn The node. - * @param pos The position of the argument/result. Results range from -1..-m and arguments form 0..n + * @param pos The position of the argument. * @param reg The register which is admissible for that node, argument/result and position. */ -void be_set_constr_single_reg(ir_node *irn, int pos, const arch_register_t *reg); +void be_set_constr_single_reg_in(ir_node *irn, int pos, + const arch_register_t *reg, arch_register_req_type_t additional_flags); +void be_set_constr_single_reg_out(ir_node *irn, int pos, + const arch_register_t *reg, arch_register_req_type_t additional_flags); /** * Impose register constraints on a backend node. @@ -467,23 +470,14 @@ void be_set_constr_single_reg(ir_node *irn, int pos, const arch_register_t *reg) */ void be_set_constr_limited(ir_node *irn, int pos, const arch_register_req_t *req); -/** - * Set the flags of a node. - * @param irn The node itself. - * @param pos The position (0..n) for arguments, (-1..-m) for results. - * @param flags The flags to set for that node and position. - */ -void be_node_set_flags(ir_node *irn, int pos, arch_irn_flags_t flags); - -void be_node_add_flags(ir_node *irn, int pos, arch_irn_flags_t flags); - /** * Set the register class of a node. * @param irn The node itself. - * @param pos The position (0..n) for arguments, (-1..-m) for results. + * @param pos The position (0..n) for arguments * @param flags The register class to set for that node and position. */ -void be_node_set_reg_class(ir_node *irn, int pos, const arch_register_class_t *cls); +void be_node_set_reg_class_in(ir_node *irn, int pos, const arch_register_class_t *cls); +void be_node_set_reg_class_out(ir_node *irn, int pos, const arch_register_class_t *cls); /** * Set the register requirement type of a node. @@ -512,12 +506,8 @@ void be_phi_handler_reset(void); /** * Set the register requirements for a phi node. */ -void be_set_phi_reg_req(ir_node *phi, const arch_register_req_t *req); - -/* - * Set flags for a phi node - */ -void be_set_phi_flags(ir_node *phi, arch_irn_flags_t flags); +void be_set_phi_reg_req(ir_node *phi, const arch_register_req_t *req, + arch_register_req_type_t additional_types); /** * irn handler for common be nodes and Phi's. diff --git a/ir/be/besched.c b/ir/be/besched.c index 5cdb8f400..0a84ac4d7 100644 --- a/ir/be/besched.c +++ b/ir/be/besched.c @@ -190,24 +190,3 @@ void be_remove_dead_nodes_from_schedule(be_irg_t *birg) // walk schedule and remove non-marked nodes irg_block_walk_graph(irg, remove_dead_nodes_walker, NULL, &env); } - -static void *sched_irn_init(ir_phase *ph, const ir_node *irn, void *old) -{ - sched_info_t *info = old ? old : phase_alloc(ph, sizeof(*info)); - - info->idx = get_irn_idx(irn); - INIT_LIST_HEAD(&info->list); - info->scheduled = 0; - info->time_step = 0; - return info; -} - -void be_sched_init_phase(ir_graph *irg) -{ - init_irg_phase(irg, PHASE_BE_SCHED, 0, sched_irn_init); -} - -void be_sched_free_phase(ir_graph *irg) -{ - free_irg_phase(irg, PHASE_BE_SCHED); -} diff --git a/ir/be/besched.h b/ir/be/besched.h index e02d94023..5352f5ee1 100644 --- a/ir/be/besched.h +++ b/ir/be/besched.h @@ -85,7 +85,4 @@ void sched_remove(const ir_node *irn); */ void be_remove_dead_nodes_from_schedule(be_irg_t *birg); -void be_sched_init_phase(ir_graph *irg); -void be_sched_free_phase(ir_graph *irg); - -#endif /* FIRM_BE_BESCHED_H */ +#endif diff --git a/ir/be/besched_t.h b/ir/be/besched_t.h index cf7b7d2d1..79685aa0d 100644 --- a/ir/be/besched_t.h +++ b/ir/be/besched_t.h @@ -36,26 +36,10 @@ #include "beutil.h" #include "besched.h" - -typedef unsigned int sched_timestep_t; - -extern size_t sched_irn_data_offset; - -/** - * The schedule structure which is present at each ir node. - * - * Currently, only basic blocks are scheduled. The list head of - * every block schedule list is the Block list. - */ -typedef struct _sched_info_t { - struct list_head list; /**< The list head to list the nodes in a schedule. */ - unsigned idx; /**< The node index of the nodes this schedule info belongs to. */ - sched_timestep_t time_step; /**< If a is after b in a schedule, its time step is larger than b's. */ - unsigned scheduled : 1; /**< 1, if the node is in the schedule of the block, 0 else. */ -} sched_info_t; +#include "beinfo.h" #define _sched_entry(list_head) (list_entry(list_head, sched_info_t, list)) -#define get_irn_sched_info(irn) ((sched_info_t *) get_or_set_irn_phase_info(skip_Proj_const(irn), PHASE_BE_SCHED)) +#define get_irn_sched_info(irn) (&be_get_info(skip_Proj_const(irn))->sched_info) #define get_sched_info_irn(irg, sched_info) get_idx_irn((irg), (sched_info)->idx) /** @@ -65,7 +49,7 @@ typedef struct _sched_info_t { */ static inline int _have_sched_info(const ir_graph *irg) { - return get_irg_phase(irg, PHASE_BE_SCHED) != NULL; + return be_info_initialized(irg); } /** diff --git a/ir/be/beschednormal.c b/ir/be/beschednormal.c index 6b83ee544..cc5ea38ca 100644 --- a/ir/be/beschednormal.c +++ b/ir/be/beschednormal.c @@ -108,17 +108,20 @@ typedef struct flag_and_cost { static int count_result(const ir_node* irn) { const ir_mode* mode = get_irn_mode(irn); - return - mode != mode_M && - mode != mode_X && - !arch_irn_is(irn, ignore); + + if (mode == mode_M || mode == mode_X) + return 0; + + if (arch_get_register_req_out(irn)->type & arch_register_req_type_ignore) + return 0; + + return 1; } /* TODO high cost for store trees */ - static int normal_tree_cost(ir_node* irn) { flag_and_cost* fc = get_irn_link(irn); @@ -159,7 +162,7 @@ static int normal_tree_cost(ir_node* irn) cost = normal_tree_cost(pred); if (be_is_Barrier(pred)) cost = 1; // XXX hack: the barrier causes all users to have a reguse of #regs - if (!arch_irn_is(pred, ignore)) { + if (!arch_irn_is_ignore(pred)) { real_pred = (is_Proj(pred) ? get_Proj_pred(pred) : pred); pred_fc = get_irn_link(real_pred); pred_fc->no_root = 1; @@ -183,7 +186,7 @@ static int normal_tree_cost(ir_node* irn) ir_node* op = fc->costs[i].irn; if (op == last) continue; if (get_irn_mode(op) == mode_M) continue; - if (arch_irn_is(op, ignore)) continue; + if (arch_irn_is_ignore(op)) continue; cost = MAX(fc->costs[i].cost + n_op_res, cost); last = op; ++n_op_res; diff --git a/ir/be/beschedrss.c b/ir/be/beschedrss.c index 3659127b2..c76ebc169 100644 --- a/ir/be/beschedrss.c +++ b/ir/be/beschedrss.c @@ -632,7 +632,7 @@ static void collect_descendants(rss_t *rss, rss_irn_t *rirn, ir_node *irn, int * ir_node *user = get_edge_src_irn(edge); /* skip ignore nodes as they do not really contribute to register pressure */ - if (arch_irn_is(user, ignore)) + if (arch_irn_is_ignore(user)) continue; /* @@ -680,7 +680,7 @@ static void collect_single_consumer(rss_t *rss, rss_irn_t *rss_irn, ir_node *con assert(! is_Proj(consumer) && "Cannot handle Projs"); if (! is_Phi(consumer) && ! is_Block(consumer) && get_nodes_block(consumer) == block) { - if (!arch_irn_is(consumer, ignore) && + if (!arch_irn_is_ignore(consumer) && !plist_has_value(rss_irn->consumer_list, consumer)) { plist_insert_back(rss_irn->consumer_list, consumer); DBG((rss->dbg, LEVEL_2, "\t\tconsumer %+F\n", consumer)); @@ -2111,7 +2111,7 @@ static void process_block(ir_node *block, void *env) { if (be_is_Keep(irn)) continue; - if (!arch_irn_is(irn, ignore) && + if (!arch_irn_is_ignore(irn) && arch_get_irn_reg_class_out(irn) == cls) { plist_insert_back(rss->nodes, skip_Proj(irn)); } diff --git a/ir/be/beschedtrace.c b/ir/be/beschedtrace.c index 5bb8d72d1..4e903ed54 100644 --- a/ir/be/beschedtrace.c +++ b/ir/be/beschedtrace.c @@ -302,11 +302,16 @@ static int get_reg_difference(trace_env_t *env, ir_node *irn) { for (i = get_irn_arity(irn) - 1; i >= 0; i--) { ir_node *in = get_irn_n(irn, i); - if (mode_is_datab(get_irn_mode(in)) && /* must be data node */ - !arch_irn_is(in, ignore) && /* ignore "ignore" nodes :) */ - !be_is_live_end(env->liveness, block, in)) { /* if the value lives outside of block: do not count */ - num_in++; - } + if (!mode_is_datab(get_irn_mode(in))) + continue; + + if (arch_irn_is_ignore(in)) + continue; + + if (be_is_live_end(env->liveness, block, in)) + continue; + + num_in++; } return num_out - num_in; diff --git a/ir/be/bespill.c b/ir/be/bespill.c index 6df8bc7dc..2746cb042 100644 --- a/ir/be/bespill.c +++ b/ir/be/bespill.c @@ -562,39 +562,19 @@ static int is_value_available(spill_env_t *env, const ir_node *arg, if(arg == get_irg_frame(env->irg)) return 1; +#if 0 /* hack for now (happens when command should be inserted at end of block) */ - if(is_Block(reloader)) { + if(is_Block(reloader)) return 0; - } +#else + (void)reloader; +#endif /* * Ignore registers are always available */ - if (arch_irn_is(arg, ignore)) { + if (arch_irn_is_ignore(arg)) return 1; - } - - /* the following test does not work while spilling, - * because the liveness info is not adapted yet to the effects of the - * additional spills/reloads. - */ -#if 0 - /* we want to remat before the insn reloader - * thus an arguments is alive if - * - it interferes with the reloaders result - * - or it is (last-) used by reloader itself - */ - if (values_interfere(env->birg->lv, reloader, arg)) { - return 1; - } - - arity = get_irn_arity(reloader); - for (i = 0; i < arity; ++i) { - ir_node *rel_arg = get_irn_n(reloader, i); - if (rel_arg == arg) - return 1; - } -#endif return 0; } @@ -640,6 +620,10 @@ static int check_remat_conditions_costs(spill_env_t *env, if(parentcosts + costs >= env->reload_cost + env->spill_cost) { return REMAT_COST_INFINITE; } + /* never rematerialize a node which modifies the flags. + * (would be better to test wether the flags are actually live at point + * reloader...) + */ if (arch_irn_is(spilled, modify_flags)) { return REMAT_COST_INFINITE; } diff --git a/ir/be/bespillbelady.c b/ir/be/bespillbelady.c index 4e4000de2..768ece1d2 100644 --- a/ir/be/bespillbelady.c +++ b/ir/be/bespillbelady.c @@ -280,11 +280,10 @@ static inline unsigned get_distance(ir_node *from, unsigned from_step, const ir_node *def, int skip_from_uses) { be_next_use_t use; - int flags = arch_irn_get_flags(def); unsigned costs; unsigned time; - assert(! (flags & arch_irn_flags_ignore)); + assert(!arch_irn_is_ignore(def)); use = be_get_next_use(uses, from, from_step, def, skip_from_uses); time = use.time; @@ -292,7 +291,7 @@ static inline unsigned get_distance(ir_node *from, unsigned from_step, return USES_INFINITY; /* We have to keep nonspillable nodes in the workingset */ - if (flags & arch_irn_flags_dont_spill) + if (arch_irn_get_flags(def) & arch_irn_flags_dont_spill) return 0; /* give some bonus to rematerialisable nodes */ diff --git a/ir/be/bespillbelady2.c b/ir/be/bespillbelady2.c index a0aa86647..cf2c4db4e 100644 --- a/ir/be/bespillbelady2.c +++ b/ir/be/bespillbelady2.c @@ -503,7 +503,7 @@ static inline unsigned get_curr_distance(block_info_t *bi, const ir_node *irn, i next_use_t *use = get_current_use(bi, irn); int flags = arch_irn_get_flags(irn); - assert(!(flags & arch_irn_flags_ignore)); + assert(!arch_irn_is_ignore(irn)); /* We have to keep non-spillable nodes in the working set */ if(flags & arch_irn_flags_dont_spill) diff --git a/ir/be/bespillremat.c b/ir/be/bespillremat.c deleted file mode 100644 index eaf4aa3f9..000000000 --- a/ir/be/bespillremat.c +++ /dev/null @@ -1,4617 +0,0 @@ -/* - * Copyright (C) 1995-2008 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 ILP based spilling & rematerialization - * @author Adam M. Szalkowski - * @date 06.04.2006 - * @version $Id$ - */ -#include "config.h" - -#ifdef WITH_ILP - -#include - -#include "array_t.h" -#include "hashptr.h" -#include "debug.h" -#include "obst.h" -#include "set.h" -#include "list.h" -#include "pmap.h" - -#include "irprintf.h" -#include "irgwalk.h" -#include "irdump_t.h" -#include "irnode_t.h" -#include "ircons_t.h" -#include "irloop_t.h" -#include "irnodeset.h" -#include "phiclass.h" -#include "iredges_t.h" -#include "execfreq.h" -#include "irvrfy.h" -#include "irbackedge_t.h" -#include "irprofile.h" - -#include -#include -#include -#include - -#include "be_t.h" -#include "beirg_t.h" -#include "belive_t.h" -#include "besched_t.h" -#include "bessaconstr.h" -#include "bearch_t.h" -#include "beintlive_t.h" -#include "beabi.h" -#include "benode_t.h" -#include "beutil.h" -#include "bespillremat.h" -#include "bespill.h" -#include "bepressurestat.h" -#include "bespilloptions.h" -#include "bechordal_t.h" -#include "bemodule.h" - -#include "lc_opts.h" -#include "lc_opts_enum.h" - -#define DUMP_PROBLEM 1 -#define DUMP_MPS 2 -#define DUMP_SOLUTION 4 -#define DUMP_STATS 8 -#define DUMP_PRESSURE 16 - -#define KEEPALIVE_REMATS 1 -#define KEEPALIVE_SPILLS 2 -#define KEEPALIVE_RELOADS 4 - -#define VERIFY_MEMINTERF 1 -#define VERIFY_DOMINANCE 2 - -#define REMATS_NONE 0 -#define REMATS_BRIGGS 1 -#define REMATS_NOINVERSE 2 -#define REMATS_ALL 3 - -static unsigned opt_dump_flags = 0; -static int opt_log = 0; -static unsigned opt_keep_alive = 0; -static int opt_goodwin = 1; -static int opt_memcopies = 1; -static int opt_memoperands = 1; -static int opt_verify = VERIFY_MEMINTERF; -static unsigned opt_remats = REMATS_ALL; -static int opt_repair_schedule = 0; -static int opt_no_enlarge_liveness = 0; -static int opt_remat_while_live = 1; -static int opt_timeout = 300; -static double opt_cost_reload = 8.0; -static double opt_cost_memoperand = 7.0; -static double opt_cost_spill = 15.0; -static double opt_cost_remat = 1.0; - - -static const lc_opt_enum_mask_items_t dump_items[] = { - { "problem", DUMP_PROBLEM }, - { "mps", DUMP_MPS }, - { "solution", DUMP_SOLUTION }, - { "stats", DUMP_STATS }, - { "pressure", DUMP_PRESSURE }, - { NULL, 0 } -}; - -static lc_opt_enum_mask_var_t dump_var = { - &opt_dump_flags, dump_items -}; - -static const lc_opt_enum_mask_items_t keepalive_items[] = { - { "remats", KEEPALIVE_REMATS }, - { "spills", KEEPALIVE_SPILLS }, - { "reloads", KEEPALIVE_RELOADS }, - { NULL, 0 } -}; - -static lc_opt_enum_mask_var_t keep_alive_var = { - &opt_keep_alive, keepalive_items -}; - -static const lc_opt_enum_mask_items_t remats_items[] = { - { "none", REMATS_NONE }, - { "briggs", REMATS_BRIGGS }, - { "noinverse", REMATS_NOINVERSE }, - { "all", REMATS_ALL }, - { NULL, 0 } -}; - -static lc_opt_enum_mask_var_t remats_var = { - &opt_remats, remats_items -}; - -static const lc_opt_table_entry_t options[] = { - LC_OPT_ENT_ENUM_MASK("keepalive", "keep alive inserted nodes", &keep_alive_var), - - LC_OPT_ENT_BOOL ("goodwin", "activate goodwin reduction", &opt_goodwin), - LC_OPT_ENT_BOOL ("memcopies", "activate memcopy handling", &opt_memcopies), - LC_OPT_ENT_BOOL ("memoperands", "activate memoperands", &opt_memoperands), - LC_OPT_ENT_ENUM_INT ("remats", "type of remats to insert", &remats_var), - LC_OPT_ENT_BOOL ("repair_schedule", "repair the schedule by rematting once used nodes",&opt_repair_schedule), - LC_OPT_ENT_BOOL ("no_enlage_liveness", "do not enlarge liveness of operands of remats",&opt_no_enlarge_liveness), - LC_OPT_ENT_BOOL ("remat_while_live", "only remat where rematted value was live", &opt_remat_while_live), - - LC_OPT_ENT_ENUM_MASK("dump", "dump problem, solution or statistical data", &dump_var), - LC_OPT_ENT_BOOL ("log", "activate the lpp log", &opt_log), - LC_OPT_ENT_INT ("timeout", "ILP solver timeout", &opt_timeout), - - LC_OPT_ENT_DBL ("cost_reload", "cost of a reload", &opt_cost_reload), - LC_OPT_ENT_DBL ("cost_memoperand", "cost of a memory operand", &opt_cost_memoperand), - LC_OPT_ENT_DBL ("cost_spill", "cost of a spill instruction", &opt_cost_spill), - LC_OPT_ENT_DBL ("cost_remat", "cost of a rematerialization", &opt_cost_remat), - LC_OPT_LAST -}; - -//#define EXECFREQ_LOOPDEPH /* compute execution frequency from loop depth only */ -//#define SCHEDULE_PHIM /* insert phim nodes into schedule */ - -#define SOLVE -//#define SOLVE_LOCAL -#define LPP_SERVER "i44pc52" -#define LPP_SOLVER "cplex" - - -#define MAX_PATHS INT_MAX -#define ILP_UNDEF -1 - -typedef struct _spill_ilp_t { - const arch_register_class_t *cls; - int n_regs; - be_irg_t *birg; - be_lv_t *lv; - lpp_t *lpp; - struct obstack *obst; - set *remat_info; - pset *all_possible_remats; - pset *inverse_ops; - ir_node *keep; - set *values; /**< for collecting all definitions of values before running ssa-construction */ - pset *spills; - set *interferences; - ir_node *m_unknown; - set *memoperands; - phi_classes_t *pc; -#ifndef SCHEDULE_PHIM - pset *phims; -#endif - DEBUG_ONLY(firm_dbg_module_t * dbg); -} spill_ilp_t; - -typedef int ilp_var_t; -typedef int ilp_cst_t; - -typedef struct _spill_bb_t { - set *ilp; - set *reloads; -} spill_bb_t; - -typedef struct _remat_t { - const ir_node *op; /**< for copy_irn */ - const ir_node *value; /**< the value which is being recomputed by this remat */ - const ir_node *proj; /**< not NULL if the above op produces a tuple */ - int cost; /**< cost of this remat */ - int inverse; /**< nonzero if this is an inverse remat */ -} remat_t; - -/** - * Data to be attached to each IR node. For remats this contains the ilp_var - * for this remat and for normal ops this contains the ilp_vars for - * reloading each operand - */ -typedef struct _op_t { - int is_remat; - union { - struct { - ilp_var_t ilp; - const remat_t *remat; /** the remat this op belongs to */ - int pre; /** 1, if this is a pressure-increasing remat */ - } remat; - struct { - ilp_var_t ilp; - ir_node *op; /** the operation this live range belongs to */ - union { - ilp_var_t *reloads; - ilp_var_t *copies; - } args; - } live_range; - } attr; -} op_t; - -typedef struct _defs_t { - const ir_node *value; - ir_node *spills; /**< points to the first spill for this value (linked by link field) */ - ir_node *remats; /**< points to the first definition for this value (linked by link field) */ -} defs_t; - -typedef struct _remat_info_t { - const ir_node *irn; /**< the irn to which these remats belong */ - pset *remats; /**< possible remats for this value */ - pset *remats_by_operand; /**< remats with this value as operand */ -} remat_info_t; - -typedef struct _keyval_t { - const void *key; - const void *val; -} keyval_t; - -typedef struct _spill_t { - ir_node *irn; - ilp_var_t reg_in; - ilp_var_t mem_in; - ilp_var_t reg_out; - ilp_var_t mem_out; - ilp_var_t spill; -} spill_t; - -typedef struct _memoperand_t { - ir_node *irn; /**< the irn */ - unsigned int pos; /**< the position of the argument */ - ilp_var_t ilp; /**< the ilp var for this memory operand */ -} memoperand_t; - -static inline int -has_reg_class(const spill_ilp_t * si, const ir_node * irn) -{ - return arch_irn_consider_in_reg_alloc(si->cls, irn); -} - -#if 0 -static int -cmp_remat(const void *a, const void *b) -{ - const keyval_t *p = a; - const keyval_t *q = b; - const remat_t *r = p->val; - const remat_t *s = q->val; - - assert(r && s); - - return !(r == s || r->op == s->op); -} -#endif -static int -cmp_remat(const void *a, const void *b) -{ - const remat_t *r = a; - const remat_t *s = b; - - return !(r == s || r->op == s->op); -} - -static int -cmp_spill(const void *a, const void *b, size_t size) -{ - const spill_t *p = a; - const spill_t *q = b; - (void) size; - -// return !(p->irn == q->irn && p->bb == q->bb); - return !(p->irn == q->irn); -} - -static int -cmp_memoperands(const void *a, const void *b, size_t size) -{ - const memoperand_t *p = a; - const memoperand_t *q = b; - (void) size; - - return !(p->irn == q->irn && p->pos == q->pos); -} - -static keyval_t * -set_find_keyval(set * set, const void * key) -{ - keyval_t query; - - query.key = key; - return set_find(set, &query, sizeof(query), HASH_PTR(key)); -} - -static keyval_t * -set_insert_keyval(set * set, void * key, void * val) -{ - keyval_t query; - - query.key = key; - query.val = val; - return set_insert(set, &query, sizeof(query), HASH_PTR(key)); -} - -static defs_t * -set_find_def(set * set, const ir_node * value) -{ - defs_t query; - - query.value = value; - return set_find(set, &query, sizeof(query), HASH_PTR(value)); -} - -static defs_t * -set_insert_def(set * set, const ir_node * value) -{ - defs_t query; - - query.value = value; - query.spills = NULL; - query.remats = NULL; - return set_insert(set, &query, sizeof(query), HASH_PTR(value)); -} - -static memoperand_t * -set_insert_memoperand(set * set, ir_node * irn, unsigned int pos, ilp_var_t ilp) -{ - memoperand_t query; - - query.irn = irn; - query.pos = pos; - query.ilp = ilp; - return set_insert(set, &query, sizeof(query), HASH_PTR(irn)+pos); -} - -static memoperand_t * -set_find_memoperand(set * set, const ir_node * irn, unsigned int pos) -{ - memoperand_t query; - - query.irn = (ir_node*)irn; - query.pos = pos; - return set_find(set, &query, sizeof(query), HASH_PTR(irn)+pos); -} - - -static spill_t * -set_find_spill(set * set, const ir_node * value) -{ - spill_t query; - - query.irn = (ir_node*)value; - return set_find(set, &query, sizeof(query), HASH_PTR(value)); -} - -#define pset_foreach(s,i) for((i)=pset_first((s)); (i); (i)=pset_next((s))) -#define set_foreach(s,i) for((i)=set_first((s)); (i); (i)=set_next((s))) -#define foreach_post_remat(s,i) for((i)=next_post_remat((s)); (i); (i)=next_post_remat((i))) -#define foreach_pre_remat(s,i) for((i)=next_pre_remat((s)); (i); (i)=next_pre_remat((i))) -#define sched_foreach_op(s,i) for((i)=sched_next_op((s));!sched_is_end((i));(i)=sched_next_op((i))) - -static int -cmp_remat_info(const void *a, const void *b, size_t size) -{ - const remat_info_t *p = a; - const remat_info_t *q = b; - (void) size; - - return !(p->irn == q->irn); -} - -static int -cmp_defs(const void *a, const void *b, size_t size) -{ - const defs_t *p = a; - const defs_t *q = b; - (void) size; - - return !(p->value == q->value); -} - -static int -cmp_keyval(const void *a, const void *b, size_t size) -{ - const keyval_t *p = a; - const keyval_t *q = b; - (void) size; - - return !(p->key == q->key); -} - -static double -execution_frequency(const spill_ilp_t *si, const ir_node * irn) -{ -#define FUDGE 0.001 - if(ir_profile_has_data()) - return ((double)ir_profile_get_block_execcount(get_block_const(irn))) + FUDGE; - -#ifndef EXECFREQ_LOOPDEPH - return get_block_execfreq(si->birg->exec_freq, get_block_const(irn)) + FUDGE; -#else - if(is_Block(irn)) - return exp(get_loop_depth(get_irn_loop(irn)) * log(10)) + FUDGE; - else - return exp(get_loop_depth(get_irn_loop(get_nodes_block(irn))) * log(10)) + FUDGE; -#endif -} - -static double get_cost(const ir_node *irn) -{ - if(be_is_Spill(irn)) { - return opt_cost_spill; - } else if(be_is_Reload(irn)){ - return opt_cost_reload; - } else { - return arch_get_op_estimated_cost(irn); - } -} - -/** - * Checks, whether node and its operands have suitable reg classes - */ -static inline int -is_rematerializable(const spill_ilp_t * si, const ir_node * irn) -{ - int n; - int remat = (arch_irn_get_flags(irn) & arch_irn_flags_rematerializable) != 0; - -#if 0 - if(!remat) - ir_fprintf(stderr, " Node %+F is not rematerializable\n", irn); -#endif - - for (n = get_irn_arity(irn)-1; n>=0 && remat; --n) { - ir_node *op = get_irn_n(irn, n); - remat &= has_reg_class(si, op) || arch_irn_get_flags(op) & arch_irn_flags_ignore || is_NoMem(op); - -// if(!remat) -// ir_fprintf(stderr, " Argument %d (%+F) of Node %+F has wrong regclass\n", i, op, irn); - } - - return remat; -} - -/** - * Try to create a remat from @p op with destination value @p dest_value - */ -static inline remat_t * -get_remat_from_op(spill_ilp_t * si, const ir_node * dest_value, const ir_node * op) -{ - remat_t *remat = NULL; - -// if(!mode_is_datab(get_irn_mode(dest_value))) -// return NULL; - - if(dest_value == op) { - const ir_node *proj = NULL; - - if(is_Proj(dest_value)) { - op = get_Proj_pred(op); - proj = dest_value; - } - - if(!is_rematerializable(si, op)) - return NULL; - - remat = obstack_alloc(si->obst, sizeof(*remat)); - remat->op = op; - remat->cost = (int)get_cost(op); - remat->value = dest_value; - remat->proj = proj; - remat->inverse = 0; - } else { - arch_inverse_t inverse; - int n; - - /* get the index of the operand we want to retrieve by the inverse op */ - for (n = get_irn_arity(op)-1; n>=0; --n) { - ir_node *arg = get_irn_n(op, n); - - if(arg == dest_value) break; - } - if(n<0) return NULL; - - DBG((si->dbg, LEVEL_5, "\t requesting inverse op for argument %d of op %+F\n", n, op)); - - /* else ask the backend to give an inverse op */ - if(arch_get_inverse(op, n, &inverse, si->obst)) { - int i; - - DBG((si->dbg, LEVEL_4, "\t backend gave us an inverse op with %d nodes and cost %d\n", inverse.n, inverse.costs)); - - assert(inverse.n > 0 && "inverse op should have at least one node"); - - for(i=inverse.n-1; i>=0; --i) { - pset_insert_ptr(si->inverse_ops, inverse.nodes[i]); - } - - if(inverse.n <= 2) { - remat = obstack_alloc(si->obst, sizeof(*remat)); - remat->op = inverse.nodes[0]; - remat->cost = inverse.costs; - remat->value = dest_value; - remat->proj = (inverse.n==2)?inverse.nodes[1]:NULL; - remat->inverse = 1; - - // Matze: commented this out, this doesn't seem to be true if - // the inverse is a simple operation with only 1 result... - //assert(is_Proj(remat->proj)); - } else { - assert(0 && "I can not handle remats with more than 2 nodes"); - } - } - } - - if(remat) { - if(remat->proj) { - DBG((si->dbg, LEVEL_3, "\t >Found remat %+F for %+F from %+F with %+F\n", remat->op, dest_value, op, remat->proj)); - } else { - DBG((si->dbg, LEVEL_3, "\t >Found remat %+F for %+F from %+F\n", remat->op, dest_value, op)); - } - } - return remat; -} - - -static inline void -add_remat(const spill_ilp_t * si, const remat_t * remat) -{ - remat_info_t *remat_info, - query; - int n; - - assert(remat->op); - assert(remat->value); - - query.irn = remat->value; - query.remats = NULL; - query.remats_by_operand = NULL; - remat_info = set_insert(si->remat_info, &query, sizeof(query), HASH_PTR(remat->value)); - - if(remat_info->remats == NULL) { - remat_info->remats = new_pset(cmp_remat, 4096); - } - pset_insert(remat_info->remats, remat, HASH_PTR(remat->op)); - - /* insert the remat into the remats_be_operand set of each argument of the remat op */ - for (n = get_irn_arity(remat->op)-1; n>=0; --n) { - ir_node *arg = get_irn_n(remat->op, n); - - query.irn = arg; - query.remats = NULL; - query.remats_by_operand = NULL; - remat_info = set_insert(si->remat_info, &query, sizeof(query), HASH_PTR(arg)); - - if(remat_info->remats_by_operand == NULL) { - remat_info->remats_by_operand = new_pset(cmp_remat, 4096); - } - pset_insert(remat_info->remats_by_operand, remat, HASH_PTR(remat->op)); - } -} - -static int -get_irn_n_nonremat_edges(const spill_ilp_t * si, const ir_node * irn) -{ - const ir_edge_t *edge = get_irn_out_edge_first(irn); - int i = 0; - - while(edge) { - if(!pset_find_ptr(si->inverse_ops, edge->src)) { - ++i; - } - edge = get_irn_out_edge_next(irn, edge); - } - - return i; -} - -static int -get_irn_n_nonignore_args(const spill_ilp_t * si, const ir_node * irn) -{ - int n; - int ret = 0; - - if(is_Proj(irn)) - irn = get_Proj_pred(irn); - - for(n=get_irn_arity(irn)-1; n>=0; --n) { - const ir_node *arg = get_irn_n(irn, n); - - if(has_reg_class(si, arg)) ++ret; - } - - return ret; -} - -static inline void -get_remats_from_op(spill_ilp_t * si, const ir_node * op) -{ - int n; - remat_t *remat; - - if( has_reg_class(si, op) - && (opt_repair_schedule || get_irn_n_nonremat_edges(si, op) > 1) - && (opt_remats != REMATS_BRIGGS || get_irn_n_nonignore_args(si, op) == 0) - ) { - remat = get_remat_from_op(si, op, op); - if(remat) { - add_remat(si, remat); - } - } - - if(opt_remats == REMATS_ALL) { - /* repeat the whole stuff for each remat retrieved by get_remat_from_op(op, arg) - for each arg */ - for (n = get_irn_arity(op)-1; n>=0; --n) { - ir_node *arg = get_irn_n(op, n); - - if(has_reg_class(si, arg)) { - /* try to get an inverse remat */ - remat = get_remat_from_op(si, arg, op); - if(remat) { - add_remat(si, remat); - } - } - } - } -} - -static inline int -value_is_defined_before(const spill_ilp_t * si, const ir_node * pos, const ir_node * val) -{ - ir_node *block; - ir_node *def_block = get_nodes_block(val); - int ret; - (void) si; - - if(val == pos) - return 0; - - /* if pos is at end of a basic block */ - if(is_Block(pos)) { - ret = (pos == def_block || block_dominates(def_block, pos)); -// ir_fprintf(stderr, "(def(bb)=%d) ", ret); - return ret; - } - - /* else if this is a normal operation */ - block = get_nodes_block(pos); - if(block == def_block) { - if(!sched_is_scheduled(val)) return 1; - - ret = sched_comes_after(val, pos); -// ir_fprintf(stderr, "(def(same block)=%d) ",ret); - return ret; - } - - ret = block_dominates(def_block, block); -// ir_fprintf(stderr, "(def(other block)=%d) ", ret); - return ret; -} - -static inline ir_node *sched_block_last_noncf(const ir_node * bb) -{ - return sched_skip((ir_node*)bb, 0, sched_skip_cf_predicator, NULL); -} - -/** - * Returns first non-Phi node of block @p bb - */ -static inline ir_node * -sched_block_first_nonphi(const ir_node * bb) -{ - return sched_skip((ir_node*)bb, 1, sched_skip_phi_predicator, NULL); -} - -static int -sched_skip_proj_predicator(const ir_node * irn, void * data) -{ - (void) data; - return (is_Proj(irn)); -} - -static inline ir_node * -sched_next_nonproj(const ir_node * irn, int forward) -{ - return sched_skip((ir_node*)irn, forward, sched_skip_proj_predicator, NULL); -} - -/** - * Returns next operation node (non-Proj) after @p irn - * or the basic block of this node - */ -static inline ir_node * -sched_next_op(const ir_node * irn) -{ - ir_node *next = sched_next(irn); - - if(is_Block(next)) - return next; - - return sched_next_nonproj(next, 1); -} - -/** - * Returns previous operation node (non-Proj) before @p irn - * or the basic block of this node - */ -static inline ir_node * -sched_prev_op(const ir_node * irn) -{ - ir_node *prev = sched_prev(irn); - - if(is_Block(prev)) - return prev; - - return sched_next_nonproj(prev, 0); -} - -static void -sched_put_after(ir_node * insert, ir_node * irn) -{ - if(is_Block(insert)) { - insert = sched_block_first_nonphi(insert); - } else { - insert = sched_next_op(insert); - } - sched_reset(irn); - sched_add_before(insert, irn); -} - -static void sched_put_before(ir_node * insert, ir_node * irn) -{ - if(is_Block(insert)) { - insert = sched_block_last_noncf(insert); - } else { - insert = sched_next_nonproj(insert, 0); - insert = sched_prev(insert); - } - sched_reset(irn); - sched_add_after(insert, irn); -} - -static ir_node * -next_post_remat(const ir_node * irn) -{ - op_t *op; - ir_node *next; - - if(is_Block(irn)) { - next = sched_block_first_nonphi(irn); - } else { - next = sched_next_op(irn); - } - - if(sched_is_end(next)) - return NULL; - - op = get_irn_link(next); - if(op->is_remat && !op->attr.remat.pre) { - return next; - } - - return NULL; -} - - -static ir_node *next_pre_remat(const ir_node * irn) -{ - op_t *op; - ir_node *ret; - - if(is_Block(irn)) { - ret = sched_block_last_noncf(irn); - ret = sched_next(ret); - ret = sched_prev_op(ret); - } else { - ret = sched_prev_op(irn); - } - - if(sched_is_end(ret) || is_Phi(ret)) - return NULL; - - op = (op_t*)get_irn_link(ret); - if(op->is_remat && op->attr.remat.pre) { - return ret; - } - - return NULL; -} - -/** - * Tells you whether a @p remat can be placed before the irn @p pos - */ -static inline int -can_remat_before(const spill_ilp_t * si, const remat_t * remat, const ir_node * pos, const pset * live) -{ - const ir_node *op = remat->op; - const ir_node *prev; - int n, - res = 1; - - if(is_Block(pos)) { - prev = sched_block_last_noncf(pos); - prev = sched_next_nonproj(prev, 0); - } else { - prev = sched_prev_op(pos); - } - /* do not remat if the rematted value is defined immediately before this op */ - if(prev == remat->op) { - return 0; - } - -#if 0 - /* this should be just fine, the following OP will be using this value, right? */ - - /* only remat AFTER the real definition of a value (?) */ - if(!value_is_defined_before(si, pos, remat->value)) { -// ir_fprintf(stderr, "error(not defined)"); - return 0; - } -#endif - - for(n=get_irn_arity(op)-1; n>=0 && res; --n) { - const ir_node *arg = get_irn_n(op, n); - - if(opt_no_enlarge_liveness) { - if(has_reg_class(si, arg) && live) { - res &= pset_find_ptr((pset*)live, arg)?1:0; - } else { - res &= value_is_defined_before(si, pos, arg); - } - } else { - res &= value_is_defined_before(si, pos, arg); - } - } - - return res; -} - -/** - * Tells you whether a @p remat can be placed after the irn @p pos - */ -static inline int -can_remat_after(const spill_ilp_t * si, const remat_t * remat, const ir_node * pos, const pset * live) -{ - if(is_Block(pos)) { - pos = sched_block_first_nonphi(pos); - } else { - pos = sched_next_op(pos); - } - - /* only remat AFTER the real definition of a value (?) */ - if(!value_is_defined_before(si, pos, remat->value)) { - return 0; - } - - return can_remat_before(si, remat, pos, live); -} - -/** - * Collect potetially rematerializable OPs - */ -static void -walker_remat_collector(ir_node * irn, void * data) -{ - spill_ilp_t *si = data; - - if(!is_Block(irn) && !is_Phi(irn)) { - DBG((si->dbg, LEVEL_4, "\t Processing %+F\n", irn)); - get_remats_from_op(si, irn); - } -} - -/** - * Inserts a copy of @p irn before @p pos - */ -static ir_node * -insert_copy_before(const spill_ilp_t * si, const ir_node * irn, ir_node * pos) -{ - ir_node *bb; - ir_node *copy; - - bb = is_Block(pos)?pos:get_nodes_block(pos); - copy = exact_copy(irn); - - set_phi_class(si->pc, copy, NULL); - set_nodes_block(copy, bb); - sched_put_before(pos, copy); - - return copy; -} - -/** - * Inserts a copy of @p irn after @p pos - */ -static ir_node * -insert_copy_after(const spill_ilp_t * si, const ir_node * irn, ir_node * pos) -{ - ir_node *bb; - ir_node *copy; - - bb = is_Block(pos)?pos:get_nodes_block(pos); - copy = exact_copy(irn); - - set_phi_class(si->pc, copy, NULL); - set_nodes_block(copy, bb); - sched_put_after(pos, copy); - - return copy; -} - -static ir_node * -insert_remat_after(spill_ilp_t * si, const remat_t * remat, ir_node * pos, const pset * live) -{ - char buf[256]; - - if(can_remat_after(si, remat, pos, live)) { - ir_node *copy, - *proj_copy; - op_t *op; - - DBG((si->dbg, LEVEL_3, "\t >inserting remat2 %+F\n", remat->op)); - - copy = insert_copy_after(si, remat->op, pos); - - ir_snprintf(buf, sizeof(buf), "remat2_%N_%N", copy, pos); - op = obstack_alloc(si->obst, sizeof(*op)); - op->is_remat = 1; - op->attr.remat.remat = remat; - op->attr.remat.pre = 0; - op->attr.remat.ilp = lpp_add_var_default(si->lpp, buf, lpp_binary, remat->cost*execution_frequency(si, pos), 0.0); - - set_irn_link(copy, op); - pset_insert_ptr(si->all_possible_remats, copy); - if(remat->proj) { - proj_copy = insert_copy_after(si, remat->proj, copy); - set_irn_n(proj_copy, 0, copy); - set_irn_link(proj_copy, op); - pset_insert_ptr(si->all_possible_remats, proj_copy); - } else { - proj_copy = NULL; - } - - return copy; - } - - return NULL; -} - -static ir_node * -insert_remat_before(spill_ilp_t * si, const remat_t * remat, ir_node * pos, const pset * live) -{ - char buf[256]; - - if(can_remat_before(si, remat, pos, live)) { - ir_node *copy, - *proj_copy; - op_t *op; - - DBG((si->dbg, LEVEL_3, "\t >inserting remat %+F\n", remat->op)); - - copy = insert_copy_before(si, remat->op, pos); - - ir_snprintf(buf, sizeof(buf), "remat_%N_%N", copy, pos); - op = obstack_alloc(si->obst, sizeof(*op)); - op->is_remat = 1; - op->attr.remat.remat = remat; - op->attr.remat.pre = 1; - op->attr.remat.ilp = lpp_add_var_default(si->lpp, buf, lpp_binary, remat->cost*execution_frequency(si, pos), 0.0); - - set_irn_link(copy, op); - pset_insert_ptr(si->all_possible_remats, copy); - if(remat->proj) { - proj_copy = insert_copy_after(si, remat->proj, copy); - set_irn_n(proj_copy, 0, copy); - set_irn_link(proj_copy, op); - pset_insert_ptr(si->all_possible_remats, proj_copy); - } else { - proj_copy = NULL; - } - - return copy; - } - - return NULL; -} - -static int -get_block_n_succs(const ir_node *block) { - const ir_edge_t *edge; - - assert(edges_activated(current_ir_graph)); - - edge = get_block_succ_first(block); - if (! edge) - return 0; - - edge = get_block_succ_next(block, edge); - return edge ? 2 : 1; -} - -static int -is_start_block(const ir_node * bb) -{ - return get_irg_start_block(get_irn_irg(bb)) == bb; -} - -static int -is_merge_edge(const ir_node * bb) -{ - if(is_start_block(bb)) - return 0; - - if(opt_goodwin) - return get_block_n_succs(bb) == 1; - else - return 1; -} - -static int -is_diverge_edge(const ir_node * bb) -{ - if(is_start_block(bb)) - return 0; - - if(opt_goodwin) - return get_Block_n_cfgpreds(bb) == 1; - else - return 1; -} - -static void -get_live_end(spill_ilp_t * si, ir_node * bb, pset * live) -{ - ir_node *irn; - int i; - - be_lv_foreach(si->lv, bb, be_lv_state_end, i) { - irn = be_lv_get_irn(si->lv, bb, i); - - if (has_reg_class(si, irn) && !pset_find_ptr(si->all_possible_remats, irn)) { - pset_insert_ptr(live, irn); - } - } - - irn = sched_last(bb); - - /* all values eaten by control flow operations are also live until the end of the block */ - sched_foreach_reverse(bb, irn) { - int i; - - if (!sched_skip_cf_predicator(irn, NULL)) break; - - for(i=get_irn_arity(irn)-1; i>=0; --i) { - ir_node *arg = get_irn_n(irn,i); - - if(has_reg_class(si, arg)) { - pset_insert_ptr(live, arg); - } - } - } - /* - * find values that are used by remats at end of block - * and insert them into live set - */ - foreach_pre_remat(bb, irn) { - int n; - - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(irn, n); - - if(!has_reg_class(si, remat_arg)) continue; - - /* if value is becoming live through use by remat */ - if(!pset_find_ptr(live, remat_arg)) { - DBG((si->dbg, LEVEL_4, " value %+F becoming live through use by remat at end of block %+F\n", remat_arg, irn)); - - pset_insert_ptr(live, remat_arg); - } - } - } -} - -static void -walker_regclass_copy_insertor(ir_node * irn, void * data) -{ - spill_ilp_t *si = data; - - if(is_Phi(irn) && has_reg_class(si, irn)) { - int n; - - for(n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *phi_arg = get_irn_n(irn, n); - ir_node *bb = get_Block_cfgpred_block(get_nodes_block(irn), n); - - if(!has_reg_class(si, phi_arg)) { - ir_node *copy = be_new_Copy(si->cls, si->birg->irg, bb, phi_arg); - ir_node *pos = sched_block_last_noncf(bb); - op_t *op = obstack_alloc(si->obst, sizeof(*op)); - - DBG((si->dbg, LEVEL_2, "\t copy to my regclass for arg %+F of %+F\n", phi_arg, irn)); - sched_add_after(pos, copy); - set_irn_n(irn, n, copy); - - op->is_remat = 0; - op->attr.live_range.args.reloads = NULL; - op->attr.live_range.ilp = ILP_UNDEF; - set_irn_link(copy, op); - } - } - } -} - -/** - * Insert (so far unused) remats into the irg to - * recompute the potential liveness of all values - */ -static void -walker_remat_insertor(ir_node * bb, void * data) -{ - spill_ilp_t *si = data; - ir_node *irn; - int n, i; - pset *live; - pset *post_remats; - remat_t *remat; - - /* skip start block, no remats to do there */ - if(is_start_block(bb)) return; - - DBG((si->dbg, LEVEL_3, "\t Entering %+F\n\n", bb)); - - live = pset_new_ptr_default(); - be_lv_foreach(si->lv, bb, be_lv_state_end, i) { - ir_node *value = be_lv_get_irn(si->lv, bb, i); - - /* add remats at end of block */ - if (has_reg_class(si, value)) { - pset_insert_ptr(live, value); - } - } - - irn = sched_last(bb); - while(!sched_is_end(irn)) { - ir_node *next; - pset *args; - ir_node *arg; - pset *used; - - next = sched_prev(irn); - - /* delete defined value from live set */ - if(has_reg_class(si, irn)) { - pset_remove_ptr(live, irn); - } - - if(is_Phi(irn) || is_Proj(irn)) { - irn = next; - continue; - } - - args = pset_new_ptr_default(); - used = pset_new_ptr_default(); - - /* collect arguments of op and set args of op already live in epilog */ - for (n = get_irn_arity(irn)-1; n>=0; --n) { - ir_node *arg = get_irn_n(irn, n); - - pset_insert_ptr(args, arg); - if(has_reg_class(si, arg)) { - pset_insert_ptr(live, arg); - pset_insert_ptr(used, arg); - } - } - - /* insert all possible remats before irn */ - pset_foreach(args, arg) { - remat_info_t *remat_info, - query; - - /* continue if the operand has the wrong reg class */ - if(!has_reg_class(si, arg)) - continue; - - query.irn = arg; - query.remats = NULL; - query.remats_by_operand = NULL; - remat_info = set_find(si->remat_info, &query, sizeof(query), HASH_PTR(arg)); - - if(!remat_info) { - continue; - } - - if(remat_info->remats) { - pset_foreach(remat_info->remats, remat) { - ir_node *remat_irn = NULL; - - DBG((si->dbg, LEVEL_4, "\t considering remat %+F for arg %+F\n", remat->op, arg)); - remat_irn = insert_remat_before(si, remat, irn, live); - - if(remat_irn) { - for(n=get_irn_arity(remat_irn)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(remat_irn, n); - - /* collect args of remats which are not args of op */ - if(has_reg_class(si, remat_arg) && !pset_find_ptr(args, remat_arg)) { - pset_insert_ptr(used, remat_arg); - } - } - } - } - } - } - - /* do not place post remats after jumps */ - if (sched_skip_cf_predicator(irn, si->birg->main_env->arch_env)) { - del_pset(used); - del_pset(args); - break; - } - - /* insert all possible remats after irn */ - post_remats = pset_new_ptr_default(); - pset_foreach(used, arg) { - remat_info_t *remat_info, - query; - - /* continue if the operand has the wrong reg class */ - if(!has_reg_class(si, arg)) - continue; - - query.irn = arg; - query.remats = NULL; - query.remats_by_operand = NULL; - remat_info = set_find(si->remat_info, &query, sizeof(query), HASH_PTR(arg)); - - if(!remat_info) { - continue; - } - - if(remat_info->remats_by_operand) { - pset_foreach(remat_info->remats_by_operand, remat) { - /* do not insert remats producing the same value as one of the operands */ - if(!pset_find_ptr(args, remat->value)) { - DBG((si->dbg, LEVEL_4, "\t considering remat %+F with arg %+F\n", remat->op, arg)); - - /* only remat values that can be used by real ops */ - if(!opt_remat_while_live || pset_find_ptr(live, remat->value)) { - pset_insert_ptr(post_remats, remat); - } - } - } - } - } - pset_foreach(post_remats, remat) { - insert_remat_after(si, remat, irn, live); - } - del_pset(post_remats); - - del_pset(used); - del_pset(args); - irn = next; - } - - /* add remats at end if successor has multiple predecessors */ - if(is_merge_edge(bb)) { - pset *live_out = pset_new_ptr_default(); - ir_node *value; - - get_live_end(si, bb, live_out); - - /* add remats at end of block */ - pset_foreach(live_out, value) { - remat_info_t *remat_info, - query; - - query.irn = value; - query.remats = NULL; - query.remats_by_operand = NULL; - remat_info = set_find(si->remat_info, &query, sizeof(query), HASH_PTR(value)); - - if(remat_info && remat_info->remats) { - pset_foreach(remat_info->remats, remat) { - DBG((si->dbg, LEVEL_4, "\t considering remat %+F at end of block %+F\n", remat->op, bb)); - - insert_remat_before(si, remat, bb, live_out); - } - } - } - del_pset(live_out); - } - - if(is_diverge_edge(bb)) { - pset *live_in = pset_new_ptr_default(); - ir_node *value; - - be_lv_foreach(si->lv, bb, be_lv_state_in, i) { - value = be_lv_get_irn(si->lv, bb, i); - - if(has_reg_class(si, value)) { - pset_insert_ptr(live_in, value); - } - } - /* add phis to live_in */ - sched_foreach(bb, value) { - if(!is_Phi(value)) break; - - if(has_reg_class(si, value)) { - pset_insert_ptr(live_in, value); - } - } - - /* add remat2s at beginning of block */ - post_remats = pset_new_ptr_default(); - pset_foreach(live_in, value) { - remat_info_t *remat_info, - query; - - query.irn = value; - query.remats = NULL; - query.remats_by_operand = NULL; - remat_info = set_find(si->remat_info, &query, sizeof(query), HASH_PTR(value)); - - if(remat_info && remat_info->remats_by_operand) { - pset_foreach(remat_info->remats_by_operand, remat) { - DBG((si->dbg, LEVEL_4, "\t considering remat2 %+F at beginning of block %+F\n", remat->op, bb)); - - /* put the remat here if all its args are available and result is still live */ - if(!opt_remat_while_live || pset_find_ptr(live_in, remat->value)) { - pset_insert_ptr(post_remats, remat); - } - } - } - } - pset_foreach(post_remats, remat) { - insert_remat_after(si, remat, bb, live_in); - } - del_pset(post_remats); - del_pset(live_in); - } -} - -static int -can_be_copied(const ir_node * bb, const ir_node * irn) -{ - const ir_edge_t *edge = get_block_succ_first(bb); - const ir_node *next_bb = edge->src; - int pos = edge->pos; - const ir_node *phi; - - assert(is_merge_edge(bb)); - - sched_foreach(next_bb, phi) { - const ir_node *phi_arg; - - if(!is_Phi(phi)) break; - - phi_arg = get_irn_n(phi, pos); - - if(phi_arg == irn) { - return 1; - } - } - return 0; -} - -/** - * Initialize additional node info - */ -static void -luke_initializer(ir_node * bb, void * data) -{ - spill_ilp_t *si = (spill_ilp_t*)data; - spill_bb_t *spill_bb; - ir_node *irn; - - spill_bb = obstack_alloc(si->obst, sizeof(*spill_bb)); - set_irn_link(bb, spill_bb); - - sched_foreach(bb, irn) { - op_t *op; - - op = obstack_alloc(si->obst, sizeof(*op)); - op->is_remat = 0; - op->attr.live_range.ilp = ILP_UNDEF; - if(is_Phi(irn)) { - if(opt_memcopies) { - op->attr.live_range.args.copies = obstack_alloc(si->obst, sizeof(*op->attr.live_range.args.copies) * get_irn_arity(irn)); - memset(op->attr.live_range.args.copies, 0xFF, sizeof(*op->attr.live_range.args.copies) * get_irn_arity(irn)); - } - } else if(!is_Proj(irn)) { - op->attr.live_range.args.reloads = obstack_alloc(si->obst, sizeof(*op->attr.live_range.args.reloads) * get_irn_arity(irn)); - memset(op->attr.live_range.args.reloads, 0xFF, sizeof(*op->attr.live_range.args.reloads) * get_irn_arity(irn)); - } else { - op->attr.live_range.args.reloads = NULL; - } - set_irn_link(irn, op); - } -} - - -/** - * Preparation of blocks' ends for Luke Blockwalker(tm)(R) - */ -static void -luke_endwalker(ir_node * bb, void * data) -{ - spill_ilp_t *si = (spill_ilp_t*)data; - pset *live; - pset *use_end; - char buf[256]; - ilp_cst_t cst; - ir_node *irn; - spill_bb_t *spill_bb = get_irn_link(bb); - int i; - - live = pset_new_ptr_default(); - use_end = pset_new_ptr_default(); - - be_lv_foreach(si->lv, bb, be_lv_state_end, i) { - irn = be_lv_get_irn(si->lv, bb, i); - if (has_reg_class(si, irn) && !pset_find_ptr(si->all_possible_remats, irn)) { - pset_insert_ptr(live, irn); - } - } - /* - * find values that are used by remats at end of block - * and insert them into live set - */ - foreach_pre_remat(bb, irn) { - int n; - - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(irn, n); - - if(has_reg_class(si, remat_arg)) { - pset_insert_ptr(live, remat_arg); - } - } - } - - /* collect values used by cond jumps etc. at bb end (use_end) -> always live */ - /* their reg_out must always be set */ - sched_foreach_reverse(bb, irn) { - int n; - - if (!sched_skip_cf_predicator(irn, si->birg->main_env->arch_env)) break; - - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *irn_arg = get_irn_n(irn, n); - - if(has_reg_class(si, irn_arg)) { - pset_insert_ptr(use_end, irn_arg); - } - } - } - - ir_snprintf(buf, sizeof(buf), "check_end_%N", bb); - //cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, si->n_regs); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, si->n_regs - pset_count(use_end)); - - spill_bb->ilp = new_set(cmp_spill, pset_count(live)+pset_count(use_end)); - - /* if this is a merge edge we can reload at the end of this block */ - if(is_merge_edge(bb)) { - spill_bb->reloads = new_set(cmp_keyval, pset_count(live)+pset_count(use_end)); - } else if(pset_count(use_end)){ - spill_bb->reloads = new_set(cmp_keyval, pset_count(use_end)); - } else { - spill_bb->reloads = NULL; - } - - pset_foreach(live,irn) { - spill_t query, - *spill; - double spill_cost; - int default_spilled; - - - /* handle values used by control flow nodes later separately */ - if(pset_find_ptr(use_end, irn)) continue; - - query.irn = irn; - spill = set_insert(spill_bb->ilp, &query, sizeof(query), HASH_PTR(irn)); - - spill_cost = is_Unknown(irn)?0.0001:opt_cost_spill*execution_frequency(si, bb); - - ir_snprintf(buf, sizeof(buf), "reg_out_%N_%N", irn, bb); - spill->reg_out = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - lpp_set_factor_fast(si->lpp, cst, spill->reg_out, 1.0); - - ir_snprintf(buf, sizeof(buf), "mem_out_%N_%N", irn, bb); - spill->mem_out = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - ir_snprintf(buf, sizeof(buf), "spill_%N_%N", irn, bb); - /* by default spill value right after definition */ - default_spilled = be_is_live_in(si->lv, bb, irn) || is_Phi(irn); - spill->spill = lpp_add_var_default(si->lpp, buf, lpp_binary, spill_cost, !default_spilled); - - if(is_merge_edge(bb)) { - ilp_var_t reload; - ilp_cst_t rel_cst; - - ir_snprintf(buf, sizeof(buf), "reload_%N_%N", bb, irn); - reload = lpp_add_var_default(si->lpp, buf, lpp_binary, opt_cost_reload*execution_frequency(si, bb), can_be_copied(bb, irn)); - set_insert_keyval(spill_bb->reloads, irn, INT_TO_PTR(reload)); - - /* reload <= mem_out */ - rel_cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, rel_cst, reload, 1.0); - lpp_set_factor_fast(si->lpp, rel_cst, spill->mem_out, -1.0); - } - - spill->reg_in = ILP_UNDEF; - spill->mem_in = ILP_UNDEF; - } - - pset_foreach(use_end,irn) { - spill_t query, - *spill; - double spill_cost; - ilp_cst_t end_use_req, - rel_cst; - ilp_var_t reload; - int default_spilled; - - query.irn = irn; - spill = set_insert(spill_bb->ilp, &query, sizeof(query), HASH_PTR(irn)); - - spill_cost = is_Unknown(irn)?0.0001:opt_cost_spill*execution_frequency(si, bb); - - ir_snprintf(buf, sizeof(buf), "reg_out_%N_%N", irn, bb); - spill->reg_out = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - ir_snprintf(buf, sizeof(buf), "mem_out_%N_%N", irn, bb); - spill->mem_out = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - ir_snprintf(buf, sizeof(buf), "spill_%N_%N", irn, bb); - default_spilled = be_is_live_in(si->lv, bb, irn) || is_Phi(irn); - spill->spill = lpp_add_var_default(si->lpp, buf, lpp_binary, spill_cost, !default_spilled); - - /* reload for use be control flow op */ - ir_snprintf(buf, sizeof(buf), "reload_%N_%N", bb, irn); - reload = lpp_add_var_default(si->lpp, buf, lpp_binary, opt_cost_reload*execution_frequency(si, bb), 1.0); - set_insert_keyval(spill_bb->reloads, irn, INT_TO_PTR(reload)); - - /* reload <= mem_out */ - rel_cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, rel_cst, reload, 1.0); - lpp_set_factor_fast(si->lpp, rel_cst, spill->mem_out, -1.0); - - spill->reg_in = ILP_UNDEF; - spill->mem_in = ILP_UNDEF; - - ir_snprintf(buf, sizeof(buf), "req_cf_end_%N_%N", irn, bb); - end_use_req = lpp_add_cst_uniq(si->lpp, buf, lpp_equal, 1); - lpp_set_factor_fast(si->lpp, end_use_req, spill->reg_out, 1.0); - } - - del_pset(live); - del_pset(use_end); -} - -#ifndef NDEBUG -/** - * Find a remat of value @p value in the epilog of @p pos - */ -static ir_node * -find_post_remat(const ir_node * value, const ir_node * pos) -{ - while((pos = next_post_remat(pos)) != NULL) { - op_t *op; - - op = get_irn_link(pos); - assert(op->is_remat && !op->attr.remat.pre); - - if(op->attr.remat.remat->value == value) - return (ir_node*)pos; - -#if 0 - const ir_edge_t *edge; - foreach_out_edge(pos, edge) { - ir_node *proj = get_edge_src_irn(edge); - assert(is_Proj(proj)); - } -#endif - - } - - return NULL; -} -#endif - -static spill_t * -add_to_spill_bb(spill_ilp_t * si, ir_node * bb, ir_node * irn) -{ - spill_bb_t *spill_bb = get_irn_link(bb); - spill_t *spill, - query; - char buf[256]; - int default_spilled; - - query.irn = irn; - spill = set_find(spill_bb->ilp, &query, sizeof(query), HASH_PTR(irn)); - if(!spill) { - double spill_cost = is_Unknown(irn)?0.0001:opt_cost_spill*execution_frequency(si, bb); - - spill = set_insert(spill_bb->ilp, &query, sizeof(query), HASH_PTR(irn)); - - spill->reg_out = ILP_UNDEF; - spill->reg_in = ILP_UNDEF; - spill->mem_in = ILP_UNDEF; - - ir_snprintf(buf, sizeof(buf), "mem_out_%N_%N", irn, bb); - spill->mem_out = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - ir_snprintf(buf, sizeof(buf), "spill_%N_%N", irn, bb); - default_spilled = be_is_live_in(si->lv, bb, irn) || is_Phi(irn); - spill->spill = lpp_add_var_default(si->lpp, buf, lpp_binary, spill_cost, !default_spilled); - } - - return spill; -} - -/** - * Inserts ILP-constraints and variables for memory copying before the given position - */ -static void -insert_mem_copy_position(spill_ilp_t * si, pset * live, const ir_node * block) -{ - const ir_node *succ; - const ir_edge_t *edge; - spill_bb_t *spill_bb = get_irn_link(block); - ir_node *phi; - int pos; - ilp_cst_t cst; - ilp_var_t copyreg; - char buf[256]; - ir_node *tmp; - - - assert(edges_activated(current_ir_graph)); - - edge = get_block_succ_first(block); - if(!edge) return; - - succ = edge->src; - pos = edge->pos; - - edge = get_block_succ_next(block, edge); - /* next block can only contain phis, if this is a merge edge */ - if(edge) return; - - ir_snprintf(buf, sizeof(buf), "copyreg_%N", block); - copyreg = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - ir_snprintf(buf, sizeof(buf), "check_copyreg_%N", block); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, si->n_regs); - - pset_foreach(live, tmp) { - spill_t *spill; -#if 0 - op_t *op = get_irn_link(irn); - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.ilp, 1.0); -#endif - spill = set_find_spill(spill_bb->ilp, tmp); - assert(spill); - - lpp_set_factor_fast(si->lpp, cst, spill->reg_out, 1.0); - } - lpp_set_factor_fast(si->lpp, cst, copyreg, 1.0); - - sched_foreach(succ, phi) { - const ir_node *to_copy; - op_t *to_copy_op; - spill_t *to_copy_spill; - op_t *phi_op = get_irn_link(phi); - ilp_var_t reload = ILP_UNDEF; - - - if(!is_Phi(phi)) break; - if(!has_reg_class(si, phi)) continue; - - to_copy = get_irn_n(phi, pos); - to_copy_op = get_irn_link(to_copy); - - to_copy_spill = set_find_spill(spill_bb->ilp, to_copy); - assert(to_copy_spill); - - if(spill_bb->reloads) { - keyval_t *keyval = set_find_keyval(spill_bb->reloads, to_copy); - - if(keyval) { - reload = PTR_TO_INT(keyval->val); - } - } - - ir_snprintf(buf, sizeof(buf), "req_copy_%N_%N_%N", block, phi, to_copy); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - /* copy - reg_out - reload - remat - live_range <= 0 */ - lpp_set_factor_fast(si->lpp, cst, phi_op->attr.live_range.args.copies[pos], 1.0); - lpp_set_factor_fast(si->lpp, cst, to_copy_spill->reg_out, -1.0); - if(reload != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, reload, -1.0); - lpp_set_factor_fast(si->lpp, cst, to_copy_op->attr.live_range.ilp, -1.0); - foreach_pre_remat(block, tmp) { - op_t *remat_op = get_irn_link(tmp); - if(remat_op->attr.remat.remat->value == to_copy) { - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, -1.0); - } - } - - ir_snprintf(buf, sizeof(buf), "copyreg_%N_%N_%N", block, phi, to_copy); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - /* copy - reg_out - copyreg <= 0 */ - lpp_set_factor_fast(si->lpp, cst, phi_op->attr.live_range.args.copies[pos], 1.0); - lpp_set_factor_fast(si->lpp, cst, to_copy_spill->reg_out, -1.0); - lpp_set_factor_fast(si->lpp, cst, copyreg, -1.0); - } -} - - -/** - * Walk all irg blocks and emit this ILP - */ -static void -luke_blockwalker(ir_node * bb, void * data) -{ - spill_ilp_t *si = (spill_ilp_t*)data; - ir_node *irn; - pset *live; - char buf[256]; - ilp_cst_t cst; - spill_bb_t *spill_bb = get_irn_link(bb); - ir_node *tmp; - spill_t *spill; - pset *defs = pset_new_ptr_default(); - - live = pset_new_ptr_default(); - - /**************************************** - * B A S I C B L O C K E N D - ***************************************/ - - - /* init live values at end of block */ - get_live_end(si, bb, live); - - pset_foreach(live, irn) { - op_t *op; - ilp_var_t reload = ILP_UNDEF; - - spill = set_find_spill(spill_bb->ilp, irn); - assert(spill); - - if(spill_bb->reloads) { - keyval_t *keyval = set_find_keyval(spill_bb->reloads, irn); - - if(keyval) { - reload = PTR_TO_INT(keyval->val); - } - } - - op = get_irn_link(irn); - assert(!op->is_remat); - - ir_snprintf(buf, sizeof(buf), "lr_%N_%N", irn, bb); - op->attr.live_range.ilp = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - op->attr.live_range.op = bb; - - ir_snprintf(buf, sizeof(buf), "reg_out_%N_%N", bb, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - /* reg_out - reload - remat - live_range <= 0 */ - lpp_set_factor_fast(si->lpp, cst, spill->reg_out, 1.0); - if(reload != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, reload, -1.0); - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.ilp, -1.0); - foreach_pre_remat(bb, tmp) { - op_t *remat_op = get_irn_link(tmp); - if(remat_op->attr.remat.remat->value == irn) { - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, -1.0); - } - } - ir_snprintf(buf, sizeof(buf), "reg_out2_%N_%N", bb, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_greater, 0.0); - - /* value may only die at bb end if it is used for a mem copy */ - /* reg_out + \sum copy - reload - remat - live_range >= 0 */ - lpp_set_factor_fast(si->lpp, cst, spill->reg_out, 1.0); - if(reload != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, reload, -1.0); - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.ilp, -1.0); - foreach_pre_remat(bb, tmp) { - op_t *remat_op = get_irn_link(tmp); - if(remat_op->attr.remat.remat->value == irn) { - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, -1.0); - } - } - if(is_merge_edge(bb)) { - const ir_edge_t *edge = get_block_succ_first(bb); - const ir_node *next_bb = edge->src; - int pos = edge->pos; - const ir_node *phi; - - sched_foreach(next_bb, phi) { - const ir_node *phi_arg; - - if(!is_Phi(phi)) break; - - phi_arg = get_irn_n(phi, pos); - - if(phi_arg == irn) { - op_t *phi_op = get_irn_link(phi); - ilp_var_t copy = phi_op->attr.live_range.args.copies[pos]; - - lpp_set_factor_fast(si->lpp, cst, copy, 1.0); - } - } - } - } - - if(opt_memcopies) - insert_mem_copy_position(si, live, bb); - - /* - * assure the remat args are available - */ - foreach_pre_remat(bb, tmp) { - op_t *remat_op = get_irn_link(tmp); - int n; - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - op_t *arg_op = get_irn_link(remat_arg); - - if(!has_reg_class(si, remat_arg)) continue; - - spill = set_find_spill(spill_bb->ilp, remat_arg); - assert(spill); - - /* arguments of remats have to be live until the very end of the block - * remat = reg_out(remat_arg) and (reload(remat_arg) or live_range(remat_arg)), - * no remats, they could be in wrong order - */ - - ir_snprintf(buf, sizeof(buf), "req_remat_%N_arg_%N", tmp, remat_arg); - cst = lpp_add_cst(si->lpp, buf, lpp_less, 0.0); - - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 3.0); - lpp_set_factor_fast(si->lpp, cst, spill->reg_out, -2.0); - lpp_set_factor_fast(si->lpp, cst, arg_op->attr.live_range.ilp, -1.0); - - /* use reload placed for this argument */ - if(spill_bb->reloads) { - keyval_t *keyval = set_find_keyval(spill_bb->reloads, remat_arg); - - if(keyval) { - ilp_var_t reload = PTR_TO_INT(keyval->val); - - lpp_set_factor_fast(si->lpp, cst, reload, -1.0); - } - } - } - } - DBG((si->dbg, LEVEL_4, "\t %d values live at end of block %+F\n", pset_count(live), bb)); - - - - - /************************************** - * B A S I C B L O C K B O D Y - **************************************/ - - sched_foreach_reverse_from(sched_block_last_noncf(bb), irn) { - op_t *op; - op_t *tmp_op; - int n, - u = 0, - d = 0; - ilp_cst_t check_pre, - check_post; - set *args; - pset *used; - pset *remat_defs; - keyval_t *keyval; - ilp_cst_t one_memoperand = -1; - - /* iterate only until first phi */ - if(is_Phi(irn)) - break; - - op = get_irn_link(irn); - /* skip remats */ - if(op->is_remat) continue; - - DBG((si->dbg, LEVEL_4, "\t at node %+F\n", irn)); - - /* collect defined values */ - if(has_reg_class(si, irn)) { - pset_insert_ptr(defs, irn); - } - - /* skip projs */ - if(is_Proj(irn)) continue; - - /* - * init set of irn's arguments - * and all possibly used values around this op - * and values defined by post remats - */ - args = new_set(cmp_keyval, get_irn_arity(irn)); - used = pset_new_ptr(pset_count(live) + get_irn_arity(irn)); - remat_defs = pset_new_ptr(pset_count(live)); - - if(!is_start_block(bb) || !be_is_Barrier(irn)) { - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *irn_arg = get_irn_n(irn, n); - if(has_reg_class(si, irn_arg)) { - set_insert_keyval(args, irn_arg, (void*)n); - pset_insert_ptr(used, irn_arg); - } - } - foreach_post_remat(irn, tmp) { - op_t *remat_op = get_irn_link(tmp); - - pset_insert_ptr(remat_defs, remat_op->attr.remat.remat->value); - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - if(has_reg_class(si, remat_arg)) { - pset_insert_ptr(used, remat_arg); - } - } - } - foreach_pre_remat(irn, tmp) { - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - if(has_reg_class(si, remat_arg)) { - pset_insert_ptr(used, remat_arg); - } - } - } - } - - /********************************** - * I N E P I L O G O F irn - **********************************/ - - /* ensure each dying value is used by only one post remat */ - pset_foreach(used, tmp) { - ir_node *value = tmp; - op_t *value_op = get_irn_link(value); - ir_node *remat; - int n_remats = 0; - - cst = ILP_UNDEF; - foreach_post_remat(irn, remat) { - op_t *remat_op = get_irn_link(remat); - - for(n=get_irn_arity(remat)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(remat, n); - - /* if value is used by this remat add it to constraint */ - if(remat_arg == value) { - if(n_remats == 0) { - /* sum remat2s <= 1 + n_remats*live_range */ - ir_snprintf(buf, sizeof(buf), "dying_lr_%N_%N", value, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1.0); - } - - n_remats++; - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - break; - } - } - } - - if(pset_find_ptr(live, value) && cst != ILP_UNDEF) { - lpp_set_factor_fast(si->lpp, cst, value_op->attr.live_range.ilp, -n_remats); - } - } - - /* ensure at least one value dies at post remat */ - foreach_post_remat(irn, tmp) { - op_t *remat_op = get_irn_link(tmp); - pset *remat_args = pset_new_ptr(get_irn_arity(tmp)); - ir_node *remat_arg; - - for(n=get_irn_arity(tmp)-1; n>=0; --n) { - remat_arg = get_irn_n(tmp, n); - - if(has_reg_class(si, remat_arg)) { - - /* does arg always die at this op? */ - if(!pset_find_ptr(live, remat_arg)) - goto skip_one_must_die; - - pset_insert_ptr(remat_args, remat_arg); - } - } - - /* remat + \sum live_range(remat_arg) <= |args| */ - ir_snprintf(buf, sizeof(buf), "one_must_die_%+F", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, pset_count(remat_args)); - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - - pset_foreach(remat_args, remat_arg) { - op_t *arg_op = get_irn_link(remat_arg); - - lpp_set_factor_fast(si->lpp, cst, arg_op->attr.live_range.ilp, 1.0); - } - -skip_one_must_die: - del_pset(remat_args); - } - - /* new live ranges for values from L\U defined by post remats */ - pset_foreach(live, tmp) { - ir_node *value = tmp; - op_t *value_op = get_irn_link(value); - - if(!set_find_keyval(args, value) && !pset_find_ptr(defs, value)) { - ilp_var_t prev_lr = ILP_UNDEF; - ir_node *remat; - - if(pset_find_ptr(remat_defs, value)) { - - /* next_live_range <= prev_live_range + sum remat2s */ - ir_snprintf(buf, sizeof(buf), "next_lr_%N_%N", value, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - ir_snprintf(buf, sizeof(buf), "lr_%N_%N", value, irn); - prev_lr = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - - lpp_set_factor_fast(si->lpp, cst, value_op->attr.live_range.ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, prev_lr, -1.0); - - foreach_post_remat(irn, remat) { - op_t *remat_op = get_irn_link(remat); - - /* if value is being rematerialized by this remat */ - if(value == remat_op->attr.remat.remat->value) { - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, -1.0); - } - } - - value_op->attr.live_range.ilp = prev_lr; - value_op->attr.live_range.op = irn; - } - } - } - - /* requirements for post remats and start live ranges from L/U' for values dying here */ - foreach_post_remat(irn, tmp) { - op_t *remat_op = get_irn_link(tmp); - int n; - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - op_t *arg_op = get_irn_link(remat_arg); - - if(!has_reg_class(si, remat_arg)) continue; - - /* only for values in L\U (TODO and D?), the others are handled with post_use */ - if(!pset_find_ptr(used, remat_arg)) { - /* remat <= live_range(remat_arg) */ - ir_snprintf(buf, sizeof(buf), "req_remat2_%N_arg_%N", tmp, remat_arg); - cst = lpp_add_cst(si->lpp, buf, lpp_less, 0.0); - - /* if value is becoming live through use by remat2 */ - if(!pset_find_ptr(live, remat_arg)) { - ilp_var_t lr; - - ir_snprintf(buf, sizeof(buf), "lr_%N_%N", remat_arg, irn); - lr = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - - arg_op->attr.live_range.ilp = lr; - arg_op->attr.live_range.op = irn; - - DBG((si->dbg, LEVEL_3, " value %+F becoming live through use by remat2 %+F\n", remat_arg, tmp)); - - pset_insert_ptr(live, remat_arg); - add_to_spill_bb(si, bb, remat_arg); - } - - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, arg_op->attr.live_range.ilp, -1.0); - } - } - } - - d = pset_count(defs); - DBG((si->dbg, LEVEL_4, "\t %+F produces %d values in my register class\n", irn, d)); - - /* count how many regs irn needs for arguments */ - u = set_count(args); - - - /* check the register pressure in the epilog */ - /* sum_{L\U'} lr + sum_{U'} post_use <= k - |D| */ - ir_snprintf(buf, sizeof(buf), "check_post_%N", irn); - check_post = lpp_add_cst_uniq(si->lpp, buf, lpp_less, si->n_regs - d); - - /* add L\U' to check_post */ - pset_foreach(live, tmp) { - if(!pset_find_ptr(used, tmp) && !pset_find_ptr(defs, tmp)) { - /* if a live value is not used by irn */ - tmp_op = get_irn_link(tmp); - lpp_set_factor_fast(si->lpp, check_post, tmp_op->attr.live_range.ilp, 1.0); - } - } - - /*********************************************************** - * I T E R A T I O N O V E R U S E S F O R E P I L O G - **********************************************************/ - - - pset_foreach(used, tmp) { - ilp_var_t prev_lr; - ilp_var_t post_use; - int p = 0; - spill_t *spill; - ir_node *arg = tmp; - op_t *arg_op = get_irn_link(arg); - ir_node *remat; - - spill = add_to_spill_bb(si, bb, arg); - - /* new live range for each used value */ - ir_snprintf(buf, sizeof(buf), "lr_%N_%N", arg, irn); - prev_lr = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - - /* the epilog stuff - including post_use, check_post, check_post_remat */ - ir_snprintf(buf, sizeof(buf), "post_use_%N_%N", arg, irn); - post_use = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - - lpp_set_factor_fast(si->lpp, check_post, post_use, 1.0); - - /* arg is live throughout epilog if the next live_range is in a register */ - if(pset_find_ptr(live, arg)) { - DBG((si->dbg, LEVEL_3, "\t arg %+F is possibly live in epilog of %+F\n", arg, irn)); - - /* post_use >= next_lr + remat */ - ir_snprintf(buf, sizeof(buf), "post_use_%N_%N-%d", arg, irn, p++); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, post_use, -1.0); - lpp_set_factor_fast(si->lpp, cst, arg_op->attr.live_range.ilp, 1.0); - } - - /* forall post remat which use arg add a similar cst */ - foreach_post_remat(irn, remat) { - int n; - - for (n=get_irn_arity(remat)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(remat, n); - op_t *remat_op = get_irn_link(remat); - - if(remat_arg == arg) { - DBG((si->dbg, LEVEL_3, "\t found remat with arg %+F in epilog of %+F\n", arg, irn)); - - /* post_use >= remat */ - ir_snprintf(buf, sizeof(buf), "post_use_%N_%N-%d", arg, irn, p++); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, post_use, -1.0); - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - } - } - } - - /* if value is not an arg of op and not possibly defined by post remat - * then it may only die and not become live - */ - if(!set_find_keyval(args, arg)) { - /* post_use <= prev_lr */ - ir_snprintf(buf, sizeof(buf), "req_post_use_%N_%N", arg, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, post_use, 1.0); - lpp_set_factor_fast(si->lpp, cst, prev_lr, -1.0); - - if(!pset_find_ptr(remat_defs, arg) && pset_find_ptr(live, arg)) { - /* next_lr <= prev_lr */ - ir_snprintf(buf, sizeof(buf), "next_lr_%N_%N", arg, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, arg_op->attr.live_range.ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, prev_lr, -1.0); - } - } - - if(opt_memoperands && (!is_start_block(bb) || be_is_Barrier(irn))) { - for(n = get_irn_arity(irn)-1; n>=0; --n) { - if (get_irn_n(irn, n) == arg && - arch_possible_memory_operand(irn, n)) { - ilp_var_t memoperand; - - ir_snprintf(buf, sizeof(buf), "memoperand_%N_%d", irn, n); - memoperand = lpp_add_var_default(si->lpp, buf, lpp_binary, opt_cost_memoperand*execution_frequency(si, bb), 0.0); - set_insert_memoperand(si->memoperands, irn, n, memoperand); - - ir_snprintf(buf, sizeof(buf), "nolivepost_%N_%d", irn, n); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1.0); - - lpp_set_factor_fast(si->lpp, cst, memoperand, 1.0); - lpp_set_factor_fast(si->lpp, cst, post_use, 1.0); - } - } - } - - /* new live range begins for each used value */ - arg_op->attr.live_range.ilp = prev_lr; - arg_op->attr.live_range.op = irn; - - pset_insert_ptr(live, arg); - } - - /* just to be sure */ - check_post = ILP_UNDEF; - - /* allow original defintions to be removed */ - if(opt_repair_schedule) { - pset_foreach(defs, tmp) { - op_t *tmp_op = get_irn_link(tmp); - spill_t *spill = set_find_spill(spill_bb->ilp, tmp); -#if 1 - ilp_var_t delete; - assert(spill); - - ir_snprintf(buf, sizeof(buf), "delete_%N", tmp); - delete = lpp_add_var_default(si->lpp, buf, lpp_binary, -1.0 * get_cost(irn) * execution_frequency(si, bb), 0.0); - - /* op may not be killed if its first live_range is 1 */ - ir_snprintf(buf, sizeof(buf), "killorig-lr_%N", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1.0); - lpp_set_factor_fast(si->lpp, cst, delete, 1.0); - lpp_set_factor_fast(si->lpp, cst, tmp_op->attr.live_range.ilp, 1.0); - - /* op may not be killed if it is spilled after the definition */ - ir_snprintf(buf, sizeof(buf), "killorig-spill_%N", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1.0); - lpp_set_factor_fast(si->lpp, cst, delete, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->spill, 1.0); -#else - ilp_var_t keep; - assert(spill); - - ir_snprintf(buf, sizeof(buf), "keep_%N", tmp); - keep = lpp_add_var_default(si->lpp, buf, lpp_binary, get_cost(irn) * execution_frequency(si, bb), 1.0); - - /* op may not be killed if its first live_range is 1 */ - ir_snprintf(buf, sizeof(buf), "killorig-lr_%N", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_greater, 0.0); - lpp_set_factor_fast(si->lpp, cst, keep, 1.0); - lpp_set_factor_fast(si->lpp, cst, tmp_op->attr.live_range.ilp, -1.0); - - /* op may not be killed if it is spilled after the definition */ - ir_snprintf(buf, sizeof(buf), "killorig-spill_%N", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_greater, 0.0); - lpp_set_factor_fast(si->lpp, cst, keep, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->spill, -1.0); -#endif - } - } else { -#if 0 - pset_foreach(defs, tmp) { - op_t *tmp_op = get_irn_link(tmp); - spill_t *spill = set_find_spill(spill_bb->ilp, tmp); - assert(spill); - - /* live_range or spill should be 1 - TODO: lr should be live until first use */ - ir_snprintf(buf, sizeof(buf), "nokillorig_%N", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_greater, 1.0); - lpp_set_factor_fast(si->lpp, cst, tmp_op->attr.live_range.ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->spill, 1.0); - } -#endif - } - - - /****************** - * P R O L O G - ******************/ - - /* check the register pressure in the prolog */ - /* sum_{L\U} lr <= k - |U| */ - ir_snprintf(buf, sizeof(buf), "check_pre_%N", irn); - check_pre = lpp_add_cst_uniq(si->lpp, buf, lpp_less, si->n_regs - u); - - /* for the prolog remove defined values from the live set */ - pset_foreach(defs, tmp) { - pset_remove_ptr(live, tmp); - } - - if(opt_memoperands && (!is_start_block(bb) || be_is_Barrier(irn))) { - ir_snprintf(buf, sizeof(buf), "one_memoperand_%N", irn); - one_memoperand = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1.0); - } - - /*********************************************************** - * I T E R A T I O N O V E R A R G S F O R P R O L O G - **********************************************************/ - - - set_foreach(args, keyval) { - spill_t *spill; - const ir_node *arg = keyval->key; - int i = PTR_TO_INT(keyval->val); - op_t *arg_op = get_irn_link(arg); - ilp_cst_t requirements; - int n_memoperands; - - spill = set_find_spill(spill_bb->ilp, arg); - assert(spill); - - ir_snprintf(buf, sizeof(buf), "reload_%N_%N", arg, irn); - op->attr.live_range.args.reloads[i] = lpp_add_var_default(si->lpp, buf, lpp_binary, opt_cost_reload*execution_frequency(si, bb), 1.0); - - /* reload <= mem_out */ - ir_snprintf(buf, sizeof(buf), "req_reload_%N_%N", arg, irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.args.reloads[i], 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->mem_out, -1.0); - - /* requirement: arg must be in register for use */ - /* reload + remat + live_range == 1 */ - ir_snprintf(buf, sizeof(buf), "req_%N_%N", irn, arg); - requirements = lpp_add_cst_uniq(si->lpp, buf, lpp_equal, 1.0); - - lpp_set_factor_fast(si->lpp, requirements, arg_op->attr.live_range.ilp, 1.0); - lpp_set_factor_fast(si->lpp, requirements, op->attr.live_range.args.reloads[i], 1.0); - foreach_pre_remat(irn, tmp) { - op_t *remat_op = get_irn_link(tmp); - if(remat_op->attr.remat.remat->value == arg) { - lpp_set_factor_fast(si->lpp, requirements, remat_op->attr.remat.ilp, 1.0); - } - } - - if(opt_memoperands && (!is_start_block(bb) || be_is_Barrier(irn))) { - n_memoperands = 0; - for(n = get_irn_arity(irn)-1; n>=0; --n) { - if(get_irn_n(irn, n) == arg) { - n_memoperands++; - } - } - for(n = get_irn_arity(irn)-1; n>=0; --n) { - if (get_irn_n(irn, n) == arg && - arch_possible_memory_operand(irn, n)) { - memoperand_t *memoperand; - memoperand = set_find_memoperand(si->memoperands, irn, n); - - /* memoperand <= mem_out */ - ir_snprintf(buf, sizeof(buf), "req_memoperand_%N_%d", irn, n); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, memoperand->ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->mem_out, -1.0); - - /* the memoperand is only sufficient if it is used once by the op */ - if(n_memoperands == 1) - lpp_set_factor_fast(si->lpp, requirements, memoperand->ilp, 1.0); - - lpp_set_factor_fast(si->lpp, one_memoperand, memoperand->ilp, 1.0); - - /* we have one more free register if we use a memory operand */ - lpp_set_factor_fast(si->lpp, check_pre, memoperand->ilp, -1.0); - } - } - } - } - - /* iterate over L\U */ - pset_foreach(live, tmp) { - if(!set_find_keyval(args, tmp)) { - /* if a live value is not used by irn */ - tmp_op = get_irn_link(tmp); - lpp_set_factor_fast(si->lpp, check_pre, tmp_op->attr.live_range.ilp, 1.0); - } - } - - /* requirements for remats */ - foreach_pre_remat(irn, tmp) { - op_t *remat_op = get_irn_link(tmp); - int n; - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - op_t *arg_op = get_irn_link(remat_arg); - - if(!has_reg_class(si, remat_arg)) continue; - - /* remat <= live_rang(remat_arg) [ + reload(remat_arg) ] */ - ir_snprintf(buf, sizeof(buf), "req_remat_%N_arg_%N", tmp, remat_arg); - cst = lpp_add_cst(si->lpp, buf, lpp_less, 0.0); - - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, arg_op->attr.live_range.ilp, -1.0); - - /* if remat arg is also used by current op then we can use reload placed for this argument */ - if((keyval = set_find_keyval(args, remat_arg)) != NULL) { - int index = (int)keyval->val; - - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.args.reloads[index], -1.0); - } - } - } - - - - - /************************* - * D O N E W I T H O P - *************************/ - - DBG((si->dbg, LEVEL_4, "\t %d values live at %+F\n", pset_count(live), irn)); - - pset_foreach(live, tmp) { - assert(has_reg_class(si, tmp)); - } - -#ifndef NDEBUG - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *arg = get_irn_n(irn, n); - - assert(!find_post_remat(arg, irn) && "there should be no post remat for an argument of an op"); - } -#endif - - del_pset(remat_defs); - del_pset(used); - del_set(args); - del_pset(defs); - defs = pset_new_ptr_default(); - - /* skip everything above barrier in start block */ - if(is_start_block(bb) && be_is_Barrier(irn)) { - assert(pset_count(live) == 0); - break; - } - - } - del_pset(defs); - - - - /*************************************** - * B E G I N N I N G O F B L O C K - ***************************************/ - - - /* we are now at the beginning of the basic block, there are only \Phis in front of us */ - DBG((si->dbg, LEVEL_3, "\t %d values live at beginning of block %+F\n", pset_count(live), bb)); - - pset_foreach(live, irn) { - assert(is_Phi(irn) || get_nodes_block(irn) != bb); - } - - /* construct mem_outs for all values */ - set_foreach(spill_bb->ilp, spill) { - ir_snprintf(buf, sizeof(buf), "mem_out_%N_%N", spill->irn, bb); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - lpp_set_factor_fast(si->lpp, cst, spill->mem_out, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->spill, -1.0); - - if(pset_find_ptr(live, spill->irn)) { - int default_spilled; - DBG((si->dbg, LEVEL_5, "\t %+F live at beginning of block %+F\n", spill->irn, bb)); - - ir_snprintf(buf, sizeof(buf), "mem_in_%N_%N", spill->irn, bb); - default_spilled = be_is_live_in(si->lv, bb, spill->irn) || is_Phi(spill->irn); - spill->mem_in = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, default_spilled); - lpp_set_factor_fast(si->lpp, cst, spill->mem_in, -1.0); - - if(opt_memcopies && is_Phi(spill->irn) && get_nodes_block(spill->irn) == bb) { - int n; - op_t *op = get_irn_link(spill->irn); - - for(n=get_irn_arity(spill->irn)-1; n>=0; --n) { - const ir_node *arg = get_irn_n(spill->irn, n); - double freq=0.0; - int m; - ilp_var_t var; - - - /* argument already done? */ - if(op->attr.live_range.args.copies[n] != ILP_UNDEF) continue; - - /* get sum of execution frequencies of blocks with the same phi argument */ - for(m=n; m>=0; --m) { - const ir_node *arg2 = get_irn_n(spill->irn, m); - - if(arg==arg2) { - freq += execution_frequency(si, get_Block_cfgpred_block(bb, m)); - } - } - - /* copies are not for free */ - ir_snprintf(buf, sizeof(buf), "copy_%N_%N", arg, spill->irn); - var = lpp_add_var_default(si->lpp, buf, lpp_binary, opt_cost_spill * freq, 1.0); - - for(m=n; m>=0; --m) { - const ir_node *arg2 = get_irn_n(spill->irn, m); - - if(arg==arg2) { - op->attr.live_range.args.copies[m] = var; - } - } - -#if 0 - /* copy <= mem_in */ - ir_snprintf(buf, sizeof(buf), "nocopy_%N_%N", arg, spill->irn); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, var, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->mem_in, -1.0); -#endif - } - } - } - } - - foreach_post_remat(bb, tmp) { - int n; - op_t *remat_op = get_irn_link(tmp); - pset *remat_args = pset_new_ptr(get_irn_arity(tmp)); - ir_node *remat_arg; - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - remat_arg = get_irn_n(tmp, n); - - if(has_reg_class(si, remat_arg)) { - pset_insert_ptr(remat_args, remat_arg); - } - } - - /* remat + \sum live_range(remat_arg) <= |args| */ - ir_snprintf(buf, sizeof(buf), "one_must_die_%N", tmp); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, pset_count(remat_args)); - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - - pset_foreach(remat_args, remat_arg) { - if(pset_find_ptr(live, remat_arg)) { - op_t *remat_arg_op = get_irn_link(remat_arg); - lpp_set_factor_fast(si->lpp, cst, remat_arg_op->attr.live_range.ilp, 1.0); - } - } - del_pset(remat_args); - } - - foreach_post_remat(bb, tmp) { - int n; - - for(n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - - /* if value is becoming live through use by remat2 */ - if(has_reg_class(si, remat_arg) && !pset_find_ptr(live, remat_arg)) { - op_t *remat_arg_op = get_irn_link(remat_arg); - ilp_cst_t nomem; - - DBG((si->dbg, LEVEL_3, " value %+F becoming live through use by remat2 at bb start %+F\n", remat_arg, tmp)); - - pset_insert_ptr(live, remat_arg); - spill = add_to_spill_bb(si, bb, remat_arg); - remat_arg_op->attr.live_range.ilp = ILP_UNDEF; - - /* we need reg_in and mem_in for this value; they will be referenced later */ - ir_snprintf(buf, sizeof(buf), "reg_in_%N_%N", remat_arg, bb); - spill->reg_in = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - ir_snprintf(buf, sizeof(buf), "mem_in_%N_%N", remat_arg, bb); - spill->mem_in = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - - /* optimization: all memory stuff should be 0, for we do not want to insert reloads for remats */ - ir_snprintf(buf, sizeof(buf), "nomem_%N_%N", remat_arg, bb); - nomem = lpp_add_cst_uniq(si->lpp, buf, lpp_equal, 0.0); - lpp_set_factor_fast(si->lpp, nomem, spill->spill, 1.0); - } - } - } - - /* L\U is empty at bb start */ - /* arg is live throughout epilog if it is reg_in into this block */ - - /* check the register pressure at the beginning of the block - * including remats - */ - /* reg_in entspricht post_use */ - - ir_snprintf(buf, sizeof(buf), "check_start_%N", bb); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, si->n_regs); - - pset_foreach(live, irn) { - ilp_cst_t nospill; - - spill = set_find_spill(spill_bb->ilp, irn); - assert(spill); - - ir_snprintf(buf, sizeof(buf), "reg_in_%N_%N", irn, bb); - spill->reg_in = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 0.0); - - lpp_set_factor_fast(si->lpp, cst, spill->reg_in, 1.0); - - /* spill + mem_in <= 1 */ - ir_snprintf(buf, sizeof(buf), "nospill_%N_%N", irn, bb); - nospill = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1); - - lpp_set_factor_fast(si->lpp, nospill, spill->mem_in, 1.0); - lpp_set_factor_fast(si->lpp, nospill, spill->spill, 1.0); - - } /* post_remats are NOT included in register pressure check because - they do not increase regpressure */ - - /* mem_in/reg_in for live_in values, especially phis and their arguments */ - pset_foreach(live, irn) { - int p = 0, - n; - - spill = set_find_spill(spill_bb->ilp, irn); - assert(spill && spill->irn == irn); - - if(is_Phi(irn) && get_nodes_block(irn) == bb) { - for (n=get_Phi_n_preds(irn)-1; n>=0; --n) { - ilp_cst_t mem_in, - reg_in; - ir_node *phi_arg = get_Phi_pred(irn, n); - ir_node *bb_p = get_Block_cfgpred_block(bb, n); - spill_bb_t *spill_bb_p = get_irn_link(bb_p); - spill_t *spill_p; - op_t *op = get_irn_link(irn); - - /* although the phi is in the right regclass one or more of - * its arguments can be in a different one or at least to - * ignore - */ - if(has_reg_class(si, phi_arg)) { - /* mem_in < mem_out_arg + copy */ - ir_snprintf(buf, sizeof(buf), "mem_in_%N_%N-%d", irn, bb, p); - mem_in = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - /* reg_in < reg_out_arg */ - ir_snprintf(buf, sizeof(buf), "reg_in_%N_%N-%d", irn, bb, p++); - reg_in = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - lpp_set_factor_fast(si->lpp, mem_in, spill->mem_in, 1.0); - lpp_set_factor_fast(si->lpp, reg_in, spill->reg_in, 1.0); - - spill_p = set_find_spill(spill_bb_p->ilp, phi_arg); - assert(spill_p); - - lpp_set_factor_fast(si->lpp, mem_in, spill_p->mem_out, -1.0); - if(opt_memcopies) - lpp_set_factor_fast(si->lpp, mem_in, op->attr.live_range.args.copies[n], -1.0); - - lpp_set_factor_fast(si->lpp, reg_in, spill_p->reg_out, -1.0); - } - } - } else { - /* else assure the value arrives on all paths in the same resource */ - - for (n=get_Block_n_cfgpreds(bb)-1; n>=0; --n) { - ilp_cst_t mem_in, - reg_in; - ir_node *bb_p = get_Block_cfgpred_block(bb, n); - spill_bb_t *spill_bb_p = get_irn_link(bb_p); - spill_t *spill_p; - - ir_snprintf(buf, sizeof(buf), "mem_in_%N_%N-%d", irn, bb, p); - mem_in = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - ir_snprintf(buf, sizeof(buf), "reg_in_%N_%N-%d", irn, bb, p++); - reg_in = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - lpp_set_factor_fast(si->lpp, mem_in, spill->mem_in, 1.0); - lpp_set_factor_fast(si->lpp, reg_in, spill->reg_in, 1.0); - - spill_p = set_find_spill(spill_bb_p->ilp, irn); - assert(spill_p); - - lpp_set_factor_fast(si->lpp, mem_in, spill_p->mem_out, -1.0); - lpp_set_factor_fast(si->lpp, reg_in, spill_p->reg_out, -1.0); - } - } - } - - foreach_post_remat(bb, tmp) { - int n; - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *remat_arg = get_irn_n(tmp, n); - op_t *remat_op = get_irn_link(tmp); - - if(!has_reg_class(si, remat_arg)) continue; - - spill = set_find_spill(spill_bb->ilp, remat_arg); - assert(spill); - - ir_snprintf(buf, sizeof(buf), "req_remat2_%N_%N_arg_%N", tmp, bb, remat_arg); - cst = lpp_add_cst(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, spill->reg_in, -1.0); - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - } - } - - pset_foreach(live, irn) { - const op_t *op = get_irn_link(irn); - const ir_node *remat; - int n_remats = 0; - - cst = ILP_UNDEF; - - foreach_post_remat(bb, remat) { - int n; - - for (n=get_irn_arity(remat)-1; n>=0; --n) { - const ir_node *arg = get_irn_n(remat, n); - - if(arg == irn) { - const op_t *remat_op = get_irn_link(remat); - - if(cst == ILP_UNDEF) { - /* sum remat2s <= 1 + n_remats*live_range */ - ir_snprintf(buf, sizeof(buf), "dying_lr_%N_%N", irn, bb); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1.0); - } - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, 1.0); - ++n_remats; - break; - } - } - } - if(cst != ILP_UNDEF && op->attr.live_range.ilp != ILP_UNDEF) { - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.ilp, -n_remats); - } - } - - /* first live ranges from reg_ins */ - pset_foreach(live, irn) { - op_t *op = get_irn_link(irn); - - if(op->attr.live_range.ilp != ILP_UNDEF) { - - spill = set_find_spill(spill_bb->ilp, irn); - assert(spill && spill->irn == irn); - - ir_snprintf(buf, sizeof(buf), "first_lr_%N_%N", irn, bb); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - lpp_set_factor_fast(si->lpp, cst, op->attr.live_range.ilp, 1.0); - lpp_set_factor_fast(si->lpp, cst, spill->reg_in, -1.0); - - foreach_post_remat(bb, tmp) { - op_t *remat_op = get_irn_link(tmp); - - if(remat_op->attr.remat.remat->value == irn) { - lpp_set_factor_fast(si->lpp, cst, remat_op->attr.remat.ilp, -1.0); - } - } - } - } - - /* walk forward now and compute constraints for placing spills */ - /* this must only be done for values that are not defined in this block */ - pset_foreach(live, irn) { - /* - * if value is defined in this block we can anways place the spill directly after the def - * -> no constraint necessary - */ - if(!is_Phi(irn) && get_nodes_block(irn) == bb) { - assert(0); - } - - - spill = set_find_spill(spill_bb->ilp, irn); - assert(spill); - - ir_snprintf(buf, sizeof(buf), "req_spill_%N_%N", irn, bb); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0.0); - - lpp_set_factor_fast(si->lpp, cst, spill->spill, 1.0); - if(is_diverge_edge(bb)) lpp_set_factor_fast(si->lpp, cst, spill->reg_in, -1.0); - - if(!is_Phi(irn)) { - sched_foreach_op(bb, tmp) { - op_t *op = get_irn_link(tmp); - - if(is_Phi(tmp)) continue; - assert(!is_Proj(tmp)); - - if(op->is_remat) { - const ir_node *value = op->attr.remat.remat->value; - - if(value == irn) { - /* only collect remats up to the first real use of a value */ - lpp_set_factor_fast(si->lpp, cst, op->attr.remat.ilp, -1.0); - } - } else { - int n; - - for (n=get_irn_arity(tmp)-1; n>=0; --n) { - ir_node *arg = get_irn_n(tmp, n); - - if(arg == irn) { - /* if a value is used stop collecting remats */ - goto next_live; - } - } - } - } - } -next_live: ; - } - - del_pset(live); -} - -typedef struct _irnlist_t { - struct list_head list; - ir_node *irn; -} irnlist_t; - -typedef struct _interference_t { - struct list_head blocklist; - ir_node *a; - ir_node *b; -} interference_t; - -static int -cmp_interference(const void *a, const void *b, size_t size) -{ - const interference_t *p = a; - const interference_t *q = b; - (void) size; - - return !(p->a == q->a && p->b == q->b); -} - -static interference_t * -set_find_interference(set * set, ir_node * a, ir_node * b) -{ - interference_t query; - - query.a = (a>b)?a:b; - query.b = (a>b)?b:a; - - return set_find(set, &query, sizeof(query), HASH_PTR(PTR_TO_INT(a) ^ PTR_TO_INT(b))); -} - -static interference_t * -set_insert_interference(spill_ilp_t * si, set * set, ir_node * a, ir_node * b, ir_node * bb) -{ - interference_t query, - *result; - irnlist_t *list = obstack_alloc(si->obst, sizeof(*list)); - - list->irn = bb; - - result = set_find_interference(set, a, b); - if(result) { - - list_add(&list->list, &result->blocklist); - return result; - } - - query.a = (a>b)?a:b; - query.b = (a>b)?b:a; - - result = set_insert(set, &query, sizeof(query), HASH_PTR(PTR_TO_INT(a) ^ PTR_TO_INT(b))); - - INIT_LIST_HEAD(&result->blocklist); - list_add(&list->list, &result->blocklist); - - return result; -} - -static -int values_interfere_in_block(const spill_ilp_t *si, const ir_node *bb, const ir_node *a, const ir_node *b) -{ - const ir_edge_t *edge; - - if (get_nodes_block(a) != bb && get_nodes_block(b) != bb) { - /* both values are live in, so they interfere */ - return 1; - } - - /* ensure a dominates b */ - if (value_dominates(b, a)) { - const ir_node *t; - t = b; - b = a; - a = t; - } - assert(get_nodes_block(b) == bb && "at least b should be defined here in this block"); - - - /* the following code is stolen from bera.c */ - if (be_is_live_end(si->lv, bb, a)) - return 1; - - foreach_out_edge(a, edge) { - const ir_node *user = edge->src; - if (get_nodes_block(user) == bb - && ! is_Phi(user) - && b != user - && ! pset_find_ptr(si->inverse_ops, user) - && value_dominates(b, user)) - return 1; - } - - return 0; -} - -/** - * Walk all irg blocks and collect interfering values inside of phi classes - */ -static void -luke_interferencewalker(ir_node * bb, void * data) -{ - spill_ilp_t *si = (spill_ilp_t*)data; - int l1, l2; - - be_lv_foreach(si->lv, bb, be_lv_state_end | be_lv_state_out | be_lv_state_in, l1) { - ir_node *a = be_lv_get_irn(si->lv, bb, l1); - op_t *a_op = get_irn_link(a); - - - /* a is only interesting if it is in my register class and if it is inside a phi class */ - if (has_reg_class(si, a) && get_phi_class(si->pc, a)) { - if (a_op->is_remat || pset_find_ptr(si->inverse_ops, a)) - continue; - - for (l2 = _be_lv_next_irn(si->lv, bb, 0xff, l1 + 1); l2 >= 0; l2 = _be_lv_next_irn(si->lv, bb, 0xff, l2 + 1)) { - ir_node *b = be_lv_get_irn(si->lv, bb, l2); - op_t *b_op = get_irn_link(b); - - /* a and b are only interesting if they are in the same phi class */ - if (has_reg_class(si, b) && get_phi_class(si->pc, a) == get_phi_class(si->pc, b)) { - if (b_op->is_remat || pset_find_ptr(si->inverse_ops, b)) - continue; - - if (values_interfere_in_block(si, bb, a, b)) { - DBG((si->dbg, LEVEL_4, "\tvalues interfere in %+F: %+F, %+F\n", bb, a, b)); - set_insert_interference(si, si->interferences, a, b, bb); - } - } - } - } - } -} - -static unsigned int copy_path_id = 0; - -static void -write_copy_path_cst(spill_ilp_t *si, pset * copies, ilp_var_t any_interfere) -{ - ilp_cst_t cst; - ilp_var_t copy; - char buf[256]; - void *ptr; - - ir_snprintf(buf, sizeof(buf), "copy_path-%d", copy_path_id++); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0); - - lpp_set_factor_fast(si->lpp, cst, any_interfere, 1.0); - - pset_foreach(copies, ptr) { - copy = PTR_TO_INT(ptr); - lpp_set_factor_fast(si->lpp, cst, copy, -1.0); - } -} - -/** - * @parameter copies contains a path of copies which lead us to irn - * @parameter visited contains a set of nodes already visited on this path - */ -static int -find_copy_path(spill_ilp_t * si, const ir_node * irn, const ir_node * target, ilp_var_t any_interfere, pset * copies, pset * visited) -{ - const ir_edge_t *edge; - op_t *op = get_irn_link(irn); - pset *visited_users = pset_new_ptr_default(); - int paths = 0; - - if(op->is_remat) return 0; - - pset_insert_ptr(visited, irn); - - if(is_Phi(irn)) { - int n; - pset *visited_operands = pset_new_ptr(get_irn_arity(irn)); - - /* visit all operands */ - for(n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *arg = get_irn_n(irn, n); - ilp_var_t copy = op->attr.live_range.args.copies[n]; - - if(!has_reg_class(si, arg)) continue; - if(pset_find_ptr(visited_operands, arg)) continue; - pset_insert_ptr(visited_operands, arg); - - if(arg == target) { - if(++paths > MAX_PATHS && pset_count(copies) != 0) { - del_pset(visited_operands); - del_pset(visited_users); - pset_remove_ptr(visited, irn); - return paths; - } - pset_insert(copies, INT_TO_PTR(copy), copy); - write_copy_path_cst(si, copies, any_interfere); - pset_remove(copies, INT_TO_PTR(copy), copy); - } else if(!pset_find_ptr(visited, arg)) { - pset_insert(copies, INT_TO_PTR(copy), copy); - paths += find_copy_path(si, arg, target, any_interfere, copies, visited); - pset_remove(copies, INT_TO_PTR(copy), copy); - - if(paths > MAX_PATHS) { - if(pset_count(copies) == 0) { - ilp_cst_t cst; - char buf[256]; - - ir_snprintf(buf, sizeof(buf), "always_copy-%d-%d", any_interfere, copy); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_equal, 0); - lpp_set_factor_fast(si->lpp, cst, any_interfere, -1.0); - lpp_set_factor_fast(si->lpp, cst, copy, 1.0); - DBG((si->dbg, LEVEL_1, "ALWAYS COPYING %d FOR INTERFERENCE %d\n", copy, any_interfere)); - - paths = 0; - } else { - del_pset(visited_operands); - del_pset(visited_users); - pset_remove_ptr(visited, irn); - return paths; - } - } else if(pset_count(copies) == 0) { - paths = 0; - } - } - } - - del_pset(visited_operands); - } - - /* visit all uses which are phis */ - foreach_out_edge(irn, edge) { - ir_node *user = edge->src; - int pos = edge->pos; - op_t *op = get_irn_link(user); - ilp_var_t copy; - - if(!is_Phi(user)) continue; - if(!has_reg_class(si, user)) continue; - if(pset_find_ptr(visited_users, user)) continue; - pset_insert_ptr(visited_users, user); - - copy = op->attr.live_range.args.copies[pos]; - - if(user == target) { - if(++paths > MAX_PATHS && pset_count(copies) != 0) { - del_pset(visited_users); - pset_remove_ptr(visited, irn); - return paths; - } - pset_insert(copies, INT_TO_PTR(copy), copy); - write_copy_path_cst(si, copies, any_interfere); - pset_remove(copies, INT_TO_PTR(copy), copy); - } else if(!pset_find_ptr(visited, user)) { - pset_insert(copies, INT_TO_PTR(copy), copy); - paths += find_copy_path(si, user, target, any_interfere, copies, visited); - pset_remove(copies, INT_TO_PTR(copy), copy); - - if(paths > MAX_PATHS) { - if(pset_count(copies) == 0) { - ilp_cst_t cst; - char buf[256]; - - ir_snprintf(buf, sizeof(buf), "always_copy-%d-%d", any_interfere, copy); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_equal, 0); - lpp_set_factor_fast(si->lpp, cst, any_interfere, -1.0); - lpp_set_factor_fast(si->lpp, cst, copy, 1.0); - DBG((si->dbg, LEVEL_1, "ALWAYS COPYING %d FOR INTERFERENCE %d\n", copy, any_interfere)); - - paths = 0; - } else { - del_pset(visited_users); - pset_remove_ptr(visited, irn); - return paths; - } - } else if(pset_count(copies) == 0) { - paths = 0; - } - } - } - - del_pset(visited_users); - pset_remove_ptr(visited, irn); - return paths; -} - -static void -gen_copy_constraints(spill_ilp_t * si, const ir_node * a, const ir_node * b, ilp_var_t any_interfere) -{ - pset * copies = pset_new_ptr_default(); - pset * visited = pset_new_ptr_default(); - - find_copy_path(si, a, b, any_interfere, copies, visited); - - del_pset(visited); - del_pset(copies); -} - - -static void -memcopyhandler(spill_ilp_t * si) -{ - interference_t *interference; - char buf[256]; - /* teste Speicherwerte auf Interferenz */ - - DBG((si->dbg, LEVEL_2, "\t calling interferencewalker\n")); - irg_block_walk_graph(si->birg->irg, luke_interferencewalker, NULL, si); - - /* now lets emit the ILP unequations for the crap */ - set_foreach(si->interferences, interference) { - irnlist_t *irnlist; - ilp_var_t interfere, any_interfere; - ilp_cst_t any_interfere_cst, cst; - const ir_node *a = interference->a; - const ir_node *b = interference->b; - - /* any_interf <= \sum interf */ - ir_snprintf(buf, sizeof(buf), "interfere_%N_%N", a, b); - any_interfere_cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0); - any_interfere = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - lpp_set_factor_fast(si->lpp, any_interfere_cst, any_interfere, 1.0); - - list_for_each_entry(irnlist_t, irnlist, &interference->blocklist, list) { - const ir_node *bb = irnlist->irn; - spill_bb_t *spill_bb = get_irn_link(bb); - spill_t *spilla, - *spillb; - char buf[256]; - - spilla = set_find_spill(spill_bb->ilp, a); - assert(spilla); - - spillb = set_find_spill(spill_bb->ilp, b); - assert(spillb); - - /* interfere <-> (mem_in_a or spill_a) and (mem_in_b or spill_b): */ - /* 1: mem_in_a + mem_in_b + spill_a + spill_b - interfere <= 1 */ - /* 2: - mem_in_a - spill_a + interfere <= 0 */ - /* 3: - mem_in_b - spill_b + interfere <= 0 */ - ir_snprintf(buf, sizeof(buf), "interfere_%N_%N_%N", bb, a, b); - interfere = lpp_add_var_default(si->lpp, buf, lpp_binary, 0.0, 1.0); - - ir_snprintf(buf, sizeof(buf), "interfere_%N_%N_%N-1", bb, a, b); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 1); - - lpp_set_factor_fast(si->lpp, cst, interfere, -1.0); - if(spilla->mem_in != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, spilla->mem_in, 1.0); - lpp_set_factor_fast(si->lpp, cst, spilla->spill, 1.0); - if(spillb->mem_in != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, spillb->mem_in, 1.0); - lpp_set_factor_fast(si->lpp, cst, spillb->spill, 1.0); - - ir_snprintf(buf, sizeof(buf), "interfere_%N_%N_%N-2", bb, a, b); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0); - - lpp_set_factor_fast(si->lpp, cst, interfere, 1.0); - if(spilla->mem_in != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, spilla->mem_in, -1.0); - lpp_set_factor_fast(si->lpp, cst, spilla->spill, -1.0); - - ir_snprintf(buf, sizeof(buf), "interfere_%N_%N_%N-3", bb, a, b); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0); - - lpp_set_factor_fast(si->lpp, cst, interfere, 1.0); - if(spillb->mem_in != ILP_UNDEF) lpp_set_factor_fast(si->lpp, cst, spillb->mem_in, -1.0); - lpp_set_factor_fast(si->lpp, cst, spillb->spill, -1.0); - - - lpp_set_factor_fast(si->lpp, any_interfere_cst, interfere, -1.0); - - /* any_interfere >= interf */ - ir_snprintf(buf, sizeof(buf), "interfere_%N_%N-%N", a, b, bb); - cst = lpp_add_cst_uniq(si->lpp, buf, lpp_less, 0); - - lpp_set_factor_fast(si->lpp, cst, interfere, 1.0); - lpp_set_factor_fast(si->lpp, cst, any_interfere, -1.0); - } - - /* now that we know whether the two values interfere in memory we can drop constraints to enforce copies */ - gen_copy_constraints(si,a,b,any_interfere); - } -} - - -static inline int -is_zero(double x) -{ - return fabs(x) < 0.00001; -} - -/** - * node attribute hook for changing colors - */ -static int mark_remat_nodes_hook(FILE *F, ir_node *n, ir_node *l) -{ - spill_ilp_t *si = get_irg_link(current_ir_graph); - (void) l; - - if(pset_find_ptr(si->all_possible_remats, n)) { - op_t *op = (op_t*)get_irn_link(n); - assert(op && op->is_remat); - - if(!op->attr.remat.remat->inverse) { - if(op->attr.remat.pre) { - ir_fprintf(F, "color:red info3:\"remat value: %+F\"", op->attr.remat.remat->value); - } else { - ir_fprintf(F, "color:orange info3:\"remat2 value: %+F\"", op->attr.remat.remat->value); - } - - return 1; - } else { - op_t *op = (op_t*)get_irn_link(n); - assert(op && op->is_remat); - - if(op->attr.remat.pre) { - ir_fprintf(F, "color:cyan info3:\"remat inverse value: %+F\"", op->attr.remat.remat->value); - } else { - ir_fprintf(F, "color:lightcyan info3:\"remat2 inverse value: %+F\"", op->attr.remat.remat->value); - } - - return 1; - } - } - - return 0; -} - -static void -dump_graph_with_remats(ir_graph * irg, const char * suffix) -{ - set_dump_node_vcgattr_hook(mark_remat_nodes_hook); - be_dump(irg, suffix, dump_ir_block_graph_sched); - set_dump_node_vcgattr_hook(NULL); -} - -/** - * Edge hook to dump the schedule edges with annotated register pressure. - */ -static int -sched_pressure_edge_hook(FILE *F, ir_node *irn) -{ - if(sched_is_scheduled(irn) && sched_has_prev(irn)) { - ir_node *prev = sched_prev(irn); - fprintf(F, "edge:{sourcename:\""); - PRINT_NODEID(irn); - fprintf(F, "\" targetname:\""); - PRINT_NODEID(prev); - fprintf(F, "\" label:\"%d", (int)get_irn_link(irn)); - fprintf(F, "\" color:magenta}\n"); - } - return 1; -} - -static void -dump_ir_block_graph_sched_pressure(ir_graph *irg, const char *suffix) -{ - DUMP_NODE_EDGE_FUNC old_edge_hook = get_dump_node_edge_hook(); - - dump_consts_local(0); - set_dump_node_edge_hook(sched_pressure_edge_hook); - dump_ir_block_graph(irg, suffix); - set_dump_node_edge_hook(old_edge_hook); -} - -static void -walker_pressure_annotator(ir_node * bb, void * data) -{ - spill_ilp_t *si = data; - ir_node *irn; - int n, i; - pset *live = pset_new_ptr_default(); - int projs = 0; - - be_lv_foreach(si->lv, bb, be_lv_state_end, i) { - irn = be_lv_get_irn(si->lv, bb, i); - - if (has_reg_class(si, irn)) { - pset_insert_ptr(live, irn); - } - } - - set_irn_link(bb, INT_TO_PTR(pset_count(live))); - - sched_foreach_reverse(bb, irn) { - if(is_Phi(irn)) { - set_irn_link(irn, INT_TO_PTR(pset_count(live))); - continue; - } - - if(has_reg_class(si, irn)) { - pset_remove_ptr(live, irn); - if(is_Proj(irn)) ++projs; - } - - if(!is_Proj(irn)) projs = 0; - - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *arg = get_irn_n(irn, n); - - if(has_reg_class(si, arg)) pset_insert_ptr(live, arg); - } - set_irn_link(irn, INT_TO_PTR(pset_count(live)+projs)); - } - - del_pset(live); -} - -static void -dump_pressure_graph(spill_ilp_t * si, const char *suffix) -{ - be_dump(si->birg->irg, suffix, dump_ir_block_graph_sched_pressure); -} - -static void -connect_all_remats_with_keep(spill_ilp_t * si) -{ - ir_node *irn; - ir_node **ins, - **pos; - int n_remats; - - - n_remats = pset_count(si->all_possible_remats); - if(n_remats) { - ins = obstack_alloc(si->obst, n_remats * sizeof(*ins)); - - pos = ins; - pset_foreach(si->all_possible_remats, irn) { - *pos = irn; - ++pos; - } - - si->keep = be_new_Keep(si->cls, si->birg->irg, get_irg_end_block(si->birg->irg), n_remats, ins); - - obstack_free(si->obst, ins); - } -} - -static void -connect_all_spills_with_keep(spill_ilp_t * si) -{ - ir_node *irn; - ir_node **ins, - **pos; - int n_spills; - ir_node *keep; - - - n_spills = pset_count(si->spills); - if(n_spills) { - ins = obstack_alloc(si->obst, n_spills * sizeof(*ins)); - - pos = ins; - pset_foreach(si->spills, irn) { - *pos = irn; - ++pos; - } - - keep = be_new_Keep(si->cls, si->birg->irg, get_irg_end_block(si->birg->irg), n_spills, ins); - - obstack_free(si->obst, ins); - } -} - -/** insert a spill at an arbitrary position */ -static ir_node *be_spill2(ir_node *irn, ir_node *insert) -{ - ir_node *bl = is_Block(insert) ? insert : get_nodes_block(insert); - ir_graph *irg = get_irn_irg(bl); - ir_node *frame = get_irg_frame(irg); - ir_node *spill; - ir_node *next; - const arch_register_class_t *cls = arch_get_irn_reg_class_out(irn); - const arch_register_class_t *cls_frame = arch_get_irn_reg_class_out(frame); - - spill = be_new_Spill(cls, cls_frame, irg, bl, frame, irn); - - /* - * search the right insertion point. a spill of a phi cannot be put - * directly after the phi, if there are some phis behind the one which - * is spilled. Also, a spill of a Proj must be after all Projs of the - * same tuple node. - * - * Here's one special case: - * If the spill is in the start block, the spill must be after the frame - * pointer is set up. This is done by setting insert to the end of the block - * which is its default initialization (see above). - */ - - if (bl == get_irg_start_block(irg) && sched_get_time_step(frame) >= sched_get_time_step(insert)) - insert = frame; - - for (next = sched_next(insert); is_Phi(next) || is_Proj(next); next = sched_next(insert)) - insert = next; - - sched_add_after(insert, spill); - return spill; -} - -static void -delete_remat(spill_ilp_t * si, ir_node * remat) { - int n; - ir_node *bad = get_irg_bad(si->birg->irg); - - sched_remove(remat); - - /* kill links to operands */ - for (n=get_irn_arity(remat)-1; n>=-1; --n) { - set_irn_n(remat, n, bad); - } -} - -static void -clean_remat_info(spill_ilp_t * si) -{ - int n; - remat_t *remat; - remat_info_t *remat_info; - ir_node *bad = get_irg_bad(si->birg->irg); - - set_foreach(si->remat_info, remat_info) { - if(!remat_info->remats) continue; - - pset_foreach(remat_info->remats, remat) - { - if(remat->proj && get_irn_n_edges(remat->proj) == 0) { - if(sched_is_scheduled(remat->proj)) { - sched_remove((ir_node*)remat->proj); - } - set_irn_n((ir_node*)remat->proj, -1, bad); - set_irn_n((ir_node*)remat->proj, 0, bad); - } - - if(get_irn_n_edges(remat->op) == 0) { - if(sched_is_scheduled(remat->op)) { - sched_remove((ir_node*)remat->op); - } - for (n=get_irn_arity(remat->op)-1; n>=-1; --n) { - set_irn_n((ir_node*)remat->op, n, bad); - } - } - } - - if(remat_info->remats) del_pset(remat_info->remats); - if(remat_info->remats_by_operand) del_pset(remat_info->remats_by_operand); - } -} - -static void -delete_unnecessary_remats(spill_ilp_t * si) -{ - if(opt_keep_alive & KEEPALIVE_REMATS) { - int n; - ir_node *bad = get_irg_bad(si->birg->irg); - - if(si->keep) { - for (n=get_irn_arity(si->keep)-1; n>=0; --n) { - ir_node *keep_arg = get_irn_n(si->keep, n); - op_t *arg_op = get_irn_link(keep_arg); - lpp_name_t *name; - - assert(arg_op->is_remat); - - name = si->lpp->vars[arg_op->attr.remat.ilp]; - - if(is_zero(name->value)) { - DBG((si->dbg, LEVEL_3, "\t deleting remat %+F\n", keep_arg)); - /* TODO check whether reload is preferred over remat (could be bug) */ - delete_remat(si, keep_arg); - } else { - if(!arg_op->attr.remat.remat->inverse) { - if(arg_op->attr.remat.pre) { - DBG((si->dbg, LEVEL_2, "\t**remat kept: %+F\n", keep_arg)); - } else { - DBG((si->dbg, LEVEL_2, "\t%%%%remat2 kept: %+F\n", keep_arg)); - } - } else { - if(arg_op->attr.remat.pre) { - DBG((si->dbg, LEVEL_2, "\t**INVERSE remat kept: %+F\n", keep_arg)); - } else { - DBG((si->dbg, LEVEL_2, "\t%%%%INVERSE remat2 kept: %+F\n", keep_arg)); - } - } - } - - set_irn_n(si->keep, n, bad); - } - } else { - DBG((si->dbg, LEVEL_2, "\t no remats to delete (none have been inserted)\n")); - } - } else { - ir_node *remat; - - pset_foreach(si->all_possible_remats, remat) { - op_t *remat_op = get_irn_link(remat); - lpp_name_t *name = si->lpp->vars[remat_op->attr.remat.ilp]; - - if(is_zero(name->value)) { - DBG((si->dbg, LEVEL_3, "\t deleting remat %+F\n", remat)); - /* TODO check whether reload is preferred over remat (could be bug) */ - delete_remat(si, remat); - } else { - if(!remat_op->attr.remat.remat->inverse) { - if(remat_op->attr.remat.pre) { - DBG((si->dbg, LEVEL_2, "\t**remat kept: %+F\n", remat)); - } else { - DBG((si->dbg, LEVEL_2, "\t%%%%remat2 kept: %+F\n", remat)); - } - } else { - if(remat_op->attr.remat.pre) { - DBG((si->dbg, LEVEL_2, "\t**INVERSE remat kept: %+F\n", remat)); - } else { - DBG((si->dbg, LEVEL_2, "\t%%%%INVERSE remat2 kept: %+F\n", remat)); - } - } - } - } - } -} - -static pset * -get_spills_for_value(spill_ilp_t * si, const ir_node * value) -{ - pset *spills = pset_new_ptr_default(); - - const ir_node *next; - defs_t *defs; - - defs = set_find_def(si->values, value); - - if(defs && defs->spills) { - for(next = defs->spills; next; next = get_irn_link(next)) { - pset_insert_ptr(spills, next); - } - } - - return spills; -} - -static ir_node * -new_r_PhiM_nokeep(ir_graph * irg, ir_node *block, int arity, ir_node **in) -{ - ir_node *res; - - assert( get_irn_arity(block) == arity ); - - res = new_ir_node(NULL, irg, block, op_Phi, mode_M, arity, in); - res->attr.phi.u.backedge = new_backedge_arr(irg->obst, arity); - - return res; -} - -/** - * @param before The node after which the spill will be placed in the schedule - */ -static ir_node * -insert_spill(spill_ilp_t * si, ir_node * irn, const ir_node * value, ir_node * before) -{ - defs_t *defs; - ir_node *spill; - - DBG((si->dbg, LEVEL_3, "\t inserting spill for value %+F after %+F\n", irn, before)); - - spill = be_spill2(irn, before); - - defs = set_insert_def(si->values, value); - assert(defs); - - /* enter into the linked list */ - set_irn_link(spill, defs->spills); - defs->spills = spill; - - if(opt_keep_alive & KEEPALIVE_SPILLS) - pset_insert_ptr(si->spills, spill); - - return spill; -} - -/** - * @param before The Phi node which has to be spilled - */ -static ir_node * -insert_mem_phi(spill_ilp_t * si, ir_node * phi) -{ - ir_node *mem_phi; - ir_node **ins; - defs_t *defs; - int n; - - NEW_ARR_A(ir_node*, ins, get_irn_arity(phi)); - - for(n=get_irn_arity(phi)-1; n>=0; --n) { - ins[n] = si->m_unknown; - } - - mem_phi = new_r_PhiM_nokeep(si->birg->irg, get_nodes_block(phi), get_irn_arity(phi), ins); - - defs = set_insert_def(si->values, phi); - assert(defs); - - /* enter into the linked list */ - set_irn_link(mem_phi, defs->spills); - defs->spills = mem_phi; - -#ifdef SCHEDULE_PHIM - sched_add_after(phi, mem_phi); -#else - pset_insert_ptr(si->phims, mem_phi); -#endif - - if(opt_keep_alive & KEEPALIVE_SPILLS) - pset_insert_ptr(si->spills, mem_phi); - - - return mem_phi; -} - -/** - * Add remat to list of defs, destroys link field! - */ -static void -insert_remat(spill_ilp_t * si, ir_node * remat) -{ - defs_t *defs; - op_t *remat_op = get_irn_link(remat); - - assert(remat_op->is_remat); - - defs = set_insert_def(si->values, remat_op->attr.remat.remat->value); - assert(defs); - - /* enter into the linked list */ - set_irn_link(remat, defs->remats); - defs->remats = remat; -} - - -/** - * Add reload before operation and add to list of defs - */ -static ir_node * -insert_reload(spill_ilp_t * si, const ir_node * value, ir_node * after) -{ - defs_t *defs; - ir_node *reload, - *spill; - - DBG((si->dbg, LEVEL_3, "\t inserting reload for value %+F before %+F\n", value, after)); - - defs = set_find_def(si->values, value); - - spill = defs->spills; - assert(spill && "no spill placed before reload"); - - reload = be_reload(si->cls, after, get_irn_mode(value), spill); - - /* enter into the linked list */ - set_irn_link(reload, defs->remats); - defs->remats = reload; - - return reload; -} - -void perform_memory_operand(spill_ilp_t * si, memoperand_t * memoperand) -{ - defs_t *defs; - ir_node *value = get_irn_n(memoperand->irn, memoperand->pos); - ir_node *spill; - - DBG((si->dbg, LEVEL_2, "\t inserting memory operand for value %+F at %+F\n", value, memoperand->irn)); - - defs = set_find_def(si->values, value); - - spill = defs->spills; - assert(spill && "no spill placed before reload"); - - arch_perform_memory_operand(memoperand->irn, spill, memoperand->pos); -} - -void insert_memoperands(spill_ilp_t * si) -{ - memoperand_t *memoperand; - lpp_name_t *name; - - set_foreach(si->memoperands, memoperand) { - name = si->lpp->vars[memoperand->ilp]; - if(!is_zero(name->value)) { - perform_memory_operand(si, memoperand); - } - } -} - -static void -walker_spill_placer(ir_node * bb, void * data) { - spill_ilp_t *si = (spill_ilp_t*)data; - ir_node *irn; - spill_bb_t *spill_bb = get_irn_link(bb); - pset *spills_to_do = pset_new_ptr_default(); - spill_t *spill; - - set_foreach(spill_bb->ilp, spill) { - lpp_name_t *name; - - if(is_Phi(spill->irn) && get_nodes_block(spill->irn) == bb) { - name = si->lpp->vars[spill->mem_in]; - if(!is_zero(name->value)) { - ir_node *mem_phi; - - mem_phi = insert_mem_phi(si, spill->irn); - - DBG((si->dbg, LEVEL_2, "\t >>spilled Phi %+F -> %+F\n", spill->irn, mem_phi)); - } - } - - name = si->lpp->vars[spill->spill]; - if(!is_zero(name->value)) { - /* place spill directly after definition */ - if(get_nodes_block(spill->irn) == bb) { - insert_spill(si, spill->irn, spill->irn, spill->irn); - continue; - } - - /* place spill at bb start */ - if(spill->reg_in > 0) { - name = si->lpp->vars[spill->reg_in]; - if(!is_zero(name->value)) { - insert_spill(si, spill->irn, spill->irn, bb); - continue; - } - } - /* place spill after a remat */ - pset_insert_ptr(spills_to_do, spill->irn); - } - } - DBG((si->dbg, LEVEL_3, "\t %d spills to do in block %+F\n", pset_count(spills_to_do), bb)); - - - for(irn = sched_block_first_nonphi(bb); !sched_is_end(irn); irn = sched_next(irn)) { - op_t *op = get_irn_link(irn); - - if(be_is_Spill(irn)) continue; - - if(op->is_remat) { - /* TODO fix this if we want to support remats with more than two nodes */ - if(get_irn_mode(irn) != mode_T && pset_find_ptr(spills_to_do, op->attr.remat.remat->value)) { - pset_remove_ptr(spills_to_do, op->attr.remat.remat->value); - - insert_spill(si, irn, op->attr.remat.remat->value, irn); - } - } else { - if(pset_find_ptr(spills_to_do, irn)) { - pset_remove_ptr(spills_to_do, irn); - - insert_spill(si, irn, irn, irn); - } - } - - } - - assert(pset_count(spills_to_do) == 0); - - /* afterwards free data in block */ - del_pset(spills_to_do); -} - -static ir_node * -insert_mem_copy(spill_ilp_t * si, ir_node * bb, ir_node * value) -{ - ir_node *insert_pos = bb; - ir_node *spill; - - /* find last definition of arg value in block */ - ir_node *next; - defs_t *defs; - int last = 0; - - defs = set_find_def(si->values, value); - - if(defs && defs->remats) { - for(next = defs->remats; next; next = get_irn_link(next)) { - if(get_nodes_block(next) == bb && sched_get_time_step(next) > last) { - last = sched_get_time_step(next); - insert_pos = next; - } - } - } - - if(get_nodes_block(value) == bb && sched_get_time_step(value) > last) { - last = sched_get_time_step(value); - insert_pos = value; - } - - DBG((si->dbg, LEVEL_2, "\t inserting mem copy for value %+F after %+F\n", value, insert_pos)); - - spill = be_spill2(is_Block(insert_pos)?value:insert_pos, insert_pos); - - return spill; -} - -static void -phim_fixer(spill_ilp_t *si) { - defs_t *defs; - - set_foreach(si->values, defs) { - const ir_node *phi = defs->value; - op_t *op = get_irn_link(phi); - ir_node *phi_m = NULL; - ir_node *next = defs->spills; - int n; - - if(!is_Phi(phi)) continue; - - while(next) { - if(is_Phi(next) && get_irn_mode(next) == mode_M) { - phi_m = next; - break; - } else { - next = get_irn_link(next); - } - } - if(!phi_m) continue; - - for(n=get_irn_arity(phi)-1; n>=0; --n) { - ir_node *value = get_irn_n(phi, n); - defs_t *val_defs = set_find_def(si->values, value); - - /* a spill of this value */ - ir_node *spill; - - - if(opt_memcopies) { - ir_node *pred = get_Block_cfgpred_block(get_nodes_block(phi), n); - lpp_name_t *name = si->lpp->vars[op->attr.live_range.args.copies[n]]; - - if(!is_zero(name->value)) { - spill = insert_mem_copy(si, pred, value); - } else { - spill = val_defs->spills; - } - } else { - spill = val_defs->spills; - } - - assert(spill && "no spill placed before PhiM"); - set_irn_n(phi_m, n, spill); - } - } -} - -static void -walker_reload_placer(ir_node * bb, void * data) { - spill_ilp_t *si = (spill_ilp_t*)data; - ir_node *irn; - spill_bb_t *spill_bb = get_irn_link(bb); - - /* reloads at end of block */ - if(spill_bb->reloads) { - keyval_t *keyval; - - set_foreach(spill_bb->reloads, keyval) { - ir_node *irn = (ir_node*)keyval->key; - ilp_var_t reload = PTR_TO_INT(keyval->val); - lpp_name_t *name; - - name = si->lpp->vars[reload]; - if(!is_zero(name->value)) { - ir_node *reload; - ir_node *insert_pos = bb; - ir_node *prev = sched_block_last_noncf(bb); - op_t *prev_op = get_irn_link(prev); - - while(be_is_Spill(prev)) { - prev = sched_prev(prev); - } - - prev_op = get_irn_link(prev); - - /* insert reload before pre-remats */ - while(!sched_is_end(prev) && !be_is_Reload(prev) && !is_Phi(prev) - && prev_op->is_remat && prev_op->attr.remat.pre) { - insert_pos = prev; - - do { - prev = sched_prev(prev); - } while(be_is_Spill(prev)); - - prev_op = get_irn_link(prev); - - } - - reload = insert_reload(si, irn, insert_pos); - - if(opt_keep_alive & KEEPALIVE_RELOADS) - pset_insert_ptr(si->spills, reload); - } - } - } - - /* walk and insert more reloads and collect remats */ - sched_foreach_reverse(bb, irn) { - op_t *op = get_irn_link(irn); - - if(be_is_Reload(irn) || be_is_Spill(irn)) continue; - if(is_Phi(irn)) break; - - if(op->is_remat) { - if(get_irn_mode(irn) != mode_T) { - insert_remat(si, irn); - } - } else { - int n; - - for (n=get_irn_arity(irn)-1; n>=0; --n) { - ir_node *arg = get_irn_n(irn, n); - - if(op->attr.live_range.args.reloads && op->attr.live_range.args.reloads[n] != ILP_UNDEF) { - lpp_name_t *name; - - name = si->lpp->vars[op->attr.live_range.args.reloads[n]]; - if(!is_zero(name->value)) { - ir_node *reload; - ir_node *insert_pos = irn; - ir_node *prev = sched_prev(insert_pos); - op_t *prev_op; - - while(be_is_Spill(prev)) { - prev = sched_prev(prev); - } - - prev_op = get_irn_link(prev); - - /* insert reload before pre-remats */ - while(!sched_is_end(prev) && !be_is_Reload(prev) && !is_Phi(prev) - && prev_op->is_remat && prev_op->attr.remat.pre) { - insert_pos = prev; - - do { - prev = sched_prev(prev); - } while(be_is_Spill(prev)); - - prev_op = get_irn_link(prev); - - } - - reload = insert_reload(si, arg, insert_pos); - - assert(reload && "no reload returned"); - set_irn_n(irn, n, reload); - - if(opt_keep_alive & KEEPALIVE_RELOADS) - pset_insert_ptr(si->spills, reload); - } - } - } - } - } - - del_set(spill_bb->ilp); - if(spill_bb->reloads) del_set(spill_bb->reloads); -} - -static void -walker_collect_used(ir_node * irn, void * data) -{ - bitset_t *used = data; - - bitset_set(used, get_irn_idx(irn)); -} - -struct kill_helper { - bitset_t *used; - spill_ilp_t *si; -}; - -static void -walker_kill_unused(ir_node * bb, void * data) -{ - struct kill_helper *kh = data; - ir_node *bad = get_irg_bad(get_irn_irg(bb)); - ir_node *irn; - - - for(irn=sched_first(bb); !sched_is_end(irn);) { - ir_node *next = sched_next(irn); - int n; - - if(!bitset_is_set(kh->used, get_irn_idx(irn))) { - if(be_is_Spill(irn) || be_is_Reload(irn)) { - DBG((kh->si->dbg, LEVEL_1, "\t SUBOPTIMAL! %+F IS UNUSED (cost: %g)\n", irn, get_cost(irn) * execution_frequency(kh->si, bb))); -#if 0 - assert(lpp_get_sol_state(kh->si->lpp) != lpp_optimal && "optimal solution is suboptimal?"); -#endif - } - - sched_remove(irn); - - set_nodes_block(irn, bad); - for (n=get_irn_arity(irn)-1; n>=0; --n) { - set_irn_n(irn, n, bad); - } - } - irn = next; - } -} - -#ifndef SCHEDULE_PHIM -static void -kill_unused_phims(spill_ilp_t * si, struct kill_helper * kh) -{ - ir_node *phi; - ir_node *bad = get_irg_bad(si->birg->irg); - int n; - - pset_foreach(si->phims, phi) { - if(!bitset_is_set(kh->used, get_irn_idx(phi))) { - - set_nodes_block(phi, bad); - for (n=get_irn_arity(phi)-1; n>=0; --n) { - set_irn_n(phi, n, bad); - } - } - } -} -#endif - -static void -kill_all_unused_values_in_schedule(spill_ilp_t * si) -{ - struct kill_helper kh; - - kh.used = bitset_malloc(get_irg_last_idx(si->birg->irg)); - kh.si = si; - - irg_walk_graph(si->birg->irg, walker_collect_used, NULL, kh.used); -#ifndef SCHEDULE_PHIM - kill_unused_phims(si, &kh); -#endif - irg_block_walk_graph(si->birg->irg, walker_kill_unused, NULL, &kh); - - bitset_free(kh.used); -} - -void -print_irn_pset(pset * p) -{ - ir_node *irn; - - pset_foreach(p, irn) { - ir_printf("%+F\n", irn); - } -} - -void -dump_phi_class(spill_ilp_t *si, ir_node **phiclass, const char * file) -{ - FILE *f = fopen(file, "w"); - ir_node *irn; - interference_t *interference; - int i; - - set_break(si->interferences); - - ir_fprintf(f, "digraph phiclass {\n"); - - for (i = ARR_LEN(phiclass) - 1; i >= 0; --i) { - irn = phiclass[i]; - if (is_Phi(irn)) - ir_fprintf(f, " %F%N [shape=box]\n", irn, irn); - } - - for (i = ARR_LEN(phiclass) - 1; i >= 0; --i) { - int n; - - irn = phiclass[i]; - if (! is_Phi(irn)) - continue; - - for (n = get_irn_arity(irn) - 1; n >= 0; --n) { - ir_node *arg = get_irn_n(irn, n); - - ir_fprintf(f, " %F%N -> %F%N\n", irn, irn, arg, arg); - } - } - - set_foreach(si->interferences, interference) { - const ir_node *a = interference->a; - const ir_node *b = interference->b; - if (get_phi_class(si->pc, (ir_node *)a) == phiclass) { - ir_fprintf(f, " %F%N -> %F%N [color=red,dir=none,style=bold]\n", a, a, b, b); - } - } - - ir_fprintf(f, "}"); - fclose(f); -} - -static void -rewire_uses(spill_ilp_t * si) -{ - defs_t *defs; - ir_nodeset_t ignore; - - ir_nodeset_init(&ignore); - ir_nodeset_insert(&ignore, get_irg_end(si->birg->irg)); - - /* then fix uses of spills */ - set_foreach(si->values, defs) { - pset *reloads; - pset *spills; - const ir_node *next = defs->remats; - int remats = 0; - - reloads = pset_new_ptr_default(); - - while(next) { - if(be_is_Reload(next)) { - pset_insert_ptr(reloads, next); - } else { - ++remats; - } - next = get_irn_link(next); - } - - spills = get_spills_for_value(si, defs->value); - DBG((si->dbg, LEVEL_2, "\t %d remats, %d reloads, and %d spills for value %+F\n", remats, pset_count(reloads), pset_count(spills), defs->value)); - if(pset_count(spills) > 1) { - be_ssa_construction_env_t senv; - ir_node *node; - //assert(pset_count(reloads) > 0); - // print_irn_pset(spills); - // print_irn_pset(reloads); - - be_ssa_construction_init(&senv, si->birg); - be_ssa_construction_set_ignore_uses(&senv, &ignore); - pset_foreach(spills, node) { - be_ssa_construction_add_copy(&senv, node); - } - pset_foreach(spills, node) { - be_ssa_construction_fix_users(&senv, node); - } - be_ssa_construction_update_liveness_phis(&senv, si->lv); - pset_foreach(spills, node) { - be_liveness_update(si->lv, node); - } - be_ssa_construction_destroy(&senv); - } - - del_pset(reloads); - del_pset(spills); - } - - /* first fix uses of remats and reloads */ - set_foreach(si->values, defs) { - const ir_node *next = defs->remats; - int orig_kept = 0; - - if(next) { - be_ssa_construction_env_t senv; - - be_ssa_construction_init(&senv, si->birg); - - if(sched_is_scheduled(defs->value)) { - be_ssa_construction_add_copy(&senv, (ir_node*) defs->value); - orig_kept = 1; - } - - next = defs->remats; - while(next) { - be_ssa_construction_add_copy(&senv, (ir_node*) next); - next = get_irn_link(next); - } - - if(sched_is_scheduled(defs->value)) { - be_ssa_construction_fix_users(&senv, (ir_node*) defs->value); - } - - next = defs->remats; - while(next) { - be_ssa_construction_fix_users(&senv, (ir_node*) next); - next = get_irn_link(next); - } - - be_ssa_construction_update_liveness_phis(&senv, si->lv); - if(sched_is_scheduled(defs->value)) { - be_liveness_update(si->lv, (ir_node*) defs->value); - } - - next = defs->remats; - while(next) { - be_liveness_update(si->lv, (ir_node*) next); - next = get_irn_link(next); - } - - be_ssa_construction_destroy(&senv); - } - } - - ir_nodeset_destroy(&ignore); -// remove_unused_defs(si); -} - - -static void -writeback_results(spill_ilp_t * si) -{ - /* walk through the graph and collect all spills, reloads and remats for a value */ - - si->values = new_set(cmp_defs, 4096); - - DBG((si->dbg, LEVEL_1, "Applying results\n")); - delete_unnecessary_remats(si); - si->m_unknown = new_r_Unknown(si->birg->irg, mode_M); - irg_block_walk_graph(si->birg->irg, walker_spill_placer, NULL, si); - irg_block_walk_graph(si->birg->irg, walker_reload_placer, NULL, si); - if(opt_memoperands) - insert_memoperands(si); - phim_fixer(si); - - /* clean the remat info! there are still back-edges leading there! */ - clean_remat_info(si); - - rewire_uses(si); - - connect_all_spills_with_keep(si); - - del_set(si->values); -} - -static int -get_n_regs(spill_ilp_t * si) -{ - int arch_n_regs = arch_register_class_n_regs(si->cls); - - bitset_t *arch_regs = bitset_malloc(arch_n_regs); - bitset_t *abi_regs = bitset_malloc(arch_n_regs); - - arch_put_non_ignore_regs(si->cls, arch_regs); - be_abi_put_ignore_regs(si->birg->abi, si->cls, abi_regs); - - bitset_andnot(arch_regs, abi_regs); - arch_n_regs = bitset_popcnt(arch_regs); - - bitset_free(arch_regs); - bitset_free(abi_regs); - - DBG((si->dbg, LEVEL_1, "\tArchitecture has %d free registers in class %s\n", arch_n_regs, si->cls->name)); - return arch_n_regs; -} - -static void -walker_reload_mover(ir_node * bb, void * data) -{ - spill_ilp_t *si = data; - ir_node *tmp; - - sched_foreach(bb, tmp) { - if(be_is_Reload(tmp) && has_reg_class(si, tmp)) { - ir_node *reload = tmp; - ir_node *irn = tmp; - - /* move reload upwards */ - - int pressure = (int)get_irn_link(reload); - if(pressure < si->n_regs) { - irn = sched_prev(reload); - DBG((si->dbg, LEVEL_5, "regpressure before %+F: %d\n", reload, pressure)); - sched_remove(reload); - pressure = (int)get_irn_link(irn); - - while(pressure < si->n_regs) { - if( sched_is_end(irn) || - (be_is_Reload(irn) && has_reg_class(si, irn)) || - /* do not move reload before its spill */ - (irn == be_get_Reload_mem(reload)) || - /* do not move before phi */ - is_Phi(irn)) break; - - set_irn_link(irn, INT_TO_PTR(pressure+1)); - DBG((si->dbg, LEVEL_5, "new regpressure before %+F: %d\n", irn, pressure+1)); - irn = sched_prev(irn); - - pressure = (int)get_irn_link(irn); - } - - DBG((si->dbg, LEVEL_3, "putting reload %+F after %+F\n", reload, irn)); - sched_put_after(irn, reload); - } - } - } -} - -static void -move_reloads_upward(spill_ilp_t * si) -{ - irg_block_walk_graph(si->birg->irg, walker_reload_mover, NULL, si); -} - - -/** - * Walk all irg blocks and check for interfering spills inside of phi classes - */ -static void -luke_meminterferencechecker(ir_node * bb, void * data) -{ - spill_ilp_t *si = (spill_ilp_t*)data; - int l1, l2; - - be_lv_foreach(si->lv, bb, be_lv_state_end | be_lv_state_out | be_lv_state_in, l1) { - ir_node *a = be_lv_get_irn(si->lv, bb, l1); - - if (! be_is_Spill(a) && (!is_Phi(a) || get_irn_mode(a) != mode_T)) - continue; - - /* a is only interesting if it is in my register class and if it is inside a phi class */ - if (has_reg_class(si, a) && get_phi_class(si->pc, a)) { - for (l2 = _be_lv_next_irn(si->lv, bb, 0xff, l1 + 1); l2 >= 0; l2 = _be_lv_next_irn(si->lv, bb, 0xff, l2 + 1)) { - ir_node *b = be_lv_get_irn(si->lv, bb, l2); - - if (! be_is_Spill(b) && (! is_Phi(b) || get_irn_mode(b) != mode_T)) - continue; - - /* a and b are only interesting if they are in the same phi class */ - if (has_reg_class(si, b) && get_phi_class(si->pc, a) == get_phi_class(si->pc, b)) { - if (values_interfere_in_block(si, bb, a, b)) { - ir_fprintf(stderr, "$$ Spills interfere in %+F: %+F, %+F \t$$\n", bb, a, b); - } - } - } - } - } -} - -static void -verify_phiclasses(spill_ilp_t * si) -{ - /* analyze phi classes */ - phi_class_free(si->pc); - si->pc = phi_class_new_from_irg(si->birg->irg, 0); - - DBG((si->dbg, LEVEL_2, "\t calling memory interference checker\n")); - irg_block_walk_graph(si->birg->irg, luke_meminterferencechecker, NULL, si); -} - -void -be_spill_remat(be_irg_t *birg, const arch_register_class_t *cls) -{ - char buf[256]; - char problem_name[256]; - char dump_suffix[256]; - char dump_suffix2[256]; - struct obstack obst; - spill_ilp_t si; - ir_graph *irg = be_get_birg_irg(birg); - - ir_snprintf(problem_name, sizeof(problem_name), "%F_%s", irg, cls->name); - ir_snprintf(dump_suffix, sizeof(dump_suffix), "-%s-remats", cls->name); - ir_snprintf(dump_suffix2, sizeof(dump_suffix2), "-%s-pressure", cls->name); - - FIRM_DBG_REGISTER(si.dbg, "firm.be.ra.spillremat"); - DBG((si.dbg, LEVEL_1, "\n\n\t\t===== Processing %s =====\n\n", problem_name)); - - if(opt_verify & VERIFY_DOMINANCE) - be_check_dominance(irg); - - be_assure_liveness(birg); - - obstack_init(&obst); - si.obst = &obst; - si.birg = birg; - si.cls = cls; - si.lpp = new_lpp(problem_name, lpp_minimize); - si.remat_info = new_set(cmp_remat_info, 4096); - si.interferences = new_set(cmp_interference, 32); - si.memoperands = new_set(cmp_memoperands, 128); - si.all_possible_remats = pset_new_ptr_default(); - si.spills = pset_new_ptr_default(); - si.inverse_ops = pset_new_ptr_default(); - si.lv = birg->lv; - si.keep = NULL; - si.n_regs = get_n_regs(&si); - - set_irg_link(irg, &si); - compute_doms(irg); - - /* compute phi classes */ - // phi_class_compute(irg); - - if(opt_dump_flags & DUMP_STATS) - be_analyze_regpressure(birg, cls, "-pre"); - - DBG((si.dbg, LEVEL_2, "\t initializing\n")); - irg_block_walk_graph(irg, luke_initializer, NULL, &si); - - if(opt_remats) { - /* collect remats */ - DBG((si.dbg, LEVEL_1, "Collecting remats\n")); - irg_walk_graph(irg, walker_remat_collector, NULL, &si); - } - - /* insert possible remats */ - DBG((si.dbg, LEVEL_1, "Inserting possible remats\n")); - irg_block_walk_graph(irg, walker_remat_insertor, NULL, &si); - DBG((si.dbg, LEVEL_2, " -> inserted %d possible remats\n", pset_count(si.all_possible_remats))); - - if(opt_keep_alive & KEEPALIVE_REMATS) { - DBG((si.dbg, LEVEL_1, "Connecting remats with keep and dumping\n")); - connect_all_remats_with_keep(&si); - /* dump graph with inserted remats */ - dump_graph_with_remats(irg, dump_suffix); - } - - /* insert copies for phi arguments not in my regclass */ - irg_walk_graph(irg, walker_regclass_copy_insertor, NULL, &si); - - /* recompute liveness */ - DBG((si.dbg, LEVEL_1, "Recomputing liveness\n")); - be_liveness_recompute(si.lv); - - /* build the ILP */ - DBG((si.dbg, LEVEL_1, "\tBuilding ILP\n")); - DBG((si.dbg, LEVEL_2, "\t endwalker\n")); - irg_block_walk_graph(irg, luke_endwalker, NULL, &si); - - DBG((si.dbg, LEVEL_2, "\t blockwalker\n")); - irg_block_walk_graph(irg, luke_blockwalker, NULL, &si); - - si.pc = phi_class_new_from_irg(birg->irg, 0); - if (opt_memcopies) { - DBG((si.dbg, LEVEL_2, "\t memcopyhandler\n")); - memcopyhandler(&si); - } - - if (opt_dump_flags & DUMP_PROBLEM) { - FILE *f; - ir_snprintf(buf, sizeof(buf), "%s-spillremat.ilp", problem_name); - if ((f = fopen(buf, "wt")) != NULL) { - lpp_dump_plain(si.lpp, f); - fclose(f); - } - } - - if (opt_dump_flags & DUMP_MPS) { - FILE *f; - - ir_snprintf(buf, sizeof(buf), "%s-spillremat.mps", problem_name); - if ((f = fopen(buf, "wt")) != NULL) { - mps_write_mps(si.lpp, s_mps_fixed, f); - fclose(f); - } - - ir_snprintf(buf, sizeof(buf), "%s-spillremat.mst", problem_name); - if ((f = fopen(buf, "wt")) != NULL) { - mps_write_mst(si.lpp, s_mps_fixed, f); - fclose(f); - } - } - - lpp_check_startvals(si.lpp); - -#ifdef SOLVE - DBG((si.dbg, LEVEL_1, "\tSolving %s (%d variables, %d constraints)\n", problem_name, si.lpp->var_next, si.lpp->cst_next)); - lpp_set_time_limit(si.lpp, opt_timeout); - - if(opt_log) - lpp_set_log(si.lpp, stdout); - -#ifdef SOLVE_LOCAL - lpp_solve_cplex(si.lpp); -#else - lpp_solve_net(si.lpp, LPP_SERVER, LPP_SOLVER); -#endif - assert(lpp_is_sol_valid(si.lpp) - && "solution of ILP must be valid"); - - DBG((si.dbg, LEVEL_1, "\t%s: iterations: %d, solution time: %g, objective function: %g, best bound: %g\n", problem_name, si.lpp->iterations, si.lpp->sol_time, is_zero(si.lpp->objval)?0.0:si.lpp->objval, is_zero(si.lpp->best_bound)?0.0:si.lpp->best_bound)); - - if(opt_dump_flags & DUMP_SOLUTION) { - FILE *f; - char buf[256]; - - ir_snprintf(buf, sizeof(buf), "%s-spillremat.sol", problem_name); - if ((f = fopen(buf, "wt")) != NULL) { - int i; - for (i = 0; i < si.lpp->var_next; ++i) { - lpp_name_t *name = si.lpp->vars[i]; - fprintf(f, "%20s %4d %10f\n", name->name, name->nr, name->value); - } - fclose(f); - } - } - -#ifndef SCHEDULE_PHIM - si.phims = pset_new_ptr_default(); -#endif - writeback_results(&si); - - -#endif /* SOLVE */ - - kill_all_unused_values_in_schedule(&si); - -#if !defined(SCHEDULE_PHIM) && defined(SOLVE) - del_pset(si.phims); -#endif - - if(opt_keep_alive & (KEEPALIVE_SPILLS | KEEPALIVE_RELOADS)) - be_dump(irg, "-spills-placed", dump_ir_block_graph); - - // move reloads upwards - be_liveness_recompute(si.lv); - irg_block_walk_graph(irg, walker_pressure_annotator, NULL, &si); - move_reloads_upward(&si); - - if(opt_memcopies) { - verify_phiclasses(&si); - } - - irg_block_walk_graph(irg, walker_pressure_annotator, NULL, &si); - - if(opt_dump_flags & DUMP_PRESSURE) - dump_pressure_graph(&si, dump_suffix2); - - if(opt_dump_flags & DUMP_STATS) - be_analyze_regpressure(birg, cls, "-post"); - - if(opt_verify & VERIFY_DOMINANCE) - be_check_dominance(irg); - - free_dom(irg); - del_set(si.interferences); - del_pset(si.inverse_ops); - del_pset(si.all_possible_remats); - del_set(si.memoperands); - del_pset(si.spills); - free_lpp(si.lpp); - phi_class_free(si.pc); - obstack_free(&obst, NULL); - DBG((si.dbg, LEVEL_1, "\tdone.\n")); -} - -void be_init_spillremat(void) -{ - static be_spiller_t remat_spiller = { - be_spill_remat - }; - lc_opt_entry_t *be_grp = lc_opt_get_grp(firm_opt_get_root(), "be"); - lc_opt_entry_t *ra_grp = lc_opt_get_grp(be_grp, "ra"); - lc_opt_entry_t *chordal_grp = lc_opt_get_grp(ra_grp, "chordal"); - lc_opt_entry_t *remat_grp = lc_opt_get_grp(chordal_grp, "remat"); - - be_register_spiller("remat", &remat_spiller); - lc_opt_add_table(remat_grp, options); -} - -BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillremat); - -#else /* WITH_ILP */ - -static __attribute__((unused)) -void only_that_you_can_compile_without_WITH_ILP_defined(void) -{ -} - -#endif /* WITH_ILP */ diff --git a/ir/be/bespillremat.h b/ir/be/bespillremat.h deleted file mode 100644 index 1d3d53a51..000000000 --- a/ir/be/bespillremat.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 1995-2008 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 ILP based spilling & rematerialization - * @author Adam M. Szalkowski - * @date 06.04.2006 - * @version $Id$ - */ -#ifndef FIRM_BE_BESPILLREMAT_H -#define FIRM_BE_BESPILLREMAT_H - -#include "bearch.h" -#include "beirg.h" - -void be_spill_remat(be_irg_t *birg, const arch_register_class_t *cls); - -#endif /* FIRM_BE_BESPILLREMAT_H */ diff --git a/ir/be/bessadestr.c b/ir/be/bessadestr.c index d1b4bd235..db7ddc747 100644 --- a/ir/be/bessadestr.c +++ b/ir/be/bessadestr.c @@ -131,13 +131,15 @@ static void insert_all_perms_walker(ir_node *bl, void *data) { * register class by construction. */ for(phi = get_irn_link(bl); phi; phi = get_irn_link(phi)) { - ir_node *arg = get_irn_n(phi, i); - unsigned hash = hash_irn(arg); - perm_proj_t templ; + ir_node *arg = get_irn_n(phi, i); + const arch_register_req_t *req = arch_get_register_req_out(arg); + unsigned hash; + perm_proj_t templ; - if (arch_irn_is(arg, ignore)) + if (req->type & arch_register_req_type_ignore) continue; + hash = hash_irn(arg); templ.arg = arg; pp = set_find(arg_set, &templ, sizeof(templ), hash); @@ -242,13 +244,17 @@ static void set_regs_or_place_dupls_walker(ir_node *bl, void *data) { /* process all arguments of the phi */ for (i = 0, max = get_irn_arity(phi); i < max; ++i) { - ir_node *arg = get_irn_n(phi, i); - ir_node *arg_block = get_Block_cfgpred_block(phi_block, i); - const arch_register_t *arg_reg = get_reg(arg); + ir_node *arg = get_irn_n(phi, i); + const arch_register_req_t *req = arch_get_register_req_out(arg); + const arch_register_t *arg_reg; + ir_node *arg_block; - if (arch_irn_is(arg, ignore)) + if (req->type & arch_register_req_type_ignore) continue; + arg_block = get_Block_cfgpred_block(phi_block, i); + arg_reg = get_reg(arg); + assert(arg_reg && "Register must be set while placing perms"); DBG((dbg, LEVEL_1, " for %+F(%s) -- %+F(%s)\n", phi, phi_reg->name, arg, arg_reg->name)); @@ -420,9 +426,10 @@ static void ssa_destruction_check_walker(ir_node *bl, void *data) { phi_reg = get_reg(phi); /* iterate over all args of phi */ for (i = 0, max = get_irn_arity(phi); i < max; ++i) { - ir_node *arg = get_irn_n(phi, i); + ir_node *arg = get_irn_n(phi, i); + const arch_register_req_t *req = arch_get_register_req_out(arg); - if (arch_irn_is(arg, ignore)) + if (req->type & arch_register_req_type_ignore) continue; arg_reg = get_reg(arg); diff --git a/ir/be/bestate.c b/ir/be/bestate.c index 7adc54b69..28e336e1a 100644 --- a/ir/be/bestate.c +++ b/ir/be/bestate.c @@ -597,7 +597,6 @@ void be_assure_state(be_irg_t *birg, const arch_register_t *reg, void *func_env, len = ARR_LEN(phis); for(i = 0; i < len; ++i) { ir_node *phi = phis[i]; - be_set_phi_flags(phi, arch_irn_flags_ignore); arch_set_irn_register(phi, env.reg); } be_ssa_construction_destroy(&senv); diff --git a/ir/be/beverify.c b/ir/be/beverify.c index 7e18c11c1..c49be922d 100644 --- a/ir/be/beverify.c +++ b/ir/be/beverify.c @@ -284,31 +284,28 @@ static void verify_schedule_walker(ir_node *block, void *data) { static int should_be_scheduled(ir_node *node) { - if(is_Block(node)) - return -1; - - if(is_Proj(node)) - return 0; - - if(get_irn_mode(node) == mode_M) { - if(is_Phi(node) || is_Sync(node) || is_Pin(node)) - return 0; - } - if(be_is_Keep(node) && get_irn_opcode(get_nodes_block(node)) == iro_Bad) - return 0; - switch(get_irn_opcode(node)) { + case iro_Bad: + case iro_Block: case iro_End: case iro_NoMem: - case iro_Bad: + case iro_Pin: + case iro_Proj: + case iro_Sync: case iro_Unknown: return 0; + case iro_Phi: + if (get_irn_mode(node) == mode_M) + return 0; + break; default: break; } - if (arch_irn_get_flags(node) & arch_irn_flags_ignore) - return -1; + if (get_irn_mode(node) != mode_T) { + if (arch_irn_is_ignore(node)) + return -1; + } return 1; } @@ -771,7 +768,7 @@ static void value_used(ir_node *node) { return; reg = arch_get_irn_register(node); - if (reg->type & arch_register_type_virtual) + if (reg == NULL || reg->type & arch_register_type_virtual) return; reg_node = registers[reg->index]; @@ -794,7 +791,7 @@ static void value_def(ir_node *node) return; reg = arch_get_irn_register(node); - if (reg->type & arch_register_type_virtual) + if (reg == NULL || reg->type & arch_register_type_virtual) return; reg_node = registers[reg->index]; diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 9e65fdb62..e7ad57022 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -249,55 +249,9 @@ static const arch_register_req_t *ia32_get_irn_reg_req(const ir_node *node, } /* unknowns should be transformed already */ - assert(!is_Unknown(node)); return arch_no_register_req; } -static void ia32_set_irn_reg(ir_node *irn, const arch_register_t *reg) -{ - int pos = 0; - - if (get_irn_mode(irn) == mode_X) { - return; - } - - if (is_Proj(irn)) { - pos = get_Proj_proj(irn); - irn = skip_Proj(irn); - } - - if (is_ia32_irn(irn)) { - const arch_register_t **slots; - - slots = get_ia32_slots(irn); - slots[pos] = reg; - } else { - ia32_set_firm_reg(irn, reg, cur_reg_set); - } -} - -static const arch_register_t *ia32_get_irn_reg(const ir_node *irn) -{ - int pos = 0; - - if (is_Proj(irn)) { - if (get_irn_mode(irn) == mode_X) { - return NULL; - } - - pos = get_Proj_proj(irn); - irn = skip_Proj_const(irn); - } - - if (is_ia32_irn(irn)) { - const arch_register_t **slots = get_ia32_slots(irn); - assert(pos < get_ia32_n_res(irn)); - return slots[pos]; - } else { - return ia32_get_firm_reg(irn, cur_reg_set); - } -} - static arch_irn_class_t ia32_classify(const ir_node *irn) { arch_irn_class_t classification = 0; @@ -321,29 +275,6 @@ static arch_irn_class_t ia32_classify(const ir_node *irn) { return classification; } -static arch_irn_flags_t ia32_get_flags(const ir_node *irn) { - arch_irn_flags_t flags = arch_irn_flags_none; - - if (is_Unknown(irn)) - return arch_irn_flags_ignore; - - if(is_Proj(irn) && mode_is_datab(get_irn_mode(irn))) { - ir_node *pred = get_Proj_pred(irn); - - if(is_ia32_irn(pred)) { - flags = get_ia32_out_flags(pred, get_Proj_proj(irn)); - } - - irn = pred; - } - - if (is_ia32_irn(irn)) { - flags |= get_ia32_flags(irn); - } - - return flags; -} - /** * The IA32 ABI callback object. */ @@ -412,15 +343,16 @@ static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap const arch_env_t *arch_env = env->aenv; if (! env->flags.try_omit_fp) { - ir_graph *irg =env->irg; + ir_graph *irg = env->irg; ir_node *bl = get_irg_start_block(irg); ir_node *curr_sp = be_abi_reg_map_get(reg_map, arch_env->sp); ir_node *curr_bp = be_abi_reg_map_get(reg_map, arch_env->bp); - ir_node *noreg = ia32_new_NoReg_gp(cg); + ir_node *noreg = ia32_new_NoReg_gp(cg); ir_node *push; - /* ALL nodes representing bp must be set to ignore. */ - be_node_set_flags(get_Proj_pred(curr_bp), BE_OUT_POS(get_Proj_proj(curr_bp)), arch_irn_flags_ignore); + /* mark bp register as ignore */ + be_set_constr_single_reg_out(get_Proj_pred(curr_bp), + get_Proj_proj(curr_bp), arch_env->bp, arch_register_req_type_ignore); /* push ebp */ push = new_rd_ia32_Push(NULL, irg, bl, noreg, noreg, *mem, curr_bp, curr_sp); @@ -429,22 +361,19 @@ static const arch_register_t *ia32_abi_prologue(void *self, ir_node **mem, pmap /* the push must have SP out register */ arch_set_irn_register(curr_sp, arch_env->sp); - set_ia32_flags(push, arch_irn_flags_ignore); /* this modifies the stack bias, because we pushed 32bit */ *stack_bias -= 4; /* move esp to ebp */ - curr_bp = be_new_Copy(arch_env->bp->reg_class, irg, bl, curr_sp); - be_set_constr_single_reg(curr_bp, BE_OUT_POS(0), arch_env->bp); - arch_set_irn_register(curr_bp, arch_env->bp); - be_node_set_flags(curr_bp, BE_OUT_POS(0), arch_irn_flags_ignore); + curr_bp = be_new_Copy(arch_env->bp->reg_class, irg, bl, curr_sp); + be_set_constr_single_reg_out(curr_bp, 0, arch_env->bp, + arch_register_req_type_ignore); /* beware: the copy must be done before any other sp use */ curr_sp = be_new_CopyKeep_single(arch_env->sp->reg_class, irg, bl, curr_sp, curr_bp, get_irn_mode(curr_sp)); - be_set_constr_single_reg(curr_sp, BE_OUT_POS(0), arch_env->sp); - arch_set_irn_register(curr_sp, arch_env->sp); - be_node_set_flags(curr_sp, BE_OUT_POS(0), arch_irn_flags_ignore); + be_set_constr_single_reg_out(curr_sp, 0, arch_env->sp, + arch_register_req_type_produces_sp); be_abi_reg_map_set(reg_map, arch_env->sp, curr_sp); be_abi_reg_map_set(reg_map, arch_env->bp, curr_bp); @@ -484,7 +413,6 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ /* leave */ leave = new_rd_ia32_Leave(NULL, irg, bl, curr_bp); - set_ia32_flags(leave, arch_irn_flags_ignore); curr_bp = new_r_Proj(irg, bl, leave, mode_bp, pn_ia32_Leave_frame); curr_sp = new_r_Proj(irg, bl, leave, get_irn_mode(curr_sp), pn_ia32_Leave_stack); } else { @@ -497,11 +425,11 @@ static void ia32_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_ /* copy ebp to esp */ curr_sp = be_new_Copy(&ia32_reg_classes[CLASS_ia32_gp], irg, bl, curr_bp); arch_set_irn_register(curr_sp, arch_env->sp); - be_node_set_flags(curr_sp, BE_OUT_POS(0), arch_irn_flags_ignore); + be_set_constr_single_reg_out(curr_sp, 0, arch_env->sp, + arch_register_req_type_ignore); /* pop ebp */ - pop = new_rd_ia32_Pop(NULL, env->irg, bl, *mem, curr_sp); - set_ia32_flags(pop, arch_irn_flags_ignore); + pop = new_rd_ia32_PopEbp(NULL, env->irg, bl, *mem, curr_sp); curr_bp = new_r_Proj(irg, bl, pop, mode_bp, pn_ia32_Pop_res); curr_sp = new_r_Proj(irg, bl, pop, get_irn_mode(curr_sp), pn_ia32_Pop_stack); @@ -893,10 +821,7 @@ static const be_abi_callbacks_t ia32_abi_callbacks = { static const arch_irn_ops_t ia32_irn_ops = { ia32_get_irn_reg_req, - ia32_set_irn_reg, - ia32_get_irn_reg, ia32_classify, - ia32_get_flags, ia32_get_frame_entity, ia32_set_frame_entity, ia32_set_frame_offset, @@ -1164,7 +1089,7 @@ static void transform_to_Load(ia32_code_gen_t *cg, ir_node *node) { /* copy the register from the old node to the new Load */ reg = arch_get_irn_register(node); - arch_set_irn_register(new_op, reg); + arch_set_irn_register(proj, reg); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node)); @@ -1769,7 +1694,6 @@ static arch_env_t *ia32_init(FILE *file_handle) { /* enter the ISA object into the intrinsic environment */ intrinsic_env.isa = isa; - ia32_handle_intrinsics(); /* emit asm includes */ n = get_irp_n_asms(); @@ -2355,6 +2279,7 @@ static const lc_opt_table_entry_t ia32_options[] = { const arch_isa_if_t ia32_isa_if = { ia32_init, ia32_done, + ia32_handle_intrinsics, ia32_get_n_reg_class, ia32_get_reg_class, ia32_get_reg_class_for_mode, diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 34c75bb32..51324749d 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -167,7 +167,7 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) assert(pos == 0); reg = arch_get_irn_register(irn); } else if (is_ia32_irn(irn)) { - reg = get_ia32_out_reg(irn, pos); + reg = arch_irn_get_register(irn, pos); } else { const ir_edge_t *edge; diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index 6bbbc64e2..fbb1e6c26 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -73,7 +73,7 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) in2 = get_irn_n(irn, n_ia32_binary_right); in1_reg = arch_get_irn_register(in1); in2_reg = arch_get_irn_register(in2); - out_reg = get_ia32_out_reg(irn, 0); + out_reg = arch_irn_get_register(irn, 0); irg = cg->irg; block = get_nodes_block(irn); @@ -258,7 +258,7 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg, ir_node *in_node, *block; reqs = get_ia32_out_req_all(node); - n_res = get_ia32_n_res(node); + n_res = arch_irn_get_n_outs(node); block = get_nodes_block(node); /* check all OUT requirements, if there is a should_be_same */ @@ -280,7 +280,7 @@ static void assure_should_be_same_requirements(ia32_code_gen_t *cg, same_pos = get_first_same(req); /* get in and out register */ - out_reg = get_ia32_out_reg(node, i); + out_reg = arch_irn_get_register(node, i); in_node = get_irn_n(node, same_pos); in_reg = arch_get_irn_register(in_node); @@ -406,7 +406,7 @@ static void fix_am_source(ir_node *irn) return; reqs = get_ia32_out_req_all(irn); - n_res = get_ia32_n_res(irn); + n_res = arch_irn_get_n_outs(irn); for (i = 0; i < n_res; i++) { const arch_register_t *out_reg; @@ -419,7 +419,7 @@ static void fix_am_source(ir_node *irn) continue; /* get in and out register */ - out_reg = get_ia32_out_reg(irn, i); + out_reg = arch_irn_get_register(irn, i); same_pos = get_first_same(reqs[i]); same_node = get_irn_n(irn, same_pos); same_reg = arch_get_irn_register(same_node); diff --git a/ir/be/ia32/ia32_fpu.c b/ir/be/ia32/ia32_fpu.c index 3c7fcbd57..40ca7b5c7 100644 --- a/ir/be/ia32/ia32_fpu.c +++ b/ir/be/ia32/ia32_fpu.c @@ -288,7 +288,6 @@ void rewire_fpu_mode_nodes(be_irg_t *birg) len = ARR_LEN(phis); for(i = 0; i < len; ++i) { ir_node *phi = phis[i]; - be_set_phi_flags(phi, arch_irn_flags_ignore); arch_set_irn_register(phi, reg); } be_ssa_construction_destroy(&senv); diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index e3ddcf61f..4b3012a6d 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -46,6 +46,7 @@ #include "xmalloc.h" #include "../bearch_t.h" +#include "../beinfo.h" #include "bearch_ia32_t.h" #include "ia32_nodes_attr.h" @@ -70,7 +71,7 @@ static void dump_reg_req(FILE *F, ir_node *n, const arch_register_req_t **reqs, int inout) { char *dir = inout ? "out" : "in"; - int max = inout ? get_ia32_n_res(n) : get_irn_arity(n); + int max = inout ? (int) arch_irn_get_n_outs(n) : get_irn_arity(n); char buf[1024]; int i; @@ -139,7 +140,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { int bad = 0; int i, n_res, flags; const arch_register_req_t **reqs; - const arch_register_t **slots; switch (reason) { case dump_node_opcode_txt: @@ -205,7 +205,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { break; case dump_node_info_txt: - n_res = get_ia32_n_res(n); + n_res = arch_irn_get_n_outs(n); fprintf(F, "=== IA32 attr begin ===\n"); /* dump IN requirements */ @@ -221,12 +221,9 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { } /* dump assigned registers */ - slots = get_ia32_slots(n); - if (slots && n_res > 0) { + if (n_res > 0) { for (i = 0; i < n_res; i++) { - const arch_register_t *reg; - - reg = slots[i]; + const arch_register_t *reg = arch_irn_get_register(n, i); fprintf(F, "reg #%d = %s\n", i, reg ? arch_register_get_name(reg) : "n/a"); } @@ -292,7 +289,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { fprintf(F, "size = %u\n", get_ia32_copyb_size(n)); } - fprintf(F, "n_res = %d\n", get_ia32_n_res(n)); + fprintf(F, "n_res = %d\n", arch_irn_get_n_outs(n)); fprintf(F, "use_frame = %d\n", is_ia32_use_frame(n)); fprintf(F, "commutative = %d\n", is_ia32_commutative(n)); fprintf(F, "need stackent = %d\n", is_ia32_need_stackent(n)); @@ -301,7 +298,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { /* dump flags */ fprintf(F, "flags ="); - flags = get_ia32_flags(n); + flags = arch_irn_get_flags(n); if (flags == arch_irn_flags_none) { fprintf(F, " none"); } @@ -312,12 +309,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { if (flags & arch_irn_flags_rematerializable) { fprintf(F, " remat"); } - if (flags & arch_irn_flags_ignore) { - fprintf(F, " ignore"); - } - if (flags & arch_irn_flags_modify_sp) { - fprintf(F, " modify_sp"); - } if (flags & arch_irn_flags_modify_flags) { fprintf(F, " modify_flags"); } @@ -796,43 +787,6 @@ void set_ia32_req_in(ir_node *node, const arch_register_req_t *req, int pos) { attr->in_req[pos] = req; } -/** - * Returns the register flag of an ia32 node. - */ -arch_irn_flags_t get_ia32_flags(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return attr->data.flags; -} - -/** - * Sets the register flag of an ia32 node. - */ -void set_ia32_flags(ir_node *node, arch_irn_flags_t flags) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.flags = flags; -} - -void add_ia32_flags(ir_node *node, arch_irn_flags_t flags) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.flags |= flags; -} - -/** - * Returns the result register slots of an ia32 node. - */ -const arch_register_t **get_ia32_slots(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return attr->slots; -} - -/** - * Returns the number of results. - */ -int get_ia32_n_res(const ir_node *node) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - return ARR_LEN(attr->slots); -} - /** * Returns the condition code of a node. */ @@ -860,24 +814,6 @@ unsigned get_ia32_copyb_size(const ir_node *node) return attr->size; } -/** - * Sets the flags for the n'th out. - */ -void set_ia32_out_flags(ir_node *node, arch_irn_flags_t flags, int pos) { - ia32_attr_t *attr = get_ia32_attr(node); - assert(pos < ARR_LEN(attr->out_flags) && "Invalid OUT position."); - attr->out_flags[pos] = flags; -} - -/** - * Gets the flags for the n'th out. - */ -arch_irn_flags_t get_ia32_out_flags(const ir_node *node, int pos) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - assert(pos < ARR_LEN(attr->out_flags) && "Invalid OUT position."); - return attr->out_flags[pos]; -} - /** * Get the list of available execution units. */ @@ -981,18 +917,6 @@ void ia32_swap_left_right(ir_node *node) set_irn_n(node, n_ia32_binary_right, left); } -/** - * Returns the OUT register at position pos. - */ -const arch_register_t *get_ia32_out_reg(const ir_node *node, int pos) { - const ia32_attr_t *attr = get_ia32_attr_const(node); - - assert(pos < ARR_LEN(attr->slots) && "Invalid OUT position."); - assert(attr->slots[pos] && "No register assigned"); - - return attr->slots[pos]; -} - /** * Initializes the nodes attributes. */ @@ -1005,8 +929,9 @@ void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, ir_graph *irg = get_irn_irg(node); struct obstack *obst = get_irg_obstack(irg); ia32_attr_t *attr = get_ia32_attr(node); + backend_info_t *info; - set_ia32_flags(node, flags); + arch_irn_set_flags(node, flags); set_ia32_in_req_all(node, in_reqs); set_ia32_out_req_all(node, out_reqs); @@ -1015,12 +940,9 @@ void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, attr->attr_type |= IA32_ATTR_ia32_attr_t; #endif - attr->out_flags = NEW_ARR_D(int, obst, n_res); - memset(attr->out_flags, 0, n_res * sizeof(attr->out_flags[0])); - - attr->slots = NEW_ARR_D(const arch_register_t*, obst, n_res); - /* void* cast to suppress an incorrect warning on MSVC */ - memset((void*)attr->slots, 0, n_res * sizeof(attr->slots[0])); + info = be_get_info(node); + info->out_infos = NEW_ARR_D(reg_out_info_t, obst, n_res); + memset(info->out_infos, 0, n_res * sizeof(info->out_infos[0])); } void @@ -1264,16 +1186,17 @@ static void ia32_copy_attr(const ir_node *old_node, ir_node *new_node) struct obstack *obst = get_irg_obstack(irg); const ia32_attr_t *attr_old = get_ia32_attr_const(old_node); ia32_attr_t *attr_new = get_ia32_attr(new_node); + backend_info_t *old_info = be_get_info(old_node); + backend_info_t *new_info; + + new_info = be_get_info(new_node); /* copy the attributes */ memcpy(attr_new, attr_old, get_op_attr_size(get_irn_op(old_node))); /* copy out flags */ - attr_new->out_flags = - DUP_ARR_D(int, obst, attr_old->out_flags); - /* copy register assignments */ - attr_new->slots = - DUP_ARR_D(arch_register_t*, obst, attr_old->slots); + new_info->out_infos = + DUP_ARR_D(reg_out_info_t, obst, old_info->out_infos); } /* Include the generated constructor functions */ diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index ce7d968f7..e3c99f2a7 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -283,33 +283,6 @@ void set_ia32_req_out(ir_node *node, const arch_register_req_t *req, int pos); */ void set_ia32_req_in(ir_node *node, const arch_register_req_t *req, int pos); -/** - * Returns the register flag of an ia32 node. - */ -arch_irn_flags_t get_ia32_flags(const ir_node *node); - -/** - * Sets the register flag of an ia32 node. - */ -void set_ia32_flags(ir_node *node, arch_irn_flags_t flags); - -void add_ia32_flags(ir_node *node, arch_irn_flags_t flags); - -/** - * Returns the result register slots of an ia32 node. - */ -const arch_register_t **get_ia32_slots(const ir_node *node); - -/** - * Returns the OUT register at position pos. - */ -const arch_register_t *get_ia32_out_reg(const ir_node *node, int pos); - -/** - * Returns the number of results. - */ -int get_ia32_n_res(const ir_node *node); - /** * Returns the condition code of a node. */ diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index 065cb49c3..c2de549f8 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -92,7 +92,6 @@ typedef struct ia32_attr_t ia32_attr_t; struct ia32_attr_t { except_attr exc; /**< the exception attribute. MUST be the first one. */ struct ia32_attr_data_bitfield { - unsigned flags:5; /**< Indicating if spillable, rematerializeable, stack modifying and/or ignore. */ unsigned tp:3; /**< ia32 node type. */ unsigned am_arity:2; /**< Indicates the address mode type supported by this node. */ unsigned am_scale:2; /**< The address mode scale for index register. */ @@ -114,8 +113,6 @@ struct ia32_attr_t { unsigned is_remat : 1; } data; - int *out_flags; /**< flags for each produced value */ - int am_offs; /**< offsets for AddrMode */ ir_entity *am_sc; /**< SymConst for AddrMode */ @@ -129,8 +126,6 @@ struct ia32_attr_t { const arch_register_req_t **in_req; /**< register requirements for arguments */ const arch_register_req_t **out_req; /**< register requirements for results */ - const arch_register_t **slots; /**< register slots for assigned registers */ - ir_label_t exc_label; /**< the exception label iff this instruction can throw an exception */ #ifndef NDEBUG diff --git a/ir/be/ia32/ia32_optimize.c b/ir/be/ia32/ia32_optimize.c index 1d5647b66..059ce491f 100644 --- a/ir/be/ia32/ia32_optimize.c +++ b/ir/be/ia32/ia32_optimize.c @@ -224,8 +224,8 @@ static void peephole_ia32_Cmp(ir_node *const node) } set_ia32_ls_mode(test, get_ia32_ls_mode(node)); - reg = arch_get_irn_register(node); - arch_set_irn_register(test, reg); + reg = arch_irn_get_register(node, pn_ia32_Cmp_eflags); + arch_irn_set_register(test, pn_ia32_Test_eflags, reg); foreach_out_edge_safe(node, edge, tmp) { ir_node *const user = get_edge_src_irn(edge); @@ -558,10 +558,12 @@ static void peephole_store_incsp(ir_node *store) dbg_info *dbgi; ir_node *node; ir_node *block; - ir_node *noref; + ir_node *noreg; ir_node *mem; ir_node *push; ir_node *val; + ir_node *base; + ir_node *index; ir_node *am_base = get_irn_n(store, n_ia32_Store_base); if (!be_is_IncSP(am_base) || get_nodes_block(am_base) != get_nodes_block(store)) @@ -610,7 +612,7 @@ static void peephole_store_incsp(ir_node *store) || get_ia32_op_type(node) == ia32_AddrModeD)) { int node_offset = get_ia32_am_offs_int(node); ir_mode *node_ls_mode = get_ia32_ls_mode(node); - int node_size = get_mode_size_bytes(node); + int node_size = get_mode_size_bytes(node_ls_mode); /* overlapping with our position? abort */ if (node_offset < my_offset + my_store_size && node_offset + node_size >= my_offset) @@ -628,7 +630,7 @@ static void peephole_store_incsp(ir_node *store) dbgi = get_irn_dbg_info(store); block = get_nodes_block(store); noreg = ia32_new_NoReg_gp(cg); - val = get_ia32_ + val = get_irn_n(store, n_ia32_Store_val); push = new_rd_ia32_Push(dbgi, irg, block, noreg, noreg, mem, @@ -740,7 +742,7 @@ static void peephole_Load_IncSP_to_pop(ir_node *irn) if (loads[loadslot] != NULL) break; - dreg = arch_get_irn_register(node); + dreg = arch_irn_get_register(node, pn_ia32_Load_res); if (regmask & (1 << dreg->index)) { /* this register is already used */ break; @@ -782,10 +784,10 @@ static void peephole_Load_IncSP_to_pop(ir_node *irn) const arch_register_t *reg; mem = get_irn_n(load, n_ia32_mem); - reg = arch_get_irn_register(load); + reg = arch_irn_get_register(load, pn_ia32_Load_res); pop = new_rd_ia32_Pop(get_irn_dbg_info(load), irg, block, mem, pred_sp); - arch_set_irn_register(pop, reg); + arch_irn_set_register(pop, pn_ia32_Load_res, reg); copy_mark(load, pop); diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 4bbb018ad..61b6b4060 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -17,7 +17,7 @@ $arch = "ia32"; # # => { # op_flags => "N|L|C|X|I|F|Y|H|c|K", -# irn_flags => "R|N|I|S" +# irn_flags => "R|N" # arity => "0|1|2|3 ... |variable|dynamic|any", # state => "floats|pinned|mem_pinned|exc_pinned", # args => [ @@ -63,8 +63,6 @@ $arch = "ia32"; # following irn_flags are supported: # R rematerializeable # N not spillable -# I ignore for register allocation -# S modifies stack pointer # # state: state of the operation, OPTIONAL (default is "floats") # @@ -79,10 +77,7 @@ $arch = "ia32"; # # outs: if a node defines more than one output, the names of the projections # nodes having outs having automatically the mode mode_T -# One can also annotate some flags for each out, additional to irn_flags. -# They are separated from name with a colon ':', and concatenated by pipe '|' -# Only I and S are available at the moment (same meaning as in irn_flags). -# example: [ "frame:I", "stack:I|S", "M" ] +# example: [ "frame", "stack", "M" ] # # comment: OPTIONAL comment for the node constructor # @@ -248,7 +243,7 @@ sub ia32_custom_init_attr { my $res = ""; if(defined($node->{modified_flags})) { - $res .= "\tset_ia32_flags(res, get_ia32_flags(res) | arch_irn_flags_modify_flags);\n"; + $res .= "\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);\n"; } if(defined($node->{am})) { my $am = $node->{am}; @@ -323,8 +318,7 @@ $fpcw_flags = [ "FP_IM", "FP_DM", "FP_ZM", "FP_OM", "FP_UM", "FP_PM", Immediate => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_NOREG" ] }, + reg_req => { out => [ "gp_NOREG:I" ] }, attr => "ir_entity *symconst, int symconst_sign, long offset", attr_type => "ia32_immediate_attr_t", hash_func => "ia32_hash_Immediate", @@ -1191,8 +1185,7 @@ GetEIP => { Unknown_GP => { state => "pinned", op_flags => "c|NB", - irn_flags => "I", - reg_req => { out => [ "gp_UKNWN" ] }, + reg_req => { out => [ "gp_UKNWN:I" ] }, units => [], emit => "", latency => 0, @@ -1202,8 +1195,7 @@ Unknown_GP => { Unknown_VFP => { state => "pinned", op_flags => "c|NB", - irn_flags => "I", - reg_req => { out => [ "vfp_UKNWN" ] }, + reg_req => { out => [ "vfp_UKNWN:I" ] }, units => [], emit => "", mode => "mode_E", @@ -1214,8 +1206,7 @@ Unknown_VFP => { Unknown_XMM => { state => "pinned", op_flags => "c|NB", - irn_flags => "I", - reg_req => { out => [ "xmm_UKNWN" ] }, + reg_req => { out => [ "xmm_UKNWN:I" ] }, units => [], emit => "", latency => 0, @@ -1225,8 +1216,7 @@ Unknown_XMM => { NoReg_GP => { state => "pinned", op_flags => "c|NB|NI", - irn_flags => "I", - reg_req => { out => [ "gp_NOREG" ] }, + reg_req => { out => [ "gp_NOREG:I" ] }, units => [], emit => "", latency => 0, @@ -1236,8 +1226,7 @@ NoReg_GP => { NoReg_VFP => { state => "pinned", op_flags => "c|NB|NI", - irn_flags => "I", - reg_req => { out => [ "vfp_NOREG" ] }, + reg_req => { out => [ "vfp_NOREG:I" ] }, units => [], emit => "", mode => "mode_E", @@ -1248,8 +1237,7 @@ NoReg_VFP => { NoReg_XMM => { state => "pinned", op_flags => "c|NB|NI", - irn_flags => "I", - reg_req => { out => [ "xmm_NOREG" ] }, + reg_req => { out => [ "xmm_NOREG:I" ] }, units => [], emit => "", latency => 0, @@ -1259,8 +1247,7 @@ NoReg_XMM => { ChangeCW => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "fp_cw" ] }, + reg_req => { out => [ "fpcw:I" ] }, mode => $mode_fpcw, latency => 3, units => [ "GP" ], @@ -1270,7 +1257,7 @@ ChangeCW => { FldCW => { op_flags => "L|F", state => "pinned", - reg_req => { in => [ "gp", "gp", "none" ], out => [ "fp_cw" ] }, + reg_req => { in => [ "gp", "gp", "none" ], out => [ "fpcw:I" ] }, ins => [ "base", "index", "mem" ], latency => 5, emit => ". fldcw %AM", @@ -1365,10 +1352,10 @@ Lea => { Push => { state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "gp", "esp" ], out => [ "esp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "gp", "esp" ], out => [ "esp:I|S", "none" ] }, ins => [ "base", "index", "mem", "val", "stack" ], emit => '. push%M %unop3', - outs => [ "stack:I|S", "M" ], + outs => [ "stack", "M" ], am => "source,unary", latency => 2, units => [ "GP" ], @@ -1376,9 +1363,19 @@ Push => { Pop => { state => "exc_pinned", - reg_req => { in => [ "none", "esp" ], out => [ "gp", "none", "none", "esp" ] }, + reg_req => { in => [ "none", "esp" ], out => [ "gp", "none", "none", "esp:I|S" ] }, ins => [ "mem", "stack" ], - outs => [ "res", "M", "unused", "stack:I|S" ], + outs => [ "res", "M", "unused", "stack" ], + emit => '. pop%M %D0', + latency => 3, # Pop is more expensive than Push on Athlon + units => [ "GP" ], +}, + +PopEbp => { + state => "exc_pinned", + reg_req => { in => [ "none", "esp" ], out => [ "ebp:I", "none", "none", "esp:I|S" ] }, + ins => [ "mem", "stack" ], + outs => [ "res", "M", "unused", "stack" ], emit => '. pop%M %D0', latency => 3, # Pop is more expensive than Push on Athlon units => [ "GP" ], @@ -1386,53 +1383,51 @@ Pop => { PopMem => { state => "exc_pinned", - reg_req => { in => [ "gp", "gp", "none", "esp" ], out => [ "none", "none", "none", "esp" ] }, + reg_req => { in => [ "gp", "gp", "none", "esp" ], out => [ "none", "none", "none", "esp:I|S" ] }, ins => [ "base", "index", "mem", "stack" ], - outs => [ "unused0", "M", "unused1", "stack:I|S" ], + outs => [ "unused0", "M", "unused1", "stack" ], emit => '. pop%M %AM', latency => 3, # Pop is more expensive than Push on Athlon units => [ "GP" ], }, Enter => { - reg_req => { in => [ "esp" ], out => [ "ebp", "esp", "none" ] }, + reg_req => { in => [ "esp" ], out => [ "ebp", "esp:I|S", "none" ] }, emit => '. enter', - outs => [ "frame:I", "stack:I|S", "M" ], + outs => [ "frame", "stack", "M" ], latency => 15, units => [ "GP" ], }, Leave => { - reg_req => { in => [ "ebp" ], out => [ "ebp", "esp" ] }, + reg_req => { in => [ "ebp" ], out => [ "ebp", "esp:I|S" ] }, emit => '. leave', - outs => [ "frame:I", "stack:I|S" ], + outs => [ "frame", "stack" ], latency => 3, units => [ "GP" ], }, AddSP => { - irn_flags => "I", state => "pinned", - reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "in_r4", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "esp:I|S", "none" ] }, ins => [ "base", "index", "mem", "stack", "size" ], am => "source,binary", emit => '. addl %binop', latency => 1, - outs => [ "stack:I|S", "M" ], + outs => [ "stack", "M" ], units => [ "GP" ], modified_flags => $status_flags }, SubSP => { -#irn_flags => "I", state => "pinned", - reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "in_r4", "gp", "none" ] }, + reg_req => { in => [ "gp", "gp", "none", "esp", "gp" ], out => [ "esp:I|S", "gp", "none" ] }, ins => [ "base", "index", "mem", "stack", "size" ], am => "source,binary", emit => ". subl %binop\n". ". movl %%esp, %D1", latency => 2, - outs => [ "stack:I|S", "addr", "M" ], + outs => [ "stack", "addr", "M" ], units => [ "GP" ], modified_flags => $status_flags }, @@ -1468,10 +1463,10 @@ Call => { state => "exc_pinned", reg_req => { in => [ "gp", "gp", "none", "gp", "esp", "fpcw", "eax", "ecx", "edx" ], - out => [ "esp", "fpcw", "none", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ] + out => [ "esp:I|S", "fpcw:I", "none", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ] }, ins => [ "base", "index", "mem", "addr", "stack", "fpcw", "eax", "ecx", "edx" ], - outs => [ "stack:I|S", "fpcw:I", "M", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ], + outs => [ "stack", "fpcw", "M", "eax", "ecx", "edx", "vf0", "vf1", "vf2", "vf3", "vf4", "vf5", "vf6", "vf7", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" ], attr_type => "ia32_call_attr_t", attr => "unsigned pop, ir_type *call_tp", am => "source,unary", @@ -2022,6 +2017,7 @@ vfisttp => { vfldz => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -2031,6 +2027,7 @@ vfldz => { vfld1 => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -2040,6 +2037,7 @@ vfld1 => { vfldpi => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -2049,6 +2047,7 @@ vfldpi => { vfldln2 => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -2058,6 +2057,7 @@ vfldln2 => { vfldlg2 => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -2067,6 +2067,7 @@ vfldlg2 => { vfldl2t => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", @@ -2076,6 +2077,7 @@ vfldl2t => { vfldl2e => { irn_flags => "R", reg_req => { out => [ "vfp" ] }, + outs => [ "res" ], latency => 4, units => [ "VFP" ], mode => "mode_E", diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 6fe28ab4b..00007f8a0 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -268,7 +268,7 @@ static ir_node *gen_Const(ir_node *node) mode); set_ia32_op_type(load, ia32_AddrModeS); set_ia32_am_sc(load, floatent); - set_ia32_flags(load, get_ia32_flags(load) | arch_irn_flags_rematerializable); + arch_irn_add_flags(load, arch_irn_flags_rematerializable); res = new_r_Proj(irg, block, load, mode_xmm, pn_ia32_xLoad_res); } } else { @@ -286,7 +286,7 @@ static ir_node *gen_Const(ir_node *node) load = new_rd_ia32_vfld(dbgi, irg, block, noreg, noreg, nomem, mode); set_ia32_op_type(load, ia32_AddrModeS); set_ia32_am_sc(load, floatent); - set_ia32_flags(load, get_ia32_flags(load) | arch_irn_flags_rematerializable); + arch_irn_add_flags(load, arch_irn_flags_rematerializable); res = new_r_Proj(irg, block, load, mode_vfp, pn_ia32_vfld_res); /* take the mode from the entity */ set_ia32_ls_mode(load, get_type_mode(get_entity_type(floatent))); @@ -1312,6 +1312,9 @@ static ir_node *transform_AM_mem(ir_graph *const irg, ir_node *const block, NEW_ARR_A(ir_node*, ins, arity + 1); + /* NOTE: This sometimes produces dead-code because the old sync in + * src_mem might not be used anymore, we should detect this case + * and kill the sync... */ for (i = arity - 1; i >= 0; --i) { ir_node *const pred = get_Sync_pred(src_mem, i); @@ -1905,7 +1908,10 @@ static ir_node *gen_Load(ir_node *node) set_address(new_node, &addr); if (get_irn_pinned(node) == op_pin_state_floats) { - add_ia32_flags(new_node, arch_irn_flags_rematerializable); + assert(pn_ia32_xLoad_res == pn_ia32_vfld_res + && pn_ia32_vfld_res == pn_ia32_Load_res + && pn_ia32_Load_res == pn_ia32_res); + arch_irn_add_flags(new_node, arch_irn_flags_rematerializable); } SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); @@ -2307,6 +2313,7 @@ static ir_node *gen_float_const_Store(ir_node *node, ir_node *cns) set_address(new_node, &addr); SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node)); + assert(i < 4); ins[i++] = new_node; size -= 4; @@ -2314,7 +2321,11 @@ static ir_node *gen_float_const_Store(ir_node *node, ir_node *cns) addr.offset += 4; } while (size != 0); - return i == 1 ? ins[0] : new_rd_Sync(dbgi, irg, new_block, i, ins); + if (i > 1) { + return new_rd_Sync(dbgi, irg, new_block, i, ins); + } else { + return ins[0]; + } } /** @@ -4286,7 +4297,7 @@ static ir_node *gen_be_Call(ir_node *node) static ir_node *gen_be_IncSP(ir_node *node) { ir_node *res = be_duplicate_node(node); - be_node_add_flags(res, -1, arch_irn_flags_modify_flags); + arch_irn_add_flags(res, arch_irn_flags_modify_flags); return res; } @@ -4381,17 +4392,17 @@ static ir_node *gen_Proj_be_Call(ir_node *node) proj = pn_ia32_Call_M; } else { arch_register_req_t const *const req = arch_get_register_req_out(node); - int const n_outs = get_ia32_n_res(new_call); + int const n_outs = arch_irn_get_n_outs(new_call); int i; assert(proj >= pn_be_Call_first_res); - assert(req->type == arch_register_req_type_limited); + assert(req->type & arch_register_req_type_limited); for (i = 0; i < n_outs; ++i) { arch_register_req_t const *const new_req = get_ia32_out_req(new_call, i); - if (new_req->type != arch_register_req_type_limited || - new_req->cls != req->cls || + if (!(new_req->type & arch_register_req_type_limited) || + new_req->cls != req->cls || *new_req->limited != *req->limited) continue; @@ -4466,7 +4477,7 @@ static ir_node *gen_Proj_ASM(ir_node *node) new_pred = be_transform_node(pred); block = get_nodes_block(new_pred); return new_r_Proj(current_ir_graph, block, new_pred, mode_M, - get_ia32_n_res(new_pred) + 1); + arch_irn_get_n_outs(new_pred) + 1); } /** @@ -4682,7 +4693,7 @@ static void add_missing_keep_walker(ir_node *node, void *data) if (!is_ia32_irn(node)) return; - n_outs = get_ia32_n_res(node); + n_outs = arch_irn_get_n_outs(node); if (n_outs <= 0) return; if (is_ia32_SwitchJmp(node)) diff --git a/ir/be/ia32/ia32_x87.c b/ir/be/ia32/ia32_x87.c index 17c1fa40b..22ffaa886 100644 --- a/ir/be/ia32/ia32_x87.c +++ b/ir/be/ia32/ia32_x87.c @@ -450,6 +450,15 @@ static inline const arch_register_t *x87_get_irn_register(const ir_node *irn) return res; } /* x87_get_irn_register */ +static inline const arch_register_t *x87_irn_get_register(const ir_node *irn, + int pos) +{ + const arch_register_t *res = arch_irn_get_register(irn, pos); + + assert(res->reg_class->regs == ia32_vfp_regs); + return res; +} + /* -------------- x87 perm --------------- */ /** @@ -926,7 +935,7 @@ static int sim_binop(x87_state *state, ir_node *n, const exchange_tmpl *tmpl) ir_node *op2 = get_irn_n(n, n_ia32_binary_right); const arch_register_t *op1_reg = x87_get_irn_register(op1); const arch_register_t *op2_reg = x87_get_irn_register(op2); - const arch_register_t *out = x87_get_irn_register(n); + const arch_register_t *out = x87_irn_get_register(n, pn_ia32_res); int reg_index_1 = arch_register_get_index(op1_reg); int reg_index_2 = arch_register_get_index(op2_reg); vfp_liveness live = vfp_live_args_after(sim, n, REGMASK(out)); @@ -1144,14 +1153,14 @@ static int sim_unop(x87_state *state, ir_node *n, ir_op *op) * * @return NO_NODE_ADDED */ -static int sim_load(x87_state *state, ir_node *n, ir_op *op) +static int sim_load(x87_state *state, ir_node *n, ir_op *op, int res_pos) { - const arch_register_t *out = x87_get_irn_register(n); + const arch_register_t *out = x87_irn_get_register(n, res_pos); ia32_x87_attr_t *attr; DB((dbg, LEVEL_1, ">>> %+F -> %s\n", n, arch_register_get_name(out))); x87_push(state, arch_register_get_index(out), x87_patch_insn(n, op)); - assert(out == x87_get_irn_register(n)); + assert(out == x87_irn_get_register(n, res_pos)); attr = get_ia32_x87_attr(n); attr->x87[2] = out = &ia32_st_regs[0]; DB((dbg, LEVEL_1, "<<< %s -> %s\n", get_irn_opname(n), arch_register_get_name(out))); @@ -1320,13 +1329,11 @@ static int sim_##op(x87_state *state, ir_node *n) { \ #define GEN_BINOP(op) _GEN_BINOP(op, op) #define GEN_BINOPR(op) _GEN_BINOP(op, op##r) -#define GEN_LOAD2(op, nop) \ -static int sim_##op(x87_state *state, ir_node *n) { \ - return sim_load(state, n, op_ia32_##nop); \ +#define GEN_LOAD(op) \ +static int sim_##op(x87_state *state, ir_node *n) { \ + return sim_load(state, n, op_ia32_##op, pn_ia32_v##op##_res); \ } -#define GEN_LOAD(op) GEN_LOAD2(op, op) - #define GEN_UNOP(op) \ static int sim_##op(x87_state *state, ir_node *n) { \ return sim_unop(state, n, op_ia32_##op); \ @@ -2001,7 +2008,7 @@ end_call: */ static int sim_Spill(x87_state *state, ir_node *n) { - assert(0 && "Spill not lowered"); + panic("Spill not lowered"); return sim_fst(state, n); } /* sim_Spill */ @@ -2015,7 +2022,7 @@ static int sim_Spill(x87_state *state, ir_node *n) */ static int sim_Reload(x87_state *state, ir_node *n) { - assert(0 && "Reload not lowered"); + panic("Reload not lowered"); return sim_fld(state, n); } /* sim_Reload */ diff --git a/ir/be/mips/bearch_mips.c b/ir/be/mips/bearch_mips.c index d5d9ef8ed..06f289bd8 100644 --- a/ir/be/mips/bearch_mips.c +++ b/ir/be/mips/bearch_mips.c @@ -157,33 +157,6 @@ static void mips_set_irn_reg(ir_node *irn, const arch_register_t *reg) } } -static const arch_register_t *mips_get_irn_reg(const ir_node *irn) -{ - int pos = 0; - const arch_register_t *reg = NULL; - - if (is_Proj(irn)) { - - if (get_irn_mode(irn) == mode_X) { - return NULL; - } - - pos = mips_translate_proj_pos(irn); - irn = skip_Proj_const(irn); - } - - if (is_mips_irn(irn)) { - const arch_register_t **slots; - slots = get_mips_slots(irn); - reg = slots[pos]; - } - else { - reg = mips_get_firm_reg(irn, cur_reg_set); - } - - return reg; -} - static arch_irn_class_t mips_classify(const ir_node *irn) { irn = skip_Proj_const(irn); @@ -195,16 +168,6 @@ static arch_irn_class_t mips_classify(const ir_node *irn) return 0; } -static arch_irn_flags_t mips_get_flags(const ir_node *irn) -{ - irn = skip_Proj_const(irn); - - if (!is_mips_irn(irn)) - return 0; - - return get_mips_flags(irn); -} - int mips_is_Load(const ir_node *node) { return is_mips_lw(node) || is_mips_lh(node) || is_mips_lhu(node) || @@ -277,10 +240,7 @@ static int mips_get_sp_bias(const ir_node *irn) static const arch_irn_ops_t mips_irn_ops = { mips_get_irn_reg_req, - mips_set_irn_reg, - mips_get_irn_reg, mips_classify, - mips_get_flags, mips_get_frame_entity, mips_set_frame_entity, mips_set_frame_offset, @@ -558,7 +518,7 @@ static const arch_register_t *mips_abi_prologue(void *self, ir_node** mem, pmap sp = new_rd_mips_addu(NULL, irg, block, sp, mips_create_Immediate(initialstackframesize)); mips_set_irn_reg(sp, &mips_gp_regs[REG_SP]); - set_mips_flags(sp, arch_irn_flags_ignore); + panic("FIXME Use IncSP or set register requirement with ignore"); /* TODO: where to get an edge with a0-a3 int i; @@ -596,7 +556,7 @@ static const arch_register_t *mips_abi_prologue(void *self, ir_node** mem, pmap sp = new_rd_mips_addu(NULL, irg, block, sp, mips_create_Immediate(-initialstackframesize)); mips_set_irn_reg(sp, &mips_gp_regs[REG_SP]); - set_mips_flags(sp, arch_irn_flags_ignore); + panic("FIXME Use IncSP or set register requirement with ignore"); reg = be_abi_reg_map_get(reg_map, &mips_gp_regs[REG_FP]); store = new_rd_mips_sw(NULL, irg, block, sp, reg, *mem, NULL, 0); @@ -608,7 +568,7 @@ static const arch_register_t *mips_abi_prologue(void *self, ir_node** mem, pmap fp = new_rd_mips_addu(NULL, irg, block, sp, mips_create_Immediate(-initialstackframesize)); mips_set_irn_reg(fp, &mips_gp_regs[REG_FP]); - set_mips_flags(fp, arch_irn_flags_ignore); + panic("FIXME Use IncSP or set register requirement with ignore"); be_abi_reg_map_set(reg_map, &mips_gp_regs[REG_FP], fp); be_abi_reg_map_set(reg_map, &mips_gp_regs[REG_SP], sp); @@ -630,12 +590,12 @@ static void mips_abi_epilogue(void *self, ir_node *block, ir_node **mem, pmap *r // copy fp to sp sp = new_rd_mips_or(NULL, irg, block, fp, mips_create_zero()); mips_set_irn_reg(sp, &mips_gp_regs[REG_SP]); - set_mips_flags(sp, arch_irn_flags_ignore); + panic("FIXME Use be_Copy or set register requirement with ignore"); // 1. restore fp load = new_rd_mips_lw(NULL, irg, block, sp, *mem, NULL, fp_save_offset - initial_frame_size); - set_mips_flags(load, arch_irn_flags_ignore); + panic("FIXME register requirement with ignore"); fp = new_r_Proj(irg, block, load, mode_Iu, pn_mips_lw_res); *mem = new_r_Proj(irg, block, load, mode_Iu, pn_mips_lw_M); @@ -847,6 +807,7 @@ static int mips_is_valid_clobber(const void *self, const char *clobber) const arch_isa_if_t mips_isa_if = { mips_init, mips_done, + NULL, /* handle intrinsics */ mips_get_n_reg_class, mips_get_reg_class, mips_get_reg_class_for_mode, diff --git a/ir/be/mips/mips_new_nodes.c b/ir/be/mips/mips_new_nodes.c index e88434e7c..6c3766778 100644 --- a/ir/be/mips/mips_new_nodes.c +++ b/ir/be/mips/mips_new_nodes.c @@ -222,9 +222,6 @@ static int mips_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { if (attr->flags & arch_irn_flags_rematerializable) { fprintf(F, " remat"); } - if (attr->flags & arch_irn_flags_ignore) { - fprintf(F, " ignore"); - } } fprintf(F, " (%d)\n", attr->flags); diff --git a/ir/be/mips/mips_spec.pl b/ir/be/mips/mips_spec.pl index 2cc8789b8..c1dfb2d13 100644 --- a/ir/be/mips/mips_spec.pl +++ b/ir/be/mips/mips_spec.pl @@ -7,88 +7,6 @@ $arch = "mips"; $new_emit_syntax = 1; -# The node description is done as a perl hash initializer with the -# following structure: -# -# %nodes = ( -# -# => { -# op_flags => "N|L|C|X|I|F|Y|H|c|K", -# "arity" => "0|1|2|3 ... |variable|dynamic|any", -# "state" => "floats|pinned|mem_pinned|exc_pinned", -# "args" => [ -# { "type" => "type 1", "name" => "name 1" }, -# { "type" => "type 2", "name" => "name 2" }, -# ... -# ], -# comment => "any comment for constructor", -# reg_req => { in => [ "reg_class|register" ], out => [ "reg_class|register|in_rX" ] }, -# cmp_attr => "c source code for comparing node attributes", -# outs => { "out1", "out2" } # optional, creates pn_op_out1, ... consts -# ins => { "in1", "in2" } # optional, creates n_op_in1, ... consts -# mode => "mode_Iu" # optional, predefines the mode -# emit => "emit code with templates", -# attr => "attitional attribute arguments for constructor", -# init_attr => "emit attribute initialization template", -# rd_constructor => "c source code which constructs an ir_node", -# hash_func => "name of the hash function for this operation", -# latency => "latency of this operation (can be float)" -# attr_type => "name of the attribute struct", -# }, -# -# ... # (all nodes you need to describe) -# -# ); # close the %nodes initializer - -# op_flags: flags for the operation, OPTIONAL (default is "N") -# the op_flags correspond to the firm irop_flags: -# N irop_flag_none -# L irop_flag_labeled -# C irop_flag_commutative -# X irop_flag_cfopcode -# I irop_flag_ip_cfopcode -# F irop_flag_fragile -# Y irop_flag_forking -# H irop_flag_highlevel -# c irop_flag_constlike -# K irop_flag_keep -# -# R rematerializeable -# N not spillable -# I ignore for register allocation -# -# state: state of the operation, OPTIONAL (default is "floats") -# -# arity: arity of the operation, MUST NOT BE OMITTED -# -# args: the OPTIONAL arguments of the node constructor (debug, irg and block -# are always the first 3 arguments and are always autmatically -# created) -# If this key is missing the following arguments will be created: -# for i = 1 .. arity: ir_node *op_i -# ir_mode *mode -# -# outs: if a node defines more than one output, the names of the projections -# nodes having outs having automatically the mode mode_T -# -# comment: OPTIONAL comment for the node constructor -# -# rd_constructor: for every operation there will be a -# new_rd__ function with the arguments from above -# which creates the ir_node corresponding to the defined operation -# you can either put the complete source code of this function here -# -# This key is OPTIONAL. If omitted, the following constructor will -# be created: -# if (!op__) assert(0); -# for i = 1 to arity -# set in[i] = op_i -# done -# res = new_ir_node(db, irg, block, op__, mode, arity, in) -# return res -# -# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3 - # register types: # 0 - no special type # 1 - caller save (register must be saved by the caller of a function) @@ -187,8 +105,7 @@ $mode_gp = "mode_Iu"; Immediate => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "gp_NOREG" ] }, + reg_req => { out => [ "gp_NOREG:I" ] }, attr => "mips_immediate_type_t imm_type, ir_entity *entity, long val", attr_type => "mips_immediate_attr_t", mode => $mode_gp, @@ -353,8 +270,7 @@ mfhi => { zero => { state => "pinned", op_flags => "c", - irn_flags => "I", - reg_req => { out => [ "zero" ] }, + reg_req => { out => [ "zero:I" ] }, emit => '', mode => $mode_gp }, diff --git a/ir/be/ppc32/bearch_ppc32.c b/ir/be/ppc32/bearch_ppc32.c index 707c0381f..1a5daee57 100644 --- a/ir/be/ppc32/bearch_ppc32.c +++ b/ir/be/ppc32/bearch_ppc32.c @@ -137,59 +137,6 @@ static const arch_register_req_t *ppc32_get_irn_reg_req(const ir_node *irn, return arch_no_register_req; } -static void ppc32_set_irn_reg(ir_node *irn, const arch_register_t *reg) -{ - int pos = 0; - - if (is_Proj(irn)) { - - if (get_irn_mode(irn) == mode_X) { - return; - } - - pos = ppc32_translate_proj_pos(irn); - irn = skip_Proj(irn); - } - - if (is_ppc32_irn(irn)) { - const arch_register_t **slots; - - slots = get_ppc32_slots(irn); - slots[pos] = reg; - } - else { - /* here we set the registers for the Phi nodes */ - ppc32_set_firm_reg(irn, reg, cur_reg_set); - } -} - -static const arch_register_t *ppc32_get_irn_reg(const ir_node *irn) -{ - int pos = 0; - const arch_register_t *reg = NULL; - - if (is_Proj(irn)) { - - if (get_irn_mode(irn) == mode_X) { - return NULL; - } - - pos = ppc32_translate_proj_pos(irn); - irn = skip_Proj_const(irn); - } - - if (is_ppc32_irn(irn)) { - const arch_register_t **slots; - slots = get_ppc32_slots(irn); - reg = slots[pos]; - } - else { - reg = ppc32_get_firm_reg(irn, cur_reg_set); - } - - return reg; -} - static arch_irn_class_t ppc32_classify(const ir_node *irn) { irn = skip_Proj_const(irn); @@ -201,20 +148,6 @@ static arch_irn_class_t ppc32_classify(const ir_node *irn) return 0; } -static arch_irn_flags_t ppc32_get_flags(const ir_node *irn) -{ - irn = skip_Proj_const(irn); - - if (is_ppc32_irn(irn)) { - return get_ppc32_flags(irn); - } - else if (is_Unknown(irn)) { - return arch_irn_flags_ignore; - } - - return 0; -} - static ir_entity *ppc32_get_frame_entity(const ir_node *irn) { if(!is_ppc32_irn(irn)) return NULL; @@ -359,10 +292,7 @@ static const be_abi_callbacks_t ppc32_abi_callbacks = { static const arch_irn_ops_t ppc32_irn_ops = { ppc32_get_irn_reg_req, - ppc32_set_irn_reg, - ppc32_get_irn_reg, ppc32_classify, - ppc32_get_flags, ppc32_get_frame_entity, ppc32_set_frame_entity, ppc32_set_stack_bias, @@ -921,6 +851,7 @@ static int ppc32_is_valid_clobber(const void *self, const char *clobber) const arch_isa_if_t ppc32_isa_if = { ppc32_init, ppc32_done, + NULL, /* handle intrinsics */ ppc32_get_n_reg_class, ppc32_get_reg_class, ppc32_get_reg_class_for_mode, diff --git a/ir/be/ppc32/ppc32_new_nodes.c b/ir/be/ppc32/ppc32_new_nodes.c index aeb2d1f83..4ae904bd9 100644 --- a/ir/be/ppc32/ppc32_new_nodes.c +++ b/ir/be/ppc32/ppc32_new_nodes.c @@ -205,9 +205,6 @@ static int ppc32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { if (attr->flags & arch_irn_flags_rematerializable) { fprintf(F, " remat"); } - if (attr->flags & arch_irn_flags_ignore) { - fprintf(F, " ignore"); - } } fprintf(F, " (%d)\n", attr->flags); diff --git a/ir/be/ppc32/ppc32_spec.pl b/ir/be/ppc32/ppc32_spec.pl index a492fc0e6..ec2d5c44b 100644 --- a/ir/be/ppc32/ppc32_spec.pl +++ b/ir/be/ppc32/ppc32_spec.pl @@ -7,91 +7,6 @@ $arch = "ppc32"; $new_emit_syntax = 1; -# The node description is done as a perl hash initializer with the -# following structure: -# -# %nodes = ( -# -# => { -# "op_flags" => "N|L|C|X|I|F|Y|H|c|K", -# "irn_flags" => "R|N|I" -# "arity" => "0|1|2|3 ... |variable|dynamic|any", -# "state" => "floats|pinned|mem_pinned|exc_pinned", -# "args" => [ -# { "type" => "type 1", "name" => "name 1" }, -# { "type" => "type 2", "name" => "name 2" }, -# ... -# ], -# comment => "any comment for constructor", -# reg_req => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] }, -# cmp_attr => "c source code for comparing node attributes", -# outs => { "out1", "out2" } # optional, creates pn_op_out1, ... consts -# ins => { "in1", "in2" } # optional, creates n_op_in1, ... consts -# mode => "mode_Iu" # optional, predefines the mode -# emit => "emit code with templates", -# attr => "attitional attribute arguments for constructor", -# init_attr => "emit attribute initialization template", -# rd_constructor => "c source code which constructs an ir_node", -# hash_func => "name of the hash function for this operation", -# latency => "latency of this operation (can be float)" -# attr_type => "name of the attribute struct", -# }, -# -# ... # (all nodes you need to describe) -# -# ); # close the %nodes initializer - -# op_flags: flags for the operation, OPTIONAL (default is "N") -# the op_flags correspond to the firm irop_flags: -# N irop_flag_none -# L irop_flag_labeled -# C irop_flag_commutative -# X irop_flag_cfopcode -# I irop_flag_ip_cfopcode -# F irop_flag_fragile -# Y irop_flag_forking -# H irop_flag_highlevel -# c irop_flag_constlike -# K irop_flag_keep -# -# irn_flags: special node flags, OPTIONAL (default is 0) -# following irn_flags are supported: -# R rematerializeable -# N not spillable -# I ignore for register allocation -# -# state: state of the operation, OPTIONAL (default is "floats") -# -# arity: arity of the operation, MUST NOT BE OMITTED -# -# args: the OPTIONAL arguments of the node constructor (debug, irg and block -# are always the first 3 arguments and are always autmatically -# created) -# If this key is missing the following arguments will be created: -# for i = 1 .. arity: ir_node *op_i -# ir_mode *mode -# -# outs: if a node defines more than one output, the names of the projections -# nodes having outs having automatically the mode mode_T -# -# comment: OPTIONAL comment for the node constructor -# -# rd_constructor: for every operation there will be a -# new_rd__ function with the arguments from above -# which creates the ir_node corresponding to the defined operation -# you can either put the complete source code of this function here -# -# This key is OPTIONAL. If omitted, the following constructor will -# be created: -# if (!op__) assert(0); -# for i = 1 to arity -# set in[i] = op_i -# done -# res = new_ir_node(db, irg, block, op__, mode, arity, in) -# return res -# -# NOTE: rd_constructor and args are only optional if and only if arity is 0,1,2 or 3 - # register types: # 0 - no special type # 1 - caller save (register must be saved by the caller of a function) diff --git a/ir/be/scripts/generate_new_opcodes.pl b/ir/be/scripts/generate_new_opcodes.pl index 1a634a6e3..2597c808e 100755 --- a/ir/be/scripts/generate_new_opcodes.pl +++ b/ir/be/scripts/generate_new_opcodes.pl @@ -487,10 +487,8 @@ foreach my $op (keys(%nodes)) { $temp .= "\tflags |= arch_irn_flags_rematerializable;\n"; } elsif ($flag eq "N") { $temp .= "\tflags |= arch_irn_flags_dont_spill;\n"; - } elsif ($flag eq "I") { - $temp .= "\tflags |= arch_irn_flags_ignore;\n"; - } elsif ($flag eq "S") { - $temp .= "\tflags |= arch_irn_flags_modify_sp;\n"; + } else { + die "Fatal error: unknown flag $flag for ${op}\n"; } } $temp .= "\n"; @@ -513,33 +511,6 @@ foreach my $op (keys(%nodes)) { } $temp .= "\n"; - # set flags for outs - if (exists($n{"outs"})) { - undef my @outs; - @outs = @{ $n{"outs"} }; - - for (my $idx = 0; $idx <= $#outs; $idx++) { - # check, if we have additional flags annotated to out - if ($outs[$idx] =~ /:((S|I)(\|(S|I))*)/) { - my $flag_string = $1; - my $prefix = ""; - my $flags = ""; - - foreach my $flag (split(/\|/, $flag_string)) { - if ($flag eq "I") { - $flags .= $prefix."arch_irn_flags_ignore"; - $prefix = " | "; - } elsif ($flag eq "S") { - $flags .= $prefix."arch_irn_flags_modify_sp"; - $prefix = " | "; - } - } - - $temp .= "\tset_$arch\_out_flags(res, $flags, $idx);\n"; - } - } - } - if (exists($n{"init_attr"})) { $temp .= "\tattr = get_irn_generic_attr(res);\n"; $temp .= "\t".$n{"init_attr"}."\n"; @@ -899,6 +870,7 @@ TP_SEARCH: foreach my $cur_type (keys(%cpu)) { sub mangle_requirements { my $reqs = shift; my $class = shift; + my $flags = shift; my @alternatives = split(/ /, $reqs); for(my $idx = 0; $idx < scalar(@alternatives); $idx++) { @@ -908,6 +880,10 @@ sub mangle_requirements { @alternatives = sort @alternatives; my $name = $class."_".join('_', @alternatives); + if (defined($flags)) { + $flags =~ s/\|/_/g; + $name .= "_$flags"; + } return $name; } @@ -961,13 +937,14 @@ sub build_inout_idx_class { for (my $idx = 0; $idx <= $#reqs; $idx++) { my $class = undef; + my ($req,) = split(/:/, $reqs[$idx]); - if ($reqs[$idx] eq "none") { + if ($req eq "none") { $class = "none"; - } elsif (is_reg_class($reqs[$idx])) { - $class = $reqs[$idx]; + } elsif (is_reg_class($req)) { + $class = $req; } else { - my @regs = split(/ /, $reqs[$idx]); + my @regs = split(/ /, $req); GET_CLASS: foreach my $reg (@regs) { if ($reg =~ /!?(in|out)\_r\d+/ || $reg =~ /!in/) { $class = "UNKNOWN_CLASS"; @@ -1015,6 +992,7 @@ sub build_subset_class_func { my $idx = shift; my $is_in = shift; my @regs = split(/ /, shift); + my $flags = shift; my @idx_class = build_inout_idx_class($node, $op, !$is_in); @@ -1165,7 +1143,7 @@ CHECK_REQS: foreach (@regs) { # Generate register requirements structure ### sub generate_requirements { - my $reqs = shift; + my ($reqs, $flags) = split(/:/, shift); my $node = shift; my $op = shift; my $idx = shift; @@ -1173,6 +1151,17 @@ sub generate_requirements { my $class = ""; my $result; + my @req_type_mask; + if (defined($flags)) { + foreach my $f (split(/|/, $flags)) { + if ($f eq "I") { + push(@req_type_mask, "arch_register_req_type_ignore"); + } elsif ($f eq "S") { + push(@req_type_mask, "arch_register_req_type_produces_sp"); + } + } + } + if ($reqs eq "none") { $result = <in[i], NULL, irg); hook_new_node(irg, res); + if (get_irg_phase_state(irg) == phase_backend) { + be_info_new_node(res); + } return res; } diff --git a/ir/ir/irtypes.h b/ir/ir/irtypes.h index 79a27197d..4dbae00f9 100644 --- a/ir/ir/irtypes.h +++ b/ir/ir/irtypes.h @@ -370,6 +370,7 @@ struct ir_node { /* ------- For analyses -------- */ ir_loop *loop; /**< the loop the node is in. Access routines in irloop.h */ struct ir_node **deps; /**< Additional dependencies induced by state. */ + void *backend_info; irn_edges_info_t edge_info; /**< Everlasting out edges. */ /* ------- Opcode depending fields -------- */ attr attr; /**< The set of attributes of this node. Depends on opcode. -- 2.20.1