X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=fb11964d7f57e986827fd28e223a8cd3dff899a2;hb=3bf79be6379b877beb90b9bd6ea285b2d928dbd8;hp=5548106eadf450d59e0ec6e064bfc4d610114330;hpb=aa457045478abd5c3d8f7791d2fbbd33aafa6ec8;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 5548106ea..fb11964d7 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -23,6 +23,8 @@ #include "../besched_t.h" #include "../benode_t.h" +#include "../beabi.h" +#include "../be_dbgout.h" #include "ia32_emitter.h" #include "gen_ia32_emitter.h" @@ -49,10 +51,20 @@ 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.text" + ".section\t.text", + ".section\t.data", + ".section\t.rodata", + ".section\t.text", + ".section\t.tbss,\"awT\",@nobits", + ".section\t.ctors,\"aw\",@progbits" }, { - ".section\t.text", ".section\t.data", ".section .rdata,\"dr\"", ".section\t.text" + ".section\t.text", + ".section\t.data", + ".section .rdata,\"dr\"", + ".section\t.text", + ".section\t.tbss,\"awT\",@nobits", + ".section\t.ctors,\"aw\",@progbits" } }; @@ -69,6 +81,8 @@ void ia32_switch_section(FILE *F, section_t sec) { 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; @@ -820,57 +834,59 @@ static ir_node *get_proj(const ir_node *irn, long proj) { * Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false) */ static void finish_CondJmp(FILE *F, const ir_node *irn, ir_mode *mode) { - const ir_node *proj1, *proj2 = NULL; - const ir_node *block, *next_bl = NULL; + const ir_node *proj_true; + const ir_node *proj_false; + const ir_node *block; + const ir_node *next_block; char buf[SNPRINTF_BUF_LEN]; char cmd_buf[SNPRINTF_BUF_LEN]; char cmnt_buf[SNPRINTF_BUF_LEN]; int is_unsigned; + int pnc; + int flipped = 0; /* get both Proj's */ - proj1 = get_proj(irn, pn_Cond_true); - assert(proj1 && "CondJmp without true Proj"); + proj_true = get_proj(irn, pn_Cond_true); + assert(proj_true && "CondJmp without true Proj"); - proj2 = get_proj(irn, pn_Cond_false); - assert(proj2 && "CondJmp without false Proj"); + proj_false = get_proj(irn, pn_Cond_false); + assert(proj_false && "CondJmp without false Proj"); + + pnc = get_ia32_pncode(irn); /* for now, the code works for scheduled and non-schedules blocks */ block = get_nodes_block(irn); /* we have a block schedule */ - next_bl = next_blk_sched(block); + next_block = next_blk_sched(block); - if (get_cfop_target_block(proj1) == next_bl) { + if (get_cfop_target_block(proj_true) == next_block) { /* exchange both proj's so the second one can be omitted */ - const ir_node *t = proj1; - proj1 = proj2; - proj2 = t; + const ir_node *t = proj_true; + proj_true = proj_false; + proj_false = t; + + flipped = 1; + pnc = get_negated_pnc(pnc, mode); } /* the first Proj must always be created */ is_unsigned = mode_is_float(mode) || ! mode_is_signed(mode); - if (get_Proj_proj(proj1) == pn_Cond_true) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s", - get_cmp_suffix(get_ia32_pncode(irn), is_unsigned), - get_cfop_target(proj1, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == TRUE */"); - } - else { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s", - get_cmp_suffix(get_negated_pnc(get_ia32_pncode(irn), mode), is_unsigned), - get_cfop_target(proj1, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* cmp(a, b) == FALSE */"); - } + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s", + get_cmp_suffix(pnc, is_unsigned), + get_cfop_target(proj_true, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* %s(a, b) %s*/", + get_pnc_string(pnc), flipped ? "(was flipped)" : ""); IA32_DO_EMIT(irn); /* the second Proj might be a fallthrough */ - if (get_cfop_target_block(proj2) != next_bl) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(proj2, buf)); + if (get_cfop_target_block(proj_false) != next_block) { + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(proj_false, buf)); snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* otherwise */"); } else { cmd_buf[0] = '\0'; - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough %s */", get_cfop_target(proj2, buf)); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough %s */", get_cfop_target(proj_false, buf)); } IA32_DO_EMIT(irn); } @@ -1000,7 +1016,7 @@ static void emit_ia32_x87CondJmp(ir_node *irn, ia32_emit_env_t *env) { if (reverse) set_ia32_pncode(irn, (long)get_inversed_pnc(get_ia32_pncode(irn))); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "%s %%%s", instr, reg); + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "%s %s%s", instr, reg[0] == '\0' ? "" : "%", reg); lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); IA32_DO_EMIT(irn); lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fnstsw %%ax", irn); @@ -1042,7 +1058,7 @@ static void CMov_emitter(ir_node *irn, ia32_emit_env_t *env) { } else if (is_PsiCondCMov) { /* omit compare because flags are already set by And/Or */ - snprintf(cmd_buf, SNPRINTF_BUF_LEN, " "); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "test %1S, %1S", irn, irn); } else { assert(0 && "unsupported CMov"); @@ -1059,17 +1075,25 @@ static void CMov_emitter(ir_node *irn, ia32_emit_env_t *env) { set_irn_n(irn, idx_left, get_irn_n(irn, idx_right)); set_irn_n(irn, idx_right, t); - cmp_suffix = get_cmp_suffix(get_inversed_pnc(get_ia32_pncode(irn)), is_unsigned); + cmp_suffix = get_cmp_suffix(get_negated_pnc(get_ia32_pncode(irn), get_irn_mode(irn)), is_unsigned); } else { /* out is different from in: need copy default -> out */ - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %4S", irn, irn); + if (is_PsiCondCMov) + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %3S", irn, irn); + else + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %4S", irn, irn); + lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* copy default -> out */" ); IA32_DO_EMIT(irn); } - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmov%s %1D, %3S", cmp_suffix, irn, irn); + if (is_PsiCondCMov) + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmov%s %1D, %2S", cmp_suffix, irn, irn); + else + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmov%s %1D, %3S", cmp_suffix, irn, irn); + lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* condition is true case */" ); IA32_DO_EMIT(irn); } @@ -1574,8 +1598,10 @@ static void emit_ia32_Conv_I2I(const ir_node *irn, ia32_emit_env_t *emit_env) { conv_cmd = "cbw"; else if (n == 16 || m == 16) conv_cmd = "cwde"; - else + else { + printf("%d -> %d unsupported\n", n, m); assert(0 && "unsupported Conv_I2I"); + } } switch(get_ia32_op_type(irn)) { @@ -1765,22 +1791,24 @@ static void emit_ia32_Const(const ir_node *n, ia32_emit_env_t *env) { FILE *F = env->out; char cmd_buf[256], cmnt_buf[256]; const lc_arg_env_t *arg_env = ia32_get_arg_env(); - - if (get_ia32_Immop_tarval(n) == get_tarval_null(get_irn_mode(n))) { - const char *instr = "xor"; - if (env->isa->opt_arch == arch_pentium_4) { - /* P4 prefers sub r, r, others xor r, r */ - instr = "sub"; - } - lc_esnprintf(arg_env, cmd_buf, 256, "%s %1D, %1D ", instr, n, n); - lc_esnprintf(arg_env, cmnt_buf, 256, "/* optimized mov 0 to register */"); - } - else { - if (get_ia32_op_type(n) == ia32_SymConst) { - lc_esnprintf(arg_env, cmd_buf, 256, "mov %1D, OFFSET FLAT:%C ", n, n); - lc_esnprintf(arg_env, cmnt_buf, 256, "/* Move address of SymConst into register */"); - } - else { + ir_mode *mode = get_irn_mode(n); + tarval *tv = get_ia32_Immop_tarval(n); + + if (get_ia32_op_type(n) == ia32_SymConst) { + lc_esnprintf(arg_env, cmd_buf, 256, "mov %1D, OFFSET FLAT:%C ", n, n); + lc_esnprintf(arg_env, cmnt_buf, 256, "/* Move address of SymConst into register */"); + } else { + assert(mode == get_tarval_mode(tv)); + /* beware: in some rare cases mode is mode_b which has no tarval_null() */ + if (tv == get_tarval_b_false() || tv == get_tarval_null(mode)) { + const char *instr = "xor"; + if (env->isa->opt_arch == arch_pentium_4) { + /* P4 prefers sub r, r, others xor r, r */ + instr = "sub"; + } + lc_esnprintf(arg_env, cmd_buf, 256, "%s %1D, %1D ", instr, n, n); + lc_esnprintf(arg_env, cmnt_buf, 256, "/* optimized mov 0 to register */"); + } else { lc_esnprintf(arg_env, cmd_buf, 256, "mov %1D, %C ", n, n); lc_esnprintf(arg_env, cmnt_buf, 256, "/* Mov Const into register */"); } @@ -1792,7 +1820,7 @@ static void emit_ia32_Const(const ir_node *n, ia32_emit_env_t *env) { * Emits code to increase stack pointer. */ static void emit_ia32_AddSP(const ir_node *irn, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; + FILE *F = emit_env->out; char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; if (is_ia32_ImmConst(irn)) { @@ -1812,6 +1840,53 @@ static void emit_ia32_AddSP(const ir_node *irn, ia32_emit_env_t *emit_env) { IA32_DO_EMIT(irn); } +/** + * Emits code to increase stack pointer. + */ +static void emit_ia32_SubSP(const ir_node *irn, ia32_emit_env_t *emit_env) { + FILE *F = emit_env->out; + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + + if (is_ia32_ImmConst(irn)) { + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, %C", irn, irn); + } + else if (is_ia32_ImmSymConst(irn)) { + if (get_ia32_op_type(irn) == ia32_Normal) + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, OFFSET_FLAT:%C", irn, irn); + else /* source address mode */ + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, [%s%s]", irn, get_id_str(get_ia32_am_sc(irn)), get_ia32_am_offs(irn)); + } + else { + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, %2S", irn, irn); + } + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* free space on stack */"); + + IA32_DO_EMIT(irn); +} + +/** + * Emits code to load the TLS base + */ +static void emit_ia32_LdTls(const ir_node *irn, ia32_emit_env_t *emit_env) { + FILE *F = emit_env->out; + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + + switch (asm_flavour) { + case ASM_LINUX_GAS: + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, DWORD PTR %%gs:0", irn); + break; + case ASM_MINGW_GAS: + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, DWORD PTR %%gs:0", irn); + break; + default: + assert(0 && "unsupported TLS"); + break; + } + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get thread local storage base */"); + + IA32_DO_EMIT(irn); +} + static void emit_be_Return(const ir_node *n, ia32_emit_env_t *env) { FILE *F = env->out; const lc_arg_env_t *arg_env = ia32_get_arg_env(); @@ -1874,6 +1949,8 @@ static void ia32_register_emitters(void) { IA32_EMIT(Conv_I2I8Bit); IA32_EMIT(Const); IA32_EMIT(AddSP); + IA32_EMIT(SubSP); + IA32_EMIT(LdTls); IA32_EMIT(xCmp); IA32_EMIT(xCmpSet); IA32_EMIT(xCmpCMov); @@ -1911,6 +1988,36 @@ static void ia32_register_emitters(void) { #undef IA32_EMIT } +static const char *last_name = NULL; +static unsigned last_line = -1; +static unsigned num = -1; + +/** + * Emit the debug support for node irn. + */ +static void ia32_emit_dbg(const ir_node *irn, ia32_emit_env_t *env) { + dbg_info *db = get_irn_dbg_info(irn); + unsigned lineno; + const char *fname = be_retrieve_dbg_info(db, &lineno); + + if (fname) { + if (last_name != fname) { + last_line = -1; + be_dbg_include_begin(env->cg->birg->main_env->db_handle, fname); + last_name = fname; + } + 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); + } + } +} + /** * Emits code for a node. */ @@ -1923,6 +2030,7 @@ static void ia32_emit_node(const ir_node *irn, void *env) { if (op->ops.generic) { void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic; + ia32_emit_dbg(irn, emit_env); (*emit)(irn, env); } else { @@ -1944,23 +2052,20 @@ static void ia32_emit_alignment(FILE *F, unsigned align, unsigned skip) { static void ia32_emit_align_func(FILE *F, cpu_support cpu) { unsigned align; unsigned maximum_skip; - /* gcc doesn't emit alignment for p4 ?*/ - if (cpu == arch_pentium_4) - return; - switch (cpu) { case arch_i386: - align = 2; maximum_skip = 3; + align = 2; break; case arch_i486: - align = 4; maximum_skip = 15; + align = 4; break; case arch_k6: - align = 5; maximum_skip = 31; + align = 5; break; default: - align = 4; maximum_skip = 15; + align = 4; } + maximum_skip = (1 << align) - 1; ia32_emit_alignment(F, align, maximum_skip); } @@ -1970,23 +2075,20 @@ static void ia32_emit_align_func(FILE *F, cpu_support cpu) { static void ia32_emit_align_label(FILE *F, cpu_support cpu) { unsigned align; unsigned maximum_skip; - /* gcc doesn't emit alignment for p4 ?*/ - if (cpu == arch_pentium_4) - return; - switch (cpu) { case arch_i386: - align = 2; maximum_skip = 3; + align = 2; break; case arch_i486: - align = 4; maximum_skip = 15; + align = 4; break; case arch_k6: - align = 5; maximum_skip = 7; + align = 5; break; default: - align = 4; maximum_skip = 7; + align = 4; } + maximum_skip = (1 << align) - 1; ia32_emit_alignment(F, align, maximum_skip); } @@ -2031,6 +2133,7 @@ static void ia32_gen_block(ir_node *block, void *env) { } /* emit the contents of the block */ + ia32_emit_dbg(block, env); sched_foreach(block, irn) { ia32_emit_node(irn, env); } @@ -2039,12 +2142,15 @@ static void ia32_gen_block(ir_node *block, void *env) { /** * Emits code for function start. */ -static void ia32_emit_func_prolog(FILE *F, ir_graph *irg, cpu_support cpu) { +static void ia32_emit_func_prolog(FILE *F, ir_graph *irg, ia32_emit_env_t *emit_env) { entity *irg_ent = get_irg_entity(irg); const char *irg_name = get_entity_ld_name(irg_ent); + cpu_support cpu = emit_env->isa->opt_arch; + const be_irg_t *birg = emit_env->cg->birg; fprintf(F, "\n"); ia32_switch_section(F, SECTION_TEXT); + be_dbg_method_begin(birg->main_env->db_handle, irg_ent, be_abi_get_stack_layout(birg->abi)); ia32_emit_align_func(F, cpu); if (get_entity_visibility(irg_ent) == visibility_external_visible) { fprintf(F, ".globl %s\n", irg_name); @@ -2056,10 +2162,12 @@ static void ia32_emit_func_prolog(FILE *F, ir_graph *irg, cpu_support cpu) { /** * Emits code for function end */ -static void ia32_emit_func_epilog(FILE *F, ir_graph *irg) { +static void ia32_emit_func_epilog(FILE *F, ir_graph *irg, ia32_emit_env_t *emit_env) { const char *irg_name = get_entity_ld_name(get_irg_entity(irg)); + const be_irg_t *birg = emit_env->cg->birg; ia32_dump_function_size(F, irg_name); + be_dbg_method_end(birg->main_env->db_handle); fprintf(F, "\n"); } @@ -2096,7 +2204,7 @@ void ia32_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) { ia32_register_emitters(); - ia32_emit_func_prolog(F, irg, emit_env.isa->opt_arch); + ia32_emit_func_prolog(F, irg, &emit_env); irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env); if ((cg->opt & IA32_OPT_EXTBB) && cg->blk_sched) { @@ -2121,5 +2229,5 @@ void ia32_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) { irg_walk_blkwise_graph(irg, NULL, ia32_gen_block, &emit_env); } - ia32_emit_func_epilog(F, irg); + ia32_emit_func_epilog(F, irg, &emit_env); }