From eb798733d50fbfb32b12ae9cb2f989d8b86f0d12 Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Fri, 16 Feb 2007 09:34:29 +0000 Subject: [PATCH] experiment with new emitter style, change assembler syntax of ia32 backend to AT&T --- ir/be/ia32/bearch_ia32.c | 40 +- ir/be/ia32/ia32_emitter.c | 1884 +++++++++++-------------- ir/be/ia32/ia32_emitter.h | 46 +- ir/be/ia32/ia32_finish.c | 25 +- ir/be/ia32/ia32_intrinsics.c | 18 +- ir/be/ia32/ia32_new_nodes.c | 256 +--- ir/be/ia32/ia32_new_nodes.h | 65 +- ir/be/ia32/ia32_nodes_attr.h | 4 - ir/be/ia32/ia32_optimize.c | 110 +- ir/be/ia32/ia32_spec.pl | 372 ++--- ir/be/ia32/ia32_transform.c | 662 ++++----- ir/be/scripts/generate_emitter.pl | 10 +- ir/be/scripts/generate_emitter_new.pl | 188 +++ 13 files changed, 1706 insertions(+), 1974 deletions(-) create mode 100755 ir/be/scripts/generate_emitter_new.pl diff --git a/ir/be/ia32/bearch_ia32.c b/ir/be/ia32/bearch_ia32.c index 9f2650fdc..c894e2fe4 100644 --- a/ir/be/ia32/bearch_ia32.c +++ b/ir/be/ia32/bearch_ia32.c @@ -727,16 +727,16 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in inverse->costs += 1; } break; - case iro_ia32_Eor: + case iro_ia32_Xor: if (get_ia32_immop_type(irn) != ia32_ImmNone) { /* xor with const: inverse = xor */ - inverse->nodes[0] = new_rd_ia32_Eor(dbg, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem); + inverse->nodes[0] = new_rd_ia32_Xor(dbg, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem); inverse->costs += (get_ia32_immop_type(irn) == ia32_ImmSymConst) ? 5 : 1; copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn); } else { /* normal xor */ - inverse->nodes[0] = new_rd_ia32_Eor(dbg, irg, block, noreg, noreg, (ir_node *) irn, get_irn_n(irn, i), nomem); + inverse->nodes[0] = new_rd_ia32_Xor(dbg, irg, block, noreg, noreg, (ir_node *) irn, get_irn_n(irn, i), nomem); inverse->costs += 1; } break; @@ -745,8 +745,8 @@ static arch_inverse_t *ia32_get_inverse(const void *self, const ir_node *irn, in inverse->costs += 1; break; } - case iro_ia32_Minus: { - inverse->nodes[0] = new_rd_ia32_Minus(dbg, irg, block, noreg, noreg, (ir_node*) irn, nomem); + case iro_ia32_Neg: { + inverse->nodes[0] = new_rd_ia32_Neg(dbg, irg, block, noreg, noreg, (ir_node*) irn, nomem); inverse->costs += 1; break; } @@ -893,23 +893,6 @@ ia32_irn_ops_t ia32_irn_ops = { * |___/ **************************************************/ -/** - * Transform the Thread Local Store base. - */ -static void transform_tls(ir_graph *irg) { - ir_node *irn = get_irg_tls(irg); - - if (irn) { - dbg_info *dbg = get_irn_dbg_info(irn); - ir_node *blk = get_nodes_block(irn); - ir_node *newn; - newn = new_rd_ia32_LdTls(dbg, irg, blk, get_irn_mode(irn)); - - exchange(irn, newn); - set_irg_tls(irg, newn); - } -} - /** * Transforms the standard firm graph into * an ia32 firm graph @@ -920,17 +903,15 @@ static void ia32_prepare_graph(void *self) { FIRM_DBG_REGISTER(cg->mod, "firm.be.ia32.transform"); - /* 1st: transform constants and psi condition trees */ + /* 1st: transform psi condition trees */ ia32_pre_transform_phase(cg); /* 2nd: transform all remaining nodes */ - transform_tls(cg->irg); ia32_transform_graph(cg); // Matze: disabled for now. Because after transformation start block has no - // self-loop anymore so it will probably melt with its successor block. - // - // This will bring several nodes to the startblock and we still can't - // handle spill before the initial IncSP nicely + // self-loop anymore so it might be merged with its successor block. This + // will bring several nodes to the startblock which sometimes get scheduled + // before the initial IncSP/Barrier //local_optimize_graph(cg->irg); if (cg->dump) @@ -1400,7 +1381,7 @@ static void ia32_codegen(void *self) { ia32_code_gen_t *cg = self; ir_graph *irg = cg->irg; - ia32_gen_routine(cg->isa->out, irg, cg); + ia32_gen_routine(cg, cg->isa->out, irg); cur_reg_set = NULL; @@ -1597,7 +1578,6 @@ static void *ia32_init(FILE *file_handle) { ia32_handle_intrinsics(); ia32_switch_section(isa->out, NO_SECTION); - fprintf(isa->out, "\t.intel_syntax\n"); /* needed for the debug support */ ia32_switch_section(isa->out, SECTION_TEXT); diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 7bfee7571..7acb26a78 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -1,11 +1,10 @@ /** * This file implements the node emitter. - * @author Christian Wuerdig + * @author Christian Wuerdig, Matthias Braun * $Id$ */ - #ifdef HAVE_CONFIG_H -#include "config.h" +#include #endif #include @@ -21,6 +20,7 @@ #include "irprog_t.h" #include "iredges_t.h" #include "execfreq.h" +#include "error.h" #include "../besched_t.h" #include "../benode_t.h" @@ -35,7 +35,7 @@ #include "ia32_map_regs.h" #include "bearch_ia32_t.h" -#define BLOCK_PREFIX(x) ".L" x +#define BLOCK_PREFIX ".L" #define SNPRINTF_BUF_LEN 128 @@ -117,23 +117,6 @@ static void ia32_dump_function_size(FILE *F, const char *name) } } -/************************************************************* - * _ _ __ _ _ - * (_) | | / _| | | | | - * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ - * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| - * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | - * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| - * | | | | - * |_| |_| - *************************************************************/ - -/* We always pass the ir_node which is a pointer. */ -static int ia32_get_arg_type(const lc_arg_occ_t *occ) { - return lc_arg_type_ptr; -} - - /** * Returns the register at in position pos. */ @@ -168,8 +151,7 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos) { p_req->limited(p_req->limited_env, bs); idx = bitset_next_set(bs, 0); reg = arch_register_for_index(p_req->cls, idx); - } - else { + } else { /* otherwise get first register in class */ reg = arch_register_for_index(p_req->cls, 0); } @@ -192,11 +174,9 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) { if (get_irn_mode(irn) != mode_T) { reg = arch_get_irn_register(arch_env, irn); - } - else if (is_ia32_irn(irn)) { + } else if (is_ia32_irn(irn)) { reg = get_ia32_out_reg(irn, pos); - } - else { + } else { const ir_edge_t *edge; foreach_out_edge(irn, edge) { @@ -213,202 +193,214 @@ static const arch_register_t *get_out_reg(const ir_node *irn, int pos) { return reg; } -enum io_direction { - IN_REG, - OUT_REG -}; - /** - * Returns the name of the in register at position pos. + * Returns an ident for the given tarval tv. */ -static const char *get_ia32_reg_name(ir_node *irn, int pos, enum io_direction in_out) { - const arch_register_t *reg; - - if (in_out == IN_REG) { - reg = get_in_reg(irn, pos); +static ident *get_ident_for_tv(tarval *tv) { + char buf[256]; + int len = tarval_snprintf(buf, sizeof(buf), tv); + assert(len); + return new_id_from_str(buf); +} - if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]) { - /* FIXME: works for binop only */ - assert(2 <= pos && pos <= 3); - reg = get_ia32_attr(irn)->x87[pos - 2]; +/** + * Determine the gnu assembler suffix that indicates a mode + */ +static char get_mode_suffix(const ir_mode *mode) { + if(mode_is_float(mode)) { + switch(get_mode_size_bits(mode)) { + case 32: + return 's'; + case 64: + return 'l'; + case 80: + return 't'; } - } - else { - /* destination address mode nodes don't have outputs */ - if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) { - return "MEM"; + } else { + assert(mode_is_int(mode) || mode_is_reference(mode)); + switch(get_mode_size_bits(mode)) { + case 64: + return 'q'; + case 32: + return 'l'; + case 16: + return 'w'; + case 8: + return 'b'; } + } + panic("Can't output mode_suffix for %+F\n", mode); +} - reg = get_out_reg(irn, pos); - if (reg->reg_class == &ia32_reg_classes[CLASS_ia32_vfp]) - reg = get_ia32_attr(irn)->x87[pos + 2]; +static int produces_result(const ir_node *node) { + return !(is_ia32_St(node) || + is_ia32_Store8Bit(node) || + is_ia32_CondJmp(node) || + is_ia32_xCondJmp(node) || + is_ia32_CmpSet(node) || + is_ia32_xCmpSet(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) { + switch(get_mode_size_bits(mode)) { + case 8: + return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg); + case 16: + return ia32_get_mapped_reg_name(env->isa->regs_16bit, reg); + default: + return (char *)arch_register_get_name(reg); } - return arch_register_get_name(reg); } +#if 0 /** - * Get the register name for a node. + * Determines the SSE suffix depending on the mode. */ -static int ia32_get_reg_name(lc_appendable_t *app, +static int ia32_print_mode_suffix(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *arg) { - const char *buf; - ir_node *irn = arg->v_ptr; - int nr = occ->width - 1; + ir_node *irn = arg->v_ptr; + ir_mode *mode = get_ia32_ls_mode(irn); - if (! irn) - return lc_appendable_snadd(app, "(null)", 6); + 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; - buf = get_ia32_reg_name(irn, nr, occ->conversion == 'S' ? IN_REG : OUT_REG); + if(mode_is_signed(mode)) + lc_appendable_chadd(app, 's'); + else + lc_appendable_chadd(app, 'z'); - /* append the stupid % to register names */ - lc_appendable_chadd(app, '%'); - return lc_appendable_snadd(app, buf, strlen(buf)); + lc_appendable_chadd(app, get_mode_suffix(mode)); + return 2; + } } +#endif /** - * Get the x87 register name for a node. + * Add a number to a prefix. This number will not be used a second time. */ -static int ia32_get_x87_name(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +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; +} + +/************************************************************* + * _ _ __ _ _ + * (_) | | / _| | | | | + * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __ + * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__| + * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ | + * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_| + * | | | | + * |_| |_| + *************************************************************/ + +void ia32_emit_ident(ia32_emit_env_t *env, ident *id) { - const char *buf; - ir_node *irn = arg->v_ptr; - int nr = occ->width - 1; - ia32_attr_t *attr; - int res = 0; + size_t len = get_id_strlen(id); + const char* str = get_id_str(id); - if (! irn) - return lc_appendable_snadd(app, "(null)", 6); + ia32_emit_string_len(env, str, len); +} - attr = get_ia32_attr(irn); - buf = attr->x87[nr]->name; +void ia32_emit_irprintf(ia32_emit_env_t *env, const char *fmt, ...) +{ + char buf[128]; + va_list ap; - res += lc_appendable_chadd(app, '%'); - res += lc_appendable_snadd(app, buf, strlen(buf)); + va_start(ap, fmt); + ir_vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); - return res; + ia32_emit_string(env, buf); } -/** - * Returns the tarval, offset or scale of an ia32 as a string. - */ -static int ia32_const_to_str(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +void ia32_emit_source_register(ia32_emit_env_t *env, const ir_node *node, int pos) { - const char *buf; - ir_node *irn = arg->v_ptr; + const arch_register_t *reg = get_in_reg(node, pos); + const char *reg_name = arch_register_get_name(reg); - if (! irn) - return lc_arg_append(app, occ, "(null)", 6); + assert(pos < get_irn_arity(node)); - if (occ->conversion == 'C') { - buf = get_ia32_cnst(irn); - } - else { /* 'O' */ - buf = get_ia32_am_offs(irn); - } + ia32_emit_char(env, '%'); + ia32_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); - return buf ? lc_appendable_snadd(app, buf, strlen(buf)) : 0; + ia32_emit_char(env, '%'); + ia32_emit_string(env, reg_name); } -/** - * Determines the SSE suffix depending on the mode. - */ -static int ia32_get_mode_suffix(lc_appendable_t *app, - const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +void ia32_emit_x87_name(ia32_emit_env_t *env, const ir_node *node, int pos) { - ir_node *irn = arg->v_ptr; - ir_mode *mode = get_ia32_ls_mode(irn);; + ia32_attr_t *attr = get_ia32_attr(node); - if (mode == mode_T) { - mode = get_ia32_ls_mode(irn); - assert(mode != NULL); - } + assert(pos < 7); + ia32_emit_char(env, '%'); + ia32_emit_string(env, attr->x87[pos]->name); +} - if (! irn) - return lc_arg_append(app, occ, "(null)", 6); +void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node) +{ + tarval *tv; + ident *id; - if (mode_is_float(mode)) { - return lc_appendable_chadd(app, get_mode_size_bits(mode) == 32 ? 's' : 'd'); - } - else { - return lc_appendable_chadd(app, mode_is_signed(mode) ? 's' : 'z'); + 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); + break; + default: + assert(0); + ia32_emit_string(env, "BAD"); + return; } -} -/** - * Return the ia32 printf arg environment. - * We use the firm environment with some additional handlers. - */ -const lc_arg_env_t *ia32_get_arg_env(void) { - static lc_arg_env_t *env = NULL; - - static const lc_arg_handler_t ia32_reg_handler = { ia32_get_arg_type, ia32_get_reg_name }; - static const lc_arg_handler_t ia32_const_handler = { ia32_get_arg_type, ia32_const_to_str }; - static const lc_arg_handler_t ia32_mode_handler = { ia32_get_arg_type, ia32_get_mode_suffix }; - static const lc_arg_handler_t ia32_x87_handler = { ia32_get_arg_type, ia32_get_x87_name }; - - if(env == NULL) { - /* extend the firm printer */ - env = firm_get_arg_env(); - - lc_arg_register(env, "ia32:sreg", 'S', &ia32_reg_handler); - lc_arg_register(env, "ia32:dreg", 'D', &ia32_reg_handler); - lc_arg_register(env, "ia32:cnst", 'C', &ia32_const_handler); - lc_arg_register(env, "ia32:offs", 'O', &ia32_const_handler); - lc_arg_register(env, "ia32:mode", 'M', &ia32_mode_handler); - lc_arg_register(env, "ia32:x87", 'X', &ia32_x87_handler); - } + ia32_emit_ident(env, id); +} - return env; +void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_mode *mode) +{ + ia32_emit_char(env, get_mode_suffix(mode)); } -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); - case 16: - return ia32_get_mapped_reg_name(env->isa->regs_16bit, reg); - default: - return (char *)arch_register_get_name(reg); +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'); + } else { + ia32_emit_char(env, 'z'); } } /** * Emits registers and/or address mode of a binary operation. */ -const char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) { - static char *buf = NULL; - -#define PRODUCES_RESULT(n) \ - (!(is_ia32_St(n) || \ - is_ia32_Store8Bit(n) || \ - is_ia32_CondJmp(n) || \ - is_ia32_xCondJmp(n) || \ - is_ia32_CmpSet(n) || \ - is_ia32_xCmpSet(n) || \ - is_ia32_SwitchJmp(n))) - - if (! buf) { - buf = xcalloc(1, SNPRINTF_BUF_LEN); - } - else { - memset(buf, 0, SNPRINTF_BUF_LEN); - } - - switch(get_ia32_op_type(n)) { +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(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n)); - } - else if (is_ia32_ImmSymConst(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, OFFSET FLAT:%s", n, get_ia32_cnst(n)); - } - else { - const arch_register_t *in1 = get_in_reg(n, 2); - const arch_register_t *in2 = get_in_reg(n, 3); - const arch_register_t *out = PRODUCES_RESULT(n) ? get_out_reg(n, 0) : NULL; + if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { + ia32_emit_char(env, '$'); + ia32_emit_immediate(env, node); + ia32_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 *in; const char *in_name; @@ -416,115 +408,73 @@ const char *ia32_emit_binop(const ir_node *n, ia32_emit_env_t *env) { out = out ? out : in1; in_name = arch_register_get_name(in); - if (is_ia32_emit_cl(n)) { + if (is_ia32_emit_cl(node)) { assert(REGS_ARE_EQUAL(&ia32_gp_regs[REG_ECX], in) && "shift operation needs ecx"); in_name = "cl"; } - snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s", arch_register_get_name(out), in_name); + ia32_emit_char(env, '%'); + ia32_emit_string(env, in_name); + ia32_emit_cstring(env, ", %"); + ia32_emit_string(env, arch_register_get_name(out)); } break; case ia32_AddrModeS: - if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) { - assert(! PRODUCES_RESULT(n) && "Source AM with Const must not produce result"); - snprintf(buf, SNPRINTF_BUF_LEN, "%s, %s", get_ia32_cnst(n), ia32_emit_am(n, env)); - } - else { - if (PRODUCES_RESULT(n)) { - 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, "%3S, %s", n, ia32_emit_am(n, 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); + ia32_emit_cstring(env, ", $"); + ia32_emit_immediate(env, node); + } else if (produces_result(node)) { + ia32_emit_am(env, node); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } else { + ia32_emit_am(env, node); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 2); } break; case ia32_AddrModeD: - if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s,%s%s", - ia32_emit_am(n, env), - is_ia32_ImmSymConst(n) ? " OFFSET FLAT:" : " ", /* In case of a symconst we must add OFFSET to */ - get_ia32_cnst(n)); /* tell the assembler to store it's address. */ - } - else { - const arch_register_t *in1 = get_in_reg(n, get_irn_arity(n) == 5 ? 3 : 2); - ir_mode *mode = get_ia32_ls_mode(n); + if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { + ia32_emit_char(env, '$'); + ia32_emit_immediate(env, node); + ia32_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); + ir_mode *mode = get_ia32_ls_mode(node); const char *in_name; - if(mode == NULL) { - // except stores only integer nodes support dest AM - mode = mode_Is; - } - in_name = ia32_get_reg_name_for_mode(env, mode, in1); - if (is_ia32_emit_cl(n)) { + if (is_ia32_emit_cl(node)) { assert(REGS_ARE_EQUAL(&ia32_gp_regs[REG_ECX], in1) && "shift operation needs ecx"); in_name = "cl"; } - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %%%s", ia32_emit_am(n, env), in_name); + ia32_emit_char(env, '%'); + ia32_emit_string(env, in_name); + ia32_emit_cstring(env, ", "); + ia32_emit_am(env, node); } break; default: assert(0 && "unsupported op type"); } - -#undef PRODUCES_RESULT - - return buf; -} - -/** - * Returns the xxx PTR string for a given mode - * - * @param mode the mode - * @param x87_insn if non-zero returns the string for a x87 instruction - * else for a SSE instruction - */ -static const char *pointer_size(ir_mode *mode, int x87_insn) -{ - if (mode) { - switch (get_mode_size_bits(mode)) { - case 8: return "BYTE PTR"; - case 16: return "WORD PTR"; - case 32: return "DWORD PTR"; - case 64: - if (x87_insn) - return "QWORD PTR"; - return NULL; - case 80: - case 96: return "XWORD PTR"; - default: return NULL; - } - } - return NULL; } /** * Emits registers and/or address mode of a binary operation. */ -const char *ia32_emit_x87_binop(const ir_node *n, ia32_emit_env_t *env) { - static char *buf = NULL; - - /* verify that this function is never called on non-AM supporting operations */ - //assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support"); - - if (! buf) { - buf = xcalloc(1, SNPRINTF_BUF_LEN); - } - else { - memset(buf, 0, SNPRINTF_BUF_LEN); - } - - switch(get_ia32_op_type(n)) { +void ia32_emit_x87_binop(ia32_emit_env_t *env, const ir_node *node) { + switch(get_ia32_op_type(node)) { case ia32_Normal: - if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) { - ir_mode *mode = get_ia32_ls_mode(n); - const char *p = pointer_size(mode, 1); - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s %s", p, get_ia32_cnst(n)); - } - else { - ia32_attr_t *attr = get_ia32_attr(n); + if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { + // should not happen... + assert(0); + } else { + ia32_attr_t *attr = get_ia32_attr(node); const arch_register_t *in1 = attr->x87[0]; const arch_register_t *in2 = attr->x87[1]; const arch_register_t *out = attr->x87[2]; @@ -533,173 +483,102 @@ const char *ia32_emit_x87_binop(const ir_node *n, ia32_emit_env_t *env) { in = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2; out = out ? out : in1; - snprintf(buf, SNPRINTF_BUF_LEN, "%%%s, %%%s", - arch_register_get_name(out), arch_register_get_name(in)); + 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)); } break; case ia32_AddrModeS: case ia32_AddrModeD: - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s", ia32_emit_am(n, env)); + ia32_emit_am(env, node); break; default: assert(0 && "unsupported op type"); } - - return buf; } /** * Emits registers and/or address mode of a unary operation. */ -const char *ia32_emit_unop(const ir_node *n, ia32_emit_env_t *env) { - static char *buf = NULL; - - if (! buf) { - buf = xcalloc(1, SNPRINTF_BUF_LEN); - } - else { - memset(buf, 0, SNPRINTF_BUF_LEN); - } - - switch(get_ia32_op_type(n)) { +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(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%C", n); - } - else if (is_ia32_ImmSymConst(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "OFFSET FLAT:%C", n); - } - else { - if (is_ia32_MulS(n) || is_ia32_Mulh(n)) { + if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) { + ia32_emit_char(env, '$'); + ia32_emit_immediate(env, node); + } else { + if (is_ia32_IMul(node) || is_ia32_Mulh(node)) { /* MulS and Mulh implicitly multiply by EAX */ - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S", n); - } else if(is_ia32_Push(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S", n); - } else if(is_ia32_Pop(n)) { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%2D", n); + ia32_emit_source_register(env, node, 3); + } else if(is_ia32_IDiv(node)) { + ia32_emit_source_register(env, node, 1); + } else if(is_ia32_Push(node)) { + ia32_emit_source_register(env, node, 2); + } else if(is_ia32_Pop(node)) { + ia32_emit_dest_register(env, node, 1); } else { - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n); + ia32_emit_dest_register(env, node, 0); } } break; - case ia32_AddrModeD: - assert(!is_ia32_Push(n)); - snprintf(buf, SNPRINTF_BUF_LEN, "%s", ia32_emit_am(n, env)); - break; case ia32_AddrModeS: - /* - Mulh is emitted via emit_unop - imul [MEM] means EDX:EAX <- EAX * [MEM] - */ - assert((is_ia32_Mulh(n) || is_ia32_MulS(n) || is_ia32_Push(n)) && "Only MulS and Mulh can have AM source as unop"); - lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s", ia32_emit_am(n, env)); + case ia32_AddrModeD: + ia32_emit_am(env, node); break; default: assert(0 && "unsupported op type"); } - - return buf; } /** * Emits address mode. */ -const char *ia32_emit_am(const ir_node *n, ia32_emit_env_t *env) { - ia32_am_flavour_t am_flav = get_ia32_am_flavour(n); - int had_output = 0; - char *s; - const char *p; - static struct obstack *obst = NULL; - ir_mode *mode = get_ia32_ls_mode(n); +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); + int offs = get_ia32_am_offs_int(node); /* just to be sure... */ - assert(!is_ia32_use_frame(n) || get_ia32_frame_ent(n) != NULL); - - if (! is_ia32_Lea(n)) - assert(mode && "AM node must have ls_mode attribute set."); + assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL); - if (! obst) { - obst = xcalloc(1, sizeof(*obst)); - } - else { - obstack_free(obst, NULL); - } - - /* obstack_free with NULL results in an uninitialized obstack */ - obstack_init(obst); - - p = pointer_size(mode, ia32_has_x87_register(n) || is_ia32_GetST0(n) || is_ia32_SetST0(n)); - if (p) - obstack_printf(obst, "%s ", p); - - /* emit address mode symconst */ - if (get_ia32_am_sc(n)) { - if (is_ia32_am_sc_sign(n)) - obstack_printf(obst, "-"); - obstack_printf(obst, "%s", get_id_str(get_ia32_am_sc(n))); - } - - if (am_flav & ia32_B) { - obstack_printf(obst, "["); - lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n); - had_output = 1; + /* emit offset */ + if (id != NULL) { + if (is_ia32_am_sc_sign(node)) + ia32_emit_char(env, '-'); + ia32_emit_ident(env, id); } - if (am_flav & ia32_I) { - if (had_output) { - obstack_printf(obst, "+"); - } - else { - obstack_printf(obst, "["); + if(offs != 0) { + if(id != NULL) { + ia32_emit_irprintf(env, "%+d", offs); + } else { + ia32_emit_irprintf(env, "%d", offs); } + } - lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n); + if (am_flav & (ia32_B | ia32_I)) { + ia32_emit_char(env, '('); - if (am_flav & ia32_S) { - obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n)); + /* emit base */ + if (am_flav & ia32_B) { + ia32_emit_source_register(env, node, 0); } - had_output = 1; - } - - if (am_flav & ia32_O) { - int offs = get_ia32_am_offs_int(n); + /* emit index + scale */ + if (am_flav & ia32_I) { + ia32_emit_char(env, ','); + ia32_emit_source_register(env, node, 1); - if (offs != 0) { - /* omit explicit + if there was no base or index */ - if (! had_output) { - obstack_printf(obst, "[%d", offs); - } else { - obstack_printf(obst, "%+d", offs); + if (am_flav & ia32_S) { + ia32_emit_irprintf(env, ",%d", 1 << get_ia32_am_scale(node)); } - - had_output = 1; } + ia32_emit_char(env, ')'); } - - if (had_output) - obstack_printf(obst, "] "); - - obstack_1grow(obst, '\0'); - s = obstack_finish(obst); - - return s; -} - -/** - * emit an address - */ -const char *ia32_emit_adr(const ir_node *irn, ia32_emit_env_t *env) -{ - static char buf[SNPRINTF_BUF_LEN]; - ir_mode *mode = get_ia32_ls_mode(irn); - const char *adr = get_ia32_cnst(irn); - const char *pref = pointer_size(mode, ia32_has_x87_register(irn)); - - snprintf(buf, SNPRINTF_BUF_LEN, "%s %s", pref ? pref : "", adr); - return buf; } +#if 0 /** * Formated print of commands and comments. */ @@ -712,18 +591,50 @@ static void ia32_fprintf_format(FILE *F, const ir_node *irn, char *cmd_buf, char 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); +} -/** - * 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; +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); +} /************************************************* @@ -798,6 +709,12 @@ 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)); +} + + /** * Returns the target block for a control flow node. */ @@ -808,11 +725,11 @@ static ir_node *get_cfop_target_block(const ir_node *irn) { /** * Returns the target label for a control flow node. */ -static char *get_cfop_target(const ir_node *irn, char *buf) { - ir_node *bl = get_cfop_target_block(irn); +void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) { + ir_node *block = get_cfop_target_block(node); - snprintf(buf, SNPRINTF_BUF_LEN, BLOCK_PREFIX("%ld"), get_irn_node_nr(bl)); - return buf; + ia32_emit_cstring(env, BLOCK_PREFIX); + ia32_emit_irprintf(env, "%d", get_irn_node_nr(block)); } /** Return the next block in Block schedule */ @@ -823,13 +740,13 @@ 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 *irn, long proj) { +static ir_node *get_proj(const ir_node *node, long proj) { const ir_edge_t *edge; ir_node *src; - assert(get_irn_mode(irn) == mode_T && "expected mode_T node"); + assert(get_irn_mode(node) == mode_T && "expected mode_T node"); - foreach_out_edge(irn, edge) { + foreach_out_edge(node, edge) { src = get_edge_src_irn(edge); assert(is_Proj(src) && "Proj expected"); @@ -845,29 +762,23 @@ 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) { +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; 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 */ - proj_true = get_proj(irn, pn_Cond_true); + proj_true = get_proj(node, pn_Cond_true); assert(proj_true && "CondJmp without true Proj"); - proj_false = get_proj(irn, pn_Cond_false); + proj_false = get_proj(node, 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); + block = get_nodes_block(node); /* we have a block schedule */ next_block = next_blk_sched(block); @@ -882,311 +793,290 @@ static void finish_CondJmp(FILE *F, const ir_node *irn, ir_mode *mode) { pnc = get_negated_pnc(pnc, mode); } - /* the first Proj must always be created */ - is_unsigned = mode_is_float(mode) || ! mode_is_signed(mode); - /* in case of unordered compare, check for parity */ if (pnc & pn_Cmp_Uo) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jp %s", get_cfop_target(proj_true, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* jump to false if result is unordered */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tjp "); + ia32_emit_cfop_target(env, proj_true); + ia32_emit_finish_line(env, proj_true); } - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "j%s %s", - get_cmp_suffix(pnc), - get_cfop_target(proj_true, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* %s(a, b) %s*/", - get_pnc_string(pnc & ~ia32_pn_Cmp_Unsigned), flipped ? "(was flipped)" : ""); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tj"); + ia32_emit_cmp_suffix(env, pnc); + ia32_emit_char(env, ' '); + ia32_emit_cfop_target(env, proj_true); + ia32_emit_finish_line(env, proj_true); /* the second Proj might be a fallthrough */ 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(proj_false, buf)); + ia32_emit_cstring(env, "\tjmp "); + ia32_emit_cfop_target(env, proj_false); + ia32_emit_finish_line(env, proj_false); + } else { + ia32_emit_cstring(env, "\t/* fallthrough to"); + ia32_emit_cfop_target(env, proj_false); + ia32_emit_cstring(env, " */"); + ia32_emit_finish_line(env, proj_false); } - IA32_DO_EMIT(irn); } /** * Emits code for conditional jump. */ -static void CondJmp_emitter(const ir_node *irn, ia32_emit_env_t *env) { - FILE *F = env->out; - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; +static void CondJmp_emitter(ia32_emit_env_t *env, const ir_node *node) { + ia32_emit_cstring(env, "\tcmp "); + ia32_emit_binop(env, node); + ia32_emit_finish_line(env, node); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cmp %s", ia32_emit_binop(irn, env)); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); - IA32_DO_EMIT(irn); - finish_CondJmp(F, irn, mode_Is); + finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); } /** * Emits code for conditional jump with two variables. */ -static void emit_ia32_CondJmp(const ir_node *irn, ia32_emit_env_t *env) { - CondJmp_emitter(irn, env); +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(const ir_node *irn, ia32_emit_env_t *env) { - -#define IA32_IS_IMMOP (is_ia32_ImmConst(irn) || is_ia32_ImmSymConst(irn)) - - FILE *F = env->out; - const char *op1 = arch_register_get_name(get_in_reg(irn, 0)); - const char *op2 = IA32_IS_IMMOP ? get_ia32_cnst(irn) : NULL; - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; - - if (! op2) - op2 = arch_register_get_name(get_in_reg(irn, 1)); - - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "test %%%s,%s%s ", op1, IA32_IS_IMMOP ? " " : " %", op2); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); - - IA32_DO_EMIT(irn); - finish_CondJmp(F, irn, mode_Is); - -#undef IA32_IS_IMMOP +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 $"); + ia32_emit_immediate(env, node); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + ia32_emit_finish_line(env, node); + } else { + ia32_emit_cstring(env, "\ttest "); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + ia32_emit_finish_line(env, node); + } + finish_CondJmp(env, node, mode_Iu, get_ia32_pncode(node)); } /** * Emits code for conditional test and jump with two variables. */ -static void emit_ia32_TestJmp(const ir_node *irn, ia32_emit_env_t *env) { - TestJmp_emitter(irn, env); +static void emit_ia32_TestJmp(ia32_emit_env_t *env, const ir_node *node) { + TestJmp_emitter(env, node); } -static void emit_ia32_CJmp(const ir_node *irn, ia32_emit_env_t *env) { - FILE *F = env->out; - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; +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); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, " "); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F omitted redundant test */", irn); - IA32_DO_EMIT(irn); - finish_CondJmp(F, irn, mode_Is); + finish_CondJmp(env, node, mode_Is, get_ia32_pncode(node)); } -static void emit_ia32_CJmpAM(const ir_node *irn, ia32_emit_env_t *env) { - FILE *F = env->out; - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; +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); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, " "); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F omitted redundant test/cmp */", irn); - IA32_DO_EMIT(irn); - finish_CondJmp(F, irn, mode_Is); + finish_CondJmp(env, node, mode_Is, get_ia32_pncode(node)); } /** * Emits code for conditional SSE floating point jump with two variables. */ -static void emit_ia32_xCondJmp(ir_node *irn, ia32_emit_env_t *env) { - FILE *F = env->out; - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; - const lc_arg_env_t *arg_env = ia32_get_arg_env(); - - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %s", irn, ia32_emit_binop(irn, env)); - lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); - IA32_DO_EMIT(irn); +static void emit_ia32_xCondJmp(ia32_emit_env_t *env, const ir_node *node) { + ia32_emit_cstring(env, "\tucomis"); + ia32_emit_mode_suffix(env, get_irn_mode(node)); + ia32_emit_char(env, ' '); + ia32_emit_binop(env, node); + ia32_emit_finish_line(env, node); - finish_CondJmp(F, irn, mode_F); + finish_CondJmp(env, node, mode_F, get_ia32_pncode(node)); } /** * 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); +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; - const char *instr = "fcom"; - int reverse = 0; + long pnc = get_ia32_pncode(node); - switch (get_ia32_irn_opcode(irn)) { + switch (get_ia32_irn_opcode(node)) { case iro_ia32_fcomrJmp: - reverse = 1; + pnc = get_inversed_pnc(pnc); case iro_ia32_fcomJmp: default: - instr = "fucom"; + ia32_emit_cstring(env, "\tfucom "); break; case iro_ia32_fcomrpJmp: - reverse = 1; + pnc = get_inversed_pnc(pnc); case iro_ia32_fcompJmp: - instr = "fucomp"; + ia32_emit_cstring(env, "\tfucomp "); break; case iro_ia32_fcomrppJmp: - reverse = 1; + pnc = get_inversed_pnc(pnc); case iro_ia32_fcomppJmp: - instr = "fucompp"; + ia32_emit_cstring(env, "\tfucompp "); reg = ""; break; } - if (reverse) - set_ia32_pncode(irn, get_inversed_pnc(get_ia32_pncode(irn))); + if(reg[0] != '\0') { + ia32_emit_char(env, '%'); + ia32_emit_string(env, reg); + } + ia32_emit_finish_line(env, node); - 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); - 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); + ia32_emit_cstring(env, "\tfnstsw %ax"); + ia32_emit_finish_line(env, node); + ia32_emit_cstring(env, "\tsahf"); + ia32_emit_finish_line(env, node); - /* the compare flags must be evaluated using carry , ie unsigned */ - finish_CondJmp(F, irn, mode_Is); + finish_CondJmp(env, node, mode_D, pnc); } -static void CMov_emitter(ir_node *irn, ia32_emit_env_t *env) { - FILE *F = env->out; - const lc_arg_env_t *arg_env = ia32_get_arg_env(); - const char *cmp_suffix = get_cmp_suffix(get_ia32_pncode(irn)); - int is_PsiCondCMov = is_ia32_PsiCondCMov(irn); +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; int idx_right = 3 - is_PsiCondCMov; - - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; const arch_register_t *in1, *in2, *out; - out = arch_get_irn_register(env->arch_env, irn); - in1 = arch_get_irn_register(env->arch_env, get_irn_n(irn, idx_left)); - in2 = arch_get_irn_register(env->arch_env, get_irn_n(irn, idx_right)); + out = arch_get_irn_register(env->arch_env, node); + in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_left)); + in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, idx_right)); /* we have to emit the cmp first, because the destination register */ /* could be one of the compare registers */ - if (is_ia32_CmpCMov(irn)) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, %2S", irn, irn); - } - else if (is_ia32_xCmpCMov(irn)) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %1S, %2S", get_irn_n(irn, 0), irn, irn); - } - else if (is_PsiCondCMov) { + if (is_ia32_CmpCMov(node)) { + ia32_emit_cstring(env, "\tcmp "); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + } else if (is_ia32_xCmpCMov(node)) { + ia32_emit_cstring(env, "\tucomis"); + ia32_emit_mode_suffix(env, get_irn_mode(node)); + ia32_emit_char(env, ' '); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + } else if (is_PsiCondCMov) { /* omit compare because flags are already set by And/Or */ - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "test %1S, %1S", irn, irn); - } - else { + ia32_emit_cstring(env, "\ttest "); + ia32_emit_source_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + } else { assert(0 && "unsupported CMov"); } - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* Psi condition */" ); - IA32_DO_EMIT(irn); + ia32_emit_finish_line(env, node); if (REGS_ARE_EQUAL(out, in2)) { /* best case: default in == out -> do nothing */ - } - else if (REGS_ARE_EQUAL(out, in1)) { + } else if (REGS_ARE_EQUAL(out, in1)) { + ir_node *n = (ir_node*) node; /* true in == out -> need complement compare and exchange true and default in */ - ir_node *t = get_irn_n(irn, idx_left); - set_irn_n(irn, idx_left, get_irn_n(irn, idx_right)); - set_irn_n(irn, idx_right, t); + ir_node *t = get_irn_n(n, idx_left); + set_irn_n(n, idx_left, get_irn_n(n, idx_right)); + set_irn_n(n, idx_right, t); - cmp_suffix = get_cmp_suffix(get_negated_pnc(get_ia32_pncode(irn), get_irn_mode(irn))); - - } - else { + pnc = get_negated_pnc(pnc, get_irn_mode(node)); + } else { /* out is different from in: need copy default -> out */ - 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); + if (is_PsiCondCMov) { + ia32_emit_cstring(env, "\tmovl "); + ia32_emit_dest_register(env, node, 2); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } else { + ia32_emit_cstring(env, "\tmovl "); + ia32_emit_source_register(env, node, 3); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } + ia32_emit_finish_line(env, node); } - 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); + if (is_PsiCondCMov) { + ia32_emit_cstring(env, "\tcmov"); + ia32_emit_cmp_suffix(env, pnc); + ia32_emit_cstring(env, "l "); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } else { + ia32_emit_cstring(env, "\tcmov"); + ia32_emit_cmp_suffix(env, pnc); + ia32_emit_cstring(env, "l "); + ia32_emit_source_register(env, node, 2); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } + ia32_emit_finish_line(env, node); } -static void emit_ia32_CmpCMov(ir_node *irn, ia32_emit_env_t *env) { - CMov_emitter(irn, env); +static void emit_ia32_CmpCMov(ia32_emit_env_t *env, const ir_node *node) { + CMov_emitter(env, node); } -static void emit_ia32_PsiCondCMov(ir_node *irn, ia32_emit_env_t *env) { - CMov_emitter(irn, env); +static void emit_ia32_PsiCondCMov(ia32_emit_env_t *env, const ir_node *node) { + CMov_emitter(env, node); } -static void emit_ia32_xCmpCMov(ir_node *irn, ia32_emit_env_t *env) { - CMov_emitter(irn, env); +static void emit_ia32_xCmpCMov(ia32_emit_env_t *env, const ir_node *node) { + CMov_emitter(env, node); } -static void Set_emitter(ir_node *irn, ir_mode *mode, ia32_emit_env_t *env) { - FILE *F = env->out; - const lc_arg_env_t *arg_env = ia32_get_arg_env(); - const char *cmp_suffix = get_cmp_suffix(get_ia32_pncode(irn)); +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; - - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; const arch_register_t *out; - out = arch_get_irn_register(env->arch_env, irn); + out = arch_get_irn_register(env->arch_env, node); reg8bit = ia32_get_mapped_reg_name(env->isa->regs_8bit, out); - if (is_ia32_CmpSet(irn)) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %s", ia32_emit_binop(irn, env)); - } - else if (is_ia32_xCmpSet(irn)) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ucomis%M %s", get_irn_n(irn, 2), ia32_emit_binop(irn, env)); - } - else if (is_ia32_PsiCondSet(irn)) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, 0", irn); - } - else { + if (is_ia32_CmpSet(node)) { + ia32_emit_cstring(env, "\tcmp "); + ia32_emit_binop(env, node); + } else if (is_ia32_xCmpSet(node)) { + ia32_emit_cstring(env, "\tucomis"); + ia32_emit_mode_suffix(env, get_irn_mode(get_irn_n(node, 2))); + ia32_emit_char(env, ' '); + ia32_emit_binop(env, node); + } else if (is_ia32_PsiCondSet(node)) { + ia32_emit_cstring(env, "\tcmp $0, "); + ia32_emit_source_register(env, node, 0); + } else { assert(0 && "unsupported Set"); } - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* calculate Psi condition */" ); - IA32_DO_EMIT(irn); + ia32_emit_finish_line(env, node); /* use mov to clear target because it doesn't affect the eflags */ - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "mov %%%s, 0", arch_register_get_name(out)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* clear target as set modifies only lower 8 bit */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tmovl $0, %"); + ia32_emit_string(env, arch_register_get_name(out)); + ia32_emit_finish_line(env, node); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "set%s %%%s", cmp_suffix, reg8bit); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* set 1 iff true, 0 otherweise */" ); - IA32_DO_EMIT(irn); + ia32_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); } -static void emit_ia32_CmpSet(ir_node *irn, ia32_emit_env_t *env) { - Set_emitter(irn, get_irn_mode(get_irn_n(irn, 2)), env); +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(ir_node *irn, ia32_emit_env_t *env) { - Set_emitter(irn, get_irn_mode(get_irn_n(irn, 0)), env); +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(ir_node *irn, ia32_emit_env_t *env) { - Set_emitter(irn, get_irn_mode(get_irn_n(irn, 2)), env); +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(ir_node *irn, ia32_emit_env_t *env) { - FILE *F = env->out; - const lc_arg_env_t *arg_env = ia32_get_arg_env(); - int sse_pnc = -1; - long pnc = get_ia32_pncode(irn); - long unord = pnc & pn_Cmp_Uo; - char cmd_buf[SNPRINTF_BUF_LEN]; - char cmnt_buf[SNPRINTF_BUF_LEN]; +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; assert( (pnc & ia32_pn_Cmp_Unsigned) == 0); @@ -1236,28 +1126,31 @@ static void emit_ia32_xCmp(ir_node *irn, ia32_emit_env_t *env) { - and result and stored result - cleanup stack */ - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "sub %%esp, 8"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* reserve some space for unordered compare result */"); - IA32_DO_EMIT(NULL); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cmpsd %s, 3", ia32_emit_binop(irn, env)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* SSE compare: unordered */"); - IA32_DO_EMIT(NULL); - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "movsd [%%esp], %1D", irn); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* store compare result */"); - IA32_DO_EMIT(NULL); + ia32_emit_cstring(env, "\tsubl $8, %esp"); + ia32_emit_finish_line(env, node); + + ia32_emit_cstring(env, "\tcmpsd $3, "); + ia32_emit_binop(env, node); + ia32_emit_finish_line(env, node); + + ia32_emit_cstring(env, "\tmovsd "); + ia32_emit_dest_register(env, node, 0); + ia32_emit_cstring(env, ", (%esp)"); + ia32_emit_finish_line(env, node); } - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cmpsd %s, %d", ia32_emit_binop(irn, env), sse_pnc); - lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* SSE compare (%+F) with result in %1D */", irn, irn); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tcmpsd "); + ia32_emit_irprintf(env, "%d, ", sse_pnc); + ia32_emit_binop(env, node); + ia32_emit_finish_line(env, node); if (unord && sse_pnc != 3) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "andpd %1D, [%%esp]", irn); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* build the final result */"); - IA32_DO_EMIT(NULL); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "add %%esp, 8"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* free allocated space */"); - IA32_DO_EMIT(NULL); + ia32_emit_cstring(env, "\tandpd (%esp), "); + ia32_emit_dest_register(env, node, 0); + ia32_emit_finish_line(env, node); + + ia32_emit_cstring(env, "\taddl $8, %esp"); + ia32_emit_finish_line(env, node); } } @@ -1306,43 +1199,40 @@ 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(const ir_node *irn, ia32_emit_env_t *emit_env) { +static void emit_ia32_SwitchJmp(ia32_emit_env_t *env, const ir_node *node) { unsigned long interval; - char buf[SNPRINTF_BUF_LEN]; - int last_value, i, pn; + int last_value, i; + long pnc; jmp_tbl_t tbl; ir_node *proj; const ir_edge_t *edge; - const lc_arg_env_t *env = ia32_get_arg_env(); - FILE *F = emit_env->out; - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; /* fill the table structure */ tbl.label = xmalloc(SNPRINTF_BUF_LEN); tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, ".TBL_"); tbl.defProj = NULL; - tbl.num_branches = get_irn_n_edges(irn); + tbl.num_branches = get_irn_n_edges(node); tbl.branches = xcalloc(tbl.num_branches, sizeof(tbl.branches[0])); tbl.min_value = INT_MAX; tbl.max_value = INT_MIN; i = 0; /* go over all proj's and collect them */ - foreach_out_edge(irn, edge) { + foreach_out_edge(node, edge) { proj = get_edge_src_irn(edge); assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); - pn = get_Proj_proj(proj); + pnc = get_Proj_proj(proj); /* create branch entry */ tbl.branches[i].target = proj; - tbl.branches[i].value = pn; + tbl.branches[i].value = pnc; - tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value; - tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value; + tbl.min_value = pnc < tbl.min_value ? pnc : tbl.min_value; + tbl.max_value = pnc > tbl.max_value ? pnc : tbl.max_value; /* check for default proj */ - if (pn == get_ia32_pncode(irn)) { + if (pnc == get_ia32_pncode(node)) { assert(tbl.defProj == NULL && "found two defProjs at SwitchJmp"); tbl.defProj = proj; } @@ -1357,48 +1247,53 @@ static void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) { interval = tbl.max_value - tbl.min_value; /* emit the table */ - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, %u", irn, interval); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* compare for switch */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tcmpl $"); + ia32_emit_irprintf(env, "%u, ", interval); + ia32_emit_source_register(env, node, 0); + ia32_emit_finish_line(env, node); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "ja %s", get_cfop_target(tbl.defProj, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default jump if out of range */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tja "); + ia32_emit_cfop_target(env, tbl.defProj); + ia32_emit_finish_line(env, node); if (tbl.num_branches > 1) { /* create table */ + ia32_emit_cstring(env, "\tjmp *"); + ia32_emit_string(env, tbl.label); + ia32_emit_cstring(env, "(,"); + ia32_emit_source_register(env, node, 0); + ia32_emit_cstring(env, ",4)"); + ia32_emit_finish_line(env, node); - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "jmp %s[%1S*4]", tbl.label, irn); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get jump table entry as target */"); - IA32_DO_EMIT(irn); - - ia32_switch_section(F, SECTION_RODATA); - fprintf(F, "\t.align 4\n"); + ia32_switch_section(env->out, SECTION_RODATA); + ia32_emit_cstring(env, "\t.align 4\n"); + ia32_write_line(env); - fprintf(F, "%s:\n", tbl.label); + ia32_emit_string(env, tbl.label); + ia32_emit_cstring(env, ":\n"); + ia32_write_line(env); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[0].target, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", tbl.branches[0].value); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, ".long "); + ia32_emit_cfop_target(env, tbl.branches[0].target); + ia32_emit_finish_line(env, NULL); last_value = tbl.branches[0].value; for (i = 1; i < tbl.num_branches; ++i) { while (++last_value < tbl.branches[i].value) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.defProj, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* default case */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, ".long "); + ia32_emit_cfop_target(env, tbl.defProj); + ia32_emit_finish_line(env, NULL); } - snprintf(cmd_buf, SNPRINTF_BUF_LEN, ".long %s", get_cfop_target(tbl.branches[i].target, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, ".long "); + ia32_emit_cfop_target(env, tbl.branches[i].target); + ia32_emit_finish_line(env, NULL); } - ia32_switch_section(F, SECTION_TEXT); - } - else { + ia32_switch_section(env->out, SECTION_TEXT); + } else { /* one jump is enough */ - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(tbl.branches[0].target, buf)); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* only one case given */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tjmp "); + ia32_emit_cfop_target(env, tbl.branches[0].target); + ia32_emit_finish_line(env, node); } if (tbl.label) @@ -1410,53 +1305,23 @@ static void emit_ia32_SwitchJmp(const ir_node *irn, ia32_emit_env_t *emit_env) { /** * Emits code for a unconditional jump. */ -static void emit_Jmp(const ir_node *irn, ia32_emit_env_t *env) { - ir_node *block, *next_bl; - FILE *F = env->out; - char buf[SNPRINTF_BUF_LEN], cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; +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 */ - block = get_nodes_block(irn); + block = get_nodes_block(node); /* we have a block schedule */ - next_bl = next_blk_sched(block); - if (get_cfop_target_block(irn) != next_bl) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "jmp %s", get_cfop_target(irn, buf)); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%+F) */", irn, get_cfop_target_block(irn)); - } - else { - cmd_buf[0] = '\0'; - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough %s */", get_cfop_target(irn, buf)); - } - IA32_DO_EMIT(irn); -} - -/**************************** - * _ - * (_) - * _ __ _ __ ___ _ ___ - * | '_ \| '__/ _ \| |/ __| - * | |_) | | | (_) | |\__ \ - * | .__/|_| \___/| ||___/ - * | | _/ | - * |_| |__/ - ****************************/ - -/** - * Emits code for a proj -> node - */ -static void emit_Proj(const ir_node *irn, ia32_emit_env_t *env) { - ir_node *pred = get_Proj_pred(irn); - - if (get_irn_op(pred) == op_Start) { - switch(get_Proj_proj(irn)) { - case pn_Start_X_initial_exec: - emit_Jmp(irn, env); - break; - default: - break; - } + next_block = next_blk_sched(block); + if (get_cfop_target_block(node) != next_block) { + ia32_emit_cstring(env, "\tjmp "); + ia32_emit_cfop_target(env, node); + } else { + ia32_emit_cstring(env, "\t/* fallthrough to "); + ia32_emit_cfop_target(env, node); + ia32_emit_cstring(env, " */"); } + ia32_emit_finish_line(env, node); } /********************************** @@ -1473,70 +1338,54 @@ static void emit_Proj(const ir_node *irn, ia32_emit_env_t *env) { /** * Emit movsb/w instructions to make mov count divideable by 4 */ -static void emit_CopyB_prolog(FILE *F, const ir_node *irn, int rem) { - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - - ir_fprintf(F, "\t/* memcopy prolog %+F */\n", irn); - - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cld"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* copy direction forward */"); +static void emit_CopyB_prolog(ia32_emit_env_t *env, int rem) { + ia32_emit_cstring(env, "\tcld"); + ia32_emit_finish_line(env, NULL); switch(rem) { - case 1: - IA32_DO_EMIT(NULL); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsb"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 1 */"); - break; - case 2: - IA32_DO_EMIT(NULL); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsw"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 2 */"); - break; - case 3: - IA32_DO_EMIT(NULL); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsb"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 3 */"); - IA32_DO_EMIT(NULL); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsw"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy remainder 3 */"); - break; + case 1: + ia32_emit_cstring(env, "\tmovsb"); + ia32_emit_finish_line(env, NULL); + break; + case 2: + ia32_emit_cstring(env, "\tmovsw"); + ia32_emit_finish_line(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); + break; } - - IA32_DO_EMIT(NULL); } /** * Emit rep movsd instruction for memcopy. */ -static void emit_ia32_CopyB(const ir_node *irn, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; - tarval *tv = get_ia32_Immop_tarval(irn); +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); - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - emit_CopyB_prolog(F, irn, rem); + emit_CopyB_prolog(env, rem); - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "rep movsd"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\trep movsd"); + ia32_emit_finish_line(env, node); } /** * Emits unrolled memcopy. */ -static void emit_ia32_CopyB_i(const ir_node *irn, ia32_emit_env_t *emit_env) { - tarval *tv = get_ia32_Immop_tarval(irn); +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); - FILE *F = emit_env->out; - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - emit_CopyB_prolog(F, irn, size & 0x3); + emit_CopyB_prolog(env, size & 0x3); size >>= 2; while (size--) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "movsd"); - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* memcopy unrolled */"); - IA32_DO_EMIT(irn); + ia32_emit_cstring(env, "\tmovsd"); + ia32_emit_finish_line(env, NULL); } } @@ -1555,129 +1404,142 @@ static void emit_ia32_CopyB_i(const ir_node *irn, ia32_emit_env_t *emit_env) { /** * Emit code for conversions (I, FP), (FP, I) and (FP, FP). */ -static void emit_ia32_Conv_with_FP(const ir_node *irn, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; - const lc_arg_env_t *env = ia32_get_arg_env(); - ir_mode *ls_mode = get_ia32_ls_mode(irn); - int ls_bits = get_mode_size_bits(ls_mode); - char *from, *to, buf[64]; - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - - if(is_ia32_Conv_I2FP(irn)) { - from = "si"; - to = ls_bits == 32 ? "ss" : "sd"; - } else if(is_ia32_Conv_FP2I(irn)) { - from = ls_bits == 32 ? "ss" : "sd"; - to = "si"; +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"); + + if(is_ia32_Conv_I2FP(node)) { + if(ls_bits == 32) { + ia32_emit_cstring(env, "si2ss"); + } else { + ia32_emit_cstring(env, "si2sd"); + } + } else if(is_ia32_Conv_FP2I(node)) { + if(ls_bits == 32) { + ia32_emit_cstring(env, "ss2si"); + } else { + ia32_emit_cstring(env, "sd2si"); + } } else { - assert(is_ia32_Conv_FP2FP(irn)); - from = ls_bits == 32 ? "sd" : "ss"; - to = ls_bits == 32 ? "ss" : "sd"; + assert(is_ia32_Conv_FP2FP(node)); + if(ls_bits == 32) { + ia32_emit_cstring(env, "sd2ss"); + } else { + ia32_emit_cstring(env, "ss2sd"); + } } - switch(get_ia32_op_type(irn)) { + switch(get_ia32_op_type(node)) { case ia32_Normal: - lc_esnprintf(env, buf, sizeof(buf), "%1D, %3S", irn, irn); + ia32_emit_dest_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 2); break; case ia32_AddrModeS: - lc_esnprintf(env, buf, sizeof(buf), "%1D, %s", irn, ia32_emit_am(irn, emit_env)); + ia32_emit_dest_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_am(env, node); break; default: assert(0 && "unsupported op type for Conv"); } - - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "cvt%s2%s %s", from, to, buf); - lc_esnprintf(env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); - IA32_DO_EMIT(irn); + ia32_emit_finish_line(env, node); } -static void emit_ia32_Conv_I2FP(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv_with_FP(irn, emit_env); +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(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv_with_FP(irn, emit_env); +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(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv_with_FP(irn, emit_env); +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(const ir_node *irn, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; - const lc_arg_env_t *env = ia32_get_arg_env(); - char *move_cmd = "movzx"; - char *conv_cmd = NULL; - ir_mode *smaller_mode = get_ia32_ls_mode(irn); - int smaller_bits = get_mode_size_bits(smaller_mode); - int signed_mode; - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; +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); + int signed_mode; const arch_register_t *in_reg, *out_reg; assert(!mode_is_float(smaller_mode)); assert(smaller_bits == 8 || smaller_bits == 16 || smaller_bits == 32); signed_mode = mode_is_signed(smaller_mode); - if(signed_mode) { - move_cmd = "movsx"; + if(smaller_bits == 32) { + // this should not happen as it's no convert + assert(0); + sign_suffix = ""; + } else { + sign_suffix = signed_mode ? "s" : "z"; } - switch(get_ia32_op_type(irn)) { + switch(get_ia32_op_type(node)) { case ia32_Normal: - in_reg = get_in_reg(irn, 2); - out_reg = get_out_reg(irn, 0); + in_reg = get_in_reg(node, 2); + out_reg = get_out_reg(node, 0); if (REGS_ARE_EQUAL(in_reg, &ia32_gp_regs[REG_EAX]) && REGS_ARE_EQUAL(out_reg, in_reg) && signed_mode) { - if (smaller_bits == 8) - conv_cmd = "cbw"; - else if (smaller_bits == 16) - conv_cmd = "cwde"; - else - assert(0); - /* argument and result are both in EAX and */ /* signedness is ok: -> use converts */ - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s", conv_cmd); - } - else if (REGS_ARE_EQUAL(out_reg, in_reg) && ! signed_mode) - { + if (smaller_bits == 8) { + ia32_emit_cstring(env, "\tcbtw"); + } else if (smaller_bits == 16) { + ia32_emit_cstring(env, "\tcwtl"); + } else { + assert(0); + } + } else if (REGS_ARE_EQUAL(out_reg, in_reg) && !signed_mode) { /* argument and result are in the same register */ /* and signedness is ok: -> use and with mask */ int mask = (1 << smaller_bits) - 1; - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "and %1D, 0x%x", irn, mask); - } - else { - /* use move w/o sign extension */ - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s %1D, %%%s", - move_cmd, irn, - ia32_get_reg_name_for_mode(emit_env, smaller_mode, in_reg)); + ia32_emit_cstring(env, "\tandl $0x"); + ia32_emit_irprintf(env, "%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); + ia32_emit_mode_suffix(env, smaller_mode); + ia32_emit_cstring(env, "l %"); + ia32_emit_string(env, sreg); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); } - break; - case ia32_AddrModeS: - lc_esnprintf(env, cmd_buf, SNPRINTF_BUF_LEN, "%s %1D, %s", - move_cmd, irn, ia32_emit_am(irn, emit_env)); + case ia32_AddrModeS: { + ia32_emit_cstring(env, "\tmov"); + ia32_emit_string(env, sign_suffix); + ia32_emit_mode_suffix(env, smaller_mode); + ia32_emit_cstring(env, "l %"); + ia32_emit_am(env, node); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); break; + } default: assert(0 && "unsupported op type for Conv"); } - - lc_esnprintf(env, cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); - - IA32_DO_EMIT(irn); + ia32_emit_finish_line(env, node); } /** * Emits code for an 8Bit Int conversion. */ -void emit_ia32_Conv_I2I8Bit(const ir_node *irn, ia32_emit_env_t *emit_env) { - emit_ia32_Conv_I2I(irn, emit_env); +void emit_ia32_Conv_I2I8Bit(ia32_emit_env_t *env, const ir_node *node) { + emit_ia32_Conv_I2I(env, node); } @@ -1694,97 +1556,92 @@ void emit_ia32_Conv_I2I8Bit(const ir_node *irn, ia32_emit_env_t *emit_env) { /** * Emits a backend call */ -static void emit_be_Call(const ir_node *irn, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; - ir_entity *ent = be_Call_get_entity(irn); - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; +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 "); if (ent) { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, "call %s", get_entity_ld_name(ent)); - } - else { - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "call %1D", get_irn_n(irn, be_pos_Call_ptr)); + ia32_emit_string(env, get_entity_ld_name(ent)); + } else { + ia32_emit_char(env, '*'); + ia32_emit_dest_register(env, get_irn_n(node, be_pos_Call_ptr), 0); } - - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (be_Call) */", irn); - - IA32_DO_EMIT(irn); + ia32_emit_finish_line(env, node); } /** * Emits code to increase stack pointer. */ -static void emit_be_IncSP(const ir_node *irn, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; - int offs = be_get_IncSP_offset(irn); - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - - if (offs) { - if (offs > 0) - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "sub %1S, %u", irn, offs); - else - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1S, %u", irn, -offs); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (IncSP) */", irn); - } - else { - snprintf(cmd_buf, SNPRINTF_BUF_LEN, " "); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted %+F (IncSP) with 0 */", irn); - } +static void emit_be_IncSP(ia32_emit_env_t *env, const ir_node *node) { + int offs = be_get_IncSP_offset(node); + + if (offs == 0) + return; - IA32_DO_EMIT(irn); + if (offs > 0) { + ia32_emit_cstring(env, "\tsubl $"); + ia32_emit_irprintf(env, "%u, ", offs); + ia32_emit_source_register(env, node, 0); + } else { + ia32_emit_cstring(env, "\taddl $"); + ia32_emit_irprintf(env, "%u, ", -offs); + ia32_emit_source_register(env, node, 0); + } + ia32_emit_finish_line(env, node); } /** * Emits code to set stack pointer. */ -static void emit_be_SetSP(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]; - - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %3S", irn, irn); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (restore SP) */", irn); - IA32_DO_EMIT(irn); +static void emit_be_SetSP(ia32_emit_env_t *env, const ir_node *node) { + ia32_emit_cstring(env, "\tmovl "); + ia32_emit_source_register(env, node, 2); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + ia32_emit_finish_line(env, node); } /** * Emits code for Copy/CopyKeep. */ -static void Copy_emitter(const ir_node *irn, ir_node *op, ia32_emit_env_t *emit_env) { - FILE *F = emit_env->out; - const arch_env_t *aenv = emit_env->arch_env; - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; +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; - if (REGS_ARE_EQUAL(arch_get_irn_register(aenv, irn), arch_get_irn_register(aenv, op)) || + 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(irn))) - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "movsd %1D, %1S", irn, irn, irn); - else - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %1S", irn, irn); - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F */", irn); - IA32_DO_EMIT(irn); + if (mode_is_float(get_irn_mode(node))) { + ia32_emit_cstring(env, "\tmovsd "); + ia32_emit_source_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } else { + ia32_emit_cstring(env, "\tmovl "); + ia32_emit_source_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); + } + ia32_emit_finish_line(env, node); } -static void emit_be_Copy(const ir_node *irn, ia32_emit_env_t *emit_env) { - Copy_emitter(irn, be_get_Copy_op(irn), emit_env); +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(const ir_node *irn, ia32_emit_env_t *emit_env) { - Copy_emitter(irn, be_get_CopyKeep_op(irn), emit_env); +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(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]; +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; - in1 = arch_get_irn_register(emit_env->arch_env, get_irn_n(irn, 0)); - in2 = arch_get_irn_register(emit_env->arch_env, get_irn_n(irn, 1)); + in1 = arch_get_irn_register(env->arch_env, get_irn_n(node, 0)); + in2 = arch_get_irn_register(env->arch_env, get_irn_n(node, 1)); cls1 = arch_register_get_class(in1); cls2 = arch_register_get_class(in2); @@ -1804,142 +1661,90 @@ static void emit_be_Perm(const ir_node *irn, ia32_emit_env_t *emit_env) { lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xor %1S, %2S", irn, irn); } else { #endif - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "xchg %1S, %2S", irn, irn); + ia32_emit_cstring(env, "\txchg "); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + ia32_emit_finish_line(env, node); #if 0 } #endif - } - else if (cls1 == &ia32_reg_classes[CLASS_ia32_xmm]) { - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, - "pxor %1S, %2S\n\tpxor %2S, %1S\n\tpxor %1S, %2S", irn, irn, irn, irn, irn, irn); - } - else if (cls1 == &ia32_reg_classes[CLASS_ia32_vfp]) { + } else if (cls1 == &ia32_reg_classes[CLASS_ia32_xmm]) { + ia32_emit_cstring(env, "\tpxorq "); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + ia32_emit_finish_line(env, NULL); + + ia32_emit_cstring(env, "\tpxorq "); + ia32_emit_source_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 1); + ia32_emit_finish_line(env, NULL); + + ia32_emit_cstring(env, "\tpxorq "); + ia32_emit_source_register(env, node, 1); + ia32_emit_cstring(env, ", "); + ia32_emit_source_register(env, node, 0); + ia32_emit_finish_line(env, node); + } else if (cls1 == &ia32_reg_classes[CLASS_ia32_vfp]) { /* is a NOP */ - cmd_buf[0] = '\0'; - } - else if (cls1 == &ia32_reg_classes[CLASS_ia32_st]) { + } else if (cls1 == &ia32_reg_classes[CLASS_ia32_st]) { /* is a NOP */ - cmd_buf[0] = '\0'; } - - lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F(%1A, %2A) */", irn, irn, irn); - IA32_DO_EMIT(irn); } /** * Emits code for Constant loading. */ -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(); - 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 */"); +static void emit_ia32_Const(ia32_emit_env_t *env, const ir_node *node) { + ir_mode *mode = get_irn_mode(node); + ia32_immop_type_t imm_tp = get_ia32_immop_type(node); + + if (imm_tp == ia32_ImmSymConst) { + ia32_emit_cstring(env, "\tmovl $"); + ia32_emit_immediate(env, node); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); } else { + tarval *tv = get_ia32_Immop_tarval(node); assert(mode == mode_Iu); /* 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 (tarval_is_null(tv)) { if (env->isa->opt_arch == arch_pentium_4) { /* P4 prefers sub r, r, others xor r, r */ - instr = "sub"; + ia32_emit_cstring(env, "\tsubl "); + } else { + ia32_emit_cstring(env, "\txorl "); } - 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 */"); + ia32_emit_dest_register(env, node, 0); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); } else { - lc_esnprintf(arg_env, cmd_buf, 256, "mov %1D, %C ", n, n); - lc_esnprintf(arg_env, cmnt_buf, 256, "/* Mov Const into register */"); + ia32_emit_cstring(env, "\tmovl $"); + ia32_emit_immediate(env, node); + ia32_emit_cstring(env, ", "); + ia32_emit_dest_register(env, node, 0); } } - lc_efprintf(arg_env, F, "\t%-35s %-60s /* %+F (%+G) */\n", cmd_buf, cmnt_buf, n, n); -} - -/** - * 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; - 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, "sub %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, "sub %1D, OFFSET_FLAT:%C", irn, irn); - else /* source address mode */ - lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "sub %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, "sub %1D, %2S", irn, irn); - } - snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* reserve space on stack */"); - - 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); + ia32_emit_finish_line(env, node); } /** * 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_ia32_LdTls(ia32_emit_env_t *env, const ir_node *node) { + ia32_emit_cstring(env, "\tmovl %gs:0, "); + ia32_emit_dest_register(env, node, 0); + ia32_emit_finish_line(env, node); } -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(); - - lc_efprintf(arg_env, F, "\t%-35s %-60s /* %+F (%+G) */\n", "ret", "/* be_Return */", n, n); +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); } -static void emit_Nothing(const ir_node *n, ia32_emit_env_t *env) { - FILE *F = env->out; - - ir_fprintf(F, "\t%35s /* %+F (%+G) */\n", " ", n, n); +static void emit_Nothing(ia32_emit_env_t *env, const ir_node *node) { } @@ -1990,8 +1795,6 @@ static void ia32_register_emitters(void) { IA32_EMIT(Conv_I2I); IA32_EMIT(Conv_I2I8Bit); IA32_EMIT(Const); - IA32_EMIT(AddSP); - IA32_EMIT(SubSP); IA32_EMIT(LdTls); IA32_EMIT(xCmp); IA32_EMIT(xCmpSet); @@ -2019,7 +1822,7 @@ static void ia32_register_emitters(void) { /* firm emitter */ EMIT(Jmp); - EMIT(Proj); + IGN(Proj); IGN(Phi); IGN(Start); @@ -2035,10 +1838,10 @@ static unsigned last_line = -1; static unsigned num = -1; /** - * Emit the debug support for node irn. + * Emit the debug support for node node. */ -static void ia32_emit_dbg(const ir_node *irn, ia32_emit_env_t *env) { - dbg_info *db = get_irn_dbg_info(irn); +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); @@ -2063,38 +1866,40 @@ static void ia32_emit_dbg(const ir_node *irn, ia32_emit_env_t *env) { } } +typedef void (*emit_func_ptr) (ia32_emit_env_t *, const ir_node *); + /** * Emits code for a node. */ -static void ia32_emit_node(const ir_node *irn, void *env) { - ia32_emit_env_t *emit_env = env; - ir_op *op = get_irn_op(irn); - DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;) +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", 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; - ia32_emit_dbg(irn, emit_env); - (*emit)(irn, env); - } - else { - emit_Nothing(irn, env); - ir_fprintf(stderr, "Warning: No emit handler for node %+F (%+G)\n", irn, irn); + emit_func_ptr func = (emit_func_ptr) op->ops.generic; + ia32_emit_dbg(env, node); + (*func) (env, node); + } else { + emit_Nothing(env, node); + ir_fprintf(stderr, "Warning: No emit handler for node %+F (%+G)\n", node, node); } } /** * Emits gas alignment directives */ -static void ia32_emit_alignment(FILE *F, unsigned align, unsigned skip) { - fprintf(F, "\t.p2align %u,,%u\n", align, skip); +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); } /** * Emits gas alignment directives for Functions depended on cpu architecture. */ -static void ia32_emit_align_func(FILE *F, cpu_support cpu) { +static void ia32_emit_align_func(ia32_emit_env_t *env, cpu_support cpu) { unsigned align; unsigned maximum_skip; @@ -2112,13 +1917,13 @@ static void ia32_emit_align_func(FILE *F, cpu_support cpu) { align = 4; } maximum_skip = (1 << align) - 1; - ia32_emit_alignment(F, align, maximum_skip); + ia32_emit_alignment(env, align, maximum_skip); } /** * Emits gas alignment directives for Labels depended on cpu architecture. */ -static void ia32_emit_align_label(FILE *F, cpu_support cpu) { +static void ia32_emit_align_label(ia32_emit_env_t *env, cpu_support cpu) { unsigned align; unsigned maximum_skip; switch (cpu) { @@ -2135,10 +1940,10 @@ static void ia32_emit_align_label(FILE *F, cpu_support cpu) { align = 4; } maximum_skip = (1 << align) - 1; - ia32_emit_alignment(F, align, maximum_skip); + ia32_emit_alignment(env, align, maximum_skip); } -static int is_first_loop_block(ir_node *block, ir_node *prev_block, ia32_emit_env_t *env) { +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; static const double DELTA = .0001; @@ -2173,12 +1978,11 @@ static int is_first_loop_block(ir_node *block, ir_node *prev_block, ia32_emit_en * 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, ir_node *last_block, ia32_emit_env_t *env) { +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; - FILE *F = env->out; - const ir_node *irn; + const ir_node *node; int i; assert(is_Block(block)); @@ -2209,13 +2013,12 @@ static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t } if (need_label) { - char cmd_buf[SNPRINTF_BUF_LEN]; 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(block, last_block, env)) { + if (! is_first_loop_block(env, block, last_block)) { /* align blocks where the previous block has no fallthrough */ arity = get_irn_arity(block); @@ -2230,48 +2033,48 @@ static void ia32_gen_block(ir_node *block, ir_node *last_block, ia32_emit_env_t } if (align) - ia32_emit_align_label(env->out, env->isa->opt_arch); + ia32_emit_align_label(env, env->isa->opt_arch); - ir_snprintf(cmd_buf, sizeof(cmd_buf), BLOCK_PREFIX("%d:"), - get_irn_node_nr(block)); - fprintf(F, "%-43s ", cmd_buf); + ia32_emit_cstring(env, BLOCK_PREFIX); + ia32_emit_irprintf(env, "%d:", get_irn_node_nr(block)); + ia32_pad_comment(env); + ia32_emit_cstring(env, "\t/* preds:"); /* emit list of pred blocks in comment */ - fprintf(F, "/* preds:"); - arity = get_irn_arity(block); for (i = 0; i < arity; ++i) { ir_node *predblock = get_Block_cfgpred_block(block, i); - fprintf(F, " %ld", get_irn_node_nr(predblock)); + ia32_emit_irprintf(env, " %d", get_irn_node_nr(predblock)); } if (exec_freq != NULL) { - fprintf(F, " freq: %f", get_block_execfreq(exec_freq, block)); + ia32_emit_irprintf(env, " freq: %f", get_block_execfreq(exec_freq, block)); } - - fprintf(F, " */\n"); + ia32_emit_cstring(env, " */\n"); + ia32_write_line(env); } /* emit the contents of the block */ - ia32_emit_dbg(block, env); - sched_foreach(block, irn) { - ia32_emit_node(irn, env); + ia32_emit_dbg(env, block); + sched_foreach(block, node) { + ia32_emit_node(env, node); } } /** * Emits code for function start. */ -static void ia32_emit_func_prolog(FILE *F, ir_graph *irg, ia32_emit_env_t *emit_env) { +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 = emit_env->isa->opt_arch; - const be_irg_t *birg = emit_env->cg->birg; + 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_dbg_method_begin(birg->main_env->db_handle, irg_ent, be_abi_get_stack_layout(birg->abi)); - ia32_emit_align_func(F, cpu); + ia32_emit_align_func(env, cpu); if (get_entity_visibility(irg_ent) == visibility_external_visible) { fprintf(F, ".globl %s\n", irg_name); } @@ -2282,9 +2085,10 @@ static void ia32_emit_func_prolog(FILE *F, ir_graph *irg, ia32_emit_env_t *emit_ /** * Emits code for function end */ -static void ia32_emit_func_epilog(FILE *F, ir_graph *irg, ia32_emit_env_t *emit_env) { +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 = emit_env->cg->birg; + const be_irg_t *birg = env->cg->birg; + FILE *F = env->out; ia32_dump_function_size(F, irg_name); be_dbg_method_end(birg->main_env->db_handle); @@ -2294,9 +2098,8 @@ static void ia32_emit_func_epilog(FILE *F, ir_graph *irg, ia32_emit_env_t *emit_ /** * Block-walker: * Sets labels for control flow nodes (jump target) - * TODO: Jump optimization */ -static void ia32_gen_labels(ir_node *block, void *env) { +static void ia32_gen_labels(ir_node *block, void *data) { ir_node *pred; int n = get_Block_n_cfgpreds(block); @@ -2309,25 +2112,30 @@ static void ia32_gen_labels(ir_node *block, void *env) { /** * Main driver. Emits the code for one routine. */ -void ia32_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) { - ia32_emit_env_t emit_env; +void ia32_gen_routine(ia32_code_gen_t *cg, FILE *F, 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); - emit_env.out = F; - emit_env.arch_env = cg->arch_env; - emit_env.cg = cg; - emit_env.isa = (ia32_isa_t *)cg->arch_env->isa; - FIRM_DBG_REGISTER(emit_env.mod, "firm.be.ia32.emitter"); + env.out = F; + 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) */ arch_env = cg->arch_env; ia32_register_emitters(); - ia32_emit_func_prolog(F, irg, &emit_env); - irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env); + ia32_emit_func_prolog(&env, irg); + irg_block_walk_graph(irg, ia32_gen_labels, NULL, &env); n = ARR_LEN(cg->blk_sched); for (i = 0; i < n;) { @@ -2339,9 +2147,9 @@ void ia32_gen_routine(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg) { /* set here the link. the emitter expects to find the next block here */ set_irn_link(block, next_bl); - ia32_gen_block(block, last_block, &emit_env); + ia32_gen_block(&env, block, last_block); last_block = block; } - ia32_emit_func_epilog(F, irg, &emit_env); + ia32_emit_func_epilog(&env, irg); } diff --git a/ir/be/ia32/ia32_emitter.h b/ir/be/ia32/ia32_emitter.h index 40860d3a4..68d31575b 100644 --- a/ir/be/ia32/ia32_emitter.h +++ b/ir/be/ia32/ia32_emitter.h @@ -1,13 +1,12 @@ /** * Header file for ia32 emitter, containing some function definitions and types. - * @author Christian Wuerdig + * @author Christian Wuerdig, Matthias Braun * $Id$ */ - #ifndef _IA32_EMITTER_H_ #define _IA32_EMITTER_H_ -#include "irargs_t.h" // this also inlucdes +#include "irargs_t.h" #include "irnode.h" #include "debug.h" @@ -20,22 +19,45 @@ typedef struct _ia32_emit_env_t { 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; -const lc_arg_env_t *ia32_get_arg_env(void); +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; +} -const char *ia32_emit_binop(const ir_node *irn, ia32_emit_env_t *env); -const char *ia32_emit_unop(const ir_node *irn, ia32_emit_env_t *env); -const char *ia32_emit_am(const ir_node *irn, ia32_emit_env_t *env); -const char *ia32_emit_adr(const ir_node *irn, ia32_emit_env_t *env); +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); +} -const char *ia32_emit_x87_binop(const ir_node *n, ia32_emit_env_t *env); +#define ia32_emit_cstring(env,x) { ia32_emit_string_len(env, x, sizeof(x)-1); } -int get_ia32_reg_nr(ir_node *irn, int posi, int in_out); -const char *get_ia32_in_reg_name(ir_node *irn, int pos); +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); +void ia32_emit_immediate(ia32_emit_env_t *env, const ir_node *node); +void ia32_emit_mode_suffix(ia32_emit_env_t *env, const ir_mode *mode); +void ia32_emit_extend_suffix(ia32_emit_env_t *env, const ir_mode *mode); +void ia32_emit_binop(ia32_emit_env_t *env, const ir_node *node); +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(FILE *F, ir_graph *irg, const ia32_code_gen_t *cg); +void ia32_gen_routine(ia32_code_gen_t *cg, FILE *F, ir_graph *irg); /** * Sections. diff --git a/ir/be/ia32/ia32_finish.c b/ir/be/ia32/ia32_finish.c index cedfbad54..a3cf361e5 100644 --- a/ir/be/ia32/ia32_finish.c +++ b/ir/be/ia32/ia32_finish.c @@ -66,14 +66,14 @@ static void ia32_transform_sub_to_neg_add(ir_node *irn, ia32_code_gen_t *cg) { int size; ident *name; - res = new_rd_ia32_xEor(dbg, irg, block, noreg, noreg, in2, noreg_fp, nomem); + res = new_rd_ia32_xXor(dbg, irg, block, noreg, noreg, in2, noreg_fp, nomem); size = get_mode_size_bits(mode); name = ia32_gen_fp_known_const(size == 32 ? ia32_SSIGN : ia32_DSIGN); set_ia32_am_sc(res, name); set_ia32_op_type(res, ia32_AddrModeS); set_ia32_ls_mode(res, mode); } else { - res = new_rd_ia32_Minus(dbg, irg, block, noreg, noreg, in2, nomem); + res = new_rd_ia32_Neg(dbg, irg, block, noreg, noreg, in2, nomem); } arch_set_irn_register(cg->arch_env, res, in2_reg); @@ -124,9 +124,8 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { ir_node *res = NULL; ir_node *nomem, *noreg, *base, *index, *op1, *op2; ir_node *block; - const char *offs = NULL; + int offs = 0; const arch_register_t *out_reg, *base_reg, *index_reg; - int imm_tp = ia32_ImmConst; /* must be a LEA */ if (! is_ia32_Lea(irn)) @@ -134,6 +133,7 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { am_flav = get_ia32_am_flavour(irn); + /* mustn't have a symconst */ if (get_ia32_am_sc(irn)) return; @@ -149,18 +149,7 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { index = get_irn_n(irn,1); if (am_flav & ia32_O) { - offs = get_ia32_am_offs(irn); - - if (! offs) { - ident *id = get_ia32_am_sc(irn); - - assert(id != NULL); - offs = get_id_str(id); - imm_tp = ia32_ImmSymConst; - } - /* offset has a explicit sign -> we need to skip + */ - else if (offs[0] == '+') - offs++; + offs = get_ia32_am_offs_int(irn); } out_reg = arch_get_irn_register(cg->arch_env, irn); @@ -218,8 +207,8 @@ static void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { set_ia32_commutative(res); if (imm) { - set_ia32_cnst(res, offs); - set_ia32_immop_type(res, imm_tp); + tarval *tv = new_tarval_from_long(offs, mode_Iu); + set_ia32_Immop_tarval(res, tv); } SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); diff --git a/ir/be/ia32/ia32_intrinsics.c b/ir/be/ia32/ia32_intrinsics.c index 89c4a6a9b..7d492bf6a 100644 --- a/ir/be/ia32/ia32_intrinsics.c +++ b/ir/be/ia32/ia32_intrinsics.c @@ -191,7 +191,7 @@ static int map_Shrs(ir_node *call, void *ctx) { l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_res_mode); /* h_res = SAR a_h, cnt */ - h_res = new_rd_ia32_l_Shrs(dbg, irg, block, a_h, cnt, h_res_mode); + h_res = new_rd_ia32_l_Sar(dbg, irg, block, a_h, cnt, h_res_mode); //add_irn_dep(h_res, l_res); @@ -225,13 +225,13 @@ static int map_Mul(ir_node *call, void *ctx) { t3 = a_l * b_h h_res = t2 + t3 */ - mul = new_rd_ia32_l_MulS(dbg, irg, block, a_l, b_l); - pEDX = new_rd_Proj(dbg, irg, block, mul, l_res_mode, pn_ia32_l_MulS_EDX); - l_res = new_rd_Proj(dbg, irg, block, mul, l_res_mode, pn_ia32_l_MulS_EAX); + mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l); + pEDX = new_rd_Proj(dbg, irg, block, mul, l_res_mode, pn_ia32_l_Mul_EDX); + l_res = new_rd_Proj(dbg, irg, block, mul, l_res_mode, pn_ia32_l_Mul_EAX); - mul = new_rd_ia32_l_Mul(dbg, irg, block, a_h, b_l, h_res_mode); + mul = new_rd_ia32_l_Mul(dbg, irg, block, a_h, b_l); add = new_rd_ia32_l_Add(dbg, irg, block, mul, pEDX, h_res_mode); - mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_h, h_res_mode); + mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_h); h_res = new_rd_ia32_l_Add(dbg, irg, block, add, mul, h_res_mode); resolve_call(call, l_res, h_res, irg, block); @@ -298,9 +298,9 @@ static int map_Abs(ir_node *call, void *ctx) { */ - sign = new_rd_ia32_l_Shrs(dbg, irg, block, a_h, new_Const_long(h_res_mode, 31), h_res_mode); - sub_l = new_rd_ia32_l_Eor(dbg, irg, block, a_l, sign, l_res_mode); - sub_h = new_rd_ia32_l_Eor(dbg, irg, block, a_h, sign, h_res_mode); + sign = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(h_res_mode, 31), h_res_mode); + sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_res_mode); + sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, h_res_mode); res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign); l_res = new_r_Proj(irg, block, res, l_res_mode, pn_ia32_Sub64Bit_low_res); h_res = new_r_Proj(irg, block, res, h_res_mode, pn_ia32_Sub64Bit_high_res); diff --git a/ir/be/ia32/ia32_new_nodes.c b/ir/be/ia32/ia32_new_nodes.c index 648930cd4..2ec104dfe 100644 --- a/ir/be/ia32/ia32_new_nodes.c +++ b/ir/be/ia32/ia32_new_nodes.c @@ -201,11 +201,17 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { break; case dump_node_nodeattr_txt: - if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n) || is_ia32_Cnst(n)) { - char *pref = is_ia32_ImmSymConst(n) || (get_ia32_op_type(n) == ia32_SymConst) ? "SymC " : ""; - const char *cnst = get_ia32_cnst(n); - - fprintf(F, "[%s%s]", pref, cnst ? cnst : "NONE"); + if (is_ia32_ImmConst(n) || is_ia32_ImmSymConst(n)) { + if(is_ia32_ImmSymConst(n)) { + ident *id = get_ia32_Immop_symconst(n); + fprintf(F, "[SymC %s]", get_id_str(id)); + } else { + char buf[128]; + tarval *tv = get_ia32_Immop_tarval(n); + + tarval_snprintf(buf, sizeof(buf), tv); + fprintf(F, "[%s]", buf); + } } if (! is_ia32_Lea(n)) { @@ -258,12 +264,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { case ia32_Normal: fprintf(F, "Normal"); break; - case ia32_Const: - fprintf(F, "Const"); - break; - case ia32_SymConst: - fprintf(F, "SymConst"); - break; case ia32_AddrModeD: fprintf(F, "AM Dest (Load+Store)"); break; @@ -338,14 +338,9 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { fprintf(F, " (%d)\n", am_flav); /* dump AM offset */ - fprintf(F, "AM offset = "); - if (get_ia32_am_offs(n)) { - fprintf(F, "%s", get_ia32_am_offs(n)); - } - else { - fprintf(F, "n/a"); + if(get_ia32_am_offs_int(n) != 0) { + fprintf(F, "AM offset = %d\n", get_ia32_am_offs_int(n)); } - fprintf(F, "\n"); /* dump AM symconst */ if(get_ia32_am_sc(n) != NULL) { @@ -460,16 +455,6 @@ static int ia32_dump_node(ir_node *n, FILE *F, dump_reason_t reason) { * |___/ ***************************************************************************************************/ -/** - * Returns an ident for the given tarval tv. - */ -static ident *get_ident_for_tv(tarval *tv) { - char buf[1024]; - int len = tarval_snprintf(buf, sizeof(buf), tv); - assert(len); - return new_id_from_str(buf); -} - /** * Wraps get_irn_generic_attr() as it takes no const ir_node, so we need to do a cast. * Firm was made by people hating const :-( @@ -503,14 +488,6 @@ ia32_immop_type_t get_ia32_immop_type(const ir_node *node) { return attr->data.imm_tp; } -/** - * Sets the immediate op type of an ia32 node. - */ -void set_ia32_immop_type(ir_node *node, ia32_immop_type_t tp) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->data.imm_tp = tp; -} - /** * Gets the supported addrmode of an ia32 node */ @@ -543,18 +520,6 @@ void set_ia32_am_flavour(ir_node *node, ia32_am_flavour_t am_flavour) { attr->data.am_flavour = am_flavour; } -/** - * Joins all offsets to one string with adds. - */ -char *get_ia32_am_offs(const ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - static char res[64]; - - snprintf(res, sizeof(res), "%+d", attr->am_offs); - - return res; -} - /** * Gets the addressmode offset as int. */ @@ -571,53 +536,11 @@ void set_ia32_am_offs_int(ir_node *node, int offset) { attr->am_offs = offset; } -#if 0 -/** - * Add an offset for addrmode. - */ -static void extend_ia32_am_offs(ir_node *node, char *offset, char op) { - ia32_attr_t *attr = get_ia32_attr(node); - int res, o; - - if (offset == NULL || offset[0] == '\0') - return; - - if (offset[0] == '-') - res = sscanf(offset, "%d", &o); - else - res = sscanf(offset, "%u", &o); - assert(res == 1); - - if (op == '-') - attr->am_offs -= o; - else if (op == '+') - attr->am_offs += o; - else - assert(0); -} - -/** - * Add an offset for addrmode. - */ -void add_ia32_am_offs(ir_node *node, const char *offset) { - extend_ia32_am_offs(node, (char *)offset, '+'); -} -#endif - void add_ia32_am_offs_int(ir_node *node, int offset) { ia32_attr_t *attr = get_ia32_attr(node); attr->am_offs += offset; } -#if 0 -/** - * Sub an offset for addrmode. - */ -void sub_ia32_am_offs(ir_node *node, const char *offset) { - extend_ia32_am_offs(node, (char *)offset, '-'); -} -#endif - /** * Returns the symconst ident associated to addrmode. */ @@ -679,6 +602,7 @@ void set_ia32_am_scale(ir_node *node, int scale) { */ tarval *get_ia32_Immop_tarval(const ir_node *node) { ia32_attr_t *attr = get_ia32_attr(node); + assert(attr->data.imm_tp == ia32_ImmConst); return attr->cnst_val.tv; } @@ -687,59 +611,20 @@ tarval *get_ia32_Immop_tarval(const ir_node *node) { */ void set_ia32_Immop_tarval(ir_node *node, tarval *tv) { ia32_attr_t *attr = get_ia32_attr(node); + attr->data.imm_tp = ia32_ImmConst; attr->cnst_val.tv = tv; - attr->cnst = get_ident_for_tv(tv); } -/** - * Sets a symconsts ident - */ -void set_ia32_Symconst_ident(ir_node *node, ident *ident) -{ +void set_ia32_Immop_symconst(ir_node *node, ident *ident) { ia32_attr_t *attr = get_ia32_attr(node); + attr->data.imm_tp = ia32_ImmSymConst; attr->cnst_val.sc = ident; - attr->cnst = ident; -} - -/** - * Gets the string representation of the internal const (tv or symconst) - */ -const char *get_ia32_cnst(const ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - if (! attr->cnst) - return NULL; - return get_id_str(attr->cnst); -} - -tarval *get_ia32_cnst_tv(const ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - assert(attr->data.tp == ia32_Const); - return attr->cnst_val.tv; -} - - -/** - * Sets the string representation of the internal const. - */ -void set_ia32_cnst(ir_node *node, const char *cnst) { - ia32_attr_t *attr = get_ia32_attr(node); - attr->cnst = new_id_from_str(cnst); } -/** - * Gets the ident representation of the internal const (tv or symconst) - */ -ident *get_ia32_id_cnst(const ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - return attr->cnst; -} - -/** - * Sets the ident representation of the internal const. - */ -void set_ia32_id_cnst(ir_node *node, ident *cnst) { +ident *get_ia32_Immop_symconst(const ir_node *node) { ia32_attr_t *attr = get_ia32_attr(node); - attr->cnst = cnst; + assert(attr->data.imm_tp == ia32_ImmSymConst); + return attr->cnst_val.sc; } /** @@ -1107,73 +992,20 @@ void set_ia32_orig_node(ir_node *node, const char *name) { * |_| ******************************************************************************************************/ -/** - * Gets the type of an ia32_Const. - */ -unsigned get_ia32_Const_type(const ir_node *node) { - ia32_attr_t *attr = get_ia32_attr(node); - - assert(is_ia32_Cnst(node) && "Need ia32_Const to get type"); - - return attr->data.tp; -} - -/** - * Sets the type of an ia32_Const. - */ -void set_ia32_Const_type(ir_node *node, int type) { - ia32_attr_t *attr = get_ia32_attr(node); - - assert(is_ia32_Cnst(node) && "Need ia32_Const to set type"); - assert((type == ia32_Const || type == ia32_SymConst) && "Unsupported ia32_Const type"); - - attr->data.tp = type; -} - /** * Copy the attributes from an ia32_Const to an Immop (Add_i, Sub_i, ...) node */ -void set_ia32_Immop_attr(ir_node *node, ir_node *cnst) { - ia32_attr_t *na = get_ia32_attr(node); - ia32_attr_t *ca = get_ia32_attr(cnst); - - switch(get_ia32_Const_type(cnst)) { - case ia32_Const: - assert(ca->cnst_val.tv != NULL); - na->cnst_val.tv = ca->cnst_val.tv; - na->cnst = ca->cnst; - set_ia32_immop_type(node, ia32_ImmConst); - break; - case ia32_SymConst: - na->cnst_val.sc = ca->cnst_val.sc; - na->cnst = na->cnst_val.sc; - set_ia32_immop_type(node, ia32_ImmSymConst); - break; - default: - assert(0 && "Need ia32_Const to set Immop attr"); - } -} - -/** - * Copy the attributes from Immop to an Immop - */ -void copy_ia32_Immop_attr(ir_node *dst, ir_node *src) { - ia32_attr_t *da = get_ia32_attr(dst); - ia32_attr_t *sa = get_ia32_attr(src); +void copy_ia32_Immop_attr(ir_node *node, ir_node *from) { + ia32_immop_type_t immop_type = get_ia32_immop_type(from); - switch(get_ia32_immop_type(src)) { - case ia32_ImmConst: - da->cnst_val.tv = sa->cnst_val.tv; - da->cnst = sa->cnst; - set_ia32_immop_type(dst, ia32_ImmConst); - break; - case ia32_ImmSymConst: - da->cnst_val.sc = sa->cnst_val.sc; - da->cnst = sa->cnst; - set_ia32_immop_type(dst, ia32_ImmSymConst); - break; - default: - assert(0 && "Need Immop to copy Immop attr"); + if(immop_type == ia32_ImmConst) { + set_ia32_Immop_tarval(node, get_ia32_Immop_tarval(from)); + } else if(immop_type == ia32_ImmSymConst) { + set_ia32_Immop_symconst(node, get_ia32_Immop_symconst(from)); + } else { + ia32_attr_t *attr = get_ia32_attr(node); + assert(immop_type == ia32_ImmNone); + attr->data.imm_tp = ia32_ImmNone; } } @@ -1181,8 +1013,6 @@ void copy_ia32_Immop_attr(ir_node *dst, ir_node *src) { * Copy the attributes from a Firm Const/SymConst to an ia32_Const */ void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) { - ia32_attr_t *attr = get_ia32_attr(ia32_cnst); - assert(is_ia32_Cnst(ia32_cnst) && "Need ia32_Const to set Const attr"); switch (get_irn_opcode(cnst)) { @@ -1190,9 +1020,7 @@ void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) { set_ia32_Const_tarval(ia32_cnst, get_Const_tarval(cnst)); break; case iro_SymConst: - attr->data.tp = ia32_SymConst; - attr->cnst_val.sc = get_sc_ident(cnst); - attr->cnst = attr->cnst_val.sc; + set_ia32_Immop_symconst(ia32_cnst, get_sc_ident(cnst)); break; case iro_Unknown: assert(0 && "Unknown Const NYI"); @@ -1203,8 +1031,6 @@ void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) { } void set_ia32_Const_tarval(ir_node *ia32_cnst, tarval *tv) { - ia32_attr_t *attr = get_ia32_attr(ia32_cnst); - if(mode_is_reference(get_tarval_mode(tv))) { if(tarval_is_null(tv)) { tv = get_tarval_null(mode_Iu); @@ -1217,9 +1043,7 @@ void set_ia32_Const_tarval(ir_node *ia32_cnst, tarval *tv) { assert(tv != get_tarval_bad() && tv != get_tarval_undefined() && tv != NULL); - attr->data.tp = ia32_Const; - attr->cnst_val.tv = tv; - attr->cnst = get_ident_for_tv(attr->cnst_val.tv); + set_ia32_Immop_tarval(ia32_cnst, tv); } @@ -1381,15 +1205,16 @@ ir_node *get_ia32_result_proj(const ir_node *node) /* default compare operation to compare attributes */ int ia32_compare_attr(ia32_attr_t *a, ia32_attr_t *b) { - if (a->data.tp != b->data.tp) + if (a->data.tp != b->data.tp + || a->data.imm_tp != b->data.imm_tp) return 1; - if (a->cnst != b->cnst) + if (a->data.imm_tp == ia32_ImmConst + && a->cnst_val.tv != b->cnst_val.tv) return 1; - if (a->data.use_frame != b->data.use_frame - || a->data.use_frame != b->data.use_frame - || a->frame_ent != b->frame_ent) + if (a->data.imm_tp == ia32_ImmSymConst + && a->cnst_val.sc != b->cnst_val.sc) return 1; if (a->data.am_flavour != b->data.am_flavour @@ -1401,6 +1226,11 @@ int ia32_compare_attr(ia32_attr_t *a, ia32_attr_t *b) { || a->ls_mode != b->ls_mode) return 1; + if (a->data.use_frame != b->data.use_frame + || a->data.use_frame != b->data.use_frame + || a->frame_ent != b->frame_ent) + return 1; + if(a->pn_code != b->pn_code) return 1; diff --git a/ir/be/ia32/ia32_new_nodes.h b/ir/be/ia32/ia32_new_nodes.h index d23ecb58a..1df4f3be0 100644 --- a/ir/be/ia32/ia32_new_nodes.h +++ b/ir/be/ia32/ia32_new_nodes.h @@ -71,11 +71,6 @@ ia32_am_flavour_t get_ia32_am_flavour(const ir_node *node); */ void set_ia32_am_flavour(ir_node *node, ia32_am_flavour_t am_flavour); -/** - * Gets the joined addrmode offset. - */ -char *get_ia32_am_offs(const ir_node *node); - /** * Gets the addressmode offset as long. */ @@ -86,22 +81,8 @@ int get_ia32_am_offs_int(const ir_node *node); */ void set_ia32_am_offs_int(ir_node *node, int offset); -#if 0 -/** - * Adds an offset for addrmode. - */ -void add_ia32_am_offs(ir_node *node, const char *offset); -#endif - void add_ia32_am_offs_int(ir_node *node, int offset); -#if 0 -/** - * Subs an offset for addrmode. - */ -void sub_ia32_am_offs(ir_node *node, const char *offset); -#endif - /** * Returns the symconst ident associated to addrmode. */ @@ -138,41 +119,24 @@ int get_ia32_am_scale(const ir_node *node); void set_ia32_am_scale(ir_node *node, int scale); /** - * Return the tarval of an immediate operation or NULL in case of SymConst + * Return the tarval of an immediate operation or NULL if none set */ tarval *get_ia32_Immop_tarval(const ir_node *node); /** - * Sets the attributes of an immediate operation to the specified tarval - */ -void set_ia32_Immop_tarval(ir_node *node, tarval *tv); - -/** - * Sets a symconsts ident - */ -void set_ia32_Symconst_ident(ir_node *node, ident *ident); - -/** - * Gets the string representation of the internal const (tv or symconst) - */ -const char *get_ia32_cnst(const ir_node *node); - -tarval* get_ia32_cnst_tv(const ir_node *node); - -/** - * Sets the string representation of the internal const. + * Return the symconst ident of an immediate operation or NULL if none set */ -void set_ia32_cnst(ir_node *node, const char *cnst); +ident* get_ia32_Immop_symconst(const ir_node *node); /** - * Gets the ident representation of the internal const (tv or symconst) + * Sets the attributes of an immediate operation to the specified tarval */ -ident *get_ia32_id_cnst(const ir_node *node); +void set_ia32_Immop_tarval(ir_node *node, tarval *tv); /** - * Sets the ident representation of the internal const. + * Sets the attributes of an immediate operation to the specified SymConst */ -void set_ia32_id_cnst(ir_node *node, ident *cnst); +void set_ia32_Immop_symconst(ir_node *node, ident *ident); /** * Sets the uses_frame flag. @@ -427,21 +391,6 @@ void set_ia32_orig_node(ir_node *node, const char *name); */ ident *ia32_get_ent_ident(ir_entity *ent); -/** - * Gets the type of an ia32_Const. - */ -unsigned get_ia32_Const_type(const ir_node *node); - -/** - * Sets the type of an ia32_Const. - */ -void set_ia32_Const_type(ir_node *node, int type); - -/** - * Copy the attributes from an ia32_Const to an Immop (Add_i, Sub_i, ...) node - */ -void set_ia32_Immop_attr(ir_node *node, ir_node *cnst); - /** * Copy the attributes from Immop to an Immop */ diff --git a/ir/be/ia32/ia32_nodes_attr.h b/ir/be/ia32/ia32_nodes_attr.h index d1c087426..45c07a980 100644 --- a/ir/be/ia32/ia32_nodes_attr.h +++ b/ir/be/ia32/ia32_nodes_attr.h @@ -20,8 +20,6 @@ typedef enum { pn_EAX, pn_EDX } pn_ia32_Register; typedef enum { ia32_Normal, - ia32_Const, - ia32_SymConst, ia32_AddrModeD, ia32_AddrModeS } ia32_op_type_t; @@ -116,8 +114,6 @@ typedef struct _ia32_attr_t { ident *sc; /**< the symconst ident */ } cnst_val; - ident *cnst; /**< points to the string representation of the constant value (either tv or sc) */ - ir_mode *ls_mode; /**< the mode of the stored/loaded value, or the mode to convert to */ ir_entity *frame_ent; /**< the frame entity attached to this node */ diff --git a/ir/be/ia32/ia32_optimize.c b/ir/be/ia32/ia32_optimize.c index 14b80fd4a..8a119a2b0 100644 --- a/ir/be/ia32/ia32_optimize.c +++ b/ir/be/ia32/ia32_optimize.c @@ -80,8 +80,18 @@ void ia32_pre_transform_phase(ia32_code_gen_t *cg) { * NOTE: THESE PEEPHOLE OPTIMIZATIONS MUST BE CALLED AFTER SCHEDULING AND REGISTER ALLOCATION. */ -static int ia32_cnst_compare(ir_node *n1, ir_node *n2) { - return get_ia32_id_cnst(n1) == get_ia32_id_cnst(n2); +static int ia32_const_equal(const ir_node *n1, const ir_node *n2) { + if(get_ia32_immop_type(n1) != get_ia32_immop_type(n2)) + return 0; + + if(get_ia32_immop_type(n1) == ia32_ImmConst) { + return get_ia32_Immop_tarval(n1) == get_ia32_Immop_tarval(n2); + } else if(get_ia32_immop_type(n1) == ia32_ImmSymConst) { + return get_ia32_Immop_symconst(n1) == get_ia32_Immop_symconst(n2); + } + + assert(get_ia32_immop_type(n1) == ia32_ImmNone); + return 1; } /** @@ -132,10 +142,10 @@ static int is_TestJmp_replacement(ir_node *cand, ir_node *irn) { } } - if (same_args) - return ia32_cnst_compare(cand, irn); + if (!same_args) + return 0; - return 0; + return ia32_const_equal(cand, irn); } /** @@ -168,20 +178,16 @@ static int is_CondJmp_cand(const ir_node *irn) { * Checks if the arguments of cand are the same of irn. */ static int is_CondJmp_replacement(ir_node *cand, ir_node *irn) { - int i, n = get_irn_arity(cand); - int same_args = 1; + int i, arity; - for (i = 0; i < n; i++) { + arity = get_irn_arity(cand); + for (i = 0; i < arity; i++) { if (get_irn_n(cand, i) != get_irn_n(irn, i)) { - same_args = 0; - break; + return 0; } } - if (same_args) - return ia32_cnst_compare(cand, irn); - - return 0; + return ia32_const_equal(cand, irn); } /** @@ -235,10 +241,8 @@ static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) { * attached to the node */ for(node = sched_next(irn); !sched_is_end(node); node = sched_next(node)) { - const char *am_offs; ir_node *mem; - int offset = -1; - int n; + int offset; int storeslot; // it has to be a store @@ -257,18 +261,7 @@ static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) { if( (get_ia32_am_flavour(node) & ia32_am_IS) != 0) break; - am_offs = get_ia32_am_offs(node); - if(am_offs == NULL) { - offset = 0; - } else { - // the am_offs has to be of the form "+NUMBER" - if(sscanf(am_offs, "+%d%n", &offset, &n) != 1 || am_offs[n] != '\0') { - // we shouldn't have any cases in the compiler at the moment - // that produce something different from esp+XX - assert(0); - break; - } - } + offset = get_ia32_am_offs_int(node); storeslot = offset / 4; if(storeslot >= MAXPUSH_OPTIMIZE) @@ -309,9 +302,10 @@ static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) { // create a push push = new_rd_ia32_Push(NULL, irg, block, noreg, noreg, val, curr_sp, mem); - if(get_ia32_immop_type(store) != ia32_ImmNone) { - copy_ia32_Immop_attr(push, store); - } + + set_ia32_am_support(push, ia32_am_Source); + copy_ia32_Immop_attr(push, store); + sched_add_before(irn, push); // create stackpointer proj @@ -352,6 +346,7 @@ static void ia32_create_Pushs(ir_node *irn, ia32_code_gen_t *cg) { } } +#if 0 /** * Tries to optimize two following IncSP. */ @@ -373,6 +368,7 @@ static void ia32_optimize_IncSP(ir_node *irn, ia32_code_gen_t *cg) { sched_remove(prev); } } +#endif /** * Performs Peephole Optimizations. @@ -391,7 +387,7 @@ static void ia32_peephole_optimize_node(ir_node *irn, void *env) { if (be_is_IncSP(irn)) { // optimize_IncSP doesn't respect dependency edges yet... //ia32_optimize_IncSP(irn, cg); - (void) ia32_optimize_IncSP; + if (cg->opt & IA32_OPT_PUSHARGS) ia32_create_Pushs(irn, cg); } @@ -608,30 +604,24 @@ static ia32_am_cand_t is_am_candidate(ia32_code_gen_t *cg, heights_t *h, const i static int load_store_addr_is_equal(const ir_node *load, const ir_node *store, const ir_node *addr_b, const ir_node *addr_i) { - int is_equal = (addr_b == get_irn_n(load, 0)) && (addr_i == get_irn_n(load, 1)); - ir_entity *lent = get_ia32_frame_ent(load); - ir_entity *sent = get_ia32_frame_ent(store); - ident *lid = get_ia32_am_sc(load); - ident *sid = get_ia32_am_sc(store); - char *loffs = get_ia32_am_offs(load); - char *soffs = get_ia32_am_offs(store); - - /* are both entities set and equal? */ - if (is_equal && (lent || sent)) - is_equal = lent && sent && (lent == sent); - - /* are address mode idents set and equal? */ - if (is_equal && (lid || sid)) - is_equal = lid && sid && (lid == sid); - - /* are offsets set and equal */ - if (is_equal && (loffs || soffs)) - is_equal = loffs && soffs && strcmp(loffs, soffs) == 0; - - /* are the load and the store of the same mode? */ - is_equal = is_equal ? get_ia32_ls_mode(load) == get_ia32_ls_mode(store) : 0; - - return is_equal; + if(get_irn_n(load, 0) != addr_b) + return 0; + if(get_irn_n(load, 1) != addr_i) + return 0; + + if(get_ia32_frame_ent(load) != get_ia32_frame_ent(store)) + return 0; + + if(get_ia32_am_sc(load) != get_ia32_am_sc(store)) + return 0; + if(is_ia32_am_sc_sign(load) != is_ia32_am_sc_sign(store)) + return 0; + if(get_ia32_am_offs_int(load) != get_ia32_am_offs_int(store)) + return 0; + if(get_ia32_ls_mode(load) != get_ia32_ls_mode(store)) + return 0; + + return 1; } typedef enum _ia32_take_lea_attr { @@ -862,7 +852,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn) { have_am_sc = 1; dolea = 1; - am_sc = get_ia32_id_cnst(irn); + am_sc = get_ia32_Immop_symconst(irn); am_sc_sign = is_ia32_am_sc_sign(irn); } @@ -906,7 +896,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn) { /* check for SHL 1,2,3 */ if (pred_is_specific_node(temp, is_ia32_Shl)) { - if (get_ia32_Immop_tarval(temp)) { + if (is_ia32_ImmConst(temp)) { long shiftval = get_tarval_long(get_ia32_Immop_tarval(temp)); if (shiftval <= 3) { @@ -1030,7 +1020,7 @@ static ir_node *fold_addr(ia32_code_gen_t *cg, ir_node *irn) { SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(cg, irn)); - DBG((mod, LEVEL_1, "\tLEA [%+F + %+F * %d + %s]\n", base, index, scale, get_ia32_am_offs(res))); + DBG((mod, LEVEL_1, "\tLEA [%+F + %+F * %d + %d]\n", base, index, scale, get_ia32_am_offs_int(res))); /* we will exchange it, report here before the Proj is created */ if (shift && lea && lea_o) { diff --git a/ir/be/ia32/ia32_spec.pl b/ir/be/ia32/ia32_spec.pl index 7f1ab164f..227272d6e 100644 --- a/ir/be/ia32/ia32_spec.pl +++ b/ir/be/ia32/ia32_spec.pl @@ -2,16 +2,11 @@ # $Id$ # This is the specification for the ia32 assembler Firm-operations +$new_emit_syntax = 1; + # the cpu architecture (ia32, ia64, mips, sparc, ppc, ...) $arch = "ia32"; -# this strings mark the beginning and the end of a comment in emit -$comment_string = "/*"; -$comment_string_end = "*/"; - -# the number of additional opcodes you want to register -#$additional_opcodes = 0; - # The node description is done as a perl hash initializer with the # following structure: # @@ -177,6 +172,39 @@ $comment_string_end = "*/"; "bundels_per_cycle" => 1 ); # vliw +%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);", + "A1" => "${arch}_emit_in_node_name(env, node, 0);", + "A2" => "${arch}_emit_in_node_name(env, node, 1);", + "A3" => "${arch}_emit_in_node_name(env, node, 2);", + "A4" => "${arch}_emit_in_node_name(env, node, 3);", + "A5" => "${arch}_emit_in_node_name(env, node, 4);", + "A6" => "${arch}_emit_in_node_name(env, node, 5);", + "X1" => "${arch}_emit_x87_name(env, node, 0);", + "X2" => "${arch}_emit_x87_name(env, node, 1);", + "X3" => "${arch}_emit_x87_name(env, node, 2);", + "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));", + "M" => "${arch}_emit_mode_suffix(env, get_ia32_ls_mode(node));", + "AM" => "${arch}_emit_am(env, node);", + "unop" => "${arch}_emit_unop(env, node);", + "binop" => "${arch}_emit_binop(env, node);", + "x87_binop" => "${arch}_emit_x87_binop(env, node);", +); + #--------------------------------------------------# # _ # # (_) # @@ -220,15 +248,15 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "irn_flags" => "R", "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. add %ia32_emit_binop /* Add(%A3, %A4) -> %D1 */', + "emit" => '. addl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, -"AddC" => { - "comment" => "construct Add with Carry: AddC(a, b) = Add(b, a) = a + b + carry", +"Adc" => { + "comment" => "construct Add with Carry: Adc(a, b) = Add(b, a) = a + b + carry", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. adc %ia32_emit_binop /* AddC(%A3, %A4) -> %D1 */', + "emit" => '. adcl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -239,10 +267,10 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "arity" => 4, "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] }, "emit" => ' -. mov %D1, %S1 /* mov a_l into assigned l_res register */ -. mov %D2, %S2 /* mov a_h into assigned h_res register */ -. add %D1, %S3 /* a_l + b_l */ -. adc %D2, %S4 /* a_h + b_h + carry */ +. movl %S1, %D1 +. movl %S2, %D2 +. addl %S3, %D1 +. adcl %S4, %D2 ', "outs" => [ "low_res", "high_res" ], "units" => [ "GP" ], @@ -256,58 +284,60 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "arity" => 2, }, -"l_AddC" => { +"l_Adc" => { "op_flags" => "C", "cmp_attr" => "return 1;", - "comment" => "construct lowered Add with Carry: AddC(a, b) = Add(b, a) = a + b + carry", + "comment" => "construct lowered Add with Carry: Adc(a, b) = Adc(b, a) = a + b + carry", "arity" => 2, }, -"MulS" => { +"Mul" => { # we should not rematrialize this node. It produces 2 results and has # very strict constrains "comment" => "construct MulS: MulS(a, b) = MulS(b, a) = a * b", "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx", "none" ] }, - "emit" => '. mul %ia32_emit_unop /* Mul(%A1, %A2) -> %D1 */', + "emit" => '. mull %unop', "outs" => [ "EAX", "EDX", "M" ], "latency" => 10, "units" => [ "GP" ], }, -"l_MulS" => { +"l_Mul" => { # we should not rematrialize this node. It produces 2 results and has # very strict constrains "op_flags" => "C", "cmp_attr" => "return 1;", - "comment" => "construct lowered MulS: MulS(a, b) = MulS(b, a) = a * b", + "comment" => "construct lowered MulS: Mul(a, b) = Mul(b, a) = a * b", "outs" => [ "EAX", "EDX", "M" ], "arity" => 2 }, -"Mul" => { +"IMul" => { "irn_flags" => "R", "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. imul %ia32_emit_binop /* Mul(%A1, %A2) -> %D1 */', + "emit" => '. imull %binop', "latency" => 5, "units" => [ "GP" ], "mode" => "mode_Iu", }, -"l_Mul" => { +"l_IMul" => { "op_flags" => "C", "cmp_attr" => "return 1;", - "comment" => "construct lowered Mul: Mul(a, b) = Mul(b, a) = a * b", + "comment" => "construct lowered IMul: IMul(a, b) = IMul(b, a) = a * b", "arity" => 2 }, # Mulh is an exception from the 4 INs with AM because the target is always EAX:EDX +# Matze: It's not clear to me why we have a separate Mulh node and not just use +# the IMul node... "Mulh" => { # we should not rematrialize this node. It produces 2 results and has # very strict constrains "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", "reg_req" => { "in" => [ "gp", "gp", "eax", "gp", "none" ], "out" => [ "eax", "edx" ] }, - "emit" => '. imul %ia32_emit_unop /* Mulh(%A1, %A2) -> %D1 */', + "emit" => '. imull %unop', "outs" => [ "EAX", "EDX", "M" ], "latency" => 5, "units" => [ "GP" ], @@ -317,7 +347,7 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "irn_flags" => "R", "comment" => "construct And: And(a, b) = And(b, a) = a AND b", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. and %ia32_emit_binop /* And(%A1, %A2) -> %D1 */', + "emit" => '. andl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -326,24 +356,24 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "irn_flags" => "R", "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. or %ia32_emit_binop /* Or(%A1, %A2) -> %D1 */', + "emit" => '. orl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, -"Eor" => { +"Xor" => { "irn_flags" => "R", - "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", + "comment" => "construct Xor: Xor(a, b) = Xor(b, a) = a EOR b", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. xor %ia32_emit_binop /* Xor(%A1, %A2) -> %D1 */', + "emit" => '. xorl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, -"l_Eor" => { +"l_Xor" => { "op_flags" => "C", "cmp_attr" => "return 1;", - "comment" => "construct lowered Eor: Eor(a, b) = Eor(b, a) = a EOR b", + "comment" => "construct lowered Xor: Xor(a, b) = Xor(b, a) = a XOR b", "arity" => 2 }, @@ -353,15 +383,15 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "irn_flags" => "R", "comment" => "construct Sub: Sub(a, b) = a - b", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. sub %ia32_emit_binop /* Sub(%A3, %A4) -> %D1 */', + "emit" => '. subl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, -"SubC" => { +"Sbb" => { "comment" => "construct Sub with Carry: SubC(a, b) = a - b - carry", "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. sbb %ia32_emit_binop /* SubC(%A3, %A4) -> %D1 */', + "emit" => '. sbbl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -372,10 +402,10 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "arity" => 4, "reg_req" => { "in" => [ "gp", "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] }, "emit" => ' -. mov %D1, %S1 /* mov a_l into assigned l_res register */ -. mov %D2, %S2 /* mov a_h into assigned h_res register */ -. sub %D1, %S3 /* a_l - b_l */ -. sbb %D2, %S4 /* a_h - b_h - borrow */ +. movl %S1, %D1 +. movl %S2, %D2 +. subl %S3, %D1 +. sbbl %S4, %D2 ', "outs" => [ "low_res", "high_res" ], "units" => [ "GP" ], @@ -388,7 +418,7 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "arity" => 2, }, -"l_SubC" => { +"l_Sbb" => { "cmp_attr" => "return 1;", "comment" => "construct lowered Sub with Carry: SubC(a, b) = a - b - carry", "arity" => 2, @@ -397,10 +427,10 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "IDiv" => { "op_flags" => "F|L", "state" => "exc_pinned", - "reg_req" => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx" ] }, + "reg_req" => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx", "none" ] }, "attr" => "ia32_op_flavour_t dm_flav", "init_attr" => "attr->data.op_flav = dm_flav;", - "emit" => ". idiv %S2 /* signed IDiv(%S1, %S2) -> %D1, (%A1, %A2, %A3) */", + "emit" => ". idivl %unop", "outs" => [ "div_res", "mod_res", "M" ], "latency" => 25, "units" => [ "GP" ], @@ -409,10 +439,10 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "Div" => { "op_flags" => "F|L", "state" => "exc_pinned", - "reg_req" => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx" ] }, + "reg_req" => { "in" => [ "eax", "gp", "edx", "none" ], "out" => [ "eax", "edx", "none" ] }, "attr" => "ia32_op_flavour_t dm_flav", "init_attr" => "attr->data.op_flav = dm_flav;", - "emit" => ". div %S2 /* unsigned Div(%S1, %S2) -> %D1, (%A1, %A2, %A3) */", + "emit" => ". divl %unop", "outs" => [ "div_res", "mod_res", "M" ], "latency" => 25, "units" => [ "GP" ], @@ -422,7 +452,7 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "irn_flags" => "R", "comment" => "construct Shl: Shl(a, b) = a << b", "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. shl %ia32_emit_binop /* Shl(%A1, %A2) -> %D1 */', + "emit" => '. shll %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -447,21 +477,18 @@ $default_cmp_attr = "return ia32_compare_attr(attr_a, attr_b);"; "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "!in" ] }, "emit" => ' -if (get_ia32_immop_type(n) == ia32_ImmNone) { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shld %ia32_emit_am, %S4, %%cl /* ShlD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shld %S3, %S4, %%cl /* ShlD(%A3, %A4, %A5) -> %D1 */ - } -} -else { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shld %ia32_emit_am, %S4, %C /* ShlD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shld %S3, %S4, %C /* ShlD(%A3, %A4, %A5) -> %D1 */ - } +if (get_ia32_immop_type(node) == ia32_ImmNone) { + if (get_ia32_op_type(node) == ia32_AddrModeD) { + . shldl %%cl, %S4, %AM + } else { + . shldl %%cl, %S4, %S3 + } +} else { + if (get_ia32_op_type(node) == ia32_AddrModeD) { + . shldl $%C, %S4, %AM + } else { + . shldl $%C, %S4, %S3 + } } ', "latency" => 6, @@ -479,7 +506,7 @@ else { "irn_flags" => "R", "comment" => "construct Shr: Shr(a, b) = a >> b", "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. shr %ia32_emit_binop /* Shr(%A1, %A2) -> %D1 */', + "emit" => '. shrl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -502,23 +529,19 @@ else { # (and probably never will). So we create artificial interferences of the result # with all inputs, so the spiller can always assure a free register. "reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "ecx", "none" ], "out" => [ "!in" ] }, - "emit" => -' -if (get_ia32_immop_type(n) == ia32_ImmNone) { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shrd %ia32_emit_am, %S4, %%cl /* ShrD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shrd %S3, %S4, %%cl /* ShrD(%A3, %A4, %A5) -> %D1 */ - } -} -else { - if (get_ia32_op_type(n) == ia32_AddrModeD) { -4. shrd %ia32_emit_am, %S4, %C /* ShrD(%A3, %A4, %A5) -> %D1 */ - } - else { -4. shrd %S3, %S4, %C /* ShrD(%A3, %A4, %A5) -> %D1 */ - } + "emit" => ' +if (get_ia32_immop_type(node) == ia32_ImmNone) { + if (get_ia32_op_type(node) == ia32_AddrModeD) { + . shrdl %%cl, %S4, %AM + } else { + . shrdl %%cl, %S4, %S3 + } +} else { + if (get_ia32_op_type(node) == ia32_AddrModeD) { + . shrdl $%C, %S4, %AM + } else { + . shrdl $%C, %S4, %S3 + } } ', "latency" => 6, @@ -532,46 +555,46 @@ else { "arity" => 3 }, -"Shrs" => { +"Sar" => { "irn_flags" => "R", "comment" => "construct Shrs: Shrs(a, b) = a >> b", "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. sar %ia32_emit_binop /* Shrs(%A1, %A2) -> %D1 */', + "emit" => '. sarl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, -"l_Shrs" => { +"l_Sar" => { "cmp_attr" => "return 1;", - "comment" => "construct lowered Shrs: Shrs(a, b) = a << b", + "comment" => "construct lowered Sar: Sar(a, b) = a << b", "arity" => 2 }, -"RotR" => { +"Ror" => { "irn_flags" => "R", - "comment" => "construct RotR: RotR(a, b) = a ROTR b", + "comment" => "construct Ror: Ror(a, b) = a ROR b", "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. ror %ia32_emit_binop /* RotR(%A1, %A2) -> %D1 */', + "emit" => '. rorl %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, -"RotL" => { +"Rol" => { "irn_flags" => "R", - "comment" => "construct RotL: RotL(a, b) = a ROTL b", + "comment" => "construct Rol: Rol(a, b) = a ROL b", "reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. rol %ia32_emit_binop /* RotL(%A1, %A2) -> %D1 */', + "emit" => '. roll %binop', "units" => [ "GP" ], "mode" => "mode_Iu", }, # unary operations -"Minus" => { +"Neg" => { "irn_flags" => "R", "comment" => "construct Minus: Minus(a) = -a", "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. neg %ia32_emit_unop /* Neg(%A1) -> %D1, (%A1) */', + "emit" => '. negl %unop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -582,17 +605,17 @@ else { "arity" => 4, "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "!in", "!in" ] }, "emit" => ' -. mov %D1, %S1 /* l_res */ -. mov %D2, %S1 /* h_res */ -. sub %D1, %S2 /* 0 - a_l -> low_res */ -. sbb %D2, %S3 /* 0 - a_h - borrow -> high_res */ +. movl %S1, %D1 +. movl %S1, %D2 +. subl %S2, %D1 +. sbbl %S3, %D2 ', "outs" => [ "low_res", "high_res" ], "units" => [ "GP" ], }, -"l_Minus" => { +"l_Neg" => { "cmp_attr" => "return 1;", "comment" => "construct lowered Minus: Minus(a) = -a", "arity" => 1, @@ -602,7 +625,7 @@ else { "irn_flags" => "R", "comment" => "construct Increment: Inc(a) = a++", "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. inc %ia32_emit_unop /* Inc(%S1) -> %D1, (%A1) */', + "emit" => '. incl %unop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -611,7 +634,7 @@ else { "irn_flags" => "R", "comment" => "construct Decrement: Dec(a) = a--", "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. dec %ia32_emit_unop /* Dec(%S1) -> %D1, (%A1) */', + "emit" => '. decl %unop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -620,7 +643,7 @@ else { "irn_flags" => "R", "comment" => "construct Not: Not(a) = !a", "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. not %ia32_emit_unop /* Not(%S1) -> %D1, (%A1) */', + "emit" => '. notl %unop', "units" => [ "GP" ], "mode" => "mode_Iu", }, @@ -752,7 +775,7 @@ else { "comment" => "load floating point control word FldCW(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "fp_cw" ] }, "latency" => 5, - "emit" => ". fldcw %ia32_emit_am /* FldCW(%A1) -> %D1 */", + "emit" => ". fldcw %AM", "mode" => "mode_Hu", "units" => [ "GP" ], }, @@ -763,17 +786,17 @@ else { "comment" => "store floating point control word: FstCW(ptr, mem) = ST ptr -> reg", "reg_req" => { "in" => [ "gp", "gp", "fp_cw", "none" ] }, "latency" => 5, - "emit" => ". fstcw %ia32_emit_am /* FstCW(%A3) -> %A1 */", + "emit" => ". fstcw %AM", "mode" => "mode_M", "units" => [ "GP" ], }, -"Cdq" => { +"Cltd" => { # we should not rematrialize this node. It produces 2 results and has # very strict constrains "comment" => "construct CDQ: sign extend EAX -> EDX:EAX", "reg_req" => { "in" => [ "gp" ], "out" => [ "eax in_r1", "edx" ] }, - "emit" => '. cdq /* sign extend EAX -> EDX:EAX, (%A1) */', + "emit" => '. cltd', "outs" => [ "EAX", "EDX" ], "units" => [ "GP" ], }, @@ -786,14 +809,7 @@ else { "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "gp", "none" ] }, "latency" => 3, - "emit" => -' if (get_mode_size_bits(get_ia32_ls_mode(n)) < 32) { -4. mov%Mx %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */ - } - else { -4. mov %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */ - } -', + "emit" => ". mov%SE%ME%.l %AM, %D1", "outs" => [ "res", "M" ], "units" => [ "GP" ], }, @@ -820,7 +836,7 @@ else { "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { "in" => [ "gp", "gp", "gp", "none" ] }, - "emit" => '. mov %ia32_emit_binop /* Store(%A3) -> (%A1) */', + "emit" => '. mov%M %binop', "latency" => 3, "units" => [ "GP" ], "mode" => "mode_M", @@ -831,7 +847,7 @@ else { "state" => "exc_pinned", "comment" => "construct 8Bit Store: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { "in" => [ "gp", "gp", "eax ebx ecx edx", "none" ] }, - "emit" => '. mov %ia32_emit_binop /* Store(%A3) -> (%A1) */', + "emit" => '. mov%M %binop', "latency" => 3, "units" => [ "GP" ], "mode" => "mode_M", @@ -841,7 +857,7 @@ else { "irn_flags" => "R", "comment" => "construct Lea: Lea(a,b) = lea [a+b*const+offs] | res = a + b * const + offs with const = 0,1,2,4,8", "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => '. lea %D1, %ia32_emit_am /* LEA(%A1, %A2) */', + "emit" => '. leal %AM, %D1', "latency" => 2, "units" => [ "GP" ], "mode" => "mode_Iu", @@ -849,8 +865,8 @@ else { "Push" => { "comment" => "push on the stack", - "reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp" ] }, - "emit" => '. push %ia32_emit_unop /* PUSH(%A1) */', + "reg_req" => { "in" => [ "gp", "gp", "gp", "esp", "none" ], "out" => [ "esp", "none" ] }, + "emit" => '. pushl %unop', "outs" => [ "stack:I|S", "M" ], "latency" => 3, "units" => [ "GP" ], @@ -858,8 +874,8 @@ else { "Pop" => { "comment" => "pop a gp register from the stack", - "reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "esp", "gp" ] }, - "emit" => '. pop %ia32_emit_unop /* POP(%A1) */', + "reg_req" => { "in" => [ "gp", "gp", "esp", "none" ], "out" => [ "esp", "gp", "none" ] }, + "emit" => '. popl %unop', "outs" => [ "stack:I|S", "res", "M" ], "latency" => 4, "units" => [ "GP" ], @@ -868,7 +884,7 @@ else { "Enter" => { "comment" => "create stack frame", "reg_req" => { "in" => [ "esp" ], "out" => [ "ebp", "esp" ] }, - "emit" => '. enter /* Enter */', + "emit" => '. enter', "outs" => [ "frame:I", "stack:I|S", "M" ], "latency" => 15, "units" => [ "GP" ], @@ -877,7 +893,7 @@ else { "Leave" => { "comment" => "destroy stack frame", "reg_req" => { "in" => [ "esp", "ebp" ], "out" => [ "ebp", "esp" ] }, - "emit" => '. leave /* Leave */', + "emit" => '. leave', "outs" => [ "frame:I", "stack:I|S" ], "latency" => 3, "units" => [ "GP" ], @@ -886,7 +902,8 @@ else { "AddSP" => { "irn_flags" => "I", "comment" => "allocate space on stack", - "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, + "reg_req" => { "in" => [ "gp", "gp", "esp", "gp", "none" ], "out" => [ "in_r3", "none" ] }, + "emit" => '. addl %binop', "outs" => [ "stack:S", "M" ], "units" => [ "GP" ], }, @@ -894,7 +911,8 @@ else { "SubSP" => { "irn_flags" => "I", "comment" => "free space on stack", - "reg_req" => { "in" => [ "esp", "gp" ], "out" => [ "esp", "none" ] }, + "reg_req" => { "in" => [ "gp", "gp", "esp", "gp", "none" ], "out" => [ "in_r3", "none" ] }, + "emit" => '. subl %binop', "outs" => [ "stack:S", "M" ], "units" => [ "GP" ], }, @@ -923,7 +941,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE Add: Add(a, b) = Add(b, a) = a + b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. adds%M %ia32_emit_binop /* SSE Add(%A3, %A4) -> %D1 */', + "emit" => '. adds%M %binop', "latency" => 4, "units" => [ "SSE" ], "mode" => "mode_D", @@ -933,7 +951,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. muls%M %ia32_emit_binop /* SSE Mul(%A3, %A4) -> %D1 */', + "emit" => '. muls%M %binop', "latency" => 4, "units" => [ "SSE" ], "mode" => "mode_D", @@ -943,7 +961,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. maxs%M %ia32_emit_binop /* SSE Max(%A3, %A4) -> %D1 */', + "emit" => '. maxs%M %binop', "latency" => 2, "units" => [ "SSE" ], "mode" => "mode_D", @@ -953,7 +971,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. mins%M %ia32_emit_binop /* SSE Min(%A3, %A4) -> %D1 */', + "emit" => '. mins%M %binop', "latency" => 2, "units" => [ "SSE" ], "mode" => "mode_D", @@ -963,7 +981,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE And: And(a, b) = a AND b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. andp%M %ia32_emit_binop /* SSE And(%A3, %A4) -> %D1 */', + "emit" => '. andp%M %binop', "latency" => 3, "units" => [ "SSE" ], "mode" => "mode_D", @@ -973,16 +991,16 @@ else { "irn_flags" => "R", "comment" => "construct SSE Or: Or(a, b) = a OR b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. orp%M %ia32_emit_binop /* SSE Or(%A3, %A4) -> %D1 */', + "emit" => '. orp%M %binop', "units" => [ "SSE" ], "mode" => "mode_D", }, -"xEor" => { +"xXor" => { "irn_flags" => "R", - "comment" => "construct SSE Eor: Eor(a, b) = a XOR b", + "comment" => "construct SSE Xor: Xor(a, b) = a XOR b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. xorp%M %ia32_emit_binop /* SSE Xor(%A3, %A4) -> %D1 */', + "emit" => '. xorp%M %binop', "latency" => 3, "units" => [ "SSE" ], "mode" => "mode_D", @@ -994,7 +1012,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE AndNot: AndNot(a, b) = a AND NOT b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, - "emit" => '. andnp%M %ia32_emit_binop /* SSE AndNot(%A3, %A4) -> %D1 */', + "emit" => '. andnp%M %binop', "latency" => 3, "units" => [ "SSE" ], "mode" => "mode_D", @@ -1004,7 +1022,7 @@ else { "irn_flags" => "R", "comment" => "construct SSE Sub: Sub(a, b) = a - b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3" ] }, - "emit" => '. subs%M %ia32_emit_binop /* SSE Sub(%A1, %A2) -> %D1 */', + "emit" => '. subs%M %binop', "latency" => 4, "units" => [ "SSE" ], "mode" => "mode_D", @@ -1015,7 +1033,7 @@ else { "comment" => "construct SSE Div: Div(a, b) = a / b", "reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] }, "outs" => [ "res", "M" ], - "emit" => '. divs%M %ia32_emit_binop /* SSE Div(%A1, %A2) -> %D1 */', + "emit" => '. divs%M %binop', "latency" => 16, "units" => [ "SSE" ], }, @@ -1045,7 +1063,7 @@ else { "irn_flags" => "R", "comment" => "represents a SSE constant", "reg_req" => { "out" => [ "xmm" ] }, - "emit" => '. movs%M %D1, %C /* Load fConst into register */', + "emit" => '. movs%M %D1, $%C', "latency" => 2, "units" => [ "SSE" ], "mode" => "mode_D", @@ -1058,7 +1076,7 @@ else { "state" => "exc_pinned", "comment" => "construct SSE Load: Load(ptr, mem) = LD ptr", "reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "xmm", "none" ] }, - "emit" => '. movs%M %D1, %ia32_emit_am /* Load((%A1)) -> %D1 */', + "emit" => '. movs%M %D1, %AM', "outs" => [ "res", "M" ], "latency" => 2, "units" => [ "SSE" ], @@ -1069,7 +1087,7 @@ else { "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { "in" => [ "gp", "gp", "xmm", "none" ] }, - "emit" => '. movs%M %ia32_emit_binop /* Store(%S3) -> (%A1) */', + "emit" => '. movs%M %binop', "latency" => 2, "units" => [ "SSE" ], "mode" => "mode_M", @@ -1080,7 +1098,7 @@ else { "state" => "exc_pinned", "comment" => "construct Store without index: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { "in" => [ "gp", "xmm", "none" ] }, - "emit" => '. movs%M %ia32_emit_am, %S2 /* store XMM0 onto stack */', + "emit" => '. movs%M %AM, %S2', "latency" => 2, "units" => [ "SSE" ], "mode" => "mode_M", @@ -1106,7 +1124,7 @@ else { "state" => "exc_pinned", "comment" => "store ST0 onto stack", "reg_req" => { "in" => [ "gp", "gp", "none" ] }, - "emit" => '. fstp %ia32_emit_am /* store ST0 onto stack */', + "emit" => '. fstp%M %AM', "latency" => 4, "units" => [ "SSE" ], "mode" => "mode_M", @@ -1118,7 +1136,7 @@ else { "state" => "exc_pinned", "comment" => "load ST0 from stack", "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "vf0", "none" ] }, - "emit" => '. fld %ia32_emit_am /* load ST0 from stack */', + "emit" => '. fld%M %AM', "outs" => [ "res", "M" ], "latency" => 2, "units" => [ "SSE" ], @@ -1548,7 +1566,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b", "reg_req" => { }, - "emit" => '. fadd %ia32_emit_x87_binop /* x87 fadd(%A3, %A4) -> %D1 */', + "emit" => '. fadd %x87_binop', }, "faddp" => { @@ -1556,7 +1574,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 Add: Add(a, b) = Add(b, a) = a + b", "reg_req" => { }, - "emit" => '. faddp %ia32_emit_x87_binop /* x87 fadd(%A3, %A4) -> %D1 */', + "emit" => '. faddp %x87_binop', }, "fmul" => { @@ -1564,7 +1582,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b", "reg_req" => { }, - "emit" => '. fmul %ia32_emit_x87_binop /* x87 fmul(%A3, %A4) -> %D1 */', + "emit" => '. fmul %x87_binop', }, "fmulp" => { @@ -1572,7 +1590,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Mul: Mul(a, b) = Mul(b, a) = a + b", "reg_req" => { }, - "emit" => '. fmulp %ia32_emit_x87_binop /* x87 fmul(%A3, %A4) -> %D1 */',, + "emit" => '. fmulp %x87_binop',, }, "fsub" => { @@ -1580,7 +1598,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sub: Sub(a, b) = a - b", "reg_req" => { }, - "emit" => '. fsub %ia32_emit_x87_binop /* x87 fsub(%A3, %A4) -> %D1 */', + "emit" => '. fsub %x87_binop', }, "fsubp" => { @@ -1588,7 +1606,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sub: Sub(a, b) = a - b", "reg_req" => { }, - "emit" => '. fsubp %ia32_emit_x87_binop /* x87 fsub(%A3, %A4) -> %D1 */', + "emit" => '. fsubp %x87_binop', }, "fsubr" => { @@ -1597,7 +1615,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp SubR: SubR(a, b) = b - a", "reg_req" => { }, - "emit" => '. fsubr %ia32_emit_x87_binop /* x87 fsubr(%A3, %A4) -> %D1 */', + "emit" => '. fsubr %x87_binop', }, "fsubrp" => { @@ -1606,7 +1624,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp SubR: SubR(a, b) = b - a", "reg_req" => { }, - "emit" => '. fsubrp %ia32_emit_x87_binop /* x87 fsubr(%A3, %A4) -> %D1 */', + "emit" => '. fsubrp %x87_binop', }, "fprem" => { @@ -1614,7 +1632,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)", "reg_req" => { }, - "emit" => '. fprem1 /* x87 fprem(%A3, %A4) -> %D1 */', + "emit" => '. fprem1', }, # this node is just here, to keep the simulator running @@ -1624,7 +1642,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Rem: Rem(a, b) = a - Q * b (Q is integer)", "reg_req" => { }, - "emit" => '. fprem1 /* x87 fprem(%A3, %A4) -> %D1 WITH POP */', + "emit" => '. fprem1', }, "fdiv" => { @@ -1632,7 +1650,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Div: Div(a, b) = a / b", "reg_req" => { }, - "emit" => '. fdiv %ia32_emit_x87_binop /* x87 fdiv(%A3, %A4) -> %D1 */', + "emit" => '. fdiv %x87_binop', }, "fdivp" => { @@ -1640,7 +1658,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Div: Div(a, b) = a / b", "reg_req" => { }, - "emit" => '. fdivp %ia32_emit_x87_binop /* x87 fdiv(%A3, %A4) -> %D1 */', + "emit" => '. fdivp %x87_binop', }, "fdivr" => { @@ -1648,7 +1666,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp DivR: DivR(a, b) = b / a", "reg_req" => { }, - "emit" => '. fdivr %ia32_emit_x87_binop /* x87 fdivr(%A3, %A4) -> %D1 */', + "emit" => '. fdivr %x87_binop', }, "fdivrp" => { @@ -1656,7 +1674,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp DivR: DivR(a, b) = b / a", "reg_req" => { }, - "emit" => '. fdivrp %ia32_emit_x87_binop /* x87 fdivr(%A3, %A4) -> %D1 */', + "emit" => '. fdivrp %x87_binop', }, "fabs" => { @@ -1664,7 +1682,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Abs: Abs(a) = |a|", "reg_req" => { }, - "emit" => '. fabs /* x87 fabs(%A1) -> %D1 */', + "emit" => '. fabs', }, "fchs" => { @@ -1672,7 +1690,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Chs: Chs(a) = -a", "reg_req" => { }, - "emit" => '. fchs /* x87 fchs(%A1) -> %D1 */', + "emit" => '. fchs', }, "fsin" => { @@ -1680,7 +1698,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sin: Sin(a) = sin(a)", "reg_req" => { }, - "emit" => '. fsin /* x87 sin(%A1) -> %D1 */', + "emit" => '. fsin', }, "fcos" => { @@ -1688,7 +1706,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Cos: Cos(a) = cos(a)", "reg_req" => { }, - "emit" => '. fcos /* x87 cos(%A1) -> %D1 */', + "emit" => '. fcos', }, "fsqrt" => { @@ -1696,7 +1714,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp Sqrt: Sqrt(a) = a ^ 0.5", "reg_req" => { }, - "emit" => '. fsqrt $ /* x87 sqrt(%A1) -> %D1 */', + "emit" => '. fsqrt $', }, # x87 Load and Store @@ -1707,7 +1725,7 @@ else { "state" => "exc_pinned", "comment" => "x87 fp Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { }, - "emit" => '. fld %ia32_emit_am /* Load((%A1)) -> %D1 */', + "emit" => '. fld%M %AM', }, "fst" => { @@ -1716,7 +1734,7 @@ else { "state" => "exc_pinned", "comment" => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { }, - "emit" => '. fst %ia32_emit_am /* Store(%A3) -> (%A1) */', + "emit" => '. fst%M %AM', "mode" => "mode_M", }, @@ -1726,7 +1744,7 @@ else { "state" => "exc_pinned", "comment" => "x87 fp Store: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { }, - "emit" => '. fstp %ia32_emit_am /* Store(%A3) -> (%A1) and pop */', + "emit" => '. fstp%M %AM', "mode" => "mode_M", }, @@ -1737,7 +1755,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp integer Load: Load(ptr, mem) = iLD ptr -> reg", "reg_req" => { }, - "emit" => '. fild %ia32_emit_am /* integer Load((%A1)) -> %D1 */', + "emit" => '. fild%M %AM', }, "fist" => { @@ -1745,7 +1763,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val", "reg_req" => { }, - "emit" => '. fist %ia32_emit_am /* integer Store(%A3) -> (%A1) */', + "emit" => '. fist%M %AM', "mode" => "mode_M", }, @@ -1754,7 +1772,7 @@ else { "rd_constructor" => "NONE", "comment" => "x87 fp integer Store: Store(ptr, val, mem) = iST ptr,val", "reg_req" => { }, - "emit" => '. fistp %ia32_emit_am /* integer Store(%A3) -> (%A1) and pop */', + "emit" => '. fistp%M %AM', "mode" => "mode_M", }, @@ -1765,7 +1783,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load 0.0: Ld 0.0 -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldz /* x87 0.0 -> %D1 */', + "emit" => '. fldz', }, "fld1" => { @@ -1773,7 +1791,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load 1.0: Ld 1.0 -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fld1 /* x87 1.0 -> %D1 */', + "emit" => '. fld1', }, "fldpi" => { @@ -1781,7 +1799,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load pi: Ld pi -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldpi /* x87 pi -> %D1 */', + "emit" => '. fldpi', }, "fldln2" => { @@ -1789,7 +1807,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load ln 2: Ld ln 2 -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldln2 /* x87 ln(2) -> %D1 */', + "emit" => '. fldln2', }, "fldlg2" => { @@ -1797,7 +1815,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load lg 2: Ld lg 2 -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldlg2 /* x87 log(2) -> %D1 */', + "emit" => '. fldlg2', }, "fldl2t" => { @@ -1805,7 +1823,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load ld 10: Ld ld 10 -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldll2t /* x87 ld(10) -> %D1 */', + "emit" => '. fldll2t', }, "fldl2e" => { @@ -1813,7 +1831,7 @@ else { "irn_flags" => "R", "comment" => "x87 fp Load ld e: Ld ld e -> reg", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fldl2e /* x87 ld(e) -> %D1 */', + "emit" => '. fldl2e', }, "fldConst" => { @@ -1822,7 +1840,7 @@ else { "rd_constructor" => "NONE", "comment" => "represents a x87 constant", "reg_req" => { "out" => [ "vfp" ] }, - "emit" => '. fld %ia32_emit_adr /* Load fConst into register -> %D1 */', + "emit" => '. fld $%C', }, # fxch, fpush, fpop @@ -1834,7 +1852,7 @@ else { "comment" => "x87 stack exchange", "reg_req" => { }, "cmp_attr" => "return 1;", - "emit" => '. fxch %X1 /* x87 swap %X1, %X3 */', + "emit" => '. fxch %X1', }, "fpush" => { @@ -1842,7 +1860,7 @@ else { "comment" => "x87 stack push", "reg_req" => {}, "cmp_attr" => "return 1;", - "emit" => '. fld %X1 /* x87 push %X1 */', + "emit" => '. fld %X1', }, "fpushCopy" => { @@ -1850,7 +1868,7 @@ else { "comment" => "x87 stack push", "reg_req" => { "in" => [ "vfp"], "out" => [ "vfp" ] }, "cmp_attr" => "return 1;", - "emit" => '. fld %X1 /* x87 push %X1 */', + "emit" => '. fld %X1', }, "fpop" => { @@ -1858,7 +1876,7 @@ else { "comment" => "x87 stack pop", "reg_req" => { }, "cmp_attr" => "return 1;", - "emit" => '. fstp %X1 /* x87 pop %X1 */', + "emit" => '. fstp %X1', }, # compare diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 4834db183..ae3ccf2f5 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -118,16 +118,16 @@ static INLINE ir_node *get_new_node(ir_node *old_node) * Returns 1 if irn is a Const representing 0, 0 otherwise */ static INLINE int is_ia32_Const_0(ir_node *irn) { - return (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_Const) ? - classify_tarval(get_ia32_Immop_tarval(irn)) == TV_CLASSIFY_NULL : 0; + return is_ia32_irn(irn) && is_ia32_Const(irn) && get_ia32_immop_type(irn) == ia32_ImmConst + && tarval_is_null(get_ia32_Immop_tarval(irn)); } /** * Returns 1 if irn is a Const representing 1, 0 otherwise */ static INLINE int is_ia32_Const_1(ir_node *irn) { - return (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_Const) ? - classify_tarval(get_ia32_Immop_tarval(irn)) == TV_CLASSIFY_ONE : 0; + return is_ia32_irn(irn) && is_ia32_Const(irn) && get_ia32_immop_type(irn) == ia32_ImmConst + && tarval_is_one(get_ia32_Immop_tarval(irn)); } /** @@ -488,10 +488,10 @@ static void fold_immediate(ia32_transform_env_t *env, ir_node *node, int in1, in /* exchange left/right */ set_irn_n(node, in1, right); set_irn_n(node, in2, ia32_get_admissible_noreg(env->cg, node, in2)); - set_ia32_Immop_attr(node, left); + copy_ia32_Immop_attr(node, left); } else if(is_ia32_Cnst(right)) { set_irn_n(node, in2, ia32_get_admissible_noreg(env->cg, node, in2)); - set_ia32_Immop_attr(node, right); + copy_ia32_Immop_attr(node, right); } else { return; } @@ -633,7 +633,7 @@ static ir_node *gen_shift_binop(ia32_transform_env_t *env, ir_node *node, DB((mod, LEVEL_1, "Shift/Rot with immediate ...")); new_op = func(dbg, irg, block, noreg, noreg, expr_op, noreg, nomem); - set_ia32_Immop_attr(new_op, imm_op); + copy_ia32_Immop_attr(new_op, imm_op); } else { /* This is a normal shift/rot */ DB((mod, LEVEL_1, "Shift/Rot binop ...")); @@ -680,54 +680,6 @@ static ir_node *gen_unop(ia32_transform_env_t *env, ir_node *node, ir_node *op, } -/** - * Creates an ia32 Add with immediate. - * - * @param env The transformation environment - * @param expr_op The expression operator - * @param const_op The constant - * @return the created ia32 Add node - */ -static ir_node *gen_imm_Add(ia32_transform_env_t *env, ir_node *node, - ir_node *expr_op, ir_node *const_op) { - ir_node *new_op = NULL; - tarval *tv = get_ia32_Immop_tarval(const_op); - ir_graph *irg = env->irg; - dbg_info *dbg = get_irn_dbg_info(node); - ir_node *block = transform_node(env, get_nodes_block(node)); - ir_node *noreg = ia32_new_NoReg_gp(env->cg); - ir_node *nomem = new_NoMem(); - int normal_add = 1; - tarval_classification_t class_tv, class_negtv; - DEBUG_ONLY(firm_dbg_module_t *mod = env->mod;) - - /* try to optimize to inc/dec */ - if ((env->cg->opt & IA32_OPT_INCDEC) && tv && (get_ia32_op_type(const_op) == ia32_Const)) { - /* optimize tarvals */ - class_tv = classify_tarval(tv); - class_negtv = classify_tarval(tarval_neg(tv)); - - if (class_tv == TV_CLASSIFY_ONE) { /* + 1 == INC */ - DB((env->mod, LEVEL_2, "Add(1) to Inc ... ")); - new_op = new_rd_ia32_Inc(dbg, irg, block, noreg, noreg, expr_op, nomem); - normal_add = 0; - } - else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { /* + (-1) == DEC */ - DB((mod, LEVEL_2, "Add(-1) to Dec ... ")); - new_op = new_rd_ia32_Dec(dbg, irg, block, noreg, noreg, expr_op, nomem); - normal_add = 0; - } - } - - if (normal_add) { - new_op = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, expr_op, noreg, nomem); - set_ia32_Immop_attr(new_op, const_op); - set_ia32_commutative(new_op); - } - - return new_op; -} - /** * Creates an ia32 Add. * @@ -762,90 +714,132 @@ static ir_node *gen_Add(ia32_transform_env_t *env, ir_node *node) { else return gen_binop_float(env, node, op1, op2, new_rd_ia32_vfadd); } - else { - /* integer ADD */ - if (!expr_op) { - /* No expr_op means, that we have two const - one symconst and */ - /* one tarval or another symconst - because this case is not */ - /* covered by constant folding */ - /* We need to check for: */ - /* 1) symconst + const -> becomes a LEA */ - /* 2) symconst + symconst -> becomes a const + LEA as the elf */ - /* linker doesn't support two symconsts */ - - if (get_ia32_op_type(new_op1) == ia32_SymConst - && get_ia32_op_type(new_op2) == ia32_SymConst) { - /* this is the 2nd case */ - new_op = new_rd_ia32_Lea(dbg, irg, block, new_op1, noreg); - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_op2)); - set_ia32_am_flavour(new_op, ia32_am_OB); - set_ia32_am_support(new_op, ia32_am_Source); - set_ia32_op_type(new_op, ia32_AddrModeS); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - } else { - /* this is the 1st case */ - if (get_ia32_op_type(new_op1) == ia32_SymConst) { - tarval *tv = get_ia32_cnst_tv(new_op2); - long offs = get_tarval_long(tv); - - new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_op1)); - add_ia32_am_offs_int(new_op, offs); - set_ia32_am_flavour(new_op, ia32_am_O); - set_ia32_am_support(new_op, ia32_am_Source); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else if (get_ia32_op_type(new_op2) == ia32_SymConst) { - tarval *tv = get_ia32_cnst_tv(new_op1); - long offs = get_tarval_long(tv); - - new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - - add_ia32_am_offs_int(new_op, offs); - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_op2)); - set_ia32_am_flavour(new_op, ia32_am_O); - set_ia32_am_support(new_op, ia32_am_Source); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else { - tarval *tv1 = get_ia32_cnst_tv(new_op1); - tarval *tv2 = get_ia32_cnst_tv(new_op2); - tarval *restv = tarval_add(tv1, tv2); + /* integer ADD */ + if (!expr_op) { + ia32_immop_type_t tp1 = get_ia32_immop_type(new_op1); + ia32_immop_type_t tp2 = get_ia32_immop_type(new_op2); + + /* No expr_op means, that we have two const - one symconst and */ + /* one tarval or another symconst - because this case is not */ + /* covered by constant folding */ + /* We need to check for: */ + /* 1) symconst + const -> becomes a LEA */ + /* 2) symconst + symconst -> becomes a const + LEA as the elf */ + /* linker doesn't support two symconsts */ + + if (tp1 == ia32_ImmSymConst && tp2 == ia32_ImmSymConst) { + /* this is the 2nd case */ + new_op = new_rd_ia32_Lea(dbg, irg, block, new_op1, noreg); + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op2)); + set_ia32_am_flavour(new_op, ia32_am_OB); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); - DEBUG_ONLY(ir_fprintf(stderr, "Warning: add with 2 consts not folded: %+F\n", node)); + DBG_OPT_LEA3(new_op1, new_op2, node, new_op); + } else if (tp1 == ia32_ImmSymConst) { + tarval *tv = get_ia32_Immop_tarval(new_op2); + long offs = get_tarval_long(tv); - new_op = new_rd_ia32_Const(dbg, irg, block); - set_ia32_Const_tarval(new_op, restv); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - } - } + new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); + DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - return new_op; - } - else if (imm_op) { - /* This is expr + const */ - new_op = gen_imm_Add(env, node, expr_op, imm_op); + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op1)); + add_ia32_am_offs_int(new_op, offs); + set_ia32_am_flavour(new_op, ia32_am_O); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); + } else if (tp2 == ia32_ImmSymConst) { + tarval *tv = get_ia32_Immop_tarval(new_op1); + long offs = get_tarval_long(tv); + + new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); + DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Dest); + add_ia32_am_offs_int(new_op, offs); + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op2)); + set_ia32_am_flavour(new_op, ia32_am_O); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); + } else { + tarval *tv1 = get_ia32_Immop_tarval(new_op1); + tarval *tv2 = get_ia32_Immop_tarval(new_op2); + tarval *restv = tarval_add(tv1, tv2); + + DEBUG_ONLY(ir_fprintf(stderr, "Warning: add with 2 consts not folded: %+F\n", node)); + + new_op = new_rd_ia32_Const(dbg, irg, block); + set_ia32_Const_tarval(new_op, restv); + DBG_OPT_LEA3(new_op1, new_op2, node, new_op); } - else { - /* This is a normal add */ - new_op = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, new_op1, new_op2, nomem); - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Full); - set_ia32_commutative(new_op); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + return new_op; + } else if (imm_op) { + if((env->cg->opt & IA32_OPT_INCDEC) && get_ia32_immop_type(imm_op) == ia32_ImmConst) { + tarval_classification_t class_tv, class_negtv; + tarval *tv = get_ia32_Immop_tarval(imm_op); + + /* optimize tarvals */ + class_tv = classify_tarval(tv); + class_negtv = classify_tarval(tarval_neg(tv)); + + if (class_tv == TV_CLASSIFY_ONE) { /* + 1 == INC */ + DB((env->mod, LEVEL_2, "Add(1) to Inc ... ")); + new_op = new_rd_ia32_Inc(dbg, irg, block, noreg, noreg, expr_op, nomem); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + return new_op; + } else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { /* + (-1) == DEC */ + DB((env->mod, LEVEL_2, "Add(-1) to Dec ... ")); + new_op = new_rd_ia32_Dec(dbg, irg, block, noreg, noreg, expr_op, nomem); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + return new_op; + } } } + /* This is a normal add */ + new_op = new_rd_ia32_Add(dbg, irg, block, noreg, noreg, new_op1, new_op2, nomem); + + /* set AM support */ + set_ia32_am_support(new_op, ia32_am_Full); + set_ia32_commutative(new_op); + + fold_immediate(env, new_op, 2, 3); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); return new_op; } +#if 0 +static ir_node *create_ia32_Mul(ia32_transform_env_t *env, ir_node *node) { + ir_graph *irg = env->irg; + dbg_info *dbg = get_irn_dbg_info(node); + ir_node *block = transform_node(env, get_nodes_block(node)); + ir_node *op1 = get_Mul_left(node); + ir_node *op2 = get_Mul_right(node); + ir_node *new_op1 = transform_node(env, op1); + ir_node *new_op2 = transform_node(env, op2); + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *proj_EAX, *proj_EDX, *res; + ir_node *in[1]; + + res = new_rd_ia32_Mul(dbg, irg, block, noreg, noreg, new_op1, new_op2, new_NoMem()); + set_ia32_commutative(res); + set_ia32_am_support(res, ia32_am_Source); + + /* imediates are not supported, so no fold_immediate */ + proj_EAX = new_rd_Proj(dbg, irg, block, res, mode_Iu, pn_EAX); + proj_EDX = new_rd_Proj(dbg, irg, block, res, mode_Iu, pn_EDX); + + /* keep EAX */ + in[0] = proj_EDX; + be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, in); + + return proj_EAX; +} +#endif /** @@ -857,25 +851,22 @@ static ir_node *gen_Add(ia32_transform_env_t *env, ir_node *node) { static ir_node *gen_Mul(ia32_transform_env_t *env, ir_node *node) { ir_node *op1 = get_Mul_left(node); ir_node *op2 = get_Mul_right(node); - ir_node *new_op; ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { FP_USED(env->cg); if (USE_SSE2(env->cg)) - new_op = gen_binop_float(env, node, op1, op2, new_rd_ia32_xMul); + return gen_binop_float(env, node, op1, op2, new_rd_ia32_xMul); else - new_op = gen_binop_float(env, node, op1, op2, new_rd_ia32_vfmul); - } - else { - new_op = gen_binop(env, node, op1, op2, new_rd_ia32_Mul); + return gen_binop_float(env, node, op1, op2, new_rd_ia32_vfmul); } - return new_op; + // for the lower 32bit of the result it doesn't matter whether we use + // signed or unsigned multiplication so we use IMul as it has fewer + // constraints + return gen_binop(env, node, op1, op2, new_rd_ia32_IMul); } - - /** * Creates an ia32 Mulh. * Note: Mul produces a 64Bit result and Mulh returns the upper 32 bit of @@ -961,7 +952,7 @@ static ir_node *gen_Eor(ia32_transform_env_t *env, ir_node *node) { ir_mode *mode = get_irn_mode(node); assert(! mode_is_float(mode)); - return gen_binop(env, node, op1, op2, new_rd_ia32_Eor); + return gen_binop(env, node, op1, op2, new_rd_ia32_Xor); } @@ -1051,54 +1042,6 @@ static ir_node *gen_Min(ia32_transform_env_t *env, ir_node *node) { } - -/** - * Creates an ia32 Sub with immediate. - * - * @param env The transformation environment - * @param expr_op The first operator - * @param const_op The constant operator - * @return The created ia32 Sub node - */ -static ir_node *gen_imm_Sub(ia32_transform_env_t *env, ir_node *node, - ir_node *expr_op, ir_node *const_op) { - ir_node *new_op = NULL; - tarval *tv = get_ia32_Immop_tarval(const_op); - ir_graph *irg = env->irg; - dbg_info *dbg = get_irn_dbg_info(node); - ir_node *block = transform_node(env, get_nodes_block(node)); - ir_node *noreg = ia32_new_NoReg_gp(env->cg); - ir_node *nomem = new_NoMem(); - int normal_sub = 1; - tarval_classification_t class_tv, class_negtv; - DEBUG_ONLY(firm_dbg_module_t *mod = env->mod;) - - /* try to optimize to inc/dec */ - if ((env->cg->opt & IA32_OPT_INCDEC) && tv && (get_ia32_op_type(const_op) == ia32_Const)) { - /* optimize tarvals */ - class_tv = classify_tarval(tv); - class_negtv = classify_tarval(tarval_neg(tv)); - - if (class_tv == TV_CLASSIFY_ONE) { /* - 1 == DEC */ - DB((mod, LEVEL_2, "Sub(1) to Dec ... ")); - new_op = new_rd_ia32_Dec(dbg, irg, block, noreg, noreg, expr_op, nomem); - normal_sub = 0; - } - else if (class_negtv == TV_CLASSIFY_ONE) { /* - (-1) == Sub */ - DB((mod, LEVEL_2, "Sub(-1) to Inc ... ")); - new_op = new_rd_ia32_Inc(dbg, irg, block, noreg, noreg, expr_op, nomem); - normal_sub = 0; - } - } - - if (normal_sub) { - new_op = new_rd_ia32_Sub(dbg, irg, block, noreg, noreg, expr_op, noreg, nomem); - set_ia32_Immop_attr(new_op, const_op); - } - - return new_op; -} - /** * Creates an ia32 Sub. * @@ -1132,80 +1075,98 @@ static ir_node *gen_Sub(ia32_transform_env_t *env, ir_node *node) { return gen_binop_float(env, node, op1, op2, new_rd_ia32_xSub); else return gen_binop_float(env, node, op1, op2, new_rd_ia32_vfsub); - } else { - /* integer SUB */ - if (! expr_op) { - /* No expr_op means, that we have two const - one symconst and */ - /* one tarval or another symconst - because this case is not */ - /* covered by constant folding */ - /* We need to check for: */ - /* 1) symconst - const -> becomes a LEA */ - /* 2) symconst - symconst -> becomes a const - LEA as the elf */ - /* linker doesn't support two symconsts */ - - if (get_ia32_op_type(new_op1) == ia32_SymConst - && get_ia32_op_type(new_op2) == ia32_SymConst) { - /* this is the 2nd case */ - new_op = new_rd_ia32_Lea(dbg, irg, block, new_op1, noreg); - set_ia32_am_sc(new_op, get_ia32_id_cnst(op2)); - set_ia32_am_sc_sign(new_op); - set_ia32_am_flavour(new_op, ia32_am_OB); - - DBG_OPT_LEA3(op1, op2, node, new_op); - } else { - /* this is the 1st case */ - new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); - - DBG_OPT_LEA3(op1, op2, node, new_op); - - if (get_ia32_op_type(new_op1) == ia32_SymConst) { - tarval *tv = get_ia32_cnst_tv(new_op2); - long offs = get_tarval_long(tv); - - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_op1)); - add_ia32_am_offs_int(new_op, -offs); - set_ia32_am_flavour(new_op, ia32_am_O); - set_ia32_am_support(new_op, ia32_am_Source); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else if (get_ia32_op_type(new_op2) == ia32_SymConst) { - tarval *tv = get_ia32_cnst_tv(new_op1); - long offs = get_tarval_long(tv); - - add_ia32_am_offs_int(new_op, offs); - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_op2)); - set_ia32_am_sc_sign(new_op); - set_ia32_am_flavour(new_op, ia32_am_O); - set_ia32_am_support(new_op, ia32_am_Source); - set_ia32_op_type(new_op, ia32_AddrModeS); - } else { - tarval *tv1 = get_ia32_cnst_tv(new_op1); - tarval *tv2 = get_ia32_cnst_tv(new_op2); - tarval *restv = tarval_sub(tv1, tv2); + } - DEBUG_ONLY(ir_fprintf(stderr, "Warning: sub with 2 consts not folded: %+F\n", node)); + /* integer SUB */ + if (! expr_op) { + ia32_immop_type_t tp1 = get_ia32_immop_type(new_op1); + ia32_immop_type_t tp2 = get_ia32_immop_type(new_op2); + + /* No expr_op means, that we have two const - one symconst and */ + /* one tarval or another symconst - because this case is not */ + /* covered by constant folding */ + /* We need to check for: */ + /* 1) symconst - const -> becomes a LEA */ + /* 2) symconst - symconst -> becomes a const - LEA as the elf */ + /* linker doesn't support two symconsts */ + if (tp1 == ia32_ImmSymConst && tp2 == ia32_ImmSymConst) { + /* this is the 2nd case */ + new_op = new_rd_ia32_Lea(dbg, irg, block, new_op1, noreg); + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(op2)); + set_ia32_am_sc_sign(new_op); + set_ia32_am_flavour(new_op, ia32_am_OB); + + DBG_OPT_LEA3(op1, op2, node, new_op); + } else if (tp1 == ia32_ImmSymConst) { + tarval *tv = get_ia32_Immop_tarval(new_op2); + long offs = get_tarval_long(tv); - new_op = new_rd_ia32_Const(dbg, irg, block); - set_ia32_Const_tarval(new_op, restv); - DBG_OPT_LEA3(new_op1, new_op2, node, new_op); - } - } + new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); + DBG_OPT_LEA3(op1, op2, node, new_op); + + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op1)); + add_ia32_am_offs_int(new_op, -offs); + set_ia32_am_flavour(new_op, ia32_am_O); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); + } else if (tp2 == ia32_ImmSymConst) { + tarval *tv = get_ia32_Immop_tarval(new_op1); + long offs = get_tarval_long(tv); - return new_op; - } else if (imm_op) { - /* This is expr - const */ - new_op = gen_imm_Sub(env, node, expr_op, imm_op); + new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg); + DBG_OPT_LEA3(op1, op2, node, new_op); - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Dest); + add_ia32_am_offs_int(new_op, offs); + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_op2)); + set_ia32_am_sc_sign(new_op); + set_ia32_am_flavour(new_op, ia32_am_O); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); } else { - /* This is a normal sub */ - new_op = new_rd_ia32_Sub(dbg, irg, block, noreg, noreg, new_op1, new_op2, nomem); + tarval *tv1 = get_ia32_Immop_tarval(new_op1); + tarval *tv2 = get_ia32_Immop_tarval(new_op2); + tarval *restv = tarval_sub(tv1, tv2); + + DEBUG_ONLY(ir_fprintf(stderr, "Warning: sub with 2 consts not folded: %+F\n", node)); - /* set AM support */ - set_ia32_am_support(new_op, ia32_am_Full); + new_op = new_rd_ia32_Const(dbg, irg, block); + set_ia32_Const_tarval(new_op, restv); + DBG_OPT_LEA3(new_op1, new_op2, node, new_op); + } + + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + return new_op; + } else if (imm_op) { + if((env->cg->opt & IA32_OPT_INCDEC) && get_ia32_immop_type(imm_op) == ia32_ImmConst) { + tarval_classification_t class_tv, class_negtv; + tarval *tv = get_ia32_Immop_tarval(imm_op); + + /* optimize tarvals */ + class_tv = classify_tarval(tv); + class_negtv = classify_tarval(tarval_neg(tv)); + + if (class_tv == TV_CLASSIFY_ONE) { + DB((env->mod, LEVEL_2, "Sub(1) to Dec ... ")); + new_op = new_rd_ia32_Dec(dbg, irg, block, noreg, noreg, expr_op, nomem); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + return new_op; + } else if (class_tv == TV_CLASSIFY_ALL_ONE || class_negtv == TV_CLASSIFY_ONE) { + DB((env->mod, LEVEL_2, "Sub(-1) to Inc ... ")); + new_op = new_rd_ia32_Inc(dbg, irg, block, noreg, noreg, expr_op, nomem); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + return new_op; + } } } + /* This is a normal sub */ + new_op = new_rd_ia32_Sub(dbg, irg, block, noreg, noreg, new_op1, new_op2, nomem); + + /* set AM support */ + set_ia32_am_support(new_op, ia32_am_Full); + + fold_immediate(env, new_op, 2, 3); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); return new_op; @@ -1262,14 +1223,12 @@ static ir_node *generate_DivMod(ia32_transform_env_t *env, ir_node *node, if (mode_is_signed(mode)) { /* in signed mode, we need to sign extend the dividend */ - cltd = new_rd_ia32_Cdq(dbg, irg, block, new_dividend); - new_dividend = new_rd_Proj(dbg, irg, block, cltd, mode_Iu, pn_ia32_Cdq_EAX); - edx_node = new_rd_Proj(dbg, irg, block, cltd, mode_Iu, pn_ia32_Cdq_EDX); - } - else { + cltd = new_rd_ia32_Cltd(dbg, irg, block, new_dividend); + new_dividend = new_rd_Proj(dbg, irg, block, cltd, mode_Iu, pn_ia32_Cltd_EAX); + edx_node = new_rd_Proj(dbg, irg, block, cltd, mode_Iu, pn_ia32_Cltd_EDX); + } else { edx_node = new_rd_ia32_Const(dbg, irg, block); add_irn_dep(edx_node, be_abi_get_start_barrier(env->cg->birg->abi)); - set_ia32_Const_type(edx_node, ia32_Const); set_ia32_Immop_tarval(edx_node, get_tarval_null(mode_Iu)); } @@ -1383,7 +1342,7 @@ static ir_node *gen_Quot(ia32_transform_env_t *env, ir_node *node) { if (is_ia32_xConst(new_op2)) { new_op = new_rd_ia32_xDiv(dbg, irg, block, noreg, noreg, new_op1, noreg, nomem); set_ia32_am_support(new_op, ia32_am_None); - set_ia32_Immop_attr(new_op, new_op2); + copy_ia32_Immop_attr(new_op, new_op2); } else { new_op = new_rd_ia32_xDiv(dbg, irg, block, noreg, noreg, new_op1, new_op2, nomem); // Matze: disabled for now, spillslot coalescer fails @@ -1427,14 +1386,14 @@ static ir_node *gen_Shr(ia32_transform_env_t *env, ir_node *node) { /** - * Creates an ia32 Shrs. + * Creates an ia32 Sar. * * @param env The transformation environment * @return The created ia32 Shrs node */ static ir_node *gen_Shrs(ia32_transform_env_t *env, ir_node *node) { return gen_shift_binop(env, node, get_Shrs_left(node), - get_Shrs_right(node), new_rd_ia32_Shrs); + get_Shrs_right(node), new_rd_ia32_Sar); } @@ -1449,7 +1408,7 @@ static ir_node *gen_Shrs(ia32_transform_env_t *env, ir_node *node) { */ static ir_node *gen_RotL(ia32_transform_env_t *env, ir_node *node, ir_node *op1, ir_node *op2) { - return gen_shift_binop(env, node, op1, op2, new_rd_ia32_RotL); + return gen_shift_binop(env, node, op1, op2, new_rd_ia32_Rol); } @@ -1466,7 +1425,7 @@ static ir_node *gen_RotL(ia32_transform_env_t *env, ir_node *node, */ static ir_node *gen_RotR(ia32_transform_env_t *env, ir_node *node, ir_node *op1, ir_node *op2) { - return gen_shift_binop(env, node, op1, op2, new_rd_ia32_RotR); + return gen_shift_binop(env, node, op1, op2, new_rd_ia32_Ror); } @@ -1486,31 +1445,26 @@ static ir_node *gen_Rot(ia32_transform_env_t *env, ir_node *node) { operand "-e+mode_size_bits" (it's an already modified "mode_size_bits-e", that means we can create a RotR instead of an Add and a RotL */ - if (is_Proj(op2)) { - ir_node *pred = get_Proj_pred(op2); - - if (is_ia32_Add(pred)) { - ir_node *pred_pred = get_irn_n(pred, 2); - tarval *tv = get_ia32_Immop_tarval(pred); + if (get_irn_op(op2) == op_Add) { + ir_node *add = op2; + ir_node *left = get_Add_left(add); + ir_node *right = get_Add_right(add); + if (is_Const(right)) { + tarval *tv = get_Const_tarval(right); ir_mode *mode = get_irn_mode(node); long bits = get_mode_size_bits(mode); - if (is_Proj(pred_pred)) { - pred_pred = get_Proj_pred(pred_pred); - } - - if (is_ia32_Minus(pred_pred) && - tarval_is_long(tv) && - get_tarval_long(tv) == bits) + if (get_irn_op(left) == op_Minus && + tarval_is_long(tv) && + get_tarval_long(tv) == bits) { DB((env->mod, LEVEL_1, "RotL into RotR ... ")); - rotate = gen_RotR(env, node, op1, get_irn_n(pred_pred, 2)); + rotate = gen_RotR(env, node, op1, get_Minus_op(left)); } - } } - if (!rotate) { + if (rotate == NULL) { rotate = gen_RotL(env, node, op1, op2); } @@ -1543,7 +1497,7 @@ ir_node *gen_Minus_ex(ia32_transform_env_t *env, ir_node *node, ir_node *op) { ir_node *noreg_fp = ia32_new_NoReg_fp(env->cg); ir_node *nomem = new_rd_NoMem(irg); - res = new_rd_ia32_xEor(dbg, irg, block, noreg_gp, noreg_gp, new_op, noreg_fp, nomem); + res = new_rd_ia32_xXor(dbg, irg, block, noreg_gp, noreg_gp, new_op, noreg_fp, nomem); size = get_mode_size_bits(mode); name = ia32_gen_fp_known_const(size == 32 ? ia32_SSIGN : ia32_DSIGN); @@ -1555,7 +1509,7 @@ ir_node *gen_Minus_ex(ia32_transform_env_t *env, ir_node *node, ir_node *op) { res = new_rd_ia32_vfchs(dbg, irg, block, new_op); } } else { - res = gen_unop(env, node, op, new_rd_ia32_Minus); + res = gen_unop(env, node, op, new_rd_ia32_Neg); } SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node)); @@ -1631,13 +1585,13 @@ static ir_node *gen_Abs(ia32_transform_env_t *env, ir_node *node) { } } else { - res = new_rd_ia32_Cdq(dbg, irg, block, new_op); + res = new_rd_ia32_Cltd(dbg, irg, block, new_op); SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node)); p_eax = new_rd_Proj(dbg, irg, block, res, mode_Iu, pn_EAX); p_edx = new_rd_Proj(dbg, irg, block, res, mode_Iu, pn_EDX); - res = new_rd_ia32_Eor(dbg, irg, block, noreg_gp, noreg_gp, p_eax, p_edx, nomem); + res = new_rd_ia32_Xor(dbg, irg, block, noreg_gp, noreg_gp, p_eax, p_edx, nomem); SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node)); res = new_rd_ia32_Sub(dbg, irg, block, noreg_gp, noreg_gp, res, p_edx, nomem); @@ -1702,11 +1656,11 @@ static ir_node *gen_Load(ia32_transform_env_t *env, ir_node *node) { /* base is a constant address */ if (is_imm) { - if (get_ia32_op_type(new_ptr) == ia32_SymConst) { - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_ptr)); + if (get_ia32_immop_type(new_ptr) == ia32_ImmSymConst) { + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_ptr)); am_flav = ia32_am_N; } else { - tarval *tv = get_ia32_cnst_tv(new_ptr); + tarval *tv = get_ia32_Immop_tarval(new_ptr); long offs = get_tarval_long(tv); add_ia32_am_offs_int(new_op, offs); @@ -1756,23 +1710,10 @@ static ir_node *gen_Store(ia32_transform_env_t *env, ir_node *node) { int is_imm = 0; ir_node *new_op; ia32_am_flavour_t am_flav = ia32_am_B; - ia32_immop_type_t immop = ia32_ImmNone; - - if (! mode_is_float(mode)) { - /* in case of storing a const (but not a symconst) -> make it an attribute */ - if (is_ia32_Cnst(new_val)) { - switch (get_ia32_op_type(new_val)) { - case ia32_Const: - immop = ia32_ImmConst; - break; - case ia32_SymConst: - immop = ia32_ImmSymConst; - break; - default: - assert(0 && "unsupported Const type"); - } - sval = noreg; - } + + if (is_ia32_Const(new_val)) { + assert(!mode_is_float(mode)); + sval = noreg; } /* address might be a constant (symconst or absolute address) */ @@ -1785,31 +1726,28 @@ static ir_node *gen_Store(ia32_transform_env_t *env, ir_node *node) { FP_USED(env->cg); if (USE_SSE2(env->cg)) { new_op = new_rd_ia32_xStore(dbg, irg, block, sptr, noreg, sval, new_mem); - } - else { + } else { new_op = new_rd_ia32_vfst(dbg, irg, block, sptr, noreg, sval, new_mem); } - } - else if (get_mode_size_bits(mode) == 8) { + } else if (get_mode_size_bits(mode) == 8) { new_op = new_rd_ia32_Store8Bit(dbg, irg, block, sptr, noreg, sval, new_mem); - } - else { + } else { new_op = new_rd_ia32_Store(dbg, irg, block, sptr, noreg, sval, new_mem); } /* stored const is an immediate value */ - if (! mode_is_float(mode) && is_ia32_Cnst(new_val)) { - set_ia32_Immop_attr(new_op, new_val); + if (is_ia32_Const(new_val)) { + assert(!mode_is_float(mode)); + copy_ia32_Immop_attr(new_op, new_val); } /* base is an constant address */ if (is_imm) { - if (get_ia32_op_type(new_ptr) == ia32_SymConst) { - set_ia32_am_sc(new_op, get_ia32_id_cnst(new_ptr)); + if (get_ia32_immop_type(new_ptr) == ia32_ImmSymConst) { + set_ia32_am_sc(new_op, get_ia32_Immop_symconst(new_ptr)); am_flav = ia32_am_N; - } - else { - tarval *tv = get_ia32_cnst_tv(new_ptr); + } else { + tarval *tv = get_ia32_Immop_tarval(new_ptr); long offs = get_tarval_long(tv); add_ia32_am_offs_int(new_op, offs); @@ -1821,7 +1759,6 @@ static ir_node *gen_Store(ia32_transform_env_t *env, ir_node *node) { set_ia32_op_type(new_op, ia32_AddrModeD); set_ia32_am_flavour(new_op, am_flav); set_ia32_ls_mode(new_op, mode); - set_ia32_immop_type(new_op, immop); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); @@ -1871,25 +1808,25 @@ static ir_node *gen_Cond(ia32_transform_env_t *env, ir_node *node) { } if ((pnc == pn_Cmp_Eq || pnc == pn_Cmp_Lg) && mode_is_int(get_irn_mode(expr))) { - if (get_ia32_op_type(cnst) == ia32_Const && + if (get_ia32_immop_type(cnst) == ia32_ImmConst && classify_tarval(get_ia32_Immop_tarval(cnst)) == TV_CLASSIFY_NULL) { /* a Cmp A =/!= 0 */ ir_node *op1 = expr; ir_node *op2 = expr; - const char *cnst = NULL; + int is_and = 0; /* check, if expr is an only once used And operation */ if (is_ia32_And(expr) && get_irn_n_edges(expr)) { op1 = get_irn_n(expr, 2); op2 = get_irn_n(expr, 3); - cnst = (is_ia32_ImmConst(expr) || is_ia32_ImmSymConst(expr)) ? get_ia32_cnst(expr) : NULL; + is_and = (is_ia32_ImmConst(expr) || is_ia32_ImmSymConst(expr)); } res = new_rd_ia32_TestJmp(dbg, irg, block, op1, op2); set_ia32_pncode(res, pnc); - if (cnst) { + if (is_and) { copy_ia32_Immop_attr(res, expr); } @@ -1910,7 +1847,7 @@ static ir_node *gen_Cond(ia32_transform_env_t *env, ir_node *node) { else { res = new_rd_ia32_CondJmp(dbg, irg, block, noreg, noreg, expr, noreg, nomem); } - set_ia32_Immop_attr(res, cnst); + copy_ia32_Immop_attr(res, cnst); } else { ir_mode *cmp_mode = get_irn_mode(cmp_a); @@ -2002,7 +1939,6 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env, ir_node *node) { res = new_rd_ia32_Const(dbg, irg, block); add_irn_dep(res, be_abi_get_start_barrier(env->cg->birg->abi)); - set_ia32_op_type(res, ia32_Const); set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is)); res = new_rd_ia32_CopyB(dbg, irg, block, new_dst, new_src, res, new_mem); @@ -2017,7 +1953,6 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env, ir_node *node) { else { res = new_rd_ia32_CopyB_i(dbg, irg, block, new_dst, new_src, new_mem); set_ia32_Immop_tarval(res, new_tarval_from_long(size, mode_Is)); - set_ia32_immop_type(res, ia32_ImmConst); /* ok: now attach Proj's because movsd will destroy esi and edi */ in[0] = new_r_Proj(irg, block, res, dst_mode, pn_ia32_CopyB_i_DST); @@ -2520,9 +2455,6 @@ static ir_node *gen_be_FrameAddr(ia32_transform_env_t *env, ir_node *node) { set_ia32_use_frame(res); set_ia32_am_flavour(res, ia32_am_OB); - //set_ia32_immop_type(res, ia32_ImmConst); - //set_ia32_commutative(res); - SET_IA32_ORIG_NODE(res, ia32_get_old_node_name(env->cg, node)); return res; @@ -2837,9 +2769,13 @@ static ir_node *gen_be_AddSP(ia32_transform_env_t *env, ir_node *node) { ir_node *new_sz = transform_node(env, sz); ir_node *sp = get_irn_n(node, be_pos_AddSP_old_sp); ir_node *new_sp = transform_node(env, sp); + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *nomem = new_NoMem(); - new_op = new_rd_ia32_AddSP(dbg, irg, block, new_sp, new_sz); - fold_immediate(env, new_op, 0, 1); + /* ia32 stack grows in reverse direction, make a SubSP */ + new_op = new_rd_ia32_SubSP(dbg, irg, block, noreg, noreg, new_sp, new_sz, nomem); + set_ia32_am_support(new_op, ia32_am_Source); + fold_immediate(env, new_op, 2, 3); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); @@ -2858,9 +2794,13 @@ static ir_node *gen_be_SubSP(ia32_transform_env_t *env, ir_node *node) { ir_node *new_sz = transform_node(env, sz); ir_node *sp = get_irn_n(node, be_pos_SubSP_old_sp); ir_node *new_sp = transform_node(env, sp); + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *nomem = new_NoMem(); - new_op = new_rd_ia32_SubSP(dbg, irg, block, new_sp, new_sz); - fold_immediate(env, new_op, 0, 1); + /* ia32 stack grows in reverse direction, make an AddSP */ + new_op = new_rd_ia32_AddSP(dbg, irg, block, noreg, noreg, new_sp, new_sz, nomem); + set_ia32_am_support(new_op, ia32_am_Source); + fold_immediate(env, new_op, 2, 3); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); @@ -3088,17 +3028,17 @@ static ir_node *gen_lowered_Store(ia32_transform_env_t *env, ir_node *node, cons return gen_lowered_Store(env, node, new_rd_ia32_##op, fp_unit); \ } -GEN_LOWERED_OP(AddC) +GEN_LOWERED_OP(Adc) GEN_LOWERED_OP(Add) -GEN_LOWERED_OP(SubC) +GEN_LOWERED_OP(Sbb) GEN_LOWERED_OP(Sub) -GEN_LOWERED_OP(Mul) -GEN_LOWERED_OP(Eor) +GEN_LOWERED_OP(IMul) +GEN_LOWERED_OP(Xor) GEN_LOWERED_x87_OP(vfprem) GEN_LOWERED_x87_OP(vfmul) GEN_LOWERED_x87_OP(vfsub) -GEN_LOWERED_UNOP(Minus) +GEN_LOWERED_UNOP(Neg) GEN_LOWERED_LOAD(vfild, fp_x87) GEN_LOWERED_LOAD(Load, fp_none) @@ -3132,21 +3072,22 @@ static ir_node *gen_ia32_l_vfdiv(ia32_transform_env_t *env, ir_node *node) { * Transforms a l_MulS into a "real" MulS node. * * @param env The transformation environment - * @return the created ia32 MulS node + * @return the created ia32 Mul node */ -static ir_node *gen_ia32_l_MulS(ia32_transform_env_t *env, ir_node *node) { +static ir_node *gen_ia32_l_Mul(ia32_transform_env_t *env, ir_node *node) { ir_node *noreg = ia32_new_NoReg_gp(env->cg); ir_graph *irg = env->irg; dbg_info *dbg = get_irn_dbg_info(node); ir_node *block = transform_node(env, get_nodes_block(node)); ir_node *left = get_binop_left(node); ir_node *right = get_binop_right(node); + ir_node *new_left = transform_node(env, left); + ir_node *new_right = transform_node(env, right); ir_node *in[2]; - /* l_MulS is already a mode_T node, so we create the MulS in the normal way */ + /* l_Mul is already a mode_T node, so we create the Mul in the normal way */ /* and then skip the result Proj, because all needed Projs are already there. */ - - ir_node *muls = new_rd_ia32_MulS(dbg, irg, block, noreg, noreg, left, right, new_NoMem()); + ir_node *muls = new_rd_ia32_Mul(dbg, irg, block, noreg, noreg, new_left, new_right, new_NoMem()); clear_ia32_commutative(muls); set_ia32_am_support(muls, ia32_am_Source); fold_immediate(env, muls, 2, 3); @@ -3163,7 +3104,7 @@ static ir_node *gen_ia32_l_MulS(ia32_transform_env_t *env, ir_node *node) { GEN_LOWERED_SHIFT_OP(Shl) GEN_LOWERED_SHIFT_OP(Shr) -GEN_LOWERED_SHIFT_OP(Shrs) +GEN_LOWERED_SHIFT_OP(Sar) /** * Transforms a l_ShlD/l_ShrD into a ShlD/ShrD. Those nodes have 3 data inputs: @@ -3219,7 +3160,7 @@ static ir_node *gen_lowered_64bit_shifts(ia32_transform_env_t *env, ir_node *nod else new_op = new_rd_ia32_ShrD(dbg, irg, block, noreg, noreg, new_op1, new_op2, noreg, nomem); - set_ia32_Immop_attr(new_op, imm_op); + copy_ia32_Immop_attr(new_op, imm_op); } else { /* This is a normal ShiftD */ @@ -3656,6 +3597,16 @@ static ir_node *gen_Proj_Quot(ia32_transform_env_t *env, ir_node *node) return new_rd_Unknown(irg, mode); } +static ir_node *gen_Proj_tls(ia32_transform_env_t *env, ir_node *node) { + ir_graph *irg = env->irg; + dbg_info *dbg = get_irn_dbg_info(node); + ir_node *block = transform_node(env, get_nodes_block(node)); + + ir_node *res = new_rd_ia32_LdTls(dbg, irg, block, mode_Iu); + + return res; +} + static ir_node *gen_Proj(ia32_transform_env_t *env, ir_node *node) { ir_graph *irg = env->irg; dbg_info *dbg = get_irn_dbg_info(node); @@ -3683,15 +3634,20 @@ static ir_node *gen_Proj(ia32_transform_env_t *env, ir_node *node) { return gen_Proj_be_SubSP(env, node); } else if(be_is_AddSP(pred)) { return gen_Proj_be_AddSP(env, node); - } else if(get_irn_op(pred) == op_Start && proj == pn_Start_X_initial_exec) { - ir_node *block = get_nodes_block(pred); - ir_node *jump; - - block = transform_node(env, block); - // we exchange the ProjX with a jump - jump = new_rd_Jmp(dbg, irg, block); - ir_fprintf(stderr, "created jump: %+F\n", jump); - return jump; + } else if(get_irn_op(pred) == op_Start) { + if(proj == pn_Start_X_initial_exec) { + ir_node *block = get_nodes_block(pred); + ir_node *jump; + + block = transform_node(env, block); + // we exchange the ProjX with a jump + jump = new_rd_Jmp(dbg, irg, block); + ir_fprintf(stderr, "created jump: %+F\n", jump); + return jump; + } + if(node == env->old_anchors[anchor_tls]) { + return gen_Proj_tls(env, node); + } } return duplicate_node(env, node); @@ -3748,16 +3704,16 @@ static void register_transformers(void) { /* transform ops from intrinsic lowering */ GEN(ia32_l_Add); - GEN(ia32_l_AddC); + GEN(ia32_l_Adc); GEN(ia32_l_Sub); - GEN(ia32_l_SubC); - GEN(ia32_l_Minus); + GEN(ia32_l_Sbb); + GEN(ia32_l_Neg); GEN(ia32_l_Mul); - GEN(ia32_l_Eor); - GEN(ia32_l_MulS); + GEN(ia32_l_Xor); + GEN(ia32_l_IMul); GEN(ia32_l_Shl); GEN(ia32_l_Shr); - GEN(ia32_l_Shrs); + GEN(ia32_l_Sar); GEN(ia32_l_ShlD); GEN(ia32_l_ShrD); GEN(ia32_l_vfdiv); diff --git a/ir/be/scripts/generate_emitter.pl b/ir/be/scripts/generate_emitter.pl index 6fe175fc0..445cb3d25 100755 --- a/ir/be/scripts/generate_emitter.pl +++ b/ir/be/scripts/generate_emitter.pl @@ -13,9 +13,10 @@ my $specfile = $ARGV[0]; my $target_dir = $ARGV[1]; our $arch; -our $comment_string; -our $comment_string_end; +our $comment_string = "/*"; +our $comment_string_end = "*/" ; our %nodes; +our $new_emit_syntax = 0; # include spec file @@ -29,6 +30,11 @@ unless ($return = do $specfile) { } use strict "subs"; +if ($new_emit_syntax) { + do "generate_emitter_new.pl"; + return; +} + my $comment_string_quoted = quotemeta($comment_string); my $target_c = $target_dir."/gen_".$arch."_emitter.c"; diff --git a/ir/be/scripts/generate_emitter_new.pl b/ir/be/scripts/generate_emitter_new.pl new file mode 100755 index 000000000..0e210aaeb --- /dev/null +++ b/ir/be/scripts/generate_emitter_new.pl @@ -0,0 +1,188 @@ +#!/usr/bin/perl -w + +# This script generates C code which emits assembler code for the +# assembler ir nodes. It takes a "emit" key from the node specification +# and substitutes lines starting with . with a corresponding fprintf(). +# Creation: 2005/11/07 +# $Id$ + +use strict; +use Data::Dumper; + +my $specfile = $ARGV[0]; +my $target_dir = $ARGV[1]; + +our $arch; +our $comment_string; +our $comment_string_end; +our %nodes; +our %emit_templates; +our $spec_version = 1; + +# include spec file + +my $return; + +no strict "subs"; +unless ($return = do $specfile) { + warn "couldn't parse $specfile: $@" if $@; + warn "couldn't do $specfile: $!" unless defined $return; + warn "couldn't run $specfile" unless $return; +} +use strict "subs"; + +my $comment_string_quoted = quotemeta($comment_string); + +my $target_c = $target_dir."/gen_".$arch."_emitter.c"; +my $target_h = $target_dir."/gen_".$arch."_emitter.h"; + +# stacks for output +my @obst_func; # stack for the emit functions +my @obst_register; # stack for emitter register code +my $line; + +sub create_emitter { + my $result = shift; + my $indent = shift; + my $template = shift; + our %emit_templates; + our $arch; + + my @tokens = ($template =~ m/[^\%]+|\%[a-zA-Z_][a-zA-Z0-9_]*|\%./g); + push(@{$result}, "${indent}${arch}_emit_char(env, '\t');\n"); + for (@tokens) { + SWITCH: { + if (/%\./) { last SWITCH; } + if (/%%/) { push(@{$result}, "${indent}${arch}_emit_char(env, '%');\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"); + } + last SWITCH; + } + push(@{$result}, "${indent}${arch}_emit_cstring(env, \"$_\");\n"); + } + } + push(@{$result}, "${indent}${arch}_emit_finish_line(env, node);\n"); +} + + + +foreach my $op (keys(%nodes)) { + my %n = %{ $nodes{"$op"} }; + + # 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)"; + + push(@obst_register, " BE_EMIT($op);\n"); + + if($n{"emit"} eq "") { + push(@obst_func, $line." {\n"); + push(@obst_func, "}\n\n"); + next; + } + + push(@obst_func, $line." {\n"); + my @emit = split(/\n/, $n{"emit"}); + + if($spec_version < 3) { last; } + + foreach my $template (@emit) { + # substitute only lines, starting with a '.' + if ($template =~ /^(\s*)\.\s*(.*)/) { + my $indent = "\t$1"; + create_emitter(\@obst_func, $indent, $2); + } else { + push(@obst_func, "\t$template\n"); + } + } + + push(@obst_func, "}\n\n"); +} + +open(OUT, ">$target_h") || die("Could not open $target_h, reason: $!\n"); + +my $creation_time = localtime(time()); + +my $tmp = uc($arch); + +print OUT<$target_c") || die("Could not open $target_c, reason: $!\n"); + +$creation_time = localtime(time()); + +print OUT< +#endif + +#include + +#include "irnode.h" +#include "irop_t.h" +#include "irprog_t.h" + +#include "gen_${arch}_emitter.h" +#include "${arch}_new_nodes.h" +#include "${arch}_emitter.h" + +EOF + +print OUT @obst_func; + +print OUT<ops.generic = (op_func)emit_$arch\_##a + + /* generated emitter functions */ +EOF + +print OUT @obst_register; + +print OUT<