X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_emitter.c;h=56a93111237192f41325ed6ac87a980978810d53;hb=c99aaa20c33a6f767ab26489f4bb8e2b2711a749;hp=af53e41e30957d2498f41629c8be71d7f89d9c60;hpb=b644c35fa89324522c70d601a2582a22d66098fb;p=libfirm diff --git a/ir/be/ia32/ia32_emitter.c b/ir/be/ia32/ia32_emitter.c index af53e41e3..56a931112 100644 --- a/ir/be/ia32/ia32_emitter.c +++ b/ir/be/ia32/ia32_emitter.c @@ -392,47 +392,265 @@ void ia32_emit_source_register_or_immediate(const ir_node *node, int pos) } /** - * Emits registers and/or address mode of a binary operation. + * Returns the target block for a control flow node. */ -void ia32_emit_binop(const ir_node *node) +static ir_node *get_cfop_target_block(const ir_node *irn) { - const ir_node *right_op = get_irn_n(node, n_ia32_binary_right); - const ir_mode *mode = get_ia32_ls_mode(node); - const arch_register_t *reg_left; + assert(get_irn_mode(irn) == mode_X); + return get_irn_link(irn); +} - switch(get_ia32_op_type(node)) { - case ia32_Normal: - reg_left = get_in_reg(node, n_ia32_binary_left); - if (is_ia32_Immediate(right_op)) { - emit_ia32_Immediate(right_op); - be_emit_cstring(", "); - emit_register(reg_left, mode); +/** + * Emits a block label for the given block. + */ +static void ia32_emit_block_name(const ir_node *block) +{ + if (has_Block_label(block)) { + be_emit_string(be_gas_block_label_prefix()); + be_emit_irprintf("%lu", get_Block_label(block)); + } else { + be_emit_cstring(BLOCK_PREFIX); + be_emit_irprintf("%ld", get_irn_node_nr(block)); + } +} + +/** + * Emits the target label for a control flow node. + */ +static void ia32_emit_cfop_target(const ir_node *node) +{ + ir_node *block = get_cfop_target_block(node); + ia32_emit_block_name(block); +} + +/* + * coding of conditions + */ +struct cmp2conditon_t { + const char *name; + int num; +}; + +/* + * positive conditions for signed compares + */ +static const struct cmp2conditon_t cmp2condition_s[] = { + { NULL, pn_Cmp_False }, /* always false */ + { "e", pn_Cmp_Eq }, /* == */ + { "l", pn_Cmp_Lt }, /* < */ + { "le", pn_Cmp_Le }, /* <= */ + { "g", pn_Cmp_Gt }, /* > */ + { "ge", pn_Cmp_Ge }, /* >= */ + { "ne", pn_Cmp_Lg }, /* != */ + { NULL, pn_Cmp_Leg}, /* always true */ +}; + +/* + * positive conditions for unsigned compares + */ +static const struct cmp2conditon_t cmp2condition_u[] = { + { NULL, pn_Cmp_False }, /* always false */ + { "e", pn_Cmp_Eq }, /* == */ + { "b", pn_Cmp_Lt }, /* < */ + { "be", pn_Cmp_Le }, /* <= */ + { "a", pn_Cmp_Gt }, /* > */ + { "ae", pn_Cmp_Ge }, /* >= */ + { "ne", pn_Cmp_Lg }, /* != */ + { NULL, pn_Cmp_Leg }, /* always true */ +}; + +static void ia32_emit_cmp_suffix(int pnc) +{ + const char *str; + + if ((pnc & ia32_pn_Cmp_float) || (pnc & ia32_pn_Cmp_unsigned)) { + pnc = pnc & 7; + assert(cmp2condition_u[pnc].num == pnc); + str = cmp2condition_u[pnc].name; + } else { + pnc = pnc & 7; + assert(cmp2condition_s[pnc].num == pnc); + str = cmp2condition_s[pnc].name; + } + + be_emit_string(str); +} + +/** + * fmt parameter output + * ---- ---------------------- --------------------------------------------- + * %% % + * %AM address mode of the node + * %AR const arch_register_t* address mode of the node or register + * %ASx address mode of the node or source register x + * %Dx destination register x + * %I immediate of the node + * %L control flow target of the node + * %M mode suffix of the node + * %P int condition code + * %R const arch_register_t* register + * %Sx source register x + * %s const char* string + * %u unsigned int unsigned int + * + * x starts at 0 + * # modifier for %ASx, %D and %S uses ls mode of node to alter register width + */ +static void ia32_emitf(const ir_node *node, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + for (;;) { + const char *start = fmt; + const ir_mode *mode = NULL; + + while (*fmt != '%' && *fmt != '\n' && *fmt != '\0') + ++fmt; + if (fmt != start) { + be_emit_string_len(start, fmt - start); + } + + if (*fmt == '\n') { + be_emit_finish_line_gas(node); + ++fmt; + if (*fmt == '\0') + break; + continue; + } + + if (*fmt == '\0') break; - } else { - const arch_register_t *reg_right - = get_in_reg(node, n_ia32_binary_right); - emit_register(reg_right, mode); - be_emit_cstring(", "); - emit_register(reg_left, mode); + + ++fmt; + if (*fmt == '#') { + mode = get_ia32_ls_mode(node); + ++fmt; } - break; - case ia32_AddrModeS: - if (is_ia32_Immediate(right_op)) { - emit_ia32_Immediate(right_op); - be_emit_cstring(", "); - ia32_emit_am(node); - } else { - reg_left = get_in_reg(node, n_ia32_binary_left); - ia32_emit_am(node); - be_emit_cstring(", "); - emit_register(reg_left, mode); + + switch (*fmt++) { + case '%': + be_emit_char('%'); + break; + + case 'A': { + switch (*fmt++) { + case 'M': + ia32_emit_am(node); + break; + + case 'R': { + const arch_register_t *reg = va_arg(ap, const arch_register_t*); + if (get_ia32_op_type(node) == ia32_AddrModeS) { + ia32_emit_am(node); + } else { + emit_register(reg, NULL); + } + break; + } + + case 'S': + if (get_ia32_op_type(node) == ia32_AddrModeS) { + ia32_emit_am(node); + ++fmt; + } else { + 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; + + if (*fmt < '0' || '9' <= *fmt) + goto unknown; + + pos = *fmt++ - '0'; + reg = get_out_reg(node, pos); + emit_register(reg, mode); + break; + } + + case 'I': + emit_ia32_Immediate(node); + break; + + case 'L': + ia32_emit_cfop_target(node); + break; + + case 'M': { + ia32_emit_mode_suffix_mode(get_ia32_ls_mode(node)); + break; + } + + case 'P': { + int pnc = va_arg(ap, int); + ia32_emit_cmp_suffix(pnc); + break; + } + + case 'R': { + const arch_register_t *reg = va_arg(ap, const arch_register_t*); + emit_register(reg, NULL); + break; + } + +emit_S: + case 'S': { + unsigned pos; + const ir_node *in; + + if (*fmt < '0' || '9' <= *fmt) + goto unknown; + + pos = *fmt++ - '0'; + in = get_irn_n(node, pos); + if (is_ia32_Immediate(in)) { + emit_ia32_Immediate(in); + } else { + const arch_register_t *reg = get_in_reg(node, pos); + emit_register(reg, mode); + } + break; + } + + case 's': { + const char *str = va_arg(ap, const char*); + be_emit_string(str); + break; + } + + case 'u': { + unsigned num = va_arg(ap, unsigned); + be_emit_irprintf("%u", num); + break; + } + + default: +unknown: + panic("unknown conversion"); } - break; - case ia32_AddrModeD: - panic("DestMode can't be output by %%binop anymore"); - break; - default: - assert(0 && "unsupported op type"); + } + + va_end(ap); +} + +/** + * Emits registers and/or address mode of a binary operation. + */ +void ia32_emit_binop(const ir_node *node) +{ + if (is_ia32_Immediate(get_irn_n(node, n_ia32_binary_right))) { + ia32_emitf(node, "%#S4, %#AS3"); + } else { + ia32_emitf(node, "%#AS4, %#S3"); } } @@ -475,24 +693,9 @@ void ia32_emit_x87_binop(const ir_node *node) */ void ia32_emit_unop(const ir_node *node, int pos) { - const ir_node *op; - - switch(get_ia32_op_type(node)) { - case ia32_Normal: - op = get_irn_n(node, pos); - if (is_ia32_Immediate(op)) { - emit_ia32_Immediate(op); - } else { - ia32_emit_source_register(node, pos); - } - break; - case ia32_AddrModeS: - case ia32_AddrModeD: - ia32_emit_am(node); - break; - default: - assert(0 && "unsupported op type"); - } + char fmt[] = "%ASx"; + fmt[3] = '0' + pos; + ia32_emitf(node, fmt); } static void ia32_emit_entity(ir_entity *entity, int no_pic_adjust) @@ -579,70 +782,15 @@ static void emit_ia32_IMul(const ir_node *node) ir_node *left = get_irn_n(node, n_ia32_IMul_left); const arch_register_t *out_reg = get_out_reg(node, pn_ia32_IMul_res); - be_emit_cstring("\timul"); - ia32_emit_mode_suffix(node); - be_emit_char(' '); - - ia32_emit_binop(node); - /* do we need the 3-address form? */ if (is_ia32_NoReg_GP(left) || get_in_reg(node, n_ia32_IMul_left) != out_reg) { - be_emit_cstring(", "); - emit_register(out_reg, get_ia32_ls_mode(node)); + ia32_emitf(node, "\timul%M %#S4, %#AS3, %#D0\n"); + } else { + ia32_emitf(node, "\timul%M %#AS4, %#S3\n"); } - be_emit_finish_line_gas(node); } -/************************************************* - * _ _ _ - * (_) | | | - * ___ _ __ ___ _| |_ ___ ___ _ __ __| | - * / _ \ '_ ` _ \| | __| / __/ _ \| '_ \ / _` | - * | __/ | | | | | | |_ | (_| (_) | | | | (_| | - * \___|_| |_| |_|_|\__| \___\___/|_| |_|\__,_| - * - *************************************************/ - -#undef IA32_DO_EMIT -#define IA32_DO_EMIT(irn) ia32_fprintf_format(F, irn, cmd_buf, cmnt_buf) - -/* - * coding of conditions - */ -struct cmp2conditon_t { - const char *name; - int num; -}; - -/* - * positive conditions for signed compares - */ -static const struct cmp2conditon_t cmp2condition_s[] = { - { NULL, pn_Cmp_False }, /* always false */ - { "e", pn_Cmp_Eq }, /* == */ - { "l", pn_Cmp_Lt }, /* < */ - { "le", pn_Cmp_Le }, /* <= */ - { "g", pn_Cmp_Gt }, /* > */ - { "ge", pn_Cmp_Ge }, /* >= */ - { "ne", pn_Cmp_Lg }, /* != */ - { NULL, pn_Cmp_Leg}, /* always true */ -}; - -/* - * positive conditions for unsigned compares - */ -static const struct cmp2conditon_t cmp2condition_u[] = { - { NULL, pn_Cmp_False }, /* always false */ - { "e", pn_Cmp_Eq }, /* == */ - { "b", pn_Cmp_Lt }, /* < */ - { "be", pn_Cmp_Le }, /* <= */ - { "a", pn_Cmp_Gt }, /* > */ - { "ae", pn_Cmp_Ge }, /* >= */ - { "ne", pn_Cmp_Lg }, /* != */ - { NULL, pn_Cmp_Leg }, /* always true */ -}; - /** * walks up a tree of copies/perms/spills/reloads to find the original value * that is moved around @@ -727,23 +875,6 @@ static int determine_final_pnc(const ir_node *node, int flags_pos, return pnc; } -static void ia32_emit_cmp_suffix(int pnc) -{ - const char *str; - - if ((pnc & ia32_pn_Cmp_float) || (pnc & ia32_pn_Cmp_unsigned)) { - pnc = pnc & 7; - assert(cmp2condition_u[pnc].num == pnc); - str = cmp2condition_u[pnc].name; - } else { - pnc = pnc & 7; - assert(cmp2condition_s[pnc].num == pnc); - str = cmp2condition_s[pnc].name; - } - - be_emit_string(str); -} - void ia32_emit_cmp_suffix_node(const ir_node *node, int flags_pos) { @@ -763,29 +894,6 @@ void ia32_emit_cmp_suffix_node(const ir_node *node, ia32_emit_cmp_suffix(pnc); } -/** - * Returns the target block for a control flow node. - */ -static ir_node *get_cfop_target_block(const ir_node *irn) -{ - assert(get_irn_mode(irn) == mode_X); - return get_irn_link(irn); -} - -/** - * Emits a block label for the given block. - */ -static void ia32_emit_block_name(const ir_node *block) -{ - if (has_Block_label(block)) { - be_emit_string(be_gas_block_label_prefix()); - be_emit_irprintf("%lu", get_Block_label(block)); - } else { - be_emit_cstring(BLOCK_PREFIX); - be_emit_irprintf("%ld", get_irn_node_nr(block)); - } -} - /** * Emits an exception label for a given node. */ @@ -795,16 +903,6 @@ static void ia32_emit_exc_label(const ir_node *node) be_emit_irprintf("%lu", get_ia32_exc_label_id(node)); } -/** - * Emits the target label for a control flow node. - */ -static void ia32_emit_cfop_target(const ir_node *node) -{ - ir_node *block = get_cfop_target_block(node); - - ia32_emit_block_name(block); -} - /** * Returns the Proj with projection number proj and NOT mode_M */ @@ -875,16 +973,12 @@ static void emit_ia32_Jcc(const ir_node *node) * which indicates that the result is unordered */ switch (pnc & 15) { case pn_Cmp_Uo: { - be_emit_cstring("\tjp "); - ia32_emit_cfop_target(proj_true); - be_emit_finish_line_gas(proj_true); + ia32_emitf(proj_true, "\tjp %L\n"); break; } case pn_Cmp_Leg: - be_emit_cstring("\tjnp "); - ia32_emit_cfop_target(proj_true); - be_emit_finish_line_gas(proj_true); + ia32_emitf(proj_true, "\tjnp %L\n"); break; case pn_Cmp_Eq: @@ -894,20 +988,16 @@ static void emit_ia32_Jcc(const ir_node *node) * as the falseblock might have no label emitted then */ if (can_be_fallthrough(proj_false)) { need_parity_label = 1; - be_emit_cstring("\tjp 1f"); + ia32_emitf(proj_false, "\tjp 1f\n"); } else { - be_emit_cstring("\tjp "); - ia32_emit_cfop_target(proj_false); + ia32_emitf(proj_false, "\tjp %L\n"); } - be_emit_finish_line_gas(proj_false); goto emit_jcc; case pn_Cmp_Ug: case pn_Cmp_Uge: case pn_Cmp_Ne: - be_emit_cstring("\tjp "); - ia32_emit_cfop_target(proj_true); - be_emit_finish_line_gas(proj_true); + ia32_emitf(proj_true, "\tjp %L\n"); goto emit_jcc; default: @@ -915,28 +1005,18 @@ static void emit_ia32_Jcc(const ir_node *node) } } else { emit_jcc: - be_emit_cstring("\tj"); - ia32_emit_cmp_suffix(pnc); - be_emit_char(' '); - ia32_emit_cfop_target(proj_true); - be_emit_finish_line_gas(proj_true); + ia32_emitf(proj_true, "\tj%P %L\n", pnc); } if (need_parity_label) { - be_emit_cstring("1:"); - be_emit_write_line(); + ia32_emitf(NULL, "1:\n"); } /* the second Proj might be a fallthrough */ if (can_be_fallthrough(proj_false)) { - be_emit_cstring("\t/* fallthrough to "); - ia32_emit_cfop_target(proj_false); - be_emit_cstring(" */"); - be_emit_finish_line_gas(proj_false); + ia32_emitf(proj_false, "\t/* fallthrough to %L */\n"); } else { - be_emit_cstring("\tjmp "); - ia32_emit_cfop_target(proj_false); - be_emit_finish_line_gas(proj_false); + ia32_emitf(proj_false, "\tjmp %L\n"); } } @@ -971,11 +1051,7 @@ static void emit_ia32_CMov(const ir_node *node) in_false = tmp; } else { /* we need a mov */ - be_emit_cstring("\tmovl "); - emit_register(in_false, NULL); - be_emit_cstring(", "); - emit_register(out, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tmovl %R, %R\n", in_false, out); } if (ins_permuted) { @@ -988,17 +1064,7 @@ static void emit_ia32_CMov(const ir_node *node) /* TODO: handling of Nans isn't correct yet */ - be_emit_cstring("\tcmov"); - ia32_emit_cmp_suffix(pnc); - be_emit_char(' '); - if (get_ia32_op_type(node) == ia32_AddrModeS) { - ia32_emit_am(node); - } else { - emit_register(in_true, get_ia32_ls_mode(node)); - } - be_emit_cstring(", "); - emit_register(out, get_ia32_ls_mode(node)); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tcmov%P %AR, %#R\n", pnc, in_true, out); } /********************************************************* @@ -1099,53 +1165,30 @@ static void emit_ia32_SwitchJmp(const ir_node *node) interval = tbl.max_value - tbl.min_value; /* emit the table */ - be_emit_cstring("\tcmpl $"); - be_emit_irprintf("%u, ", interval); - ia32_emit_source_register(node, 0); - be_emit_finish_line_gas(node); - - be_emit_cstring("\tja "); - ia32_emit_cfop_target(tbl.defProj); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tcmpl $%u, %S0\n", interval); + ia32_emitf(tbl.defProj, "\tja %L\n"); if (tbl.num_branches > 1) { /* create table */ - be_emit_cstring("\tjmp *"); - be_emit_string(tbl.label); - be_emit_cstring("(,"); - ia32_emit_source_register(node, 0); - be_emit_cstring(",4)"); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tjmp *%s(,%S0,4)\n", tbl.label); be_gas_emit_switch_section(GAS_SECTION_RODATA); - be_emit_cstring("\t.align 4\n"); - be_emit_write_line(); - - be_emit_string(tbl.label); - be_emit_cstring(":\n"); - be_emit_write_line(); - - be_emit_cstring(".long "); - ia32_emit_cfop_target(tbl.branches[0].target); - be_emit_finish_line_gas(NULL); + ia32_emitf(NULL, "\t.align 4\n"); + ia32_emitf(NULL, "%s:\n", tbl.label); last_value = tbl.branches[0].value; - for (i = 1; i < tbl.num_branches; ++i) { - while (++last_value < tbl.branches[i].value) { - be_emit_cstring(".long "); - ia32_emit_cfop_target(tbl.defProj); - be_emit_finish_line_gas(NULL); + for (i = 0; i != tbl.num_branches; ++i) { + while (last_value != tbl.branches[i].value) { + ia32_emitf(tbl.defProj, ".long %L\n"); + ++last_value; } - be_emit_cstring(".long "); - ia32_emit_cfop_target(tbl.branches[i].target); - be_emit_finish_line_gas(NULL); + ia32_emitf(tbl.branches[i].target, ".long %L\n"); + ++last_value; } be_gas_emit_switch_section(GAS_SECTION_TEXT); } else { /* one jump is enough */ - be_emit_cstring("\tjmp "); - ia32_emit_cfop_target(tbl.branches[0].target); - be_emit_finish_line_gas(node); + ia32_emitf(tbl.branches[0].target, "\tjmp %L\n"); } if (tbl.label) @@ -1166,14 +1209,10 @@ static void emit_Jmp(const ir_node *node) /* we have a block schedule */ if (can_be_fallthrough(node)) { - be_emit_cstring("\t/* fallthrough to "); - ia32_emit_cfop_target(node); - be_emit_cstring(" */"); + ia32_emitf(node, "\t/* fallthrough to %L */\n"); } else { - be_emit_cstring("\tjmp "); - ia32_emit_cfop_target(node); + ia32_emitf(node, "\tjmp %L\n"); } - be_emit_finish_line_gas(node); } static void emit_ia32_Immediate(const ir_node *node) @@ -1333,8 +1372,7 @@ static void emit_ia32_Asm(const ir_node *node) ident *asm_text = attr->asm_text; const char *s = get_id_str(asm_text); - be_emit_cstring("#APP\t"); - be_emit_finish_line_gas(node); + ia32_emitf(node, "#APP\t\n"); if (s[0] != '\t') be_emit_char('\t'); @@ -1347,11 +1385,7 @@ static void emit_ia32_Asm(const ir_node *node) } } - be_emit_char('\n'); - be_emit_write_line(); - - be_emit_cstring("#NO_APP\n"); - be_emit_write_line(); + ia32_emitf(NULL, "\n#NO_APP\n"); } /********************************** @@ -1370,17 +1404,10 @@ static void emit_ia32_Asm(const ir_node *node) */ static void emit_CopyB_prolog(unsigned size) { - be_emit_cstring("\tcld"); - be_emit_finish_line_gas(NULL); - - if (size & 1) { - be_emit_cstring("\tmovsb"); - be_emit_finish_line_gas(NULL); - } - if (size & 2) { - be_emit_cstring("\tmovsw"); - be_emit_finish_line_gas(NULL); - } + if (size & 1) + ia32_emitf(NULL, "\tmovsb\n"); + if (size & 2) + ia32_emitf(NULL, "\tmovsw\n"); } /** @@ -1391,9 +1418,7 @@ static void emit_ia32_CopyB(const ir_node *node) unsigned size = get_ia32_copyb_size(node); emit_CopyB_prolog(size); - - be_emit_cstring("\trep movsd"); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\trep movsd\n"); } /** @@ -1407,8 +1432,7 @@ static void emit_ia32_CopyB_i(const ir_node *node) size >>= 2; while (size--) { - be_emit_cstring("\tmovsd"); - be_emit_finish_line_gas(NULL); + ia32_emitf(NULL, "\tmovsd\n"); } } @@ -1431,44 +1455,30 @@ static void emit_ia32_Conv_with_FP(const ir_node *node) { ir_mode *ls_mode = get_ia32_ls_mode(node); int ls_bits = get_mode_size_bits(ls_mode); - - be_emit_cstring("\tcvt"); + const char *conv; if (is_ia32_Conv_I2FP(node)) { if (ls_bits == 32) { - be_emit_cstring("si2ss"); + conv = "si2ss"; } else { - be_emit_cstring("si2sd"); + conv = "si2sd"; } } else if (is_ia32_Conv_FP2I(node)) { if (ls_bits == 32) { - be_emit_cstring("ss2si"); + conv = "ss2si"; } else { - be_emit_cstring("sd2si"); + conv = "sd2si"; } } else { assert(is_ia32_Conv_FP2FP(node)); if (ls_bits == 32) { - be_emit_cstring("sd2ss"); + conv = "sd2ss"; } else { - be_emit_cstring("ss2sd"); + conv = "ss2sd"; } } - be_emit_char(' '); - switch(get_ia32_op_type(node)) { - case ia32_Normal: - ia32_emit_source_register(node, n_ia32_unary_op); - break; - case ia32_AddrModeS: - ia32_emit_am(node); - break; - default: - assert(0 && "unsupported op type for Conv"); - } - be_emit_cstring(", "); - ia32_emit_dest_register(node, 0); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tcvt%s %AS3, %D0\n", conv); } static void emit_ia32_Conv_I2FP(const ir_node *node) @@ -1491,56 +1501,24 @@ static void emit_ia32_Conv_FP2FP(const ir_node *node) */ static void emit_ia32_Conv_I2I(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; + ir_mode *smaller_mode = get_ia32_ls_mode(node); + int smaller_bits = get_mode_size_bits(smaller_mode); + int signed_mode = mode_is_signed(smaller_mode); assert(!mode_is_float(smaller_mode)); assert(smaller_bits == 8 || smaller_bits == 16); - signed_mode = mode_is_signed(smaller_mode); - sign_suffix = signed_mode ? "s" : "z"; - - out_reg = get_out_reg(node, 0); - - switch(get_ia32_op_type(node)) { - case ia32_Normal: - in_reg = get_in_reg(node, n_ia32_unary_op); - - if (in_reg == &ia32_gp_regs[REG_EAX] && - out_reg == &ia32_gp_regs[REG_EAX] && - signed_mode && - smaller_bits == 16) - { - /* argument and result are both in EAX and */ - /* signedness is ok: -> use the smaller cwtl opcode */ - be_emit_cstring("\tcwtl"); - } else { - be_emit_cstring("\tmov"); - be_emit_string(sign_suffix); - ia32_emit_mode_suffix_mode(smaller_mode); - be_emit_cstring("l "); - emit_register(in_reg, smaller_mode); - be_emit_cstring(", "); - emit_register(out_reg, NULL); - } - break; - case ia32_AddrModeS: { - be_emit_cstring("\tmov"); - be_emit_string(sign_suffix); - ia32_emit_mode_suffix_mode(smaller_mode); - be_emit_cstring("l "); - ia32_emit_am(node); - be_emit_cstring(", "); - emit_register(out_reg, NULL); - break; - } - default: - panic("unsupported op type for Conv"); + if (signed_mode && + smaller_bits == 16 && + &ia32_gp_regs[REG_EAX] == get_out_reg(node, 0) && + &ia32_gp_regs[REG_EAX] == arch_get_irn_register(arch_env, get_irn_n(node, n_ia32_unary_op))) { + /* argument and result are both in EAX and signedness is ok: use the + * smaller cwtl opcode */ + ia32_emitf(node, "\tcwtl\n"); + } else { + const char *sign_suffix = signed_mode ? "s" : "z"; + ia32_emitf(node, "\tmov%s%Ml %#AS3, %D0\n", sign_suffix); } - be_emit_finish_line_gas(node); } @@ -1577,22 +1555,16 @@ static void emit_be_Call(const ir_node *node) */ static void emit_be_IncSP(const ir_node *node) { - int offs = be_get_IncSP_offset(node); - const arch_register_t *reg = arch_get_irn_register(arch_env, node); + int offs = be_get_IncSP_offset(node); if (offs == 0) return; if (offs > 0) { - be_emit_cstring("\tsubl $"); - be_emit_irprintf("%u, ", offs); - emit_register(reg, NULL); + ia32_emitf(node, "\tsubl $%u, %D0\n", offs); } else { - be_emit_cstring("\taddl $"); - be_emit_irprintf("%u, ", -offs); - emit_register(reg, NULL); + ia32_emitf(node, "\taddl $%u, %D0\n", -offs); } - be_emit_finish_line_gas(node); } /** @@ -1602,7 +1574,6 @@ static void Copy_emitter(const ir_node *node, const ir_node *op) { const arch_register_t *in = arch_get_irn_register(arch_env, op); const arch_register_t *out = arch_get_irn_register(arch_env, node); - ir_mode *mode; if (in == out) { return; @@ -1613,19 +1584,11 @@ static void Copy_emitter(const ir_node *node, const ir_node *op) if (arch_register_get_class(in) == &ia32_reg_classes[CLASS_ia32_vfp]) return; - mode = get_irn_mode(node); - if (mode == mode_E) { - be_emit_cstring("\tmovsd "); - emit_register(in, NULL); - be_emit_cstring(", "); - emit_register(out, NULL); + if (get_irn_mode(node) == mode_E) { + ia32_emitf(node, "\tmovsd %R, %R\n", in, out); } else { - be_emit_cstring("\tmovl "); - emit_register(in, NULL); - be_emit_cstring(", "); - emit_register(out, NULL); + ia32_emitf(node, "\tmovl %R, %R\n", in, out); } - be_emit_finish_line_gas(node); } static void emit_be_Copy(const ir_node *node) @@ -1655,29 +1618,11 @@ static void emit_be_Perm(const ir_node *node) assert(cls0 == cls1 && "Register class mismatch at Perm"); if (cls0 == &ia32_reg_classes[CLASS_ia32_gp]) { - be_emit_cstring("\txchg "); - emit_register(in1, NULL); - be_emit_cstring(", "); - emit_register(in0, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\txchg %R, %R\n", in1, in0); } else if (cls0 == &ia32_reg_classes[CLASS_ia32_xmm]) { - be_emit_cstring("\txorpd "); - emit_register(in1, NULL); - be_emit_cstring(", "); - emit_register(in0, NULL); - be_emit_finish_line_gas(NULL); - - be_emit_cstring("\txorpd "); - emit_register(in0, NULL); - be_emit_cstring(", "); - emit_register(in1, NULL); - be_emit_finish_line_gas(NULL); - - be_emit_cstring("\txorpd "); - emit_register(in1, NULL); - be_emit_cstring(", "); - emit_register(in0, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(NULL, "\txorpd %R, %R\n", in1, in0); + ia32_emitf(NULL, "\txorpd %R, %R\n", in0, in1); + ia32_emitf(node, "\txorpd %R, %R\n", in1, in0); } else if (cls0 == &ia32_reg_classes[CLASS_ia32_vfp]) { /* is a NOP */ } else if (cls0 == &ia32_reg_classes[CLASS_ia32_st]) { @@ -1692,12 +1637,7 @@ static void emit_be_Perm(const ir_node *node) */ static void emit_ia32_Const(const ir_node *node) { - be_emit_cstring("\tmovl "); - emit_ia32_Immediate(node); - be_emit_cstring(", "); - ia32_emit_dest_register(node, 0); - - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tmovl %I, %D0\n"); } /** @@ -1705,65 +1645,43 @@ static void emit_ia32_Const(const ir_node *node) */ static void emit_ia32_LdTls(const ir_node *node) { - be_emit_cstring("\tmovl %gs:0, "); - ia32_emit_dest_register(node, 0); - be_emit_finish_line_gas(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) { - be_emit_cstring("\tmovl "); - emit_register(src, NULL); - be_emit_cstring(", "); - emit_register(dst, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tmovl %R, %R\n", src, dst); } /* helper function for emit_ia32_Minus64Bit */ static void emit_neg(const ir_node* node, const arch_register_t *reg) { - be_emit_cstring("\tnegl "); - emit_register(reg, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tnegl %R\n", reg); } /* helper function for emit_ia32_Minus64Bit */ static void emit_sbb0(const ir_node* node, const arch_register_t *reg) { - be_emit_cstring("\tsbbl $0, "); - emit_register(reg, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tsbbl $0, %R\n", reg); } /* helper function for emit_ia32_Minus64Bit */ static void emit_sbb(const ir_node* node, const arch_register_t *src, const arch_register_t *dst) { - be_emit_cstring("\tsbbl "); - emit_register(src, NULL); - be_emit_cstring(", "); - emit_register(dst, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\tsbbl %R, %R\n", src, dst); } /* helper function for emit_ia32_Minus64Bit */ static void emit_xchg(const ir_node* node, const arch_register_t *src, const arch_register_t *dst) { - be_emit_cstring("\txchgl "); - emit_register(src, NULL); - be_emit_cstring(", "); - emit_register(dst, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\txchgl %R, %R\n", src, dst); } /* helper function for emit_ia32_Minus64Bit */ static void emit_zero(const ir_node* node, const arch_register_t *reg) { - be_emit_cstring("\txorl "); - emit_register(reg, NULL); - be_emit_cstring(", "); - emit_register(reg, NULL); - be_emit_finish_line_gas(node); + ia32_emitf(node, "\txorl %R, %R\n", reg, reg); } static void emit_ia32_Minus64Bit(const ir_node *node) @@ -1822,30 +1740,20 @@ zero_neg: static void emit_ia32_GetEIP(const ir_node *node) { - be_emit_cstring("\tcall "); - be_emit_string(pic_base_label); - be_emit_finish_line_gas(node); - - be_emit_string(pic_base_label); - be_emit_cstring(":\n"); - be_emit_write_line(); - - be_emit_cstring("\tpopl "); - ia32_emit_dest_register(node, 0); - be_emit_char('\n'); - be_emit_write_line(); + ia32_emitf(node, "\tcall %s\n", pic_base_label); + ia32_emitf(NULL, "%s:\n", pic_base_label); + ia32_emitf(node, "\tpopl %D0\n"); } static void emit_be_Return(const ir_node *node) { - unsigned pop; - be_emit_cstring("\tret"); + unsigned pop = be_Return_get_pop(node); - pop = be_Return_get_pop(node); if (pop > 0 || be_Return_get_emit_pop(node)) { - be_emit_irprintf(" $%d", pop); + ia32_emitf(node, "\tret $%u\n", pop); + } else { + ia32_emitf(node, "\tret\n"); } - be_emit_finish_line_gas(node); } static void emit_Nothing(const ir_node *node) @@ -1884,39 +1792,39 @@ static void ia32_register_emitters(void) ia32_register_spec_emitters(); /* other ia32 emitter functions */ + IA32_EMIT2(Conv_I2I8Bit, Conv_I2I); IA32_EMIT(Asm); IA32_EMIT(CMov); - IA32_EMIT(IMul); - IA32_EMIT(SwitchJmp); - IA32_EMIT(CopyB); - IA32_EMIT(CopyB_i); - IA32_EMIT(Conv_I2FP); - IA32_EMIT(Conv_FP2I); + IA32_EMIT(Const); IA32_EMIT(Conv_FP2FP); + IA32_EMIT(Conv_FP2I); + IA32_EMIT(Conv_I2FP); IA32_EMIT(Conv_I2I); - IA32_EMIT2(Conv_I2I8Bit, Conv_I2I); - IA32_EMIT(Const); + IA32_EMIT(CopyB); + IA32_EMIT(CopyB_i); + IA32_EMIT(GetEIP); + IA32_EMIT(IMul); + IA32_EMIT(Jcc); IA32_EMIT(LdTls); IA32_EMIT(Minus64Bit); - IA32_EMIT(Jcc); - IA32_EMIT(GetEIP); + IA32_EMIT(SwitchJmp); /* benode emitter */ BE_EMIT(Call); - BE_EMIT(IncSP); BE_EMIT(Copy); BE_EMIT(CopyKeep); + BE_EMIT(IncSP); BE_EMIT(Perm); BE_EMIT(Return); - BE_IGN(RegParams); BE_IGN(Barrier); BE_IGN(Keep); + BE_IGN(RegParams); /* firm emitter */ EMIT(Jmp); - IGN(Proj); IGN(Phi); + IGN(Proj); IGN(Start); #undef BE_EMIT @@ -1928,6 +1836,23 @@ static void ia32_register_emitters(void) typedef void (*emit_func_ptr) (const ir_node *); +/** + * Assign and emit an exception label if the current instruction can fail. + */ +static void ia32_assign_exc_label(ir_node *node) +{ + /* assign a new ID to the instruction */ + set_ia32_exc_label_id(node, ++exc_label_id); + /* print it */ + ia32_emit_exc_label(node); + be_emit_char(':'); + be_emit_pad_comment(); + be_emit_cstring("/* exception to Block "); + ia32_emit_cfop_target(node); + be_emit_cstring(" */\n"); + be_emit_write_line(); +} + /** * Emits code for a node. */ @@ -1944,16 +1869,13 @@ static void ia32_emit_node(ir_node *node) } if (mark_spill_reload) { if (is_ia32_is_spill(node)) { - be_emit_cstring("\txchg %ebx, %ebx /* spill mark */\n"); - be_emit_write_line(); + ia32_emitf(NULL, "\txchg %ebx, %ebx /* spill mark */\n"); } if (is_ia32_is_reload(node)) { - be_emit_cstring("\txchg %edx, %edx /* reload mark */\n"); - be_emit_write_line(); + ia32_emitf(NULL, "\txchg %edx, %edx /* reload mark */\n"); } if (is_ia32_is_remat(node)) { - be_emit_cstring("\txchg %ecx, %ecx /* remat mark */\n"); - be_emit_write_line(); + ia32_emitf(NULL, "\txchg %ecx, %ecx /* remat mark */\n"); } } } @@ -1975,9 +1897,7 @@ static void ia32_emit_node(ir_node *node) */ static void ia32_emit_alignment(unsigned align, unsigned skip) { - be_emit_cstring("\t.p2align "); - be_emit_irprintf("%u,,%u\n", align, skip); - be_emit_write_line(); + ia32_emitf(NULL, "\t.p2align %u,,%u\n", align, skip); } /** @@ -2154,25 +2074,6 @@ static void ia32_gen_labels(ir_node *block, void *data) } } -/** - * Assign and emit an exception label if the current instruction can fail. - */ -void ia32_assign_exc_label(ir_node *node) -{ - if (get_ia32_exc_label(node)) { - /* assign a new ID to the instruction */ - set_ia32_exc_label_id(node, ++exc_label_id); - /* print it */ - ia32_emit_exc_label(node); - be_emit_char(':'); - be_emit_pad_comment(); - be_emit_cstring("/* exception to Block "); - ia32_emit_cfop_target(node); - be_emit_cstring(" */\n"); - be_emit_write_line(); - } -} - /** * Compare two exception_entries. */