X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=015290a09249ac4a5774cab692a63e9d9573db96;hb=7ebe4f361f80ea154488f16ede0841f2aa752d1f;hp=c124a68f25a56830c6ebd6dfbd59449c9528b524;hpb=863d31d7a5c8210432fef88b30fc3e8353131538;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index c124a68f2..015290a09 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -1,7 +1,8 @@ /** - * This file implements the node emitter. - * @author Christian Wuerdig, Matthias Braun - * $Id$ + * @file + * @brief This file implements the node emitter. + * @author Christian Wuerdig, Matthias Braun + * @version $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -29,6 +30,7 @@ #include "../be_dbgout.h" #include "../beemitter.h" #include "../begnuas.h" +#include "../beirg_t.h" #include "ia32_emitter.h" #include "gen_ia32_emitter.h" @@ -38,17 +40,20 @@ #include "ia32_map_regs.h" #include "bearch_ia32_t.h" +DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;) + #define BLOCK_PREFIX ".L" #define SNPRINTF_BUF_LEN 128 -/* global arch_env for lc_printf functions */ -static const arch_env_t *arch_env = NULL; - /** * Returns the register at in position pos. */ -static const arch_register_t *get_in_reg(const ir_node *irn, int pos) { +static +const arch_register_t *get_in_reg(ia32_emit_env_t *env, const ir_node *irn, + int pos) +{ + const arch_env_t *arch_env = env->arch_env; ir_node *op; const arch_register_t *reg = NULL; @@ -85,9 +90,13 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos) { /** * Returns the register at out position pos. */ -static const arch_register_t *get_out_reg(const ir_node *irn, int pos) { - ir_node *proj; - const arch_register_t *reg = NULL; +static +const arch_register_t *get_out_reg(ia32_emit_env_t *env, const ir_node *irn, + int pos) +{ + const arch_env_t *arch_env = env->arch_env; + ir_node *proj; + const arch_register_t *reg = NULL; /* 1st case: irn is not of mode_T, so it has only */ /* one OUT register -> good */ @@ -118,7 +127,8 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) { /** * Returns an ident for the given tarval tv. */ -static ident *get_ident_for_tv(tarval *tv) { +static +ident *get_ident_for_tv(tarval *tv) { char buf[256]; tarval_snprintf(buf, sizeof(buf), tv); return new_id_from_str(buf); @@ -127,7 +137,8 @@ static ident *get_ident_for_tv(tarval *tv) { /** * Determine the gnu assembler suffix that indicates a mode */ -static char get_mode_suffix(const ir_mode *mode) { +static +char get_mode_suffix(const ir_mode *mode) { if(mode_is_float(mode)) { switch(get_mode_size_bits(mode)) { case 32: @@ -138,7 +149,7 @@ static char get_mode_suffix(const ir_mode *mode) { return 't'; } } else { - assert(mode_is_int(mode) || mode_is_reference(mode)); + assert(mode_is_int(mode) || mode_is_reference(mode) || mode_is_character(mode)); switch(get_mode_size_bits(mode)) { case 64: return 'q'; @@ -153,7 +164,8 @@ static char get_mode_suffix(const ir_mode *mode) { panic("Can't output mode_suffix for %+F\n", mode); } -static int produces_result(const ir_node *node) { +static +int produces_result(const ir_node *node) { return !(is_ia32_St(node) || is_ia32_Store8Bit(node) || is_ia32_CondJmp(node) || @@ -163,7 +175,9 @@ static int produces_result(const ir_node *node) { is_ia32_SwitchJmp(node)); } -static const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) { +static +const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, + const arch_register_t *reg) { switch(get_mode_size_bits(mode)) { case 8: return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg); @@ -177,7 +191,8 @@ static const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mod /** * 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 +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; @@ -207,7 +222,7 @@ static char *get_unique_label(char *buf, size_t buflen, const char *prefix) { void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos) { - const arch_register_t *reg = get_in_reg(node, pos); + const arch_register_t *reg = get_in_reg(env, node, pos); const char *reg_name = arch_register_get_name(reg); assert(pos < get_irn_arity(node)); @@ -217,7 +232,7 @@ void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int po } 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 arch_register_t *reg = get_out_reg(env, node, pos); const char *reg_name = arch_register_get_name(reg); be_emit_char(env, '%'); @@ -236,15 +251,20 @@ void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos) void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node) { tarval *tv; + ir_entity *ent; ident *id; + be_emit_char(env, '$'); + switch(get_ia32_immop_type(node)) { case ia32_ImmConst: tv = get_ia32_Immop_tarval(node); id = get_ident_for_tv(tv); break; case ia32_ImmSymConst: - id = get_ia32_Immop_symconst(node); + ent = get_ia32_Immop_symconst(node); + mark_entity_visited(ent); + id = get_entity_ld_ident(ent); break; default: assert(0); @@ -267,7 +287,8 @@ void ia32_emit_x87_mode_suffix(ia32_emit_env_t *env, const ir_node *node) ia32_emit_mode_suffix(env, mode); } -static char get_xmm_mode_suffix(ir_mode *mode) +static +char get_xmm_mode_suffix(ir_mode *mode) { assert(mode_is_float(mode)); switch(get_mode_size_bits(mode)) { @@ -307,7 +328,8 @@ void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode) } } -static void ia32_emit_function_object(ia32_emit_env_t *env, const char *name) +static +void ia32_emit_function_object(ia32_emit_env_t *env, const char *name) { switch (be_gas_flavour) { case GAS_FLAVOUR_NORMAL: @@ -327,7 +349,8 @@ static void ia32_emit_function_object(ia32_emit_env_t *env, const char *name) } } -static void ia32_emit_function_size(ia32_emit_env_t *env, const char *name) +static +void ia32_emit_function_size(ia32_emit_env_t *env, const char *name) { switch (be_gas_flavour) { case GAS_FLAVOUR_NORMAL: @@ -352,14 +375,13 @@ 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)) { - be_emit_char(env, '$'); ia32_emit_immediate(env, node); be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 2); } else { - const arch_register_t *in1 = get_in_reg(node, 2); - const arch_register_t *in2 = get_in_reg(node, 3); - const arch_register_t *out = produces_result(node) ? get_out_reg(node, 0) : NULL; + const arch_register_t *in1 = get_in_reg(env, node, 2); + const arch_register_t *in2 = get_in_reg(env, node, 3); + const arch_register_t *out = produces_result(node) ? get_out_reg(env, node, 0) : NULL; const arch_register_t *in; const char *in_name; @@ -379,29 +401,25 @@ void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node) { } break; case ia32_AddrModeS: + ia32_emit_am(env, node); + be_emit_cstring(env, ", "); 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); - be_emit_cstring(env, ", $"); ia32_emit_immediate(env, node); } else if (produces_result(node)) { - ia32_emit_am(env, node); - be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - ia32_emit_am(env, node); - be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 2); } break; case ia32_AddrModeD: if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { - be_emit_char(env, '$'); ia32_emit_immediate(env, node); 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); + const arch_register_t *in1 = get_in_reg(env, node, + get_irn_arity(node) == 5 ? 3 : 2); ir_mode *mode = get_ia32_ls_mode(node); const char *in_name; @@ -464,7 +482,6 @@ 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)) { - be_emit_char(env, '$'); ia32_emit_immediate(env, node); } else { if (is_ia32_Mul(node) || is_ia32_IMul1OP(node)) { @@ -494,21 +511,33 @@ 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) { ia32_am_flavour_t am_flav = get_ia32_am_flavour(node); - ident *id = get_ia32_am_sc(node); + ir_entity *ent = get_ia32_am_sc(node); int offs = get_ia32_am_offs_int(node); /* just to be sure... */ assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL); /* emit offset */ - if (id != NULL) { + if (ent != NULL) { + ident *id; + + mark_entity_visited(ent); + id = get_entity_ld_ident(ent); if (is_ia32_am_sc_sign(node)) be_emit_char(env, '-'); be_emit_ident(env, id); + + if(get_entity_owner(ent) == get_tls_type()) { + if (get_entity_visibility(ent) == visibility_external_allocated) { + be_emit_cstring(env, "@INDNTPOFF"); + } else { + be_emit_cstring(env, "@NTPOFF"); + } + } } if(offs != 0) { - if(id != NULL) { + if(ent != NULL) { be_emit_irprintf(env->emit, "%+d", offs); } else { be_emit_irprintf(env->emit, "%d", offs); @@ -560,7 +589,8 @@ struct cmp2conditon_t { /* * positive conditions for signed compares */ -static const struct cmp2conditon_t cmp2condition_s[] = { +static +const struct cmp2conditon_t cmp2condition_s[] = { { NULL, pn_Cmp_False }, /* always false */ { "e", pn_Cmp_Eq }, /* == */ { "l", pn_Cmp_Lt }, /* < */ @@ -582,7 +612,8 @@ static const struct cmp2conditon_t cmp2condition_s[] = { /* * positive conditions for unsigned compares */ -static const struct cmp2conditon_t cmp2condition_u[] = { +static +const struct cmp2conditon_t cmp2condition_u[] = { { NULL, pn_Cmp_False }, /* always false */ { "e", pn_Cmp_Eq }, /* == */ { "b", pn_Cmp_Lt }, /* < */ @@ -596,7 +627,8 @@ static const struct cmp2conditon_t cmp2condition_u[] = { /* * returns the condition code */ -static const char *get_cmp_suffix(int cmp_code) +static +const char *get_cmp_suffix(int cmp_code) { assert( (cmp2condition_s[cmp_code & 15].num) == (cmp_code & 15)); assert( (cmp2condition_u[cmp_code & 7].num) == (cmp_code & 7)); @@ -617,18 +649,26 @@ void ia32_emit_cmp_suffix(ia32_emit_env_t *env, long pnc) /** * Returns the target block for a control flow node. */ -static ir_node *get_cfop_target_block(const ir_node *irn) { +static +ir_node *get_cfop_target_block(const ir_node *irn) { return get_irn_link(irn); } +static +void ia32_emit_block_name(ia32_emit_env_t *env, const ir_node *block) +{ + be_emit_cstring(env, BLOCK_PREFIX); + be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block)); +} + /** * Returns the target label for a control flow node. */ +static void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) { ir_node *block = get_cfop_target_block(node); - be_emit_cstring(env, BLOCK_PREFIX); - be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block)); + ia32_emit_block_name(env, block); } /** Return the next block in Block schedule */ @@ -639,7 +679,8 @@ static ir_node *next_blk_sched(const ir_node *block) { /** * Returns the Proj with projection number proj and NOT mode_M */ -static ir_node *get_proj(const ir_node *node, long proj) { +static +ir_node *get_proj(const ir_node *node, long proj) { const ir_edge_t *edge; ir_node *src; @@ -661,8 +702,9 @@ static ir_node *get_proj(const ir_node *node, long proj) { /** * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false) */ -static void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, - ir_mode *mode, long pnc) { +static +void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode, + long pnc) { const ir_node *proj_true; const ir_node *proj_false; const ir_node *block; @@ -711,7 +753,7 @@ static void finish_CondJmp(ia32_emit_env_t *env, const ir_node *node, ia32_emit_cfop_target(env, proj_false); be_emit_finish_line_gas(env, proj_false); } else { - be_emit_cstring(env, "\t/* fallthrough to"); + be_emit_cstring(env, "\t/* fallthrough to "); ia32_emit_cfop_target(env, proj_false); be_emit_cstring(env, " */"); be_emit_finish_line_gas(env, proj_false); @@ -721,7 +763,8 @@ 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) { +static +void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tcmp "); ia32_emit_binop(env, node); be_emit_finish_line_gas(env, node); @@ -732,16 +775,18 @@ static void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code for conditional jump with two variables. */ -static void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_CondJmp(ia32_emit_env_t *env, const ir_node *node) { CondJmp_emitter(env, node); } /** * Emits code for conditional test and jump. */ -static void TestJmp_emitter(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)) { - be_emit_cstring(env, "\ttest $"); + be_emit_cstring(env, "\ttest "); ia32_emit_immediate(env, node); be_emit_cstring(env, ", "); ia32_emit_source_register(env, node, 0); @@ -759,18 +804,21 @@ static void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code for conditional test and jump with two variables. */ -static void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) { TestJmp_emitter(env, node); } -static void emit_ia32_CJmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_CJmp(ia32_emit_env_t *env, const ir_node *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) { +static +void emit_ia32_CJmpAM(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "/* omitted redundant test/cmp */"); be_emit_finish_line_gas(env, node); @@ -780,7 +828,8 @@ 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) { +static +void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tucomi"); ia32_emit_xmm_mode_suffix(env, node); be_emit_char(env, ' '); @@ -793,7 +842,8 @@ static void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code for conditional x87 floating point jump with two variables. */ -static void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) { ia32_attr_t *attr = get_ia32_attr(node); const char *reg = attr->x87[1]->name; long pnc = get_ia32_pncode(node); @@ -834,7 +884,8 @@ static void emit_ia32_x87CondJmp(ia32_emit_env_t *env, const ir_node *node) { finish_CondJmp(env, node, mode_E, pnc); } -static void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { +static +void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { long pnc = get_ia32_pncode(node); int is_PsiCondCMov = is_ia32_PsiCondCMov(node); int idx_left = 2 - is_PsiCondCMov; @@ -914,19 +965,23 @@ static void CMov_emitter(ia32_emit_env_t *env, const ir_node *node) { be_emit_finish_line_gas(env, node); } -static void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) { CMov_emitter(env, node); } -static void emit_ia32_PsiCondCMov(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_PsiCondCMov(ia32_emit_env_t *env, const ir_node *node) { CMov_emitter(env, node); } -static void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) { CMov_emitter(env, node); } -static void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode) { +static +void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode) { int pnc = get_ia32_pncode(node); const char *reg8bit; const arch_register_t *out; @@ -962,19 +1017,23 @@ static void Set_emitter(ia32_emit_env_t *env, const ir_node *node, ir_mode *mode be_emit_finish_line_gas(env, node); } -static void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_CmpSet(ia32_emit_env_t *env, const ir_node *node) { Set_emitter(env, node, get_irn_mode(get_irn_n(node, 2))); } -static void emit_ia32_PsiCondSet(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_PsiCondSet(ia32_emit_env_t *env, const ir_node *node) { Set_emitter(env, node, get_irn_mode(get_irn_n(node, 0))); } -static void emit_ia32_xCmpSet(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_xCmpSet(ia32_emit_env_t *env, const ir_node *node) { Set_emitter(env, node, get_irn_mode(get_irn_n(node, 2))); } -static void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_xCmp(ia32_emit_env_t *env, const ir_node *node) { int sse_pnc = -1; long pnc = get_ia32_pncode(node); long unord = pnc & pn_Cmp_Uo; @@ -1085,7 +1144,8 @@ typedef struct _jmp_tbl_t { /** * Compare two variables of type branch_t. Used to sort all switch cases */ -static int ia32_cmp_branch_t(const void *a, const void *b) { +static +int ia32_cmp_branch_t(const void *a, const void *b) { branch_t *b1 = (branch_t *)a; branch_t *b2 = (branch_t *)b; @@ -1100,7 +1160,8 @@ static int ia32_cmp_branch_t(const void *a, const void *b) { * possible otherwise a cmp-jmp cascade). Port from * cggg ia32 backend */ -static void emit_ia32_SwitchJmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_SwitchJmp(ia32_emit_env_t *env, const ir_node *node) { unsigned long interval; int last_value, i; long pnc; @@ -1206,7 +1267,8 @@ static void emit_ia32_SwitchJmp(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code for a unconditional jump. */ -static void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_Jmp(ia32_emit_env_t *env, const ir_node *node) { ir_node *block, *next_block; /* for now, the code works for scheduled and non-schedules blocks */ @@ -1239,7 +1301,8 @@ 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) { +static +void emit_CopyB_prolog(ia32_emit_env_t *env, int rem) { be_emit_cstring(env, "\tcld"); be_emit_finish_line_gas(env, NULL); @@ -1264,7 +1327,8 @@ static void emit_CopyB_prolog(ia32_emit_env_t *env, int rem) { /** * Emit rep movsd instruction for memcopy. */ -static void emit_ia32_CopyB(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_CopyB(ia32_emit_env_t *env, const ir_node *node) { tarval *tv = get_ia32_Immop_tarval(node); int rem = get_tarval_long(tv); @@ -1277,7 +1341,8 @@ static void emit_ia32_CopyB(ia32_emit_env_t *env, const ir_node *node) { /** * Emits unrolled memcopy. */ -static void emit_ia32_CopyB_i(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_CopyB_i(ia32_emit_env_t *env, const ir_node *node) { tarval *tv = get_ia32_Immop_tarval(node); int size = get_tarval_long(tv); @@ -1305,7 +1370,8 @@ static void emit_ia32_CopyB_i(ia32_emit_env_t *env, const ir_node *node) { /** * Emit code for conversions (I, FP), (FP, I) and (FP, FP). */ -static void emit_ia32_Conv_with_FP(ia32_emit_env_t *env, const ir_node *node) { +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); @@ -1350,22 +1416,26 @@ static void emit_ia32_Conv_with_FP(ia32_emit_env_t *env, const ir_node *node) { be_emit_finish_line_gas(env, node); } -static void emit_ia32_Conv_I2FP(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_Conv_I2FP(ia32_emit_env_t *env, const ir_node *node) { emit_ia32_Conv_with_FP(env, node); } -static void emit_ia32_Conv_FP2I(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_Conv_FP2I(ia32_emit_env_t *env, const ir_node *node) { emit_ia32_Conv_with_FP(env, node); } -static void emit_ia32_Conv_FP2FP(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_Conv_FP2FP(ia32_emit_env_t *env, const ir_node *node) { emit_ia32_Conv_with_FP(env, node); } /** * Emits code for an Int conversion. */ -static void emit_ia32_Conv_I2I(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_Conv_I2I(ia32_emit_env_t *env, const ir_node *node) { const char *sign_suffix; ir_mode *smaller_mode = get_ia32_ls_mode(node); int smaller_bits = get_mode_size_bits(smaller_mode); @@ -1386,8 +1456,8 @@ static void emit_ia32_Conv_I2I(ia32_emit_env_t *env, const ir_node *node) { switch(get_ia32_op_type(node)) { case ia32_Normal: - in_reg = get_in_reg(node, 2); - out_reg = get_out_reg(node, 0); + in_reg = get_in_reg(env, node, 2); + out_reg = get_out_reg(env, node, 0); if (REGS_ARE_EQUAL(in_reg, &ia32_gp_regs[REG_EAX]) && REGS_ARE_EQUAL(out_reg, in_reg) && @@ -1458,11 +1528,13 @@ void emit_ia32_Conv_I2I8Bit(ia32_emit_env_t *env, const ir_node *node) { /** * Emits a backend call */ -static void emit_be_Call(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); be_emit_cstring(env, "\tcall "); if (ent) { + mark_entity_visited(ent); be_emit_string(env, get_entity_ld_name(ent)); } else { be_emit_char(env, '*'); @@ -1474,7 +1546,8 @@ static void emit_be_Call(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code to increase stack pointer. */ -static void emit_be_IncSP(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_be_IncSP(ia32_emit_env_t *env, const ir_node *node) { int offs = be_get_IncSP_offset(node); if (offs == 0) @@ -1495,7 +1568,8 @@ static void emit_be_IncSP(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code to set stack pointer. */ -static void emit_be_SetSP(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_be_SetSP(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tmovl "); ia32_emit_source_register(env, node, 2); be_emit_cstring(env, ", "); @@ -1506,14 +1580,18 @@ static void emit_be_SetSP(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code for Copy/CopyKeep. */ -static void Copy_emitter(ia32_emit_env_t *env, const ir_node *node, const ir_node *op) { +static +void Copy_emitter(ia32_emit_env_t *env, const ir_node *node, const ir_node *op) +{ const arch_env_t *aenv = env->arch_env; + ir_mode *mode; if (REGS_ARE_EQUAL(arch_get_irn_register(aenv, node), arch_get_irn_register(aenv, op)) || arch_register_type_is(arch_get_irn_register(aenv, op), virtual)) return; - if (mode_is_float(get_irn_mode(node))) { + mode = get_irn_mode(node); + if (mode == mode_E) { be_emit_cstring(env, "\tmovsd "); ia32_emit_source_register(env, node, 0); be_emit_cstring(env, ", "); @@ -1527,18 +1605,21 @@ static void Copy_emitter(ia32_emit_env_t *env, const ir_node *node, const ir_nod be_emit_finish_line_gas(env, node); } -static void emit_be_Copy(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_be_Copy(ia32_emit_env_t *env, const ir_node *node) { Copy_emitter(env, node, be_get_Copy_op(node)); } -static void emit_be_CopyKeep(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_be_CopyKeep(ia32_emit_env_t *env, const ir_node *node) { Copy_emitter(env, node, be_get_CopyKeep_op(node)); } /** * Emits code for exchange. */ -static void emit_be_Perm(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_be_Perm(ia32_emit_env_t *env, const ir_node *node) { const arch_register_t *in1, *in2; const arch_register_class_t *cls1, *cls2; @@ -1551,26 +1632,11 @@ static void emit_be_Perm(ia32_emit_env_t *env, const ir_node *node) { assert(cls1 == cls2 && "Register class mismatch at Perm"); if (cls1 == &ia32_reg_classes[CLASS_ia32_gp]) { -#if 0 - if(emit_env->isa->opt_arch == arch_athlon) { - // xchg commands are Vector path on athlons and therefore stall the DirectPath pipeline - // it is often beneficial to use the 3 xor trick instead of an xchg - cmnt_buf[0] = 0; - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %1S, %2S", irn, irn); - IA32_DO_EMIT(irn); - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %2S, %1S", irn, irn); - IA32_DO_EMIT(irn); - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %1S, %2S", irn, irn); - } else { -#endif - be_emit_cstring(env, "\txchg "); - ia32_emit_source_register(env, node, 1); - be_emit_cstring(env, ", "); - ia32_emit_source_register(env, node, 0); - be_emit_finish_line_gas(env, node); -#if 0 - } -#endif + be_emit_cstring(env, "\txchg "); + ia32_emit_source_register(env, node, 1); + be_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + be_emit_finish_line_gas(env, node); } else if (cls1 == &ia32_reg_classes[CLASS_ia32_xmm]) { be_emit_cstring(env, "\txorpd "); ia32_emit_source_register(env, node, 1); @@ -1599,11 +1665,12 @@ static void emit_be_Perm(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code for Constant loading. */ -static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { +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) { - be_emit_cstring(env, "\tmovl $"); + be_emit_cstring(env, "\tmovl "); ia32_emit_immediate(env, node); be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); @@ -1622,7 +1689,7 @@ static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); } else { - be_emit_cstring(env, "\tmovl $"); + be_emit_cstring(env, "\tmovl "); ia32_emit_immediate(env, node); be_emit_cstring(env, ", "); ia32_emit_dest_register(env, node, 0); @@ -1634,18 +1701,21 @@ static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { /** * Emits code to load the TLS base */ -static void emit_ia32_LdTls(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_ia32_LdTls(ia32_emit_env_t *env, const ir_node *node) { be_emit_cstring(env, "\tmovl %gs:0, "); ia32_emit_dest_register(env, node, 0); be_emit_finish_line_gas(env, node); } -static void emit_be_Return(ia32_emit_env_t *env, const ir_node *node) { +static +void emit_be_Return(ia32_emit_env_t *env, const ir_node *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) { +static +void emit_Nothing(ia32_emit_env_t *env, const ir_node *node) { } @@ -1663,7 +1733,8 @@ static void emit_Nothing(ia32_emit_env_t *env, const ir_node *node) { * Enters the emitter functions for handled nodes into the generic * pointer of an opcode. */ -static void ia32_register_emitters(void) { +static +void ia32_register_emitters(void) { #define IA32_EMIT2(a,b) op_ia32_##a->ops.generic = (op_func)emit_ia32_##b #define IA32_EMIT(a) IA32_EMIT2(a,a) @@ -1741,7 +1812,8 @@ static unsigned num = -1; /** * Emit the debug support for node node. */ -static void ia32_emit_dbg(ia32_emit_env_t *env, const ir_node *node) { +static +void ia32_emit_dbg(ia32_emit_env_t *env, const ir_node *node) { dbg_info *db = get_irn_dbg_info(node); unsigned lineno; const char *fname = be_retrieve_dbg_info(db, &lineno); @@ -1773,11 +1845,11 @@ typedef void (*emit_func_ptr) (ia32_emit_env_t *, const ir_node *); /** * Emits code for a node. */ -static void ia32_emit_node(ia32_emit_env_t *env, const ir_node *node) { +static +void ia32_emit_node(ia32_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", node)); + DBG((dbg, LEVEL_1, "emitting code for %+F\n", node)); if (op->ops.generic) { emit_func_ptr func = (emit_func_ptr) op->ops.generic; @@ -1792,7 +1864,8 @@ 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) { +static +void ia32_emit_alignment(ia32_emit_env_t *env, unsigned align, unsigned skip) { be_emit_cstring(env, "\t.p2align "); be_emit_irprintf(env->emit, "%u,,%u\n", align, skip); be_emit_write_line(env); @@ -1801,7 +1874,8 @@ static void ia32_emit_alignment(ia32_emit_env_t *env, unsigned align, unsigned s /** * Emits gas alignment directives for Functions depended on cpu architecture. */ -static void ia32_emit_align_func(ia32_emit_env_t *env, cpu_support cpu) { +static +void ia32_emit_align_func(ia32_emit_env_t *env, cpu_support cpu) { unsigned align; unsigned maximum_skip; @@ -1825,7 +1899,8 @@ static void ia32_emit_align_func(ia32_emit_env_t *env, cpu_support cpu) { /** * Emits gas alignment directives for Labels depended on cpu architecture. */ -static void ia32_emit_align_label(ia32_emit_env_t *env, cpu_support cpu) { +static +void ia32_emit_align_label(ia32_emit_env_t *env, cpu_support cpu) { unsigned align; unsigned maximum_skip; switch (cpu) { @@ -1845,11 +1920,21 @@ static void ia32_emit_align_label(ia32_emit_env_t *env, cpu_support cpu) { ia32_emit_alignment(env, align, maximum_skip); } -static int is_first_loop_block(ia32_emit_env_t *env, ir_node *block, ir_node *prev_block) { - ir_exec_freq *exec_freq = env->cg->birg->exec_freq; - double block_freq, prev_freq; +/** + * Test wether a block should be aligned. + * For cpus in the P4/Athlon class it is usefull to align jump labels to + * 16 bytes. However we should only do that if the alignment nops before the + * label aren't executed more often than we have jumps to the label. + */ +static +int should_align_block(ia32_emit_env_t *env, ir_node *block, ir_node *prev) { static const double DELTA = .0001; - cpu_support cpu = env->isa->opt_arch; + ir_exec_freq *exec_freq = env->cg->birg->exec_freq; + double block_freq; + double prev_freq = 0; /**< execfreq of the fallthrough block */ + double jmp_freq = 0; /**< execfreq of all non-fallthrough blocks */ + cpu_support cpu = env->isa->opt_arch; + int i, n_cfgpreds; if(exec_freq == NULL) return 0; @@ -1857,88 +1942,74 @@ static int is_first_loop_block(ia32_emit_env_t *env, ir_node *block, ir_node *pr return 0; block_freq = get_block_execfreq(exec_freq, block); - prev_freq = get_block_execfreq(exec_freq, prev_block); - - if(block_freq < DELTA || prev_freq < DELTA) + if(block_freq < DELTA) return 0; - block_freq /= prev_freq; + n_cfgpreds = get_Block_n_cfgpreds(block); + for(i = 0; i < n_cfgpreds; ++i) { + ir_node *pred = get_Block_cfgpred_block(block, i); + double pred_freq = get_block_execfreq(exec_freq, pred); + + if(pred == prev) { + assert(prev_freq == 0); + prev_freq += pred_freq; + } else { + jmp_freq += pred_freq; + } + } + + if(prev_freq < DELTA && !(jmp_freq < DELTA)) + return 1; + + jmp_freq /= prev_freq; switch (cpu) { case arch_athlon: case arch_athlon_64: case arch_k6: - return block_freq > 3; + return jmp_freq > 3; default: - break; + return jmp_freq > 2; } - - return block_freq > 2; } -/** - * Walks over the nodes in a block connected by scheduling edges - * and emits code for each node. - */ -static void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_block) { - ir_graph *irg = get_irn_irg(block); - ir_node *start_block = get_irg_start_block(irg); - int need_label = 1; - const ir_node *node; - int i; - - assert(is_Block(block)); - - if (block == start_block) +static +void ia32_emit_block_header(ia32_emit_env_t *env, ir_node *block, ir_node *prev) +{ + int n_cfgpreds; + int need_label; + int i, arity; + ir_exec_freq *exec_freq = env->cg->birg->exec_freq; + + need_label = 1; + n_cfgpreds = get_Block_n_cfgpreds(block); + if (n_cfgpreds == 0) { need_label = 0; - - if (need_label && get_irn_arity(block) == 1) { - ir_node *pred_block = get_Block_cfgpred_block(block, 0); - - if (pred_block == last_block && get_irn_n_edges_kind(pred_block, EDGE_KIND_BLOCK) <= 2) + } else if (n_cfgpreds == 1) { + ir_node *pred = get_Block_cfgpred(block, 0); + ir_node *pred_block = get_nodes_block(pred); + + /* we don't need labels for fallthrough blocks, however switch-jmps + * are no fallthoughs */ + if(pred_block == prev && + !(is_Proj(pred) && is_ia32_SwitchJmp(get_Proj_pred(pred)))) { need_label = 0; - } - - /* special case: if one of our cfg preds is a switch-jmp we need a label, */ - /* otherwise there might be jump table entries jumping to */ - /* non-existent (omitted) labels */ - for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) { - ir_node *pred = get_Block_cfgpred(block, i); - - if (is_Proj(pred)) { - assert(get_irn_mode(pred) == mode_X); - if (is_ia32_SwitchJmp(get_Proj_pred(pred))) { - need_label = 1; - break; - } + } else { + need_label = 1; } + } else { + need_label = 1; } - if (need_label) { - int i, arity; - int align = 1; - ir_exec_freq *exec_freq = env->cg->birg->exec_freq; - - /* align the loop headers */ - if (! is_first_loop_block(env, block, last_block)) { - /* align blocks where the previous block has no fallthrough */ - arity = get_irn_arity(block); - - for (i = 0; i < arity; ++i) { - ir_node *predblock = get_Block_cfgpred_block(block, i); - - if (predblock == last_block) { - align = 0; - break; - } - } - } + if (should_align_block(env, block, prev)) { + assert(need_label); + ia32_emit_align_label(env, env->isa->opt_arch); + } - if (align) - ia32_emit_align_label(env, env->isa->opt_arch); + if(need_label) { + ia32_emit_block_name(env, block); + be_emit_char(env, ':'); - 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:"); @@ -1950,11 +2021,28 @@ static void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_b } if (exec_freq != NULL) { - be_emit_irprintf(env->emit, " freq: %f", get_block_execfreq(exec_freq, block)); + be_emit_irprintf(env->emit, " freq: %f", + get_block_execfreq(exec_freq, block)); } be_emit_cstring(env, " */\n"); - be_emit_write_line(env); + } else { + be_emit_cstring(env, "\t/* "); + ia32_emit_block_name(env, block); + be_emit_cstring(env, ": */\n"); } + be_emit_write_line(env); +} + +/** + * Walks over the nodes in a block connected by scheduling edges + * and emits code for each node. + */ +static +void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_block) +{ + const ir_node *node; + + ia32_emit_block_header(env, block, last_block); /* emit the contents of the block */ ia32_emit_dbg(env, block); @@ -1966,7 +2054,8 @@ 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) { +static +void ia32_emit_func_prolog(ia32_emit_env_t *env, ir_graph *irg) { 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; @@ -1991,7 +2080,8 @@ static void ia32_emit_func_prolog(ia32_emit_env_t *env, ir_graph *irg) { /** * Emits code for function end */ -static void ia32_emit_func_epilog(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; @@ -2005,7 +2095,8 @@ static void ia32_emit_func_epilog(ia32_emit_env_t *env, ir_graph *irg) { * Block-walker: * Sets labels for control flow nodes (jump target) */ -static void ia32_gen_labels(ir_node *block, void *data) { +static +void ia32_gen_labels(ir_node *block, void *data) { ir_node *pred; int n = get_Block_n_cfgpreds(block); @@ -2028,10 +2119,6 @@ void ia32_gen_routine(ia32_code_gen_t *cg, ir_graph *irg) { env.emit = &env.isa->emit; env.arch_env = cg->arch_env; env.cg = cg; - FIRM_DBG_REGISTER(env.mod, "firm.be.ia32.emitter"); - - /* set the global arch_env (needed by print hooks) */ - arch_env = cg->arch_env; ia32_register_emitters(); @@ -2054,3 +2141,8 @@ void ia32_gen_routine(ia32_code_gen_t *cg, ir_graph *irg) { ia32_emit_func_epilog(&env, irg); } + +void ia32_init_emitter(void) +{ + FIRM_DBG_REGISTER(dbg, "firm.be.ia32.emitter"); +}