X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=6aef8b4ce0df09cbbb46e2f69313cfa6d181bc32;hb=ee2ce90606e3b629b45482964a70a71a46aa6966;hp=009d0718a9ad7ad8aded7ddb35fa25e8e8a83bbc;hpb=ef7ac8eec7325a927785c27ab0224ba521b0ad81;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index 009d0718a..6aef8b4ce 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -557,12 +557,15 @@ void ia32_emit_am(const ir_node *node) int offs = get_ia32_am_offs_int(node); ir_node *base = get_irn_n(node, n_ia32_base); int has_base = !is_ia32_NoReg_GP(base); - ir_node *index = get_irn_n(node, n_ia32_index); - int has_index = !is_ia32_NoReg_GP(index); + ir_node *idx = get_irn_n(node, n_ia32_index); + int has_index = !is_ia32_NoReg_GP(idx); /* just to be sure... */ assert(!is_ia32_use_frame(node) || get_ia32_frame_ent(node) != NULL); + if (get_ia32_am_tls_segment(node)) + be_emit_cstring("%gs:"); + /* emit offset */ if (ent != NULL) { const ia32_attr_t *attr = get_ia32_attr_const(node); @@ -672,6 +675,9 @@ static void ia32_emitf(const ir_node *node, const char *fmt, ...) end_of_mods: switch (*fmt++) { + arch_register_t const *reg; + ir_node const *imm; + case '%': be_emit_char('%'); break; @@ -685,17 +691,13 @@ emit_AM: ia32_emit_am(node); break; - case 'R': { - const arch_register_t *reg = va_arg(ap, const arch_register_t*); + case 'R': + reg = va_arg(ap, const arch_register_t*); if (get_ia32_op_type(node) == ia32_AddrModeS) { goto emit_AM; } else { - if (mod & EMIT_ALTERNATE_AM) - be_emit_char('*'); - emit_register(reg, NULL); + goto emit_R; } - break; - } case 'S': if (get_ia32_op_type(node) == ia32_AddrModeS) { @@ -705,40 +707,33 @@ emit_AM: assert(get_ia32_op_type(node) == ia32_Normal); goto emit_S; } - break; default: goto unknown; } break; } - case 'D': { - unsigned pos; - const arch_register_t *reg; - + case 'D': if (*fmt < '0' || '9' <= *fmt) goto unknown; - - pos = *fmt++ - '0'; - reg = get_out_reg(node, pos); - emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL); - break; - } + reg = get_out_reg(node, *fmt++ - '0'); + goto emit_R; case 'I': + imm = node; +emit_I: if (!(mod & EMIT_ALTERNATE_AM)) be_emit_char('$'); - emit_ia32_Immediate_no_prefix(node); + emit_ia32_Immediate_no_prefix(imm); break; case 'L': ia32_emit_cfop_target(node); break; - case 'M': { + case 'M': ia32_emit_mode_suffix_mode(get_ia32_ls_mode(node)); break; - } case 'P': { ia32_condition_code_t cc = va_arg(ap, ia32_condition_code_t); @@ -746,8 +741,11 @@ emit_AM: break; } - case 'R': { - const arch_register_t *reg = va_arg(ap, const arch_register_t*); + case 'R': + reg = va_arg(ap, const arch_register_t*); +emit_R: + if (mod & EMIT_ALTERNATE_AM) + be_emit_char('*'); if (mod & EMIT_HIGH_REG) { emit_8bit_register_high(reg); } else if (mod & EMIT_LOW_REG) { @@ -756,31 +754,22 @@ emit_AM: emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL); } break; - } emit_S: case 'S': { - unsigned pos; - const ir_node *in; + unsigned pos; if (*fmt < '0' || '9' <= *fmt) goto unknown; pos = *fmt++ - '0'; - in = get_irn_n(node, pos); - if (is_ia32_Immediate(in)) { - if (!(mod & EMIT_ALTERNATE_AM)) - be_emit_char('$'); - emit_ia32_Immediate_no_prefix(in); + imm = get_irn_n(node, pos); + if (is_ia32_Immediate(imm)) { + goto emit_I; } else { - const arch_register_t *reg; - - if (mod & EMIT_ALTERNATE_AM) - be_emit_char('*'); reg = get_in_reg(node, pos); - emit_register(reg, mod & EMIT_RESPECT_LS ? get_ia32_ls_mode(node) : NULL); + goto emit_R; } - break; } case 's': { @@ -910,11 +899,11 @@ static ir_node *find_original_value(ir_node *node) return find_original_value(get_irn_n(pred, get_Proj_proj(node) + 1)); } else if (is_ia32_Load(pred)) { return find_original_value(get_irn_n(pred, n_ia32_Load_mem)); + } else if (is_ia32_Store(pred)) { + return find_original_value(get_irn_n(pred, n_ia32_Store_val)); } else { return node; } - } else if (is_ia32_Store(node)) { - return find_original_value(get_irn_n(node, n_ia32_Store_val)); } else if (is_Phi(node)) { int i, arity; arity = get_irn_arity(node); @@ -1131,127 +1120,16 @@ static void emit_ia32_CMovcc(const ir_node *node) ia32_emitf(node, "\tcmov%P %#AR, %#R\n", cc, in_true, out); } - -/* jump table entry (target and corresponding number) */ -typedef struct branch_t { - ir_node *target; - int value; -} branch_t; - -/* jump table for switch generation */ -typedef struct jmp_tbl_t { - ir_node *defProj; /**< default target */ - long min_value; /**< smallest switch case */ - long max_value; /**< largest switch case */ - long num_branches; /**< number of jumps */ - char label[SNPRINTF_BUF_LEN]; /**< label of the jump table */ - branch_t *branches; /**< jump array */ -} jmp_tbl_t; - -/** - * Compare two variables of type branch_t. Used to sort all switch cases - */ -static int ia32_cmp_branch_t(const void *a, const void *b) -{ - branch_t *b1 = (branch_t *)a; - branch_t *b2 = (branch_t *)b; - - if (b1->value <= b2->value) - return -1; - else - return 1; -} - -static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node) -{ - int i; - long default_pn = get_ia32_default_pn(node); - ir_node *proj; - const ir_edge_t *edge; - - /* fill the table structure */ - get_unique_label(tbl->label, SNPRINTF_BUF_LEN, "TBL_"); - tbl->defProj = NULL; - tbl->num_branches = get_irn_n_edges(node) - 1; - tbl->branches = XMALLOCNZ(branch_t, tbl->num_branches); - tbl->min_value = LONG_MAX; - tbl->max_value = LONG_MIN; - - i = 0; - /* go over all proj's and collect them */ - foreach_out_edge(node, edge) { - long pn; - proj = get_edge_src_irn(edge); - assert(is_Proj(proj) && "Only proj allowed at SwitchJmp"); - - pn = get_Proj_proj(proj); - - /* check for default proj */ - if (pn == default_pn) { - assert(tbl->defProj == NULL && "found two default Projs at SwitchJmp"); - tbl->defProj = proj; - } else { - tbl->min_value = pn < tbl->min_value ? pn : tbl->min_value; - tbl->max_value = pn > tbl->max_value ? pn : tbl->max_value; - - /* create branch entry */ - tbl->branches[i].target = proj; - tbl->branches[i].value = pn; - ++i; - } - - } - assert(i == tbl->num_branches); - - /* sort the branches by their number */ - qsort(tbl->branches, tbl->num_branches, sizeof(tbl->branches[0]), ia32_cmp_branch_t); -} - /** - * Emits code for a SwitchJmp (creates a jump table if - * possible otherwise a cmp-jmp cascade). Port from - * cggg ia32 backend + * Emits code for a SwitchJmp */ static void emit_ia32_SwitchJmp(const ir_node *node) { - unsigned long interval; - int last_value, i; - jmp_tbl_t tbl; - - /* fill the table structure */ - generate_jump_table(&tbl, node); - - /* two-complement's magic make this work without overflow */ - interval = tbl.max_value - tbl.min_value; - - /* emit the table */ - ia32_emitf(node, "\tcmpl $%u, %S0\n", interval); - ia32_emitf(tbl.defProj, "\tja %L\n"); + ir_entity *jump_table = get_ia32_am_sc(node); + long default_pn = get_ia32_default_pn(node); - if (tbl.num_branches > 1) { - /* create table */ - ia32_emitf(node, "\tjmp *%s(,%S0,4)\n", tbl.label); - - be_gas_emit_switch_section(GAS_SECTION_RODATA); - ia32_emitf(NULL, "\t.align 4\n"); - ia32_emitf(NULL, "%s:\n", tbl.label); - - last_value = tbl.branches[0].value; - for (i = 0; i != tbl.num_branches; ++i) { - while (last_value != tbl.branches[i].value) { - ia32_emitf(tbl.defProj, ".long %L\n"); - ++last_value; - } - ia32_emitf(tbl.branches[i].target, ".long %L\n"); - ++last_value; - } - be_gas_emit_switch_section(GAS_SECTION_TEXT); - } else { - /* one jump is enough */ - ia32_emitf(tbl.branches[0].target, "\tjmp %L\n"); - } - - free(tbl.branches); + ia32_emitf(node, "\tjmp %*AM\n"); + emit_jump_table(node, default_pn, jump_table, get_cfop_target_block); } /** @@ -1259,11 +1137,6 @@ static void emit_ia32_SwitchJmp(const ir_node *node) */ static void emit_ia32_Jmp(const ir_node *node) { - ir_node *block; - - /* for now, the code works for scheduled and non-schedules blocks */ - block = get_nodes_block(node); - /* we have a block schedule */ if (can_be_fallthrough(node)) { ia32_emitf(node, "\t/* fallthrough to %L */\n"); @@ -1497,8 +1370,8 @@ static void emit_ia32_Conv_FP2FP(const ir_node *node) */ static void emit_ia32_Conv_I2I(const ir_node *node) { - ir_mode *smaller_mode = get_ia32_ls_mode(node); - int signed_mode = mode_is_signed(smaller_mode); + ir_mode *smaller_mode = get_ia32_ls_mode(node); + int signed_mode = mode_is_signed(smaller_mode); const char *sign_suffix; assert(!mode_is_float(smaller_mode)); @@ -1606,14 +1479,6 @@ static void emit_ia32_Const(const ir_node *node) ia32_emitf(node, "\tmovl %I, %D0\n"); } -/** - * Emits code to load the TLS base - */ -static void emit_ia32_LdTls(const ir_node *node) -{ - ia32_emitf(node, "\tmovl %%gs:0, %D0\n"); -} - /* helper function for emit_ia32_Minus64Bit */ static void emit_mov(const ir_node* node, const arch_register_t *src, const arch_register_t *dst) { @@ -1779,7 +1644,6 @@ static void ia32_register_emitters(void) IA32_EMIT(IMul); IA32_EMIT(Jcc); IA32_EMIT(Setcc); - IA32_EMIT(LdTls); IA32_EMIT(Minus64Bit); IA32_EMIT(SwitchJmp); IA32_EMIT(ClimbFrame); @@ -1792,7 +1656,6 @@ static void ia32_register_emitters(void) BE_EMIT(Perm); BE_EMIT(Return); - BE_IGN(Barrier); BE_IGN(Keep); BE_IGN(Start); @@ -1936,10 +1799,10 @@ static int should_align_block(const ir_node *block) */ static void ia32_emit_block_header(ir_node *block) { - ir_graph *irg = current_ir_graph; + ir_graph *irg = current_ir_graph; int need_label = block_needs_label(block); - int i, arity; - ir_exec_freq *exec_freq = be_get_irg_exec_freq(irg); + ir_exec_freq *exec_freq = be_get_irg_exec_freq(irg); + int arity; if (block == get_irg_end_block(irg)) return; @@ -1989,6 +1852,7 @@ static void ia32_emit_block_header(ir_node *block) if (arity <= 0) { be_emit_cstring(" none"); } else { + int i; for (i = 0; i < arity; ++i) { ir_node *predblock = get_Block_cfgpred_block(block, i); be_emit_irprintf(" %d", get_irn_node_nr(predblock)); @@ -2118,14 +1982,14 @@ void ia32_gen_routine(ir_graph *irg) Those are ascending with ascending addresses. */ qsort(exc_list, ARR_LEN(exc_list), sizeof(exc_list[0]), cmp_exc_entry); { - size_t i; + size_t e; - for (i = 0; i < ARR_LEN(exc_list); ++i) { + for (e = 0; e < ARR_LEN(exc_list); ++e) { be_emit_cstring("\t.long "); - ia32_emit_exc_label(exc_list[i].exc_instr); + ia32_emit_exc_label(exc_list[e].exc_instr); be_emit_char('\n'); be_emit_cstring("\t.long "); - be_gas_emit_block_name(exc_list[i].block); + be_gas_emit_block_name(exc_list[e].block); be_emit_char('\n'); } } @@ -2331,8 +2195,8 @@ static void bemit_mod_am(unsigned reg, const ir_node *node) int offs = get_ia32_am_offs_int(node); ir_node *base = get_irn_n(node, n_ia32_base); int has_base = !is_ia32_NoReg_GP(base); - ir_node *index = get_irn_n(node, n_ia32_index); - int has_index = !is_ia32_NoReg_GP(index); + ir_node *idx = get_irn_n(node, n_ia32_index); + int has_index = !is_ia32_NoReg_GP(idx); unsigned modrm = 0; unsigned sib = 0; unsigned emitoffs = 0; @@ -2367,7 +2231,7 @@ static void bemit_mod_am(unsigned reg, const ir_node *node) /* Determine if we need a SIB byte. */ if (has_index) { - const arch_register_t *reg_index = arch_get_irn_register(index); + const arch_register_t *reg_index = arch_get_irn_register(idx); int scale = get_ia32_am_scale(node); assert(scale < 4); /* R/M set to ESP means SIB in 32bit mode. */ @@ -3190,8 +3054,8 @@ static void bemit_load(const ir_node *node) if (out->index == REG_GP_EAX) { ir_node *base = get_irn_n(node, n_ia32_base); int has_base = !is_ia32_NoReg_GP(base); - ir_node *index = get_irn_n(node, n_ia32_index); - int has_index = !is_ia32_NoReg_GP(index); + ir_node *idx = get_irn_n(node, n_ia32_index); + int has_index = !is_ia32_NoReg_GP(idx); if (!has_base && !has_index) { ir_entity *ent = get_ia32_am_sc(node); int offs = get_ia32_am_offs_int(node); @@ -3235,8 +3099,8 @@ static void bemit_store(const ir_node *node) if (in->index == REG_GP_EAX) { ir_node *base = get_irn_n(node, n_ia32_base); int has_base = !is_ia32_NoReg_GP(base); - ir_node *index = get_irn_n(node, n_ia32_index); - int has_index = !is_ia32_NoReg_GP(index); + ir_node *idx = get_irn_n(node, n_ia32_index); + int has_index = !is_ia32_NoReg_GP(idx); if (!has_base && !has_index) { ir_entity *ent = get_ia32_am_sc(node); int offs = get_ia32_am_offs_int(node); @@ -3377,7 +3241,6 @@ static void bemit_ia32_jcc(const ir_node *node) const ir_node *proj_false; const ir_node *dest_true; const ir_node *dest_false; - const ir_node *block; cc = determine_final_cc(node, 0, cc); @@ -3388,8 +3251,6 @@ static void bemit_ia32_jcc(const ir_node *node) proj_false = get_proj(node, pn_ia32_Jcc_false); assert(proj_false && "Jcc without false Proj"); - block = get_nodes_block(node); - if (can_be_fallthrough(proj_true)) { /* exchange both proj's so the second one can be omitted */ const ir_node *t = proj_true; @@ -3430,63 +3291,13 @@ static void bemit_ia32_jcc(const ir_node *node) static void bemit_switchjmp(const ir_node *node) { - unsigned long interval; - int last_value; - int i; - jmp_tbl_t tbl; - const arch_register_t *in; - - /* fill the table structure */ - generate_jump_table(&tbl, node); - - /* two-complement's magic make this work without overflow */ - interval = tbl.max_value - tbl.min_value; + ir_entity *jump_table = get_ia32_am_sc(node); + long default_pn = get_ia32_default_pn(node); - in = get_in_reg(node, 0); - /* emit the table */ - if (get_signed_imm_size(interval) == 1) { - bemit8(0x83); // cmpl $imm8, %in - bemit_modru(in, 7); - bemit8(interval); - } else { - bemit8(0x81); // cmpl $imm32, %in - bemit_modru(in, 7); - bemit32(interval); - } - bemit8(0x0F); // ja tbl.defProj - bemit8(0x87); - ia32_emitf(tbl.defProj, ".long %L - . - 4\n"); - - if (tbl.num_branches > 1) { - /* create table */ - bemit8(0xFF); // jmp *tbl.label(,%in,4) - bemit8(MOD_IND | ENC_REG(4) | ENC_RM(0x04)); - bemit8(ENC_SIB(2, reg_gp_map[in->index], 0x05)); - be_emit_irprintf("\t.long %s\n", tbl.label); - - be_gas_emit_switch_section(GAS_SECTION_RODATA); - be_emit_cstring(".align 4\n"); - be_emit_irprintf("%s:\n", tbl.label); - - last_value = tbl.branches[0].value; - for (i = 0; i != tbl.num_branches; ++i) { - while (last_value != tbl.branches[i].value) { - ia32_emitf(tbl.defProj, ".long %L\n"); - ++last_value; - } - ia32_emitf(tbl.branches[i].target, ".long %L\n"); - ++last_value; - } - be_gas_emit_switch_section(GAS_SECTION_TEXT); - } else { - /* one jump is enough */ - panic("switch only has one case"); - //ia32_emitf(tbl.branches[0].target, "\tjmp %L\n"); - } - - be_emit_write_line(); + bemit8(0xFF); // jmp *tbl.label(,%in,4) + bemit_mod_am(0x05, node); - free(tbl.branches); + emit_jump_table(node, default_pn, jump_table, get_cfop_target_block); } /** @@ -4050,7 +3861,6 @@ static void ia32_register_binary_emitters(void) /* ignore the following nodes */ register_emitter(op_ia32_ProduceVal, emit_Nothing); - register_emitter(op_be_Barrier, emit_Nothing); register_emitter(op_be_Keep, emit_Nothing); register_emitter(op_be_Start, emit_Nothing); register_emitter(op_Phi, emit_Nothing);