X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=e9df948dd0d10a5b44c009d5dcd84cf86a735c30;hb=7dc4f40516155d520a4616d946636357e28c5e51;hp=ec363f397440c557aeaf4b7759bc9b7659b5f8de;hpb=80fd56ac0ffd1de6c526a5c820a1ff31f659104b;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index ec363f397..e9df948dd 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -30,6 +30,7 @@ #include "ia32_nodes_attr.h" #include "ia32_new_nodes.h" #include "ia32_map_regs.h" +#include "bearch_ia32_t.h" #define BLOCK_PREFIX(x) ".L" x @@ -352,7 +353,7 @@ char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) { (!(is_ia32_St(n) || \ is_ia32_Store8Bit(n) || \ is_ia32_CondJmp(n) || \ - is_ia32_fCondJmp(n) || \ + is_ia32_xCondJmp(n) || \ is_ia32_SwitchJmp(n))) if (! buf) { @@ -396,7 +397,7 @@ char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) { lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %s", n, ia32_emit_am(n, env)); } else { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n, env)); + lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, ia32_emit_am(n, env)); } } break; @@ -503,8 +504,8 @@ char *ia32_emit_unop(const ir_node *n, ia32_emit_env_t *env) { lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n); } break; - case ia32_am_Dest: - snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n, env)); + case ia32_AddrModeD: + snprintf(buf, SNPRINTF_BUF_LEN, "%s", ia32_emit_am(n, env)); break; default: assert(0 && "unsupported op type"); @@ -885,6 +886,55 @@ static void emit_ia32_CJmpAM(const ir_node *irn, ia32_emit_env_t *env) { finish_CondJmp(F, irn, get_ia32_res_mode(irn)); } +/** + * Emits code for conditional x87 floating point jump with two variables. + */ +static void emit_ia32_x87CondJmp(ir_node *irn, ia32_emit_env_t *env) { + FILE *F = env->out; + char cmd_buf[SNPRINTF_BUF_LEN]; + char cmnt_buf[SNPRINTF_BUF_LEN]; + ia32_attr_t *attr = get_ia32_attr(irn); + const char *reg = attr->x87[1]->name; + const char *instr = "fcom"; + int reverse = 0; + + switch (get_ia32_pncode(irn)) { + case iro_ia32_fcomrJmp: + reverse = 1; + case iro_ia32_fcomJmp: + default: + instr = "fucom"; + break; + case iro_ia32_fcomrpJmp: + reverse = 1; + case iro_ia32_fcompJmp: + instr = "fucomp"; + break; + case iro_ia32_fcomrppJmp: + reverse = 1; + case iro_ia32_fcomppJmp: + instr = "fucompp"; + reg = ""; + break; + } + + if (reverse) + set_ia32_pncode(irn, (long)get_negated_pnc(get_ia32_pncode(irn), mode_Is)); + + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "%s %s", instr, 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 %3D", irn); + lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fnstsw %%ax", irn); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* Store x87 FPU Control Word */"); + IA32_DO_EMIT(irn); + snprintf(cmd_buf, SNPRINTF_BUF_LEN, "sahf"); + snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* Store ah into flags */"); + IA32_DO_EMIT(irn); + + finish_CondJmp(F, irn, mode_Is); +} + /********************************************************* * _ _ _ * (_) | (_) @@ -1444,9 +1494,10 @@ static void emit_ia32_Const(const ir_node *n, ia32_emit_env_t *env) { */ static void ia32_register_emitters(void) { -#define IA32_EMIT(a) op_ia32_##a->ops.generic = (op_func)emit_ia32_##a -#define EMIT(a) op_##a->ops.generic = (op_func)emit_##a -#define BE_EMIT(a) op_be_##a->ops.generic = (op_func)emit_be_##a +#define IA32_EMIT2(a,b) op_ia32_##a->ops.generic = (op_func)emit_ia32_##b +#define IA32_EMIT(a) IA32_EMIT2(a,a) +#define EMIT(a) op_##a->ops.generic = (op_func)emit_##a +#define BE_EMIT(a) op_be_##a->ops.generic = (op_func)emit_be_##a /* first clear the generic function pointer for all ops */ clear_irp_opcodes_generic_func(); @@ -1468,6 +1519,12 @@ static void ia32_register_emitters(void) { IA32_EMIT(Conv_I2I); IA32_EMIT(Conv_I2I8Bit); IA32_EMIT(Const); + IA32_EMIT2(fcomJmp, x87CondJmp); + IA32_EMIT2(fcompJmp, x87CondJmp); + IA32_EMIT2(fcomppJmp, x87CondJmp); + IA32_EMIT2(fcomrJmp, x87CondJmp); + IA32_EMIT2(fcomrpJmp, x87CondJmp); + IA32_EMIT2(fcomrppJmp, x87CondJmp); /* benode emitter */ BE_EMIT(Call); @@ -1480,9 +1537,10 @@ static void ia32_register_emitters(void) { EMIT(Jmp); EMIT(Proj); -#undef IA32_EMIT #undef BE_EMIT #undef EMIT +#undef IA32_EMIT2 +#undef IA32_EMIT } /** @@ -1505,17 +1563,91 @@ static void ia32_emit_node(const ir_node *irn, void *env) { } } +/** + * Emits gas alignment directives for Functions dependend on cpu architecture. + */ +static void ia32_emit_align_func(FILE *F, cpu_support cpu) { + /* gcc doesn't emit alignment for p4 ?*/ + if (cpu == arch_pentium_4) + return; + + fprintf(F, "\t.p2align "); + + switch (cpu) { + case arch_i386: + /* align 4 bytes, maximum skip 3 bytes */ + fprintf(F, "2,,3"); + break; + case arch_i486: + /* align 16 bytes, maximum skip 15 bytes */ + fprintf(F, "4,,15"); + break; + case arch_k6: + /* align 32 bytes, maximum skip 31 bytes */ + fprintf(F, "5,,31"); + break; + default: + /* align 16 bytes, maximum skip 15 bytes */ + fprintf(F, "4,,15"); + } + + fprintf(F, "\n"); +} + +/** + * Emits gas alignment directives for Labels dependend on cpu architecture. + */ +static void ia32_emit_align_label(FILE *F, cpu_support cpu) { + /* gcc doesn't emit alignment for p4 ?*/ + if (cpu == arch_pentium_4) + return; + + fprintf(F, "\t.p2align "); + + switch (cpu) { + case arch_i386: + /* align 4 bytes, maximum skip 3 bytes */ + fprintf(F, "2,,3"); + break; + case arch_i486: + /* align 16 bytes, maximum skip 15 bytes */ + fprintf(F, "4,,15"); + break; + case arch_k6: + /* align 32 bytes, maximum skip 7 bytes */ + fprintf(F, "5,,7"); + break; + default: + /* align 16 bytes, maximum skip 7 bytes */ + fprintf(F, "4,,7"); + } + + fprintf(F, "\n"); +} + /** * Walks over the nodes in a block connected by scheduling edges * and emits code for each node. */ static void ia32_gen_block(ir_node *block, void *env) { + ia32_emit_env_t *emit_env = env; const ir_node *irn; + int need_label = block != get_irg_start_block(get_irn_irg(block)); if (! is_Block(block)) return; - fprintf(((ia32_emit_env_t *)env)->out, BLOCK_PREFIX("%ld:\n"), get_irn_node_nr(block)); + if (need_label && (emit_env->cg->opt & IA32_OPT_EXTBB)) { + /* if the extended block scheduler is used, only leader blocks need + labels. */ + need_label = (block == get_extbb_leader(get_nodes_extbb(block))); + } + + if (need_label) { + ia32_emit_align_label(emit_env->out, emit_env->isa->opt_arch); + fprintf(emit_env->out, BLOCK_PREFIX("%ld:\n"), get_irn_node_nr(block)); + } + sched_foreach(block, irn) { ia32_emit_node(irn, env); } @@ -1524,12 +1656,13 @@ 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) { +static void ia32_emit_func_prolog(FILE *F, ir_graph *irg, cpu_support cpu) { entity *irg_ent = get_irg_entity(irg); const char *irg_name = get_entity_ld_name(irg_ent); fprintf(F, "\n"); ia32_switch_section(F, SECTION_TEXT); + ia32_emit_align_func(F, cpu); if (get_entity_visibility(irg_ent) == visibility_external_visible) { fprintf(F, ".globl %s\n", irg_name); } @@ -1581,7 +1714,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); + ia32_emit_func_prolog(F, irg, emit_env.isa->opt_arch); irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env); if ((cg->opt & IA32_OPT_EXTBB) && cg->blk_sched) {