From 8535fe8732b0acf822be252812a7158ce5b8134a Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Mon, 19 Mar 2007 17:05:21 +0000 Subject: [PATCH] The big committ: - Replace limit callback in register requirements with a simple bitset - Fix backends, generators and the rest of the code for the change register requirements structure - Eliminated the custom register_requirement structures in the backend, they are pointless now, use the normal arch_register_req_t - Fix TEMPLATE backend - Extract emitter framework from ia32 and provide generic header/code for it - Port TEMPLATE backend to new emitter - Extract gas specific emit stuff (declarations, sections) from ia32 backend and provide it as generic header/code. Make TEMPLATE backend use that - Remove several FIRM_DBG_REGISTERs from functions which are called very often. Before we had millions of string hashtable lookups because of that. The prefered way is to have 1 static debug module per file and initialize it in the module constructor. No passing around in environment structs and in no case should you dynamically register it in single functions. --- ir/be/TEMPLATE/TEMPLATE_emitter.c | 293 +++----- ir/be/TEMPLATE/TEMPLATE_emitter.h | 12 +- ir/be/TEMPLATE/TEMPLATE_gen_decls.c | 607 ---------------- ir/be/TEMPLATE/TEMPLATE_gen_decls.h | 9 - ir/be/TEMPLATE/TEMPLATE_new_nodes.c | 90 ++- ir/be/TEMPLATE/TEMPLATE_new_nodes.h | 12 +- ir/be/TEMPLATE/TEMPLATE_nodes_attr.h | 11 +- ir/be/TEMPLATE/TEMPLATE_spec.pl | 528 +++++++------- ir/be/TEMPLATE/TEMPLATE_transform.c | 16 - ir/be/TEMPLATE/bearch_TEMPLATE.c | 155 ++-- ir/be/TEMPLATE/bearch_TEMPLATE_t.h | 10 +- ir/be/arm/arm_emitter.c | 3 +- ir/be/arm/arm_new_nodes.c | 200 +++--- ir/be/arm/arm_new_nodes.h | 18 +- ir/be/arm/arm_nodes_attr.h | 11 +- ir/be/arm/bearch_arm.c | 133 ++-- ir/be/be_t.h | 1 - ir/be/beabi.c | 52 +- ir/be/bearch.c | 218 +++--- ir/be/bearch.h | 322 +++++---- ir/be/beblocksched.c | 31 +- ir/be/bechordal.c | 353 +++++----- ir/be/becopyheur.c | 11 +- ir/be/becopyheur2.c | 52 +- ir/be/becopyheur3.c | 25 +- ir/be/becopyilp.c | 8 +- ir/be/becopyilp2.c | 15 +- ir/be/becopyopt.c | 93 +-- ir/be/becopyopt_t.h | 7 +- ir/be/beemitter.c | 95 +++ ir/be/beemitter.h | 58 ++ ir/be/{ia32/ia32_gen_decls.c => begnuas.c} | 101 ++- ir/be/begnuas.h | 41 ++ ir/be/beilpsched.c | 1 + ir/be/beinsn.c | 43 +- ir/be/beinsn_t.h | 33 +- ir/be/beirgmod.c | 17 +- ir/be/belistsched.c | 19 +- ir/be/belive.c | 29 +- ir/be/belive_t.h | 1 - ir/be/beloopana.c | 35 +- ir/be/belower.c | 19 +- ir/be/bemodule.c | 12 +- ir/be/benode.c | 413 +++++------ ir/be/beraextern.c | 38 +- ir/be/bespillbelady.c | 7 +- ir/be/bespillmorgan.c | 6 +- ir/be/bespillremat.c | 8 +- ir/be/bespillslots.c | 9 +- ir/be/bestabs.c | 3 +- ir/be/beuses.c | 2 +- ir/be/ia32/bearch_ia32.c | 141 ++-- ir/be/ia32/bearch_ia32_t.h | 3 +- ir/be/ia32/ia32_emitter.c | 777 +++++++++------------ ir/be/ia32/ia32_emitter.h | 57 +- ir/be/ia32/ia32_finish.c | 41 +- ir/be/ia32/ia32_gen_decls.h | 17 - ir/be/ia32/ia32_new_nodes.c | 96 +-- ir/be/ia32/ia32_new_nodes.h | 23 +- ir/be/ia32/ia32_nodes_attr.h | 10 +- ir/be/ia32/ia32_spec.pl | 11 +- ir/be/mips/bearch_mips.c | 93 +-- ir/be/mips/mips_new_nodes.c | 76 +- ir/be/mips/mips_new_nodes.h | 16 +- ir/be/mips/mips_nodes_attr.h | 11 +- ir/be/mips/mips_spec.pl | 80 +-- ir/be/ppc32/bearch_ppc32.c | 81 +-- ir/be/ppc32/ppc32_new_nodes.c | 76 +- ir/be/ppc32/ppc32_new_nodes.h | 14 +- ir/be/ppc32/ppc32_nodes_attr.h | 10 +- ir/be/ppc32/ppc32_transform.c | 6 +- ir/be/scripts/generate_emitter.pl | 2 +- ir/be/scripts/generate_emitter_new.pl | 19 +- ir/be/scripts/generate_machine.pl | 2 +- ir/be/scripts/generate_new_opcodes.pl | 57 +- ir/be/scripts/generate_regalloc_if.pl | 311 ++++----- 76 files changed, 2622 insertions(+), 3694 deletions(-) delete mode 100644 ir/be/TEMPLATE/TEMPLATE_gen_decls.c delete mode 100644 ir/be/TEMPLATE/TEMPLATE_gen_decls.h create mode 100644 ir/be/beemitter.c create mode 100644 ir/be/beemitter.h rename ir/be/{ia32/ia32_gen_decls.c => begnuas.c} (88%) create mode 100644 ir/be/begnuas.h delete mode 100644 ir/be/ia32/ia32_gen_decls.h diff --git a/ir/be/TEMPLATE/TEMPLATE_emitter.c b/ir/be/TEMPLATE/TEMPLATE_emitter.c index 010e6d336..28c5c4b29 100644 --- a/ir/be/TEMPLATE/TEMPLATE_emitter.c +++ b/ir/be/TEMPLATE/TEMPLATE_emitter.c @@ -26,52 +26,20 @@ #define SNPRINTF_BUF_LEN 128 -static const arch_env_t *arch_env = NULL; - - -/************************************************************* - * _ _ __ _ _ - * (_) | | / _| | | | | - * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ - * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| - * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | - * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| - * | | | | - * |_| |_| - *************************************************************/ - -/** - * Return a const or symconst as string. - */ -static const char *node_const_to_str(ir_node *n) { - /* TODO */ -} - -/** - * Returns node's offset as string. - */ -static char *node_offset_to_str(ir_node *n) { - /* TODO */ -} - -/* We always pass the ir_node which is a pointer. */ -static int TEMPLATE_get_arg_type(const lc_arg_occ_t *occ) { - return lc_arg_type_ptr; -} - - /** * Returns the register at in position pos. */ -static const arch_register_t *get_in_reg(ir_node *irn, int pos) { +static const arch_register_t *get_in_reg(const arch_env_t *arch_env, + const ir_node *node, int pos) +{ ir_node *op; const arch_register_t *reg = NULL; - assert(get_irn_arity(irn) > pos && "Invalid IN position"); + assert(get_irn_arity(node) > pos && "Invalid IN position"); /* The out register of the operator at position pos is the in register we need. */ - op = get_irn_n(irn, pos); + op = get_irn_n(node, pos); reg = arch_get_irn_register(arch_env, op); @@ -82,7 +50,9 @@ static const arch_register_t *get_in_reg(ir_node *irn, int pos) { /** * Returns the register at out position pos. */ -static const arch_register_t *get_out_reg(ir_node *irn, int pos) { +static const arch_register_t *get_out_reg(const arch_env_t *arch_env, + const ir_node *node, int pos) +{ ir_node *proj; const arch_register_t *reg = NULL; @@ -91,16 +61,14 @@ static const arch_register_t *get_out_reg(ir_node *irn, int pos) { /* 2nd case: irn is of mode_T -> collect all Projs and ask the */ /* Proj with the corresponding projnum for the register */ - if (get_irn_mode(irn) != mode_T) { - reg = arch_get_irn_register(arch_env, irn); - } - else if (is_TEMPLATE_irn(irn)) { - reg = get_TEMPLATE_out_reg(irn, pos); - } - else { + if (get_irn_mode(node) != mode_T) { + reg = arch_get_irn_register(arch_env, node); + } else if (is_TEMPLATE_irn(node)) { + reg = get_TEMPLATE_out_reg(node, pos); + } else { const ir_edge_t *edge; - foreach_out_edge(irn, edge) { + foreach_out_edge(node, edge) { proj = get_edge_src_irn(edge); assert(is_Proj(proj) && "non-Proj from mode_T node"); if (get_Proj_proj(proj) == pos) { @@ -114,148 +82,43 @@ static const arch_register_t *get_out_reg(ir_node *irn, int pos) { return reg; } -/** - * Returns the number of the in register at position pos. - */ -int get_TEMPLATE_reg_nr(ir_node *irn, int pos, int in_out) { - const arch_register_t *reg; - - if (in_out == 1) { - reg = get_in_reg(irn, pos); - } - else { - reg = get_out_reg(irn, pos); - } - - return arch_register_get_index(reg); -} - -/** - * Returns the name of the in register at position pos. - */ -const char *get_TEMPLATE_reg_name(ir_node *irn, int pos, int in_out) { - const arch_register_t *reg; - - if (in_out == 1) { - reg = get_in_reg(irn, pos); - } - else { - reg = get_out_reg(irn, pos); - } - - return arch_register_get_name(reg); -} +/************************************************************* + * _ _ __ _ _ + * (_) | | / _| | | | | + * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ + * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| + * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | + * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| + * | | | | + * |_| |_| + *************************************************************/ -/** - * Get the register name for a node. - */ -static int TEMPLATE_get_reg_name(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +void TEMPLATE_emit_immediate(TEMPLATE_emit_env_t *env, const ir_node *node) { - const char *buf; - ir_node *X = arg->v_ptr; - int nr = occ->width - 1; - - if (!X) - return lc_arg_append(app, occ, "(null)", 6); - - if (occ->conversion == 'S') { - buf = get_TEMPLATE_reg_name(X, nr, 1); - } - else { /* 'D' */ - buf = get_TEMPLATE_reg_name(X, nr, 0); - } - - return buf ? lc_arg_append(app, occ, buf, strlen(buf)) : 0; + /* TODO */ } -/** - * Returns the tarval or offset of an TEMPLATE node as a string. - */ -static int TEMPLATE_const_to_str(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +void TEMPLATE_emit_source_register(TEMPLATE_emit_env_t *env, const ir_node *node, int pos) { - const char *buf; - ir_node *X = arg->v_ptr; - - if (!X) - return lc_arg_append(app, occ, "(null)", 6); - - if (occ->conversion == 'C') { - buf = node_const_to_str(X); - } - else { /* 'O' */ - buf = node_offset_to_str(X); - } - - return lc_arg_append(app, occ, buf, strlen(buf)); + const arch_register_t *reg = get_in_reg(env->arch_env, node, pos); + be_emit_string(env->emit, arch_register_get_name(reg)); } -/** - * Determines the SSE suffix depending on the mode. - */ -static int TEMPLATE_get_mode_suffix(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +void TEMPLATE_emit_dest_register(TEMPLATE_emit_env_t *env, const ir_node *node, int pos) { - ir_node *X = arg->v_ptr; - - if (!X) - return lc_arg_append(app, occ, "(null)", 6); - - if (get_mode_size_bits(get_irn_mode(X)) == 32) - return lc_appendable_chadd(app, 's'); - else - return lc_appendable_chadd(app, 'd'); -} - -/** - * Return the TEMPLATE printf arg environment. - * We use the firm environment with some additional handlers. - */ -const lc_arg_env_t *TEMPLATE_get_arg_env(void) { - static lc_arg_env_t *env = NULL; - - static const lc_arg_handler_t TEMPLATE_reg_handler = { TEMPLATE_get_arg_type, TEMPLATE_get_reg_name }; - static const lc_arg_handler_t TEMPLATE_const_handler = { TEMPLATE_get_arg_type, TEMPLATE_const_to_str }; - static const lc_arg_handler_t TEMPLATE_mode_handler = { TEMPLATE_get_arg_type, TEMPLATE_get_mode_suffix }; - - if(env == NULL) { - /* extend the firm printer */ - env = firm_get_arg_env(); - //lc_arg_new_env(); - - lc_arg_register(env, "TEMPLATE:sreg", 'S', &TEMPLATE_reg_handler); - lc_arg_register(env, "TEMPLATE:dreg", 'D', &TEMPLATE_reg_handler); - lc_arg_register(env, "TEMPLATE:cnst", 'C', &TEMPLATE_const_handler); - lc_arg_register(env, "TEMPLATE:offs", 'O', &TEMPLATE_const_handler); - lc_arg_register(env, "TEMPLATE:mode", 'M', &TEMPLATE_mode_handler); - } - - return env; -} - -/* - * Add a number to a prefix. This number will not be used a second time. - */ -static char *get_unique_label(char *buf, size_t buflen, const char *prefix) { - static unsigned long id = 0; - snprintf(buf, buflen, "%s%lu", prefix, ++id); - return buf; + const arch_register_t *reg = get_out_reg(env->arch_env, node, pos); + be_emit_string(env->emit, arch_register_get_name(reg)); } - /** * Returns the target label for a control flow node. */ -static char *get_cfop_target(const ir_node *irn, char *buf) { - ir_node *bl = get_irn_link(irn); +static void TEMPLATE_emit_cfop_target(TEMPLATE_emit_env_t *env, const ir_node *node) { + ir_node *block = get_irn_link(node); - snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl)); - return buf; + be_emit_irprintf(env->emit, "BLOCK_%ld", get_irn_node_nr(block)); } - - /*********************************************************************************** * _ __ _ * (_) / _| | | @@ -266,6 +129,20 @@ static char *get_cfop_target(const ir_node *irn, char *buf) { * ***********************************************************************************/ +/** + * Emits code for a unconditional jump. + */ +static void emit_Jmp(TEMPLATE_emit_env_t *env, const ir_node *node) { + ir_node *block; + + /* for now, the code works for scheduled and non-schedules blocks */ + block = get_nodes_block(node); + + be_emit_cstring(env->emit, "\tjmp "); + TEMPLATE_emit_cfop_target(env, node); + be_emit_finish_line_gas(env->emit, node); +} + /** * Enters the emitter functions for handled nodes into the generic * pointer of an opcode. @@ -285,30 +162,29 @@ static void TEMPLATE_register_emitters(void) { TEMPLATE_register_spec_emitters(); /* register addtional emitter functions if needed */ + EMIT(Jmp); #undef TEMPLATE_EMIT #undef BE_EMIT #undef EMIT } +typedef void (*emit_func_ptr) (TEMPLATE_emit_env_t *, const ir_node *); /** * Emits code for a node. */ -void TEMPLATE_emit_node(ir_node *irn, void *env) { - TEMPLATE_emit_env_t *emit_env = env; - FILE *F = emit_env->out; - ir_op *op = get_irn_op(irn); - DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;) +void TEMPLATE_emit_node(TEMPLATE_emit_env_t *env, const ir_node *node) { + ir_op *op = get_irn_op(node); + DEBUG_ONLY(firm_dbg_module_t *mod = env->mod;) - DBG((mod, LEVEL_1, "emitting code for %+F\n", irn)); + DBG((mod, LEVEL_1, "emitting code for %+F\n", node)); if (op->ops.generic) { - void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic; - (*emit)(irn, env); - } - else { - ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn); + emit_func_ptr func = (emit_func_ptr) op->ops.generic; + (*func) (env, node); + } else { + ir_fprintf(stderr, "No emitter for node %+F\n", node); } } @@ -316,16 +192,19 @@ void TEMPLATE_emit_node(ir_node *irn, void *env) { * Walks over the nodes in a block connected by scheduling edges * and emits code for each node. */ -void TEMPLATE_gen_block(ir_node *block, void *env) { - TEMPLATE_emit_env_t *emit_env = env; - ir_node *irn; +void TEMPLATE_gen_block(ir_node *block, void *data) { + TEMPLATE_emit_env_t *env = data; + ir_node *node; if (! is_Block(block)) return; - fprintf(emit_env->out, "BLOCK_%ld:\n", get_irn_node_nr(block)); - sched_foreach(block, irn) { - TEMPLATE_emit_node(irn, env); + be_emit_cstring(env->emit, "BLOCK_"); + be_emit_irprintf(env->emit, "%ld:\n", get_irn_node_nr(block)); + be_emit_write_line(env->emit); + + sched_foreach(block, node) { + TEMPLATE_emit_node(env, node); } } @@ -333,19 +212,27 @@ void TEMPLATE_gen_block(ir_node *block, void *env) { /** * Emits code for function start. */ -void TEMPLATE_emit_func_prolog(FILE *F, ir_graph *irg) { +void TEMPLATE_emit_func_prolog(TEMPLATE_emit_env_t *env, ir_graph *irg) { const char *irg_name = get_entity_name(get_irg_entity(irg)); /* TODO: emit function header */ + be_emit_cstring(env->emit, "/* start of "); + be_emit_string(env->emit, irg_name); + be_emit_cstring(env->emit, " */\n"); + be_emit_write_line(env->emit); } /** * Emits code for function end */ -void TEMPLATE_emit_func_epilog(FILE *F, ir_graph *irg) { +void TEMPLATE_emit_func_epilog(TEMPLATE_emit_env_t *env, ir_graph *irg) { const char *irg_name = get_entity_name(get_irg_entity(irg)); /* TODO: emit function end */ + be_emit_cstring(env->emit, "/* end of "); + be_emit_string(env->emit, irg_name); + be_emit_cstring(env->emit, " */\n"); + be_emit_write_line(env->emit); } /** @@ -365,22 +252,20 @@ void TEMPLATE_gen_labels(ir_node *block, void *env) { /** * Main driver */ -void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const TEMPLATE_code_gen_t *cg) { - TEMPLATE_emit_env_t emit_env; - - emit_env.out = F; - emit_env.arch_env = cg->arch_env; - emit_env.cg = cg; - FIRM_DBG_REGISTER(emit_env.mod, "firm.be.TEMPLATE.emit"); +void TEMPLATE_gen_routine(const TEMPLATE_code_gen_t *cg, ir_graph *irg) { + TEMPLATE_emit_env_t env; - /* set the global arch_env (needed by print hooks) */ - arch_env = cg->arch_env; + env.isa = (TEMPLATE_isa_t *) cg->arch_env->isa; + env.emit = &env.isa->emit; + env.arch_env = cg->arch_env; + env.cg = cg; + FIRM_DBG_REGISTER(env.mod, "firm.be.TEMPLATE.emit"); /* register all emitter functions */ TEMPLATE_register_emitters(); - TEMPLATE_emit_func_prolog(F, irg); - irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, &emit_env); - irg_walk_blkwise_graph(irg, NULL, TEMPLATE_gen_block, &emit_env); - TEMPLATE_emit_func_epilog(F, irg); + TEMPLATE_emit_func_prolog(&env, irg); + irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, &env); + irg_walk_blkwise_graph(irg, NULL, TEMPLATE_gen_block, &env); + TEMPLATE_emit_func_epilog(&env, irg); } diff --git a/ir/be/TEMPLATE/TEMPLATE_emitter.h b/ir/be/TEMPLATE/TEMPLATE_emitter.h index e288e534d..c30354c02 100644 --- a/ir/be/TEMPLATE/TEMPLATE_emitter.h +++ b/ir/be/TEMPLATE/TEMPLATE_emitter.h @@ -6,23 +6,25 @@ #include "debug.h" #include "../bearch.h" +#include "../beemitter.h" #include "bearch_TEMPLATE_t.h" typedef struct _TEMPLATE_emit_env_t { - FILE *out; + be_emit_env_t *emit; const arch_env_t *arch_env; const TEMPLATE_code_gen_t *cg; + TEMPLATE_isa_t *isa; DEBUG_ONLY(firm_dbg_module_t *mod;) } TEMPLATE_emit_env_t; -const lc_arg_env_t *TEMPLATE_get_arg_env(void); - -void equalize_dest_src(FILE *F, ir_node *n); +void TEMPLATE_emit_source_register(TEMPLATE_emit_env_t *env, const ir_node *node, int pos); +void TEMPLATE_emit_dest_register(TEMPLATE_emit_env_t *env, const ir_node *node, int pos); +void TEMPLATE_emit_immediate(TEMPLATE_emit_env_t *env, const ir_node *node); int get_TEMPLATE_reg_nr(ir_node *irn, int posi, int in_out); const char *get_TEMPLATE_in_reg_name(ir_node *irn, int pos); -void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const TEMPLATE_code_gen_t *cg); +void TEMPLATE_gen_routine(const TEMPLATE_code_gen_t *cg, ir_graph *irg); #endif /* _TEMPLATE_EMITTER_H_ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_gen_decls.c b/ir/be/TEMPLATE/TEMPLATE_gen_decls.c deleted file mode 100644 index 63f1fa151..000000000 --- a/ir/be/TEMPLATE/TEMPLATE_gen_decls.c +++ /dev/null @@ -1,607 +0,0 @@ -/** - * Dumps global variables and constants as TEMPLATE assembler. - * @date 14.02.2006 - * @version $Id$ - */ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include "xmalloc.h" -#include - -#ifdef obstack_chunk_alloc -# undef obstack_chunk_alloc -# define obstack_chunk_alloc xmalloc -#else -# define obstack_chunk_alloc xmalloc -# define obstack_chunk_free free -#endif - -#include "tv.h" -#include "irnode.h" -#include "entity.h" -#include "irprog.h" - -#include "TEMPLATE_gen_decls.h" - -/************************************************************************/ - -/* - * returns the highest bit value - */ -static unsigned highest_bit(unsigned v) -{ - int res = -1; - - if (v >= (1U << 16U)) { - res += 16; - v >>= 16; - } - if (v >= (1U << 8U)) { - res += 8; - v >>= 8; - } - if (v >= (1U << 4U)) { - res += 4; - v >>= 4; - } - if (v >= (1U << 2U)) { - res += 2; - v >>= 2; - } - if (v >= (1U << 1U)) { - res += 1; - v >>= 1; - } - if (v >= 1) - res += 1; - - return res; -} - -/* - * output the alignment - */ -static void TEMPLATE_dump_align(struct obstack *obst, int align) -{ - int h = highest_bit(align); - - if ((1 << h) < align) - ++h; - align = (1 << h); - - if (align > 1) - obstack_printf(obst, "\t.align %d\n", align); -} - -static void dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes) -{ - switch (bytes) { - - case 1: - obstack_printf(obst, "0x%02x", get_tarval_sub_bits(tv, 0)); - break; - - case 2: - obstack_printf(obst, "0x%02x%02x", get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; - - case 4: - obstack_printf(obst, "0x%02x%02x%02x%02x", - get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; - - case 8: - obstack_printf(obst, "0x%02x%02x%02x%02x%02x%02x%02x%02x", - get_tarval_sub_bits(tv, 7), get_tarval_sub_bits(tv, 6), get_tarval_sub_bits(tv, 5), get_tarval_sub_bits(tv, 4), - get_tarval_sub_bits(tv, 3), get_tarval_sub_bits(tv, 2), get_tarval_sub_bits(tv, 1), get_tarval_sub_bits(tv, 0)); - break; - - case 10: - case 12: - break; - - default: - fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); - assert(0); - } -} - -/* - * dump an arithmetic tarval - */ -static void TEMPLATE_dump_arith_tarval(struct obstack *obst, tarval *tv, int bytes) -{ - switch (bytes) { - - case 1: - obstack_printf(obst, "\t.byte\t"); - break; - - case 2: - obstack_printf(obst, "\t.value\t"); - break; - - case 4: - obstack_printf(obst, "\t.long\t"); - break; - - case 8: - obstack_printf(obst, "\t.quad\t"); - break; - - case 10: - case 12: - break; - - default: - fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); - assert(0); - } - dump_arith_tarval(obst, tv, bytes); -} - - -/* - * dump an atomic value - */ -static void do_dump_atomic_init(struct obstack *obst, ir_node *init) -{ - ir_mode *mode = get_irn_mode(init); - int bytes = get_mode_size_bytes(mode); - tarval *tv; - - switch (get_irn_opcode(init)) { - - case iro_Cast: - do_dump_atomic_init(obst, get_Cast_op(init)); - return; - - case iro_Conv: - do_dump_atomic_init(obst, get_Conv_op(init)); - return; - - case iro_Const: - tv = get_Const_tarval(init); - - /* beware of old stuff */ - assert(! mode_is_reference(mode)); - - /* it's a arithmetic value */ - dump_arith_tarval(obst, tv, bytes); - return; - - case iro_SymConst: - switch (get_SymConst_kind(init)) { - case symconst_addr_name: - obstack_printf(obst, "%s", get_id_str(get_SymConst_name(init))); - break; - - case symconst_addr_ent: - obstack_printf(obst, "%s", get_entity_ld_name(get_SymConst_entity(init))); - break; - - case symconst_ofs_ent: - obstack_printf(obst, "%d", get_entity_offset(get_SymConst_entity(init))); - break; - - case symconst_type_size: - obstack_printf(obst, "%d", get_type_size_bytes(get_SymConst_type(init))); - break; - - case symconst_type_align: - obstack_printf(obst, "%d", get_type_alignment_bytes(get_SymConst_type(init))); - break; - - default: - assert(0 && "dump_atomic_init(): don't know how to init from this SymConst"); - } - return; - - case iro_Add: - do_dump_atomic_init(obst, get_Add_left(init)); - obstack_printf(obst, " + "); - do_dump_atomic_init(obst, get_Add_right(init)); - return; - - case iro_Sub: - do_dump_atomic_init(obst, get_Sub_left(init)); - obstack_printf(obst, " - "); - do_dump_atomic_init(obst, get_Sub_right(init)); - return; - - case iro_Mul: - do_dump_atomic_init(obst, get_Mul_left(init)); - obstack_printf(obst, " * "); - do_dump_atomic_init(obst, get_Mul_right(init)); - return; - - default: - assert(0 && "dump_atomic_init(): unknown IR-node"); - } -} - -/* - * dump an atomic value - */ -static void dump_atomic_init(struct obstack *obst, ir_node *init) -{ - ir_mode *mode = get_irn_mode(init); - int bytes = get_mode_size_bytes(mode); - - switch (bytes) { - - case 1: - obstack_printf(obst, "\t.byte\t"); - break; - - case 2: - obstack_printf(obst, "\t.value\t"); - break; - - case 4: - obstack_printf(obst, "\t.long\t"); - break; - - case 8: - obstack_printf(obst, "\t.quad\t"); - break; - - case 10: - case 12: - /* handled in arith */ - break; - - default: - fprintf(stderr, "Try to dump an tarval with %d bytes\n", bytes); - assert(0); - } - - do_dump_atomic_init(obst, init); - obstack_printf(obst, "\n"); -} - -/************************************************************************/ -/* Routines to dump global variables */ -/************************************************************************/ - -/** - * Determine if an ir_entity is a string constant - * @param ent The ir_entity - * @return 1 if it is a string constant, 0 otherwise - */ -static int ent_is_string_const(ir_entity *ent) -{ - int res = 0; - ir_type *ty; - - ty = get_entity_type(ent); - - /* if it's an array */ - if (is_Array_type(ty)) { - ir_type *elm_ty = get_array_element_type(ty); - - /* and the array's element type is primitive */ - if (is_Primitive_type(elm_ty)) { - ir_mode *mode = get_type_mode(elm_ty); - - /* - * and the mode of the element type is an int of - * the same size as the byte mode - */ - if (mode_is_int(mode) - && get_mode_size_bits(mode) == get_mode_size_bits(mode_Bs)) - { - int i, c, n; - - n = get_compound_ent_n_values(ent); - for (i = 0; i < n; ++i) { - ir_node *irn = get_compound_ent_value(ent, i); - if(get_irn_opcode(irn) != iro_Const) - return 0; - - c = (int) get_tarval_long(get_Const_tarval(irn)); - - if((i < n - 1 && !(isgraph(c) || isspace(c))) - || (i == n - 1 && c != '\0')) - return 0; - } - - res = 1; - } - } - } - - return res; -} - -/** - * Dump a atring constant. - * No checks are made!! - * @param obst The obst to dump on. - * @param ent The ir_entity to dump. - */ -static void dump_string_cst(struct obstack *obst, ir_entity *ent) -{ - int i, n; - - obstack_printf(obst, "\t.string \""); - n = get_compound_ent_n_values(ent); - - for (i = 0; i < n-1; ++i) { - ir_node *irn; - int c; - - irn = get_compound_ent_value(ent, i); - c = (int) get_tarval_long(get_Const_tarval(irn)); - - switch (c) { - case '"' : obstack_printf(obst, "\\\""); break; - case '\n': obstack_printf(obst, "\\n"); break; - case '\r': obstack_printf(obst, "\\r"); break; - case '\t': obstack_printf(obst, "\\t"); break; - default : - if (isprint(c)) - obstack_printf(obst, "%c", c); - else - obstack_printf(obst, "\\%o", c); - break; - } - } - obstack_printf(obst, "\"\n"); -} - -struct arr_info { - int n_elems; - int visit_cnt; - int size; -}; - -/* - * Dumps the initialization of global variables that are not - * "uninitialized". - */ -static void dump_global(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack, ir_entity *ent) -{ - ir_type *ty = get_entity_type(ent); - const char *ld_name = get_entity_ld_name(ent); - int align, h; - struct obstack *obst = data_obstack; - - /* - * FIXME: did NOT work for partly constant values - */ - if (! is_Method_type(ty)) { - ir_variability variability = get_entity_variability(ent); - ir_visibility visibility = get_entity_visibility(ent); - - if (variability == variability_constant) { - /* a constant ir_entity, put it on the rdata */ - obst = rdata_obstack; - } - - /* check, wether it is initialized, if yes create data */ - if (variability != variability_uninitialized) { - if (visibility == visibility_external_visible) { - obstack_printf(obst, ".globl\t%s\n", ld_name); - } - obstack_printf(obst, "\t.type\t%s,@object\n", ld_name); - obstack_printf(obst, "\t.size\t%s,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3); - - align = get_type_alignment_bytes(ty); - TEMPLATE_dump_align(obst, align); - - obstack_printf(obst, "%s:\n", ld_name); - - if (is_atomic_type(ty)) { - if (get_entity_visibility(ent) != visibility_external_allocated) - dump_atomic_init(obst, get_atomic_ent_value(ent)); - } - else { - int i, size = 0; - - if (ent_is_string_const(ent)) { - dump_string_cst(obst, ent); - } - else if (is_Array_type(ty)) { - int filler; - - /* potential spare values should be already included! */ - for (i = 0; i < get_compound_ent_n_values(ent); ++i) { - ir_entity *step = get_compound_ent_value_member(ent, i); - ir_type *stype = get_entity_type(step); - - if (get_type_mode(stype)) { - int align = (get_type_alignment_bits(stype) + 7) >> 3; - int n = size % align; - - if (n > 0) { - obstack_printf(obst, "\t.zero\t%d\n", align - n); - size += align - n; - } - } - dump_atomic_init(obst, get_compound_ent_value(ent, i)); - size += get_type_size_bytes(stype); - } - filler = get_type_size_bytes(ty) - size; - - if (filler > 0) - obstack_printf(obst, "\t.zero\t%d\n", filler); - } - else if (is_compound_type(ty)) { - ir_node **vals; - int type_size, j; - - /* Compound entities are NOT sorted. - * The sorting strategy used doesn't work for `value' compound fields nor - * for partially_constant entities. - */ - - /* - * in the worst case, every ir_entity allocates one byte, so the type - * size should be equal or bigger the number of fields - */ - type_size = get_type_size_bytes(ty); - vals = xcalloc(type_size, sizeof(*vals)); - - /* collect the values and store them at the offsets */ - for(i = 0; i < get_compound_ent_n_values(ent); ++i) { - int graph_length, aipos, offset; - struct arr_info *ai; - int all_n = 1; - compound_graph_path *path = get_compound_ent_value_path(ent, i); - - /* get the access path to the costant value */ - graph_length = get_compound_graph_path_length(path); - ai = xcalloc(graph_length, sizeof(struct arr_info)); - - /* We wanna know how many arrays are on the path to the ir_entity. We also have to know how - * many elements each array holds to calculate the offset for the ir_entity. */ - for (j = 0; j < graph_length; j++) { - ir_entity *step = get_compound_graph_path_node(path, j); - ir_type *step_type = get_entity_type(step); - int ty_size = (get_type_size_bits(step_type) + 7) >> 3; - int k, n = 0; - - if (is_Array_type(step_type)) - for (k = 0; k < get_array_n_dimensions(step_type); k++) - n += get_tarval_long(get_Const_tarval(get_array_upper_bound(step_type, k))); - if (n) all_n *= n; - ai[j].n_elems = n ? all_n + 1 : 0; - ai[j].visit_cnt = 0; - ai[j].size = ty_size; - } - - aipos = graph_length - 1; - if (aipos) aipos--; - - for (offset = j = 0; j < graph_length; j++) { - ir_entity *step = get_compound_graph_path_node(path, j); - ir_type *step_type = get_entity_type(step); - int ent_ofs = get_entity_offset_bytes(step); - int stepsize = 0; - - /* add all positive offsets (= offsets in structs) */ - if (ent_ofs >= 0) offset += ent_ofs; - - if (j == graph_length - 1) { - stepsize = (get_type_size_bits(step_type) + 7) >> 3; - - /* Search the next free position in vals depending on the information from above (ai). */ - while (vals[offset]) { - if (ai[aipos].visit_cnt < ai[aipos].n_elems) { - offset += stepsize; - ai[aipos].visit_cnt++; - } - else - while (aipos >= 0 && ai[aipos].visit_cnt == ai[aipos].n_elems) { - stepsize = ai[aipos--].size; - offset += stepsize; - } - } - - assert(aipos >= 0 && "couldn't store ir_entity"); - vals[offset] = get_compound_ent_value(ent, i); - } - } - - free(ai); - } - - /* now write them sorted */ - for(i = 0; i < type_size; ) { - if (vals[i]) { - dump_atomic_init(obst, vals[i]); - i += (get_mode_size_bytes(get_irn_mode(vals[i]))); - } - else { - /* a gap */ - obstack_printf(obst, "\t.byte\t0\n"); - ++i; - } - } - free(vals); - } - else { - assert(0 && "unsupported type"); - } - } - obstack_printf(obst, "\n"); - } - else if (visibility != visibility_external_allocated) { - if (visibility == visibility_local) { - obstack_printf(comm_obstack, "\t.local\t%s\n", ld_name); - } - - /* calculate the alignment */ - align = get_type_alignment_bytes(ty); - h = highest_bit(align); - - if ((1 << h) < align) - ++h; - align = (1 << h); - - if (align < 1) - align = 1; - - obstack_printf(comm_obstack, "\t.comm\t%s,%d,%d\n", ld_name, (get_type_size_bits(ty) + 7) >> 3, align); - } - } -} - -/* - * Dumps declarations of global variables and the initialization code. - */ -void TEMPLATE_dump_globals(struct obstack *rdata_obstack, struct obstack *data_obstack, struct obstack *comm_obstack) -{ - ir_type *gt = get_glob_type(); - int i, n = get_class_n_members(gt); - - for (i = 0; i < n; i++) - dump_global(rdata_obstack, data_obstack, comm_obstack, get_class_member(gt, i)); -} - -/************************************************************************/ - -void TEMPLATE_gen_decls(FILE *out) { - struct obstack rodata, data, comm; - int size; - char *cp; - - obstack_init(&rodata); - obstack_init(&data); - obstack_init(&comm); - - TEMPLATE_dump_globals(&rodata, &data, &comm); - - size = obstack_object_size(&data); - cp = obstack_finish(&data); - if (size > 0) { - fprintf(out, "\t.data\n"); - fwrite(cp, 1, size, out); - } - - size = obstack_object_size(&rodata); - cp = obstack_finish(&rodata); - if (size > 0) { - fprintf(out, "\t.section\t.rodata\n"); - fwrite(cp, 1, size, out); - } - - size = obstack_object_size(&comm); - cp = obstack_finish(&comm); - if (size > 0) { - fprintf(out, "\t.common\n"); - fwrite(cp, 1, size, out); - } - - obstack_free(&rodata, NULL); - obstack_free(&data, NULL); - obstack_free(&comm, NULL); -} diff --git a/ir/be/TEMPLATE/TEMPLATE_gen_decls.h b/ir/be/TEMPLATE/TEMPLATE_gen_decls.h deleted file mode 100644 index 0224dc048..000000000 --- a/ir/be/TEMPLATE/TEMPLATE_gen_decls.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _TEMPLATE_GEN_DECLS_H_ -#define _TEMPLATE_GEN_DECLS_H_ - -/** - * Generate all entities. - */ -void TEMPLATE_gen_decls(FILE *out); - -#endif /* _TEMPLATE_GEN_DECLS_H_ */ diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c index 942857056..f870d6db7 100644 --- a/ir/be/TEMPLATE/TEMPLATE_new_nodes.c +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.c @@ -45,77 +45,48 @@ * |_| ***********************************************************************************/ -/** - * Returns a string containing the names of all registers within the limited bitset - */ -static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) { - bitset_t *bs = bitset_alloca(req->cls->n_regs); - char *p = buf; - int size = 0; - int i, cnt; - - req->limited(NULL, bs); - - for (i = 0; i < req->cls->n_regs; i++) { - if (bitset_is_set(bs, i)) { - cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name); - if (cnt < 0) { - fprintf(stderr, "dumper problem, exiting\n"); - exit(1); - } - - p += cnt; - size += cnt; - - if (size >= max) - break; - } - } - - return buf; -} - /** * Dumps the register requirements for either in or out. */ -static void dump_reg_req(FILE *F, ir_node *n, const TEMPLATE_register_req_t **reqs, int inout) { +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_TEMPLATE_n_res(n) : get_irn_arity(n); - char *buf = alloca(1024); + char buf[1024]; int i; - memset(buf, 0, 1024); + memset(buf, 0, sizeof(buf)); if (reqs) { for (i = 0; i < max; i++) { fprintf(F, "%sreq #%d =", dir, i); - if (reqs[i]->req.type == arch_register_req_type_none) { + if (reqs[i]->type == arch_register_req_type_none) { fprintf(F, " n/a"); } - if (reqs[i]->req.type & arch_register_req_type_normal) { - fprintf(F, " %s", reqs[i]->req.cls->name); + if (reqs[i]->type & arch_register_req_type_normal) { + fprintf(F, " %s", reqs[i]->cls->name); } - if (reqs[i]->req.type & arch_register_req_type_limited) { - fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024)); + if (reqs[i]->type & arch_register_req_type_limited) { + fprintf(F, " %s", + arch_register_req_format(buf, sizeof(buf), reqs[i], n)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_same) { - ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_same) { + ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->other_same)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_different) { - ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_different) { + ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->other_different)); } fprintf(F, "\n"); } fprintf(F, "\n"); - } - else { + } else { fprintf(F, "%sreq = N/A\n", dir); } } @@ -133,7 +104,7 @@ static int TEMPLATE_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { int bad = 0; int i; TEMPLATE_attr_t *attr; - const TEMPLATE_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t **slots; switch (reason) { @@ -246,7 +217,7 @@ TEMPLATE_attr_t *get_TEMPLATE_attr(const ir_node *node) { /** * Returns the argument register requirements of a TEMPLATE node. */ -const TEMPLATE_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node) { +const arch_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node) { TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); return attr->in_req; } @@ -254,7 +225,7 @@ const TEMPLATE_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node) { /** * Returns the result register requirements of an TEMPLATE node. */ -const TEMPLATE_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node) { +const arch_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node) { TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); return attr->out_req; } @@ -262,7 +233,7 @@ const TEMPLATE_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node) { /** * Returns the argument register requirement at position pos of an TEMPLATE node. */ -const TEMPLATE_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos) { +const arch_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos) { TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); return attr->in_req[pos]; } @@ -270,7 +241,7 @@ const TEMPLATE_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos) /** * Returns the result register requirement at position pos of an TEMPLATE node. */ -const TEMPLATE_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos) { +const arch_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos) { TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); return attr->out_req[pos]; } @@ -278,7 +249,7 @@ const TEMPLATE_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos /** * Sets the OUT register requirements at position pos. */ -void set_TEMPLATE_req_out(ir_node *node, const TEMPLATE_register_req_t *req, int pos) { +void set_TEMPLATE_req_out(ir_node *node, const arch_register_req_t *req, int pos) { TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); attr->out_req[pos] = req; } @@ -286,7 +257,7 @@ void set_TEMPLATE_req_out(ir_node *node, const TEMPLATE_register_req_t *req, int /** * Sets the IN register requirements at position pos. */ -void set_TEMPLATE_req_in(ir_node *node, const TEMPLATE_register_req_t *req, int pos) { +void set_TEMPLATE_req_in(ir_node *node, const arch_register_req_t *req, int pos) { TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); attr->in_req[pos] = req; } @@ -370,7 +341,24 @@ int get_TEMPLATE_n_res(const ir_node *node) { return attr->n_res; } +/** + * Initializes the nodes attributes. + */ +void init_TEMPLATE_attributes(ir_node *node, arch_irn_flags_t flags, + const arch_register_req_t **in_reqs, + const arch_register_req_t **out_reqs, + const be_execution_unit_t ***execution_units, + int n_res, unsigned latency) +{ + TEMPLATE_attr_t *attr = get_TEMPLATE_attr(node); + + attr->flags = flags; + attr->out_req = out_reqs; + attr->in_req = in_reqs; + attr->n_res = n_res; + memset((void *)attr->slots, 0, n_res * sizeof(attr->slots[0])); +} /*************************************************************************************** * _ _ _ diff --git a/ir/be/TEMPLATE/TEMPLATE_new_nodes.h b/ir/be/TEMPLATE/TEMPLATE_new_nodes.h index b67c06c48..a493ae65a 100644 --- a/ir/be/TEMPLATE/TEMPLATE_new_nodes.h +++ b/ir/be/TEMPLATE/TEMPLATE_new_nodes.h @@ -27,32 +27,32 @@ TEMPLATE_attr_t *get_TEMPLATE_attr(const ir_node *node); /** * Returns the argument register requirements of an TEMPLATE node. */ -const TEMPLATE_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node); +const arch_register_req_t **get_TEMPLATE_in_req_all(const ir_node *node); /** * Returns the result register requirements of an TEMPLATE node. */ -const TEMPLATE_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node); +const arch_register_req_t **get_TEMPLATE_out_req_all(const ir_node *node); /** * Returns the argument register requirements of an TEMPLATE node. */ -const TEMPLATE_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos); +const arch_register_req_t *get_TEMPLATE_in_req(const ir_node *node, int pos); /** * Returns the result register requirements of an TEMPLATE node. */ -const TEMPLATE_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos); +const arch_register_req_t *get_TEMPLATE_out_req(const ir_node *node, int pos); /** * Sets the OUT register requirements at position pos. */ -void set_TEMPLATE_req_out(ir_node *node, const TEMPLATE_register_req_t *req, int pos); +void set_TEMPLATE_req_out(ir_node *node, const arch_register_req_t *req, int pos); /** * Sets the IN register requirements at position pos. */ -void set_TEMPLATE_req_in(ir_node *node, const TEMPLATE_register_req_t *req, int pos); +void set_TEMPLATE_req_in(ir_node *node, const arch_register_req_t *req, int pos); /** * Returns the register flag of an TEMPLATE node. diff --git a/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h b/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h index 193aeeae0..805d307f2 100644 --- a/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h +++ b/ir/be/TEMPLATE/TEMPLATE_nodes_attr.h @@ -3,19 +3,12 @@ #include "../bearch.h" -typedef struct _TEMPLATE_register_req_t { - const arch_register_req_t req; - int same_pos; /**< in case of "should be same" we need to remember the pos to get the irn */ - int different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */ -} TEMPLATE_register_req_t; - - typedef struct _TEMPLATE_attr_t { arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */ int n_res; /**< number of results for this node */ - const TEMPLATE_register_req_t **in_req; /**< register requirements for arguments */ - const TEMPLATE_register_req_t **out_req; /**< register requirements for results */ + const arch_register_req_t **in_req; /**< register requirements for arguments */ + const arch_register_req_t **out_req; /**< register requirements for results */ /* must be last, dynamically allocated */ const arch_register_t *slots[1]; /**< register slots for assigned registers */ diff --git a/ir/be/TEMPLATE/TEMPLATE_spec.pl b/ir/be/TEMPLATE/TEMPLATE_spec.pl index 7aa8109e5..45833aad0 100644 --- a/ir/be/TEMPLATE/TEMPLATE_spec.pl +++ b/ir/be/TEMPLATE/TEMPLATE_spec.pl @@ -2,34 +2,32 @@ # $Id$ # This is a template specification for the Firm-Backend +$new_emit_syntax = 1; + # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) $arch = "TEMPLATE"; -# this strings mark the beginning and the end of a comment in emit -$comment_string = "/*"; -$comment_string_end = "*/"; - # 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" }, +# 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", -# "emit" => "emit code with templates", -# "rd_constructor" => "c source code which constructs an ir_node" +# 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", +# emit => "emit code with templates", +# rd_constructor => "c source code which constructs an ir_node" # }, # # ... # (all nodes you need to describe) @@ -94,46 +92,62 @@ $comment_string_end = "*/"; # 4 - ignore (do not assign this register) # NOTE: Last entry of each class is the largest Firm-Mode a register can hold %reg_classes = ( - "general_purpose" => [ - { "name" => "r0", "type" => 1 }, - { "name" => "r1", "type" => 1 }, - { "name" => "r2", "type" => 1 }, - { "name" => "r3", "type" => 1 }, - { "name" => "r4", "type" => 1 }, - { "name" => "r5", "type" => 1 }, - { "name" => "r6", "type" => 6 }, # this is our stackpointer - { "name" => "r7", "type" => 6 }, # this is out basepointer - { "name" => "r8", "type" => 2 }, - { "name" => "r9", "type" => 2 }, - { "name" => "r10", "type" => 2 }, - { "name" => "r11", "type" => 2 }, - { "name" => "r12", "type" => 2 }, - { "name" => "r13", "type" => 2 }, - { "name" => "r14", "type" => 2 }, - { "name" => "r15", "type" => 2 }, - { "mode" => "mode_P" } - ], - "floating_point" => [ - { "name" => "f0", "type" => 1 }, - { "name" => "f1", "type" => 1 }, - { "name" => "f2", "type" => 1 }, - { "name" => "f3", "type" => 1 }, - { "name" => "f4", "type" => 1 }, - { "name" => "f5", "type" => 1 }, - { "name" => "f6", "type" => 1 }, - { "name" => "f7", "type" => 1 }, - { "name" => "f8", "type" => 1 }, - { "name" => "f9", "type" => 1 }, - { "name" => "f10", "type" => 1 }, - { "name" => "f11", "type" => 1 }, - { "name" => "f12", "type" => 1 }, - { "name" => "f13", "type" => 1 }, - { "name" => "f14", "type" => 1 }, - { "name" => "f15", "type" => 1 }, - { "mode" => "mode_D" } - ] + general_purpose => [ + { name => "r0", type => 1 }, + { name => "r1", type => 1 }, + { name => "r2", type => 1 }, + { name => "r3", type => 1 }, + { name => "r4", type => 1 }, + { name => "r5", type => 1 }, + { name => "r6", type => 1 }, + { name => "r7", type => 2 }, + { name => "r8", type => 2 }, + { name => "r9", type => 2 }, + { name => "r10", type => 2 }, + { name => "r11", type => 2 }, + { name => "r12", type => 2 }, + { name => "r13", type => 2 }, + { name => "sp", realname => "r14", type => 4 }, # this is our stackpointer + { name => "bp", realname => "r15", type => 4 }, # this is out basepointer + { mode => "mode_Iu" } + ], + floating_point => [ + { name => "f0", type => 1 }, + { name => "f1", type => 1 }, + { name => "f2", type => 1 }, + { name => "f3", type => 1 }, + { name => "f4", type => 1 }, + { name => "f5", type => 1 }, + { name => "f6", type => 1 }, + { name => "f7", type => 1 }, + { name => "f8", type => 1 }, + { name => "f9", type => 1 }, + { name => "f10", type => 1 }, + { name => "f11", type => 1 }, + { name => "f12", type => 1 }, + { name => "f13", type => 1 }, + { name => "f14", type => 1 }, + { name => "f15", type => 1 }, + { mode => "mode_D" } + ] ); # %reg_classes +%emit_templates = ( + S1 => "${arch}_emit_source_register(env, node, 0);", + S2 => "${arch}_emit_source_register(env, node, 1);", + S3 => "${arch}_emit_source_register(env, node, 2);", + S4 => "${arch}_emit_source_register(env, node, 3);", + S5 => "${arch}_emit_source_register(env, node, 4);", + S6 => "${arch}_emit_source_register(env, node, 5);", + D1 => "${arch}_emit_dest_register(env, node, 0);", + D2 => "${arch}_emit_dest_register(env, node, 1);", + D3 => "${arch}_emit_dest_register(env, node, 2);", + D4 => "${arch}_emit_dest_register(env, node, 3);", + D5 => "${arch}_emit_dest_register(env, node, 4);", + D6 => "${arch}_emit_dest_register(env, node, 5);", + C => "${arch}_emit_immediate(env, node);" +); + #--------------------------------------------------# # _ # # (_) # @@ -160,185 +174,185 @@ $comment_string_end = "*/"; # commutative operations -"Add" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. add %S1, %S2, %D1\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */' +Add => { + op_flags => "C", + irn_flags => "R", + comment => "construct Add: Add(a, b) = Add(b, a) = a + b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. add %S1, %S2, %D1' }, -"Add_i" => { - "irn_flags" => "R", - "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. add %S1, %C, %D1\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */' +Add_i => { + irn_flags => "R", + comment => "construct Add: Add(a, const) = Add(const, a) = a + const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. add %S1, %C, %D1' }, -"Mul" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" =>'. mul %S1, %S2, %D1\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' +Mul => { + op_flags => "C", + irn_flags => "R", + comment => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit =>'. mul %S1, %S2, %D1' }, -"Mul_i" => { - "irn_flags" => "R", - "comment" => "construct Mul: Mul(a, const) = Mul(const, a) = a * const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. mul %S1, %C, %D1\t\t\t/* signed Mul(%C, %S1) -> %D1, (%A1, const) */' +Mul_i => { + irn_flags => "R", + comment => "construct Mul: Mul(a, const) = Mul(const, a) = a * const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. mul %S1, %C, %D1' }, -"And" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct And: And(a, b) = And(b, a) = a AND b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. and %S1, %S2, %D1\t\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */' +And => { + op_flags => "C", + irn_flags => "R", + comment => "construct And: And(a, b) = And(b, a) = a AND b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. and %S1, %S2, %D1' }, -"And_i" => { - "irn_flags" => "R", - "comment" => "construct And: And(a, const) = And(const, a) = a AND const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. and %S1, %C, %D1\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */' +And_i => { + irn_flags => "R", + comment => "construct And: And(a, const) = And(const, a) = a AND const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. and %S1, %C, %D1' }, -"Or" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. or %S1, %S2, %D1\t\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */' +Or => { + op_flags => "C", + irn_flags => "R", + comment => "construct Or: Or(a, b) = Or(b, a) = a OR b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. or %S1, %S2, %D1' }, -"Or_i" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. or %S1, %C, %D1\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */' +Or_i => { + op_flags => "C", + irn_flags => "R", + comment => "construct Or: Or(a, const) = Or(const, a) = a OR const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. or %S1, %C, %D1' }, -"Eor" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. xor %S1, %S2, %D1\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' +Eor => { + op_flags => "C", + irn_flags => "R", + comment => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. xor %S1, %S2, %D1' }, -"Eor_i" => { - "irn_flags" => "R", - "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. xor %S1, %C, %D1\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */' +Eor_i => { + irn_flags => "R", + comment => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. xor %S1, %C, %D1' }, # not commutative operations -"Sub" => { - "irn_flags" => "R", - "comment" => "construct Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. sub %S1, %S2, %D1\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' +Sub => { + irn_flags => "R", + comment => "construct Sub: Sub(a, b) = a - b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. sub %S1, %S2, %D1' }, -"Sub_i" => { - "irn_flags" => "R", - "comment" => "construct Sub: Sub(a, const) = a - const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. subl %S1, %C, %D1\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */' +Sub_i => { + irn_flags => "R", + comment => "construct Sub: Sub(a, const) = a - const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. subl %S1, %C, %D1' }, -"Shl" => { - "irn_flags" => "R", - "comment" => "construct Shl: Shl(a, b) = a << b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. shl %S1, %S2, %D1\t\t\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' +Shl => { + irn_flags => "R", + comment => "construct Shl: Shl(a, b) = a << b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. shl %S1, %S2, %D1' }, -"Shl_i" => { - "irn_flags" => "R", - "comment" => "construct Shl: Shl(a, const) = a << const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. shl %S1, %C, %D1\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */' +Shl_i => { + irn_flags => "R", + comment => "construct Shl: Shl(a, const) = a << const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. shl %S1, %C, %D1' }, -"Shr" => { - "irn_flags" => "R", - "comment" => "construct Shr: Shr(a, b) = a >> b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] }, - "emit" => '. shr %S2, %D1\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */' +Shr => { + irn_flags => "R", + comment => "construct Shr: Shr(a, b) = a >> b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "in_r1" ] }, + emit => '. shr %S2, %D1' }, -"Shr_i" => { - "irn_flags" => "R", - "comment" => "construct Shr: Shr(a, const) = a >> const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. shr %S1, %C, %D1\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */' +Shr_i => { + irn_flags => "R", + comment => "construct Shr: Shr(a, const) = a >> const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. shr %S1, %C, %D1' }, -"RotR" => { - "irn_flags" => "R", - "comment" => "construct RotR: RotR(a, b) = a ROTR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' +RotR => { + irn_flags => "R", + comment => "construct RotR: RotR(a, b) = a ROTR b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. ror %S1, %S2, %D1' }, -"RotL" => { - "irn_flags" => "R", - "comment" => "construct RotL: RotL(a, b) = a ROTL b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */' +RotL => { + irn_flags => "R", + comment => "construct RotL: RotL(a, b) = a ROTL b", + reg_req => { in => [ "general_purpose", "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. rol %S1, %S2, %D1' }, -"RotL_i" => { - "irn_flags" => "R", - "comment" => "construct RotL: RotL(a, const) = a ROTL const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */' +RotL_i => { + irn_flags => "R", + comment => "construct RotL: RotL(a, const) = a ROTL const", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. rol %S1, %C, %D1' }, -"Minus" => { - "irn_flags" => "R", - "comment" => "construct Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. neg %S1, %D1\t\t\t/* Neg(%S1) -> %D1, (%A1) */' +Minus => { + irn_flags => "R", + comment => "construct Minus: Minus(a) = -a", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. neg %S1, %D1' }, -"Inc" => { - "irn_flags" => "R", - "comment" => "construct Increment: Inc(a) = a++", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */' +Inc => { + irn_flags => "R", + comment => "construct Increment: Inc(a) = a++", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. inc %S1, %D1' }, -"Dec" => { - "irn_flags" => "R", - "comment" => "construct Decrement: Dec(a) = a--", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */' +Dec => { + irn_flags => "R", + comment => "construct Decrement: Dec(a) = a--", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. dec %S1, %D1' }, -"Not" => { - "arity" => 1, - "remat" => 1, - "comment" => "construct Not: Not(a) = !a", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. not %S1, %D1\t\t\t/* Not(%S1) -> %D1, (%A1) */' +Not => { + arity => 1, + remat => 1, + comment => "construct Not: Not(a) = !a", + reg_req => { in => [ "general_purpose" ], out => [ "general_purpose" ] }, + emit => '. not %S1, %D1' }, # other operations -"Const" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "represents an integer constant", - "reg_req" => { "out" => [ "general_purpose" ] }, - "emit" => '. mov %C, %D1\t\t\t/* Mov Const into register */', - "cmp_attr" => +Const => { + op_flags => "c", + irn_flags => "R", + comment => "represents an integer constant", + reg_req => { out => [ "general_purpose" ] }, + emit => '. mov %C, %D1', + cmp_attr => ' /* TODO: compare Const attributes */ return 1; @@ -347,22 +361,22 @@ $comment_string_end = "*/"; # Load / Store -"Load" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. mov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1, (%A1) */' +Load => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + comment => "construct Load: Load(ptr, mem) = LD ptr -> reg", + reg_req => { in => [ "general_purpose", "none" ], out => [ "general_purpose" ] }, + emit => '. mov (%S1), %D1' }, -"Store" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' +Store => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + comment => "construct Store: Store(ptr, val, mem) = ST ptr,val", + reg_req => { in => [ "general_purpose", "general_purpose", "none" ] }, + emit => '. movl %S2, (%S1)' }, #--------------------------------------------------------# @@ -376,68 +390,68 @@ $comment_string_end = "*/"; # commutative operations -"fAdd" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct FP Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fadd %S1, %S2, %D1\t\t\t/* FP Add(%S1, %S2) -> %D1 */' +fAdd => { + op_flags => "C", + irn_flags => "R", + comment => "construct FP Add: Add(a, b) = Add(b, a) = a + b", + reg_req => { in => [ "floating_point", "floating_point" ], out => [ "floating_point" ] }, + emit => '. fadd %S1, %S2, %D1' }, -"fMul" => { - "op_flags" => "C", - "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmul %S1, %S2, %D1\t\t\t/* FP Mul(%S1, %S2) -> %D1 */' +fMul => { + op_flags => "C", + comment => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", + reg_req => { in => [ "floating_point", "floating_point" ], out => [ "floating_point" ] }, + emit =>'. fmul %S1, %S2, %D1' }, -"fMax" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */' +fMax => { + op_flags => "C", + irn_flags => "R", + comment => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", + reg_req => { in => [ "floating_point", "floating_point" ], out => [ "floating_point" ] }, + emit =>'. fmax %S1, %S2, %D1' }, -"fMin" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */' +fMin => { + op_flags => "C", + irn_flags => "R", + comment => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", + reg_req => { in => [ "floating_point", "floating_point" ], out => [ "floating_point" ] }, + emit =>'. fmin %S1, %S2, %D1' }, # not commutative operations -"fSub" => { - "irn_flags" => "R", - "comment" => "construct FP Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fsub %S1, %S2, %D1\t\t\t/* FP Sub(%S1, %S2) -> %D1 */' +fSub => { + irn_flags => "R", + comment => "construct FP Sub: Sub(a, b) = a - b", + reg_req => { in => [ "floating_point", "floating_point" ], out => [ "floating_point" ] }, + emit => '. fsub %S1, %S2, %D1' }, -"fDiv" => { - "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fdiv %S1, %S2, %D1\t\t\t/* FP Div(%S1, %S2) -> %D1 */' +fDiv => { + comment => "construct FP Div: Div(a, b) = a / b", + reg_req => { in => [ "floating_point", "floating_point" ], out => [ "floating_point" ] }, + emit => '. fdiv %S1, %S2, %D1' }, -"fMinus" => { - "irn_flags" => "R", - "comment" => "construct FP Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */' +fMinus => { + irn_flags => "R", + comment => "construct FP Minus: Minus(a) = -a", + reg_req => { in => [ "floating_point" ], out => [ "floating_point" ] }, + emit => '. fneg %S1, %D1' }, # other operations -"fConst" => { - "op_flags" => "c", - "irn_flags" => "R", - "comment" => "represents a FP constant", - "reg_req" => { "out" => [ "floating_point" ] }, - "emit" => '. fmov %C, %D1\t\t\t/* Mov fConst into register */', - "cmp_attr" => +fConst => { + op_flags => "c", + irn_flags => "R", + comment => "represents a FP constant", + reg_req => { out => [ "floating_point" ] }, + emit => '. fmov %C, %D1', + cmp_attr => ' /* TODO: compare fConst attributes */ return 1; @@ -446,22 +460,22 @@ $comment_string_end = "*/"; # Load / Store -"fLoad" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] }, - "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */' -}, - -"fStore" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] }, - "emit" => '. fmov %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' +fLoad => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + comment => "construct FP Load: Load(ptr, mem) = LD ptr", + reg_req => { in => [ "general_purpose", "none" ], out => [ "floating_point" ] }, + emit => '. fmov (%S1), %D1' +}, + +fStore => { + op_flags => "L|F", + irn_flags => "R", + state => "exc_pinned", + comment => "construct Store: Store(ptr, val, mem) = ST ptr,val", + reg_req => { in => [ "general_purpose", "floating_point", "none" ] }, + emit => '. fmov %S2, (%S1)' }, ); # end of %nodes diff --git a/ir/be/TEMPLATE/TEMPLATE_transform.c b/ir/be/TEMPLATE/TEMPLATE_transform.c index 0d0d220c8..7b9ddad4c 100644 --- a/ir/be/TEMPLATE/TEMPLATE_transform.c +++ b/ir/be/TEMPLATE/TEMPLATE_transform.c @@ -192,22 +192,6 @@ static ir_node *gen_Shr(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op -/** - * Creates an TEMPLATE RotL. - * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode - * @return the created TEMPLATE RotL node - */ -static ir_node *gen_RotL(TEMPLATE_transform_env_t *env, ir_node *op1, ir_node *op2) { - return new_rd_TEMPLATE_RotL(env->dbg, env->irg, env->block, op1, op2, env->mode); -} - - - /** * Transforms a Minus node. * diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE.c b/ir/be/TEMPLATE/bearch_TEMPLATE.c index 722761e8b..f7f6633aa 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE.c +++ b/ir/be/TEMPLATE/bearch_TEMPLATE.c @@ -21,18 +21,16 @@ #include "../be.h" #include "../beabi.h" #include "../bemodule.h" +#include "../begnuas.h" #include "bearch_TEMPLATE_t.h" #include "TEMPLATE_new_nodes.h" /* TEMPLATE nodes interface */ #include "gen_TEMPLATE_regalloc_if.h" /* the generated interface (register type and class defenitions) */ -#include "TEMPLATE_gen_decls.h" /* interface declaration emitter */ #include "TEMPLATE_transform.h" #include "TEMPLATE_emitter.h" #include "TEMPLATE_map_regs.h" -#define DEBUG_MODULE "firm.be.TEMPLATE.isa" - /* TODO: ugly, but we need it to get access to the registers assigned to Phi nodes */ static set *cur_reg_set = NULL; @@ -47,95 +45,51 @@ static set *cur_reg_set = NULL; * |___/ **************************************************/ -static ir_node *my_skip_proj(const ir_node *n) { - while (is_Proj(n)) - n = get_Proj_pred(n); - return (ir_node *)n; -} - /** * Return register requirements for a TEMPLATE node. * If the node returns a tuple (mode_T) then the proj's * will be asked for this information. */ -static const arch_register_req_t *TEMPLATE_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) { - const TEMPLATE_register_req_t *irn_req; +static const +arch_register_req_t *TEMPLATE_get_irn_reg_req(const void *self, + const ir_node *node, int pos) { long node_pos = pos == -1 ? 0 : pos; - ir_mode *mode = get_irn_mode(irn); - FIRM_DBG_REGISTER(firm_dbg_module_t *mod, DEBUG_MODULE); + ir_mode *mode = get_irn_mode(node); if (mode == mode_T || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn)); - return NULL; + return arch_no_register_req; } - DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); - - if (is_Proj(irn)) { + if (is_Proj(node)) { /* in case of a proj, we need to get the correct OUT slot */ /* of the node corresponding to the proj number */ if (pos == -1) { - node_pos = TEMPLATE_translate_proj_pos(irn); - } - else { + node_pos = TEMPLATE_translate_proj_pos(node); + } else { node_pos = pos; } - irn = my_skip_proj(irn); - - DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); + node = skip_Proj_const(node); } /* get requirements for our own nodes */ - if (is_TEMPLATE_irn(irn)) { + if (is_TEMPLATE_irn(node)) { + const arch_register_req_t *req; if (pos >= 0) { - irn_req = get_TEMPLATE_in_req(irn, pos); - } - else { - irn_req = get_TEMPLATE_out_req(irn, node_pos); + req = get_TEMPLATE_in_req(node, pos); + } else { + req = get_TEMPLATE_out_req(node, node_pos); } - DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); + assert(req != NULL); - memcpy(req, &(irn_req->req), sizeof(*req)); - - if (arch_register_req_is(&(irn_req->req), should_be_same)) { - assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI"); - req->other_same = get_irn_n(irn, irn_req->same_pos); - } - - if (arch_register_req_is(&(irn_req->req), should_be_different)) { - assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI"); - req->other_different = get_irn_n(irn, irn_req->different_pos); - } - } - /* get requirements for FIRM nodes */ - else { - /* treat Phi like Const with default requirements */ - if (is_Phi(irn)) { - DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); - - if (mode_is_float(mode)) { - memcpy(req, &(TEMPLATE_default_req_TEMPLATE_floating_point.req), sizeof(*req)); - } - else if (mode_is_int(mode) || mode_is_reference(mode)) { - memcpy(req, &(TEMPLATE_default_req_TEMPLATE_general_purpose.req), sizeof(*req)); - } - else if (mode == mode_T || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn)); - return NULL; - } - else { - assert(0 && "unsupported Phi-Mode"); - } - } - else { - DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn)); - req = NULL; - } + return req; } - return req; + /* unknowns should be transformed already */ + assert(!is_Unknown(node)); + + return arch_no_register_req; } static void TEMPLATE_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { @@ -143,7 +97,7 @@ static void TEMPLATE_set_irn_reg(const void *self, ir_node *irn, const arch_regi if (is_Proj(irn)) { pos = TEMPLATE_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj(irn); } if (is_TEMPLATE_irn(irn)) { @@ -164,7 +118,7 @@ static const arch_register_t *TEMPLATE_get_irn_reg(const void *self, const ir_no if (is_Proj(irn)) { pos = TEMPLATE_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); } if (is_TEMPLATE_irn(irn)) { @@ -180,7 +134,7 @@ static const arch_register_t *TEMPLATE_get_irn_reg(const void *self, const ir_no } static arch_irn_class_t TEMPLATE_classify(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_cfop(irn)) { return arch_irn_class_branch; @@ -193,7 +147,7 @@ static arch_irn_class_t TEMPLATE_classify(const void *self, const ir_node *irn) } static arch_irn_flags_t TEMPLATE_get_flags(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_TEMPLATE_irn(irn)) { return get_TEMPLATE_flags(irn); @@ -205,12 +159,12 @@ static arch_irn_flags_t TEMPLATE_get_flags(const void *self, const ir_node *irn) return 0; } -static ir_entity *TEMPLATE_get_frame_entity(const void *self, const ir_node *irn) { +static ir_entity *TEMPLATE_get_frame_entity(const void *self, const ir_node *node) { /* TODO: return the ir_entity assigned to the frame */ return NULL; } -static void TEMPLATE_set_frame_entity(const void *self, const ir_node *irn, ir_entity *ent) { +static void TEMPLATE_set_frame_entity(const void *self, ir_node *node, ir_entity *ent) { /* TODO: set the ir_entity assigned to the frame */ } @@ -292,7 +246,7 @@ static void TEMPLATE_before_sched(void *self) { /* Some stuff you need to do after scheduling but before register allocation */ } -static void TEMPLATE_before_ra(void *self, be_irg_t *birg) { +static void TEMPLATE_before_ra(void *self) { /* Some stuff you need to do after scheduling but before register allocation */ } @@ -309,14 +263,8 @@ static void TEMPLATE_after_ra(void *self) { static void TEMPLATE_emit_and_done(void *self) { TEMPLATE_code_gen_t *cg = self; ir_graph *irg = cg->irg; - FILE *out = cg->isa->out; - if (cg->emit_decls) { - TEMPLATE_gen_decls(out); - cg->emit_decls = 0; - } - - TEMPLATE_gen_routine(out, irg, cg); + TEMPLATE_gen_routine(cg, irg); cur_reg_set = NULL; @@ -325,11 +273,13 @@ static void TEMPLATE_emit_and_done(void *self) { free(self); } -static void *TEMPLATE_cg_init(const be_irg_t *birg); +static void *TEMPLATE_cg_init(be_irg_t *birg); static const arch_code_generator_if_t TEMPLATE_code_gen_if = { TEMPLATE_cg_init, + NULL, /* before abi introduce hook */ TEMPLATE_prepare_graph, + NULL, /* spill hook */ TEMPLATE_before_sched, /* before scheduling hook */ TEMPLATE_before_ra, /* before register allocation hook */ TEMPLATE_after_ra, /* after register allocation hook */ @@ -340,7 +290,7 @@ static const arch_code_generator_if_t TEMPLATE_code_gen_if = { /** * Initializes the code generator. */ -static void *TEMPLATE_cg_init(const be_irg_t *birg) { +static void *TEMPLATE_cg_init(be_irg_t *birg) { TEMPLATE_isa_t *isa = (TEMPLATE_isa_t *)birg->main_env->arch_env->isa; TEMPLATE_code_gen_t *cg = xmalloc(sizeof(*cg)); @@ -352,13 +302,6 @@ static void *TEMPLATE_cg_init(const be_irg_t *birg) { cg->birg = birg; FIRM_DBG_REGISTER(cg->mod, "firm.be.TEMPLATE.cg"); - isa->num_codegens++; - - if (isa->num_codegens > 1) - cg->emit_decls = 0; - else - cg->emit_decls = 1; - cur_reg_set = cg->reg_set; TEMPLATE_irn_ops.cg = cg; @@ -379,33 +322,35 @@ static void *TEMPLATE_cg_init(const be_irg_t *birg) { *****************************************************************/ static TEMPLATE_isa_t TEMPLATE_isa_template = { - &TEMPLATE_isa_if, - &TEMPLATE_general_purpose_regs[REG_R6], - &TEMPLATE_general_purpose_regs[REG_R7], - -1, - 0 + { + &TEMPLATE_isa_if, /* isa interface implementation */ + &TEMPLATE_general_purpose_regs[REG_SP], /* stack pointer register */ + &TEMPLATE_general_purpose_regs[REG_BP], /* base pointer register */ + -1, /* stack direction */ + NULL, /* main environment */ + }, + {}, /* emitter environment */ }; /** * Initializes the backend ISA and opens the output file. */ static void *TEMPLATE_init(FILE *outfile) { - static int inited = 0; + static int run_once = 0; TEMPLATE_isa_t *isa; - if(inited) + if(run_once) return NULL; + run_once = 1; isa = xcalloc(1, sizeof(*isa)); memcpy(isa, &TEMPLATE_isa_template, sizeof(*isa)); - isa->out = outfile; + be_emit_init_env(&isa->emit, outfile); TEMPLATE_register_init(isa); TEMPLATE_create_opcodes(); - inited = 1; - return isa; } @@ -415,6 +360,12 @@ static void *TEMPLATE_init(FILE *outfile) { * Closes the output file and frees the ISA structure. */ static void TEMPLATE_done(void *self) { + TEMPLATE_isa_t *isa = self; + + /* emit now all global declarations */ + be_gas_emit_decls(&isa->emit, isa->arch_isa.main_env); + + be_emit_destroy_env(&isa->emit); free(self); } @@ -470,7 +421,7 @@ static void *TEMPLATE_abi_init(const be_abi_call_t *call, const arch_env_t *arch * @return The between type of for that call. */ static ir_type *TEMPLATE_get_between_type(void *self) { - TEMPLATE_abi_env_t *env = self; + //TEMPLATE_abi_env_t *env = self; static ir_type *between_type = NULL; static ir_entity *old_bp_ent = NULL; @@ -513,7 +464,7 @@ static const arch_register_t *TEMPLATE_abi_prologue(void *self, ir_node **mem, p /* Build the epilog */ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map) { - TEMPLATE_abi_env_t *env = self; + //TEMPLATE_abi_env_t *env = self; } static const be_abi_callbacks_t TEMPLATE_abi_callbacks = { diff --git a/ir/be/TEMPLATE/bearch_TEMPLATE_t.h b/ir/be/TEMPLATE/bearch_TEMPLATE_t.h index 8b6998079..39ce98123 100644 --- a/ir/be/TEMPLATE/bearch_TEMPLATE_t.h +++ b/ir/be/TEMPLATE/bearch_TEMPLATE_t.h @@ -5,6 +5,7 @@ #include "bearch_TEMPLATE.h" #include "TEMPLATE_nodes_attr.h" #include "../be.h" +#include "../beemitter.h" #include "set.h" typedef struct _TEMPLATE_isa_t TEMPLATE_isa_t; @@ -14,19 +15,14 @@ typedef struct _TEMPLATE_code_gen_t { ir_graph *irg; /**< current irg */ const arch_env_t *arch_env; /**< the arch env */ set *reg_set; /**< set to memorize registers for FIRM nodes (e.g. phi) */ - int emit_decls; /**< flag indicating if decls were already emitted */ TEMPLATE_isa_t *isa; /**< the isa instance */ const be_irg_t *birg; /**< The be-irg (contains additional information about the irg) */ DEBUG_ONLY(firm_dbg_module_t *mod;) /**< debugging module */ } TEMPLATE_code_gen_t; struct _TEMPLATE_isa_t { - const arch_isa_if_t *impl; - const arch_register_t *sp; /**< The stack pointer register. */ - const arch_register_t *bp; /**< The base pointer register. */ - const int stack_dir; /**< -1 for decreasing, 1 for increasing. */ - int num_codegens; - FILE *out; /**< output file */ + arch_isa_t arch_isa; /**< must be derived from arch_isa */ + be_emit_env_t emit; /**< emit datastructure */ }; diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c index f346a30c9..3c5636c62 100644 --- a/ir/be/arm/arm_emitter.c +++ b/ir/be/arm/arm_emitter.c @@ -527,7 +527,7 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) { ir_node **projs; int n_projs; int block_nr; - int default_block_num; + int default_block_num = -1; block_nr = get_irn_node_nr(irn); n_projs = get_arm_n_projs(irn); @@ -543,6 +543,7 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) { projs[get_Proj_proj(proj)] = proj; } + assert(default_block_num >= 0); // CMP %1S, n_projs - 1 // BHI default diff --git a/ir/be/arm/arm_new_nodes.c b/ir/be/arm/arm_new_nodes.c index d7ad4b412..688b2cd08 100644 --- a/ir/be/arm/arm_new_nodes.c +++ b/ir/be/arm/arm_new_nodes.c @@ -4,7 +4,7 @@ * $Id$ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #ifdef HAVE_MALLOC_H @@ -32,7 +32,7 @@ #include "arm_nodes_attr.h" #include "arm_new_nodes.h" -#include "gen_arm_regalloc_if.h" +#include "gen_arm_regalloc_if_t.h" #include "../beabi.h" #include "bearch_arm_t.h" @@ -56,77 +56,48 @@ const char *arm_shf_mod_name(arm_shift_modifier mod) { * |_| ***********************************************************************************/ -/** - * Returns a string containing the names of all registers within the limited bitset - */ -static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) { - bitset_t *bs = bitset_alloca(req->cls->n_regs); - char *p = buf; - int size = 0; - int i, cnt; - - req->limited(NULL, bs); - - for (i = 0; i < req->cls->n_regs; i++) { - if (bitset_is_set(bs, i)) { - cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name); - if (cnt < 0) { - fprintf(stderr, "dumper problem, exiting\n"); - exit(1); - } - - p += cnt; - size += cnt; - - if (size >= max) - break; - } - } - - return buf; -} - /** * Dumps the register requirements for either in or out. */ -static void dump_reg_req(FILE *F, ir_node *n, const arm_register_req_t **reqs, int inout) { +static void dump_reg_req(FILE *F, const ir_node *node, + const arch_register_req_t **reqs, int inout) { char *dir = inout ? "out" : "in"; - int max = inout ? get_arm_n_res(n) : get_irn_arity(n); - char *buf = alloca(1024); + int max = inout ? get_arm_n_res(node) : get_irn_arity(node); + char buf[1024]; int i; - memset(buf, 0, 1024); + memset(buf, 0, sizeof(buf)); if (reqs) { for (i = 0; i < max; i++) { fprintf(F, "%sreq #%d =", dir, i); - if (reqs[i]->req.type == arch_register_req_type_none) { + if (reqs[i]->type == arch_register_req_type_none) { fprintf(F, " n/a"); } - if (reqs[i]->req.type & arch_register_req_type_normal) { - fprintf(F, " %s", reqs[i]->req.cls->name); + if (reqs[i]->type & arch_register_req_type_normal) { + fprintf(F, " %s", reqs[i]->cls->name); } - if (reqs[i]->req.type & arch_register_req_type_limited) { - fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024)); + if (reqs[i]->type & arch_register_req_type_limited) { + fprintf(F, " %s", + arch_register_req_format(buf, sizeof(buf), reqs[i], node)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_same) { - ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_same) { + ir_fprintf(F, " same as %+F", get_irn_n(node, reqs[i]->other_same)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_different) { - ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_different) { + ir_fprintf(F, " different from %+F", get_irn_n(node, reqs[i]->other_different)); } fprintf(F, "\n"); } fprintf(F, "\n"); - } - else { + } else { fprintf(F, "%sreq = N/A\n", dir); } } @@ -143,7 +114,7 @@ static int arm_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { int bad = 0; int i; arm_attr_t *attr = get_arm_attr(n); - const arm_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t **slots; arm_shift_modifier mod; @@ -277,7 +248,7 @@ arm_attr_t *get_arm_attr(const ir_node *node) { /** * Returns the argument register requirements of a arm node. */ -const arm_register_req_t **get_arm_in_req_all(const ir_node *node) { +const arch_register_req_t **get_arm_in_req_all(const ir_node *node) { arm_attr_t *attr = get_arm_attr(node); return attr->in_req; } @@ -285,7 +256,7 @@ const arm_register_req_t **get_arm_in_req_all(const ir_node *node) { /** * Returns the result register requirements of an arm node. */ -const arm_register_req_t **get_arm_out_req_all(const ir_node *node) { +const arch_register_req_t **get_arm_out_req_all(const ir_node *node) { arm_attr_t *attr = get_arm_attr(node); return attr->out_req; } @@ -293,7 +264,7 @@ const arm_register_req_t **get_arm_out_req_all(const ir_node *node) { /** * Returns the argument register requirement at position pos of an arm node. */ -const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos) { +const arch_register_req_t *get_arm_in_req(const ir_node *node, int pos) { arm_attr_t *attr = get_arm_attr(node); return attr->in_req[pos]; } @@ -301,7 +272,7 @@ const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos) { /** * Returns the result register requirement at position pos of an arm node. */ -const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos) { +const arch_register_req_t *get_arm_out_req(const ir_node *node, int pos) { arm_attr_t *attr = get_arm_attr(node); return attr->out_req[pos]; } @@ -309,7 +280,7 @@ const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos) { /** * Sets the OUT register requirements at position pos. */ -void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos) { +void set_arm_req_out(ir_node *node, const arch_register_req_t *req, int pos) { arm_attr_t *attr = get_arm_attr(node); attr->out_req[pos] = req; } @@ -317,7 +288,7 @@ void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos) { /** * Sets the complete OUT requirements of node. */ -void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs) { +void set_arm_req_out_all(ir_node *node, const arch_register_req_t **reqs) { arm_attr_t *attr = get_arm_attr(node); attr->out_req = reqs; } @@ -325,7 +296,7 @@ void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs) { /** * Sets the IN register requirements at position pos. */ -void set_arm_req_in(ir_node *node, const arm_register_req_t *req, int pos) { +void set_arm_req_in(ir_node *node, const arch_register_req_t *req, int pos) { arm_attr_t *attr = get_arm_attr(node); attr->in_req[pos] = req; } @@ -498,8 +469,8 @@ arm_shift_modifier get_arm_shift_modifier(ir_node *node) { } /* Set the ARM machine node attributes to default values. */ -void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs, - const arm_register_req_t ** out_reqs, const be_execution_unit_t ***execution_units, +void init_arm_attributes(ir_node *node, int flags, const arch_register_req_t ** in_reqs, + const arch_register_req_t ** out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency) { arm_attr_t *attr = get_arm_attr(node); attr->in_req = in_reqs; @@ -531,70 +502,63 @@ static int arm_comp_condJmp(arm_attr_t *attr_a, arm_attr_t *attr_b) { * ***************************************************************************************/ -/* limit the possible registers for sp in arm_StoreStackM4Inc */ -static void limit_reg_arm_StoreStackM4Inc_sp(void *_unused, bitset_t *bs) { - bs = bitset_clear_all(bs); /* disallow all register (positive constraints given) */ - bitset_set(bs, 14); /* allow r13 */ - bitset_clear(bs, 13); /* disallow ignore reg r12 */ - bitset_clear(bs, 14); /* disallow ignore reg r13 */ - bitset_clear(bs, 15); /* disallow ignore reg r15 */ - bitset_clear(bs, 16); /* disallow ignore reg rxx */ -} - -static const arm_register_req_t _arm_req_sp = { - { - arch_register_req_type_limited, - &arm_reg_classes[CLASS_arm_gp], - limit_reg_arm_StoreStackM4Inc_sp, - NULL, /* limit environment */ - NULL, /* same node */ - NULL /* different node */ - }, - 0, - 0 +#ifdef BIT +#undef BIT +#endif +#define BIT(x) (1 << (x % 32)) + +static unsigned arm_req_sp_limited[] = { BIT(REG_SP) }; +static const arch_register_req_t _arm_req_sp = { + arch_register_req_type_limited, + &arm_reg_classes[CLASS_arm_gp], + arm_req_sp_limited, + -1, + -1 }; /* construct Store: Store(ptr, val, mem) = ST ptr,val */ -ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, ir_node *sp, - int n_regs, ir_node **regs, ir_mode *mode) { - ir_node *res; - ir_node *in[16]; - int flags = 0; - static const arm_register_req_t *_in_req_arm_StoreStackM4Inc[] = - { - &arm_default_req_none, - &_arm_req_sp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - &arm_default_req_arm_gp, - }; - - assert(n_regs <= 15); - - in[0] = mem; - in[1] = sp; - memcpy(&in[2], regs, n_regs * sizeof(in[0])); - res = new_ir_node(NULL, irg, block, op_arm_StoreStackM4Inc, mode, 2 + n_regs, in); - flags |= arch_irn_flags_rematerializable; /* op can be easily recalculated */ - - /* init node attributes */ - init_arm_attributes(res, flags, _in_req_arm_StoreStackM4Inc, NULL, NULL, 0, 1); - - res = optimize_node(res); - irn_vrfy_irg(res, irg); - - return res; +ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, + ir_node *sp, int n_regs, ir_node **regs, + ir_mode *mode) { + ir_node *res; + ir_node *in[16]; + int flags = 0; + static const arch_register_req_t *_in_req_arm_StoreStackM4Inc[] = + { + &arm_StoreStackM4Inc_reg_req_in_0, + &arm_StoreStackM4Inc_reg_req_in_1, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + &arm_StoreStackM4Inc_reg_req_in_2, + }; + + assert(n_regs <= 15); + + in[0] = mem; + in[1] = sp; + memcpy(&in[2], regs, n_regs * sizeof(in[0])); + res = new_ir_node(NULL, irg, block, op_arm_StoreStackM4Inc, mode, 2 + n_regs, in); + flags |= arch_irn_flags_rematerializable; /* op can be easily recalculated */ + + /* init node attributes */ + init_arm_attributes(res, flags, _in_req_arm_StoreStackM4Inc, NULL, NULL, 0, 1); + + res = optimize_node(res); + irn_vrfy_irg(res, irg); + + return res; } /************************************************ diff --git a/ir/be/arm/arm_new_nodes.h b/ir/be/arm/arm_new_nodes.h index e453f09a4..b2f38c016 100644 --- a/ir/be/arm/arm_new_nodes.h +++ b/ir/be/arm/arm_new_nodes.h @@ -28,37 +28,37 @@ arm_attr_t *get_arm_attr(const ir_node *node); /** * Returns the argument register requirements of an arm node. */ -const arm_register_req_t **get_arm_in_req_all(const ir_node *node); +const arch_register_req_t **get_arm_in_req_all(const ir_node *node); /** * Returns the result register requirements of an arm node. */ -const arm_register_req_t **get_arm_out_req_all(const ir_node *node); +const arch_register_req_t **get_arm_out_req_all(const ir_node *node); /** * Returns the argument register requirements of an arm node. */ -const arm_register_req_t *get_arm_in_req(const ir_node *node, int pos); +const arch_register_req_t *get_arm_in_req(const ir_node *node, int pos); /** * Returns the result register requirements of an arm node. */ -const arm_register_req_t *get_arm_out_req(const ir_node *node, int pos); +const arch_register_req_t *get_arm_out_req(const ir_node *node, int pos); /** * Sets the OUT register requirements at position pos. */ -void set_arm_req_out(ir_node *node, const arm_register_req_t *req, int pos); +void set_arm_req_out(ir_node *node, const arch_register_req_t *req, int pos); /** * Sets the complete OUT requirements of node. */ -void set_arm_req_out_all(ir_node *node, const arm_register_req_t **reqs); +void set_arm_req_out_all(ir_node *node, const arch_register_req_t **reqs); /** * Sets the IN register requirements at position pos. */ -void set_arm_req_in(ir_node *node, const arm_register_req_t *req, int pos); +void set_arm_req_in(ir_node *node, const arch_register_req_t *req, int pos); /** * Returns the register flag of an arm node. @@ -103,8 +103,8 @@ int get_arm_n_res(const ir_node *node); /** * Set the ARM machine node attributes to default values. */ -void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs, - const arm_register_req_t ** out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency); +void init_arm_attributes(ir_node *node, int flags, const arch_register_req_t ** in_reqs, + const arch_register_req_t ** out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency); /** * Returns the tarval diff --git a/ir/be/arm/arm_nodes_attr.h b/ir/be/arm/arm_nodes_attr.h index 522881a17..64a751da8 100644 --- a/ir/be/arm/arm_nodes_attr.h +++ b/ir/be/arm/arm_nodes_attr.h @@ -4,13 +4,6 @@ #include "../bearch.h" #include "../../common/firm_types.h" -/** A register requirement. */ -typedef struct _arm_register_req_t { - const arch_register_req_t req; - int same_pos; /**< in case of "should be same" we need to remember the pos to get the irn */ - int different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */ -} arm_register_req_t; - /** * Possible ARM register shift types. */ @@ -66,8 +59,8 @@ typedef struct _arm_attr_t { arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */ int n_res; /**< number of results for this node */ - const arm_register_req_t **in_req; /**< register requirements for arguments */ - const arm_register_req_t **out_req; /**< register requirements for results */ + const arch_register_req_t **in_req; /**< register requirements for arguments */ + const arch_register_req_t **out_req; /**< register requirements for results */ ir_mode *op_mode; /**< operation mode */ unsigned instr_fl; /**< condition code, shift modifier */ diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index 0f5694878..912b6d226 100644 --- a/ir/be/arm/bearch_arm.c +++ b/ir/be/arm/bearch_arm.c @@ -54,100 +54,63 @@ static set *cur_reg_set = NULL; * |___/ **************************************************/ -static ir_node *my_skip_proj(const ir_node *n) { - while (is_Proj(n)) - n = get_Proj_pred(n); - return (ir_node *)n; -} - /** * Return register requirements for a arm node. * If the node returns a tuple (mode_T) then the proj's * will be asked for this information. */ -static const arch_register_req_t *arm_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) { - const arm_register_req_t *irn_req; +static const +arch_register_req_t *arm_get_irn_reg_req(const void *self, const ir_node *node, + int pos) { long node_pos = pos == -1 ? 0 : pos; - ir_mode *mode = get_irn_mode(irn); + ir_mode *mode = get_irn_mode(node); FIRM_DBG_REGISTER(firm_dbg_module_t *mod, DEBUG_MODULE); - if (is_Block(irn) || mode == mode_X || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn)); - return NULL; + if (is_Block(node) || mode == mode_X || mode == mode_M) { + DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", node)); + return arch_no_register_req; } if (mode == mode_T && pos < 0) { - DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F\n", irn)); - return NULL; + DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F\n", node)); + return arch_no_register_req; } - DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); + DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, node)); - if (is_Proj(irn)) { + if (is_Proj(node)) { /* in case of a proj, we need to get the correct OUT slot */ /* of the node corresponding to the proj number */ if (pos == -1) { - node_pos = arm_translate_proj_pos(irn); + node_pos = arm_translate_proj_pos(node); } else { node_pos = pos; } - irn = my_skip_proj(irn); + node = skip_Proj_const(node); - DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); + DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", node, node_pos)); } /* get requirements for our own nodes */ - if (is_arm_irn(irn)) { + if (is_arm_irn(node)) { + const arch_register_req_t *req; if (pos >= 0) { - irn_req = get_arm_in_req(irn, pos); + req = get_arm_in_req(node, pos); + } else { + req = get_arm_out_req(node, node_pos); } - else { - irn_req = get_arm_out_req(irn, node_pos); - } - - DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); - - memcpy(req, &(irn_req->req), sizeof(*req)); - if (arch_register_req_is(&(irn_req->req), should_be_same)) { - assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI"); - req->other_same = get_irn_n(irn, irn_req->same_pos); - } - - if (arch_register_req_is(&(irn_req->req), should_be_different)) { - assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI"); - req->other_different = get_irn_n(irn, irn_req->different_pos); - } + DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", node, pos)); + return req; } - /* get requirements for FIRM nodes */ - else { - /* treat Phi like Const with default requirements */ - if (is_Phi(irn)) { - DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); - if (mode_is_float(mode)) { - memcpy(req, &(arm_default_req_arm_fpa.req), sizeof(*req)); - } - else if (mode_is_int(mode) || mode_is_reference(mode)) { - memcpy(req, &(arm_default_req_arm_gp.req), sizeof(*req)); - } - else if (mode == mode_T || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn)); - return NULL; - } - else { - assert(0 && "unsupported Phi-Mode"); - } - } - else { - DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn)); - req = NULL; - } - } + /* unknown should be tranformed by now */ + assert(!is_Unknown(node)); + DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", node)); - return req; + return arch_no_register_req; } static void arm_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { @@ -160,7 +123,7 @@ static void arm_set_irn_reg(const void *self, ir_node *irn, const arch_register_ } pos = arm_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj(irn); } if (is_arm_irn(irn)) { @@ -186,7 +149,7 @@ static const arch_register_t *arm_get_irn_reg(const void *self, const ir_node *i } pos = arm_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); } if (is_arm_irn(irn)) { @@ -202,7 +165,7 @@ static const arch_register_t *arm_get_irn_reg(const void *self, const ir_node *i } static arch_irn_class_t arm_classify(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_cfop(irn)) { return arch_irn_class_branch; @@ -215,7 +178,7 @@ static arch_irn_class_t arm_classify(const void *self, const ir_node *irn) { } static arch_irn_flags_t arm_get_flags(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_arm_irn(irn)) { return get_arm_flags(irn); @@ -871,9 +834,6 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * // ir_node *regs[16]; // int n_regs = 0; arch_register_class_t *gp = &arm_reg_classes[CLASS_arm_gp]; - static const arm_register_req_t *fp_req[] = { - &arm_default_req_arm_gp_r11 - }; ir_node *fp = be_abi_reg_map_get(reg_map, env->isa->bp); ir_node *ip = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R12]); @@ -900,23 +860,25 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * // set_arm_req_out(sp, &arm_default_req_arm_gp_sp, 0); // arch_set_irn_register(env->arch_env, sp, env->isa->sp); store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem); - set_arm_req_out(store, &arm_default_req_arm_gp_sp, 0); -// arch_set_irn_register(env->arch_env, store, env->isa->sp); + // TODO + // set_arm_req_out(store, &arm_default_req_arm_gp_sp, 0); + // arch_set_irn_register(env->arch_env, store, env->isa->sp); sp = new_r_Proj(irg, block, store, env->isa->sp->reg_class->mode, pn_arm_StoreStackM4Inc_ptr); - arch_set_irn_register(env->arch_env, sp, env->isa->sp); + arch_set_irn_register(env->arch_env, sp, env->isa->sp); *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(env->arch_env, 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(keep, 1, gp); + arch_set_irn_register(env->arch_env, keep, &arm_gp_regs[REG_R12]); + be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_gp_regs[REG_R12] ); fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp), new_tarval_from_long(4, get_irn_mode(fp))); - set_arm_req_out_all(fp, fp_req); - //set_arm_req_out(fp, &arm_default_req_arm_gp_r11, 0); - arch_set_irn_register(env->arch_env, fp, env->isa->bp); + // TODO... + //set_arm_req_out_all(fp, fp_req); + //set_arm_req_out(fp, &arm_default_req_arm_gp_r11, 0); + arch_set_irn_register(env->arch_env, fp, env->isa->bp); // be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R0], r0); // be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R1], r1); @@ -937,11 +899,8 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp); ir_node *curr_pc = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_PC]); ir_node *curr_lr = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_LR]); - static const arm_register_req_t *sub12_req[] = { - &arm_default_req_arm_gp_sp - }; -// TODO: Activate Omit fp in epilogue + // TODO: Activate Omit fp in epilogue if(env->flags.try_omit_fp) { curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK); add_irn_dep(curr_sp, *mem); @@ -959,12 +918,14 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m ir_node *load_node; tarval *tv = new_tarval_from_long(12,mode_Iu); sub12_node = new_rd_arm_Sub_i(NULL, env->irg, bl, curr_bp, mode_Iu, tv); - set_arm_req_out_all(sub12_node, sub12_req); + // FIXME + //set_arm_req_out_all(sub12_node, sub12_req); arch_set_irn_register(env->arch_env, sub12_node, env->isa->sp); load_node = new_rd_arm_LoadStackM3( NULL, env->irg, bl, sub12_node, *mem ); - set_arm_req_out(load_node, &arm_default_req_arm_gp_r11, 0); - set_arm_req_out(load_node, &arm_default_req_arm_gp_sp, 1); - set_arm_req_out(load_node, &arm_default_req_arm_gp_pc, 2); + // FIXME + //set_arm_req_out(load_node, &arm_default_req_arm_gp_r11, 0); + //set_arm_req_out(load_node, &arm_default_req_arm_gp_sp, 1); + //set_arm_req_out(load_node, &arm_default_req_arm_gp_pc, 2); curr_bp = new_r_Proj(env->irg, bl, load_node, env->isa->bp->reg_class->mode, pn_arm_LoadStackM3_res0); curr_sp = new_r_Proj(env->irg, bl, load_node, env->isa->sp->reg_class->mode, pn_arm_LoadStackM3_res1); curr_pc = new_r_Proj(env->irg, bl, load_node, mode_Iu, pn_arm_LoadStackM3_res2); diff --git a/ir/be/be_t.h b/ir/be/be_t.h index 5c581fc49..ed568fcd5 100644 --- a/ir/be/be_t.h +++ b/ir/be/be_t.h @@ -59,7 +59,6 @@ struct _be_options_t { struct _be_main_env_t { struct obstack obst; - struct _be_node_factory_t *node_factory; struct _arch_env_t *arch_env; struct _be_options_t *options; struct _arch_code_generator_t *cg; diff --git a/ir/be/beabi.c b/ir/be/beabi.c index 8b65ccaf0..7564d82bb 100644 --- a/ir/be/beabi.c +++ b/ir/be/beabi.c @@ -5,7 +5,6 @@ * @date 7.3.2005 * @cvsid $Id$ */ - #ifdef HAVE_CONFIG_H # include #endif @@ -28,6 +27,7 @@ #include "height.h" #include "pdeq.h" #include "irtools.h" +#include "raw_bitset.h" #include "be.h" #include "beabi.h" @@ -87,6 +87,9 @@ struct _be_abi_irg_t { pmap *keep_map; /**< mapping blocks to keep nodes. */ pset *ignore_regs; /**< Additional registers which shall be ignored. */ + arch_register_req_t sp_req; + arch_register_req_t sp_cls_req; + arch_irn_handler_t irn_handler; arch_irn_ops_t irn_ops; DEBUG_ONLY(firm_dbg_module_t *dbg;) /**< The debugging module. */ @@ -644,9 +647,6 @@ static ir_node *adjust_call(be_abi_irg_t *env, ir_node *irn, ir_node *curr_sp, i */ be_node_set_reg_class(low_call, be_pos_Call_ptr, call->cls_addr); - /* Set input requirement for stack pointer. */ - be_node_set_reg_class(low_call, be_pos_Call_sp, arch_get_irn_reg_class(isa->main_env->arch_env, curr_sp, -1)); - DBG((env->dbg, LEVEL_3, "\tcreated backend call %+F\n", low_call)); /* Set the register classes and constraints of the Call parameters. */ @@ -1891,6 +1891,7 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) pmap_entry *ent; ir_node *dummy; optimization_state_t state; + unsigned *limited_bitset; be_omit_fp = birg->main_env->options->omit_fp; @@ -1906,6 +1907,16 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) env->dce_survivor = new_survive_dce(); env->birg = birg; env->stack_phis = pset_new_ptr(16); + + env->sp_req.type = arch_register_req_type_limited; + env->sp_req.cls = arch_register_get_class(env->isa->sp); + limited_bitset = rbitset_obstack_alloc(&env->obst, env->sp_req.cls->n_regs); + rbitset_set(limited_bitset, arch_register_get_index(env->isa->sp)); + env->sp_req.limited = limited_bitset; + + env->sp_cls_req.type = arch_register_req_type_normal; + env->sp_cls_req.cls = arch_register_get_class(env->isa->sp); + /* Beware: later we replace this node by the real one, ensure it is not CSE'd to another Unknown or the stack pointer gets used */ save_optimization_state(&state); @@ -1938,8 +1949,9 @@ be_abi_irg_t *be_abi_introduce(be_irg_t *birg) /* Make some important node pointers survive the dead node elimination. */ survive_dce_register_irn(env->dce_survivor, &env->init_sp); - pmap_foreach(env->regs, ent) + pmap_foreach(env->regs, ent) { survive_dce_register_irn(env->dce_survivor, (ir_node **) &ent->value); + } arch_env_push_irn_handler(env->birg->main_env->arch_env, &env->irn_handler); @@ -2152,33 +2164,19 @@ static const void *abi_get_irn_ops(const arch_irn_handler_t *handler, const ir_n return res; } -static void be_abi_limited(void *data, bitset_t *bs) -{ - be_abi_irg_t *abi = data; - bitset_clear_all(bs); - bitset_set(bs, abi->isa->sp->index); -} - -static const arch_register_req_t *abi_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) +static +const arch_register_req_t *abi_get_irn_reg_req(const void *self, + const ir_node *irn, int pos) { - be_abi_irg_t *abi = get_abi_from_ops(self); - const arch_register_t *reg = abi->isa->sp; - - memset(req, 0, sizeof(req[0])); + be_abi_irg_t *abi = get_abi_from_ops(self); if(pos == BE_OUT_POS(0)) { - req->cls = reg->reg_class; - req->type = arch_register_req_type_limited; - req->limited = be_abi_limited; - req->limited_env = abi; - } - - else if(pos >= 0 && pos < get_irn_arity(irn)) { - req->cls = reg->reg_class; - req->type = arch_register_req_type_normal; + return &abi->sp_req; + } else if(pos >= 0 && pos < get_irn_arity(irn)) { + return &abi->sp_cls_req; } - return req; + return arch_no_register_req; } static void abi_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) diff --git a/ir/be/bearch.c b/ir/be/bearch.c index 3749ace9f..db457360d 100644 --- a/ir/be/bearch.c +++ b/ir/be/bearch.c @@ -5,9 +5,8 @@ * * $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #ifdef HAVE_ALLOCA_H @@ -27,43 +26,44 @@ #include "bitset.h" #include "pset.h" #include "entity.h" +#include "raw_bitset.h" #include "irprintf.h" /* Initialize the architecture environment struct. */ arch_env_t *arch_env_init(arch_env_t *env, const arch_isa_if_t *isa_if, FILE *file_handle, be_main_env_t *main_env) { - memset(env, 0, sizeof(*env)); - env->isa = isa_if->init(file_handle); - env->isa->main_env = main_env; - return env; + memset(env, 0, sizeof(*env)); + env->isa = isa_if->init(file_handle); + env->isa->main_env = main_env; + return env; } arch_env_t *arch_env_push_irn_handler(arch_env_t *env, - const arch_irn_handler_t *handler) + const arch_irn_handler_t *handler) { - assert(env->handlers_tos < ARCH_MAX_HANDLERS); - env->handlers[env->handlers_tos++] = handler; - return env; + assert(env->handlers_tos < ARCH_MAX_HANDLERS); + env->handlers[env->handlers_tos++] = handler; + return env; } const arch_irn_handler_t *arch_env_pop_irn_handler(arch_env_t *env) { - assert(env->handlers_tos > 0 && env->handlers_tos <= ARCH_MAX_HANDLERS); - return env->handlers[--env->handlers_tos]; + assert(env->handlers_tos > 0 && env->handlers_tos <= ARCH_MAX_HANDLERS); + return env->handlers[--env->handlers_tos]; } static const arch_irn_ops_t *fallback_irn_ops = NULL; int arch_register_class_put(const arch_register_class_t *cls, bitset_t *bs) { - if(bs) { - int i, n; - for(i = 0, n = cls->n_regs; i < n; ++i) - bitset_set(bs, i); - } + if(bs) { + int i, n; + for(i = 0, n = cls->n_regs; i < n; ++i) + bitset_set(bs, i); + } - return cls->n_regs; + return cls->n_regs; } /** @@ -75,17 +75,17 @@ int arch_register_class_put(const arch_register_class_t *cls, bitset_t *bs) static INLINE const arch_irn_ops_t * get_irn_ops(const arch_env_t *env, const ir_node *irn) { - int i; + int i; - for(i = env->handlers_tos - 1; i >= 0; --i) { - const arch_irn_handler_t *handler = env->handlers[i]; - const arch_irn_ops_t *ops = handler->get_irn_ops(handler, irn); + for(i = env->handlers_tos - 1; i >= 0; --i) { + const arch_irn_handler_t *handler = env->handlers[i]; + const arch_irn_ops_t *ops = handler->get_irn_ops(handler, irn); - if(ops) - return ops; - } + if(ops) + return ops; + } - return fallback_irn_ops; + return fallback_irn_ops; } const arch_irn_ops_t *arch_get_irn_ops(const arch_env_t *env, const ir_node *irn) { @@ -93,23 +93,22 @@ const arch_irn_ops_t *arch_get_irn_ops(const arch_env_t *env, const ir_node *irn } const arch_register_req_t *arch_get_register_req(const arch_env_t *env, - arch_register_req_t *req, const ir_node *irn, int pos) + const ir_node *irn, int pos) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - req->type = arch_register_req_type_none; - return ops->impl->get_irn_reg_req(ops, req, irn, pos); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + return ops->impl->get_irn_reg_req(ops, irn, pos); } void arch_set_frame_offset(const arch_env_t *env, ir_node *irn, int offset) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - ops->impl->set_frame_offset(ops, irn, offset); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + ops->impl->set_frame_offset(ops, irn, offset); } ir_entity *arch_get_frame_entity(const arch_env_t *env, ir_node *irn) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - return ops->impl->get_frame_entity(ops, irn); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + return ops->impl->get_frame_entity(ops, irn); } void arch_set_frame_entity(const arch_env_t *env, ir_node *irn, ir_entity *ent) @@ -126,16 +125,18 @@ int arch_get_sp_bias(const arch_env_t *env, ir_node *irn) arch_inverse_t *arch_get_inverse(const arch_env_t *env, const ir_node *irn, int i, arch_inverse_t *inverse, struct obstack *obstack) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - if(ops->impl->get_inverse) { - return ops->impl->get_inverse(ops, irn, i, inverse, obstack); - } else { - return NULL; - } + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + + if(ops->impl->get_inverse) { + return ops->impl->get_inverse(ops, irn, i, inverse, obstack); + } else { + return NULL; + } } int arch_possible_memory_operand(const arch_env_t *env, const ir_node *irn, unsigned int i) { const arch_irn_ops_t *ops = get_irn_ops(env, irn); + if(ops->impl->possible_memory_operand) { return ops->impl->possible_memory_operand(ops, irn, i); } else { @@ -145,6 +146,7 @@ int arch_possible_memory_operand(const arch_env_t *env, const ir_node *irn, unsi void arch_perform_memory_operand(const arch_env_t *env, ir_node *irn, ir_node *spill, unsigned int i) { const arch_irn_ops_t *ops = get_irn_ops(env, irn); + if(ops->impl->perform_memory_operand) { ops->impl->perform_memory_operand(ops, irn, spill, i); } else { @@ -154,42 +156,43 @@ void arch_perform_memory_operand(const arch_env_t *env, ir_node *irn, ir_node *s int arch_get_op_estimated_cost(const arch_env_t *env, const ir_node *irn) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - if(ops->impl->get_op_estimated_cost) { - return ops->impl->get_op_estimated_cost(ops, irn); - } else { - return 1; - } + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + + if(ops->impl->get_op_estimated_cost) { + return ops->impl->get_op_estimated_cost(ops, irn); + } else { + return 1; + } } int arch_is_possible_memory_operand(const arch_env_t *env, const ir_node *irn, int i) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - if(ops->impl->possible_memory_operand) { - return ops->impl->possible_memory_operand(ops, irn, i); - } else { - return 0; - } + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + + if(ops->impl->possible_memory_operand) { + return ops->impl->possible_memory_operand(ops, irn, i); + } else { + return 0; + } } int arch_get_allocatable_regs(const arch_env_t *env, const ir_node *irn, int pos, bitset_t *bs) { - arch_register_req_t local_req; - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, &local_req, irn, pos); - - if(req->type == arch_register_req_type_none) { - bitset_clear_all(bs); - return 0; - } - - if(arch_register_req_is(req, limited)) { - req->limited(req->limited_env, bs); - return bitset_popcnt(bs); - } - - arch_register_class_put(req->cls, bs); - return req->cls->n_regs; + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, irn, pos); + + if(req->type == arch_register_req_type_none) { + bitset_clear_all(bs); + return 0; + } + + if(arch_register_req_is(req, limited)) { + rbitset_copy_to_bitset(req->limited, bs); + return bitset_popcnt(bs); + } + + arch_register_class_put(req->cls, bs); + return req->cls->n_regs; } void arch_put_non_ignore_regs(const arch_env_t *env, const arch_register_class_t *cls, bitset_t *bs) @@ -218,64 +221,65 @@ int arch_count_non_ignore_regs(const arch_env_t *env, const arch_register_class_ int arch_is_register_operand(const arch_env_t *env, const ir_node *irn, int pos) { - arch_register_req_t local_req; const arch_irn_ops_t *ops = get_irn_ops(env, irn); - const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, &local_req, irn, pos); + const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, irn, pos); + return req != NULL; } int arch_reg_is_allocatable(const arch_env_t *env, const ir_node *irn, int pos, const arch_register_t *reg) { - arch_register_req_t req; + const arch_register_req_t *req; - arch_get_register_req(env, &req, irn, pos); + req = arch_get_register_req(env, irn, pos); - if(req.type == arch_register_req_type_none) + if(req->type == arch_register_req_type_none) return 0; - if(arch_register_req_is(&req, limited)) { - bitset_t *bs = bitset_alloca(req.cls->n_regs); - req.limited(req.limited_env, bs); - return bitset_is_set(bs, arch_register_get_index(reg)); + if(arch_register_req_is(req, limited)) { + assert(arch_register_get_class(reg) == req->cls); + return rbitset_is_set(req->limited, arch_register_get_index(reg)); } - return req.cls == reg->reg_class; + return req->cls == reg->reg_class; } const arch_register_class_t * arch_get_irn_reg_class(const arch_env_t *env, const ir_node *irn, int pos) { - arch_register_req_t local_req; - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, &local_req, irn, pos); - return req ? req->cls : NULL; + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + const arch_register_req_t *req = ops->impl->get_irn_reg_req(ops, irn, pos); + + assert(req->type != arch_register_req_type_none || req->cls == NULL); + + return req->cls; } extern const arch_register_t * arch_get_irn_register(const arch_env_t *env, const ir_node *irn) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - return ops->impl->get_irn_reg(ops, irn); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + return ops->impl->get_irn_reg(ops, irn); } extern void arch_set_irn_register(const arch_env_t *env, ir_node *irn, const arch_register_t *reg) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - ops->impl->set_irn_reg(ops, irn, reg); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + ops->impl->set_irn_reg(ops, irn, reg); } extern arch_irn_class_t arch_irn_classify(const arch_env_t *env, const ir_node *irn) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - return ops->impl->classify(ops, irn); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + return ops->impl->classify(ops, irn); } extern arch_irn_flags_t arch_irn_get_flags(const arch_env_t *env, const ir_node *irn) { - const arch_irn_ops_t *ops = get_irn_ops(env, irn); - return ops->impl->get_flags(ops, irn); + const arch_irn_ops_t *ops = get_irn_ops(env, irn); + return ops->impl->get_flags(ops, irn); } extern const char *arch_irn_flag_str(arch_irn_flags_t fl) @@ -292,31 +296,47 @@ extern const char *arch_irn_flag_str(arch_irn_flags_t fl) return "n/a"; } -extern char *arch_register_req_format(char *buf, size_t len, const arch_register_req_t *req) +extern char *arch_register_req_format(char *buf, size_t len, + const arch_register_req_t *req, + const ir_node *node) { char tmp[128]; snprintf(buf, len, "class: %s", req->cls->name); if(arch_register_req_is(req, limited)) { - bitset_pos_t elm; - bitset_t *bs = bitset_alloca(req->cls->n_regs); - req->limited(req->limited_env, bs); + unsigned n_regs = req->cls->n_regs; + unsigned i; + strncat(buf, " limited:", len); - bitset_foreach(bs, elm) { - strncat(buf, " ", len); - strncat(buf, req->cls->regs[elm].name, len); + for(i = 0; i < n_regs; ++i) { + if(rbitset_is_set(req->limited, i)) { + const arch_register_t *reg = &req->cls->regs[i]; + strncat(buf, " ", len); + strncat(buf, reg->name, len); + } } } if(arch_register_req_is(req, should_be_same)) { - ir_snprintf(tmp, sizeof(tmp), " same to: %+F", req->other_different); + const ir_node *same = get_irn_n(node, req->other_same); + ir_snprintf(tmp, sizeof(tmp), " same to: %+F", same); strncat(buf, tmp, len); } if(arch_register_req_is(req, should_be_different)) { - ir_snprintf(tmp, sizeof(tmp), " different to: %+F", req->other_different); + const ir_node *different = get_irn_n(node, req->other_different); + ir_snprintf(tmp, sizeof(tmp), " different to: %+F", different); strncat(buf, tmp, len); } return buf; } + +static const arch_register_req_t no_requirement = { + arch_register_req_type_none, + NULL, + NULL, + -1, + -1 +}; +const arch_register_req_t *arch_no_register_req = &no_requirement; diff --git a/ir/be/bearch.h b/ir/be/bearch.h index 7b19678af..0e2e0e3c1 100644 --- a/ir/be/bearch.h +++ b/ir/be/bearch.h @@ -15,19 +15,17 @@ #include "bemachine.h" #include "beirg.h" -struct _be_node_factory_t; - typedef enum _arch_register_type_t { - arch_register_type_none = 0, - arch_register_type_caller_save = 1, /**< The register must be saved by the caller + arch_register_type_none = 0, + arch_register_type_caller_save = 1, /**< The register must be saved by the caller upon a function call. It thus can be overwritten in the called function. */ - arch_register_type_callee_save = 2, /**< The register must be saved by the caller + arch_register_type_callee_save = 2, /**< The register must be saved by the caller upon a function call. It thus can be overwritten in the called function. */ - arch_register_type_ignore = 4, /**< Do not consider this register when allocating. */ - arch_register_type_joker = 8, /**< The emitter can choose an arbitrary register */ - arch_register_type_virtual = 16, /**< This is just a virtual register */ + arch_register_type_ignore = 4, /**< Do not consider this register when allocating. */ + arch_register_type_joker = 8, /**< The emitter can choose an arbitrary register */ + arch_register_type_virtual = 16, /**< This is just a virtual register */ } arch_register_type_t; /** @@ -43,22 +41,22 @@ typedef enum _arch_register_type_t { * A register. */ struct _arch_register_t { - const char *name; /**< The name of the register. */ - const arch_register_class_t *reg_class; /**< The class the register belongs to. */ - int index; /**< The index of the register in the class. */ - arch_register_type_t type; /**< The type of the register. */ - void *data; /**< Custom data. */ + const char *name; /**< The name of the register. */ + const arch_register_class_t *reg_class; /**< The class the register belongs to. */ + int index; /**< The index of the register in the class. */ + arch_register_type_t type; /**< The type of the register. */ + void *data; /**< Custom data. */ }; static INLINE const arch_register_class_t * _arch_register_get_class(const arch_register_t *reg) { - return reg->reg_class; + return reg->reg_class; } static INLINE int _arch_register_get_index(const arch_register_t *reg) { - return reg->index; + return reg->index; } static INLINE const char *_arch_register_get_name(const arch_register_t *reg) @@ -75,10 +73,10 @@ static INLINE const char *_arch_register_get_name(const arch_register_t *reg) * Like general purpose or floating point. */ struct _arch_register_class_t { - const char *name; /**< The name of the register class. */ - int n_regs; /**< Number of registers in this class. */ - ir_mode *mode; /**< The mode of the register class. */ - const arch_register_t *regs; /**< The array of registers. */ + const char *name; /**< The name of the register class. */ + int n_regs; /**< Number of registers in this class. */ + ir_mode *mode; /**< The mode of the register class. */ + const arch_register_t *regs; /**< The array of registers. */ }; /** return the number of registers in this register class */ @@ -101,20 +99,20 @@ extern int arch_register_class_put(const arch_register_class_t *cls, bitset_t *b static INLINE const arch_register_t * _arch_register_for_index(const arch_register_class_t *cls, int idx) { - assert(0 <= idx && idx < cls->n_regs); - return &cls->regs[idx]; + assert(0 <= idx && idx < cls->n_regs); + return &cls->regs[idx]; } #define arch_register_for_index(cls, idx) \ _arch_register_for_index(cls, idx) typedef enum _arch_operand_type_t { - arch_operand_type_invalid, - arch_operand_type_memory, - arch_operand_type_register, - arch_operand_type_immediate, - arch_operand_type_symconst, - arch_operand_type_last + arch_operand_type_invalid, + arch_operand_type_memory, + arch_operand_type_register, + arch_operand_type_immediate, + arch_operand_type_symconst, + arch_operand_type_last } arch_operand_type_t; /** @@ -142,26 +140,20 @@ typedef enum _arch_register_req_type_t { * Expresses requirements to register allocation for an operand. */ typedef struct _arch_register_req_t { - arch_register_req_type_t type; /**< The type of the constraint. */ - const arch_register_class_t *cls; /**< The register class this constraint belongs to. */ - - void (*limited)(void *limited_env, bitset_t *bs); - /**< In case of the 'limited' - constraint, this function - must put all allowable - registers in the bitset and - return the number of registers - in the bitset. */ + arch_register_req_type_t type; /**< The type of the constraint. */ + const arch_register_class_t *cls; /**< The register class this constraint belongs to. */ - void *limited_env; /**< This must passed to limited. */ + const unsigned *limited; /**< allowed register bitset */ - ir_node *other_same; /**< The other which shall have the same reg - as this one. (for case should_be_same). */ - - ir_node *other_different; /**< The other node from which this one's register - must be different (case must_be_different). */ + int other_same; /**< The in number which shall have + the same res (should_be_same)*/ + int other_different; /**< The other node from which this + one's register must be different + (case must_be_different). */ } arch_register_req_t; +extern const arch_register_req_t *arch_no_register_req; + /** * Format a register requirements information into a string. * @param buf The string where to put it to. @@ -169,7 +161,7 @@ typedef struct _arch_register_req_t { * @param req The requirements structure to format. * @return A pointer to buf. */ -extern char *arch_register_req_format(char *buf, size_t len, const arch_register_req_t *req); +extern char *arch_register_req_format(char *buf, size_t len, const arch_register_req_t *req, const ir_node *node); /** @@ -224,134 +216,134 @@ extern const char *arch_irn_flag_str(arch_irn_flags_t flag); struct _arch_irn_ops_if_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). - * @return The register requirements for the selected operand. - * The pointer returned is never NULL. - */ - const arch_register_req_t *(*get_irn_reg_req)(const void *self, - arch_register_req_t *req, const ir_node *irn, int pos); + /** + * 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). + * @return The register requirements for the selected operand. + * The pointer returned is never NULL. + */ + const arch_register_req_t *(*get_irn_reg_req)(const void *self, + 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)(const void *self, ir_node *irn, const arch_register_t *reg); + /** + * 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)(const void *self, 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 void *self, const ir_node *irn); + /** + * 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 void *self, const ir_node *irn); - /** - * Classify the node. - * @param irn The node. - * @return A classification. - */ - arch_irn_class_t (*classify)(const void *self, const ir_node *irn); + /** + * Classify the node. + * @param irn The node. + * @return A classification. + */ + arch_irn_class_t (*classify)(const void *self, 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 void *self, 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 void *self, const ir_node *irn); - /** - * Get the entity on the stack frame this node depends on. - * @param self The this pointer. - * @param irn The node in question. - * @return The entity on the stack frame or NULL, if the node does not have a - * stack frame entity. - */ - ir_entity *(*get_frame_entity)(const void *self, const ir_node *irn); + /** + * Get the entity on the stack frame this node depends on. + * @param self The this pointer. + * @param irn The node in question. + * @return The entity on the stack frame or NULL, if the node does not have a + * stack frame entity. + */ + ir_entity *(*get_frame_entity)(const void *self, const ir_node *irn); - /** - * Set the entity on the stack frame this node depends on. - * @param self The this pointer. - * @param irn The node in question. - * @param ent The entity to set - */ - void (*set_frame_entity)(const void *self, ir_node *irn, ir_entity *ent); + /** + * Set the entity on the stack frame this node depends on. + * @param self The this pointer. + * @param irn The node in question. + * @param ent The entity to set + */ + void (*set_frame_entity)(const void *self, ir_node *irn, ir_entity *ent); - /** - * Set the offset of a node carrying an entity on the stack frame. - * @param self The this pointer. - * @param irn The node. - * @param offset The offset of the node's stack frame entity. - */ - void (*set_frame_offset)(const void *self, ir_node *irn, int offset); + /** + * Set the offset of a node carrying an entity on the stack frame. + * @param self The this pointer. + * @param irn The node. + * @param offset The offset of the node's stack frame entity. + */ + void (*set_frame_offset)(const void *self, ir_node *irn, int offset); - /** - * Returns the delta of the stackpointer for nodes that increment or - * decrement the stackpointer with a constant value. (push, pop - * nodes on most architectures). - * A positive value stands for an expanding stack area, a negative value for - * a shrinking one. - * - * @param self The this pointer - * @param irn The node - * @return 0 if the stackpointer is not modified with a constant - * value, otherwise the increment/decrement value - */ - int (*get_sp_bias)(const void *self, const ir_node *irn); + /** + * Returns the delta of the stackpointer for nodes that increment or + * decrement the stackpointer with a constant value. (push, pop + * nodes on most architectures). + * A positive value stands for an expanding stack area, a negative value for + * a shrinking one. + * + * @param self The this pointer + * @param irn The node + * @return 0 if the stackpointer is not modified with a constant + * value, otherwise the increment/decrement value + */ + int (*get_sp_bias)(const void *self, const ir_node *irn); - /** - * Returns an inverse operation which yields the i-th argument - * of the given node as result. - * - * @param self The this pointer. - * @param irn The original operation - * @param i Index of the argument we want the inverse operation to yield - * @param inverse struct to be filled with the resulting inverse op - * @param obstack The obstack to use for allocation of the returned nodes array - * @return The inverse operation or NULL if operation invertible - */ - arch_inverse_t *(*get_inverse)(const void *self, const ir_node *irn, int i, arch_inverse_t *inverse, struct obstack *obstack); + /** + * Returns an inverse operation which yields the i-th argument + * of the given node as result. + * + * @param self The this pointer. + * @param irn The original operation + * @param i Index of the argument we want the inverse operation to yield + * @param inverse struct to be filled with the resulting inverse op + * @param obstack The obstack to use for allocation of the returned nodes array + * @return The inverse operation or NULL if operation invertible + */ + arch_inverse_t *(*get_inverse)(const void *self, const ir_node *irn, int i, arch_inverse_t *inverse, struct obstack *obstack); - /** - * Get the estimated cycle count for @p irn. - * - * @param self The this pointer. - * @param irn The node. - * - * @return The estimated cycle count for this operation - */ - int (*get_op_estimated_cost)(const void *self, const ir_node *irn); + /** + * Get the estimated cycle count for @p irn. + * + * @param self The this pointer. + * @param irn The node. + * + * @return The estimated cycle count for this operation + */ + int (*get_op_estimated_cost)(const void *self, const ir_node *irn); - /** - * Asks the backend whether operand @p i of @p irn can be loaded form memory internally - * - * @param self The this pointer. - * @param irn The node. - * @param i Index of the argument we would like to know whether @p irn can load it form memory internally - * - * @return nonzero if argument can be loaded or zero otherwise - */ - int (*possible_memory_operand)(const void *self, const ir_node *irn, unsigned int i); + /** + * Asks the backend whether operand @p i of @p irn can be loaded form memory internally + * + * @param self The this pointer. + * @param irn The node. + * @param i Index of the argument we would like to know whether @p irn can load it form memory internally + * + * @return nonzero if argument can be loaded or zero otherwise + */ + int (*possible_memory_operand)(const void *self, const ir_node *irn, unsigned int i); - /** - * Ask the backend to assimilate @p reload of operand @p i into @p irn. - * - * @param self The this pointer. - * @param irn The node. - * @param spill The spill. - * @param i The position of the reload. - */ - void (*perform_memory_operand)(const void *self, ir_node *irn, ir_node *spill, unsigned int i); + /** + * Ask the backend to assimilate @p reload of operand @p i into @p irn. + * + * @param self The this pointer. + * @param irn The node. + * @param spill The spill. + * @param i The position of the reload. + */ + void (*perform_memory_operand)(const void *self, ir_node *irn, ir_node *spill, unsigned int i); }; /** @@ -386,8 +378,7 @@ extern void arch_perform_memory_operand(const arch_env_t *env, ir_node *irn, ir_ * operand was no register operand. */ extern const arch_register_req_t * -arch_get_register_req(const arch_env_t *env, arch_register_req_t *req, - const ir_node *irn, int pos); +arch_get_register_req(const arch_env_t *env, const ir_node *irn, int pos); /** * Check if an operand is a register operand. @@ -752,13 +743,12 @@ struct _arch_isa_if_t { * Keep this everywhere you're going. */ struct _arch_env_t { - const struct _be_node_factory_t *node_factory; /**< The node factory for be nodes. */ - arch_isa_t *isa; /**< The isa about which everything is. */ + arch_isa_t *isa; /**< The isa about which everything is. */ - arch_irn_handler_t const *handlers[ARCH_MAX_HANDLERS]; /**< The handlers are organized as + arch_irn_handler_t const *handlers[ARCH_MAX_HANDLERS]; /**< The handlers are organized as a stack. */ - int handlers_tos; /**< The stack pointer of the handler + int handlers_tos; /**< The stack pointer of the handler stack. */ }; diff --git a/ir/be/beblocksched.c b/ir/be/beblocksched.c index abec3545d..9d744a786 100644 --- a/ir/be/beblocksched.c +++ b/ir/be/beblocksched.c @@ -6,8 +6,8 @@ * CVS-Id: $Id$ */ #ifdef HAVE_CONFIG_H -#include "config.h" -#endif /* HAVE_CONFIG_H */ +#include +#endif #include "beblocksched.h" @@ -37,6 +37,8 @@ #include #endif /* WITH_ILP */ +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) + typedef enum _blocksched_algos_t { BLOCKSCHED_NAIV, BLOCKSCHED_EXTBB, BLOCKSCHED_GREEDY, BLOCKSCHED_ILP } blocksched_algos_t; @@ -92,7 +94,6 @@ typedef struct _blocksched_env_t { edge_t *edges; pdeq *worklist; int blockcount; - DEBUG_ONLY(firm_dbg_module_t *dbg;) } blocksched_env_t; /** @@ -191,7 +192,7 @@ static void coalesce_blocks(blocksched_env_t *env) continue; /* schedule the 2 blocks behind each other */ - DBG((env->dbg, LEVEL_1, "Coalesce (Jump) %+F -> %+F (%.3g)\n", + DBG((dbg, LEVEL_1, "Coalesce (Jump) %+F -> %+F (%.3g)\n", pred_entry->block, entry->block, edge->execfreq)); pred_entry->next = entry; entry->prev = pred_entry; @@ -217,7 +218,7 @@ static void coalesce_blocks(blocksched_env_t *env) continue; /* schedule the 2 blocks behind each other */ - DBG((env->dbg, LEVEL_1, "Coalesce (CondJump) %+F -> %+F (%.3g)\n", + DBG((dbg, LEVEL_1, "Coalesce (CondJump) %+F -> %+F (%.3g)\n", pred_entry->block, entry->block, edge->execfreq)); pred_entry->next = entry; entry->prev = pred_entry; @@ -238,7 +239,7 @@ static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *en env->blockcount++; mark_irn_visited(block); - DBG((env->dbg, LEVEL_1, "Pick succ of %+F\n", block)); + DBG((dbg, LEVEL_1, "Pick succ of %+F\n", block)); /* put all successors into the worklist */ foreach_block_succ(block, edge) { @@ -263,7 +264,7 @@ static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *en if (irn_visited(succ_entry->block)) continue; - DBG((env->dbg, LEVEL_1, "Put %+F into worklist\n", succ_entry->block)); + DBG((dbg, LEVEL_1, "Put %+F into worklist\n", succ_entry->block)); pdeq_putr(env->worklist, succ_entry->block); } @@ -272,7 +273,7 @@ static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *en return; } - DBG((env->dbg, LEVEL_1, "deciding...\n")); + DBG((dbg, LEVEL_1, "deciding...\n")); best_succ_execfreq = -1; /* no successor yet: pick the successor block with the highest execution @@ -297,11 +298,11 @@ static void pick_block_successor(blocksched_entry_t *entry, blocksched_env_t *en } if (succ == NULL) { - DBG((env->dbg, LEVEL_1, "pick from worklist\n")); + DBG((dbg, LEVEL_1, "pick from worklist\n")); do { if (pdeq_empty(env->worklist)) { - DBG((env->dbg, LEVEL_1, "worklist empty\n")); + DBG((dbg, LEVEL_1, "worklist empty\n")); return; } succ = pdeq_getl(env->worklist); @@ -339,12 +340,12 @@ static ir_node **create_blocksched_array(blocksched_env_t *env, blocksched_entry blocksched_entry_t *entry; block_list = NEW_ARR_D(ir_node *, obst, count); - DBG((env->dbg, LEVEL_1, "Blockschedule:\n")); + DBG((dbg, LEVEL_1, "Blockschedule:\n")); for (entry = first; entry != NULL; entry = entry->next) { assert(i < count); block_list[i++] = entry->block; - DBG((env->dbg, LEVEL_1, "\t%+F\n", entry->block)); + DBG((dbg, LEVEL_1, "\t%+F\n", entry->block)); } assert(i == count); @@ -366,7 +367,6 @@ static ir_node **create_block_schedule_greedy(ir_graph *irg, ir_exec_freq *execf env.edges = NEW_ARR_F(edge_t, 0); env.worklist = NULL; env.blockcount = 0; - FIRM_DBG_REGISTER(env.dbg, "firm.be.blocksched"); // collect edge execution frequencies irg_block_walk_graph(irg, collect_egde_frequency, NULL, &env); @@ -504,7 +504,7 @@ static void coalesce_blocks_ilp(blocksched_ilp_env_t *env) pred = get_Block_cfgpred_block(block, edge->pos); entry = get_irn_link(pred); - DBG((env->env.dbg, LEVEL_1, "Adding out cst to %+F from %+F,%d\n", + DBG((dbg, LEVEL_1, "Adding out cst to %+F from %+F,%d\n", pred, block, edge->pos)); lpp_set_factor_fast(env->lpp, entry->out_cst, edge->ilpvar, 1.0); } @@ -567,7 +567,6 @@ static ir_node **create_block_schedule_ilp(ir_graph *irg, ir_exec_freq *execfreq env.env.worklist = NULL; env.env.blockcount = 0; env.ilpedges = NEW_ARR_F(ilp_edge_t, 0); - FIRM_DBG_REGISTER(env.env.dbg, "firm.be.blocksched"); env.lpp = new_lpp("blockschedule", lpp_minimize); lpp_set_time_limit(env.lpp, 20); @@ -698,6 +697,8 @@ void be_init_blocksched(void) lc_opt_entry_t *blocksched_grp = lc_opt_get_grp(be_grp, "blocksched"); lc_opt_add_table(blocksched_grp, be_blocksched_options); + + FIRM_DBG_REGISTER(dbg, "firm.be.blocksched"); } BE_REGISTER_MODULE_CONSTRUCTOR(be_init_blocksched); diff --git a/ir/be/bechordal.c b/ir/be/bechordal.c index 604ff676b..76ccc175e 100644 --- a/ir/be/bechordal.c +++ b/ir/be/bechordal.c @@ -25,6 +25,7 @@ #include "pset.h" #include "list.h" #include "bitset.h" +#include "raw_bitset.h" #include "iterator.h" #include "bipartite.h" #include "hungarian.h" @@ -197,7 +198,7 @@ static bitset_t *get_decisive_partner_regs(bitset_t *bs, const be_operand_t *o1, return bs; } - assert(o1->req.cls == o2->req.cls); + assert(o1->req->cls == o2->req->cls); if(bitset_contains(o1->regs, o2->regs)) bitset_copy(bs, o1->regs); @@ -223,8 +224,8 @@ static be_insn_t *chordal_scan_insn(be_chordal_env_t *env, ir_node *irn) static ir_node *prepare_constr_insn(be_chordal_env_t *env, ir_node *irn) { const arch_env_t *aenv = env->birg->main_env->arch_env; - bitset_t *def_constr = bitset_alloca(env->cls->n_regs); bitset_t *tmp = bitset_alloca(env->cls->n_regs); + bitset_t *def_constr = bitset_alloca(env->cls->n_regs); ir_node *bl = get_nodes_block(irn); be_lv_t *lv = env->birg->lv; @@ -235,7 +236,7 @@ static ir_node *prepare_constr_insn(be_chordal_env_t *env, ir_node *irn) ir_node *op = get_irn_n(irn, i); ir_node *copy; const arch_register_t *reg; - arch_register_req_t req; + const arch_register_req_t *req; if (arch_get_irn_reg_class(aenv, irn, i) != env->cls) continue; @@ -247,14 +248,11 @@ static ir_node *prepare_constr_insn(be_chordal_env_t *env, ir_node *irn) if(arch_register_type_is(reg, joker)) continue; - arch_get_register_req(aenv, &req, irn, i); - if (!arch_register_req_is(&req, limited)) + req = arch_get_register_req(aenv, irn, i); + if (!arch_register_req_is(req, limited)) continue; - bitset_clear_all(tmp); - req.limited(req.limited_env, tmp); - - if (bitset_is_set(tmp, reg->index)) + if (rbitset_is_set(req->limited, reg->index)) continue; copy = be_new_Copy(env->cls, env->irg, bl, op); @@ -383,16 +381,19 @@ static void pair_up_operands(const be_chordal_alloc_env_t *alloc_env, be_insn_t int n_total; const be_operand_t *op = &insn->ops[i]; - if (! values_interfere(lv, op->irn, op->carrier) && ! op->partner) { - bitset_clear_all(bs); - bitset_copy(bs, op->regs); - bitset_and(bs, out_op->regs); - n_total = bitset_popcnt(op->regs) + bitset_popcnt(out_op->regs); + if (op->partner != NULL) + continue; + if (values_interfere(lv, op->irn, op->carrier)) + continue; - if (bitset_popcnt(bs) > 0 && n_total < smallest_n_regs) { - smallest = i; - smallest_n_regs = n_total; - } + bitset_clear_all(bs); + bitset_copy(bs, op->regs); + bitset_and(bs, out_op->regs); + n_total = bitset_popcnt(op->regs) + bitset_popcnt(out_op->regs); + + if (bitset_popcnt(bs) > 0 && n_total < smallest_n_regs) { + smallest = i; + smallest_n_regs = n_total; } } @@ -405,19 +406,16 @@ static void pair_up_operands(const be_chordal_alloc_env_t *alloc_env, be_insn_t } -static ir_node *pre_process_constraints(be_chordal_alloc_env_t *alloc_env, be_insn_t **the_insn) +static ir_node *pre_process_constraints(be_chordal_alloc_env_t *alloc_env, + be_insn_t **the_insn) { be_chordal_env_t *env = alloc_env->chordal_env; const arch_env_t *aenv = env->birg->main_env->arch_env; be_insn_t *insn = *the_insn; - ir_node *bl = get_nodes_block(insn->irn); - ir_node *copy = NULL; ir_node *perm = NULL; bitset_t *out_constr = bitset_alloca(env->cls->n_regs); - bitset_t *bs = bitset_alloca(env->cls->n_regs); be_lv_t *lv = env->birg->lv; - DEBUG_ONLY(firm_dbg_module_t *dbg = alloc_env->constr_dbg;) - + const ir_edge_t *edge; int i; assert(insn->has_constraints && "only do this for constrained nodes"); @@ -434,11 +432,6 @@ static ir_node *pre_process_constraints(be_chordal_alloc_env_t *alloc_env, be_in bitset_or(out_constr, op->regs); } - (void) bl; - (void) copy; - (void) bs; - DEBUG_ONLY((void) dbg;) - /* Make the Perm, recompute liveness and re-scan the insn since the in operands are now the Projs of the Perm. @@ -446,38 +439,37 @@ static ir_node *pre_process_constraints(be_chordal_alloc_env_t *alloc_env, be_in perm = insert_Perm_after(aenv, lv, env->cls, env->birg->dom_front, sched_prev(insn->irn)); /* Registers are propagated by insert_Perm_after(). Clean them here! */ - if(perm) { - const ir_edge_t *edge; + if(perm == NULL) + return NULL; - be_stat_ev("constr_perm", get_irn_arity(perm)); - foreach_out_edge(perm, edge) { - ir_node *proj = get_edge_src_irn(edge); - arch_set_irn_register(aenv, proj, NULL); - } + be_stat_ev("constr_perm", get_irn_arity(perm)); + foreach_out_edge(perm, edge) { + ir_node *proj = get_edge_src_irn(edge); + arch_set_irn_register(aenv, proj, NULL); + } - /* - We also have to re-build the insn since the input operands are now the Projs of - the Perm. Recomputing liveness is also a good idea if a Perm is inserted, since - the live sets may change. - */ - // be_liveness_recompute(lv); - obstack_free(&env->obst, insn); - *the_insn = insn = chordal_scan_insn(env, insn->irn); + /* + We also have to re-build the insn since the input operands are now the Projs of + the Perm. Recomputing liveness is also a good idea if a Perm is inserted, since + the live sets may change. + */ + // be_liveness_recompute(lv); + obstack_free(&env->obst, insn); + *the_insn = insn = chordal_scan_insn(env, insn->irn); + /* + Copy the input constraints of the insn to the Perm as output + constraints. Succeeding phases (coalescing) will need that. + */ + for(i = insn->use_start; i < insn->n_ops; ++i) { + be_operand_t *op = &insn->ops[i]; + ir_node *proj = op->carrier; /* - Copy the input constraints of the insn to the Perm as output - constraints. Succeeding phases (coalescing will need that). + Note that the predecessor must not be a Proj of the Perm, + since ignore-nodes are not Perm'ed. */ - for(i = insn->use_start; i < insn->n_ops; ++i) { - be_operand_t *op = &insn->ops[i]; - ir_node *proj = op->carrier; - /* - Note that the predecessor must not be a Proj of the Perm, - since ignore-nodes are not Perm'ed. - */ - if(op->has_constraints && is_Proj(proj) && get_Proj_pred(proj) == perm) { - be_set_constr_limited(perm, BE_OUT_POS(get_Proj_proj(proj)), &op->req); - } + if(op->has_constraints && is_Proj(proj) && get_Proj_pred(proj) == perm) { + be_set_constr_limited(perm, BE_OUT_POS(get_Proj_proj(proj)), op->req); } } @@ -486,6 +478,19 @@ static ir_node *pre_process_constraints(be_chordal_alloc_env_t *alloc_env, be_in static ir_node *handle_constraints(be_chordal_alloc_env_t *alloc_env, ir_node *irn, int *silent) { + const arch_env_t *aenv; + int n_regs; + bitset_t *bs; + ir_node **alloc_nodes; + hungarian_problem_t *bp; + int *assignment; + pmap *partners; + DEBUG_ONLY(firm_dbg_module_t *dbg); + int i, n_alloc; + long col; + const ir_edge_t *edge; + ir_node *perm = NULL; + int match_res, cost; be_chordal_env_t *env = alloc_env->chordal_env; void *base = obstack_base(&env->obst); be_insn_t *insn = chordal_scan_insn(env, irn); @@ -516,159 +521,155 @@ static ir_node *handle_constraints(be_chordal_alloc_env_t *alloc_env, ir_node *i Perms inserted before the constraint handling phase are considered to be correctly precolored. These Perms arise during the ABI handling phase. */ - if(insn->has_constraints) { - const arch_env_t *aenv = env->birg->main_env->arch_env; - int n_regs = env->cls->n_regs; - bitset_t *bs = bitset_alloca(n_regs); - ir_node **alloc_nodes = alloca(n_regs * sizeof(alloc_nodes[0])); - hungarian_problem_t *bp= hungarian_new(n_regs, n_regs, 2, HUNGARIAN_MATCH_PERFECT); -// bipartite_t *bp = bipartite_new(n_regs, n_regs); - int *assignment = alloca(n_regs * sizeof(assignment[0])); - pmap *partners = pmap_create(); - DEBUG_ONLY(firm_dbg_module_t *dbg = alloc_env->constr_dbg;) - - int i, n_alloc; - long col; - const ir_edge_t *edge; - ir_node *perm = NULL; - int match_res, cost; + if(!insn->has_constraints) + goto end; - /* - prepare the constraint handling of this node. - Perms are constructed and Copies are created for constrained values - interfering with the instruction. - */ - perm = pre_process_constraints(alloc_env, &insn); + aenv = env->birg->main_env->arch_env; + n_regs = env->cls->n_regs; + bs = bitset_alloca(n_regs); + alloc_nodes = alloca(n_regs * sizeof(alloc_nodes[0])); + bp = hungarian_new(n_regs, n_regs, 2, HUNGARIAN_MATCH_PERFECT); + // bipartite_t *bp = bipartite_new(n_regs, n_regs); + assignment = alloca(n_regs * sizeof(assignment[0])); + partners = pmap_create(); + DEBUG_ONLY(dbg = alloc_env->constr_dbg;) - /* find suitable in operands to the out operands of the node. */ - pair_up_operands(alloc_env, insn); + /* + prepare the constraint handling of this node. + Perms are constructed and Copies are created for constrained values + interfering with the instruction. + */ + perm = pre_process_constraints(alloc_env, &insn); - /* - look at the in/out operands and add each operand (and its possible partner) - to a bipartite graph (left: nodes with partners, right: admissible colors). - */ - for(i = 0, n_alloc = 0; i < insn->n_ops; ++i) { - be_operand_t *op = &insn->ops[i]; + /* find suitable in operands to the out operands of the node. */ + pair_up_operands(alloc_env, insn); - /* - If the operand has no partner or the partner has not been marked - for allocation, determine the admissible registers and mark it - for allocation by associating the node and its partner with the - set of admissible registers via a bipartite graph. - */ - if(!op->partner || !pmap_contains(partners, op->partner->carrier)) { + /* + look at the in/out operands and add each operand (and its possible partner) + to a bipartite graph (left: nodes with partners, right: admissible colors). + */ + for(i = 0, n_alloc = 0; i < insn->n_ops; ++i) { + be_operand_t *op = &insn->ops[i]; - pmap_insert(partners, op->carrier, op->partner ? op->partner->carrier : NULL); - alloc_nodes[n_alloc] = op->carrier; + /* + If the operand has no partner or the partner has not been marked + for allocation, determine the admissible registers and mark it + for allocation by associating the node and its partner with the + set of admissible registers via a bipartite graph. + */ + if(!op->partner || !pmap_contains(partners, op->partner->carrier)) { - DBG((dbg, LEVEL_2, "\tassociating %+F and %+F\n", op->carrier, op->partner ? op->partner->carrier : NULL)); + pmap_insert(partners, op->carrier, op->partner ? op->partner->carrier : NULL); + alloc_nodes[n_alloc] = op->carrier; - bitset_clear_all(bs); - get_decisive_partner_regs(bs, op, op->partner); + DBG((dbg, LEVEL_2, "\tassociating %+F and %+F\n", op->carrier, op->partner ? op->partner->carrier : NULL)); - DBG((dbg, LEVEL_2, "\tallowed registers for %+F: %B\n", op->carrier, bs)); + bitset_clear_all(bs); + get_decisive_partner_regs(bs, op, op->partner); - bitset_foreach(bs, col) - hungarian_add(bp, n_alloc, col, 1); -// bipartite_add(bp, n_alloc, col); + DBG((dbg, LEVEL_2, "\tallowed registers for %+F: %B\n", op->carrier, bs)); - n_alloc++; + bitset_foreach(bs, col) { + hungarian_add(bp, n_alloc, col, 1); + // bipartite_add(bp, n_alloc, col); } + + n_alloc++; } + } - /* - Put all nodes which live through the constrained instruction also to the - allocation bipartite graph. They are considered unconstrained. - */ - if(perm) { - foreach_out_edge(perm, edge) { - ir_node *proj = get_edge_src_irn(edge); + /* + Put all nodes which live through the constrained instruction also to the + allocation bipartite graph. They are considered unconstrained. + */ + if(perm != NULL) { + foreach_out_edge(perm, edge) { + ir_node *proj = get_edge_src_irn(edge); - assert(is_Proj(proj)); + assert(is_Proj(proj)); - if(values_interfere(lv, proj, irn) && !pmap_contains(partners, proj)) { - assert(n_alloc < n_regs); - alloc_nodes[n_alloc] = proj; - pmap_insert(partners, proj, NULL); + if(!values_interfere(lv, proj, irn) || pmap_contains(partners, proj)) + continue; - bitset_clear_all(bs); - arch_put_non_ignore_regs(aenv, env->cls, bs); - bitset_andnot(bs, env->ignore_colors); - bitset_foreach(bs, col) - hungarian_add(bp, n_alloc, col, 1); -// bipartite_add(bp, n_alloc, col); + assert(n_alloc < n_regs); + alloc_nodes[n_alloc] = proj; + pmap_insert(partners, proj, NULL); - n_alloc++; - } + bitset_clear_all(bs); + arch_put_non_ignore_regs(aenv, env->cls, bs); + bitset_andnot(bs, env->ignore_colors); + bitset_foreach(bs, col) { + hungarian_add(bp, n_alloc, col, 1); + // bipartite_add(bp, n_alloc, col); } + + n_alloc++; } + } - /* Compute a valid register allocation. */ - hungarian_prepare_cost_matrix(bp, HUNGARIAN_MODE_MAXIMIZE_UTIL); - match_res = hungarian_solve(bp, assignment, &cost, 1); - assert(match_res == 0 && "matching failed"); - //bipartite_matching(bp, assignment); + /* Compute a valid register allocation. */ + hungarian_prepare_cost_matrix(bp, HUNGARIAN_MODE_MAXIMIZE_UTIL); + match_res = hungarian_solve(bp, assignment, &cost, 1); + assert(match_res == 0 && "matching failed"); + //bipartite_matching(bp, assignment); - /* Assign colors obtained from the matching. */ - for(i = 0; i < n_alloc; ++i) { - const arch_register_t *reg; - ir_node *nodes[2]; - int j; + /* Assign colors obtained from the matching. */ + for(i = 0; i < n_alloc; ++i) { + const arch_register_t *reg; + ir_node *nodes[2]; + int j; - assert(assignment[i] >= 0 && "there must have been a register assigned"); - reg = arch_register_for_index(env->cls, assignment[i]); + assert(assignment[i] >= 0 && "there must have been a register assigned"); + reg = arch_register_for_index(env->cls, assignment[i]); - nodes[0] = alloc_nodes[i]; - nodes[1] = pmap_get(partners, alloc_nodes[i]); + nodes[0] = alloc_nodes[i]; + nodes[1] = pmap_get(partners, alloc_nodes[i]); - for(j = 0; j < 2; ++j) { - if(!nodes[j]) - continue; + for(j = 0; j < 2; ++j) { + if(!nodes[j]) + continue; - arch_set_irn_register(aenv, nodes[j], reg); - (void) pset_hinsert_ptr(alloc_env->pre_colored, nodes[j]); - DBG((dbg, LEVEL_2, "\tsetting %+F to register %s\n", nodes[j], reg->name)); - } + arch_set_irn_register(aenv, nodes[j], reg); + (void) pset_hinsert_ptr(alloc_env->pre_colored, nodes[j]); + DBG((dbg, LEVEL_2, "\tsetting %+F to register %s\n", nodes[j], reg->name)); } + } + /* Allocate the non-constrained Projs of the Perm. */ + if(perm != NULL) { + bitset_clear_all(bs); - /* Allocate the non-constrained Projs of the Perm. */ - if(perm) { - - bitset_clear_all(bs); - - /* Put the colors of all Projs in a bitset. */ - foreach_out_edge(perm, edge) { - ir_node *proj = get_edge_src_irn(edge); - const arch_register_t *reg = arch_get_irn_register(aenv, proj); + /* Put the colors of all Projs in a bitset. */ + foreach_out_edge(perm, edge) { + ir_node *proj = get_edge_src_irn(edge); + const arch_register_t *reg = arch_get_irn_register(aenv, proj); - if(reg != NULL) - bitset_set(bs, reg->index); - } + if(reg != NULL) + bitset_set(bs, reg->index); + } - /* Assign the not yet assigned Projs of the Perm a suitable color. */ - foreach_out_edge(perm, edge) { - ir_node *proj = get_edge_src_irn(edge); - const arch_register_t *reg = arch_get_irn_register(aenv, proj); + /* Assign the not yet assigned Projs of the Perm a suitable color. */ + foreach_out_edge(perm, edge) { + ir_node *proj = get_edge_src_irn(edge); + const arch_register_t *reg = arch_get_irn_register(aenv, proj); - DBG((dbg, LEVEL_2, "\tchecking reg of %+F: %s\n", proj, reg ? reg->name : "")); + DBG((dbg, LEVEL_2, "\tchecking reg of %+F: %s\n", proj, reg ? reg->name : "")); - if(reg == NULL) { - col = get_next_free_reg(alloc_env, bs); - reg = arch_register_for_index(env->cls, col); - bitset_set(bs, reg->index); - arch_set_irn_register(aenv, proj, reg); - pset_insert_ptr(alloc_env->pre_colored, proj); - DBG((dbg, LEVEL_2, "\tsetting %+F to register %s\n", proj, reg->name)); - } + if(reg == NULL) { + col = get_next_free_reg(alloc_env, bs); + reg = arch_register_for_index(env->cls, col); + bitset_set(bs, reg->index); + arch_set_irn_register(aenv, proj, reg); + pset_insert_ptr(alloc_env->pre_colored, proj); + DBG((dbg, LEVEL_2, "\tsetting %+F to register %s\n", proj, reg->name)); } } - - //bipartite_free(bp); - hungarian_free(bp); - pmap_destroy(partners); } + //bipartite_free(bp); + hungarian_free(bp); + pmap_destroy(partners); + end: obstack_free(&env->obst, base); return res; @@ -885,13 +886,11 @@ static void assign(ir_node *block, void *env_ptr) const arch_register_t *reg; int col = NO_COLOR; - if(pset_find_ptr(alloc_env->pre_colored, irn) || ignore) { + if(ignore || pset_find_ptr(alloc_env->pre_colored, irn)) { reg = arch_get_irn_register(arch_env, irn); col = reg->index; assert(!bitset_is_set(colors, col) && "pre-colored register must be free"); - } - - else { + } else { col = get_next_free_reg(alloc_env, colors); reg = arch_register_for_index(env->cls, col); assert(arch_get_irn_register(arch_env, irn) == NULL && "This node must not have been assigned a register yet"); diff --git a/ir/be/becopyheur.c b/ir/be/becopyheur.c index d626badd6..233a749ed 100644 --- a/ir/be/becopyheur.c +++ b/ir/be/becopyheur.c @@ -13,7 +13,7 @@ * conflicts is the best one. */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #ifdef HAVE_ALLOCA_H @@ -29,6 +29,7 @@ #include "becopystat.h" #include "benodesets.h" #include "bitset.h" +#include "raw_bitset.h" DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) @@ -251,7 +252,7 @@ static ir_node *qnode_color_irn(const qnode_t *qn, ir_node *irn, int col, const */ if (irn != trigger) { bitset_t *free_cols = bitset_alloca(cls->n_regs); - arch_register_req_t req; + const arch_register_req_t *req; ir_node *curr; int free_col; @@ -260,10 +261,10 @@ static ir_node *qnode_color_irn(const qnode_t *qn, ir_node *irn, int col, const bitset_flip_all(free_cols); /* Exclude colors not assignable to the irn */ - arch_get_register_req(arch_env, &req, irn, -1); - if (arch_register_req_is(&req, limited)) { + req = arch_get_register_req(arch_env, irn, -1); + if (arch_register_req_is(req, limited)) { bitset_t *limited = bitset_alloca(cls->n_regs); - req.limited(req.limited_env, limited); + rbitset_copy_to_bitset(req->limited, limited); bitset_and(free_cols, limited); } diff --git a/ir/be/becopyheur2.c b/ir/be/becopyheur2.c index 10ae5b671..80a8c70cb 100644 --- a/ir/be/becopyheur2.c +++ b/ir/be/becopyheur2.c @@ -1,12 +1,10 @@ - /** * More experiments on coalescing. * @author Sebastian Hack * @date 14.04.2006 */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include @@ -18,6 +16,7 @@ #include "list.h" #include "pdeq.h" #include "bitset.h" +#include "raw_bitset.h" #include "debug.h" #include "bitfiddle.h" @@ -243,15 +242,21 @@ static INLINE int color_is_fix(co2_t *env, ir_node *irn) static INLINE bitset_t *get_adm(co2_t *env, co2_irn_t *ci) { - if(!ci->adm_cache) { - arch_register_req_t req; + if(ci->adm_cache == NULL) { + const arch_register_req_t *req; ci->adm_cache = bitset_obstack_alloc(phase_obst(&env->ph), env->n_regs); - arch_get_register_req(env->co->aenv, &req, ci->irn, BE_OUT_POS(0)); - if(arch_register_req_is(&req, limited)) { - req.limited(req.limited_env, ci->adm_cache); + req = arch_get_register_req(env->co->aenv, ci->irn, BE_OUT_POS(0)); + + if(arch_register_req_is(req, limited)) { + int i, n; + + n = env->n_regs; + for(i = 0; i < n; ++i) { + if(rbitset_is_set(req->limited, i)) + bitset_set(ci->adm_cache, i); + } ci->is_constrained = 1; - } - else { + } else { bitset_copy(ci->adm_cache, env->ignore_regs); bitset_flip_all(ci->adm_cache); } @@ -281,19 +286,20 @@ static INLINE int is_constrained(co2_t *env, co2_irn_t *ci) static void incur_constraint_costs(co2_t *env, ir_node *irn, col_cost_pair_t *col_costs, int costs) { - bitset_t *aux = bitset_alloca(env->co->cls->n_regs); - arch_register_req_t req; + const arch_register_req_t *req; - arch_get_register_req(env->co->aenv, &req, irn, BE_OUT_POS(0)); + req = arch_get_register_req(env->co->aenv, irn, BE_OUT_POS(0)); - if(arch_register_req_is(&req, limited)) { - bitset_pos_t elm; - int n_constr; + if(arch_register_req_is(req, limited)) { + unsigned n_regs = env->co->cls->n_regs; + unsigned n_constr = 0; + int i; - req.limited(req.limited_env, aux); - n_constr = bitset_popcnt(aux); - bitset_foreach(aux, elm) { - col_costs[elm].costs = add_saturated(col_costs[elm].costs, costs / n_constr); + n_constr = rbitset_popcnt(req->limited, n_regs); + for(i = 0; i < n_regs; ++i) { + if(rbitset_is_set(req->limited, i)) { + col_costs[i].costs = add_saturated(col_costs[i].costs, costs / n_constr); + } } } } @@ -1130,10 +1136,10 @@ static const char *get_dot_color_name(int col) static const char *get_dot_shape_name(co2_t *env, co2_irn_t *ci) { - arch_register_req_t req; + const arch_register_req_t *req; - arch_get_register_req(env->co->aenv, &req, ci->irn, BE_OUT_POS(0)); - if(arch_register_req_is(&req, limited)) + req = arch_get_register_req(env->co->aenv, ci->irn, BE_OUT_POS(0)); + if(arch_register_req_is(req, limited)) return "diamond"; if(ci->fixed) diff --git a/ir/be/becopyheur3.c b/ir/be/becopyheur3.c index 73b7835b2..d22a6f4b7 100644 --- a/ir/be/becopyheur3.c +++ b/ir/be/becopyheur3.c @@ -1,12 +1,10 @@ - /** * More experiments on coalescing. * @author Sebastian Hack * @date 25.07.2006 */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include @@ -22,6 +20,7 @@ #include "debug.h" #include "bitfiddle.h" #include "bitset.h" +#include "raw_bitset.h" #include "irphase_t.h" #include "irgraph_t.h" @@ -78,20 +77,20 @@ BE_REGISTER_MODULE_CONSTRUCTOR(be_init_copyheur3); static void set_admissible_regs(be_java_coal_t *coal, copy_opt_t *co, ir_node *irn, int t_idx, int *col_map) { - unsigned i; - arch_register_req_t req; - unsigned n_regs = co->cls->n_regs; + const arch_register_req_t *req; + + req = arch_get_register_req(co->aenv, irn, BE_OUT_POS(0)); // ir_printf("%+F\n", irn); - arch_get_register_req(co->aenv, &req, irn, BE_OUT_POS(0)); - if(arch_register_req_is(&req, limited)) { - bitset_t *adm = bitset_alloca(n_regs); - req.limited(req.limited_env, adm); - for(i = 0; i < n_regs; ++i) - if(!bitset_is_set(adm, i) && col_map[i] >= 0) { - // printf("\tforbidding color: %d\n", i); + if(arch_register_req_is(req, limited)) { + unsigned i; + unsigned n_regs = co->cls->n_regs; + + for(i = 0; i < n_regs; ++i) { + if(!rbitset_is_set(req->limited, i) && col_map[i] >= 0) { be_java_coal_forbid_color(coal, t_idx, col_map[i]); } + } } } diff --git a/ir/be/becopyilp.c b/ir/be/becopyilp.c index 6fa870755..ae244cd4c 100644 --- a/ir/be/becopyilp.c +++ b/ir/be/becopyilp.c @@ -30,7 +30,7 @@ static int time_limit = 60; static int solve_net = 1; static int solve_log = 0; -static int dump_flags = 0; +static unsigned dump_flags = 0; static const lc_opt_enum_mask_items_t dump_items[] = { { "ilp", DUMP_ILP }, @@ -124,11 +124,11 @@ void sr_remove(size_red_t *sr) { while (redo) { redo = 0; be_ifg_foreach_node(ifg, iter, irn) { - arch_register_req_t req; + const arch_register_req_t *req; - arch_get_register_req(sr->co->aenv, &req, irn, -1); + req = arch_get_register_req(sr->co->aenv, irn, -1); - if (!arch_register_req_is(&req, limited) && !sr_is_removed(sr, irn) && !co_gs_is_optimizable(sr->co, irn)) { + if (!arch_register_req_is(req, limited) && !sr_is_removed(sr, irn) && !co_gs_is_optimizable(sr->co, irn)) { if (sr_is_simplicial(sr, irn)) { coloring_suffix_t *cs = obstack_alloc(&sr->ob, sizeof(*cs)); diff --git a/ir/be/becopyilp2.c b/ir/be/becopyilp2.c index 9e2cf822c..a97d40d4d 100644 --- a/ir/be/becopyilp2.c +++ b/ir/be/becopyilp2.c @@ -32,7 +32,8 @@ #ifdef WITH_ILP -#include +#include "bitset.h" +#include "raw_bitset.h" #include "pdeq.h" #include "irtools.h" @@ -63,20 +64,20 @@ static void build_coloring_cstr(ilp_env_t *ienv) { be_ifg_foreach_node(ifg, iter, irn) if (!sr_is_removed(ienv->sr, irn)) { int col, cst_idx; - arch_register_req_t req; + const arch_register_req_t *req; int curr_node_color = get_irn_col(ienv->co, irn); int node_nr = (int)get_irn_node_nr(irn); local_env_t *lenv = ienv->env; pmap_insert(lenv->nr_2_irn, INT_TO_PTR(node_nr), irn); - arch_get_register_req(ienv->co->aenv, &req, irn, -1); + req = arch_get_register_req(ienv->co->aenv, irn, -1); /* get assignable colors */ - if (arch_register_req_is(&req, limited)) - req.limited(req.limited_env, colors); - else { - arch_register_class_put(req.cls, colors); + if (arch_register_req_is(req, limited)) { + rbitset_copy_to_bitset(req->limited, colors); + } else { + arch_register_class_put(req->cls, colors); // bitset_andnot(colors, ienv->co->cenv->ignore_colors); } diff --git a/ir/be/becopyopt.c b/ir/be/becopyopt.c index 0001f7f8c..1b9ccd4a7 100644 --- a/ir/be/becopyopt.c +++ b/ir/be/becopyopt.c @@ -5,7 +5,7 @@ * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE. */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #ifdef HAVE_ALLOCA_H @@ -19,6 +19,7 @@ #include "xmalloc.h" #include "debug.h" #include "pmap.h" +#include "raw_bitset.h" #include "irgraph.h" #include "irgwalk.h" #include "irprog.h" @@ -202,7 +203,7 @@ void free_copy_opt(copy_opt_t *co) { } int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) { - arch_register_req_t req; + const arch_register_req_t *req; const arch_register_t *reg; if (arch_irn_is(co->aenv, irn, ignore)) @@ -212,7 +213,8 @@ int co_is_optimizable_root(const copy_opt_t *co, ir_node *irn) { if (arch_register_type_is(reg, ignore)) return 0; - if (is_Reg_Phi(irn) || is_Perm_Proj(co->aenv, irn) || is_2addr_code(co->aenv, irn, &req)) + req = arch_get_register_req(co->aenv, irn, -1); + if (is_Reg_Phi(irn) || is_Perm_Proj(co->aenv, irn) || is_2addr_code(req)) return 1; return 0; @@ -235,14 +237,16 @@ int co_is_optimizable_arg(const copy_opt_t *co, ir_node *irn) { ir_node *n = edge->src; if (!nodes_interfere(co->cenv, irn, n) || irn == n) { - arch_register_req_t req; - arch_get_register_req(co->aenv, &req, n, -1); + const arch_register_req_t *req; + req = arch_get_register_req(co->aenv, n, -1); if(is_Reg_Phi(n) || is_Perm(co->aenv, n) || - (arch_register_req_is(&req, should_be_same) && req.other_same == irn) - ) - return 1; + (arch_register_req_is(req, should_be_same))) { + ir_node *other = get_irn_n(irn, req->other_same); + if(other == irn) + return 1; + } } } @@ -384,7 +388,6 @@ static int ou_max_ind_set_costs(unit_t *ou) { static void co_collect_units(ir_node *irn, void *env) { copy_opt_t *co = env; unit_t *unit; - arch_register_req_t req; if (!is_curr_reg_class(co, irn)) return; @@ -454,21 +457,25 @@ static void co_collect_units(ir_node *irn, void *env) { unit->nodes[0] = irn; unit->nodes[1] = get_Perm_src(irn); unit->costs[1] = co->get_costs(co, irn, unit->nodes[1], -1); - } else - - /* Src == Tgt of a 2-addr-code instruction */ - if (is_2addr_code(co->aenv, irn, &req)) { - ir_node *other = req.other_same; - if (!nodes_interfere(co->cenv, irn, other)) { - unit->nodes = xmalloc(2 * sizeof(*unit->nodes)); - unit->costs = xmalloc(2 * sizeof(*unit->costs)); - unit->node_count = 2; - unit->nodes[0] = irn; - unit->nodes[1] = other; - unit->costs[1] = co->get_costs(co, irn, other, -1); + } else { + const arch_register_req_t *req = + arch_get_register_req(co->aenv, irn, -1); + + /* Src == Tgt of a 2-addr-code instruction */ + if (is_2addr_code(req)) { + ir_node *other = get_irn_n(irn, req->other_same); + if (!nodes_interfere(co->cenv, irn, other)) { + unit->nodes = xmalloc(2 * sizeof(*unit->nodes)); + unit->costs = xmalloc(2 * sizeof(*unit->costs)); + unit->node_count = 2; + unit->nodes[0] = irn; + unit->nodes[1] = other; + unit->costs[1] = co->get_costs(co, irn, other, -1); + } + } else { + assert(0 && "This is not an optimizable node!"); } - } else - assert(0 && "This is not an optimizable node!"); + } /* Insert the new unit at a position according to its costs */ if (unit->node_count > 1) { @@ -749,7 +756,6 @@ static INLINE void add_edges(copy_opt_t *co, ir_node *n1, ir_node *n2, int costs static void build_graph_walker(ir_node *irn, void *env) { copy_opt_t *co = env; int pos, max; - arch_register_req_t req; const arch_register_t *reg; if (!is_curr_reg_class(co, irn) || arch_irn_is(co->aenv, irn, ignore)) @@ -773,8 +779,14 @@ static void build_graph_walker(ir_node *irn, void *env) { } /* 2-address code */ - else if (is_2addr_code(co->aenv, irn, &req)) - add_edges(co, irn, req.other_same, co->get_costs(co, irn, req.other_same, 0)); + else { + const arch_register_req_t *req = + arch_get_register_req(co->aenv, irn, -1); + if (is_2addr_code(req)) { + ir_node *other = get_irn_n(irn, req->other_same); + add_edges(co, irn, other, co->get_costs(co, irn, other, 0)); + } + } } void co_build_graph_structure(copy_opt_t *co) { @@ -811,7 +823,6 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) { be_ifg_t *ifg = co->cenv->ifg; int *color_map = alloca(co->cls->n_regs * sizeof(color_map[0])); - bitset_t *adm = bitset_alloca(co->cls->n_regs); ir_node *irn; void *it, *nit; @@ -844,17 +855,15 @@ void co_dump_appel_graph(const copy_opt_t *co, FILE *f) int idx = PTR_TO_INT(get_irn_link(irn)); affinity_node_t *a = get_affinity_info(co, irn); - arch_register_req_t req; + const arch_register_req_t *req; ir_node *adj; - arch_get_register_req(co->aenv, &req, irn, BE_OUT_POS(0)); - if(arch_register_req_is(&req, limited)) { - bitset_clear_all(adm); - req.limited(req.limited_env, adm); - for(i = 0; i < co->cls->n_regs; ++i) - if(!bitset_is_set(adm, i) && color_map[i] >= 0) + req = arch_get_register_req(co->aenv, irn, BE_OUT_POS(0)); + if(arch_register_req_is(req, limited)) { + for(i = 0; i < co->cls->n_regs; ++i) { + if(!rbitset_is_set(req->limited, i) && color_map[i] >= 0) fprintf(f, "%d %d -1\n", color_map[i], idx); - + } } @@ -1272,25 +1281,27 @@ static void ifg_dump_node_attr(FILE *f, void *self, ir_node *irn) { co_ifg_dump_t *env = self; const arch_register_t *reg = arch_get_irn_register(env->co->aenv, irn); - arch_register_req_t req; + const arch_register_req_t *req; int limited; - arch_get_register_req(env->co->aenv, &req, irn, BE_OUT_POS(0)); - limited = arch_register_req_is(&req, limited); + req = arch_get_register_req(env->co->aenv, irn, BE_OUT_POS(0)); + limited = arch_register_req_is(req, limited); if(env->flags & CO_IFG_DUMP_LABELS) { ir_fprintf(f, "label=\"%+F", irn); +#if 0 + // TODO fix this... if((env->flags & CO_IFG_DUMP_CONSTR) && limited) { bitset_t *bs = bitset_alloca(env->co->cls->n_regs); req.limited(req.limited_env, bs); ir_fprintf(f, "\\n%B", bs); } +#endif ir_fprintf(f, "\" "); - } - - else + } else { fprintf(f, "label=\"\" shape=point " ); + } if(env->flags & CO_IFG_DUMP_SHAPE) fprintf(f, "shape=%s ", limited ? "diamond" : "ellipse"); diff --git a/ir/be/becopyopt_t.h b/ir/be/becopyopt_t.h index 5c12ab8ef..48c795fc1 100644 --- a/ir/be/becopyopt_t.h +++ b/ir/be/becopyopt_t.h @@ -52,9 +52,10 @@ struct _copy_opt_t { #define is_Perm(arch_env, irn) (arch_irn_classify(arch_env, irn) == arch_irn_class_perm) #define is_Perm_Proj(arch_env, irn) (is_Proj(irn) && is_Perm(arch_env, get_Proj_pred(irn))) -#define is_2addr_code(arch_env, irn, req) (arch_get_register_req(arch_env, req, irn, -1)->type == arch_register_req_type_should_be_same) - - +static INLINE int is_2addr_code(const arch_register_req_t *req) +{ + return req->type == arch_register_req_type_should_be_same; +} /****************************************************************************** ____ _ _ _ _ _ _____ _ diff --git a/ir/be/beemitter.c b/ir/be/beemitter.c new file mode 100644 index 000000000..c531a23c7 --- /dev/null +++ b/ir/be/beemitter.c @@ -0,0 +1,95 @@ +/* + * Author: Matthias Braun + * Date: 12.03.2007 + * Copyright: (c) Universitaet Karlsruhe + * License: This file is protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "beemitter.h" +#include "xmalloc.h" +#include "irprintf.h" + +void be_emit_init_env(be_emit_env_t *env, FILE *F) +{ + memset(env, 0, sizeof(env[0])); + + env->F = F; + obstack_init(&env->obst); + env->linelength = 0; +} + +void be_emit_destroy_env(be_emit_env_t *env) +{ + obstack_free(&env->obst, NULL); +} + +void be_emit_ident(be_emit_env_t *env, ident *id) +{ + size_t len = get_id_strlen(id); + const char *str = get_id_str(id); + + be_emit_string_len(env, str, len); +} + +void be_emit_irvprintf(be_emit_env_t *env, const char *fmt, va_list args) +{ + char buf[256]; + + ir_vsnprintf(buf, sizeof(buf), fmt, args); + be_emit_string(env, buf); +} + +void be_emit_irprintf(be_emit_env_t *env, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + be_emit_irvprintf(env, fmt, ap); + va_end(ap); +} + +void be_emit_write_line(be_emit_env_t *env) +{ + char *finished_line = obstack_finish(&env->obst); + + fwrite(finished_line, env->linelength, 1, env->F); + env->linelength = 0; + obstack_free(&env->obst, finished_line); +} + +void be_emit_pad_comment(be_emit_env_t *env) +{ + while(env->linelength <= 30) { + be_emit_char(env, ' '); + } + be_emit_cstring(env, " "); +} + +void be_emit_finish_line_gas(be_emit_env_t *env, const ir_node *node) +{ + dbg_info *dbg; + const char *sourcefile; + unsigned lineno; + + if(node == NULL) { + be_emit_char(env, '\n'); + be_emit_write_line(env); + return; + } + + be_emit_pad_comment(env); + be_emit_cstring(env, "/* "); + be_emit_irprintf(env, "%+F ", node); + + dbg = get_irn_dbg_info(node); + sourcefile = be_retrieve_dbg_info(dbg, &lineno); + if(sourcefile != NULL) { + be_emit_string(env, sourcefile); + be_emit_irprintf(env, ":%u", lineno); + } + be_emit_cstring(env, " */\n"); + be_emit_write_line(env); +} diff --git a/ir/be/beemitter.h b/ir/be/beemitter.h new file mode 100644 index 000000000..1864ffdbe --- /dev/null +++ b/ir/be/beemitter.h @@ -0,0 +1,58 @@ +/* + * Author: Matthias Braun + * Date: 12.03.2007 + * Copyright: (c) Universitaet Karlsruhe + * License: This file is protected by GPL - GNU GENERAL PUBLIC LICENSE. + */ +#ifndef BESPILLMORGAN_H_ +#define BESPILLMORGAN_H_ + +#include +#include +#include "obst.h" +#include "ident.h" +#include "irnode.h" +#include "be.h" + +/* framework for emitting data (usually the final assembly code) */ + +typedef struct be_emit_env_t { + FILE *F; + struct obstack obst; + int linelength; +} be_emit_env_t; + +static INLINE void be_emit_char(be_emit_env_t *env, char c) +{ + obstack_1grow(&env->obst, c); + env->linelength++; +} + +static INLINE void be_emit_string_len(be_emit_env_t *env, const char *str, + size_t l) +{ + obstack_grow(&env->obst, str, l); + env->linelength += l; +} + +static INLINE void be_emit_string(be_emit_env_t *env, const char *str) +{ + size_t len = strlen(str); + be_emit_string_len(env, str, len); +} + +#define be_emit_cstring(env,x) { be_emit_string_len(env, x, sizeof(x)-1); } + +void be_emit_init_env(be_emit_env_t *env, FILE *F); +void be_emit_destroy_env(be_emit_env_t *env); + +void be_emit_ident(be_emit_env_t *env, ident *id); +void be_emit_irprintf(be_emit_env_t *env, const char *fmt, ...); +void be_emit_irvprintf(be_emit_env_t *env, const char *fmt, va_list args); +void be_emit_write_line(be_emit_env_t *env); + +/* appends a gas-style comment with the node number and writes the line */ +void be_emit_finish_line_gas(be_emit_env_t *env, const ir_node *node); +void be_emit_pad_comment(be_emit_env_t *env); + +#endif diff --git a/ir/be/ia32/ia32_gen_decls.c b/ir/be/begnuas.c similarity index 88% rename from ir/be/ia32/ia32_gen_decls.c rename to ir/be/begnuas.c index 9b8c6443e..0d68ca5cd 100644 --- a/ir/be/ia32/ia32_gen_decls.c +++ b/ir/be/begnuas.c @@ -1,14 +1,15 @@ /** - * Dumps global variables and constants as ia32 assembler. - * @author Christian Wuerdig + * Dumps global variables and constants as gas assembler. + * @author Christian Wuerdig, Matthias Braun * @date 04.11.2005 * @version $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif +#include "begnuas.h" + #include #include #include @@ -21,13 +22,47 @@ #include "irprog.h" #include "error.h" -#include "../be.h" - -#include "ia32_emitter.h" -#include "ia32_gen_decls.h" +#include "be_t.h" +#include "beemitter.h" +#include "be_dbgout.h" typedef struct obstack obstack_t; +/** by default, we generate assembler code for the Linux gas */ +be_gas_flavour_t be_gas_flavour = GAS_FLAVOUR_NORMAL; + +static const char* get_section_name(be_gas_section_t section) { + static const char *text[GAS_FLAVOUR_MAX][GAS_SECTION_MAX] = { + { + ".section\t.text", + ".section\t.data", + ".section\t.rodata", + ".section\t.bss", + ".section\t.tbss,\"awT\",@nobits", + ".section\t.ctors,\"aw\",@progbits" + }, + { + ".section\t.text", + ".section\t.data", + ".section .rdata,\"dr\"", + ".section\t.bss", + ".section\t.tbss,\"awT\",@nobits", + ".section\t.ctors,\"aw\",@progbits" + } + }; + + assert(be_gas_flavour >= 0 && be_gas_flavour < GAS_FLAVOUR_MAX); + assert(section >= 0 && section < GAS_SECTION_MAX); + return text[be_gas_flavour][section]; +} + +void be_gas_emit_switch_section(be_emit_env_t *env, be_gas_section_t section) { + be_emit_char(env, '\t'); + be_emit_string(env, get_section_name(section)); + be_emit_char(env, '\n'); + be_emit_write_line(env); +} + typedef struct _ia32_decl_env { obstack_t *rodata_obst; obstack_t *data_obst; @@ -426,7 +461,7 @@ static void dump_compound_init(obstack_t *obst, ir_entity *ent) /* * In the worst case, every initializer allocates one byte. - * Moreover, initializer might be big, do not allocate an stack. + * Moreover, initializer might be big, do not allocate on stack. */ vals = xcalloc(last_ofs, sizeof(vals[0])); @@ -591,7 +626,7 @@ static void ia32_dump_globals(ir_type *gt, ia32_decl_env_t *env, int emit_common /************************************************************************/ -void ia32_gen_decls(FILE *out, const be_main_env_t *main_env) { +void be_gas_emit_decls(be_emit_env_t *emit, const be_main_env_t *main_env) { ia32_decl_env_t env; obstack_t rodata, data, bss, ctor; int size; @@ -601,14 +636,12 @@ void ia32_gen_decls(FILE *out, const be_main_env_t *main_env) { obstack_init(&rodata); obstack_init(&data); obstack_init(&bss); - - if (main_env->options->opt_profile) - obstack_init(&ctor); + obstack_init(&ctor); env.rodata_obst = &rodata; env.data_obst = &data; env.bss_obst = &bss; - env.ctor_obst = main_env->options->opt_profile ? &ctor : NULL; + env.ctor_obst = &ctor; env.main_env = main_env; ia32_dump_globals(get_glob_type(), &env, 1); @@ -616,44 +649,46 @@ void ia32_gen_decls(FILE *out, const be_main_env_t *main_env) { size = obstack_object_size(&data); cp = obstack_finish(&data); if (size > 0) { - ia32_switch_section(out, SECTION_DATA); - fwrite(cp, 1, size, out); + be_gas_emit_switch_section(emit, GAS_SECTION_DATA); + be_emit_string_len(emit, cp, size); + be_emit_write_line(emit); } size = obstack_object_size(&rodata); cp = obstack_finish(&rodata); if (size > 0) { - ia32_switch_section(out, SECTION_RODATA); - fwrite(cp, 1, size, out); + be_gas_emit_switch_section(emit, GAS_SECTION_RODATA); + be_emit_string_len(emit, cp, size); + be_emit_write_line(emit); } size = obstack_object_size(&bss); cp = obstack_finish(&bss); if (size > 0) { - ia32_switch_section(out, SECTION_COMMON); - fwrite(cp, 1, size, out); + be_gas_emit_switch_section(emit, GAS_SECTION_COMMON); + be_emit_string_len(emit, cp, size); + be_emit_write_line(emit); } - if (main_env->options->opt_profile) { - size = obstack_object_size(&ctor); - cp = obstack_finish(&ctor); - if (size > 0) { - ia32_switch_section(out, SECTION_CTOR); - fwrite(cp, 1, size, out); - } - obstack_free(&ctor, NULL); + size = obstack_object_size(&ctor); + cp = obstack_finish(&ctor); + if (size > 0) { + be_gas_emit_switch_section(emit, GAS_SECTION_CTOR); + be_emit_string_len(emit, cp, size); + be_emit_write_line(emit); } obstack_free(&rodata, NULL); obstack_free(&data, NULL); obstack_free(&bss, NULL); + obstack_free(&ctor, NULL); /* dump the Thread Local Storage */ obstack_init(&data); env.rodata_obst = &data; env.data_obst = &data; - env.bss_obst = &data; + env.bss_obst = &data; env.ctor_obst = NULL; ia32_dump_globals(get_tls_type(), &env, 0); @@ -661,9 +696,11 @@ void ia32_gen_decls(FILE *out, const be_main_env_t *main_env) { size = obstack_object_size(&data); cp = obstack_finish(&data); if (size > 0) { - ia32_switch_section(out, SECTION_TLS); - fprintf(out, ".balign\t%d\n", 32); - fwrite(cp, 1, size, out); + be_gas_emit_switch_section(emit, GAS_SECTION_TLS); + be_emit_cstring(emit, ".balign\t32\n"); + be_emit_write_line(emit); + be_emit_string_len(emit, cp, size); + be_emit_write_line(emit); } obstack_free(&data, NULL); diff --git a/ir/be/begnuas.h b/ir/be/begnuas.h new file mode 100644 index 000000000..53f853f1e --- /dev/null +++ b/ir/be/begnuas.h @@ -0,0 +1,41 @@ +/** + * Header for ia32 assembler declarations dumper. + * @author Christian Wuerdig, Matthias Braun + * $Id$ + */ +#ifndef _BE_GEN_DECLS_H_ +#define _BE_GEN_DECLS_H_ + +#include "be.h" +#include "beemitter.h" + +/** + * Sections. + */ +typedef enum section_t { + GAS_SECTION_TEXT = 0, /**< text section */ + GAS_SECTION_DATA = 1, /**< data section */ + GAS_SECTION_RODATA = 2, /**< rodata section */ + GAS_SECTION_COMMON = 3, /**< common section */ + GAS_SECTION_TLS = 4, /**< thread local storage section */ + GAS_SECTION_CTOR = 5, /**< ctor section for instrumentation code init */ + GAS_SECTION_MAX = 6 +} be_gas_section_t; + +typedef enum asm_flavour_t { + GAS_FLAVOUR_NORMAL = 0, /**< normal gas */ + GAS_FLAVOUR_MINGW = 1, /**< MinGW variant */ + GAS_FLAVOUR_MAX = 2 +} be_gas_flavour_t; + +extern be_gas_flavour_t be_gas_flavour; + + +/** + * Generate all entities. + */ +void be_gas_emit_decls(be_emit_env_t *env, const be_main_env_t *main_env); + +void be_gas_emit_switch_section(be_emit_env_t *env, be_gas_section_t section); + +#endif diff --git a/ir/be/beilpsched.c b/ir/be/beilpsched.c index d6dfdc5d6..8c9ebdf98 100644 --- a/ir/be/beilpsched.c +++ b/ir/be/beilpsched.c @@ -31,6 +31,7 @@ #include "debug.h" #include "irtools.h" #include "irdump.h" +#include "irprintf.h" #include "plist.h" #include "irprintf.h" diff --git a/ir/be/beinsn.c b/ir/be/beinsn.c index ac027f309..6f79b000a 100644 --- a/ir/be/beinsn.c +++ b/ir/be/beinsn.c @@ -1,5 +1,5 @@ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include "irgraph_t.h" @@ -9,6 +9,7 @@ #include "besched_t.h" #include "beinsn_t.h" #include "beabi.h" +#include "raw_bitset.h" be_insn_t *be_scan_insn(const be_insn_env_t *env, ir_node *irn) { @@ -29,12 +30,12 @@ be_insn_t *be_scan_insn(const be_insn_env_t *env, ir_node *irn) for(p = sched_next(irn); is_Proj(p); p = sched_next(p)) { if(arch_irn_consider_in_reg_alloc(arch_env, env->cls, p)) { - arch_get_register_req(arch_env, &o.req, p, -1); + o.req = arch_get_register_req(arch_env, p, -1); o.carrier = p; o.irn = irn; o.pos = -(get_Proj_proj(p) + 1); o.partner = NULL; - o.has_constraints = arch_register_req_is(&o.req, limited); + o.has_constraints = arch_register_req_is(o.req, limited); obstack_grow(obst, &o, sizeof(o)); insn->n_ops++; insn->out_constraints |= o.has_constraints; @@ -43,21 +44,23 @@ be_insn_t *be_scan_insn(const be_insn_env_t *env, ir_node *irn) } insn->next_insn = p; - } - else if(arch_irn_consider_in_reg_alloc(arch_env, env->cls, irn)) { - arch_get_register_req(arch_env, &o.req, irn, -1); + } else if(arch_irn_consider_in_reg_alloc(arch_env, env->cls, irn)) { + o.req = arch_get_register_req(arch_env, irn, -1); o.carrier = irn; o.irn = irn; o.pos = -1; o.partner = NULL; - o.has_constraints = arch_register_req_is(&o.req, limited); + o.has_constraints = arch_register_req_is(o.req, limited); obstack_grow(obst, &o, sizeof(o)); insn->n_ops++; insn->out_constraints |= o.has_constraints; pre_colored += arch_get_irn_register(arch_env, irn) != NULL; } - insn->pre_colored = pre_colored == insn->n_ops && insn->n_ops > 0; + if(pre_colored > 0) { + assert(pre_colored == insn->n_ops && "partly pre-colored nodes not supported"); + insn->pre_colored = 1; + } insn->use_start = insn->n_ops; for(i = 0, n = get_irn_arity(irn); i < n; ++i) { @@ -66,12 +69,12 @@ be_insn_t *be_scan_insn(const be_insn_env_t *env, ir_node *irn) if(!arch_irn_consider_in_reg_alloc(arch_env, env->cls, op)) continue; - arch_get_register_req(arch_env, &o.req, irn, i); + o.req = arch_get_register_req(arch_env, irn, i); o.carrier = op; o.irn = irn; o.pos = i; o.partner = NULL; - o.has_constraints = arch_register_req_is(&o.req, limited); + o.has_constraints = arch_register_req_is(o.req, limited); obstack_grow(obst, &o, sizeof(o)); insn->n_ops++; insn->in_constraints |= o.has_constraints; @@ -83,18 +86,23 @@ be_insn_t *be_scan_insn(const be_insn_env_t *env, ir_node *irn) /* Compute the admissible registers bitsets. */ for (i = 0; i < insn->n_ops; ++i) { be_operand_t *op = &insn->ops[i]; + const arch_register_req_t *req = op->req; - if (op->req.cls == NULL && op->req.type == arch_register_req_type_none) { - op->req.cls = env->cls; - op->req.type = arch_register_req_type_normal; +#if 0 + // Matze: can we do without this? + if (req->cls == NULL && req->type == arch_register_req_type_none) { + req->cls = env->cls; + req->type = arch_register_req_type_normal; } +#endif + + assert(req->cls == env->cls); - assert(op->req.cls == env->cls); op->regs = bitset_obstack_alloc(obst, env->cls->n_regs); - if (arch_register_req_is(&op->req, limited)) - op->req.limited(op->req.limited_env, op->regs); - else { + if (arch_register_req_is(req, limited)) { + rbitset_copy_to_bitset(req->limited, op->regs); + } else { arch_put_non_ignore_regs(arch_env, env->cls, op->regs); if (env->ignore_colors) bitset_andnot(op->regs, env->ignore_colors); @@ -111,5 +119,6 @@ be_insn_env_t *be_insn_env_init(be_insn_env_t *ie, const be_irg_t *birg, const a ie->obst = obst; ie->ignore_colors = bitset_obstack_alloc(obst, cls->n_regs); be_abi_put_ignore_regs(birg->abi, cls, ie->ignore_colors); + return ie; } diff --git a/ir/be/beinsn_t.h b/ir/be/beinsn_t.h index 777a12246..e084f4fa9 100644 --- a/ir/be/beinsn_t.h +++ b/ir/be/beinsn_t.h @@ -16,25 +16,26 @@ typedef struct _be_insn_t be_insn_t; typedef struct _be_insn_env_t be_insn_env_t; struct _be_operand_t { - ir_node *irn; - ir_node *carrier; - be_operand_t *partner; - bitset_t *regs; - int pos; - arch_register_req_t req; - unsigned has_constraints : 1; + ir_node *irn; /**< firm node of the insn this operand blongs to */ + ir_node *carrier; /**< node representing the operand value (proj or the node itself for defs, the value itself for uses */ + be_operand_t *partner; /**< used in bechordal later... (TODO what does it do?) */ + bitset_t *regs; /**< admissible register bitset */ + int pos; /**< pos of the operand (0 to n are inputs, -1 to -n are outputs) */ + const arch_register_req_t *req; /**< register constraints for the carrier node */ + unsigned has_constraints : 1; /**< the carrier node has register constraints (the constraint type is limited) */ }; struct _be_insn_t { - be_operand_t *ops; - int n_ops; - int use_start; - ir_node *next_insn; - ir_node *irn; - unsigned in_constraints : 1; - unsigned out_constraints : 1; - unsigned has_constraints : 1; - unsigned pre_colored : 1; + be_operand_t *ops; /**< the values used and defined by the insn */ + int n_ops; /**< length of the ops array */ + int use_start; /**< entries [0-use_start) in ops are defs, + [use_start-n_ops) uses */ + ir_node *next_insn; /**< next instruction in schedule */ + ir_node *irn; /**< ir_node of the instruction */ + unsigned in_constraints : 1; /**< instruction has input contraints */ + unsigned out_constraints : 1; /**< instruction has output constraints */ + unsigned has_constraints : 1; /**< in_constraints or out_constraints true */ + unsigned pre_colored : 1; /**< all defined values already have a register assigned */ }; struct _be_insn_env_t { diff --git a/ir/be/beirgmod.c b/ir/be/beirgmod.c index 28d86e148..a2b2c1f6e 100644 --- a/ir/be/beirgmod.c +++ b/ir/be/beirgmod.c @@ -13,7 +13,7 @@ * CVS-Id: $Id$ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include @@ -54,8 +54,8 @@ #include "beirgmod.h" -#define DBG_MODULE "firm.be.irgmod" #define DBG_LEVEL SET_LEVEL_0 +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) /* ____ _ @@ -172,7 +172,6 @@ static void determine_phi_blocks(pset *copies, pset *copy_blocks, pset *phi_bloc { ir_node *bl; waitq *worklist = new_waitq(); - FIRM_DBG_REGISTER(firm_dbg_module_t *dbg, DBG_MODULE); /* * Fill the worklist queue and the rest of the orig blocks array. @@ -253,7 +252,6 @@ static ir_node *search_def(ir_node *usage, int pos, pset *copies, pset *copy_blo { ir_node *curr_bl; ir_node *start_irn; - FIRM_DBG_REGISTER(firm_dbg_module_t *dbg, DBG_MODULE); curr_bl = get_nodes_block(usage); @@ -364,8 +362,6 @@ static void fix_usages(pset *copies, pset *copy_blocks, pset *phi_blocks, pset * int pos; } *outs; - FIRM_DBG_REGISTER(firm_dbg_module_t *dbg, DBG_MODULE); - obstack_init(&obst); /* @@ -486,7 +482,6 @@ void be_ssa_constr_set_phis_ignore(be_dom_front_info_t *df, be_lv_t *lv, pset *n int save_optimize = get_optimize(); int save_normalize = get_opt_normalize(); int phis_set_created = 0; - FIRM_DBG_REGISTER(firm_dbg_module_t *dbg, DBG_MODULE); ir_node *irn; @@ -579,7 +574,6 @@ ir_node *insert_Perm_after(const arch_env_t *arch_env, ir_node *bl = is_Block(pos) ? pos : get_nodes_block(pos); ir_graph *irg = get_irn_irg(bl); pset *live = pset_new_ptr_default(); - FIRM_DBG_REGISTER(firm_dbg_module_t *dbg, "be.node"); ir_node *curr, *irn, *perm, **nodes; int i, n; @@ -722,3 +716,10 @@ int be_remove_empty_blocks(ir_graph *irg) { } return changed; } + +void be_init_irgmod(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.irgmod"); +} + +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_irgmod); diff --git a/ir/be/belistsched.c b/ir/be/belistsched.c index 57f66992f..290afd960 100644 --- a/ir/be/belistsched.c +++ b/ir/be/belistsched.c @@ -5,9 +5,8 @@ * @author Sebastian Hack * @cvs-id $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include @@ -45,6 +44,8 @@ #include #include +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL); + #define BE_SCHED_NODE(irn) (be_is_Keep(irn) || be_is_CopyKeep(irn) || be_is_RegParams(irn)) enum { @@ -135,7 +136,6 @@ typedef struct _block_sched_env_t { nodeset *live; /**< simple liveness during scheduling */ const list_sched_selector_t *selector; void *selector_block_env; - DEBUG_ONLY(firm_dbg_module_t *dbg;) } block_sched_env_t; /** @@ -203,7 +203,7 @@ static INLINE int make_ready(block_sched_env_t *env, ir_node *pred, ir_node *irn if (env->selector->node_ready) env->selector->node_ready(env->selector_block_env, irn, pred); - DB((env->dbg, LEVEL_2, "\tmaking ready: %+F\n", irn)); + DB((dbg, LEVEL_2, "\tmaking ready: %+F\n", irn)); return 1; } @@ -358,7 +358,7 @@ static ir_node *add_to_sched(block_sched_env_t *env, ir_node *irn) update_sched_liveness(env, irn); sched_add_before(env->block, irn); - DBG((env->dbg, LEVEL_2, "\tadding %+F\n", irn)); + DBG((dbg, LEVEL_2, "\tadding %+F\n", irn)); } /* notify the selector about the finally selected node. */ @@ -448,9 +448,8 @@ static void list_sched_block(ir_node *block, void *env_ptr) be.live = new_nodeset(get_irn_n_edges(block)); be.selector = selector; be.sched_env = env; - FIRM_DBG_REGISTER(be.dbg, "firm.be.sched"); - DBG((be.dbg, LEVEL_1, "scheduling %+F\n", block)); + DBG((dbg, LEVEL_1, "scheduling %+F\n", block)); if (selector->init_block) be.selector_block_env = selector->init_block(env->selector_env, block); @@ -500,7 +499,7 @@ static void list_sched_block(ir_node *block, void *env_ptr) /* Make the node ready, if all operands live in a foreign block */ if (ready) { - DBG((be.dbg, LEVEL_2, "\timmediately ready: %+F\n", irn)); + DBG((dbg, LEVEL_2, "\timmediately ready: %+F\n", irn)); make_ready(&be, NULL, irn); } } @@ -524,7 +523,7 @@ static void list_sched_block(ir_node *block, void *env_ptr) irn = be.selector->select(be.selector_block_env, be.cands, be.live); } - DB((be.dbg, LEVEL_2, "\tpicked node %+F\n", irn)); + DB((dbg, LEVEL_2, "\tpicked node %+F\n", irn)); /* Add the node to the schedule. */ add_to_sched(&be, irn); @@ -687,6 +686,8 @@ void be_init_listsched(void) { lc_opt_entry_t *sched_grp = lc_opt_get_grp(be_grp, "listsched"); lc_opt_add_table(sched_grp, list_sched_option_table); + + FIRM_DBG_REGISTER(dbg, "firm.be.sched"); } BE_REGISTER_MODULE_CONSTRUCTOR(be_init_listsched); diff --git a/ir/be/belive.c b/ir/be/belive.c index c9eda11a5..352c24096 100644 --- a/ir/be/belive.c +++ b/ir/be/belive.c @@ -4,7 +4,7 @@ * @date 6.12.2004 */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include "impl.h" @@ -17,8 +17,9 @@ #include "beutil.h" #include "belive_t.h" #include "besched_t.h" +#include "bemodule.h" -#define DBG_MODULE "firm.be.liveness" +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) #define LV_STD_SIZE 128 #define LV_USE_BINARY_SEARCH @@ -238,7 +239,7 @@ static int be_lv_remove(struct _be_lv_t *li, ir_node *bl, ir_node *irn) payload[n - 1].u.node.flags = 0; --irn_live[0].u.head.n_members; - DBG((li->dbg, LEVEL_3, "\tdeleting %+F from %+F at pos %d\n", irn, bl, pos)); + DBG((dbg, LEVEL_3, "\tdeleting %+F from %+F at pos %d\n", irn, bl, pos)); return 1; } } @@ -265,7 +266,7 @@ static void register_node(be_lv_t *lv, const ir_node *irn) static INLINE void mark_live_in(be_lv_t *lv, ir_node *block, ir_node *irn) { struct _be_lv_info_node_t *n = be_lv_get_or_set(lv, block, irn); - DBG((lv->dbg, LEVEL_2, "marking %+F live in at %+F\n", irn, block)); + DBG((dbg, LEVEL_2, "marking %+F live in at %+F\n", irn, block)); n->flags |= be_lv_state_in; register_node(lv, irn); } @@ -276,7 +277,7 @@ static INLINE void mark_live_in(be_lv_t *lv, ir_node *block, ir_node *irn) static INLINE void mark_live_out(be_lv_t *lv, ir_node *block, ir_node *irn) { struct _be_lv_info_node_t *n = be_lv_get_or_set(lv, block, irn); - DBG((lv->dbg, LEVEL_2, "marking %+F live out at %+F\n", irn, block)); + DBG((dbg, LEVEL_2, "marking %+F live out at %+F\n", irn, block)); n->flags |= be_lv_state_out | be_lv_state_end; register_node(lv, irn); } @@ -287,7 +288,7 @@ static INLINE void mark_live_out(be_lv_t *lv, ir_node *block, ir_node *irn) static INLINE void mark_live_end(be_lv_t *lv, ir_node *block, ir_node *irn) { struct _be_lv_info_node_t *n = be_lv_get_or_set(lv, block, irn); - DBG((lv->dbg, LEVEL_2, "marking %+F live end at %+F\n", irn, block)); + DBG((dbg, LEVEL_2, "marking %+F live end at %+F\n", irn, block)); n->flags |= be_lv_state_end; register_node(lv, irn); } @@ -462,7 +463,6 @@ be_lv_t *be_liveness(ir_graph *irg) be_lv_t *lv = xmalloc(sizeof(lv[0])); memset(lv, 0, sizeof(lv[0])); - FIRM_DBG_REGISTER(lv->dbg, DBG_MODULE); lv->irg = irg; lv->nodes = bitset_malloc(2 * get_irg_last_idx(irg)); lv->hook_info.context = lv; @@ -676,14 +676,6 @@ int be_check_dominance(ir_graph *irg) pset *be_liveness_transfer(const arch_env_t *arch_env, const arch_register_class_t *cls, ir_node *irn, pset *live) { int i, n; - FIRM_DBG_REGISTER(firm_dbg_module_t *dbg, DBG_MODULE); - - DEBUG_ONLY( - const ir_node *x; - DBG((dbg, LEVEL_1, "%+F\n", irn)); - for(x = pset_first(live); x; x = pset_next(live)) - DBG((dbg, LEVEL_1, "\tlive: %+F\n", x)); - ) /* You should better break out of your loop when hitting the first phi function. */ assert(!is_Phi(irn) && "liveness_transfer produces invalid results for phi nodes"); @@ -749,3 +741,10 @@ pset *be_liveness_nodes_live_at_input(const be_lv_t *lv, const arch_env_t *arch_ return live; } + +void be_init_live(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.liveness"); +} + +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_live); diff --git a/ir/be/belive_t.h b/ir/be/belive_t.h index 6675f3c70..6f1e965a1 100644 --- a/ir/be/belive_t.h +++ b/ir/be/belive_t.h @@ -25,7 +25,6 @@ struct _be_lv_t { ir_graph *irg; bitset_t *nodes; hook_entry_t hook_info; - DEBUG_ONLY(firm_dbg_module_t *dbg;) }; struct _be_lv_info_node_t { diff --git a/ir/be/beloopana.c b/ir/be/beloopana.c index 37d86d9f0..42a06b0b0 100644 --- a/ir/be/beloopana.c +++ b/ir/be/beloopana.c @@ -8,7 +8,7 @@ * Compute register pressure in loops */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include "set.h" @@ -21,6 +21,9 @@ #include "belive.h" #include "besched.h" #include "beloopana.h" +#include "bemodule.h" + +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL); #define HASH_LOOP_INFO(info) (HASH_PTR((info)->loop) ^ HASH_PTR((info)->cls)) @@ -33,7 +36,6 @@ typedef struct _be_loop_info_t { struct _be_loopana_t { set *data; be_irg_t *birg; - DEBUG_ONLY(firm_dbg_module_t *dbg); }; static int cmp_loop_info(const void *a, const void *b, size_t sz) { @@ -56,7 +58,7 @@ static unsigned be_compute_block_pressure(be_loopana_t *loop_ana, ir_node *block ir_node *irn; int max_live; - DBG((loop_ana->dbg, LEVEL_1, "Processing Block %+F\n", block)); + DBG((dbg, LEVEL_1, "Processing Block %+F\n", block)); /* determine largest pressure with this block */ live_nodes = be_liveness_end_of_block(loop_ana->birg->lv, aenv, cls, block, live_nodes); @@ -73,7 +75,7 @@ static unsigned be_compute_block_pressure(be_loopana_t *loop_ana, ir_node *block max_live = MAX(cnt, max_live); } - DBG((loop_ana->dbg, LEVEL_1, "Finished with Block %+F (%s %u)\n", block, cls->name, max_live)); + DBG((dbg, LEVEL_1, "Finished with Block %+F (%s %u)\n", block, cls->name, max_live)); del_pset(live_nodes); return max_live; @@ -91,7 +93,7 @@ static unsigned be_compute_loop_pressure(be_loopana_t *loop_ana, ir_loop *loop, unsigned pressure; be_loop_info_t *entry, key; - DBG((loop_ana->dbg, LEVEL_1, "\nProcessing Loop %d\n", loop->loop_nr)); + DBG((dbg, LEVEL_1, "\nProcessing Loop %d\n", loop->loop_nr)); assert(get_loop_n_elements(loop) > 0); pressure = 0; @@ -114,7 +116,7 @@ static unsigned be_compute_loop_pressure(be_loopana_t *loop_ana, ir_loop *loop, pressure = MAX(pressure, son_pressure); } - DBG((loop_ana->dbg, LEVEL_1, "Done with loop %d, pressure %u for class %s\n", loop->loop_nr, pressure, cls->name)); + DBG((dbg, LEVEL_1, "Done with loop %d, pressure %u for class %s\n", loop->loop_nr, pressure, cls->name)); /* update info in set */ key.loop = loop; @@ -137,11 +139,10 @@ be_loopana_t *be_new_loop_pressure_cls(be_irg_t *birg, const arch_register_class loop_ana->data = new_set(cmp_loop_info, 16); loop_ana->birg = birg; - FIRM_DBG_REGISTER(loop_ana->dbg, "firm.be.loopana"); - DBG((loop_ana->dbg, LEVEL_1, "\n=====================================================\n", cls->name)); - DBG((loop_ana->dbg, LEVEL_1, " Computing register pressure for class %s:\n", cls->name)); - DBG((loop_ana->dbg, LEVEL_1, "=====================================================\n", cls->name)); + DBG((dbg, LEVEL_1, "\n=====================================================\n", cls->name)); + DBG((dbg, LEVEL_1, " Computing register pressure for class %s:\n", cls->name)); + DBG((dbg, LEVEL_1, "=====================================================\n", cls->name)); be_compute_loop_pressure(loop_ana, get_irg_loop(birg->irg), cls); @@ -160,13 +161,12 @@ be_loopana_t *be_new_loop_pressure(be_irg_t *birg) { loop_ana->data = new_set(cmp_loop_info, 16); loop_ana->birg = birg; - FIRM_DBG_REGISTER(loop_ana->dbg, "firm.be.loopana"); for (i = arch_isa_get_n_reg_class(birg->main_env->arch_env->isa) - 1; i >= 0; --i) { const arch_register_class_t *cls = arch_isa_get_reg_class(birg->main_env->arch_env->isa, i); - DBG((loop_ana->dbg, LEVEL_1, "\n=====================================================\n", cls->name)); - DBG((loop_ana->dbg, LEVEL_1, " Computing register pressure for class %s:\n", cls->name)); - DBG((loop_ana->dbg, LEVEL_1, "=====================================================\n", cls->name)); + DBG((dbg, LEVEL_1, "\n=====================================================\n", cls->name)); + DBG((dbg, LEVEL_1, " Computing register pressure for class %s:\n", cls->name)); + DBG((dbg, LEVEL_1, "=====================================================\n", cls->name)); be_compute_loop_pressure(loop_ana, irg_loop, cls); } @@ -202,3 +202,10 @@ void be_free_loop_pressure(be_loopana_t *loop_ana) { del_set(loop_ana->data); xfree(loop_ana); } + +void be_init_loopana(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.loopana"); +} + +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_loopana); diff --git a/ir/be/belower.c b/ir/be/belower.c index f4e271b5e..9ef56b703 100644 --- a/ir/be/belower.c +++ b/ir/be/belower.c @@ -623,19 +623,16 @@ static void gen_assure_different_pattern(ir_node *irn, ir_node *other_different, */ static void assure_different_constraints(ir_node *irn, constraint_env_t *env) { const arch_register_req_t *req; - arch_register_req_t req_temp; - req = arch_get_register_req(env->birg->main_env->arch_env, &req_temp, irn, -1); + req = arch_get_register_req(env->birg->main_env->arch_env, irn, -1); - if (req) { - if (arch_register_req_is(req, should_be_different)) { - gen_assure_different_pattern(irn, req->other_different, env); - } - else if (arch_register_req_is(req, should_be_different_from_all)) { - int i, n = get_irn_arity(belower_skip_proj(irn)); - for (i = 0; i < n; i++) { - gen_assure_different_pattern(irn, get_irn_n(belower_skip_proj(irn), i), env); - } + if (arch_register_req_is(req, should_be_different)) { + ir_node *different_from = get_irn_n(irn, req->other_different); + gen_assure_different_pattern(irn, different_from, env); + } else if (arch_register_req_is(req, should_be_different_from_all)) { + int i, n = get_irn_arity(belower_skip_proj(irn)); + for (i = 0; i < n; i++) { + gen_assure_different_pattern(irn, get_irn_n(belower_skip_proj(irn), i), env); } } } diff --git a/ir/be/bemodule.c b/ir/be/bemodule.c index 2ff08c2ab..bd9be6629 100644 --- a/ir/be/bemodule.c +++ b/ir/be/bemodule.c @@ -6,7 +6,7 @@ * CVS-Id: $Id$ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif /* HAVE_CONFIG_H */ #include @@ -37,6 +37,10 @@ void be_init_spillbelady(void); void be_init_spillmorgan(void); void be_init_spillremat(void); void be_init_ifg(void); +void be_init_irgmod(void); +void be_init_loopana(void); +void be_init_spillslots(void); +void be_init_live(void); void be_quit_copystat(void); @@ -52,6 +56,10 @@ void be_init_modules(void) return; run_once = 1; + be_init_irgmod(); + be_init_loopana(); + be_init_live(); + be_init_spillslots(); be_init_sched(); be_init_blocksched(); be_init_spill(); @@ -68,11 +76,9 @@ void be_init_modules(void) be_init_ifg(); be_init_arch_ia32(); -#if 0 be_init_arch_ppc32(); be_init_arch_mips(); be_init_arch_arm(); -#endif #ifdef WITH_ILP be_init_ilpsched(); diff --git a/ir/be/benode.c b/ir/be/benode.c index 03882ace7..a189252a7 100644 --- a/ir/be/benode.c +++ b/ir/be/benode.c @@ -24,6 +24,7 @@ #include "fourcc.h" #include "offset.h" #include "bitfiddle.h" +#include "raw_bitset.h" #include "irop_t.h" #include "irmode_t.h" @@ -47,30 +48,15 @@ static unsigned be_node_tag = FOURCC('B', 'E', 'N', 'O'); -typedef enum { - be_req_kind_old_limited, - be_req_kind_negate_old_limited, - be_req_kind_single_reg -} be_req_kind_t; - typedef struct { arch_register_req_t req; - be_req_kind_t kind; arch_irn_flags_t flags; - union { - struct { - void (*old_limited)(void *ptr, bitset_t *bs); - void *old_limited_env; - } old_limited; - - const arch_register_t *single_reg; - } x; } 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. */ @@ -183,6 +169,33 @@ static int FrameAddr_cmp_attr(ir_node *a, ir_node *b) { return 1; } +static INLINE be_req_t *get_be_req(const ir_node *node, int pos) +{ + int idx; + be_node_attr_t *attr; + be_reg_data_t *rd; + + assert(is_be_node(node)); + attr = get_irn_attr(node); + + if(pos < 0) { + idx = -(pos + 1); + } else { + idx = pos; + assert(idx < get_irn_arity(node)); + } + assert(idx < ARR_LEN(attr->reg_data)); + rd = &attr->reg_data[idx]; + + return pos < 0 ? &rd->req : &rd->in_req; +} + +static inline arch_register_req_t *get_req(const ir_node *node, int pos) +{ + be_req_t *bereq = get_be_req(node, pos); + return &bereq->req; +} + void be_node_init(void) { static int inited = 0; @@ -303,51 +316,30 @@ static int redir_proj(const ir_node **node) return 0; } -static be_node_attr_t *retrieve_irn_attr(const ir_node *irn, int *the_pos) +static be_reg_data_t *retrieve_reg_data(const ir_node *node) { - int dummy; - be_node_attr_t *res = NULL; - int *pos = the_pos ? the_pos : &dummy; - - *pos = -1; - if(is_Proj(irn)) { - ir_node *pred = get_Proj_pred(irn); - int p = get_Proj_proj(irn); + be_node_attr_t *attr; + int pos = 0; - if(is_be_node(pred)) { - assert(get_irn_mode(pred) == mode_T); - *pos = p; - res = get_irn_attr(pred); - assert(p >= 0 && p < ARR_LEN(res->reg_data) && "illegal proj number"); - } - } else if(is_be_node(irn) && get_irn_mode(irn) != mode_T) { - be_node_attr_t *a = get_irn_attr(irn); - if(ARR_LEN(a->reg_data) > 0) { - res = a; - *pos = 0; - } + if(is_Proj(node)) { + pos = get_Proj_proj(node); + node = get_Proj_pred(node); } - return res; -} + assert(is_be_node(node)); + attr = get_irn_attr(node); + assert(pos >= 0 && pos < ARR_LEN(attr->reg_data) && "illegal proj number"); -static be_reg_data_t *retrieve_reg_data(const ir_node *irn) -{ - int pos; - be_node_attr_t *a = retrieve_irn_attr(irn, &pos); - return a ? &a->reg_data[pos] : NULL; + return &attr->reg_data[pos]; } static void be_node_set_irn_reg(const void *_self, ir_node *irn, const arch_register_t *reg) { be_reg_data_t *r = retrieve_reg_data(irn); - - if(r) - r->reg = reg; + 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) { @@ -401,6 +393,7 @@ ir_node *be_get_Spill_val(const ir_node *irn) assert(be_is_Spill(irn)); return get_irn_n(irn, be_pos_Spill_val); } + ir_node *be_get_Spill_frame(const ir_node *irn) { assert(be_is_Spill(irn)); @@ -458,12 +451,19 @@ ir_node *be_new_Copy(const arch_register_class_t *cls, ir_graph *irg, ir_node *b { ir_node *in[1]; ir_node *res; + arch_register_req_t *req; 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); + + req = get_req(res, OUT_POS(0)); + req->cls = cls; + req->type = arch_register_req_type_should_be_same; + req->other_same = 0; + return res; } @@ -923,89 +923,61 @@ int be_get_MemPerm_entity_arity(const ir_node *irn) return get_irn_arity(irn) - 1; } -static void be_limited(void *data, bitset_t *bs) +void be_set_constr_single_reg(ir_node *node, int pos, const arch_register_t *reg) { - be_req_t *req = data; - - switch(req->kind) { - case be_req_kind_negate_old_limited: - case be_req_kind_old_limited: - req->x.old_limited.old_limited(req->x.old_limited.old_limited_env, bs); - if(req->kind == be_req_kind_negate_old_limited) - bitset_flip_all(bs); - break; - case be_req_kind_single_reg: - bitset_clear_all(bs); - bitset_set(bs, req->x.single_reg->index); - break; - } -} - -static INLINE be_req_t *get_req(ir_node *irn, int pos) -{ - int idx = pos < 0 ? -(pos + 1) : pos; - be_node_attr_t *a = get_irn_attr(irn); - be_reg_data_t *rd = &a->reg_data[idx]; - be_req_t *r = pos < 0 ? &rd->req : &rd->in_req; - - assert(is_be_node(irn)); - assert(!(pos >= 0) || pos < get_irn_arity(irn)); - assert(!(pos < 0) || -(pos + 1) <= ARR_LEN(a->reg_data)); + 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; - return r; -} + assert(req->cls == NULL || req->cls == cls); + assert(! (req->type & arch_register_req_type_limited)); + assert(req->limited == NULL); -void be_set_constr_single_reg(ir_node *irn, int pos, const arch_register_t *reg) -{ - be_req_t *r = get_req(irn, pos); + limited_bitset = rbitset_obstack_alloc(obst, arch_register_class_n_regs(cls)); + rbitset_set(limited_bitset, arch_register_get_index(reg)); - r->kind = be_req_kind_single_reg; - r->x.single_reg = reg; - r->req.limited = be_limited; - r->req.limited_env = r; - r->req.type = arch_register_req_type_limited; - r->req.cls = reg->reg_class; + req->cls = cls; + req->type |= arch_register_req_type_limited; + req->limited = limited_bitset; } -void be_set_constr_limited(ir_node *irn, int pos, const arch_register_req_t *req) +void be_set_constr_limited(ir_node *node, int pos, const arch_register_req_t *req) { - be_req_t *r = get_req(irn, pos); + ir_graph *irg = get_irn_irg(node); + struct obstack *obst = get_irg_obstack(irg); + arch_register_req_t *r = get_req(node, pos); assert(arch_register_req_is(req, limited)); - - r->kind = be_req_kind_old_limited; - r->req.limited = be_limited; - r->req.limited_env = r; - r->req.type = arch_register_req_type_limited; - r->req.cls = req->cls; - - r->x.old_limited.old_limited = req->limited; - r->x.old_limited.old_limited_env = req->limited_env; + assert(! (req->type & (arch_register_req_type_should_be_same | arch_register_req_type_should_be_different))); + memcpy(r, req, sizeof(r[0])); + 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) { - be_req_t *r = get_req(irn, pos); - r->flags = flags; + be_req_t *bereq = get_be_req(irn, pos); + bereq->flags = flags; } void be_node_set_reg_class(ir_node *irn, int pos, const arch_register_class_t *cls) { - be_req_t *r = get_req(irn, pos); + arch_register_req_t *req = get_req(irn, pos); - r->req.cls = cls; + req->cls = cls; if (cls == NULL) { - r->req.type = arch_register_req_type_none; - } else if (r->req.type == arch_register_req_type_none) { - r->req.type = arch_register_req_type_normal; + 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_req_type(ir_node *irn, int pos, arch_register_req_type_t type) { - be_req_t *r = get_req(irn, pos); - r->req.type = type; + arch_register_req_t *req = get_req(irn, pos); + req->type = type; } ir_node *be_get_IncSP_pred(ir_node *irn) { @@ -1083,77 +1055,61 @@ ir_node *be_reload(const arch_env_t *arch_env, const arch_register_class_t *cls, */ -static void *put_out_reg_req(arch_register_req_t *req, const ir_node *irn, int out_pos) +static const +arch_register_req_t *get_out_reg_req(const ir_node *irn, int out_pos) { const be_node_attr_t *a = get_irn_attr(irn); - if(out_pos < ARR_LEN(a->reg_data)) { - memcpy(req, &a->reg_data[out_pos].req, sizeof(req[0])); - - if(be_is_Copy(irn)) { - req->type |= arch_register_req_type_should_be_same; - req->other_same = be_get_Copy_op(irn); - } - } else { - req->type = arch_register_req_type_none; - req->cls = NULL; + if(out_pos >= ARR_LEN(a->reg_data)) { + return arch_no_register_req; } - return req; + return &a->reg_data[out_pos].req.req; } -static void *put_in_reg_req(arch_register_req_t *req, const ir_node *irn, int pos) +static const +arch_register_req_t *get_in_reg_req(const ir_node *irn, int pos) { const be_node_attr_t *a = get_irn_attr(irn); - if(pos < get_irn_arity(irn) && pos < ARR_LEN(a->reg_data)) { - memcpy(req, &a->reg_data[pos].in_req, sizeof(req[0])); - } else { - req->type = arch_register_req_type_none; - req->cls = NULL; - } + if(pos >= get_irn_arity(irn) || pos >= ARR_LEN(a->reg_data)) + return arch_no_register_req; - return req; + return &a->reg_data[pos].in_req.req; } static const arch_register_req_t * -be_node_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) +be_node_get_irn_reg_req(const void *self, const ir_node *irn, int pos) { int out_pos = pos; if (pos < 0) { if (get_irn_mode(irn) == mode_T) - return NULL; + return arch_no_register_req; out_pos = redir_proj((const ir_node **)&irn); assert(is_be_node(irn)); - return put_out_reg_req(req, irn, out_pos); - } - - else { - if (is_be_node(irn)) { - /* - For spills and reloads, we return "none" as requirement for frame pointer, - so every input is ok. Some backends need this (e.g. STA). We use an arbitrary - large number as pos, so put_in_reg_req will return "none" as requirement. - */ - if ((be_is_Spill(irn) && pos == be_pos_Spill_frame) || + return get_out_reg_req(irn, out_pos); + } else if (is_be_node(irn)) { + /* + * For spills and reloads, we return "none" as requirement for frame + * pointer, so every input is ok. Some backends need this (e.g. STA). + */ + if ((be_is_Spill(irn) && pos == be_pos_Spill_frame) || (be_is_Reload(irn) && pos == be_pos_Reload_frame)) - return put_in_reg_req(req, irn, INT_MAX); - else - return put_in_reg_req(req, irn, pos); - } - return NULL; + return arch_no_register_req; + + return get_in_reg_req(irn, pos); } - return req; + return arch_no_register_req; } const arch_register_t * be_node_get_irn_reg(const void *_self, const ir_node *irn) { be_reg_data_t *r = retrieve_reg_data(irn); - return r ? r->reg : NULL; + return r->reg; } static arch_irn_class_t be_node_classify(const void *_self, const ir_node *irn) @@ -1176,10 +1132,19 @@ static arch_irn_class_t be_node_classify(const void *_self, const ir_node *irn) return 0; } -static arch_irn_flags_t be_node_get_flags(const void *_self, const ir_node *irn) +static arch_irn_flags_t be_node_get_flags(const void *_self, const ir_node *node) { - be_reg_data_t *r = retrieve_reg_data(irn); - return r ? r->req.flags : 0; + 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 void *self, const ir_node *irn) @@ -1258,11 +1223,16 @@ const arch_irn_handler_t be_node_irn_handler = { */ +typedef struct { + const arch_register_t *reg; + arch_register_req_t req; +} phi_attr_t; + typedef struct { arch_irn_handler_t irn_handler; arch_irn_ops_t irn_ops; const arch_env_t *arch_env; - pmap *regs; + pmap *phi_attrs; } phi_handler_t; #define get_phi_handler_from_handler(h) container_of(h, phi_handler_t, irn_handler) @@ -1274,11 +1244,28 @@ static const void *phi_get_irn_ops(const arch_irn_handler_t *handler, const ir_n return is_Phi(irn) && mode_is_datab(get_irn_mode(irn)) ? &h->irn_ops : NULL; } +static INLINE phi_attr_t *get_Phi_attr(const phi_handler_t *handler, + const ir_node *phi) +{ + phi_attr_t *attr = pmap_get(handler->phi_attrs, (void*) phi); + if(attr == NULL) { + ir_graph *irg = get_irn_irg(phi); + struct obstack *obst = get_irg_obstack(irg); + attr = obstack_alloc(obst, sizeof(attr[0])); + memset(attr, 0, sizeof(attr[0])); + pmap_insert(handler->phi_attrs, phi, attr); + } + + return attr; +} + /** * Get register class of a Phi. - * */ -static const arch_register_req_t *get_Phi_reg_req_recursive(const phi_handler_t *h, arch_register_req_t *req, const ir_node *phi, pset **visited) +static +const arch_register_req_t *get_Phi_reg_req_recursive(const phi_handler_t *h, + const ir_node *phi, + pset **visited) { int n = get_irn_arity(phi); ir_node *op; @@ -1289,52 +1276,72 @@ static const arch_register_req_t *get_Phi_reg_req_recursive(const phi_handler_t for(i = 0; i < n; ++i) { op = get_irn_n(phi, i); + /* Matze: don't we unnecessary constraint our phis with this? + * we only need to take the regclass IMO*/ if(!is_Phi(op)) - return arch_get_register_req(h->arch_env, req, op, BE_OUT_POS(0)); + return arch_get_register_req(h->arch_env, op, BE_OUT_POS(0)); } /* - The operands of that Phi were all Phis themselves. - We have to start a DFS for a non-Phi argument now. - */ + * The operands of that Phi were all Phis themselves. + * We have to start a DFS for a non-Phi argument now. + */ if(!*visited) *visited = pset_new_ptr(16); pset_insert_ptr(*visited, phi); for(i = 0; i < n; ++i) { + const arch_register_req_t *req; op = get_irn_n(phi, i); - if(get_Phi_reg_req_recursive(h, req, op, visited)) + req = get_Phi_reg_req_recursive(h, op, visited); + if(req != NULL) return req; } return NULL; } -static const arch_register_req_t *phi_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) +static +const arch_register_req_t *phi_get_irn_reg_req(const void *self, + const ir_node *irn, int pos) { phi_handler_t *phi_handler = get_phi_handler_from_ops(self); - pset *visited = NULL; + phi_attr_t *attr; + + if(!mode_is_datab(get_irn_mode(irn))) + return arch_no_register_req; + + attr = get_Phi_attr(phi_handler, irn); - get_Phi_reg_req_recursive(phi_handler, req, irn, &visited); - /* Set the requirements type to normal, since an operand of the Phi could have had constraints. */ - req->type = arch_register_req_type_normal; - if(visited) - del_pset(visited); + if(attr->req.type == arch_register_req_type_none) { + pset *visited = NULL; + const arch_register_req_t *req; + req = get_Phi_reg_req_recursive(phi_handler, irn, &visited); - return req; + memcpy(&attr->req, req, sizeof(req[0])); + assert(attr->req.cls != NULL); + attr->req.type = arch_register_req_type_normal; + + if(visited != NULL) + del_pset(visited); + } + + return &attr->req; } static void phi_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { phi_handler_t *h = get_phi_handler_from_ops(self); - pmap_insert(h->regs, irn, (void *) reg); + phi_attr_t *attr = get_Phi_attr(h, irn); + attr->reg = reg; } static const arch_register_t *phi_get_irn_reg(const void *self, const ir_node *irn) { phi_handler_t *h = get_phi_handler_from_ops(self); - return pmap_get(h->regs, (void *) irn); + phi_attr_t *attr = get_Phi_attr(h, irn); + return attr->reg; } static arch_irn_class_t phi_classify(const void *_self, const ir_node *irn) @@ -1391,14 +1398,14 @@ arch_irn_handler_t *be_phi_handler_new(const arch_env_t *arch_env) h->irn_handler.get_irn_ops = phi_get_irn_ops; h->irn_ops.impl = &phi_irn_ops; h->arch_env = arch_env; - h->regs = pmap_create(); + h->phi_attrs = pmap_create(); return (arch_irn_handler_t *) h; } void be_phi_handler_free(arch_irn_handler_t *handler) { phi_handler_t *h = (void *) handler; - pmap_destroy(h->regs); + pmap_destroy(h->phi_attrs); free(handler); } @@ -1411,9 +1418,9 @@ const void *be_phi_get_irn_ops(const arch_irn_handler_t *self, const ir_node *ir void be_phi_handler_reset(arch_irn_handler_t *handler) { phi_handler_t *h = get_phi_handler_from_handler(handler); - if(h->regs) - pmap_destroy(h->regs); - h->regs = pmap_create(); + if(h->phi_attrs) + pmap_destroy(h->phi_attrs); + h->phi_attrs = pmap_create(); } /* @@ -1428,9 +1435,9 @@ void be_phi_handler_reset(arch_irn_handler_t *handler) /** * Dumps a register requirement to a file. */ -static void dump_node_req(FILE *f, int idx, be_req_t *req) +static void dump_node_req(FILE *f, int idx, const arch_register_req_t *req, + const ir_node *node) { - unsigned i; int did_something = 0; char buf[16]; const char *prefix = buf; @@ -1438,23 +1445,10 @@ static void dump_node_req(FILE *f, int idx, be_req_t *req) snprintf(buf, sizeof(buf), "#%d ", idx); buf[sizeof(buf) - 1] = '\0'; - if(req->flags != arch_irn_flags_none) { - fprintf(f, "%sflags: ", prefix); - prefix = ""; - for(i = arch_irn_flags_none; i <= log2_ceil(arch_irn_flags_last); ++i) { - if(req->flags & (1 << i)) { - fprintf(f, "%s%s", prefix, arch_irn_flag_str(1 << i)); - prefix = "|"; - } - } - prefix = ", "; - did_something = 1; - } - - if(req->req.cls != 0) { + if(req->cls != 0) { char tmp[256]; fprintf(f, prefix); - arch_register_req_format(tmp, sizeof(tmp), &req->req); + arch_register_req_format(tmp, sizeof(tmp), req, node); fprintf(f, "%s", tmp); did_something = 1; } @@ -1466,10 +1460,10 @@ static void dump_node_req(FILE *f, int idx, be_req_t *req) /** * Dumps node register requirements to a file. */ -static void dump_node_reqs(FILE *f, ir_node *irn) +static void dump_node_reqs(FILE *f, ir_node *node) { int i; - be_node_attr_t *a = get_irn_attr(irn); + be_node_attr_t *a = get_irn_attr(node); int len = ARR_LEN(a->reg_data); fprintf(f, "registers: \n"); @@ -1479,14 +1473,14 @@ static void dump_node_reqs(FILE *f, ir_node *irn) fprintf(f, "#%d: %s\n", i, rd->reg->name); } - fprintf(f, "in requirements\n"); + fprintf(f, "in requirements:\n"); for(i = 0; i < len; ++i) { - dump_node_req(f, i, &a->reg_data[i].in_req); + dump_node_req(f, i, &a->reg_data[i].in_req.req, node); } - fprintf(f, "\nout requirements\n"); + fprintf(f, "\nout requirements:\n"); for(i = 0; i < len; ++i) { - dump_node_req(f, i, &a->reg_data[i].req); + dump_node_req(f, i, &a->reg_data[i].req.req, node); } } @@ -1575,7 +1569,7 @@ static void copy_attr(const ir_node *old_node, ir_node *new_node) be_node_attr_t *old_attr = get_irn_attr(old_node); be_node_attr_t *new_attr = get_irn_attr(new_node); struct obstack *obst = get_irg_obstack(get_irn_irg(new_node)); - int i, len; + unsigned i, len; assert(is_be_node(old_node)); assert(is_be_node(new_node)); @@ -1588,7 +1582,8 @@ static void copy_attr(const ir_node *old_node, ir_node *new_node) else len = 0; - if(be_is_Keep(old_node) || be_is_RegParams(old_node) || be_is_Barrier(old_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); } else { new_attr->reg_data = NEW_ARR_D(be_reg_data_t, obst, len); @@ -1596,15 +1591,21 @@ static void copy_attr(const ir_node *old_node, ir_node *new_node) if(len > 0) { memcpy(new_attr->reg_data, old_attr->reg_data, len * sizeof(be_reg_data_t)); - for(i = 0; i < len; ++i) { - be_req_t *r; - - r = &new_attr->reg_data[i].req; - r->req.limited_env = r; - - r = &new_attr->reg_data[i].in_req; - r->req.limited_env = r; + const be_reg_data_t *rd = &old_attr->reg_data[i]; + be_reg_data_t *newrd = &new_attr->reg_data[i]; + if(arch_register_req_is(&rd->req.req, limited)) { + const arch_register_req_t *req = &rd->req.req; + arch_register_req_t *new_req = &newrd->req.req; + new_req->limited + = rbitset_duplicate_obstack_alloc(obst, req->limited, req->cls->n_regs); + } + if(arch_register_req_is(&rd->in_req.req, limited)) { + const arch_register_req_t *req = &rd->in_req.req; + arch_register_req_t *new_req = &newrd->in_req.req; + new_req->limited + = rbitset_duplicate_obstack_alloc(obst, req->limited, req->cls->n_regs); + } } } } diff --git a/ir/be/beraextern.c b/ir/be/beraextern.c index b70cc2dd0..d10e455be 100644 --- a/ir/be/beraextern.c +++ b/ir/be/beraextern.c @@ -75,6 +75,7 @@ alloc ::= node-nr reg-nr . #include "pset.h" #include "pmap.h" #include "bitset.h" +#include "raw_bitset.h" #include "irprintf_t.h" #include "irnode_t.h" @@ -202,7 +203,7 @@ static void handle_constraints_insn(be_raext_env_t *env, be_insn_t *insn) be_operand_t *op = &insn->ops[i]; if(op->has_constraints) { - ir_node *cpy = be_new_Copy(op->req.cls, env->irg, bl, op->carrier); + ir_node *cpy = be_new_Copy(op->req->cls, env->irg, bl, op->carrier); sched_add_before(insn->next_insn, cpy); edges_reroute(op->carrier, cpy, env->irg); } @@ -212,10 +213,10 @@ static void handle_constraints_insn(be_raext_env_t *env, be_insn_t *insn) be_operand_t *op = &insn->ops[i]; if(op->has_constraints) { - ir_node *cpy = be_new_Copy(op->req.cls, env->irg, bl, op->carrier); + ir_node *cpy = be_new_Copy(op->req->cls, env->irg, bl, op->carrier); sched_add_before(insn->irn, cpy); set_irn_n(insn->irn, op->pos, cpy); - be_set_constr_limited(cpy, BE_OUT_POS(0), &op->req); + be_set_constr_limited(cpy, BE_OUT_POS(0), op->req); } } } @@ -292,16 +293,16 @@ static void extract_vars_of_cls(be_raext_env_t *raenv) { * If yes, dump it to FILE raenv->f */ static INLINE void dump_constraint(be_raext_env_t *raenv, ir_node *irn, int pos) { - bitset_t *bs = bitset_alloca(raenv->cls->n_regs); - arch_register_req_t req; - - arch_get_register_req(raenv->aenv, &req, irn, pos); - if (arch_register_req_is(&req, limited)) { - int reg_nr; - req.limited(req.limited_env, bs); - reg_nr = bitset_next_set(bs, 0); + const arch_register_req_t *req; + + req = arch_get_register_req(raenv->aenv, irn, pos); + if (arch_register_req_is(req, limited)) { + unsigned reg_nr; + + reg_nr = rbitset_next(req->limited, 0, 1); fprintf(raenv->f, "<%d>", reg_nr); - assert(-1 == bitset_next_set(bs, reg_nr+1) && "Constraints with more than 1 possible register are not supported"); + assert(rbitset_popcnt(req->limited, raenv->cls->n_regs) <= 1 + && "Constraints with more than 1 possible register are not supported"); } } @@ -392,7 +393,7 @@ NextVar: ; static void dump_affinities_walker(ir_node *irn, void *env) { be_raext_env_t *raenv = env; - arch_register_req_t req; + const arch_register_req_t *req; int pos, max; be_var_info_t *vi1, *vi2; @@ -415,12 +416,15 @@ static void dump_affinities_walker(ir_node *irn, void *env) { /* should_be_equal constraints are affinites */ for (pos = 0, max = get_irn_arity(irn); posaenv, &req, irn, pos); + req = arch_get_register_req(raenv->aenv, irn, pos); - if (arch_register_req_is(&req, should_be_same) && arch_irn_is(raenv->aenv, req.other_same, ignore)) { - vi2 = be_get_var_info(req.other_same); + if (arch_register_req_is(req, should_be_same)) { + ir_node *other = get_irn_n(irn, req->other_same); + if(arch_irn_is(raenv->aenv, other, ignore)) { + vi2 = be_get_var_info(other); - fprintf(raenv->f, "(%d, %d, %d)\n", vi1->var_nr, vi2->var_nr, get_affinity_weight(irn)); + fprintf(raenv->f, "(%d, %d, %d)\n", vi1->var_nr, vi2->var_nr, get_affinity_weight(irn)); + } } } } diff --git a/ir/be/bespillbelady.c b/ir/be/bespillbelady.c index 15519a327..028d17b4d 100644 --- a/ir/be/bespillbelady.c +++ b/ir/be/bespillbelady.c @@ -357,14 +357,13 @@ static loc_t to_take_or_not_to_take(belady_env_t *env, ir_node* first, be_next_use_t next_use; loc_t loc; loc.time = USES_INFINITY; + loc.irn = node; if (!arch_irn_consider_in_reg_alloc(env->arch, env->cls, node)) { loc.time = USES_INFINITY; return loc; } - loc.irn = node; - /* We have to keep nonspillable nodes in the workingset */ if(arch_irn_get_flags(env->arch, node) & arch_irn_flags_dont_spill) { loc.time = 0; @@ -671,9 +670,6 @@ void be_spill_belady_spill_env(be_irg_t *birg, const arch_register_class_t *cls, belady_env_t env; ir_graph *irg = be_get_birg_irg(birg); - FIRM_DBG_REGISTER(dbg, "firm.be.spill.belady"); - //firm_dbg_set_mask(dbg, DBG_SPILL); - be_invalidate_liveness(birg); be_assure_liveness(birg); /* construct control flow loop tree */ @@ -722,6 +718,7 @@ void be_init_spillbelady(void) }; be_register_spiller("belady", &belady_spiller); + FIRM_DBG_REGISTER(dbg, "firm.be.spill.belady"); } BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillbelady); diff --git a/ir/be/bespillmorgan.c b/ir/be/bespillmorgan.c index a629a9f0c..204cafa6a 100644 --- a/ir/be/bespillmorgan.c +++ b/ir/be/bespillmorgan.c @@ -6,7 +6,7 @@ * */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include "bespillmorgan.h" @@ -544,9 +544,6 @@ void be_spill_morgan(be_irg_t *birg, const arch_register_class_t *cls) { ir_graph *irg = be_get_birg_irg(birg); morgan_env_t env; - FIRM_DBG_REGISTER(dbg, "ir.be.spillmorgan"); - //firm_dbg_set_mask(dbg, DBG_SPILLS | DBG_LOOPANA); - be_assure_liveness(birg); env.arch = birg->main_env->arch_env; @@ -610,6 +607,7 @@ void be_init_spillmorgan(void) }; be_register_spiller("morgan", &morgan_spiller); + FIRM_DBG_REGISTER(dbg, "ir.be.spillmorgan"); } BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillmorgan); diff --git a/ir/be/bespillremat.c b/ir/be/bespillremat.c index 13f58f865..b35ae8e12 100644 --- a/ir/be/bespillremat.c +++ b/ir/be/bespillremat.c @@ -77,14 +77,14 @@ #define REMATS_NOINVERSE 2 #define REMATS_ALL 3 -static int opt_dump_flags = 0; +static unsigned opt_dump_flags = 0; static int opt_log = 0; -static int opt_keep_alive = 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 int opt_remats = REMATS_ALL; +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; @@ -1909,7 +1909,7 @@ luke_blockwalker(ir_node * bb, void * data) pset *used; pset *remat_defs; keyval_t *keyval; - ilp_cst_t one_memoperand; + ilp_cst_t one_memoperand = -1; /* iterate only until first phi */ if(is_Phi(irn)) diff --git a/ir/be/bespillslots.c b/ir/be/bespillslots.c index 2b3ece63d..955b5dc0a 100644 --- a/ir/be/bespillslots.c +++ b/ir/be/bespillslots.c @@ -28,6 +28,7 @@ #include "benodesets.h" #include "bestatevent.h" #include "bespilloptions.h" +#include "bemodule.h" #define DBG_COALESCING 1 #define DBG_INTERFERENCES 2 @@ -640,7 +641,6 @@ be_fec_env_t *be_new_frame_entity_coalescer(be_irg_t *birg) env->reloads = NEW_ARR_F(ir_node*, 0); env->affinity_edges = NEW_ARR_F(affinity_edge_t*, 0); env->memperms = new_set(cmp_memperm, 10); - FIRM_DBG_REGISTER(dbg, "firm.be.spillslots"); return env; } @@ -714,3 +714,10 @@ void be_coalesce_spillslots(be_irg_t *birg) be_free_frame_entity_coalescer(env); } + +void be_init_spillslots(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.spillslots"); +} + +BE_REGISTER_MODULE_CONSTRUCTOR(be_init_spillslots); diff --git a/ir/be/bestabs.c b/ir/be/bestabs.c index 8b3fc01f2..18218383a 100644 --- a/ir/be/bestabs.c +++ b/ir/be/bestabs.c @@ -5,9 +5,8 @@ * @date 11.9.2006 * @cvsid $Id$ */ - #ifdef HAVE_CONFIG_H -# include "config.h" +# include #endif #include diff --git a/ir/be/beuses.c b/ir/be/beuses.c index bdb987549..f511839eb 100644 --- a/ir/be/beuses.c +++ b/ir/be/beuses.c @@ -9,7 +9,7 @@ * Released under the GPL */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 9275b297d..9ddbde128 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -46,13 +46,13 @@ #include "../beilpsched.h" #include "../bespillslots.h" #include "../bemodule.h" +#include "../begnuas.h" #include "bearch_ia32_t.h" #include "ia32_new_nodes.h" /* ia32 nodes interface */ #include "gen_ia32_regalloc_if.h" /* the generated interface (register type and class defenitions) */ #include "gen_ia32_machine.h" -#include "ia32_gen_decls.h" /* interface declaration emitter */ #include "ia32_transform.h" #include "ia32_emitter.h" #include "ia32_map_regs.h" @@ -62,8 +62,6 @@ #include "ia32_finish.h" #include "ia32_util.h" -#define DEBUG_MODULE "firm.be.ia32.isa" - /* TODO: ugly */ static set *cur_reg_set = NULL; @@ -140,15 +138,14 @@ ir_node *ia32_new_Unknown_xmm(ia32_code_gen_t *cg) { * Returns gp_noreg or fp_noreg, depending in input requirements. */ ir_node *ia32_get_admissible_noreg(ia32_code_gen_t *cg, ir_node *irn, int pos) { - arch_register_req_t req; - const arch_register_req_t *p_req; + const arch_register_req_t *req; - p_req = arch_get_register_req(cg->arch_env, &req, irn, pos); - assert(p_req && "Missing register requirements"); - if (p_req->cls == &ia32_reg_classes[CLASS_ia32_gp]) + req = arch_get_register_req(cg->arch_env, irn, pos); + assert(req != NULL && "Missing register requirements"); + if (req->cls == &ia32_reg_classes[CLASS_ia32_gp]) return ia32_new_NoReg_gp(cg); - else - return ia32_new_NoReg_fp(cg); + + return ia32_new_NoReg_fp(cg); } /************************************************** @@ -167,99 +164,57 @@ ir_node *ia32_get_admissible_noreg(ia32_code_gen_t *cg, ir_node *irn, int pos) { * If the node returns a tuple (mode_T) then the proj's * will be asked for this information. */ -static const arch_register_req_t *ia32_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) { - const ia32_irn_ops_t *ops = self; - const ia32_register_req_t *irn_req; - long node_pos = pos == -1 ? 0 : pos; - ir_mode *mode = is_Block(irn) ? NULL : get_irn_mode(irn); - FIRM_DBG_REGISTER(firm_dbg_module_t *mod, DEBUG_MODULE); - - if (is_Block(irn) || mode == mode_X) { - DBG((mod, LEVEL_1, "ignoring Block, mode_M, mode_X node %+F\n", irn)); - return NULL; +static const arch_register_req_t *ia32_get_irn_reg_req(const void *self, + const ir_node *node, + int pos) { + long node_pos = pos == -1 ? 0 : pos; + ir_mode *mode = is_Block(node) ? NULL : get_irn_mode(node); + + if (is_Block(node) || mode == mode_X) { + return arch_no_register_req; } if (mode == mode_T && pos < 0) { - DBG((mod, LEVEL_1, "ignoring request OUT requirements for node %+F\n", irn)); - return NULL; + return arch_no_register_req; } - DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); - - if (is_Proj(irn)) { + if (is_Proj(node)) { if(mode == mode_M) - return NULL; + return arch_no_register_req; if(pos >= 0) { - DBG((mod, LEVEL_1, "ignoring request IN requirements for node %+F\n", irn)); - return NULL; + return arch_no_register_req; } - node_pos = (pos == -1) ? get_Proj_proj(irn) : pos; - irn = skip_Proj_const(irn); - - DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); + node_pos = (pos == -1) ? get_Proj_proj(node) : pos; + node = skip_Proj_const(node); } - if (is_ia32_irn(irn)) { - irn_req = (pos >= 0) ? get_ia32_in_req(irn, pos) : get_ia32_out_req(irn, node_pos); - if (irn_req == NULL) { - /* no requirements */ - return NULL; - } - - DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); - - memcpy(req, &(irn_req->req), sizeof(*req)); + if (is_ia32_irn(node)) { + const arch_register_req_t *req; + if(pos >= 0) + req = get_ia32_in_req(node, pos); + else + req = get_ia32_out_req(node, node_pos); - if (arch_register_req_is(&(irn_req->req), should_be_same)) { - assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI"); - req->other_same = get_irn_n(irn, irn_req->same_pos); - } + assert(req != NULL); - if (arch_register_req_is(&(irn_req->req), should_be_different)) { - assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI"); - req->other_different = get_irn_n(irn, irn_req->different_pos); - } - } - else { - /* treat Unknowns like Const with default requirements */ - if (is_Unknown(irn)) { - DB((mod, LEVEL_1, "returning UKNWN reqs for %+F\n", irn)); - if (mode_is_float(mode)) { - if (USE_SSE2(ops->cg)) - memcpy(req, &(ia32_default_req_ia32_xmm_xmm_UKNWN), sizeof(*req)); - else - memcpy(req, &(ia32_default_req_ia32_vfp_vfp_UKNWN), sizeof(*req)); - } - else if (mode_is_int(mode) || mode_is_reference(mode)) - memcpy(req, &(ia32_default_req_ia32_gp_gp_UKNWN), sizeof(*req)); - else if (mode == mode_T || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring Unknown node %+F\n", irn)); - return NULL; - } - else - assert(0 && "unsupported Unknown-Mode"); - } - else { - DB((mod, LEVEL_1, "returning NULL for %+F (not ia32)\n", irn)); - req = NULL; - } + return req; } - return req; + /* unknowns should be transformed already */ + assert(!is_Unknown(node)); + + return arch_no_register_req; } static void ia32_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { int pos = 0; - const ia32_irn_ops_t *ops = self; if (get_irn_mode(irn) == mode_X) { return; } - DBG((ops->cg->mod, LEVEL_1, "ia32 assigned register %s to node %+F\n", reg->name, irn)); - if (is_Proj(irn)) { pos = get_Proj_proj(irn); irn = skip_Proj(irn); @@ -270,8 +225,7 @@ static void ia32_set_irn_reg(const void *self, ir_node *irn, const arch_register slots = get_ia32_slots(irn); slots[pos] = reg; - } - else { + } else { ia32_set_firm_reg(irn, reg, cur_reg_set); } } @@ -294,8 +248,7 @@ static const arch_register_t *ia32_get_irn_reg(const void *self, const ir_node * const arch_register_t **slots; slots = get_ia32_slots(irn); reg = slots[pos]; - } - else { + } else { reg = ia32_get_firm_reg(irn, cur_reg_set); } @@ -385,8 +338,6 @@ static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) { } } - DBG((ops->cg->mod, LEVEL_1, "stack biased %+F with %d\n", irn, bias)); - am_flav = get_ia32_am_flavour(irn); am_flav |= ia32_O; set_ia32_am_flavour(irn, am_flav); @@ -1541,7 +1492,7 @@ static void ia32_codegen(void *self) { ia32_code_gen_t *cg = self; ir_graph *irg = cg->irg; - ia32_gen_routine(cg, cg->isa->out, irg); + ia32_gen_routine(cg, irg); cur_reg_set = NULL; @@ -1660,6 +1611,7 @@ static ia32_isa_t ia32_isa_template = { -1, /* stack direction */ NULL, /* main environment */ }, + {}, /* emitter environment */ NULL, /* 16bit register names */ NULL, /* 8bit register names */ NULL, /* types */ @@ -1675,7 +1627,6 @@ static ia32_isa_t ia32_isa_template = { arch_pentium_4, /* optimize for architecture */ fp_sse2, /* use sse2 unit */ NULL, /* current code generator */ - NULL, /* output file */ #ifndef NDEBUG NULL, /* name obstack */ 0 /* name obst size */ @@ -1711,11 +1662,11 @@ static void *ia32_init(FILE *file_handle) { isa->opt &= ~IA32_OPT_INCDEC; } + be_emit_init_env(&isa->emit, file_handle); isa->regs_16bit = pmap_create(); isa->regs_8bit = pmap_create(); isa->types = pmap_create(); isa->tv_ent = pmap_create(); - isa->out = file_handle; isa->cpu = ia32_init_machine_description(); ia32_build_16bit_reg_map(isa->regs_16bit); @@ -1737,11 +1688,11 @@ static void *ia32_init(FILE *file_handle) { #endif /* NDEBUG */ ia32_handle_intrinsics(); - ia32_switch_section(isa->out, NO_SECTION); /* needed for the debug support */ - ia32_switch_section(isa->out, SECTION_TEXT); - fprintf(isa->out, ".Ltext0:\n"); + be_gas_emit_switch_section(&isa->emit, GAS_SECTION_TEXT); + be_emit_cstring(&isa->emit, ".Ltext0:\n"); + be_emit_write_line(&isa->emit); inited = 1; @@ -1757,7 +1708,7 @@ static void ia32_done(void *self) { ia32_isa_t *isa = self; /* emit now all global declarations */ - ia32_gen_decls(isa->out, isa->arch_isa.main_env); + be_gas_emit_decls(&isa->emit, isa->arch_isa.main_env); pmap_destroy(isa->regs_16bit); pmap_destroy(isa->regs_8bit); @@ -1768,6 +1719,8 @@ static void ia32_done(void *self) { obstack_free(isa->name_obst, NULL); #endif /* NDEBUG */ + be_emit_destroy_env(&isa->emit); + free(self); } @@ -2162,13 +2115,13 @@ static lc_opt_enum_int_var_t fp_unit_var = { }; static const lc_opt_enum_int_items_t gas_items[] = { - { "linux", ASM_LINUX_GAS }, - { "mingw", ASM_MINGW_GAS }, + { "normal", GAS_FLAVOUR_NORMAL }, + { "mingw", GAS_FLAVOUR_MINGW }, { NULL, 0 } }; static lc_opt_enum_int_var_t gas_var = { - (int *)&asm_flavour, gas_items + (int*) &be_gas_flavour, gas_items }; static const lc_opt_table_entry_t ia32_options[] = { diff --git a/ir/be/ia32/bearch_ia32_t.h b/ir/be/ia32/bearch_ia32_t.h index a44ee910a..a67cc182d 100644 --- a/ir/be/ia32/bearch_ia32_t.h +++ b/ir/be/ia32/bearch_ia32_t.h @@ -11,6 +11,7 @@ #include "../be.h" #include "../bemachine.h" +#include "../beemitter.h" #ifdef NDEBUG #define SET_IA32_ORIG_NODE(n, o) @@ -123,6 +124,7 @@ typedef struct _ia32_code_gen_t { */ struct _ia32_isa_t { arch_isa_t arch_isa; /**< must be derived from arch_isa_t */ + be_emit_env_t emit; pmap *regs_16bit; /**< Contains the 16bits names of the gp registers */ pmap *regs_8bit; /**< Contains the 8bits names of the gp registers */ pmap *types; /**< A map of modes to primitive types */ @@ -132,7 +134,6 @@ struct _ia32_isa_t { int opt_arch; /**< optimize for architecture */ int fp_kind; /**< floating point kind */ ia32_code_gen_t *cg; /**< the current code generator */ - FILE *out; /**< output file */ const be_machine_t *cpu; /**< the abstract machine */ #ifndef NDEBUG struct obstack *name_obst; /**< holds the original node names (for debugging) */ diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 49be5d4fa..e3f89eb31 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -21,11 +21,14 @@ #include "iredges_t.h" #include "execfreq.h" #include "error.h" +#include "raw_bitset.h" #include "../besched_t.h" #include "../benode_t.h" #include "../beabi.h" #include "../be_dbgout.h" +#include "../beemitter.h" +#include "../begnuas.h" #include "ia32_emitter.h" #include "gen_ia32_emitter.h" @@ -42,81 +45,6 @@ /* global arch_env for lc_printf functions */ static const arch_env_t *arch_env = NULL; -/** by default, we generate assembler code for the Linux gas */ -asm_flavour_t asm_flavour = ASM_LINUX_GAS; - -/** - * Switch to a new section - */ -void ia32_switch_section(FILE *F, section_t sec) { - static section_t curr_sec = NO_SECTION; - static const char *text[ASM_MAX][SECTION_MAX] = { - { - ".section\t.text", - ".section\t.data", - ".section\t.rodata", - ".section\t.bss", - ".section\t.tbss,\"awT\",@nobits", - ".section\t.ctors,\"aw\",@progbits" - }, - { - ".section\t.text", - ".section\t.data", - ".section .rdata,\"dr\"", - ".section\t.bss", - ".section\t.tbss,\"awT\",@nobits", - ".section\t.ctors,\"aw\",@progbits" - } - }; - - if (curr_sec == sec) - return; - - curr_sec = sec; - switch (sec) { - - case NO_SECTION: - break; - - case SECTION_TEXT: - case SECTION_DATA: - case SECTION_RODATA: - case SECTION_COMMON: - case SECTION_TLS: - case SECTION_CTOR: - fprintf(F, "\t%s\n", text[asm_flavour][sec]); - break; - - default: - break; - } -} - -static void ia32_dump_function_object(FILE *F, const char *name) -{ - switch (asm_flavour) { - case ASM_LINUX_GAS: - fprintf(F, "\t.type\t%s, @function\n", name); - break; - case ASM_MINGW_GAS: - fprintf(F, "\t.def\t%s;\t.scl\t2;\t.type\t32;\t.endef\n", name); - break; - default: - break; - } -} - -static void ia32_dump_function_size(FILE *F, const char *name) -{ - switch (asm_flavour) { - case ASM_LINUX_GAS: - fprintf(F, "\t.size\t%s, .-%s\n", name, name); - break; - default: - break; - } -} - /** * Returns the register at in position pos. */ @@ -136,24 +64,18 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos) { /* in case of a joker register: just return a valid register */ if (arch_register_type_is(reg, joker)) { - arch_register_req_t req; - const arch_register_req_t *p_req; + const arch_register_req_t *req; /* ask for the requirements */ - p_req = arch_get_register_req(arch_env, &req, irn, pos); + req = arch_get_register_req(arch_env, irn, pos); - if (arch_register_req_is(p_req, limited)) { + if (arch_register_req_is(req, limited)) { /* in case of limited requirements: get the first allowed register */ - - bitset_t *bs = bitset_alloca(arch_register_class_n_regs(p_req->cls)); - int idx; - - p_req->limited(p_req->limited_env, bs); - idx = bitset_next_set(bs, 0); - reg = arch_register_for_index(p_req->cls, idx); + unsigned idx = rbitset_next(req->limited, 0, 1); + reg = arch_register_for_index(req->cls, idx); } else { /* otherwise get first register in class */ - reg = arch_register_for_index(p_req->cls, 0); + reg = arch_register_for_index(req->cls, 0); } } @@ -253,33 +175,6 @@ static const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mod } } -#if 0 -/** - * Determines the SSE suffix depending on the mode. - */ -static int ia32_print_mode_suffix(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) -{ - ir_node *irn = arg->v_ptr; - ir_mode *mode = get_ia32_ls_mode(irn); - - if (mode_is_float(mode)) { - return lc_appendable_chadd(app, get_mode_size_bits(mode) == 32 ? 's' : 'd'); - } else { - if(get_mode_size_bits(mode) == 32) - return 0; - - if(mode_is_signed(mode)) - lc_appendable_chadd(app, 's'); - else - lc_appendable_chadd(app, 'z'); - - lc_appendable_chadd(app, get_mode_suffix(mode)); - return 2; - } -} -#endif - /** * Add a number to a prefix. This number will not be used a second time. */ @@ -300,25 +195,16 @@ static char *get_unique_label(char *buf, size_t buflen, const char *prefix) { * |_| |_| *************************************************************/ -void ia32_emit_ident(ia32_emit_env_t *env, ident *id) -{ - size_t len = get_id_strlen(id); - const char* str = get_id_str(id); - - ia32_emit_string_len(env, str, len); -} - -void ia32_emit_irprintf(ia32_emit_env_t *env, const char *fmt, ...) -{ - char buf[128]; - va_list ap; - - va_start(ap, fmt); - ir_vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - ia32_emit_string(env, buf); -} +// we have no C++ and can't define an implicit ia32_emit_env_t* cast to +// be_emit_env_t* so we cheat a bit... +#define be_emit_char(env,c) be_emit_char(env->emit,c) +#define be_emit_string(env,s) be_emit_string(env->emit,s) +#undef be_emit_cstring +#define be_emit_cstring(env,x) { be_emit_string_len(env->emit, x, sizeof(x)-1); } +#define be_emit_ident(env,i) be_emit_ident(env->emit,i) +#define be_emit_write_line(env) be_emit_write_line(env->emit) +#define be_emit_finish_line_gas(env,n) be_emit_finish_line_gas(env->emit,n) +#define be_emit_pad_comment(env) be_emit_pad_comment(env->emit) void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos) { @@ -327,16 +213,16 @@ void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int po assert(pos < get_irn_arity(node)); - ia32_emit_char(env, '%'); - ia32_emit_string(env, reg_name); + be_emit_char(env, '%'); + be_emit_string(env, reg_name); } void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos) { const arch_register_t *reg = get_out_reg(node, pos); const char *reg_name = arch_register_get_name(reg); - ia32_emit_char(env, '%'); - ia32_emit_string(env, reg_name); + be_emit_char(env, '%'); + be_emit_string(env, reg_name); } void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos) @@ -344,8 +230,8 @@ void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos) ia32_attr_t *attr = get_ia32_attr(node); assert(pos < 3); - ia32_emit_char(env, '%'); - ia32_emit_string(env, attr->x87[pos]->name); + be_emit_char(env, '%'); + be_emit_string(env, attr->x87[pos]->name); } void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node) @@ -363,16 +249,16 @@ void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node) break; default: assert(0); - ia32_emit_string(env, "BAD"); + be_emit_string(env, "BAD"); return; } - ia32_emit_ident(env, id); + be_emit_ident(env, id); } void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_mode *mode) { - ia32_emit_char(env, get_mode_suffix(mode)); + be_emit_char(env, get_mode_suffix(mode)); } void ia32_emit_x87_mode_suffix(ia32_emit_env_t *env, const ir_node *node) @@ -400,15 +286,15 @@ void ia32_emit_xmm_mode_suffix(ia32_emit_env_t *env, const ir_node *node) { ir_mode *mode = get_ia32_ls_mode(node); assert(mode != NULL); - ia32_emit_char(env, 's'); - ia32_emit_char(env, get_xmm_mode_suffix(mode)); + be_emit_char(env, 's'); + be_emit_char(env, get_xmm_mode_suffix(mode)); } void ia32_emit_xmm_mode_suffix_s(ia32_emit_env_t *env, const ir_node *node) { ir_mode *mode = get_ia32_ls_mode(node); assert(mode != NULL); - ia32_emit_char(env, get_xmm_mode_suffix(mode)); + be_emit_char(env, get_xmm_mode_suffix(mode)); } void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode) @@ -416,12 +302,50 @@ void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode) if(get_mode_size_bits(mode) == 32) return; if(mode_is_signed(mode)) { - ia32_emit_char(env, 's'); + be_emit_char(env, 's'); } else { - ia32_emit_char(env, 'z'); + be_emit_char(env, 'z'); + } +} + +static void ia32_emit_function_object(ia32_emit_env_t *env, const char *name) +{ + switch (be_gas_flavour) { + case GAS_FLAVOUR_NORMAL: + be_emit_cstring(env, "\t.type\t"); + be_emit_string(env, name); + be_emit_cstring(env, ", @function\n"); + be_emit_write_line(env); + break; + case GAS_FLAVOUR_MINGW: + be_emit_cstring(env, "\t.def\t"); + be_emit_string(env, name); + be_emit_cstring(env, ";\t.scl\t2;\t.type\t32;\t.endef\n"); + be_emit_write_line(env); + break; + default: + break; + } +} + +static void ia32_emit_function_size(ia32_emit_env_t *env, const char *name) +{ + switch (be_gas_flavour) { + case GAS_FLAVOUR_NORMAL: + be_emit_cstring(env, "\t.size\t"); + be_emit_string(env, name); + be_emit_cstring(env, ", .-"); + be_emit_string(env, name); + be_emit_char(env, '\n'); + be_emit_write_line(env); + break; + default: + break; } } + + /** * Emits registers and/or address mode of a binary operation. */ @@ -429,9 +353,9 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { switch(get_ia32_op_type(node)) { case ia32_Normal: if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - ia32_emit_char(env, '$'); + be_emit_char(env, '$'); ia32_emit_immediate(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 2); } else { const arch_register_t *in1 = get_in_reg(node, 2); @@ -449,33 +373,33 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { in_name = "cl"; } - ia32_emit_char(env, '%'); - ia32_emit_string(env, in_name); - ia32_emit_cstring(env, ", %"); - ia32_emit_string(env, arch_register_get_name(out)); + be_emit_char(env, '%'); + be_emit_string(env, in_name); + be_emit_cstring(env, ", %"); + be_emit_string(env, arch_register_get_name(out)); } break; case ia32_AddrModeS: if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { assert(!produces_result(node) && "Source AM with Const must not produce result"); ia32_emit_am(env, node); - ia32_emit_cstring(env, ", $"); + be_emit_cstring(env, ", $"); ia32_emit_immediate(env, node); } else if (produces_result(node)) { ia32_emit_am(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { ia32_emit_am(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 2); } break; case ia32_AddrModeD: if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - ia32_emit_char(env, '$'); + be_emit_char(env, '$'); ia32_emit_immediate(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_am(env, node); } else { const arch_register_t *in1 = get_in_reg(node, get_irn_arity(node) == 5 ? 3 : 2); @@ -489,9 +413,9 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { in_name = "cl"; } - ia32_emit_char(env, '%'); - ia32_emit_string(env, in_name); - ia32_emit_cstring(env, ", "); + be_emit_char(env, '%'); + be_emit_string(env, in_name); + be_emit_cstring(env, ", "); ia32_emit_am(env, node); } break; @@ -519,10 +443,10 @@ void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) { in = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2; out = out ? out : in1; - ia32_emit_char(env, '%'); - ia32_emit_string(env, arch_register_get_name(in)); - ia32_emit_cstring(env, ", %"); - ia32_emit_string(env, arch_register_get_name(out)); + be_emit_char(env, '%'); + be_emit_string(env, arch_register_get_name(in)); + be_emit_cstring(env, ", %"); + be_emit_string(env, arch_register_get_name(out)); } break; case ia32_AddrModeS: @@ -541,7 +465,7 @@ void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node) { switch(get_ia32_op_type(node)) { case ia32_Normal: if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - ia32_emit_char(env, '$'); + be_emit_char(env, '$'); ia32_emit_immediate(env, node); } else { if (is_ia32_Mul(node) || is_ia32_IMul1OP(node)) { @@ -580,20 +504,20 @@ void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node) { /* emit offset */ if (id != NULL) { if (is_ia32_am_sc_sign(node)) - ia32_emit_char(env, '-'); - ia32_emit_ident(env, id); + be_emit_char(env, '-'); + be_emit_ident(env, id); } if(offs != 0) { if(id != NULL) { - ia32_emit_irprintf(env, "%+d", offs); + be_emit_irprintf(env->emit, "%+d", offs); } else { - ia32_emit_irprintf(env, "%d", offs); + be_emit_irprintf(env->emit, "%d", offs); } } if (am_flav & (ia32_B | ia32_I)) { - ia32_emit_char(env, '('); + be_emit_char(env, '('); /* emit base */ if (am_flav & ia32_B) { @@ -602,76 +526,17 @@ void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node) { /* emit index + scale */ if (am_flav & ia32_I) { - ia32_emit_char(env, ','); + be_emit_char(env, ','); ia32_emit_source_register(env, node, 1); if (am_flav & ia32_S) { - ia32_emit_irprintf(env, ",%d", 1 << get_ia32_am_scale(node)); + be_emit_irprintf(env->emit, ",%d", 1 << get_ia32_am_scale(node)); } } - ia32_emit_char(env, ')'); + be_emit_char(env, ')'); } } -#if 0 -/** - * Formated print of commands and comments. - */ -static void ia32_fprintf_format(FILE *F, const ir_node *irn, char *cmd_buf, char *cmnt_buf) { - unsigned lineno; - const char *name = irn ? be_retrieve_dbg_info(get_irn_dbg_info((ir_node *)irn), &lineno) : NULL; - - if (name) - fprintf(F, "\t%-35s %-60s /* %s:%u */\n", cmd_buf, cmnt_buf, name, lineno); - else - fprintf(F, "\t%-35s %-60s\n", cmd_buf, cmnt_buf); -} -#endif - -void ia32_write_line(ia32_emit_env_t *env) -{ - char *finished_line = obstack_finish(env->obst); - - fwrite(finished_line, env->linelength, 1, env->out); - env->linelength = 0; - obstack_free(env->obst, finished_line); -} - -void ia32_pad_comment(ia32_emit_env_t *env) -{ - while(env->linelength <= 30) { - ia32_emit_char(env, ' '); - } - ia32_emit_cstring(env, " "); -} - -void ia32_emit_finish_line(ia32_emit_env_t *env, const ir_node *node) -{ - dbg_info *dbg; - const char *sourcefile; - unsigned lineno; - - if(node == NULL) { - ia32_emit_char(env, '\n'); - ia32_write_line(env); - return; - } - - ia32_pad_comment(env); - ia32_emit_cstring(env, "/* "); - ia32_emit_irprintf(env, "%+F ", node); - - dbg = get_irn_dbg_info(node); - sourcefile = be_retrieve_dbg_info(dbg, &lineno); - if(sourcefile != NULL) { - ia32_emit_string(env, sourcefile); - ia32_emit_irprintf(env, ":%u", lineno); - } - ia32_emit_cstring(env, " */\n"); - ia32_write_line(env); -} - - /************************************************* * _ _ _ * (_) | | | @@ -746,7 +611,7 @@ static const char *get_cmp_suffix(int cmp_code) void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc) { - ia32_emit_string(env, get_cmp_suffix(pnc)); + be_emit_string(env, get_cmp_suffix(pnc)); } @@ -763,8 +628,8 @@ static ir_node *get_cfop_target_block(const ir_node *irn) { void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) { ir_node *block = get_cfop_target_block(node); - ia32_emit_cstring(env, BLOCK_PREFIX); - ia32_emit_irprintf(env, "%d", get_irn_node_nr(block)); + be_emit_cstring(env, BLOCK_PREFIX); + be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block)); } /** Return the next block in Block schedule */ @@ -830,27 +695,27 @@ static void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, /* in case of unordered compare, check for parity */ if (pnc & pn_Cmp_Uo) { - ia32_emit_cstring(env, "\tjp "); + be_emit_cstring(env, "\tjp "); ia32_emit_cfop_target(env, proj_true); - ia32_emit_finish_line(env, proj_true); + be_emit_finish_line_gas(env, proj_true); } - ia32_emit_cstring(env, "\tj"); + be_emit_cstring(env, "\tj"); ia32_emit_cmp_suffix(env, pnc); - ia32_emit_char(env, ' '); + be_emit_char(env, ' '); ia32_emit_cfop_target(env, proj_true); - ia32_emit_finish_line(env, proj_true); + be_emit_finish_line_gas(env, proj_true); /* the second Proj might be a fallthrough */ if (get_cfop_target_block(proj_false) != next_block) { - ia32_emit_cstring(env, "\tjmp "); + be_emit_cstring(env, "\tjmp "); ia32_emit_cfop_target(env, proj_false); - ia32_emit_finish_line(env, proj_false); + be_emit_finish_line_gas(env, proj_false); } else { - ia32_emit_cstring(env, "\t/* fallthrough to"); + be_emit_cstring(env, "\t/* fallthrough to"); ia32_emit_cfop_target(env, proj_false); - ia32_emit_cstring(env, " */"); - ia32_emit_finish_line(env, proj_false); + be_emit_cstring(env, " */"); + be_emit_finish_line_gas(env, proj_false); } } @@ -858,9 +723,9 @@ static void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, * Emits code for conditional jump. */ static void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "\tcmp "); + be_emit_cstring(env, "\tcmp "); ia32_emit_binop(env, node); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); } @@ -877,17 +742,17 @@ static void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) { */ static void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { if(is_ia32_ImmSymConst(node) || is_ia32_ImmConst(node)) { - ia32_emit_cstring(env, "\ttest $"); + be_emit_cstring(env, "\ttest $"); ia32_emit_immediate(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } else { - ia32_emit_cstring(env, "\ttest "); + be_emit_cstring(env, "\ttest "); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); } @@ -900,15 +765,15 @@ static void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) { } static void emit_ia32_CJmp(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "/* omitted redundant test */"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "/* omitted redundant test */"); + be_emit_finish_line_gas(env, node); finish_CondJmp(env, node, mode_Is, get_ia32_pncode(node)); } static void emit_ia32_CJmpAM(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "/* omitted redundant test/cmp */"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "/* omitted redundant test/cmp */"); + be_emit_finish_line_gas(env, node); finish_CondJmp(env, node, mode_Is, get_ia32_pncode(node)); } @@ -917,11 +782,11 @@ static void emit_ia32_CJmpAM(ia32_emit_env_t *env, const ir_node *node) { * Emits code for conditional SSE floating point jump with two variables. */ static void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "\tucomi"); + be_emit_cstring(env, "\tucomi"); ia32_emit_xmm_mode_suffix(env, node); - ia32_emit_char(env, ' '); + be_emit_char(env, ' '); ia32_emit_binop(env, node); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); finish_CondJmp(env, node, mode_F, get_ia32_pncode(node)); } @@ -940,32 +805,32 @@ static void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) { reg = attr->x87[0]->name; case iro_ia32_fcomJmp: default: - ia32_emit_cstring(env, "\tfucom "); + be_emit_cstring(env, "\tfucom "); break; case iro_ia32_fcomrpJmp: pnc = get_inversed_pnc(pnc); reg = attr->x87[0]->name; case iro_ia32_fcompJmp: - ia32_emit_cstring(env, "\tfucomp "); + be_emit_cstring(env, "\tfucomp "); break; case iro_ia32_fcomrppJmp: pnc = get_inversed_pnc(pnc); case iro_ia32_fcomppJmp: - ia32_emit_cstring(env, "\tfucompp "); + be_emit_cstring(env, "\tfucompp "); reg = ""; break; } if(reg[0] != '\0') { - ia32_emit_char(env, '%'); - ia32_emit_string(env, reg); + be_emit_char(env, '%'); + be_emit_string(env, reg); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); - ia32_emit_cstring(env, "\tfnstsw %ax"); - ia32_emit_finish_line(env, node); - ia32_emit_cstring(env, "\tsahf"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "\tfnstsw %ax"); + be_emit_finish_line_gas(env, node); + be_emit_cstring(env, "\tsahf"); + be_emit_finish_line_gas(env, node); finish_CondJmp(env, node, mode_E, pnc); } @@ -984,27 +849,27 @@ static void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { /* we have to emit the cmp first, because the destination register */ /* could be one of the compare registers */ if (is_ia32_CmpCMov(node)) { - ia32_emit_cstring(env, "\tcmp "); + be_emit_cstring(env, "\tcmp "); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); } else if (is_ia32_xCmpCMov(node)) { - ia32_emit_cstring(env, "\tucomis"); + be_emit_cstring(env, "\tucomis"); ia32_emit_mode_suffix(env, get_irn_mode(node)); - ia32_emit_char(env, ' '); + be_emit_char(env, ' '); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); } else if (is_PsiCondCMov) { /* omit compare because flags are already set by And/Or */ - ia32_emit_cstring(env, "\ttest "); + be_emit_cstring(env, "\ttest "); ia32_emit_source_register(env, node, 0); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); } else { assert(0 && "unsupported CMov"); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); if (REGS_ARE_EQUAL(out, in2)) { /* best case: default in == out -> do nothing */ @@ -1019,35 +884,35 @@ static void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { } else { /* out is different from in: need copy default -> out */ if (is_PsiCondCMov) { - ia32_emit_cstring(env, "\tmovl "); + be_emit_cstring(env, "\tmovl "); ia32_emit_dest_register(env, node, 2); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - ia32_emit_cstring(env, "\tmovl "); + be_emit_cstring(env, "\tmovl "); ia32_emit_source_register(env, node, 3); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } if (is_PsiCondCMov) { - ia32_emit_cstring(env, "\tcmov"); + be_emit_cstring(env, "\tcmov"); ia32_emit_cmp_suffix(env, pnc); - ia32_emit_cstring(env, "l "); + be_emit_cstring(env, "l "); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - ia32_emit_cstring(env, "\tcmov"); + be_emit_cstring(env, "\tcmov"); ia32_emit_cmp_suffix(env, pnc); - ia32_emit_cstring(env, "l "); + be_emit_cstring(env, "l "); ia32_emit_source_register(env, node, 2); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } static void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) { @@ -1071,31 +936,31 @@ static void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode reg8bit = ia32_get_mapped_reg_name(env->isa->regs_8bit, out); if (is_ia32_CmpSet(node)) { - ia32_emit_cstring(env, "\tcmp "); + be_emit_cstring(env, "\tcmp "); ia32_emit_binop(env, node); } else if (is_ia32_xCmpSet(node)) { - ia32_emit_cstring(env, "\tucomis"); + be_emit_cstring(env, "\tucomis"); ia32_emit_mode_suffix(env, get_irn_mode(get_irn_n(node, 2))); - ia32_emit_char(env, ' '); + be_emit_char(env, ' '); ia32_emit_binop(env, node); } else if (is_ia32_PsiCondSet(node)) { - ia32_emit_cstring(env, "\tcmp $0, "); + be_emit_cstring(env, "\tcmp $0, "); ia32_emit_source_register(env, node, 0); } else { assert(0 && "unsupported Set"); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); /* use mov to clear target because it doesn't affect the eflags */ - ia32_emit_cstring(env, "\tmovl $0, %"); - ia32_emit_string(env, arch_register_get_name(out)); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "\tmovl $0, %"); + be_emit_string(env, arch_register_get_name(out)); + be_emit_finish_line_gas(env, node); - ia32_emit_cstring(env, "\tset"); + be_emit_cstring(env, "\tset"); ia32_emit_cmp_suffix(env, pnc); - ia32_emit_cstring(env, " %"); - ia32_emit_string(env, reg8bit); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, " %"); + be_emit_string(env, reg8bit); + be_emit_finish_line_gas(env, node); } static void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) { @@ -1163,31 +1028,31 @@ static void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { - and result and stored result - cleanup stack */ - ia32_emit_cstring(env, "\tsubl $8, %esp"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "\tsubl $8, %esp"); + be_emit_finish_line_gas(env, node); - ia32_emit_cstring(env, "\tcmpsd $3, "); + be_emit_cstring(env, "\tcmpsd $3, "); ia32_emit_binop(env, node); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); - ia32_emit_cstring(env, "\tmovsd "); + be_emit_cstring(env, "\tmovsd "); ia32_emit_dest_register(env, node, 0); - ia32_emit_cstring(env, ", (%esp)"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, ", (%esp)"); + be_emit_finish_line_gas(env, node); } - ia32_emit_cstring(env, "\tcmpsd "); - ia32_emit_irprintf(env, "%d, ", sse_pnc); + be_emit_cstring(env, "\tcmpsd "); + be_emit_irprintf(env->emit, "%d, ", sse_pnc); ia32_emit_binop(env, node); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); if (unord && sse_pnc != 3) { - ia32_emit_cstring(env, "\tandpd (%esp), "); + be_emit_cstring(env, "\tandpd (%esp), "); ia32_emit_dest_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); - ia32_emit_cstring(env, "\taddl $8, %esp"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "\taddl $8, %esp"); + be_emit_finish_line_gas(env, node); } } @@ -1284,53 +1149,53 @@ static void emit_ia32_SwitchJmp(ia32_emit_env_t *env, const ir_node *node) { interval = tbl.max_value - tbl.min_value; /* emit the table */ - ia32_emit_cstring(env, "\tcmpl $"); - ia32_emit_irprintf(env, "%u, ", interval); + be_emit_cstring(env, "\tcmpl $"); + be_emit_irprintf(env->emit, "%u, ", interval); ia32_emit_source_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); - ia32_emit_cstring(env, "\tja "); + be_emit_cstring(env, "\tja "); ia32_emit_cfop_target(env, tbl.defProj); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); if (tbl.num_branches > 1) { /* create table */ - ia32_emit_cstring(env, "\tjmp *"); - ia32_emit_string(env, tbl.label); - ia32_emit_cstring(env, "(,"); + be_emit_cstring(env, "\tjmp *"); + be_emit_string(env, tbl.label); + be_emit_cstring(env, "(,"); ia32_emit_source_register(env, node, 0); - ia32_emit_cstring(env, ",4)"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, ",4)"); + be_emit_finish_line_gas(env, node); - ia32_switch_section(env->out, SECTION_RODATA); - ia32_emit_cstring(env, "\t.align 4\n"); - ia32_write_line(env); + be_gas_emit_switch_section(env->emit, GAS_SECTION_RODATA); + be_emit_cstring(env, "\t.align 4\n"); + be_emit_write_line(env); - ia32_emit_string(env, tbl.label); - ia32_emit_cstring(env, ":\n"); - ia32_write_line(env); + be_emit_string(env, tbl.label); + be_emit_cstring(env, ":\n"); + be_emit_write_line(env); - ia32_emit_cstring(env, ".long "); + be_emit_cstring(env, ".long "); ia32_emit_cfop_target(env, tbl.branches[0].target); - ia32_emit_finish_line(env, NULL); + be_emit_finish_line_gas(env, NULL); last_value = tbl.branches[0].value; for (i = 1; i < tbl.num_branches; ++i) { while (++last_value < tbl.branches[i].value) { - ia32_emit_cstring(env, ".long "); + be_emit_cstring(env, ".long "); ia32_emit_cfop_target(env, tbl.defProj); - ia32_emit_finish_line(env, NULL); + be_emit_finish_line_gas(env, NULL); } - ia32_emit_cstring(env, ".long "); + be_emit_cstring(env, ".long "); ia32_emit_cfop_target(env, tbl.branches[i].target); - ia32_emit_finish_line(env, NULL); + be_emit_finish_line_gas(env, NULL); } - ia32_switch_section(env->out, SECTION_TEXT); + be_gas_emit_switch_section(env->emit, GAS_SECTION_TEXT); } else { /* one jump is enough */ - ia32_emit_cstring(env, "\tjmp "); + be_emit_cstring(env, "\tjmp "); ia32_emit_cfop_target(env, tbl.branches[0].target); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } if (tbl.label) @@ -1351,14 +1216,14 @@ static void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) { /* we have a block schedule */ next_block = next_blk_sched(block); if (get_cfop_target_block(node) != next_block) { - ia32_emit_cstring(env, "\tjmp "); + be_emit_cstring(env, "\tjmp "); ia32_emit_cfop_target(env, node); } else { - ia32_emit_cstring(env, "\t/* fallthrough to "); + be_emit_cstring(env, "\t/* fallthrough to "); ia32_emit_cfop_target(env, node); - ia32_emit_cstring(env, " */"); + be_emit_cstring(env, " */"); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } /********************************** @@ -1376,23 +1241,23 @@ static void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) { * Emit movsb/w instructions to make mov count divideable by 4 */ static void emit_CopyB_prolog(ia32_emit_env_t *env, int rem) { - ia32_emit_cstring(env, "\tcld"); - ia32_emit_finish_line(env, NULL); + be_emit_cstring(env, "\tcld"); + be_emit_finish_line_gas(env, NULL); switch(rem) { case 1: - ia32_emit_cstring(env, "\tmovsb"); - ia32_emit_finish_line(env, NULL); + be_emit_cstring(env, "\tmovsb"); + be_emit_finish_line_gas(env, NULL); break; case 2: - ia32_emit_cstring(env, "\tmovsw"); - ia32_emit_finish_line(env, NULL); + be_emit_cstring(env, "\tmovsw"); + be_emit_finish_line_gas(env, NULL); break; case 3: - ia32_emit_cstring(env, "\tmovsb"); - ia32_emit_finish_line(env, NULL); - ia32_emit_cstring(env, "\tmovsw"); - ia32_emit_finish_line(env, NULL); + be_emit_cstring(env, "\tmovsb"); + be_emit_finish_line_gas(env, NULL); + be_emit_cstring(env, "\tmovsw"); + be_emit_finish_line_gas(env, NULL); break; } } @@ -1406,8 +1271,8 @@ static void emit_ia32_CopyB(ia32_emit_env_t *env, const ir_node *node) { emit_CopyB_prolog(env, rem); - ia32_emit_cstring(env, "\trep movsd"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "\trep movsd"); + be_emit_finish_line_gas(env, node); } /** @@ -1421,8 +1286,8 @@ static void emit_ia32_CopyB_i(ia32_emit_env_t *env, const ir_node *node) { size >>= 2; while (size--) { - ia32_emit_cstring(env, "\tmovsd"); - ia32_emit_finish_line(env, NULL); + be_emit_cstring(env, "\tmovsd"); + be_emit_finish_line_gas(env, NULL); } } @@ -1445,45 +1310,45 @@ static void emit_ia32_Conv_with_FP(ia32_emit_env_t *env, const ir_node *node) { ir_mode *ls_mode = get_ia32_ls_mode(node); int ls_bits = get_mode_size_bits(ls_mode); - ia32_emit_cstring(env, "\tcvt"); + be_emit_cstring(env, "\tcvt"); if(is_ia32_Conv_I2FP(node)) { if(ls_bits == 32) { - ia32_emit_cstring(env, "si2ss"); + be_emit_cstring(env, "si2ss"); } else { - ia32_emit_cstring(env, "si2sd"); + be_emit_cstring(env, "si2sd"); } } else if(is_ia32_Conv_FP2I(node)) { if(ls_bits == 32) { - ia32_emit_cstring(env, "ss2si"); + be_emit_cstring(env, "ss2si"); } else { - ia32_emit_cstring(env, "sd2si"); + be_emit_cstring(env, "sd2si"); } } else { assert(is_ia32_Conv_FP2FP(node)); if(ls_bits == 32) { - ia32_emit_cstring(env, "sd2ss"); + be_emit_cstring(env, "sd2ss"); } else { - ia32_emit_cstring(env, "ss2sd"); + be_emit_cstring(env, "ss2sd"); } } - ia32_emit_char(env, ' '); + be_emit_char(env, ' '); switch(get_ia32_op_type(node)) { case ia32_Normal: ia32_emit_source_register(env, node, 2); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); break; case ia32_AddrModeS: ia32_emit_dest_register(env, node, 0); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_am(env, node); break; default: assert(0 && "unsupported op type for Conv"); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } static void emit_ia32_Conv_I2FP(ia32_emit_env_t *env, const ir_node *node) { @@ -1532,9 +1397,9 @@ static void emit_ia32_Conv_I2I(ia32_emit_env_t *env, const ir_node *node) { /* argument and result are both in EAX and */ /* signedness is ok: -> use converts */ if (smaller_bits == 8) { - ia32_emit_cstring(env, "\tcbtw"); + be_emit_cstring(env, "\tcbtw"); } else if (smaller_bits == 16) { - ia32_emit_cstring(env, "\tcwtl"); + be_emit_cstring(env, "\tcwtl"); } else { assert(0); } @@ -1542,35 +1407,35 @@ static void emit_ia32_Conv_I2I(ia32_emit_env_t *env, const ir_node *node) { /* argument and result are in the same register */ /* and signedness is ok: -> use and with mask */ int mask = (1 << smaller_bits) - 1; - ia32_emit_cstring(env, "\tandl $0x"); - ia32_emit_irprintf(env, "%x, ", mask); + be_emit_cstring(env, "\tandl $0x"); + be_emit_irprintf(env->emit, "%x, ", mask); ia32_emit_dest_register(env, node, 0); } else { const char *sreg = ia32_get_reg_name_for_mode(env, smaller_mode, in_reg); - ia32_emit_cstring(env, "\tmov"); - ia32_emit_string(env, sign_suffix); + be_emit_cstring(env, "\tmov"); + be_emit_string(env, sign_suffix); ia32_emit_mode_suffix(env, smaller_mode); - ia32_emit_cstring(env, "l %"); - ia32_emit_string(env, sreg); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, "l %"); + be_emit_string(env, sreg); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } break; case ia32_AddrModeS: { - ia32_emit_cstring(env, "\tmov"); - ia32_emit_string(env, sign_suffix); + be_emit_cstring(env, "\tmov"); + be_emit_string(env, sign_suffix); ia32_emit_mode_suffix(env, smaller_mode); - ia32_emit_cstring(env, "l %"); + be_emit_cstring(env, "l %"); ia32_emit_am(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); break; } default: assert(0 && "unsupported op type for Conv"); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } /** @@ -1597,14 +1462,14 @@ void emit_ia32_Conv_I2I8Bit(ia32_emit_env_t *env, const ir_node *node) { static void emit_be_Call(ia32_emit_env_t *env, const ir_node *node) { ir_entity *ent = be_Call_get_entity(node); - ia32_emit_cstring(env, "\tcall "); + be_emit_cstring(env, "\tcall "); if (ent) { - ia32_emit_string(env, get_entity_ld_name(ent)); + be_emit_string(env, get_entity_ld_name(ent)); } else { - ia32_emit_char(env, '*'); + be_emit_char(env, '*'); ia32_emit_dest_register(env, get_irn_n(node, be_pos_Call_ptr), 0); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } /** @@ -1617,26 +1482,26 @@ static void emit_be_IncSP(ia32_emit_env_t *env, const ir_node *node) { return; if (offs > 0) { - ia32_emit_cstring(env, "\tsubl $"); - ia32_emit_irprintf(env, "%u, ", offs); + be_emit_cstring(env, "\tsubl $"); + be_emit_irprintf(env->emit, "%u, ", offs); ia32_emit_source_register(env, node, 0); } else { - ia32_emit_cstring(env, "\taddl $"); - ia32_emit_irprintf(env, "%u, ", -offs); + be_emit_cstring(env, "\taddl $"); + be_emit_irprintf(env->emit, "%u, ", -offs); ia32_emit_source_register(env, node, 0); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } /** * Emits code to set stack pointer. */ static void emit_be_SetSP(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "\tmovl "); + be_emit_cstring(env, "\tmovl "); ia32_emit_source_register(env, node, 2); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } /** @@ -1650,17 +1515,17 @@ static void Copy_emitter(ia32_emit_env_t *env, const ir_node *node, const ir_nod return; if (mode_is_float(get_irn_mode(node))) { - ia32_emit_cstring(env, "\tmovsd "); + be_emit_cstring(env, "\tmovsd "); ia32_emit_source_register(env, node, 0); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - ia32_emit_cstring(env, "\tmovl "); + be_emit_cstring(env, "\tmovl "); ia32_emit_source_register(env, node, 0); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } static void emit_be_Copy(ia32_emit_env_t *env, const ir_node *node) { @@ -1699,32 +1564,32 @@ static void emit_be_Perm(ia32_emit_env_t *env, const ir_node *node) { lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %1S, %2S", irn, irn); } else { #endif - ia32_emit_cstring(env, "\txchg "); + be_emit_cstring(env, "\txchg "); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); #if 0 } #endif } else if (cls1 == &ia32_reg_classes[CLASS_ia32_xmm]) { - ia32_emit_cstring(env, "\txorpd "); + be_emit_cstring(env, "\txorpd "); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); - ia32_emit_finish_line(env, NULL); + be_emit_finish_line_gas(env, NULL); - ia32_emit_cstring(env, "\txorpd "); + be_emit_cstring(env, "\txorpd "); ia32_emit_source_register(env, node, 0); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 1); - ia32_emit_finish_line(env, NULL); + be_emit_finish_line_gas(env, NULL); - ia32_emit_cstring(env, "\txorpd "); + be_emit_cstring(env, "\txorpd "); ia32_emit_source_register(env, node, 1); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } else if (cls1 == &ia32_reg_classes[CLASS_ia32_vfp]) { /* is a NOP */ } else if (cls1 == &ia32_reg_classes[CLASS_ia32_st]) { @@ -1740,9 +1605,9 @@ static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { ia32_immop_type_t imm_tp = get_ia32_immop_type(node); if (imm_tp == ia32_ImmSymConst) { - ia32_emit_cstring(env, "\tmovl $"); + be_emit_cstring(env, "\tmovl $"); ia32_emit_immediate(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { tarval *tv = get_ia32_Immop_tarval(node); @@ -1751,35 +1616,35 @@ static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { if (tarval_is_null(tv)) { if (env->isa->opt_arch == arch_pentium_4) { /* P4 prefers sub r, r, others xor r, r */ - ia32_emit_cstring(env, "\tsubl "); + be_emit_cstring(env, "\tsubl "); } else { - ia32_emit_cstring(env, "\txorl "); + be_emit_cstring(env, "\txorl "); } ia32_emit_dest_register(env, node, 0); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - ia32_emit_cstring(env, "\tmovl $"); + be_emit_cstring(env, "\tmovl $"); ia32_emit_immediate(env, node); - ia32_emit_cstring(env, ", "); + be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } } - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } /** * Emits code to load the TLS base */ static void emit_ia32_LdTls(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "\tmovl %gs:0, "); + be_emit_cstring(env, "\tmovl %gs:0, "); ia32_emit_dest_register(env, node, 0); - ia32_emit_finish_line(env, node); + be_emit_finish_line_gas(env, node); } static void emit_be_Return(ia32_emit_env_t *env, const ir_node *node) { - ia32_emit_cstring(env, "\tret"); - ia32_emit_finish_line(env, node); + be_emit_cstring(env, "\tret"); + be_emit_finish_line_gas(env, node); } static void emit_Nothing(ia32_emit_env_t *env, const ir_node *node) { @@ -1894,12 +1759,13 @@ static void ia32_emit_dbg(ia32_emit_env_t *env, const ir_node *node) { } if (last_line != lineno) { char name[64]; - FILE *F = env->out; snprintf(name, sizeof(name), ".LM%u", ++num); last_line = lineno; be_dbg_line(env->cg->birg->main_env->db_handle, lineno, name); - fprintf(F, "%s:\n", name); + be_emit_string(env, name); + be_emit_cstring(env, ":\n"); + be_emit_write_line(env); } } } @@ -1929,9 +1795,9 @@ static void ia32_emit_node(ia32_emit_env_t *env, const ir_node *node) { * Emits gas alignment directives */ static void ia32_emit_alignment(ia32_emit_env_t *env, unsigned align, unsigned skip) { - ia32_emit_cstring(env, "\t.p2align "); - ia32_emit_irprintf(env, "%u,,%u\n", align, skip); - ia32_write_line(env); + be_emit_cstring(env, "\t.p2align "); + be_emit_irprintf(env->emit, "%u,,%u\n", align, skip); + be_emit_write_line(env); } /** @@ -2073,23 +1939,23 @@ static void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_b if (align) ia32_emit_align_label(env, env->isa->opt_arch); - ia32_emit_cstring(env, BLOCK_PREFIX); - ia32_emit_irprintf(env, "%d:", get_irn_node_nr(block)); - ia32_pad_comment(env); - ia32_emit_cstring(env, " /* preds:"); + be_emit_cstring(env, BLOCK_PREFIX); + be_emit_irprintf(env->emit, "%d:", get_irn_node_nr(block)); + be_emit_pad_comment(env); + be_emit_cstring(env, " /* preds:"); /* emit list of pred blocks in comment */ arity = get_irn_arity(block); for (i = 0; i < arity; ++i) { ir_node *predblock = get_Block_cfgpred_block(block, i); - ia32_emit_irprintf(env, " %d", get_irn_node_nr(predblock)); + be_emit_irprintf(env->emit, " %d", get_irn_node_nr(predblock)); } if (exec_freq != NULL) { - ia32_emit_irprintf(env, " freq: %f", get_block_execfreq(exec_freq, block)); + be_emit_irprintf(env->emit, " freq: %f", get_block_execfreq(exec_freq, block)); } - ia32_emit_cstring(env, " */\n"); - ia32_write_line(env); + be_emit_cstring(env, " */\n"); + be_emit_write_line(env); } /* emit the contents of the block */ @@ -2103,21 +1969,25 @@ static void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_b * Emits code for function start. */ static void ia32_emit_func_prolog(ia32_emit_env_t *env, ir_graph *irg) { - FILE *F = env->out; ir_entity *irg_ent = get_irg_entity(irg); const char *irg_name = get_entity_ld_name(irg_ent); cpu_support cpu = env->isa->opt_arch; const be_irg_t *birg = env->cg->birg; - fprintf(F, "\n"); - ia32_switch_section(F, SECTION_TEXT); + be_emit_write_line(env); + be_gas_emit_switch_section(env->emit, GAS_SECTION_TEXT); be_dbg_method_begin(birg->main_env->db_handle, irg_ent, be_abi_get_stack_layout(birg->abi)); ia32_emit_align_func(env, cpu); if (get_entity_visibility(irg_ent) == visibility_external_visible) { - fprintf(F, ".globl %s\n", irg_name); + be_emit_cstring(env, ".global "); + be_emit_string(env, irg_name); + be_emit_char(env, '\n'); + be_emit_write_line(env); } - ia32_dump_function_object(F, irg_name); - fprintf(F, "%s:\n", irg_name); + ia32_emit_function_object(env, irg_name); + be_emit_string(env, irg_name); + be_emit_cstring(env, ":\n"); + be_emit_write_line(env); } /** @@ -2126,11 +1996,11 @@ static void ia32_emit_func_prolog(ia32_emit_env_t *env, ir_graph *irg) { static void ia32_emit_func_epilog(ia32_emit_env_t *env, ir_graph *irg) { const char *irg_name = get_entity_ld_name(get_irg_entity(irg)); const be_irg_t *birg = env->cg->birg; - FILE *F = env->out; - ia32_dump_function_size(F, irg_name); + ia32_emit_function_size(env, irg_name); be_dbg_method_end(birg->main_env->db_handle); - fprintf(F, "\n"); + be_emit_char(env, '\n'); + be_emit_write_line(env); } /** @@ -2150,21 +2020,16 @@ static void ia32_gen_labels(ir_node *block, void *data) { /** * Main driver. Emits the code for one routine. */ -void ia32_gen_routine(ia32_code_gen_t *cg, FILE *F, ir_graph *irg) { +void ia32_gen_routine(ia32_code_gen_t *cg, ir_graph *irg) { ia32_emit_env_t env; ir_node *block; ir_node *last_block = NULL; int i, n; - struct obstack obst; - obstack_init(&obst); - - env.out = F; + env.isa = (ia32_isa_t *)cg->arch_env->isa; + env.emit = &env.isa->emit; env.arch_env = cg->arch_env; env.cg = cg; - env.isa = (ia32_isa_t *)cg->arch_env->isa; - env.obst = &obst; - env.linelength = 0; FIRM_DBG_REGISTER(env.mod, "firm.be.ia32.emitter"); /* set the global arch_env (needed by print hooks) */ diff --git a/ir/be/ia32/ia32_emitter.h b/ir/be/ia32/ia32_emitter.h index 1d2fcc0d2..04761b152 100644 --- a/ir/be/ia32/ia32_emitter.h +++ b/ir/be/ia32/ia32_emitter.h @@ -11,39 +11,18 @@ #include "debug.h" #include "../bearch.h" +#include "../beemitter.h" #include "bearch_ia32_t.h" -typedef struct _ia32_emit_env_t { - FILE *out; +typedef struct ia32_emit_env_t { + be_emit_env_t *emit; const arch_env_t *arch_env; const ia32_code_gen_t *cg; ia32_isa_t *isa; - struct obstack *obst; - int linelength; DEBUG_ONLY(firm_dbg_module_t *mod;) } ia32_emit_env_t; -static INLINE void ia32_emit_char(ia32_emit_env_t *env, char c) -{ - obstack_1grow(env->obst, c); - env->linelength++; -} - -static INLINE void ia32_emit_string_len(ia32_emit_env_t *env, const char *str, size_t l) -{ - obstack_grow(env->obst, str, l); - env->linelength += l; -} - -static INLINE void ia32_emit_string(ia32_emit_env_t *env, const char *str) -{ - size_t len = strlen(str); - ia32_emit_string_len(env, str, len); -} - -#define ia32_emit_cstring(env,x) { ia32_emit_string_len(env, x, sizeof(x)-1); } - void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_dest_register(ia32_emit_env_t *env, const ir_node *node, int pos); void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos); @@ -58,35 +37,7 @@ void ia32_emit_unop(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_am(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_adr(ia32_emit_env_t *env, const ir_node *node); void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node); -void ia32_emit_finish_line(ia32_emit_env_t *env, const ir_node *node); - -void ia32_gen_routine(ia32_code_gen_t *cg, FILE *F, ir_graph *irg); - -/** - * Sections. - */ -typedef enum section_t { - NO_SECTION = -1, /**< no section selected yet. */ - SECTION_TEXT = 0, /**< text section */ - SECTION_DATA = 1, /**< data section */ - SECTION_RODATA = 2, /**< rodata section */ - SECTION_COMMON = 3, /**< common section */ - SECTION_TLS = 4, /**< thread local storage section */ - SECTION_CTOR = 5, /**< ctor section for instrumentation code init */ - SECTION_MAX = 6 -} section_t; - -/** - * Switch to a new section. - */ -void ia32_switch_section(FILE *f, section_t sec); - -typedef enum asm_flavour_t { - ASM_LINUX_GAS = 0, /**< Linux gas */ - ASM_MINGW_GAS = 1, /**< MinGW gas */ - ASM_MAX = 2 -} asm_flavour_t; -extern asm_flavour_t asm_flavour; +void ia32_gen_routine(ia32_code_gen_t *cg, ir_graph *irg); #endif /* _IA32_EMITTER_H_ */ diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index 0eb6d1dda..7d36472bd 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -243,7 +243,7 @@ static INLINE int need_constraint_copy(ir_node *irn) { */ static void ia32_finish_node(ir_node *irn, void *env) { ia32_code_gen_t *cg = env; - const ia32_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t *out_reg, *in_reg, *in2_reg; int n_res, i; ir_node *copy, *in_node, *block, *in2_node; @@ -263,10 +263,12 @@ static void ia32_finish_node(ir_node *irn, void *env) { if ((op_tp == ia32_Normal || op_tp == ia32_AddrModeS) && need_constraint_copy(irn)) { for (i = 0; i < n_res; i++) { - if (arch_register_req_is(&(reqs[i]->req), should_be_same)) { + if (arch_register_req_is(reqs[i], should_be_same)) { + int same_pos = reqs[i]->other_same; + /* get in and out register */ out_reg = get_ia32_out_reg(irn, i); - in_node = get_irn_n(irn, reqs[i]->same_pos); + in_node = get_irn_n(irn, same_pos); in_reg = arch_get_irn_register(cg->arch_env, in_node); /* don't copy ignore nodes */ @@ -279,19 +281,19 @@ static void ia32_finish_node(ir_node *irn, void *env) { /* beware: the current op could be everything, so test for ia32 */ /* commutativity first before getting the second in */ if (is_ia32_commutative(irn)) { - in2_node = get_irn_n(irn, reqs[i]->same_pos ^ 1); + in2_node = get_irn_n(irn, same_pos ^ 1); in2_reg = arch_get_irn_register(cg->arch_env, in2_node); if (REGS_ARE_EQUAL(out_reg, in2_reg)) { - set_irn_n(irn, reqs[i]->same_pos, in2_node); - set_irn_n(irn, reqs[i]->same_pos ^ 1, in_node); + set_irn_n(irn, same_pos, in2_node); + set_irn_n(irn, same_pos ^ 1, in_node); } else goto insert_copy; } else { insert_copy: - DBG((cg->mod, LEVEL_1, "inserting copy for %+F in_pos %d\n", irn, reqs[i]->same_pos)); + DBG((cg->mod, LEVEL_1, "inserting copy for %+F in_pos %d\n", irn, same_pos)); /* create copy from in register */ copy = be_new_Copy(arch_register_get_class(in_reg), cg->irg, block, in_node); @@ -304,7 +306,7 @@ insert_copy: sched_add_before(irn, copy); /* set copy as in */ - set_irn_n(irn, reqs[i]->same_pos, copy); + set_irn_n(irn, same_pos, copy); } } } @@ -334,22 +336,6 @@ insert_copy: set_ia32_pncode(irn, get_negated_pnc(pnc, mode_E)); } } - - /* - If we have a CondJmp/CmpSet/xCmpSet with immediate, - we need to check if it's the right operand, otherwise - we have to change it, as CMP doesn't support immediate - as left operands. - */ -#if 0 - if ((is_ia32_CondJmp(irn) || is_ia32_CmpSet(irn) || is_ia32_xCmpSet(irn)) && - (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn)) && - op_tp == ia32_AddrModeS) - { - set_ia32_op_type(irn, ia32_AddrModeD); - set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn))); - } -#endif } end: ; } @@ -366,7 +352,7 @@ static void fix_am_source(ir_node *irn, void *env) { ia32_code_gen_t *cg = env; ir_node *base, *index, *noreg; const arch_register_t *reg_base, *reg_index; - const ia32_register_req_t **reqs; + const arch_register_req_t **reqs; int n_res, i; /* check only ia32 nodes with source address mode */ @@ -388,15 +374,16 @@ static void fix_am_source(ir_node *irn, void *env) { n_res = get_ia32_n_res(irn); for (i = 0; i < n_res; i++) { - if (arch_register_req_is(&(reqs[i]->req), should_be_same)) { + if (arch_register_req_is(reqs[i], should_be_same)) { /* get in and out register */ const arch_register_t *out_reg = get_ia32_out_reg(irn, i); + int same_pos = reqs[i]->other_same; /* there is a constraint for the remaining operand and the result register is equal to base or index register */ - if (reqs[i]->same_pos == 2 && + if (same_pos == 2 && (REGS_ARE_EQUAL(out_reg, reg_base) || REGS_ARE_EQUAL(out_reg, reg_index))) { /* turn back address mode */ diff --git a/ir/be/ia32/ia32_gen_decls.h b/ir/be/ia32/ia32_gen_decls.h deleted file mode 100644 index 88a596002..000000000 --- a/ir/be/ia32/ia32_gen_decls.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Header for ia32 assembler declarations dumper. - * @author Christian Wuerdig - * $Id$ - */ - -#ifndef _IA32_GEN_DECLS_H_ -#define _IA32_GEN_DECLS_H_ - -#include "../be.h" - -/** - * Generate all entities. - */ -void ia32_gen_decls(FILE *out, const be_main_env_t *main_env); - -#endif /* _IA32_GEN_DECLS_H_ */ diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 3c7db4071..fb614d999 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -4,9 +4,8 @@ * @author Christian Wuerdig * $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #ifdef HAVE_MALLOC_H @@ -31,6 +30,7 @@ #include "irprintf.h" #include "iredges.h" #include "error.h" +#include "raw_bitset.h" #include "../bearch.h" @@ -96,69 +96,41 @@ int ia32_has_x87_register(const ir_node *n) { * |_| ***********************************************************************************/ -/** - * Returns a string containing the names of all registers within the limited bitset - */ -static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) { - bitset_t *bs = bitset_alloca(req->cls->n_regs); - char *p = buf; - int size = 0; - int i, cnt; - - req->limited(NULL, bs); - - for (i = 0; i < req->cls->n_regs; i++) { - if (bitset_is_set(bs, i)) { - cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name); - if (cnt < 0) { - fprintf(stderr, "dumper problem, exiting\n"); - exit(1); - } - - p += cnt; - size += cnt; - - if (size >= max) - break; - } - } - - return buf; -} - /** * Dumps the register requirements for either in or out. */ -static void dump_reg_req(FILE *F, ir_node *n, const ia32_register_req_t **reqs, int inout) { +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); - char *buf = alloca(1024); + char buf[1024]; int i; - memset(buf, 0, 1024); + memset(buf, 0, sizeof(buf)); if (reqs) { for (i = 0; i < max; i++) { fprintf(F, "%sreq #%d =", dir, i); - if (reqs[i]->req.type == arch_register_req_type_none) { + if (reqs[i]->type == arch_register_req_type_none) { fprintf(F, " n/a"); } - if (reqs[i]->req.type & arch_register_req_type_normal) { - fprintf(F, " %s", reqs[i]->req.cls->name); + if (reqs[i]->type & arch_register_req_type_normal) { + fprintf(F, " %s", reqs[i]->cls->name); } - if (reqs[i]->req.type & arch_register_req_type_limited) { - fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024)); + if (reqs[i]->type & arch_register_req_type_limited) { + fprintf(F, " %s", + arch_register_req_format(buf, sizeof(buf), reqs[i], n)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_same) { - ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_same) { + ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->other_same)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_different) { - ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_different) { + ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->other_different)); } fprintf(F, "\n"); @@ -182,7 +154,7 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { ir_mode *mode = NULL; int bad = 0; int i, n_res, am_flav, flags; - const ia32_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t **slots; switch (reason) { @@ -794,7 +766,7 @@ void set_ia32_latency(ir_node *node, unsigned latency) { /** * Returns the argument register requirements of an ia32 node. */ -const ia32_register_req_t **get_ia32_in_req_all(const ir_node *node) { +const arch_register_req_t **get_ia32_in_req_all(const ir_node *node) { ia32_attr_t *attr = get_ia32_attr(node); return attr->in_req; } @@ -802,7 +774,7 @@ const ia32_register_req_t **get_ia32_in_req_all(const ir_node *node) { /** * Sets the argument register requirements of an ia32 node. */ -void set_ia32_in_req_all(ir_node *node, const ia32_register_req_t **reqs) { +void set_ia32_in_req_all(ir_node *node, const arch_register_req_t **reqs) { ia32_attr_t *attr = get_ia32_attr(node); attr->in_req = reqs; } @@ -810,7 +782,7 @@ void set_ia32_in_req_all(ir_node *node, const ia32_register_req_t **reqs) { /** * Returns the result register requirements of an ia32 node. */ -const ia32_register_req_t **get_ia32_out_req_all(const ir_node *node) { +const arch_register_req_t **get_ia32_out_req_all(const ir_node *node) { ia32_attr_t *attr = get_ia32_attr(node); return attr->out_req; } @@ -818,7 +790,7 @@ const ia32_register_req_t **get_ia32_out_req_all(const ir_node *node) { /** * Sets the result register requirements of an ia32 node. */ -void set_ia32_out_req_all(ir_node *node, const ia32_register_req_t **reqs) { +void set_ia32_out_req_all(ir_node *node, const arch_register_req_t **reqs) { ia32_attr_t *attr = get_ia32_attr(node); attr->out_req = reqs; } @@ -826,23 +798,29 @@ void set_ia32_out_req_all(ir_node *node, const ia32_register_req_t **reqs) { /** * Returns the argument register requirement at position pos of an ia32 node. */ -const ia32_register_req_t *get_ia32_in_req(const ir_node *node, int pos) { +const arch_register_req_t *get_ia32_in_req(const ir_node *node, int pos) { ia32_attr_t *attr = get_ia32_attr(node); - return attr->in_req != NULL ? attr->in_req[pos] : NULL; + if(attr->in_req == NULL) + return arch_no_register_req; + + return attr->in_req[pos]; } /** * Returns the result register requirement at position pos of an ia32 node. */ -const ia32_register_req_t *get_ia32_out_req(const ir_node *node, int pos) { +const arch_register_req_t *get_ia32_out_req(const ir_node *node, int pos) { ia32_attr_t *attr = get_ia32_attr(node); - return attr->out_req != NULL ? attr->out_req[pos] : NULL; + if(attr->out_req == NULL) + return arch_no_register_req; + + return attr->out_req[pos]; } /** * Sets the OUT register requirements at position pos. */ -void set_ia32_req_out(ir_node *node, const ia32_register_req_t *req, int pos) { +void set_ia32_req_out(ir_node *node, const arch_register_req_t *req, int pos) { ia32_attr_t *attr = get_ia32_attr(node); attr->out_req[pos] = req; } @@ -850,7 +828,7 @@ void set_ia32_req_out(ir_node *node, const ia32_register_req_t *req, int pos) { /** * Sets the IN register requirements at position pos. */ -void set_ia32_req_in(ir_node *node, const ia32_register_req_t *req, int pos) { +void set_ia32_req_in(ir_node *node, const arch_register_req_t *req, int pos) { ia32_attr_t *attr = get_ia32_attr(node); attr->in_req[pos] = req; } @@ -1151,9 +1129,11 @@ const arch_register_t *get_ia32_out_reg(const ir_node *node, int pos) { /** * Initializes the nodes attributes. */ -void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, const ia32_register_req_t **in_reqs, - const ia32_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, - int n_res, unsigned latency) +void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, + const arch_register_req_t **in_reqs, + const arch_register_req_t **out_reqs, + const be_execution_unit_t ***execution_units, + int n_res, unsigned latency) { ia32_attr_t *attr = get_ia32_attr(node); diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index 736e3e9a8..b4eed64a0 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -236,42 +236,42 @@ void set_ia32_frame_ent(ir_node *node, ir_entity *ent); /** * Returns the argument register requirements of an ia32 node. */ -const ia32_register_req_t **get_ia32_in_req_all(const ir_node *node); +const arch_register_req_t **get_ia32_in_req_all(const ir_node *node); /** * Sets the argument register requirements of an ia32 node. */ -void set_ia32_in_req_all(ir_node *node, const ia32_register_req_t **reqs); +void set_ia32_in_req_all(ir_node *node, const arch_register_req_t **reqs); /** * Returns the result register requirements of an ia32 node. */ -const ia32_register_req_t **get_ia32_out_req_all(const ir_node *node); +const arch_register_req_t **get_ia32_out_req_all(const ir_node *node); /** * Sets the result register requirements of an ia32 node. */ -void set_ia32_out_req_all(ir_node *node, const ia32_register_req_t **reqs); +void set_ia32_out_req_all(ir_node *node, const arch_register_req_t **reqs); /** * Returns the argument register requirements of an ia32 node. */ -const ia32_register_req_t *get_ia32_in_req(const ir_node *node, int pos); +const arch_register_req_t *get_ia32_in_req(const ir_node *node, int pos); /** * Returns the result register requirements of an ia32 node. */ -const ia32_register_req_t *get_ia32_out_req(const ir_node *node, int pos); +const arch_register_req_t *get_ia32_out_req(const ir_node *node, int pos); /** * Sets the OUT register requirements at position pos. */ -void set_ia32_req_out(ir_node *node, const ia32_register_req_t *req, int pos); +void set_ia32_req_out(ir_node *node, const arch_register_req_t *req, int pos); /** * Sets the IN register requirements at position pos. */ -void set_ia32_req_in(ir_node *node, const ia32_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. @@ -453,8 +453,11 @@ int is_ia32_Cnst(const ir_node *node); /** * Initializes the nodes attributes. */ -void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, const ia32_register_req_t **in_reqs, \ - const ia32_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency); +void init_ia32_attributes(ir_node *node, arch_irn_flags_t flags, + const arch_register_req_t **in_reqs, + const arch_register_req_t **out_reqs, + const be_execution_unit_t ***execution_units, + int n_res, unsigned latency); /** * Registers the ia32_copy_attr function for all ia32 opcodes. diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index f5d1de534..d8ec99621 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -65,12 +65,6 @@ typedef enum { ia32_am_OBIS = ia32_O | ia32_B | ia32_I | ia32_S } ia32_am_flavour_t; -typedef struct _ia32_register_req_t { - const arch_register_req_t req; - int same_pos; /**< in case of "should be same" we need to remember the pos to get the irn */ - int different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */ -} ia32_register_req_t; - enum { ia32_pn_Cmp_Unsigned = 0x100 /**< set this flag in a pnc to indicate an unsigned compare operation */ }; @@ -127,8 +121,8 @@ typedef struct _ia32_attr_t { const be_execution_unit_t ***exec_units; /**< list of units this operation can be executed on */ - const ia32_register_req_t **in_req; /**< register requirements for arguments */ - const ia32_register_req_t **out_req; /**< register requirements for results */ + 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 *x87[3]; /**< register slots for x87 register */ diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 8ca4d41a6..9830a7bd1 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -128,7 +128,7 @@ $arch = "ia32"; { "name" => "xmm7", "type" => 1 }, { "name" => "xmm_NOREG", "type" => 4 | 16 }, # we need a dummy register for NoReg nodes { "name" => "xmm_UKNWN", "type" => 4 | 8 | 16}, # we need a dummy register for Unknown nodes - { "mode" => "mode_LLu" } + { "mode" => "mode_E" } ], "vfp" => [ { "name" => "vf0", "type" => 1 | 16 }, @@ -198,7 +198,7 @@ $arch = "ia32"; "C" => "${arch}_emit_immediate(env, node);", "SE" => "${arch}_emit_extend_suffix(env, get_ia32_ls_mode(node));", "ME" => "if(get_mode_size_bits(get_ia32_ls_mode(node)) != 32)\n - ${arch}_emit_mode_suffix(env, get_ia32_ls_mode(node));", + ia32_emit_mode_suffix(env, get_ia32_ls_mode(node));", "M" => "${arch}_emit_mode_suffix(env, get_ia32_ls_mode(node));", "XM" => "${arch}_emit_x87_mode_suffix(env, node);", "XXM" => "${arch}_emit_xmm_mode_suffix(env, node);", @@ -835,7 +835,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) { "op_flags" => "L|F", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ] }, + "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "none" ] }, "emit" => '. mov%M %binop', "latency" => 3, "units" => [ "GP" ], @@ -846,7 +846,7 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) { "op_flags" => "L|F", "state" => "exc_pinned", "comment" => "construct 8Bit Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ] }, + "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ], "out" => ["none" ] }, "emit" => '. mov%M %binop', "latency" => 3, "units" => [ "GP" ], @@ -1951,5 +1951,4 @@ if (get_ia32_immop_type(node) == ia32_ImmNone) { ); # end of %nodes # Include the generated SIMD node specification written by the SIMD optimization - -do "../ir/be/ia32/ia32_simd_spec.pl"; +#do "../ir/be/ia32/ia32_simd_spec.pl"; diff --git a/ir/be/mips/bearch_mips.c b/ir/be/mips/bearch_mips.c index 727603f51..91ae7e55a 100644 --- a/ir/be/mips/bearch_mips.c +++ b/ir/be/mips/bearch_mips.c @@ -55,101 +55,54 @@ static set *cur_reg_set = NULL; * |___/ **************************************************/ -static ir_node *my_skip_proj(const ir_node *n) { - while (is_Proj(n)) - n = get_Proj_pred(n); - return (ir_node *)n; -} - /** * Return register requirements for a mips node. * If the node returns a tuple (mode_T) then the proj's * will be asked for this information. */ -static const arch_register_req_t *mips_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) { - const mips_register_req_t *irn_req; +static const +arch_register_req_t *mips_get_irn_reg_req(const void *self, + const ir_node *node, int pos) { long node_pos = pos == -1 ? 0 : pos; - ir_mode *mode = get_irn_mode(irn); - FIRM_DBG_REGISTER(firm_dbg_module_t *mod, DEBUG_MODULE); + ir_mode *mode = get_irn_mode(node); - if (is_Block(irn) || mode == mode_X || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn)); - return NULL; + if (is_Block(node) || mode == mode_X || mode == mode_M) { + return arch_no_register_req; } if (mode == mode_T && pos < 0) { - DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F\n", irn)); - return NULL; + return arch_no_register_req; } - DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); - - if (is_Proj(irn)) { + if (is_Proj(node)) { /* in case of a proj, we need to get the correct OUT slot */ /* of the node corresponding to the proj number */ if (pos == -1) { - node_pos = mips_translate_proj_pos(irn); + node_pos = mips_translate_proj_pos(node); } else { node_pos = pos; } - irn = my_skip_proj(irn); - - DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); + node = skip_Proj_const(node); } /* get requirements for our own nodes */ - if (is_mips_irn(irn)) { + if (is_mips_irn(node)) { + const arch_register_req_t *req; if (pos >= 0) { - irn_req = get_mips_in_req(irn, pos); - } - else { - irn_req = get_mips_out_req(irn, node_pos); - } - - DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); - - memcpy(req, &(irn_req->req), sizeof(*req)); - - if (arch_register_req_is(&(irn_req->req), should_be_same)) { - assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI"); - req->other_same = get_irn_n(irn, irn_req->same_pos); + req = get_mips_in_req(node, pos); + } else { + req = get_mips_out_req(node, node_pos); } - if (arch_register_req_is(&(irn_req->req), should_be_different)) { - assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI"); - req->other_different = get_irn_n(irn, irn_req->different_pos); - } + return req; } - /* get requirements for FIRM nodes */ - else { - /* treat Phi like Const with default requirements */ - if (is_Phi(irn)) { - DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); - if (mode_is_float(mode)) { - //memcpy(req, &(mips_default_req_mips_floating_point.req), sizeof(*req)); - assert(0 && "floating point not supported (yet)"); - } - else if (mode_is_int(mode) || mode_is_reference(mode)) { - memcpy(req, &(mips_default_req_mips_gp.req), sizeof(*req)); - } - else if (mode == mode_T || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn)); - return NULL; - } - else { - assert(0 && "unsupported Phi-Mode"); - } - } - else { - DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn)); - req = NULL; - } - } + /* unknown should be translated by now */ + assert(!is_Unknown(node)); - return req; + return arch_no_register_req; } static void mips_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { @@ -162,7 +115,7 @@ static void mips_set_irn_reg(const void *self, ir_node *irn, const arch_register } pos = mips_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj(irn); } if (is_mips_irn(irn)) { @@ -188,7 +141,7 @@ static const arch_register_t *mips_get_irn_reg(const void *self, const ir_node * } pos = mips_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); } if (is_mips_irn(irn)) { @@ -204,7 +157,7 @@ static const arch_register_t *mips_get_irn_reg(const void *self, const ir_node * } static arch_irn_class_t mips_classify(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_cfop(irn)) { return arch_irn_class_branch; @@ -216,7 +169,7 @@ static arch_irn_class_t mips_classify(const void *self, const ir_node *irn) { } static arch_irn_flags_t mips_get_flags(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_mips_irn(irn)) { return get_mips_flags(irn); diff --git a/ir/be/mips/mips_new_nodes.c b/ir/be/mips/mips_new_nodes.c index 8522ed1a1..c7b299e7a 100644 --- a/ir/be/mips/mips_new_nodes.c +++ b/ir/be/mips/mips_new_nodes.c @@ -45,77 +45,47 @@ * |_| ***********************************************************************************/ -/** - * Returns a string containing the names of all registers within the limited bitset - */ -static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) { - bitset_t *bs = bitset_alloca(req->cls->n_regs); - char *p = buf; - int size = 0; - int i, cnt; - - req->limited(NULL, bs); - - for (i = 0; i < req->cls->n_regs; i++) { - if (bitset_is_set(bs, i)) { - cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name); - if (cnt < 0) { - fprintf(stderr, "dumper problem, exiting\n"); - exit(1); - } - - p += cnt; - size += cnt; - - if (size >= max) - break; - } - } - - return buf; -} - /** * Dumps the register requirements for either in or out. */ -static void dump_reg_req(FILE *F, ir_node *n, const mips_register_req_t **reqs, int inout) { +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_mips_n_res(n) : get_irn_arity(n); - char *buf = alloca(1024); + char buf[1024]; int i; - memset(buf, 0, 1024); + memset(buf, 0, sizeof(buf)); if (reqs) { for (i = 0; i < max; i++) { fprintf(F, "%sreq #%d =", dir, i); - if (reqs[i]->req.type == arch_register_req_type_none) { + if (reqs[i]->type == arch_register_req_type_none) { fprintf(F, " n/a"); } - if (reqs[i]->req.type & arch_register_req_type_normal) { - fprintf(F, " %s", reqs[i]->req.cls->name); + if (reqs[i]->type & arch_register_req_type_normal) { + fprintf(F, " %s", reqs[i]->cls->name); } - if (reqs[i]->req.type & arch_register_req_type_limited) { - fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024)); + if (reqs[i]->type & arch_register_req_type_limited) { + fprintf(F, " %s", + arch_register_req_format(buf, sizeof(buf), reqs[i], n)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_same) { - ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_same) { + ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->other_same)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_different) { - ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_different) { + ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->other_different)); } fprintf(F, "\n"); } fprintf(F, "\n"); - } - else { + } else { fprintf(F, "%sreq = N/A\n", dir); } } @@ -134,7 +104,7 @@ static int mips_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { int i; mips_attr_t *attr; char buf[64]; - const mips_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t **slots; switch (reason) { @@ -259,7 +229,7 @@ mips_attr_t *get_mips_attr(const ir_node *node) { /** * Returns the argument register requirements of a mips node. */ -const mips_register_req_t **get_mips_in_req_all(const ir_node *node) { +const arch_register_req_t **get_mips_in_req_all(const ir_node *node) { mips_attr_t *attr = get_mips_attr(node); return attr->in_req; } @@ -267,7 +237,7 @@ const mips_register_req_t **get_mips_in_req_all(const ir_node *node) { /** * Returns the result register requirements of an mips node. */ -const mips_register_req_t **get_mips_out_req_all(const ir_node *node) { +const arch_register_req_t **get_mips_out_req_all(const ir_node *node) { mips_attr_t *attr = get_mips_attr(node); return attr->out_req; } @@ -275,7 +245,7 @@ const mips_register_req_t **get_mips_out_req_all(const ir_node *node) { /** * Returns the argument register requirement at position pos of an mips node. */ -const mips_register_req_t *get_mips_in_req(const ir_node *node, int pos) { +const arch_register_req_t *get_mips_in_req(const ir_node *node, int pos) { mips_attr_t *attr = get_mips_attr(node); return attr->in_req[pos]; } @@ -283,7 +253,7 @@ const mips_register_req_t *get_mips_in_req(const ir_node *node, int pos) { /** * Returns the result register requirement at position pos of an mips node. */ -const mips_register_req_t *get_mips_out_req(const ir_node *node, int pos) { +const arch_register_req_t *get_mips_out_req(const ir_node *node, int pos) { mips_attr_t *attr = get_mips_attr(node); return attr->out_req[pos]; } @@ -291,7 +261,7 @@ const mips_register_req_t *get_mips_out_req(const ir_node *node, int pos) { /** * Sets the OUT register requirements at position pos. */ -void set_mips_req_out(ir_node *node, const mips_register_req_t *req, int pos) { +void set_mips_req_out(ir_node *node, const arch_register_req_t *req, int pos) { mips_attr_t *attr = get_mips_attr(node); attr->out_req[pos] = req; } @@ -299,7 +269,7 @@ void set_mips_req_out(ir_node *node, const mips_register_req_t *req, int pos) { /** * Sets the IN register requirements at position pos. */ -void set_mips_req_in(ir_node *node, const mips_register_req_t *req, int pos) { +void set_mips_req_in(ir_node *node, const arch_register_req_t *req, int pos) { mips_attr_t *attr = get_mips_attr(node); attr->in_req[pos] = req; } @@ -386,8 +356,8 @@ int get_mips_n_res(const ir_node *node) { /** * Initializes the nodes attributes. */ -void init_mips_attributes(ir_node *node, arch_irn_flags_t flags, const mips_register_req_t **in_reqs, - const mips_register_req_t **out_reqs, +void init_mips_attributes(ir_node *node, arch_irn_flags_t flags, const arch_register_req_t **in_reqs, + const arch_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency) { diff --git a/ir/be/mips/mips_new_nodes.h b/ir/be/mips/mips_new_nodes.h index 370f23ea9..32aa6a14a 100644 --- a/ir/be/mips/mips_new_nodes.h +++ b/ir/be/mips/mips_new_nodes.h @@ -27,32 +27,32 @@ mips_attr_t *get_mips_attr(const ir_node *node); /** * Returns the argument register requirements of an mips node. */ -const mips_register_req_t **get_mips_in_req_all(const ir_node *node); +const arch_register_req_t **get_mips_in_req_all(const ir_node *node); /** * Returns the result register requirements of an mips node. */ -const mips_register_req_t **get_mips_out_req_all(const ir_node *node); +const arch_register_req_t **get_mips_out_req_all(const ir_node *node); /** * Returns the argument register requirements of an mips node. */ -const mips_register_req_t *get_mips_in_req(const ir_node *node, int pos); +const arch_register_req_t *get_mips_in_req(const ir_node *node, int pos); /** * Returns the result register requirements of an mips node. */ -const mips_register_req_t *get_mips_out_req(const ir_node *node, int pos); +const arch_register_req_t *get_mips_out_req(const ir_node *node, int pos); /** * Sets the OUT register requirements at position pos. */ -void set_mips_req_out(ir_node *node, const mips_register_req_t *req, int pos); +void set_mips_req_out(ir_node *node, const arch_register_req_t *req, int pos); /** * Sets the IN register requirements at position pos. */ -void set_mips_req_in(ir_node *node, const mips_register_req_t *req, int pos); +void set_mips_req_in(ir_node *node, const arch_register_req_t *req, int pos); /** * Returns the register flag of an mips node. @@ -98,8 +98,8 @@ int get_mips_n_res(const ir_node *node); /** * Initializes the nodes attributes. */ -void init_mips_attributes(ir_node *node, arch_irn_flags_t flags, const mips_register_req_t **in_reqs, - const mips_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency); +void init_mips_attributes(ir_node *node, arch_irn_flags_t flags, const arch_register_req_t **in_reqs, + const arch_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency); /** * Initialize transform ops for the mips opcodes diff --git a/ir/be/mips/mips_nodes_attr.h b/ir/be/mips/mips_nodes_attr.h index b68eb835f..0602a7d21 100644 --- a/ir/be/mips/mips_nodes_attr.h +++ b/ir/be/mips/mips_nodes_attr.h @@ -4,13 +4,6 @@ #include "../bearch.h" #include "irmode_t.h" -typedef struct _mips_register_req_t { - const arch_register_req_t req; - int same_pos; /**<< in case of "should be same" we need to remember the pos to get the irn */ - int different_pos; /**<< in case of "should be different" we need to remember the pos to get the irn */ -} mips_register_req_t; - - typedef struct _mips_attr_t { arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */ int n_res; /**< number of results for this node */ @@ -26,8 +19,8 @@ typedef struct _mips_attr_t { int stack_entity_offset; /**< contains the real stack offset for the entity */ int switch_default_pn; /**< proj number of default case in switch */ - const mips_register_req_t **in_req; /**< register requirements for arguments */ - const mips_register_req_t **out_req; /**< register requirements for results */ + const arch_register_req_t **in_req; /**< register requirements for arguments */ + const arch_register_req_t **out_req; /**< register requirements for results */ /* must be last, dynamically allocated */ const arch_register_t *slots[1]; /**< register slots for assigned registers */ diff --git a/ir/be/mips/mips_spec.pl b/ir/be/mips/mips_spec.pl index dbea8bab9..9a926b1f9 100644 --- a/ir/be/mips/mips_spec.pl +++ b/ir/be/mips/mips_spec.pl @@ -91,45 +91,47 @@ $comment_string_end = ""; # 4 - ignore (do not assign this register) # NOTE: Last entry of each class is the largest Firm-Mode a register can hold\ %reg_classes = ( - "gp" => [ - { name => "zero", type => 4+2 }, # always zero - { name => "at", type => 4 }, # reserved for assembler - { name => "v0", type => 1 }, # first return value - { name => "v1", type => 1 }, # second return value - { name => "a0", type => 1 }, # first argument - { name => "a1", type => 1 }, # second argument - { name => "a2", type => 1 }, # third argument - { name => "a3", type => 1 }, # fourth argument - { name => "t0", type => 1 }, - { name => "t1", type => 1 }, - { name => "t2", type => 1 }, - { name => "t3", type => 1 }, - { name => "t4", type => 1 }, - { name => "t5", type => 1 }, - { name => "t6", type => 1 }, - { name => "t7", type => 1 }, - { name => "s0", type => 2 }, - { name => "s1", type => 2 }, - { name => "s2", type => 2 }, - { name => "s3", type => 2 }, - { name => "s4", type => 2 }, - { name => "s5", type => 2 }, - { name => "s6", type => 2 }, - { name => "s7", type => 2 }, - { name => "t8", type => 1 }, - { name => "t9", type => 1 }, - { name => "k0", type => 4 }, # reserved for OS - { name => "k1", type => 4 }, # reserved for OS - { name => "gp", type => 4 }, # general purpose - { name => "sp", type => 4+2 }, # stack pointer - { name => "fp", type => 4+2 }, # frame pointer - { name => "ra", type => 2+1 }, # return address. This is also caller save, because - # the jla instruction that is used for calls modifies - # the ra register. It is callee save too, because at the last - # command of a function (the ja $ra) it needs to have it's - # old value. - { mode => "mode_P" } - ], + "gp" => [ + { name => "zero", type => 4+2 }, # always zero + { name => "at", type => 4 }, # reserved for assembler + { name => "v0", type => 1 }, # first return value + { name => "v1", type => 1 }, # second return value + { name => "a0", type => 1 }, # first argument + { name => "a1", type => 1 }, # second argument + { name => "a2", type => 1 }, # third argument + { name => "a3", type => 1 }, # fourth argument + { name => "t0", type => 1 }, + { name => "t1", type => 1 }, + { name => "t2", type => 1 }, + { name => "t3", type => 1 }, + { name => "t4", type => 1 }, + { name => "t5", type => 1 }, + { name => "t6", type => 1 }, + { name => "t7", type => 1 }, + { name => "s0", type => 2 }, + { name => "s1", type => 2 }, + { name => "s2", type => 2 }, + { name => "s3", type => 2 }, + { name => "s4", type => 2 }, + { name => "s5", type => 2 }, + { name => "s6", type => 2 }, + { name => "s7", type => 2 }, + { name => "t8", type => 1 }, + { name => "t9", type => 1 }, + { name => "k0", type => 4 }, # reserved for OS + { name => "k1", type => 4 }, # reserved for OS + { name => "gp", type => 4 }, # general purpose + { name => "sp", type => 4+2 }, # stack pointer + { name => "fp", type => 4+2 }, # frame pointer + { name => "ra", type => 2+1 }, # return address. This is also caller + # save, because the jla instruction that + # is used for calls modifies the ra + # register. It is callee save too, + # because at the last command of a + # function (the ja $ra) it needs to have + # it's old value. + { mode => "mode_P" } + ], ); # %reg_classes #--------------------------------------------------# diff --git a/ir/be/ppc32/bearch_ppc32.c b/ir/be/ppc32/bearch_ppc32.c index 5ef844e54..3a6124e48 100644 --- a/ir/be/ppc32/bearch_ppc32.c +++ b/ir/be/ppc32/bearch_ppc32.c @@ -1,8 +1,7 @@ /* The main ppc backend driver file. */ /* $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include "pseudo_irg.h" @@ -57,31 +56,26 @@ static set *cur_reg_set = NULL; * |___/ **************************************************/ -static ir_node *my_skip_proj(const ir_node *n) { - while (is_Proj(n)) - n = get_Proj_pred(n); - return (ir_node *)n; -} - /** * Return register requirements for a ppc node. * If the node returns a tuple (mode_T) then the proj's * will be asked for this information. */ -static const arch_register_req_t *ppc32_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) { - const ppc32_register_req_t *irn_req; +static const +arch_register_req_t *ppc32_get_irn_reg_req(const void *self, + const ir_node *irn, int pos) { long node_pos = pos == -1 ? 0 : pos; ir_mode *mode = get_irn_mode(irn); FIRM_DBG_REGISTER(firm_dbg_module_t *mod, DEBUG_MODULE); if (is_Block(irn) || mode == mode_X || mode == mode_M) { DBG((mod, LEVEL_1, "ignoring block, mode_X or mode_M node %+F\n", irn)); - return NULL; + return arch_no_register_req; } if (mode == mode_T && pos < 0) { DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F", irn)); - return NULL; + return arch_no_register_req; } DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn)); @@ -91,66 +85,33 @@ static const arch_register_req_t *ppc32_get_irn_reg_req(const void *self, arch_r /* of the node corresponding to the proj number */ if (pos == -1) { node_pos = ppc32_translate_proj_pos(irn); - } - else { + } else { node_pos = pos; } - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos)); } /* get requirements for our own nodes */ if (is_ppc32_irn(irn)) { + const arch_register_req_t *req; if (pos >= 0) { - irn_req = get_ppc32_in_req(irn, pos); - } - else { - irn_req = get_ppc32_out_req(irn, node_pos); + req = get_ppc32_in_req(irn, pos); + } else { + req = get_ppc32_out_req(irn, node_pos); } DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos)); - - memcpy(req, &(irn_req->req), sizeof(*req)); - - if (arch_register_req_is(&(irn_req->req), should_be_same)) { - assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI"); - req->other_same = get_irn_n(irn, irn_req->same_pos); - } - - if (arch_register_req_is(&(irn_req->req), should_be_different)) { - assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI"); - req->other_different = get_irn_n(irn, irn_req->different_pos); - } + return req; } - /* get requirements for FIRM nodes */ - else { - /* treat Phi like Const with default requirements */ - if (is_Phi(irn)) { - DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); - if (mode_is_float(mode)) { - memcpy(req, &(ppc32_default_req_ppc32_fp.req), sizeof(*req)); - } - else if (mode_is_int(mode) || mode_is_reference(mode)) { - memcpy(req, &(ppc32_default_req_ppc32_gp.req), sizeof(*req)); - } - else if (mode == mode_T || mode == mode_M) { - DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn)); - return NULL; - } - else { - assert(0 && "unsupported Phi-Mode"); - } - } - else { - DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn)); - req = NULL; - } - } + /* unknowns should be transformed by now */ + assert(!is_Unknown(irn)); - return req; + DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn)); + return arch_no_register_req; } static void ppc32_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) { @@ -163,7 +124,7 @@ static void ppc32_set_irn_reg(const void *self, ir_node *irn, const arch_registe } pos = ppc32_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj(irn); } if (is_ppc32_irn(irn)) { @@ -189,7 +150,7 @@ static const arch_register_t *ppc32_get_irn_reg(const void *self, const ir_node } pos = ppc32_translate_proj_pos(irn); - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); } if (is_ppc32_irn(irn)) { @@ -205,7 +166,7 @@ static const arch_register_t *ppc32_get_irn_reg(const void *self, const ir_node } static arch_irn_class_t ppc32_classify(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_cfop(irn)) { return arch_irn_class_branch; @@ -218,7 +179,7 @@ static arch_irn_class_t ppc32_classify(const void *self, const ir_node *irn) { } static arch_irn_flags_t ppc32_get_flags(const void *self, const ir_node *irn) { - irn = my_skip_proj(irn); + irn = skip_Proj_const(irn); if (is_ppc32_irn(irn)) { return get_ppc32_flags(irn); diff --git a/ir/be/ppc32/ppc32_new_nodes.c b/ir/be/ppc32/ppc32_new_nodes.c index dce4963c9..32ab4ebf2 100644 --- a/ir/be/ppc32/ppc32_new_nodes.c +++ b/ir/be/ppc32/ppc32_new_nodes.c @@ -4,7 +4,7 @@ * $Id$ */ #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #ifdef _WIN32 @@ -45,77 +45,47 @@ * |_| ***********************************************************************************/ -/** - * Returns a string containing the names of all registers within the limited bitset - */ -static char *get_limited_regs(const arch_register_req_t *req, char *buf, int max) { - bitset_t *bs = bitset_alloca(req->cls->n_regs); - char *p = buf; - int size = 0; - int i, cnt; - - req->limited(NULL, bs); - - for (i = 0; i < req->cls->n_regs; i++) { - if (bitset_is_set(bs, i)) { - cnt = snprintf(p, max - size, " %s", req->cls->regs[i].name); - if (cnt < 0) { - fprintf(stderr, "dumper problem, exiting\n"); - exit(1); - } - - p += cnt; - size += cnt; - - if (size >= max) - break; - } - } - - return buf; -} - /** * Dumps the register requirements for either in or out. */ -static void dump_reg_req(FILE *F, ir_node *n, const ppc32_register_req_t **reqs, int inout) { +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_ppc32_n_res(n) : get_irn_arity(n); - char *buf = alloca(1024); + char buf[1024]; int i; - memset(buf, 0, 1024); + memset(buf, 0, sizeof(buf)); if (reqs) { for (i = 0; i < max; i++) { fprintf(F, "%sreq #%d =", dir, i); - if (reqs[i]->req.type == arch_register_req_type_none) { + if (reqs[i]->type == arch_register_req_type_none) { fprintf(F, " n/a"); } - if (reqs[i]->req.type & arch_register_req_type_normal) { - fprintf(F, " %s", reqs[i]->req.cls->name); + if (reqs[i]->type & arch_register_req_type_normal) { + fprintf(F, " %s", reqs[i]->cls->name); } - if (reqs[i]->req.type & arch_register_req_type_limited) { - fprintf(F, " %s", get_limited_regs(&reqs[i]->req, buf, 1024)); + if (reqs[i]->type & arch_register_req_type_limited) { + fprintf(F, " %s", + arch_register_req_format(buf, sizeof(buf), reqs[i], n)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_same) { - ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->same_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_same) { + ir_fprintf(F, " same as %+F", get_irn_n(n, reqs[i]->other_same)); } - if (reqs[i]->req.type & arch_register_req_type_should_be_different) { - ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->different_pos)); + if (reqs[i]->type & arch_register_req_type_should_be_different) { + ir_fprintf(F, " different from %+F", get_irn_n(n, reqs[i]->other_different)); } fprintf(F, "\n"); } fprintf(F, "\n"); - } - else { + } else { fprintf(F, "%sreq = N/A\n", dir); } } @@ -133,7 +103,7 @@ static int ppc32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { int bad = 0; int i; ppc32_attr_t *attr; - const ppc32_register_req_t **reqs; + const arch_register_req_t **reqs; const arch_register_t **slots; switch (reason) { @@ -246,7 +216,7 @@ ppc32_attr_t *get_ppc32_attr(const ir_node *node) { /** * Returns the argument register requirements of a ppc node. */ -const ppc32_register_req_t **get_ppc32_in_req_all(const ir_node *node) { +const arch_register_req_t **get_ppc32_in_req_all(const ir_node *node) { ppc32_attr_t *attr = get_ppc32_attr(node); return attr->in_req; } @@ -254,7 +224,7 @@ const ppc32_register_req_t **get_ppc32_in_req_all(const ir_node *node) { /** * Returns the result register requirements of an ppc node. */ -const ppc32_register_req_t **get_ppc32_out_req_all(const ir_node *node) { +const arch_register_req_t **get_ppc32_out_req_all(const ir_node *node) { ppc32_attr_t *attr = get_ppc32_attr(node); return attr->out_req; } @@ -262,7 +232,7 @@ const ppc32_register_req_t **get_ppc32_out_req_all(const ir_node *node) { /** * Returns the argument register requirement at position pos of an ppc node. */ -const ppc32_register_req_t *get_ppc32_in_req(const ir_node *node, int pos) { +const arch_register_req_t *get_ppc32_in_req(const ir_node *node, int pos) { ppc32_attr_t *attr = get_ppc32_attr(node); return attr->in_req[pos]; } @@ -270,7 +240,7 @@ const ppc32_register_req_t *get_ppc32_in_req(const ir_node *node, int pos) { /** * Returns the result register requirement at position pos of an ppc node. */ -const ppc32_register_req_t *get_ppc32_out_req(const ir_node *node, int pos) { +const arch_register_req_t *get_ppc32_out_req(const ir_node *node, int pos) { ppc32_attr_t *attr = get_ppc32_attr(node); return attr->out_req[pos]; } @@ -278,7 +248,7 @@ const ppc32_register_req_t *get_ppc32_out_req(const ir_node *node, int pos) { /** * Sets the OUT register requirements at position pos. */ -void set_ppc32_req_out(ir_node *node, const ppc32_register_req_t *req, int pos) { +void set_ppc32_req_out(ir_node *node, const arch_register_req_t *req, int pos) { ppc32_attr_t *attr = get_ppc32_attr(node); attr->out_req[pos] = req; } @@ -286,7 +256,7 @@ void set_ppc32_req_out(ir_node *node, const ppc32_register_req_t *req, int pos) /** * Sets the IN register requirements at position pos. */ -void set_ppc32_req_in(ir_node *node, const ppc32_register_req_t *req, int pos) { +void set_ppc32_req_in(ir_node *node, const arch_register_req_t *req, int pos) { ppc32_attr_t *attr = get_ppc32_attr(node); attr->in_req[pos] = req; } @@ -513,7 +483,7 @@ ppc32_attr_offset_mode get_ppc32_offset_mode(const ir_node *node) { * Initializes ppc specific node attributes */ void init_ppc32_attributes(ir_node *node, int flags, - const ppc32_register_req_t **in_reqs, const ppc32_register_req_t **out_reqs, + const arch_register_req_t **in_reqs, const arch_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency) { ppc32_attr_t *attr = get_ppc32_attr(node); diff --git a/ir/be/ppc32/ppc32_new_nodes.h b/ir/be/ppc32/ppc32_new_nodes.h index f6324003d..a5ca72d5d 100644 --- a/ir/be/ppc32/ppc32_new_nodes.h +++ b/ir/be/ppc32/ppc32_new_nodes.h @@ -27,32 +27,32 @@ ppc32_attr_t *get_ppc32_attr(const ir_node *node); /** * Returns the argument register requirements of an ppc node. */ -const ppc32_register_req_t **get_ppc32_in_req_all(const ir_node *node); +const arch_register_req_t **get_ppc32_in_req_all(const ir_node *node); /** * Returns the result register requirements of an ppc node. */ -const ppc32_register_req_t **get_ppc32_out_req_all(const ir_node *node); +const arch_register_req_t **get_ppc32_out_req_all(const ir_node *node); /** * Returns the argument register requirements of an ppc node. */ -const ppc32_register_req_t *get_ppc32_in_req(const ir_node *node, int pos); +const arch_register_req_t *get_ppc32_in_req(const ir_node *node, int pos); /** * Returns the result register requirements of an ppc node. */ -const ppc32_register_req_t *get_ppc32_out_req(const ir_node *node, int pos); +const arch_register_req_t *get_ppc32_out_req(const ir_node *node, int pos); /** * Sets the OUT register requirements at position pos. */ -void set_ppc32_req_out(ir_node *node, const ppc32_register_req_t *req, int pos); +void set_ppc32_req_out(ir_node *node, const arch_register_req_t *req, int pos); /** * Sets the IN register requirements at position pos. */ -void set_ppc32_req_in(ir_node *node, const ppc32_register_req_t *req, int pos); +void set_ppc32_req_in(ir_node *node, const arch_register_req_t *req, int pos); /** * Returns the register flag of an ppc node. @@ -118,7 +118,7 @@ void set_ppc32_offset_mode(const ir_node *node, ppc32_attr_offset_mode mode); ppc32_attr_offset_mode get_ppc32_offset_mode(const ir_node *node); void init_ppc32_attributes(ir_node *node, int flags, - const ppc32_register_req_t **in_reqs, const ppc32_register_req_t **out_reqs, + const arch_register_req_t **in_reqs, const arch_register_req_t **out_reqs, const be_execution_unit_t ***execution_units, int n_res, unsigned latency); diff --git a/ir/be/ppc32/ppc32_nodes_attr.h b/ir/be/ppc32/ppc32_nodes_attr.h index 13bcea6bd..402108397 100644 --- a/ir/be/ppc32/ppc32_nodes_attr.h +++ b/ir/be/ppc32/ppc32_nodes_attr.h @@ -3,12 +3,6 @@ #include "../bearch.h" -typedef struct _ppc32_register_req_t { - const arch_register_req_t req; - int same_pos; /**< in case of "should be same" we need to remember the pos to get the irn */ - int different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */ -} ppc32_register_req_t; - typedef struct { unsigned shift:5; @@ -35,8 +29,8 @@ typedef struct _ppc32_attr_t { arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */ int n_res; /**< number of results for this node */ - const ppc32_register_req_t **in_req; /**< register requirements for arguments */ - const ppc32_register_req_t **out_req; /**< register requirements for results */ + const arch_register_req_t **in_req; /**< register requirements for arguments */ + const arch_register_req_t **out_req; /**< register requirements for results */ ppc32_attr_content_type content_type; ppc32_attr_offset_mode offset_mode; diff --git a/ir/be/ppc32/ppc32_transform.c b/ir/be/ppc32/ppc32_transform.c index f7a7e45a3..c11c56239 100644 --- a/ir/be/ppc32/ppc32_transform.c +++ b/ir/be/ppc32/ppc32_transform.c @@ -1119,9 +1119,9 @@ static ir_node *gen_CopyB(ppc32_transform_env_t *env) { int size = get_type_size_bytes(type); int offset = 0; - ir_node *load, *store; + ir_node *load, *store = NULL; - if(size/4>=1) + if(size/4 >= 1) { ir_node *res; tarval *offset0 = new_tarval_from_long(0, mode_Is); @@ -1424,7 +1424,7 @@ static ir_node *gen_fp_known_symconst(ppc32_transform_env_t *env, tarval *known_ struct tv_ent *entry; ir_node *cnst,*symcnst; ir_graph *rem; - ir_entity *ent; + ir_entity *ent = NULL; if(!const_set) const_set = new_set(cmp_tv_ent, 10); diff --git a/ir/be/scripts/generate_emitter.pl b/ir/be/scripts/generate_emitter.pl index 1326d9ab9..42d1d8b27 100755 --- a/ir/be/scripts/generate_emitter.pl +++ b/ir/be/scripts/generate_emitter.pl @@ -192,7 +192,7 @@ print OUT< #endif #include diff --git a/ir/be/scripts/generate_emitter_new.pl b/ir/be/scripts/generate_emitter_new.pl index eeb432d78..154fb2e01 100755 --- a/ir/be/scripts/generate_emitter_new.pl +++ b/ir/be/scripts/generate_emitter_new.pl @@ -15,6 +15,7 @@ our $target_dir; our $arch; our %nodes; our %emit_templates; +our $finish_line_template = "be_emit_finish_line_gas(emit, node);"; my $target_c = $target_dir."/gen_".$arch."_emitter.c"; my $target_h = $target_dir."/gen_".$arch."_emitter.h"; @@ -32,24 +33,24 @@ sub create_emitter { our $arch; my @tokens = ($template =~ m/[^\%]+|\%[a-zA-Z_][a-zA-Z0-9_]*|\%./g); - push(@{$result}, "${indent}${arch}_emit_char(env, '\t');\n"); + push(@{$result}, "${indent}be_emit_char(emit, '\t');\n"); for (@tokens) { SWITCH: { if (/%\./) { last SWITCH; } - if (/%%/) { push(@{$result}, "${indent}${arch}_emit_char(env, '%');\n"); last SWITCH; } + if (/%%/) { push(@{$result}, "${indent}be_emit_char(emit, '%');\n"); last SWITCH; } if (/%(.+)/) { if(defined($emit_templates{$1})) { push(@{$result}, "${indent}$emit_templates{$1}\n"); } else { print "Warning: No emit_template defined for '$1'\n"; - push(@{$result}, "${indent}$1(env, node);\n"); + push(@{$result}, "${indent}$1(emit, node);\n"); } last SWITCH; } - push(@{$result}, "${indent}${arch}_emit_cstring(env, \"$_\");\n"); + push(@{$result}, "${indent}be_emit_cstring(emit, \"$_\");\n"); } } - push(@{$result}, "${indent}${arch}_emit_finish_line(env, node);\n"); + push(@{$result}, "${indent}${finish_line_template}\n"); } @@ -60,7 +61,7 @@ foreach my $op (keys(%nodes)) { # skip this node description if no emit information is available next if (!defined($n{"emit"})); - $line = "static void emit_".$arch."_".$op."(${arch}_emit_env_t *env, const ir_node *node)"; + $line = "static void emit_${arch}_${op}(${arch}_emit_env_t *env, const ir_node *node)"; push(@obst_register, " BE_EMIT($op);\n"); @@ -71,6 +72,8 @@ foreach my $op (keys(%nodes)) { } push(@obst_func, $line." {\n"); + push(@obst_func, "\tbe_emit_env_t *emit = env->emit;\n"); + my @emit = split(/\n/, $n{"emit"}); foreach my $template (@emit) { @@ -105,9 +108,9 @@ print OUT< #endif #include "gen_$arch\_machine.h" diff --git a/ir/be/scripts/generate_new_opcodes.pl b/ir/be/scripts/generate_new_opcodes.pl index 9b8e9ba08..0508c7c32 100755 --- a/ir/be/scripts/generate_new_opcodes.pl +++ b/ir/be/scripts/generate_new_opcodes.pl @@ -61,6 +61,20 @@ $n_opcodes += $additional_opcodes if (defined($additional_opcodes)); push(@obst_header, "void ".$arch."_create_opcodes(void);\n"); +# create default compare function +if(defined($default_cmp_attr)) { + my $cmpcode = $default_cmp_attr; + push(@obst_cmp_attr, "static int default_cmp_attr(ir_node *a, ir_node *b) {\n"); + if($cmpcode =~ m/attr_a/) { + push(@obst_cmp_attr, "\t$arch\_attr_t *attr_a = get_$arch\_attr(a);\n"); + } + if($cmpcode =~ m/attr_b/) { + push(@obst_cmp_attr, "\t$arch\_attr_t *attr_b = get_$arch\_attr(b);\n"); + } + push(@obst_cmp_attr, "\t${cmpcode}\n"); + push(@obst_cmp_attr, "}\n\n"); +} + push(@obst_enum_op, "typedef enum _$arch\_opcodes {\n"); foreach my $op (keys(%nodes)) { my %n = %{ $nodes{"$op"} }; @@ -114,22 +128,25 @@ foreach my $op (keys(%nodes)) { push(@obst_header, "ir_op *get_op_$op(void);\n"); push(@obst_header, "int is_$op(const ir_node *n);\n"); - $cmp_attr_func = 0; + my $cmp_attr_func; + if(defined($default_cmp_attr)) { + $cmp_attr_func = "default_cmp_attr"; + } # create compare attribute function if needed - if (exists($n{"cmp_attr"}) || defined($default_cmp_attr)) { + if (exists($n{"cmp_attr"})) { + my $cmpcode = $n{"cmp_attr"}; + push(@obst_cmp_attr, "static int cmp_attr_$op(ir_node *a, ir_node *b) {\n"); - push(@obst_cmp_attr, "\t$arch\_attr_t *attr_a = get_$arch\_attr(a);\n"); - push(@obst_cmp_attr, "\t$arch\_attr_t *attr_b = get_$arch\_attr(b);\n"); - push(@obst_cmp_attr, "\t(void) attr_a;\n"); - push(@obst_cmp_attr, "\t(void) attr_b;\n"); - if(exists($n{"cmp_attr"})) { - push(@obst_cmp_attr, "\t".$n{"cmp_attr"}."\n"); - } else { - push(@obst_cmp_attr, "\t$default_cmp_attr\n"); + if($cmpcode =~ m/attr_a/) { + push(@obst_cmp_attr, "\t$arch\_attr_t *attr_a = get_$arch\_attr(a);\n"); + } + if($cmpcode =~ m/attr_b/) { + push(@obst_cmp_attr, "\t$arch\_attr_t *attr_b = get_$arch\_attr(b);\n"); } + push(@obst_cmp_attr, "\t${cmpcode}\n"); push(@obst_cmp_attr, "}\n\n"); - $cmp_attr_func = 1; + $cmp_attr_func = "cmp_attr_${op}"; } if (exists($n{"rd_constructor"}) && $n{"rd_constructor"} =~ /^NONE$/i) { @@ -214,10 +231,10 @@ foreach my $op (keys(%nodes)) { if (@in) { $in_req_var = "_in_req_$op"; - $temp .= "\tstatic const $arch\_register_req_t *".$in_req_var."[] =\n"; + $temp .= "\tstatic const arch_register_req_t *".$in_req_var."[] =\n"; $temp .= "\t{\n"; for ($idx = 0; $idx <= $#in; $idx++) { - $temp .= "\t\t".$op."_reg_req_in_".$idx.",\n"; + $temp .= "\t\t&".$op."_reg_req_in_".$idx.",\n"; } $temp .= "\t};\n"; } @@ -225,20 +242,18 @@ foreach my $op (keys(%nodes)) { if (@out) { $out_req_var = "_out_req_$op"; - $temp .= "\tstatic const $arch\_register_req_t *".$out_req_var."[] =\n"; + $temp .= "\tstatic const arch_register_req_t *".$out_req_var."[] =\n"; $temp .= "\t{\n"; for ($idx = 0; $idx <= $#out; $idx++) { - $temp .= "\t\t".$op."_reg_req_out_".$idx.",\n"; + $temp .= "\t\t&".$op."_reg_req_out_".$idx.",\n"; } $temp .= "\t};\n"; } } $temp .= "\n"; - $temp .= "\tif (!op_$op) {\n"; - $temp .= "\t\tassert(0);\n"; - $temp .= "\t\treturn NULL;\n"; - $temp .= "\t}\n\n"; + $temp .= "\tassert(op_$op != NULL);\n\n"; + for (my $i = 1; $i <= $arity; $i++) { $temp .= "\tin[".($i - 1)."] = op".$i.";\n"; } @@ -359,8 +374,8 @@ foreach my $op (keys(%nodes)) { push(@obst_new_irop, "\n\tmemset(&ops, 0, sizeof(ops));\n"); push(@obst_new_irop, "\tops.dump_node = $arch\_dump_node;\n"); - if ($cmp_attr_func) { - push(@obst_new_irop, "\tops.node_cmp_attr = cmp_attr_$op;\n"); + if (defined($cmp_attr_func)) { + push(@obst_new_irop, "\tops.node_cmp_attr = ${cmp_attr_func};\n"); } $n_opcodes++; diff --git a/ir/be/scripts/generate_regalloc_if.pl b/ir/be/scripts/generate_regalloc_if.pl index 3481218c9..535182d8c 100755 --- a/ir/be/scripts/generate_regalloc_if.pl +++ b/ir/be/scripts/generate_regalloc_if.pl @@ -7,6 +7,7 @@ use strict; use Data::Dumper; +use integer; my $specfile = $ARGV[0]; my $target_dir = $ARGV[1]; @@ -20,7 +21,7 @@ our %cpu; my $return; -no strict "subs"; +use strict "subs"; unless ($return = do $specfile) { warn "couldn't parse $specfile: $@" if $@; warn "couldn't do $specfile: $!" unless defined $return; @@ -75,9 +76,8 @@ my @obst_regdef; # stack to define a name for a register index my @obst_reginit; # stack for the register type inits my @obst_req; # stack for the register requirements my @obst_limit_func; # stack for functions to return a subset of a register class -my @obst_defreq_head; # stack for prototypes of default requirement function my @obst_header_all; # stack for some extern struct defs needed for bearch_$arch include -my @obst_requirement_def; # stack for requirement name defines +my @obst_header_t; my $numregs; my $class_ptr; @@ -86,33 +86,18 @@ my $class_idx = 0; my $tmp; my %reg2class; - -# there is a default NONE requirement -$tmp = "/* Default NONE register requirements */\n"; -$tmp .= "const $arch\_register_req_t $arch\_default_req_none = {\n"; -$tmp .= " {\n"; -$tmp .= " arch_register_req_type_none, /* register type */\n"; -$tmp .= " NULL, /* register class */\n"; -$tmp .= " NULL, /* limit function */\n"; -$tmp .= " NULL, /* limit environment */\n"; -$tmp .= " NULL, /* node for same */\n"; -$tmp .= " NULL /* node for different */\n"; -$tmp .= " },\n"; -$tmp .= " 0, /* same pos */\n"; -$tmp .= " 0 /* different pos */\n"; -$tmp .= "};\n\n"; -push(@obst_req, $tmp); -push(@obst_header_all, "extern const $arch\_register_req_t $arch\_default_req_none;\n"); +my %regclass2len; push(@obst_classdef, "enum reg_classes {\n"); my $class_mode; # assure, the initialization is done only once -push(@obst_reginit, " static int run_once = 0;\n"); +push(@obst_reginit, "\tstatic int run_once = 0;\n"); push(@obst_reginit, "\n"); -push(@obst_reginit, " if (run_once)\n return;\n"); -push(@obst_reginit, " run_once = 1;\n"); +push(@obst_reginit, "\tif (run_once)\n"); +push(@obst_reginit, "\t\treturn;\n"); +push(@obst_reginit, "\trun_once = 1;\n"); # generate register type and class variable, init function and default requirements foreach my $class_name (keys(%reg_classes)) { @@ -127,87 +112,36 @@ foreach my $class_name (keys(%reg_classes)) { push(@obst_regtypes_decl, "extern arch_register_t ".$class_name."_regs[$numregs];\n"); push(@obst_regtypes_def, "arch_register_t ".$class_name."_regs[$numregs];\n"); - push(@obst_classdef, " CLASS_$class_name = $class_idx,\n"); + push(@obst_classdef, "\tCLASS_$class_name = $class_idx,\n"); push(@obst_regclasses, "{ \"$class_name\", $numregs, NULL, ".$class_name."_regs }"); - # there is a default NORMAL requirement for each class - $tmp = "/* Default NORMAL register requirements for class $class_name */\n"; - $tmp .= "const $arch\_register_req_t $arch\_default_req_$class_name = {\n"; - $tmp .= " {\n"; - $tmp .= " arch_register_req_type_normal,\n"; - $tmp .= " $class_ptr,\n"; - $tmp .= " NULL, /* limit function */ \n"; - $tmp .= " NULL, /* limit environment */\n"; - $tmp .= " NULL, /* node for same */\n"; - $tmp .= " NULL /* node for different */\n"; - $tmp .= " },\n"; - $tmp .= " 0, /* same pos */\n"; - $tmp .= " 0 /* different pos */\n"; - $tmp .= "};\n\n"; - push(@obst_req, $tmp); - push(@obst_header_all, "extern const $arch\_register_req_t $arch\_default_req_$class_name;\n"); - my $idx = 0; - push(@obst_reginit, " /* Init of all registers in class '$class_name' */\n\n"); - push(@obst_reginit, " /* set largest possible mode for '$class_name' */\n"); - push(@obst_reginit, " $arch\_reg_classes[CLASS_".$class_name."].mode = $class_mode;\n\n"); + push(@obst_reginit, "\t/* Init of all registers in class '$class_name' */\n\n"); + push(@obst_reginit, "\t/* set largest possible mode for '$class_name' */\n"); + push(@obst_reginit, "\t$arch\_reg_classes[CLASS_".$class_name."].mode = $class_mode;\n\n"); push(@obst_regdef, "enum reg_".$class_name."_values {\n"); foreach (@class) { - # For each class we build for each of it's member registers a limit function - # which limits the class to this particular register. We also build the - # corresponding requirement structs. - # We need those functions to set register requirements on demand in transformation - # esp. for Call and RegParams where we can mix int and float parameters. - - my $limit_func_name = $arch."_limit_".$class_name."_".$_->{"name"}; - - # push the function prototype - $tmp = "void $limit_func_name(void *_unused, bitset_t *bs)"; - push(@obst_defreq_head, $tmp.";\n"); - - # push the function definition - $tmp .= " {\n"; - $tmp .= " bs = bitset_clear_all(bs);\n"; - $tmp .= " bitset_set(bs, REG_".uc($_->{"name"}).");\n"; # REGISTER to index assignment is done some lines down - $tmp .= "}\n\n"; - push(@obst_limit_func, $tmp); - - # push the default requirement struct - $tmp = "const $arch\_register_req_t $arch\_default_req_$class_name\_".$_->{"name"}." = {\n"; - $tmp .= " {\n"; - $tmp .= " arch_register_req_type_limited,\n"; - $tmp .= " $class_ptr,\n"; - $tmp .= " $limit_func_name,\n"; - $tmp .= " NULL, /* limit environment */\n"; - $tmp .= " NULL, /* node for same */\n"; - $tmp .= " NULL /* node for different */\n"; - $tmp .= " },\n"; - $tmp .= " 0, /* same pos */\n"; - $tmp .= " 0 /* different pos */\n"; - $tmp .= "};\n\n"; - push(@obst_req, $tmp); - push(@obst_header_all,"extern const $arch\_register_req_t $arch\_default_req_$class_name\_".$_->{"name"}.";\n"); - # realname is name if not set by user $_->{"realname"} = $_->{"name"} if (! exists($_->{"realname"})); $reg2class{$_->{"name"}} = { "class" => $old_classname, "index" => $idx }; # remember reg to class for later use - push(@obst_regdef, " REG_".uc($_->{"name"})." = $idx,\n"); - push(@obst_reginit, " ".$class_name."_regs[$idx].name = \"".$_->{"realname"}."\";\n"); - push(@obst_reginit, " ".$class_name."_regs[$idx].reg_class = $class_ptr;\n"); - push(@obst_reginit, " ".$class_name."_regs[$idx].index = $idx;\n"); - push(@obst_reginit, " ".$class_name."_regs[$idx].type = ".translate_reg_type($_->{"type"}).";\n"); - push(@obst_reginit, " ".$class_name."_regs[$idx].data = ".get_execunit_variable_name($_->{"unit"}).";\n"); + push(@obst_regdef, "\tREG_".uc($_->{"name"})." = $idx,\n"); + push(@obst_reginit, "\t${class_name}_regs[$idx].name = \"".$_->{"realname"}."\";\n"); + push(@obst_reginit, "\t${class_name}_regs[$idx].reg_class = $class_ptr;\n"); + push(@obst_reginit, "\t${class_name}_regs[$idx].index = $idx;\n"); + push(@obst_reginit, "\t${class_name}_regs[$idx].type = ".translate_reg_type($_->{"type"}).";\n"); + push(@obst_reginit, "\t${class_name}_regs[$idx].data = ".get_execunit_variable_name($_->{"unit"}).";\n"); push(@obst_reginit, "\n"); $idx++; } - push(@obst_regdef, " $numregs = $idx\n"); + $regclass2len{$old_classname} = $idx; + push(@obst_regdef, "\t$numregs = $idx\n"); push(@obst_regdef, "};\n\n"); $class_idx++; } -push(@obst_classdef, " N_CLASSES = ".scalar(keys(%reg_classes))."\n"); +push(@obst_classdef, "\tN_CLASSES = ".scalar(keys(%reg_classes))."\n"); push(@obst_classdef, "};\n\n"); # generate node-register constraints @@ -241,9 +175,6 @@ my $creation_time = localtime(time()); $tmp = uc($arch); print OUT<$target_h") || die("Could not open $target_h, reason: $!\n"); $creation_time = localtime(time()); print OUT< #endif -#include "gen_$arch\_regalloc_if.h" -#include "gen_$arch\_machine.h" /* we need this, as there can be units assigned to registers */ -#include "bearch_$arch\_t.h" /* we need this to put the caller saved registers into the isa set */ -#include "$arch\_map_regs.h" +#include "gen_${arch}_regalloc_if.h" +#include "gen_${arch}_machine.h" +#include "bearch_${arch}_t.h" +#include "${arch}_map_regs.h" #include "irmode.h" +#ifdef BIT +#undef BIT +#endif +#define BIT(x) (1 << (x % 32)) + EOF -print OUT "arch_register_class_t $arch\_reg_classes[] = {\n ".join(",\n ", @obst_regclasses)."\n};\n\n"; +print OUT "arch_register_class_t ${arch}_reg_classes[] = {\n\t".join(",\n\t", @obst_regclasses)."\n};\n\n"; print OUT @obst_regtypes_def, "\n"; -print OUT "void ".$arch."_register_init(void *isa_ptr) {\n"; +print OUT "void ${arch}_register_init(void *isa_ptr) {\n"; print OUT @obst_reginit; print OUT "}\n\n"; @@ -366,11 +302,9 @@ sub build_inout_idx_class { if ($reqs[$idx] eq "none") { $class = "none"; - } - elsif (is_reg_class($reqs[$idx])) { + } elsif (is_reg_class($reqs[$idx])) { $class = $reqs[$idx]; - } - else { + } else { my @regs = split(/ /, $reqs[$idx]); GET_CLASS: foreach my $reg (@regs) { if ($reg =~ /!?(in|out)\_r\d+/ || $reg =~ /!in/) { @@ -411,39 +345,47 @@ sub generate_requirements { for (my $idx = 0; $idx <= $#reqs; $idx++) { my $class = undef; - my $tmp2 = "const $arch\_register_req_t _".$op."_reg_req_$inout\_$idx = "; - my $tmp = "#define ".$op."_reg_req_$inout\_$idx "; + my $tmp2 = "const arch_register_req_t ${op}_reg_req_${inout}_${idx} = "; if ($reqs[$idx] eq "none") { - $tmp .= "&$arch\_default_req_none\n"; - } - elsif ($reqs[$idx] =~ /^new_reg_(.*)$/) { + $tmp2 .= "{\n"; + $tmp2 .= "\tarch_register_req_type_none,\n"; + $tmp2 .= "\tNULL, /* regclass */\n"; + $tmp2 .= "\tNULL, /* limit bitset */\n"; + $tmp2 .= "\t-1, /* same pos */\n"; + $tmp2 .= "\t-1 /* different pos */\n"; + $tmp2 .= "};\n"; + + push(@obst_req, $tmp2."\n"); + push(@obst_header_t, "extern const arch_register_req_t ${op}_reg_req_${inout}_${idx};\n"); + } elsif ($reqs[$idx] =~ /^new_reg_(.*)$/) { if (is_reg_class($1)) { - $tmp .= "&_".$op."_reg_req_$inout\_$idx\n"; $tmp2 .= "{\n"; - $tmp2 .= " {\n"; - $tmp2 .= " arch_register_req_type_should_be_different_from_all,\n"; - $tmp2 .= " &$arch\_reg_classes[CLASS_$arch\_".$1."],\n"; - $tmp2 .= " NULL, /* limit function */\n"; - $tmp2 .= " NULL, /* limit environment */\n"; - $tmp2 .= " NULL, /* same node */\n"; - $tmp2 .= " NULL /* different node */\n"; - $tmp2 .= " },\n"; - $tmp2 .= " 0,\n"; - $tmp2 .= " 0\n"; + $tmp2 .= "\tarch_register_req_type_should_be_different_from_all,\n"; + $tmp2 .= "\t&${arch}_reg_classes[CLASS_${arch}_$1],\n"; + $tmp2 .= "\tNULL, /* limit bitset */\n"; + $tmp2 .= "\t-1, /* same pos */\n"; + $tmp2 .= "\t-1 /* different pos */\n"; $tmp2 .= "};\n"; push(@obst_req, $tmp2."\n"); - push(@obst_header_all, "extern const $arch\_register_req_t _".$op."_reg_req_$inout\_$idx;\n"); - } - else { + push(@obst_header_t, "extern const arch_register_req_t ${op}_reg_req_${inout}_${idx};\n"); + } else { print STDERR "Invalid register class '$1' given in OUT requirement $idx for '$op'.\n"; } - } - elsif (is_reg_class($reqs[$idx])) { - $tmp .= "&$arch\_default_req_".$arch."_".$reqs[$idx]."\n"; - } - else { + } elsif (is_reg_class($reqs[$idx])) { + my $class = $reqs[$idx]; + $tmp2 .= "{\n"; + $tmp2 .= "\tarch_register_req_type_normal,\n"; + $tmp2 .= "\t&${arch}_reg_classes[CLASS_${arch}_${class}],\n"; + $tmp2 .= "\tNULL, /* limit bitset */\n"; + $tmp2 .= "\t-1, /* same pos */\n"; + $tmp2 .= "\t-1 /* different pos */\n"; + $tmp2 .= "};\n"; + + push(@obst_req, $tmp2."\n"); + push(@obst_header_t, "extern const arch_register_req_t ${op}_reg_req_${inout}_${idx};\n"); + } else { my @req_type_mask; my ($class, $has_limit, $same_pos, $different_pos) = build_subset_class_func($n, $op, $idx, (($inout eq "in") ? 1 : 0), $reqs[$idx]); @@ -461,31 +403,22 @@ sub generate_requirements { if ($different_pos == 666) { push(@req_type_mask, "arch_register_req_type_should_be_different_from_all"); undef $different_pos; - } - else { + } else { push(@req_type_mask, "arch_register_req_type_should_be_different"); } } - $tmp .= "&_".$op."_reg_req_$inout\_$idx\n"; $tmp2 .= "{\n"; - $tmp2 .= " {\n"; - $tmp2 .= " ".join(" | ", @req_type_mask).",\n"; - $tmp2 .= " &$arch\_reg_classes[CLASS_$arch\_".$class."],\n"; - $tmp2 .= " ".($has_limit ? "limit_reg_".$op."_$inout\_".$idx : "NULL").",\n"; - $tmp2 .= " NULL, /* limit environment */\n"; - $tmp2 .= " NULL, /* same node */\n"; - $tmp2 .= " NULL /* different node */\n"; - $tmp2 .= " },\n"; - $tmp2 .= " ".(defined($same_pos) ? $same_pos : "0").",\n"; - $tmp2 .= " ".(defined($different_pos) ? $different_pos : "0")."\n"; + $tmp2 .= "\t".join(" | ", @req_type_mask).",\n"; + $tmp2 .= "\t&${arch}_reg_classes[CLASS_${arch}_${class}],\n"; + $tmp2 .= "\t".($has_limit ? "limit_reg_${op}_${inout}_${idx}" : "NULL").",\n"; + $tmp2 .= "\t".(defined($same_pos) ? $same_pos : "-1").",\n"; + $tmp2 .= "\t".(defined($different_pos) ? $different_pos : "-1")."\n"; $tmp2 .= "};\n"; push(@obst_req, $tmp2."\n"); - push(@obst_header_all, "extern const $arch\_register_req_t _".$op."_reg_req_$inout\_$idx;\n"); + push(@obst_header_t, "extern const arch_register_req_t ${op}_reg_req_${inout}_${idx};\n"); } - - push(@obst_requirement_def, $tmp); } } @@ -537,7 +470,7 @@ sub build_subset_class_func { my @obst_init; my @obst_limits; my @obst_ignore; - + my @limit_array; # build function header my $n = shift; @@ -584,13 +517,11 @@ CHECK_REQS: foreach (@regs) { if (!defined($neg)) { $has_limit = 1; - push(@obst_init, " bs = bitset_set_all(bs); /* allow all register (negative constraints given) */\n"); } $_ = substr($_, 1); # skip '!' $neg = 1; - } - else { + } else { if (defined($neg) && $neg == 1) { # we have seen a negative constraint as first one but this one is positive # this doesn't make sense @@ -598,10 +529,7 @@ CHECK_REQS: foreach (@regs) { return (undef, undef, undef, undef); } - if (!defined($neg)) { - $has_limit = 1; - push(@obst_init, " bs = bitset_clear_all(bs); /* disallow all register (positive constraints given) */\n"); - } + $has_limit = 1; $neg = 0; } @@ -615,40 +543,63 @@ CHECK_REQS: foreach (@regs) { # set class if (!defined($class)) { $class = $temp; - } - elsif ($class ne $temp) { + } elsif ($class ne $temp) { # all registers must belong to the same class print STDERR "Registerclass mismatch. '$_' is not member of class '$class'.\n"; return (undef, undef, undef, undef); } - if ($neg == 1) { - $has_limit = 1; - push(@obst_limits, " bitset_clear(bs, ".get_reg_index($_)."); /* disallow $_ */\n"); - } - else { - $has_limit = 1; - push(@obst_limits, " bitset_set(bs, ".get_reg_index($_)."); /* allow $_ */\n"); - } + # calculate position inside the initializer bitfield (only 32 bits per + # element) + my $regidx = get_reg_index($_); + my $arrayp = $regidx / 32; + push(@{$limit_array[$arrayp]}, $_); } - my @cur_class = @{ $reg_classes{"$class"} }; - for (my $idx = 0; $idx <= $#cur_class; $idx++) { - if (defined($cur_class[$idx]{"type"}) && ($cur_class[$idx]{"type"} & 4)) { - push(@obst_ignore, " bitset_clear(bs, ".get_reg_index($cur_class[$idx]{"name"}).");"); - push(@obst_ignore, " /* disallow ignore reg ".$cur_class[$idx]{"name"}." */\n"); + # don't allow ignore regs in negative constraints + if($neg) { + my @cur_class = @{ $reg_classes{"$class"} }; + for (my $idx = 0; $idx <= $#cur_class; $idx++) { + if (defined($cur_class[$idx]{"type"}) && ($cur_class[$idx]{"type"} & 4)) { + my $reg = $cur_class[$idx]{"name"}; + my $regix = get_reg_index($reg); + my $arrayp = $regix / 32; + push(@{$limit_array[$arrayp]}, $reg); + } } } if ($has_limit == 1) { - push(@obst_header_all, "void limit_reg_".$op."_".($in ? "in" : "out")."_".$idx."(void *_unused, bitset_t *bs);\n"); - - push(@obst_limit_func, "/* limit the possible registers for ".($in ? "IN" : "OUT")." $idx at op $op */\n"); - push(@obst_limit_func, "void limit_reg_".$op."_".($in ? "in" : "out")."_".$idx."(void *_unused, bitset_t *bs) {\n"); - push(@obst_limit_func, @obst_init); - push(@obst_limit_func, @obst_ignore); - push(@obst_limit_func, @obst_limits); - push(@obst_limit_func, "}\n\n"); + push(@obst_limit_func, "static const unsigned limit_reg_${op}_".($in ? "in" : "out")."_${idx}[] = { "); + my $first = 1; + my $limitbitsetlen = $regclass2len{$class}; + my $limitarraylen = $limitbitsetlen / 32 + ($limitbitsetlen % 32 > 0 ? 1 : 0); + for(my $i = 0; $i < $limitarraylen; $i++) { + my $limitarraypart = $limit_array[$i]; + if($first) { + $first = 0; + } else { + push(@obst_limit_func, ", "); + } + my $temp; + if($neg) { + $temp = "0xFFFFFFFF"; + } + foreach my $reg (@{$limitarraypart}) { + if($neg) { + $temp .= " & ~"; + } elsif(defined($temp)) { + $temp .= " | "; + } + $temp .= "BIT(REG_".uc(${reg}).")"; + } + if(defined($temp)) { + push(@obst_limit_func, "${temp}"); + } else { + push(@obst_limit_func, "0"); + } + } + push(@obst_limit_func, " };\n"); } return ($class, $has_limit, $same_pos, $different_pos); -- 2.20.1