From 5da0fab6d0c10e01c19ecf6fdc3cc83d982dc8a5 Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Sun, 2 Apr 2006 11:33:21 +0000 Subject: [PATCH] Big Changes: - reorganized most instructions to have _i and normal forms - added support for shift-operand and condition - removed unused double fp opcodes, use mode instead (not working yet) - new constant create algorithm creates shorter sequences - dumper now writes immediate operands --- ir/be/arm/arm_emitter.c | 324 ++++++----- ir/be/arm/arm_emitter.h | 23 +- ir/be/arm/arm_gen_decls.c | 21 +- ir/be/arm/arm_map_regs.c | 12 +- ir/be/arm/arm_new_nodes.c | 150 +++-- ir/be/arm/arm_new_nodes.h | 20 +- ir/be/arm/arm_nodes_attr.h | 74 ++- ir/be/arm/arm_spec.pl | 603 ++++++++------------ ir/be/arm/arm_transform.c | 1109 ++++++++++++++++++++++-------------- ir/be/arm/arm_transform.h | 2 + ir/be/arm/bearch_arm.c | 193 ++++--- ir/be/arm/bearch_arm.h | 2 - ir/be/arm/bearch_arm_t.h | 9 +- 13 files changed, 1437 insertions(+), 1105 deletions(-) diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c index 6d4dc2ddb..b16eb893a 100644 --- a/ir/be/arm/arm_emitter.c +++ b/ir/be/arm/arm_emitter.c @@ -33,6 +33,30 @@ static const arch_env_t *arch_env = NULL; +/** + * Switch to a new section + */ +void arm_switch_section(FILE *f, sections sec) { + static sections curr_sec = NO_SECTION; + + if (curr_sec == sec) + return; + + curr_sec = sec; + switch (sec) { + + case NO_SECTION: + break; + + case SECTION_TEXT: + fprintf(f, "\t.text\n"); + break; + + case SECTION_DATA: + fprintf(f, "\t.data\n"); + break; + } +} /************************************************************* * _ _ __ _ _ @@ -45,80 +69,51 @@ static const arch_env_t *arch_env = NULL; * |_| |_| *************************************************************/ +/** + * Returns non-zero if a mode has a Immediate attribute. + */ int is_immediate_node(ir_node *irn) { - if (is_arm_Add_i(irn) || is_arm_Sub_i(irn)) - return 1; - if (is_arm_Shr_i(irn) || is_arm_Shr_i(irn) || is_arm_Shl_i(irn)) - return 1; - if (is_arm_And_i(irn) || is_arm_Or_i(irn) || is_arm_Eor_i(irn)) - return 1; - if (is_arm_Or_Shl_i(irn)) - return 1; - return 0; + arm_attr_t *attr = get_arm_attr(irn); + return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM; } /** - * Return a const or symconst as string. + * Return a const or SymConst as string. */ -static const char *node_const_to_str(ir_node *n) { - char buffer[SNPRINTF_BUF_LEN]; - - if ( is_immediate_node(n) ) { - long longvalue = get_tarval_long(get_arm_value(n)); - char *str; - assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand"); - snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 ); - str = xmalloc(strlen(buffer) * sizeof(char)); - strcpy(str, buffer); - return str; - } - if ( is_arm_Const(n) || is_arm_Const_Neg(n) ) { - tarval *tv = get_arm_value(n); - if ( mode_is_int(get_tarval_mode(tv)) ) { - long longvalue = get_tarval_long(get_arm_value(n)); - char *str; - assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand"); - snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 ); - str = xmalloc(strlen(buffer) * sizeof(char)); - strcpy(str, buffer); - return str; - } else { - return "found something else in arm_const"; - } - } else if ( is_arm_SymConst(n) ) { - return get_arm_symconst_label(n); - } else { - assert( 0 && "das ist gar keine Konstante"); - return NULL; +static const char *node_const_to_str(ir_node *n, char *buf, int buflen) { + if (is_immediate_node(n)) { + snprintf(buf, buflen, "#0x%X", arm_decode_imm_w_shift(get_arm_value(n))); + return buf; } + else if (is_arm_SymConst(n)) + return get_arm_symconst_label(n); + assert( 0 && "das ist gar keine Konstante"); + return NULL; } /** * Returns node's offset as string. */ -static char *node_offset_to_str(ir_node *n) { - char buffer[SNPRINTF_BUF_LEN]; - char *result; +static const char *node_offset_to_str(ir_node *n, char *buf, int buflen) { int offset = 0; ir_op *irn_op = get_irn_op(n); + if (irn_op == op_be_StackParam) { entity *ent = be_get_frame_entity(n); offset = get_entity_offset_bytes(ent); - } else if (irn_op==op_be_Reload || irn_op==op_be_Spill) { + } else if (irn_op == op_be_Reload || irn_op == op_be_Spill) { entity * ent = be_get_spill_entity(n); offset = get_entity_offset_bytes(ent); - } else if (irn_op==op_be_IncSP) { + } else if (irn_op == op_be_IncSP) { int offs = be_get_IncSP_offset(n); be_stack_dir_t dir = be_get_IncSP_direction(n); offset = (dir == be_stack_dir_expand) ? -offs : offs; } else { return "node_offset_to_str will fuer diesen Knotentyp noch implementiert werden"; } - snprintf(buffer, SNPRINTF_BUF_LEN, "%d", offset); - result = xmalloc(sizeof(char)*(strlen(buffer) + 1)); - strcpy(result, buffer); - return result; + snprintf(buf, buflen, "%d", offset); + return buf; } /* We always pass the ir_node which is a pointer. */ @@ -142,12 +137,6 @@ static const arch_register_t *get_in_reg(const ir_node *irn, int pos) { reg = arch_get_irn_register(arch_env, op); - /* ONLY TEMPORARY WORK-AROUND */ -// if (!reg) { -// printf("FIXME\n"); -// reg = &arm_general_purpose_regs[REG_MURX]; -// } - assert(reg && "no in register found"); return reg; } @@ -251,6 +240,7 @@ static int arm_get_reg_name(lc_appendable_t *app, static int arm_const_to_str(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *arg) { + char buffer[SNPRINTF_BUF_LEN]; const char *buf; ir_node *X = arg->v_ptr; @@ -258,17 +248,40 @@ static int arm_const_to_str(lc_appendable_t *app, return lc_appendable_snadd(app, "(null)", 6); if (occ->conversion == 'C') { - buf = node_const_to_str(X); + buf = node_const_to_str(X, buffer, sizeof(buffer)); } else { /* 'O' */ - buf = node_offset_to_str(X); + buf = node_offset_to_str(X, buffer, sizeof(buffer)); } return lc_appendable_snadd(app, buf, strlen(buf)); } /** - * Determines the SSE suffix depending on the mode. + * Returns the tarval or offset of an arm node as a string. + */ +static int arm_shift_str(lc_appendable_t *app, + const lc_arg_occ_t *occ, const lc_arg_value_t *arg) +{ + char buffer[SNPRINTF_BUF_LEN]; + ir_node *X = arg->v_ptr; + arm_shift_modifier mod; + + if (!X) + return lc_appendable_snadd(app, "(null)", 6); + + mod = get_arm_shift_modifier(X); + if (ARM_HAS_SHIFT(mod)) { + long v = get_tarval_long(get_arm_value(X)); + + snprintf(buffer, sizeof(buffer), " %s #%ld", arm_shf_mod_name(mod), v); + return lc_appendable_snadd(app, buffer, strlen(buffer)); + } + return 0; +} + +/** + * Determines the instruction suffix depending on the mode. */ static int arm_get_mode_suffix(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *arg) @@ -294,8 +307,9 @@ const lc_arg_env_t *arm_get_arg_env(void) { static const lc_arg_handler_t arm_reg_handler = { arm_get_arg_type, arm_get_reg_name }; static const lc_arg_handler_t arm_const_handler = { arm_get_arg_type, arm_const_to_str }; static const lc_arg_handler_t arm_mode_handler = { arm_get_arg_type, arm_get_mode_suffix }; + static const lc_arg_handler_t arm_shf_handler = { arm_get_arg_type, arm_shift_str }; - if(env == NULL) { + if (env == NULL) { /* extend the firm printer */ env = firm_get_arg_env(); //lc_arg_new_env(); @@ -305,6 +319,7 @@ const lc_arg_env_t *arm_get_arg_env(void) { lc_arg_register(env, "arm:cnst", 'C', &arm_const_handler); lc_arg_register(env, "arm:offs", 'O', &arm_const_handler); lc_arg_register(env, "arm:mode", 'M', &arm_mode_handler); + lc_arg_register(env, "arm:shf", 'X', &arm_shf_handler); } return env; @@ -314,7 +329,7 @@ const lc_arg_env_t *arm_get_arg_env(void) { * Formated print of commands and comments. */ static void arm_fprintf_format(FILE *F, char *cmd_buf, char *cmnt_buf, ir_node *irn) { - lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); + lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F (%G) */\n", cmd_buf, cmnt_buf, irn, irn); } /* @@ -357,6 +372,16 @@ static void emit_arm_SymConst(ir_node *irn, void *env) { lc_efprintf(arm_get_arg_env(), out, "\tLDR %1D, %s\t\t\t/* end of indirect SymConst */\n", irn, indi_label); } +/** + * Returns the next block in a block schedule. + */ +static ir_node *sched_next_block(ir_node *block) { + return get_irn_link(block); +} + +/** + * Emit a conditional jump. + */ static void emit_arm_CondJmp(ir_node *irn, void *env) { arm_emit_env_t *emit_env = env; FILE *out = emit_env->out; @@ -370,9 +395,9 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - foreach_out_edge(irn, edge) { - ir_node* proj = get_edge_src_irn(edge); - long nr = get_Proj_proj(proj); + foreach_out_edge(irn, edge) { + ir_node *proj = get_edge_src_irn(edge); + long nr = get_Proj_proj(proj); ir_node *block = get_irn_link(proj); if ( nr == pn_Cond_true) { true_block = block; @@ -381,13 +406,17 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { } else { assert(0 && "tertium non datur! (CondJmp)"); } - } + } if (proj_num == pn_Cmp_False) { + /* always false: should not happen */ fprintf(out, "\tB BLOCK_%ld\t\t\t/* false case */\n", get_irn_node_nr(false_block)); } else if (proj_num == pn_Cmp_True) { + /* always true: should not happen */ fprintf(out, "\tB BLOCK_%ld\t\t\t/* true case */\n", get_irn_node_nr(true_block)); } else { + ir_node *block = get_nodes_block(irn); + if (mode_is_float(opmode)) { suffix = "ICHWILLIMPLEMENTIERTWERDEN"; @@ -398,15 +427,11 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FMSTAT", irn, irn); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* FCSPR -> CPSR */"); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block)); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */"); - arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block)); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */"); - arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); } else { + if (true_block == sched_next_block(block)) { + /* negate it */ + proj_num = get_negated_pnc(proj_num, opmode); + } switch(proj_num) { case pn_Cmp_Eq: suffix = "EQ"; break; case pn_Cmp_Lt: suffix = "LT"; break; @@ -415,21 +440,37 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { case pn_Cmp_Ge: suffix = "GE"; break; case pn_Cmp_Lg: suffix = "NE"; break; case pn_Cmp_Leg: suffix = "AL"; break; - default: assert(0 && "komische Dinge geschehen"); + default: assert(0 && "komische Dinge geschehen"); suffix = "AL"; } lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, %2S", irn, irn); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> CPSR */", irn, irn ); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); + } + if (true_block == sched_next_block(block)) { lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block)); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */"); - arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block)); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */"); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); + + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block)); + arm_fprintf_format(out, "", cmnt_buf, irn); } + else { + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block)); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */"); + arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); + + if (false_block == sched_next_block(block)) { + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block)); + arm_fprintf_format(out, "", cmnt_buf, irn); + } + else { + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block)); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */"); + arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); + } + } } } @@ -561,12 +602,19 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) { static void emit_be_Call(ir_node *irn, void *env) { arm_emit_env_t *emit_env = env; - FILE *out = emit_env->out; - entity *target_entity = be_Call_get_entity(irn); - const char *target_name = get_entity_name(target_entity); - fprintf(out, "\tBL %s\t\t\t\t/* Call */\n", target_name); + FILE *F = emit_env->out; + entity *ent = be_Call_get_entity(irn); + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + + if (ent) + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "BL %s", get_entity_ld_name(ent)); + else + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "%1D", get_irn_n(irn, be_pos_Call_ptr)); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (be_Call) */", irn); + lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %G */\n", cmd_buf, cmnt_buf, irn); } +/** Emit an IncSP node */ static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) { FILE *F = emit_env->out; unsigned offs = be_get_IncSP_offset(irn); @@ -576,10 +624,9 @@ static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) { lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* IncSP(%O) */", irn); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } else { - char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, ""); + char cmnt_buf[SNPRINTF_BUF_LEN]; lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted IncSP(%O) */", irn); - lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); + lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", "", cmnt_buf, irn); } } @@ -597,27 +644,26 @@ static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) { assert( (mode != mode_E) && "IEEE Extended FP not supported"); if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) { - char cmd_buf[256], cmnt_buf[256]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, ""); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* omitted Copy: %1S -> %1D */", irn, irn); - lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); + char cmnt_buf[SNPRINTF_BUF_LEN]; + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted Copy: %1S -> %1D */", irn, irn); + lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", "", cmnt_buf, irn); return; } if (mode == mode_F) { - char cmd_buf[256], cmnt_buf[256]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYS %1D, %1S", irn, irn); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn); + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FCPYS %1D, %1S", irn, irn); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } else if (mode == mode_D) { - char cmd_buf[256], cmnt_buf[256]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYD %1D, %1S", irn, irn); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn); + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FCPYD %1D, %1S", irn, irn); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } else if (mode_is_numP(mode)) { - char cmd_buf[256], cmnt_buf[256]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "MOV %1D, %1S", irn, irn); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn); + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "MOV %1D, %1S", irn, irn); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } else { assert(0 && "move not supported for this mode"); @@ -630,9 +676,9 @@ static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) { ir_mode *mode = get_irn_mode(irn); assert( (mode != mode_E) && "IEEE Extended FP not supported"); if (mode_is_dataM(mode)) { - char cmd_buf[256], cmnt_buf[256]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "STR %2S, [%1S, #%O]", irn, irn, irn ); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Spill(%2S) -> (%1S) */", irn, irn); + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "STR %2S, [%1S, #%O]", irn, irn, irn ); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } else { assert(0 && "spill not supported for this mode"); @@ -644,9 +690,9 @@ static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) { ir_mode *mode = get_irn_mode(irn); assert( (mode != mode_E) && "IEEE Extended FP not supported"); if (mode_is_dataM(mode)) { - char cmd_buf[256], cmnt_buf[256]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn ); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Reload(%1S) -> (%1D) */", irn, irn); + char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %1D, [%1S, #%O]", irn, irn, irn ); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } else { assert(0 && "reload not supported for this mode"); @@ -665,11 +711,11 @@ static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) { static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) { FILE *F = emit_env->out; ir_mode *mode = get_irn_mode(irn); - char cmd_buf[256], cmnt_buf[256]; + char cmd_buf[256], cmnt_buf[SNPRINTF_BUF_LEN]; assert( (mode != mode_E) && "IEEE Extended FP not supported"); - lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn ); - lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0)); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %1D, [%1S, #%O]", irn, irn, irn ); + lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0)); lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); } @@ -707,7 +753,7 @@ static void emit_silence(ir_node *irn, void *env) { */ static void arm_register_emitters(void) { -#define ARM_EMIT(a) op_arm_##a->ops.generic = (op_func)emit_arm_##a +#define ARM_EMIT(a) op_arm_##a->ops.generic = (op_func)emit_arm_##a #define EMIT(a) op_##a->ops.generic = (op_func)emit_##a #define BE_EMIT(a) op_be_##a->ops.generic = (op_func)emit_be_##a #define SILENCE(a) op_##a->ops.generic = (op_func)emit_silence @@ -719,9 +765,8 @@ static void arm_register_emitters(void) { arm_register_spec_emitters(); /* other emitter functions */ - ARM_EMIT(CondJmp); -// ARM_EMIT(SwitchJmp); - ARM_EMIT(CopyB); + ARM_EMIT(CondJmp); + ARM_EMIT(CopyB); // ARM_EMIT(CopyB_i); // ARM_EMIT(Const); ARM_EMIT(SymConst); @@ -738,13 +783,14 @@ static void arm_register_emitters(void) { BE_EMIT(StackParam); /* firm emitter */ - EMIT(Jmp); - + EMIT(Jmp); /* noisy stuff */ #ifdef SILENCER - SILENCE(Proj); - SILENCE(Phi); + SILENCE(Proj); + SILENCE(Phi); + SILENCE(be_Keep); + SILENCE(be_CopyKeep); #endif #undef ARM_EMIT @@ -753,23 +799,25 @@ static void arm_register_emitters(void) { #undef SILENCE } +typedef void (node_emitter)(const ir_node *, void *); + /** * Emits code for a node. */ static void arm_emit_node(const ir_node *irn, void *env) { - arm_emit_env_t *emit_env = env; - FILE *F = emit_env->out; - ir_op *op = get_irn_op(irn); - DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;) + arm_emit_env_t *emit_env = env; + FILE *F = emit_env->out; + ir_op *op = get_irn_op(irn); + DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;) DBG((mod, LEVEL_1, "emitting code for %+F\n", irn)); if (op->ops.generic) { - void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic; - (*emit)(irn, env); + node_emitter *emit = (node_emitter *)op->ops.generic; + emit(irn, env); } else { - ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn); + ir_fprintf(F, "\t%-35s /* %+F %G */\n", "", irn, irn); } } @@ -780,9 +828,6 @@ static void arm_emit_node(const ir_node *irn, void *env) { void arm_gen_block(ir_node *block, void *env) { ir_node *irn; - if (! is_Block(block)) - return; - fprintf(((arm_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block)); sched_foreach(block, irn) { arm_emit_node(irn, env); @@ -794,10 +839,13 @@ void arm_gen_block(ir_node *block, void *env) { * Emits code for function start. */ void arm_emit_start(FILE *F, ir_graph *irg) { - const char *irg_name = get_entity_name(get_irg_entity(irg)); - fprintf(F, "\t.text\n"); + entity *ent = get_irg_entity(irg); + const char *irg_name = get_entity_ld_name(ent); + arm_switch_section(F, SECTION_TEXT); fprintf(F, "\t.align 2\n"); - fprintf(F, "\t.global %s\n", irg_name); + + if (get_entity_visibility(ent) == visibility_external_visible) + fprintf(F, "\t.global %s\n", irg_name); fprintf(F, "%s:\n", irg_name); } @@ -823,10 +871,12 @@ void arm_gen_labels(ir_node *block, void *env) { /** - * Main driver +* Main driver. Emits the code for one routine. */ void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) { arm_emit_env_t emit_env; + ir_node **blk_sched; + int i, n; emit_env.out = F; emit_env.arch_env = cg->arch_env; @@ -838,8 +888,24 @@ void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) { arm_register_emitters(); + /* create the block schedule. For now, we don't need it earlier. */ + blk_sched = sched_create_block_schedule(cg->irg); + arm_emit_start(F, irg); irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env); - irg_walk_blkwise_graph(irg, NULL, arm_gen_block, &emit_env); + + n = ARR_LEN(blk_sched); + for (i = 0; i < n;) { + ir_node *block, *next_bl; + + block = blk_sched[i]; + ++i; + next_bl = i < n ? blk_sched[i] : NULL; + + /* set here the link. the emitter expects to find the next block here */ + set_irn_link(block, next_bl); + arm_gen_block(block, &emit_env); + } + arm_emit_end(F, irg); } diff --git a/ir/be/arm/arm_emitter.h b/ir/be/arm/arm_emitter.h index 282979f2c..8c0b4145c 100644 --- a/ir/be/arm/arm_emitter.h +++ b/ir/be/arm/arm_emitter.h @@ -1,5 +1,5 @@ -#ifndef _arm_EMITTER_H_ -#define _arm_EMITTER_H_ +#ifndef _ARM_EMITTER_H_ +#define _ARM_EMITTER_H_ #include "irargs_t.h" // this also inlucdes #include "irnode.h" @@ -12,8 +12,8 @@ typedef struct _arm_emit_env_t { FILE *out; const arch_env_t *arch_env; - const arm_code_gen_t *cg; - DEBUG_ONLY(firm_dbg_module_t *mod;) + const arm_code_gen_t *cg; + DEBUG_ONLY(firm_dbg_module_t *mod;) } arm_emit_env_t; const lc_arg_env_t *arm_get_arg_env(void); @@ -25,4 +25,17 @@ const char *get_arm_in_reg_name(ir_node *irn, int pos); void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg); -#endif /* _arm_EMITTER_H_ */ +typedef enum sections { + NO_SECTION, /**< no section selected yet. */ + SECTION_TEXT, /**< text section */ + SECTION_DATA, /**< data section */ + SECTION_RODATA, /**< rodata section */ + SECTION_COMMON, /**< common section */ +} sections; + +/** + * Switch to a new section + */ +void arm_switch_section(FILE *f, sections sec); + +#endif /* _ARM_EMITTER_H_ */ diff --git a/ir/be/arm/arm_gen_decls.c b/ir/be/arm/arm_gen_decls.c index 88169b9b1..767b64fd1 100644 --- a/ir/be/arm/arm_gen_decls.c +++ b/ir/be/arm/arm_gen_decls.c @@ -9,24 +9,15 @@ #include #include -#include "xmalloc.h" -#include - -#ifdef obstack_chunk_alloc -# undef obstack_chunk_alloc -# define obstack_chunk_alloc xmalloc -#else -# define obstack_chunk_alloc xmalloc -# define obstack_chunk_free free -#endif - -extern int obstack_printf(struct obstack *obst, char *fmt, ...); +#include "obst.h" #include "tv.h" #include "irnode.h" #include "entity.h" #include "irprog.h" +#include "arm_emitter.h" + #include "arm_gen_decls.h" /************************************************************************/ @@ -574,21 +565,21 @@ void arm_gen_decls(FILE *out) { size = obstack_object_size(&data); cp = obstack_finish(&data); if (size > 0) { - fprintf(out, "\t.data\n"); + arm_switch_section(out, SECTION_DATA); fwrite(cp, 1, size, out); } size = obstack_object_size(&rodata); cp = obstack_finish(&rodata); if (size > 0) { - fprintf(out, "\t.section\t.rodata\n"); + arm_switch_section(out, SECTION_RODATA); fwrite(cp, 1, size, out); } size = obstack_object_size(&comm); cp = obstack_finish(&comm); if (size > 0) { - fprintf(out, "\t.common\n"); + arm_switch_section(out, SECTION_COMMON); fwrite(cp, 1, size, out); } diff --git a/ir/be/arm/arm_map_regs.c b/ir/be/arm/arm_map_regs.c index 387166329..f8b756987 100644 --- a/ir/be/arm/arm_map_regs.c +++ b/ir/be/arm/arm_map_regs.c @@ -15,10 +15,10 @@ static const arch_register_t *gpreg_param_reg_std[] = { - &arm_general_purpose_regs[REG_R0], - &arm_general_purpose_regs[REG_R1], - &arm_general_purpose_regs[REG_R2], - &arm_general_purpose_regs[REG_R3], + &arm_gp_regs[REG_R0], + &arm_gp_regs[REG_R1], + &arm_gp_regs[REG_R2], + &arm_gp_regs[REG_R3], }; const arch_register_t *arm_get_RegParam_reg(int n) { @@ -71,12 +71,12 @@ long arm_translate_proj_pos(const ir_node *proj) { ir_node *pred = get_Proj_pred(proj); long nr = get_Proj_proj(proj); - if (is_arm_Load(pred) || is_arm_fLoadd(pred) || is_arm_fLoads(pred)) { + if (is_arm_Load(pred) || is_arm_fLoad(pred)) { if (nr == pn_Load_res) return 0; assert(0 && "unsupported Proj(Load) number"); } - else if (is_arm_Store(pred) || is_arm_fStores(pred) || is_arm_fStored(pred)) { + else if (is_arm_Store(pred) || is_arm_fStore(pred)) { return 0; } else if (is_arm_fDiv(pred)) { diff --git a/ir/be/arm/arm_new_nodes.c b/ir/be/arm/arm_new_nodes.c index 69ba1c20a..c94d296fa 100644 --- a/ir/be/arm/arm_new_nodes.c +++ b/ir/be/arm/arm_new_nodes.c @@ -1,15 +1,17 @@ /** - * This file implements the creation of the achitecture specific firm opcodes - * and the coresponding node constructors for the arm assembler irg. + * This file implements the creation of the architecture specific firm opcodes + * and the corresponding node constructors for the arm assembler irg. * $Id$ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#ifdef _WIN32 +#ifdef HAVE_MALLOC_H #include -#else +#endif + +#ifdef HAVE_ALLOCA_H #include #endif @@ -35,6 +37,13 @@ #include "../beabi.h" #include "bearch_arm_t.h" +/** + * Returns the shift modifier string. + */ +const char *arm_shf_mod_name(arm_shift_modifier mod) { + static const char *names[] = { NULL, NULL, "ASR", "LSL", "LSR", "ROR", "RRX" }; + return names[mod]; +} /*********************************************************************************** * _ _ _ __ @@ -131,12 +140,13 @@ static void dump_reg_req(FILE *F, ir_node *n, const arm_register_req_t **reqs, i * @return 0 on success or != 0 on failure */ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) { - ir_mode *mode = NULL; + ir_mode *mode = NULL; int bad = 0; int i; - arm_attr_t *attr; + arm_attr_t *attr = get_arm_attr(n); const arm_register_req_t **reqs; const arch_register_t **slots; + arm_shift_modifier mod; switch (reason) { case dump_node_opcode_txt: @@ -155,14 +165,17 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) { break; case dump_node_nodeattr_txt: - - /* TODO: dump some attributes which should show up */ - /* in node name in dump (e.g. consts or the like) */ - + mod = ARM_GET_SHF_MOD(attr); + if (ARM_HAS_SHIFT(mod)) { + fprintf(F, "[%s #%ld]", arm_shf_mod_name(mod), get_tarval_long(attr->value)); + } + else if (mod == ARM_SHF_IMM) { + /* immediate */ + fprintf(F, "[#0x%X]", arm_decode_imm_w_shift(attr->value)); + } break; case dump_node_info_txt: - attr = get_arm_attr(n); fprintf(F, "=== arm attr begin ===\n"); /* dump IN requirements */ @@ -237,8 +250,6 @@ static int dump_node_arm(ir_node *n, FILE *F, dump_reason_t reason) { /* end of: case dump_node_info_txt */ break; } - - return bad; } @@ -479,20 +490,28 @@ void set_arm_default_proj_num(ir_node *node, long default_proj_num) { attr->default_proj_num = default_proj_num; } +/** + * Gets the shift modifier attribute. + */ +arm_shift_modifier get_arm_shift_modifier(ir_node *node) { + arm_attr_t *attr = get_arm_attr(node); + return ARM_GET_SHF_MOD(attr); +} - +/* Set the ARM machine node attributes to default values. */ void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs, const arm_register_req_t ** out_reqs, int n_res) { arm_attr_t *attr = get_arm_attr(node); - attr->in_req = in_reqs; - attr->out_req = out_reqs; - attr->n_res = n_res; - attr->flags = flags; - attr->slots = xcalloc(n_res, sizeof(attr->slots[0])); - attr->value = NULL; - attr->proj_num = -42; - attr->symconst_label = NULL; - attr->n_projs = 0; + attr->in_req = in_reqs; + attr->out_req = out_reqs; + attr->n_res = n_res; + attr->flags = flags; + attr->slots = xcalloc(n_res, sizeof(attr->slots[0])); + attr->instr_fl = (ARM_COND_AL << 3) | ARM_SHF_NONE; + attr->value = NULL; + attr->proj_num = -42; + attr->symconst_label = NULL; + attr->n_projs = 0; attr->default_proj_num = 0; } @@ -501,11 +520,11 @@ static int arm_comp_condJmp(arm_attr_t *attr_a, arm_attr_t *attr_b) { } ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg) { - return be_abi_get_callee_save_irn(cg->birg->abi, &arm_general_purpose_regs[REG_RXX]); + return be_abi_get_callee_save_irn(cg->birg->abi, &arm_gp_regs[REG_RXX]); } ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg) { - return be_abi_get_callee_save_irn(cg->birg->abi, &arm_floating_point_regs[REG_FXX]); + return be_abi_get_callee_save_irn(cg->birg->abi, &arm_fp_regs[REG_FXX]); } @@ -529,13 +548,12 @@ static void limit_reg_arm_StoreStackM4Inc_sp(void *_unused, bitset_t *bs) { bitset_clear(bs, 14); /* disallow ignore reg r13 */ bitset_clear(bs, 15); /* disallow ignore reg r15 */ bitset_clear(bs, 16); /* disallow ignore reg rxx */ - bitset_clear(bs, 17); /* disallow ignore reg MURX */ } static const arm_register_req_t _arm_req_sp = { { arch_register_req_type_limited, - &arm_reg_classes[CLASS_arm_general_purpose], + &arm_reg_classes[CLASS_arm_gp], limit_reg_arm_StoreStackM4Inc_sp, NULL, /* limit environment */ NULL, /* same node */ @@ -555,20 +573,20 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i { &arm_default_req_none, &_arm_req_sp, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, - &arm_default_req_arm_general_purpose, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, + &arm_default_req_arm_gp, }; assert(n_regs <= 15); @@ -588,10 +606,52 @@ ir_node *new_r_arm_StoreStackMInc(ir_graph *irg, ir_node *block, ir_node *mem, i return res; } -/** - * Register additional opcodes here. - */ -static void arm_register_additional_opcodes(int cur_opcode) { +/************************************************ + * ___ _ _ _ * + * / _ \ _ __ | |_(_)_ __ ___ (_)_______ _ __ * + * | | | | '_ \| __| | '_ ` _ \| |_ / _ \ '__| * + * | |_| | |_) | |_| | | | | | | |/ / __/ | * + * \___/| .__/ \__|_|_| |_| |_|_/___\___|_| * + * |_| * + ************************************************/ + +typedef struct _opt_tuple { + ir_op *op_imm_left; /**< immediate is left */ + ir_op *op_imm_right; /**< immediate is right */ + ir_op *op_shf_left; /**< shift operand on left */ + ir_op *op_shf_right; /**< shift operand on right */ +} opt_tuple; + +static const opt_tuple *opt_ops[iro_arm_last]; + +void arm_set_optimizers(void) { + /* +#define STD(op) p_##op = { op_arm_##op##_i, op_arm_##op##_i, op_arm_##op, op_arm_##op } +#define LEFT(op) p_##op = { op_arm_##op##_i, NULL, op_arm_##op, NULL } +#define SET(op) opt_ops[iro_arm_##op] = &p_##op; + + static const opt_tuple + STD(Add), + STD(And), + STD(Or), + STD(Eor), + LEFT(Bic), + LEFT(Shl), + LEFT(Shr), + LEFT(Shrs), + p_Sub = { op_arm_Sub_i, op_arm_Rsb_i, op_arm_Sub, op_arm_Rsb }, + + memset(opt_ops, 0, sizeof(opt_ops)); + SET(Add); + SET(And); + SET(Or); + SET(Eor); + SET(Sub); + SET(Bic); + SET(Shl); + SET(Shr); + SET(Shrs); + */ } diff --git a/ir/be/arm/arm_new_nodes.h b/ir/be/arm/arm_new_nodes.h index 1f899f648..a1ef249ba 100644 --- a/ir/be/arm/arm_new_nodes.h +++ b/ir/be/arm/arm_new_nodes.h @@ -1,5 +1,5 @@ -#ifndef _arm_NEW_NODES_H_ -#define _arm_NEW_NODES_H_ +#ifndef _ARM_NEW_NODES_H_ +#define _ARM_NEW_NODES_H_ /** * Function prototypes for the assembler ir node constructors. @@ -100,8 +100,11 @@ void set_arm_n_res(ir_node *node, int n_res); */ int get_arm_n_res(const ir_node *node); +/** + * Set the ARM machine node attributes to default values. + */ void init_arm_attributes(ir_node *node, int flags, const arm_register_req_t ** in_reqs, - const arm_register_req_t ** out_reqs, int n_res); + const arm_register_req_t ** out_reqs, int n_res); ir_node *arm_new_NoReg_gp(arm_code_gen_t *cg); ir_node *arm_new_NoReg_fp(arm_code_gen_t *cg); @@ -152,8 +155,17 @@ long get_arm_default_proj_num(ir_node *node); */ void set_arm_default_proj_num(ir_node *node, long default_proj_num); +/** + * Gets the shift modifier attribute. + */ +arm_shift_modifier get_arm_shift_modifier(ir_node *node); + +/** + * Decode an immediate with shifter operand + */ +unsigned int arm_decode_imm_w_shift(tarval *tv); /* Include the generated headers */ #include "gen_arm_new_nodes.h" -#endif /* _arm_NEW_NODES_H_ */ +#endif /* _ARM_NEW_NODES_H_ */ diff --git a/ir/be/arm/arm_nodes_attr.h b/ir/be/arm/arm_nodes_attr.h index b7e9de7e8..89ab590e5 100644 --- a/ir/be/arm/arm_nodes_attr.h +++ b/ir/be/arm/arm_nodes_attr.h @@ -4,28 +4,84 @@ #include "../bearch.h" #include "../../common/firm_types.h" - +/** A register requirement. */ typedef struct _arm_register_req_t { const arch_register_req_t req; - int same_pos; /**<< in case of "should be same" we need to remember the pos to get the irn */ - int different_pos; /**<< in case of "should be different" we need to remember the pos to get the irn */ + int same_pos; /**< in case of "should be same" we need to remember the pos to get the irn */ + int different_pos; /**< in case of "should be different" we need to remember the pos to get the irn */ } arm_register_req_t; +/** + * Possible ARM register shift types. + */ +typedef enum _arm_shift_modifier { + ARM_SHF_NONE = 0, /**< no shift */ + ARM_SHF_IMM = 1, /**< immediate operand with implicit ROR */ + ARM_SHF_ASR = 2, /**< arithmetic shift right */ + ARM_SHF_LSL = 3, /**< logical shift left */ + ARM_SHF_LSR = 4, /**< logical shift right */ + ARM_SHF_ROR = 5, /**< rotate right */ + ARM_SHF_RRX = 6, /**< rotate with sign extend */ +} arm_shift_modifier; + +/** True, if the modifier implies a shift argument */ +#define ARM_HAS_SHIFT(mod) ((mod) > ARM_SHF_IMM) + +/** get the shift modifier from flags */ +#define ARM_GET_SHF_MOD(attr) ((attr)->instr_fl & 7) + +/** set the shift modifier to flags */ +#define ARM_SET_SHF_MOD(attr, mod) ((attr)->instr_fl = (((attr)->instr_fl & ~7) | (mod))) + + +/** + * Possible ARM condition codes. + */ +typedef enum _arm_condition { + ARM_COND_EQ = 0, /**< Equal, Z set. */ + ARM_COND_NE = 1, /**< Not Equal, Z clear */ + ARM_COND_CS = 2, /**< Carry set, unsigned >=, C set */ + ARM_COND_CC = 3, /**< Carry clear, unsigned <, C clear */ + ARM_COND_MI = 4, /**< Minus/Negativ, N set */ + ARM_COND_PL = 5, /**< Plus/Positiv or Zero, N clear */ + ARM_COND_VS = 6, /**< Overflow, V set */ + ARM_COND_VC = 7, /**< No overflow, V clear */ + ARM_COND_HI = 8, /**< unsigned >, C set and Z clear */ + ARM_COND_LS = 9, /**< unsigned <=, C clear or Z set */ + ARM_COND_GE = 10, /**< signed >=, N == V */ + ARM_COND_LT = 11, /**< signed <, N != V */ + ARM_COND_GT = 12, /**< signed >, Z clear and N == V */ + ARM_COND_LE = 13, /**< signed <=, Z set or N != V */ + ARM_COND_AL = 14, /**< Always (unconditional) */ + ARM_COND_NV = 15 /**< forbidden */ +} arm_condition; + +/** Get the condition code from flags */ +#define ARM_GET_COND(attr) (((attr)->instr_fl >> 3) & 15) + +/** Set the condition code to flags */ +#define ARM_SET_COND(attr, code) ((attr)->instr_fl = (((attr)->instr_fl & ~(15 << 3)) | ((code) << 3))) typedef struct _arm_attr_t { - arch_irn_flags_t flags; /**<< indicating if spillable, rematerializeable ... etc. */ - int n_res; /**<< number of results for this node */ + arch_irn_flags_t flags; /**< indicating if spillable, rematerializeable ... etc. */ + int n_res; /**< number of results for this node */ - const arm_register_req_t **in_req; /**<< register requirements for arguments */ - const arm_register_req_t **out_req; /**<< register requirements for results */ + const arm_register_req_t **in_req; /**< register requirements for arguments */ + const arm_register_req_t **out_req; /**< register requirements for results */ - const arch_register_t **slots; /**<< register slots for assigned registers */ + const arch_register_t **slots; /**< register slots for assigned registers */ - tarval *value; + unsigned instr_fl; /**< condition code, shift modifier */ + tarval *value; /**< immediate */ const char *symconst_label; int proj_num; int n_projs; long default_proj_num; } arm_attr_t; +/** + * Returns the shift modifier string. + */ +const char *arm_shf_mod_name(arm_shift_modifier mod); + #endif /* _ARM_NODES_ATTR_H_ */ diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl index 0fcb9ffbb..cc5a3c54d 100644 --- a/ir/be/arm/arm_spec.pl +++ b/ir/be/arm/arm_spec.pl @@ -10,7 +10,7 @@ $arch = "arm"; $comment_string = '/*'; # the number of additional opcodes you want to register -$additional_opcodes = 0; +#$additional_opcodes = 0; # The node description is done as a perl hash initializer with the # following structure: @@ -93,7 +93,7 @@ $additional_opcodes = 0; # 4 - ignore (do not assign this register) # NOTE: Last entry of each class is the largest Firm-Mode a register can hold %reg_classes = ( - "general_purpose" => [ + "gp" => [ { "name" => "r0", "type" => 1 }, { "name" => "r1", "type" => 1 }, { "name" => "r2", "type" => 1 }, @@ -107,14 +107,13 @@ $additional_opcodes = 0; { "name" => "r10", "type" => 2 }, { "name" => "r11", "type" => 2 }, { "name" => "r12", "type" => 6 }, # reserved for linker - { "name" => "r13", "type" => 6 }, # this is our stack pointer - { "name" => "r14", "type" => 3 }, # this is our return address - { "name" => "r15", "type" => 6 }, # this is our program counter - { "name" => "rxx", "type" => 6 }, # dummy register for no_mem - { "name" => "MURX", "type" => 6 }, # this is our workaround-register - { "mode" => "mode_P" } + { "name" => "sp", "type" => 6 }, # this is our stack pointer + { "name" => "lr", "type" => 3 }, # this is our return address + { "name" => "pc", "type" => 6 }, # this is our program counter + { "name" => "rxx", "type" => 6 }, # dummy register for no_mem + { "mode" => "mode_Iu" } ], - "floating_point" => [ + "fp" => [ { "name" => "f0", "type" => 1 }, { "name" => "f1", "type" => 1 }, { "name" => "f2", "type" => 1 }, @@ -123,7 +122,7 @@ $additional_opcodes = 0; { "name" => "f5", "type" => 2 }, { "name" => "f6", "type" => 2 }, { "name" => "f7", "type" => 2 }, - { "name" => "fxx", "type" => 6 }, # dummy register for no_mem + { "name" => "fxx", "type" => 6 }, # dummy register for no_mem { "mode" => "mode_D" } ] ); # %reg_classes @@ -158,290 +157,254 @@ $additional_opcodes = 0; "op_flags" => "C", "irn_flags" => "R", "comment" => "construct Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ADD %D1, %S1, %S2\t\t\t/* Add(%S1, %S2) -> %D1, (%A1, %A2) */' + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. ADD %D1, %S1, %S2%X0 /* Add(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Add_i" => { "irn_flags" => "R", "comment" => "construct Add: Add(a, const) = Add(const, a) = a + const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ADD %D1, %S1, %C\t\t\t/* Add(%C, %S1) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "cmp_attr" => 'return attr_a->value != attr_b->value;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. ADD %D1, %S1, %C /* Add(%C, %S1) -> %D1, (%A1, const) */' }, "Mul" => { #"op_flags" => "C", "irn_flags" => "R", "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "!in_r1" ] }, - "emit" =>'. MUL %D1, %S1, %S2\t\t\t/* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "!in_r1" ] }, + "emit" =>'. MUL %D1, %S1, %S2 /* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' +}, + +"Mla" => { + #"op_flags" => "C", + "irn_flags" => "R", + "comment" => "construct Mla: Mla(a, b, c) = a * b + c", + "reg_req" => { "in" => [ "gp", "gp", "gp" ], "out" => [ "!in_r1" ] }, + "emit" =>'. MLA %D1, %S1, %S2, %S3 /* Mla(%S1, %S2, %S3) -> %D1, (%A1, %A2, %A3) */' }, "And" => { "op_flags" => "C", "irn_flags" => "R", "comment" => "construct And: And(a, b) = And(b, a) = a AND b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. AND %D1, %S1, %S2\t\t/* And(%S1, %S2) -> %D1, (%A1, %A2) */' + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. AND %D1, %S1, %S2%X0 /* And(%S1, %S2) -> %D1, (%A1, %A2) */' }, "And_i" => { "irn_flags" => "R", "comment" => "construct And: And(a, const) = And(const, a) = a AND const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. AND %D1, %S1, %C\t\t\t/* And(%C, %S1) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. AND %D1, %S1, %C /* And(%C, %S1) -> %D1, (%A1, const) */', + "cmp_attr" => 'return attr_a->value != attr_b->value;' }, "Or" => { "op_flags" => "C", "irn_flags" => "R", "comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ORR %D1, %S1, %S2\t\t/* Or(%S1, %S2) -> %D1, (%A1, %A2) */' + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. ORR %D1, %S1, %S2%X0 /* Or(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Or_i" => { "irn_flags" => "R", "comment" => "construct Or: Or(a, const) = Or(const, a) = a OR const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ORR %D1, %S1, %C\t\t\t/* Or(%C, %S1) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' -}, - -"Or_Shl_i" => { - "irn_flags" => "R", - "comment" => "construct Or with immediate shifter operand", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. ORR %D1, %S1, %S2 LSL %C\t\t\t/* Or_Shl_i(%S1, %S2 << %C) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "cmp_attr" => 'return attr_a->value != attr_b->value;', + "emit" => '. ORR %D1, %S1, %C /* Or(%C, %S1) -> %D1, (%A1, const) */' }, "Eor" => { "op_flags" => "C", "irn_flags" => "R", "comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. EOR %D1, %S1, %S2\t\t\t/* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. EOR %D1, %S1, %S2%X0 /* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Eor_i" => { "irn_flags" => "R", "comment" => "construct Eor: Eor(a, const) = Eor(const, a) = a EOR const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. EOR %D1, %S1, %C\t\t\t/* Xor(%C, %S1) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "cmp_attr" => 'return attr_a->value != attr_b->value;', + "emit" => '. EOR %D1, %S1, %C /* Xor(%C, %S1) -> %D1, (%A1, const) */' }, # not commutative operations +"Bic" => { + "irn_flags" => "R", + "comment" => "construct Bic: Bic(a, b) = a AND ~b", + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. BIC %D1, %S1, %S2%X0 /* AndNot(%S1, %S2) -> %D1, (%A1, %A2) */' +}, + +"Bic_i" => { + "irn_flags" => "R", + "comment" => "construct Bic: Bic(a, const) = a AND ~const", + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. BIC %D1, %S1, %C /* AndNot(%C, %S1) -> %D1, (%A1, const) */', + "cmp_attr" => 'return attr_a->value != attr_b->value;' +}, + "Sub" => { "irn_flags" => "R", "comment" => "construct Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. SUB %D1, %S1, %S2\t\t\t/* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. SUB %D1, %S1, %S2%X0 /* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Sub_i" => { "irn_flags" => "R", "comment" => "construct Sub: Sub(a, const) = a - const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. SUB %D1, %S1, %C\t\t\t/* Sub(%S1, %C) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "cmp_attr" => 'return attr_a->value != attr_b->value;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. SUB %D1, %S1, %C /* Sub(%S1, %C) -> %D1, (%A1, const) */', }, -"Shl" => { +"Rsb" => { "irn_flags" => "R", - "comment" => "construct Shl: Shl(a, b) = a << b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. MOV %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' + "comment" => "construct Rsb: Rsb(a, b) = b - a", + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. RSB %D1, %S1, %S2%X0 /* Rsb(%S1, %S2) -> %D1, (%A1, %A2) */' }, -"Shl_i" => { +"Rsb_i" => { "irn_flags" => "R", - "comment" => "construct Shl: Shl(a, const) = a << const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. MOV %D1, %S1, LSL %C\t\t\t/* Shl(%S1, %C) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "comment" => "construct Rsb: Rsb(a, const) = const - a", + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. RSB %D1, %S1, %C /* Rsb(%S1, %C) -> %D1, (%A1, const) */', + "cmp_attr" => 'return attr_a->value != attr_b->value;' }, -"Shr" => { +"Shl" => { "irn_flags" => "R", - "comment" => "construct Shr: Shr(a, b) = a >> b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] }, - "emit" => '. MOV %D1, %S1, LSR %S2\t\t\t/* Shr(%S1, %S2) -> %D1, (%A1, %A2) */' + "comment" => "construct Shl: Shl(a, b) = a << b", + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, + "emit" => '. MOV %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' }, -"Shr_i" => { +"Shr" => { "irn_flags" => "R", - "comment" => "construct Shr: Shr(a, const) = a >> const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. MOV %D1, %S1, LSR %C\t\t\t/* Shr(%S1, %C) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "comment" => "construct Shr: Shr(a, b) = a >> b", + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, + "emit" => '. MOV %D1, %S1, LSR %S2 /* Shr(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Shrs" => { "irn_flags" => "R", "comment" => "construct Shrs: Shrs(a, b) = a >> b", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "in_r1" ] }, - "emit" => '. MOV %D1, %S1, ASR %S2\t\t\t\t\t/* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, + "emit" => '. MOV %D1, %S1, ASR %S2\t\t /* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */' }, -"Shrs_i" => { - "irn_flags" => "R", - "comment" => "construct Shrs: Shrs(a, const) = a >> const", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. MOV %D1, %S1, ASR %C\t\t\t/* Shrs(%S1, %C) -> %D1, (%A1, const) */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' -}, - -#"Div" => { -# "irn_flags" => "R", -# "comment" => "construct Div: Div(a, b) = a / b", -# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */' -#}, -# -#"Div_i" => { -# "irn_flags" => "R", -# "comment" => "construct Div: Div(a, const) = a / const", -# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */' -#}, -# -#"Mod" => { -# "irn_flags" => "R", -# "comment" => "construct Mod: Mod(a, b) = a % b", -# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" =>'. mod %S1, %S2, %D1\t\t\t/* mod(%S1, %S2) -> %D1, (%A1, %A2) */' -#}, -# -#"Mod_i" => { -# "irn_flags" => "R", -# "comment" => "construct mod: Mod(a, const) = a % const", -# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. mod %S1, %C, %D1\t\t\t/* mod(%C, %S1) -> %D1, (%A1, const) */' -#}, -# -#"DivMod" => { -# "irn_flags" => "R", -# "comment" => "construct DivMod: DivMod(a, b) = a / b", -# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" =>'. div %S1, %S2, %D1\t\t\t/* div(%S1, %S2) -> %D1, (%A1, %A2) */' -#}, -# -#"Div_i" => { -# "irn_flags" => "R", -# "comment" => "construct DivMod: DivMod(a, const) = a / const", -# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. div %S1, %C, %D1\t\t\t/* signed div(%C, %S1) -> %D1, (%A1, const) */' -#}, - #"RotR" => { # "irn_flags" => "R", # "comment" => "construct RotR: RotR(a, b) = a ROTR b", -# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. MOV %D1, %S1, ROR %S2\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' -## "emit" => '. ror %S1, %S2, %D1\t\t\t/* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' +# "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, +# "emit" => '. MOV %D1, %S1, ROR %S2 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' +## "emit" => '. ror %S1, %S2, %D1 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' #}, #"RotL" => { # "irn_flags" => "R", # "comment" => "construct RotL: RotL(a, b) = a ROTL b", -# "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. rol %S1, %S2, %D1\t\t\t/* RotL(%S1, %S2) -> %D1, (%A1, %A2) */' +# "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, +# "emit" => '. rol %S1, %S2, %D1 /* RotL(%S1, %S2) -> %D1, (%A1, %A2) */' #}, #"RotL_i" => { # "irn_flags" => "R", # "comment" => "construct RotL: RotL(a, const) = a ROTL const", -# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. rol %S1, %C, %D1\t\t\t/* RotL(%S1, %C) -> %D1, (%A1, const) */' +# "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, +# "emit" => '. rol %S1, %C, %D1 /* RotL(%S1, %C) -> %D1, (%A1, const) */' #}, -"Minus" => { +"Mov" => { "irn_flags" => "R", - "comment" => "construct Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. RSB %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */' + "comment" => "construct Mov: a = b", + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. MOV %D1, %S1%X0\t/* Mov(%S1%X0) -> %D1, (%A1) */' }, -#"Inc" => { -# "irn_flags" => "R", -# "comment" => "construct Increment: Inc(a) = a++", -# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. inc %S1, %D1\t\t\t/* Inc(%S1) -> %D1, (%A1) */' -#}, -# -#"Dec" => { -# "irn_flags" => "R", -# "comment" => "construct Decrement: Dec(a) = a--", -# "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, -# "emit" => '. dec %S1, %D1\t\t\t/* Dec(%S1) -> %D1, (%A1) */' -#}, +"Mov_i" => { + "irn_flags" => "R", + "comment" => "represents an integer constant", + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "reg_req" => { "out" => [ "gp" ] }, + "emit" => '. MOV %D1, %C /* Mov Const into register */', + "cmp_attr" => 'return attr_a->value != attr_b->value;' +}, -"Not" => { - "arity" => 1, -# "remat" => 1, - "irn_flags" => "R", - "comment" => "construct Not: Not(a) = !a", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, - "emit" => '. MVN %D1, %S1\t\t\t/* Not(%S1) -> %D1, (%A1) */' +"Mvn" => { + "irn_flags" => "R", + "comment" => "construct Not: Not(a) = !a", + "attr" => "arm_shift_modifier mod, tarval *shf", + "init_attr" => 'ARM_SET_SHF_MOD(attr, mod); attr->value = shf;', + "cmp_attr" => 'return (attr_a->instr_fl != attr_b->instr_fl) || (attr_a->value != attr_b->value);', + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, + "emit" => '. MVN %D1, %S1%X0 /* ~(%S1%X0) -> %D1, (%A1) */' +}, + +"Mvn_i" => { + "irn_flags" => "R", + "comment" => "represents a negated integer constant", + "attr" => "tarval *tv", + "init_attr" => 'ARM_SET_SHF_MOD(attr, ARM_SHF_IMM); attr->value = tv;', + "cmp_attr" => 'return attr_a->value != attr_b->value;', + "reg_req" => { "out" => [ "gp" ] }, + "emit" => '. MVN %D1, %C /* Mov ~Const into register */', }, "Abs" => { "irn_flags" => "R", "comment" => "construct Abs: Abs(a) = |a|", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, "emit" => -'. MOVS %S1, %S1, #0\t\t\t/* set condition flag */\n -. RSBMI %D1, %S1, #0\t\t\t/* Neg(%S1) -> %D1, (%A1) */' +'. MOVS %S1, %S1, #0 /* set condition flag */\n +. RSBMI %D1, %S1, #0 /* Neg(%S1) -> %D1, (%A1) */' }, # other operations @@ -449,75 +412,48 @@ $additional_opcodes = 0; "EmptyReg" => { "op_flags" => "c", "irn_flags" => "R", - "comment" => "just to get an emptz register for calculations", - "reg_req" => { "out" => [ "general_purpose" ] }, + "comment" => "just to get an empty register for calculations", + "reg_req" => { "out" => [ "gp" ] }, "emit" => '. /* %D1 now available for calculations */', "cmp_attr" => 'return 1;' }, "Copy" => { "comment" => "implements a register copy", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "general_purpose" ] }, + "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, }, "CopyB" => { "op_flags" => "F|H", "state" => "pinned", "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)", - "reg_req" => { "in" => [ "!r13", "!r13", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "none" ] }, -}, - -"Const" => { - "irn_flags" => "R", - "comment" => "represents an integer constant", - "reg_req" => { "out" => [ "general_purpose" ] }, - "emit" => '. MOV %D1, %C \t\t\t/* Mov Const into register */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' -}, - -"Const_Neg" => { - "irn_flags" => "R", - "comment" => "represents a negated integer constant", - "reg_req" => { "out" => [ "general_purpose" ] }, - "emit" => '. MVN %D1, %C \t\t\t/* Mov negated Const into register */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' + "reg_req" => { "in" => [ "!sp", "!sp", "gp", "gp", "gp", "none" ], "out" => [ "none" ] }, }, "SymConst" => { "op_flags" => "c", "irn_flags" => "R", "comment" => "represents a symbolic constant", - "reg_req" => { "out" => [ "general_purpose" ] }, -# "emit" => '. LDR %D1, %C\t\t\t/* Mov Const into register */', + "attr" => "const char *label", + "init_attr" => ' attr->symconst_label = label;', + "reg_req" => { "out" => [ "gp" ] }, +# "emit" => '. LDR %D1, %C /* Mov Const into register */', "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_long(attr_a->value) != get_tarval_long(attr_b->value); -' +' /* should be identical but ...*/ + return strcmp(attr_a->symconst_label, attr_b->symconst_label);' }, "CondJmp" => { "op_flags" => "L|X|Y", "comment" => "construct conditional jump: CMP A, B && JMPxx LABEL", "cmp_attr" => " return arm_comp_condJmp(attr_a, attr_b);\n", - "reg_req" => { "in" => [ "general_purpose", "general_purpose" ], "out" => [ "none", "none"] }, + "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "none", "none"] }, }, "SwitchJmp" => { "op_flags" => "L|X|Y", "comment" => "construct switch", - "reg_req" => { "in" => [ "general_purpose" ], "out" => [ "none" ] }, + "reg_req" => { "in" => [ "gp" ], "out" => [ "none" ] }, "cmp_attr" => " return 0;\n", }, @@ -528,9 +464,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. LDR %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDR %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */' + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, + "emit" => '. LDR %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' +# "emit" => '. LDR %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' }, "Loadb" => { @@ -538,9 +474,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. LDRB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */' + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, + "emit" => '. LDRB %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' +# "emit" => '. LDRB %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' }, "Loadbs" => { @@ -548,9 +484,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. LDRSB %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRSB %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */' + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, + "emit" => '. LDRSB %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' +# "emit" => '. LDRSB %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' }, "Loadh" => { @@ -558,9 +494,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. LDRH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */' + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, + "emit" => '. LDRH %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' +# "emit" => '. LDRH %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' }, "Loadhs" => { @@ -568,9 +504,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "general_purpose" ] }, - "emit" => '. LDRSH %D1, [%S1, #0]\t\t\t/* Load((%S1)) -> %D1, (%A1) */' -# "emit" => '. LDRSH %D1, %S1, %O\t\t\t/* Load((%S1)) -> %D1, (%A1) */' + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp" ] }, + "emit" => '. LDRSH %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */' +# "emit" => '. LDRSH %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */' }, "Storeb" => { @@ -578,9 +514,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. STRB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp", "none" ] }, + "emit" => '. STRB %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' +# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' }, "Storebs" => { @@ -588,9 +524,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. STRSB %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp", "none" ] }, + "emit" => '. STRSB %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' +# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' }, "Storeh" => { @@ -598,9 +534,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. STRH %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp", "none" ] }, + "emit" => '. STRH %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' +# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' }, "Storehs" => { @@ -608,9 +544,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. STRSH%S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp", "none" ] }, + "emit" => '. STRSH%S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' +# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' }, "Store" => { @@ -618,9 +554,9 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "general_purpose", "none" ] }, - "emit" => '. STR %S2, [%S1, #0]\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' -# "emit" => '. movl %S2, %O(%S1)\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "gp", "none" ] }, + "emit" => '. STR %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */' +# "emit" => '. movl %S2, %O(%S1) /* Store(%S2) -> (%S1), (%A1, %A2) */' }, "StoreStackM4Inc" => { @@ -628,8 +564,8 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "r13", "general_purpose", "general_purpose", "general_purpose", "general_purpose", "none" ], "out" => [ "general_purpose", "none" ] }, - "emit" => '. STMFD %S1!, {%S2, %S3, %S4, %S5}\t\t\t/* Store multiple on Stack*/' + "reg_req" => { "in" => [ "sp", "gp", "gp", "gp", "gp", "none" ], "out" => [ "gp", "none" ] }, + "emit" => '. STMFD %S1!, {%S2, %S3, %S4, %S5} /* Store multiple on Stack*/' }, "LoadStackM3" => { @@ -637,8 +573,8 @@ $additional_opcodes = 0; "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", - "reg_req" => { "in" => [ "r13", "none" ], "out" => [ "general_purpose", "general_purpose", "general_purpose", "none" ] }, - "emit" => '. LDMFD %S1, {%D1, %D2, %D3}\t\t\t/* Load multiple from Stack */' + "reg_req" => { "in" => [ "sp", "none" ], "out" => [ "gp", "gp", "gp", "none" ] }, + "emit" => '. LDMFD %S1, {%D1, %D2, %D3} /* Load multiple from Stack */' }, @@ -659,105 +595,64 @@ $additional_opcodes = 0; # commutative operations -"fAddd" => { +"fAdd" => { "op_flags" => "C", "irn_flags" => "R", - "comment" => "construct DP FP Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FADDD %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */' + "comment" => "construct FP Add: Add(a, b) = Add(b, a) = a + b", + "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, + "emit" => '. FADD%Mx %D1, %S1, %S2 /* FP Add(%S1, %S2) -> %D1 */' }, -"fAdds" => { - "op_flags" => "C", - "irn_flags" => "R", - "comment" => "construct SP FP Add: Add(a, b) = Add(b, a) = a + b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FADDS %D1, %S1, %S2\t\t\t/* FP Add(%S1, %S2) -> %D1 */' -}, - -"fMuls" => { +"fMul" => { "op_flags" => "C", "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. FMULS %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */' -}, - -"fMuld" => { - "op_flags" => "C", - "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. FMULD %D1, %S1, %S2\t\t\t/* FP Mul(%S1, %S2) -> %D1 */' -}, - -"fDivs" => { - "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. FDIVS %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */' -}, - -"fDivd" => { - "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. FDIVD %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */' + "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, + "emit" =>'. FMUL%Mx %D1, %S1, %S2 /* FP Mul(%S1, %S2) -> %D1 */' }, "fDiv" => { "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. FDIV %D1, %S1, %S2\t\t\t/* FP Div(%S1, %S2) -> %D1 */' + "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, + "emit" =>'. FDIV%Mx %D1, %S1, %S2 /* FP Div(%S1, %S2) -> %D1 */' }, "fMax" => { "op_flags" => "C", "irn_flags" => "R", "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmax %S1, %S2, %D1\t\t\t/* FP Max(%S1, %S2) -> %D1 */' + "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, + "emit" =>'. fmax %S1, %S2, %D1 /* FP Max(%S1, %S2) -> %D1 */' }, "fMin" => { "op_flags" => "C", "irn_flags" => "R", "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" =>'. fmin %S1, %S2, %D1\t\t\t/* FP Min(%S1, %S2) -> %D1 */' + "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, + "emit" =>'. fmin %S1, %S2, %D1 /* FP Min(%S1, %S2) -> %D1 */' }, # not commutative operations -"fSubs" => { +"fSub" => { "irn_flags" => "R", "comment" => "construct FP Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FSUBS %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */' -}, - -"fSubd" => { - "irn_flags" => "R", - "comment" => "construct FP Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "floating_point", "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FSUBD %D1, %S1, %S2\t\t\t/* FP Sub(%S1, %S2) -> %D1 */' + "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, + "emit" => '. FSUB%Mx %D1, %S1, %S2 /* FP Sub(%S1, %S2) -> %D1 */' }, "fMinus" => { "irn_flags" => "R", "comment" => "construct FP Minus: Minus(a) = -a", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. fneg %S1, %D1\t\t\t/* FP Minus(%S1) -> %D1 */' -}, - -"fAbss" => { - "irn_flags" => "R", - "comment" => "construct FP Absolute value: fAbss(a) = |a|", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FABSS %D1, %S1\t\t\t/* FP Abss(%S1) -> %D1 */' + "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, + "emit" => '. fneg %S1, %D1 /* FP Minus(%S1) -> %D1 */' }, -"fAbsd" => { +"fAbs" => { "irn_flags" => "R", "comment" => "construct FP Absolute value: fAbsd(a) = |a|", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FABSD %D1, %S1\t\t\t/* FP Absd(%S1) -> %D1 */' + "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, + "emit" => '. FABS%Mx %D1, %S1 /* FP Absd(%S1) -> %D1 */' }, # other operations @@ -766,68 +661,44 @@ $additional_opcodes = 0; "op_flags" => "c", "irn_flags" => "R", "comment" => "represents a FP constant", - "reg_req" => { "out" => [ "floating_point" ] }, - "emit" => '. FMOV %D1, %C\t\t\t/* Mov fConst into register */', - "cmp_attr" => -' if (attr_a->value == NULL || attr_b->value == NULL) - return 1; - - return get_tarval_double(attr_a->value) != get_tarval_double(attr_b->value);' + "reg_req" => { "out" => [ "fp" ] }, + "emit" => '. FMOV %D1, %C /* Mov fConst into register */', + "cmp_attr" => 'return attr_a->value != attr_b->value;' }, "fConvD2S" => { "irn_flags" => "R", "comment" => "convert double to single", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FCVTSD %D1, %S1\t\t\t/* Convert double to single */', + "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, + "emit" => '. FCVTSD %D1, %S1 /* Convert double to single */', }, "fConvS2D" => { "irn_flags" => "R", "comment" => "convert single to double", - "reg_req" => { "in" => [ "floating_point" ], "out" => [ "floating_point" ] }, - "emit" => '. FCVTDS %D1, %S1\t\t\t/* Convert single to double */', + "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, + "emit" => '. FCVTDS %D1, %S1 /* Convert single to double */', }, # Load / Store -"fLoads" => { +"fLoad" => { "op_flags" => "L|F", "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] }, - "emit" => '. FLDS %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */' -# "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */' -}, - -"fLoadd" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "general_purpose", "none" ], "out" => [ "floating_point" ] }, - "emit" => '. FLDD %D1, %S1\t\t\t/* Load((%S1)) -> %D1 */' -# "emit" => '. fmov %O(%S1), %D1\t\t\t/* Load((%S1)) -> %D1 */' -}, - -"fStores" => { - "op_flags" => "L|F", - "irn_flags" => "R", - "state" => "exc_pinned", - "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] }, - "emit" => '. FSTS %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "fp" ] }, + "emit" => '. FLD%Mx %D1, %S1 /* Load((%S1)) -> %D1 */' }, -"fStored" => { +"fStore" => { "op_flags" => "L|F", "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "general_purpose", "floating_point", "none" ] }, - "emit" => '. FSTD %S2, %S1\t\t\t/* Store(%S2) -> (%S1), (%A1, %A2) */' + "reg_req" => { "in" => [ "gp", "fp", "none" ] }, + "emit" => '. FST%Mx %S2, %S1 /* Store(%S2) -> (%S1), (%A1, %A2) */' }, ); # end of %nodes diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c index 0e744d057..a3eaac588 100644 --- a/ir/be/arm/arm_transform.c +++ b/ir/be/arm/arm_transform.c @@ -12,6 +12,7 @@ #include "iredges.h" #include "irvrfy.h" #include "ircons.h" +#include "irprintf.h" #include "dbginfo.h" #include "iropt_t.h" #include "debug.h" @@ -29,6 +30,7 @@ #include + extern ir_op *get_op_Mulh(void); @@ -43,132 +45,126 @@ extern ir_op *get_op_Mulh(void); * ****************************************************************************************************/ +/** Execute ROL. */ +static unsigned do_rol(unsigned v, unsigned rol) +{ + return (v << rol) | (v >> (32 - rol)); +} + typedef struct vals_ { - int ops; - unsigned char values[4]; - unsigned char shifts[4]; + int ops; + unsigned char values[4]; + unsigned char shifts[4]; } vals; -static vals construct_vals(void) { - vals result = { 0, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; - return result; +static void gen_vals_from_word(unsigned int value, vals *result) +{ + int initial = 0; + + memset(result, 0, sizeof(*result)); + + /* special case: we prefer shift amount 0 */ + if (value < 0x100) { + result->values[0] = value; + result->ops = 1; + return; + } + + while (value != 0) { + if (value & 0xFF) { + unsigned v = do_rol(value, 8) & 0xFFFFFF; + int shf = 0; + for (;;) { + if ((v & 3) != 0) + break; + shf += 2; + v >>= 2; + } + v &= 0xFF; + shf = (initial + shf - 8) & 0x1F; + result->values[result->ops] = v; + result->shifts[result->ops] = shf; + ++result->ops; + + value ^= do_rol(v, shf) >> initial; + } + else { + value >>= 8; + initial += 8; + } + } } -static vals gen_vals_from_word(unsigned int value) -{ - vals result = construct_vals(); - int cur_offset = 0; - while (value != 0) { - if ((value & 3) == 0) { - cur_offset += 2; - value >>= 2; - } else { - result.values[result.ops] = value & 0xff; - result.shifts[result.ops] = cur_offset; - ++result.ops; - value >>= 8; - cur_offset += 8; - } - } - return result; +/** + * Creates a arm_Const node. + */ +static ir_node *create_const_node(arm_transform_env_t *env, long value) { + tarval *tv = new_tarval_from_long(value, mode_Iu); + return new_rd_arm_Mov_i(env->dbg, env->irg, env->block, env->mode, tv); } -static ir_node *create_const_node(arm_transform_env_t *env, int value) { - ir_node *result = new_rd_arm_Const(env->dbg, env->irg, env->block, env->mode); - get_arm_attr(result)->value = new_tarval_from_long(value, env->mode); - return result; +/** + * Creates a arm_Const_Neg node. + */ +static ir_node *create_const_neg_node(arm_transform_env_t *env, long value) { + tarval *tv = new_tarval_from_long(value, mode_Iu); + return new_rd_arm_Mvn_i(env->dbg, env->irg, env->block, env->mode, tv); } #define NEW_BINOP_NODE(opname, env, op1, op2) new_rd_arm_##opname(env->dbg, env->irg, env->block, op1, op2, env->mode) -unsigned int create_shifter_operand(unsigned int shift, unsigned int immediate) { +/** + * Encodes an immediate with shifter operand + */ +static unsigned int arm_encode_imm_w_shift(unsigned int shift, unsigned int immediate) { return immediate | ((shift>>1)<<8); } +/** + * Decode an immediate with shifter operand + */ +unsigned int arm_decode_imm_w_shift(tarval *tv) { + unsigned l = get_tarval_long(tv); + unsigned rol = (l & ~0xFF) >> 7; + + return do_rol(l & 0xFF, rol); +} + +/** + * Creates a possible DAG for an constant. + */ static ir_node *create_const_graph_value(arm_transform_env_t *env, unsigned int value) { ir_node *result; int negate = 0; + vals v, vn; + int cnt; - if (value < 0x100 || ~value < 0x100 ) { - if ( ~value < 0x100 ) { - negate = 1; - value = ~value; - } - result = create_const_node(env, value); - } else { - vals v; - vals v1 = gen_vals_from_word(value); - vals v2 = gen_vals_from_word(~value); - int cnt = 0; - if (v2.ops == 1) { - result = new_rd_arm_Const_Neg(env->dbg, env->irg, env->block, env->mode); - set_arm_value(result, new_tarval_from_long(create_shifter_operand(v2.shifts[0], v2.values[0]), mode_Iu)); - } else { - if ( v2.ops < v1.ops ) { - negate = 1; - v = v2; - } else { - v = v1; - } - if (v.shifts[cnt] == 0) { - result = create_const_node(env, v.values[cnt]); - } else { - result = create_const_node(env, create_shifter_operand(v.shifts[cnt], v.values[cnt])); - } - ++cnt; - while(cnt < v.ops) { - ir_node *const_node = create_const_node(env, v.values[cnt]); - ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode); - set_arm_value(orr_i_node, new_tarval_from_long(create_shifter_operand(v.shifts[cnt], v.values[cnt]), mode_Iu)); - result = orr_i_node; - ++cnt; - } + gen_vals_from_word(value, &v); + gen_vals_from_word(~value, &vn); + + if (vn.ops < v.ops) { + /* remove bits */ + result = create_const_neg_node(env, arm_encode_imm_w_shift(vn.shifts[0], vn.values[0])); + + for (cnt = 1; cnt < vn.ops; ++cnt) { + tarval *tv = new_tarval_from_long(arm_encode_imm_w_shift(vn.shifts[cnt], vn.values[cnt]), mode_Iu); + ir_node *bic_i_node = new_rd_arm_Bic_i(env->dbg, env->irg, env->block, result, env->mode, tv); + result = bic_i_node; } } - if ( negate ) { - result = new_rd_arm_Not(env->dbg, env->irg, env->block, result, env->mode); + else { + /* add bits */ + result = create_const_node(env, arm_encode_imm_w_shift(v.shifts[0], v.values[0])); + + for (cnt = 1; cnt < v.ops; ++cnt) { + tarval *tv = new_tarval_from_long(arm_encode_imm_w_shift(v.shifts[cnt], v.values[cnt]), mode_Iu); + ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode, tv); + result = orr_i_node; + } } return result; } -// static ir_node *create_const_graph_value(arm_transform_env_t *env, unsigned int value) { -// ir_node *irn = env->irn; -// ir_node *result; -// int negate = 0; -// -// if ( ~value < 0x100 ) { -// negate = 1; -// value = ~value; -// } -// -// if (value < 0x100) { -// return create_const_node(env, value); -// } else { -// vals v = gen_vals_from_word(value); -// int cnt = 0; -// ir_node *mov_val = create_const_node(env, v.values[cnt]); -// if (v.shifts[cnt] != 0) { -// ir_node *shift_node = new_rd_arm_Shl_i(env->dbg, env->irg, env->block, mov_val, env->mode); -// set_arm_value(shift_node, new_tarval_from_long(v.shifts[cnt], mode_Iu)); -// result = shift_node; -// } else { -// result = mov_val; -// } -// ++cnt; -// while(cnt < v.ops) { -// ir_node *const_node = create_const_node(env, v.values[cnt]); -// ir_node *orr_i_node = new_rd_arm_Or_i(env->dbg, env->irg, env->block, result, env->mode); -// unsigned shift = v.shifts[cnt]; -// unsigned immediate = v.values[cnt]; -// unsigned immediate_with_shift = immediate | ((shift>>1)<<8); -// set_arm_value(orr_i_node, new_tarval_from_long(immediate_with_shift, mode_Iu)); -// result = orr_i_node; -// ++cnt; -// } -// return result; -// } -// } - static ir_node *create_const_graph(arm_transform_env_t *env) { int value = get_tarval_long(get_Const_tarval(env->irn)); return create_const_graph_value(env, value); @@ -196,7 +192,7 @@ static ir_node *gen_Const(arm_transform_env_t *env) { static ir_node *gen_mask(arm_transform_env_t *env, ir_node *op, int result_bits) { unsigned mask_bits = (1 << result_bits) - 1; ir_node *mask_node = create_const_graph_value(env, mask_bits); - return new_rd_arm_And(env->dbg, env->irg, env->block, op, mask_node, get_irn_mode(env->irn)); + return new_rd_arm_And(env->dbg, env->irg, env->block, op, mask_node, get_irn_mode(env->irn), ARM_SHF_NONE, NULL); } static ir_node *gen_sign_extension(arm_transform_env_t *env, ir_node *op, int result_bits) { @@ -207,7 +203,14 @@ static ir_node *gen_sign_extension(arm_transform_env_t *env, ir_node *op, int re return rshift_node; } -static ir_node *gen_Conv(arm_transform_env_t *env, ir_node *op) { +/** + * Transforms a Conv node. + * + * @param env The transformation environment + * @return the created arm Conv node + */ +static ir_node *gen_Conv(arm_transform_env_t *env) { + ir_node *op = get_Conv_op(env->irn); ir_mode *in_mode = get_irn_mode(op); ir_mode *out_mode = env->mode; @@ -290,8 +293,10 @@ static ir_node *gen_Conv(arm_transform_env_t *env, ir_node *op) { } else if (in_mode == mode_F && out_mode == mode_D) { return new_rd_arm_fConvS2D(env->dbg, env->irg, env->block, op, env->mode); } else if (mode_is_int(in_mode) && mode_is_float(out_mode)) { + env->cg->have_fp = 1; return env->irn; /* TODO: implement int->float conversion*/ } else if (mode_is_float(in_mode) && mode_is_int(out_mode)) { + env->cg->have_fp = 1; return env->irn; /* TODO: implement float->int conversion*/ } else { assert(0 && "not implemented conversion"); @@ -299,237 +304,272 @@ static ir_node *gen_Conv(arm_transform_env_t *env, ir_node *op) { } } +/** + * Return true if an operand is a shifter operand + */ +static int is_shifter_operand(ir_node *n, arm_shift_modifier *pmod) { + arm_shift_modifier mod = ARM_SHF_NONE; + + if (is_arm_Mov(n)) + mod = get_arm_shift_modifier(n); + + *pmod = mod; + if (mod != ARM_SHF_NONE) { + long v = get_tarval_long(get_arm_value(n)); + if (v < 32) + return (int)v; + } + return 0; +} /** * Creates an arm Add. * * @param env The transformation environment - * @param op1 first operator - * @param op2 second operator * @return the created arm Add node */ -static ir_node *gen_Add(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - ir_node *result = NULL; - assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort)); +static ir_node *gen_Add(arm_transform_env_t *env) { + ir_node *irn = env->irn; + ir_node *op1 = get_Add_left(irn); + ir_node *op2 = get_Add_right(irn); + ir_node *op3; + int v; + arm_shift_modifier mod; + assert(env->mode != mode_E && "IEEE Extended FP not supported"); - if (env->mode == mode_F) { - result = new_rd_arm_fAdds(env->dbg, env->irg, env->block, op1, op2, env->mode); - } else if (env->mode == mode_D) { - result = new_rd_arm_fAddd(env->dbg, env->irg, env->block, op1, op2, env->mode); - } else if (mode_is_numP(env->mode)) { - if (is_arm_Const(op1)) { - result = new_rd_arm_Add_i(env->dbg, env->irg, env->block, op2, env->mode); - set_arm_value(result, get_arm_value(op1)); - } else if (is_arm_Const(op2)) { - result = new_rd_arm_Add_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); - } else { - result = new_rd_arm_Add(env->dbg, env->irg, env->block, op1, op2, env->mode); - } - } else { - assert(0 && "unknown mode for add"); + if (mode_is_float(env->mode)) { + env->cg->have_fp = 1; + return new_rd_arm_fAdd(env->dbg, env->irg, env->block, op1, op2, env->mode); } - return result; -} + if (mode_is_numP(env->mode)) { + if (is_arm_Mov_i(op1)) + return new_rd_arm_Add_i(env->dbg, env->irg, env->block, op2, env->mode, + get_arm_value(op1)); + if (is_arm_Mov_i(op2)) + return new_rd_arm_Add_i(env->dbg, env->irg, env->block, op1, env->mode, + get_arm_value(op2)); + + /* check for MLA */ + if (is_arm_Mul(op1) && get_irn_n_edges(op1) == 1) { + op3 = op2; + op2 = get_irn_n(op1, 1); + op1 = get_irn_n(op1, 0); + + return new_rd_arm_Mla(env->dbg, env->irg, env->block, op1, op2, op3, env->mode); + } + if (is_arm_Mul(op2) && get_irn_n_edges(op2) == 1) { + op3 = op1; + op1 = get_irn_n(op2, 0); + op2 = get_irn_n(op2, 1); + + return new_rd_arm_Mla(env->dbg, env->irg, env->block, op1, op2, op3, env->mode); + } + /* is the first a shifter */ + v = is_shifter_operand(op1, &mod); + if (v) { + op1 = get_irn_n(op1, 0); + return new_rd_arm_Add(env->dbg, env->irg, env->block, op2, op1, env->mode, + mod, new_tarval_from_long(v, mode_Iu)); + } + /* is the second a shifter */ + v = is_shifter_operand(op2, &mod); + if (v) { + op2 = get_irn_n(op2, 0); + return new_rd_arm_Add(env->dbg, env->irg, env->block, op1, op2, env->mode, + mod, new_tarval_from_long(v, mode_Iu)); + } + /* normal ADD */ + return new_rd_arm_Add(env->dbg, env->irg, env->block, op1, op2, env->mode, ARM_SHF_NONE, NULL); + } + + assert(0 && "unknown mode for add"); + return NULL; +} /** * Creates an arm Mul. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Mul node */ -static ir_node *gen_Mul(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort)); +static ir_node *gen_Mul(arm_transform_env_t *env) { + ir_node *irn = env->irn; + ir_node *op1 = get_Mul_left(irn); + ir_node *op2 = get_Mul_right(irn); + assert(env->mode != mode_E && "IEEE Extended FP not supported"); - if (env->mode == mode_F) { - return new_rd_arm_fMuls(env->dbg, env->irg, env->block, op1, op2, env->mode); - } - if (env->mode == mode_D) { - return new_rd_arm_fMuld(env->dbg, env->irg, env->block, op1, op2, env->mode); + if (mode_is_float(env->mode)) { + env->cg->have_fp = 1; + return new_rd_arm_fMul(env->dbg, env->irg, env->block, op1, op2, env->mode); } return new_rd_arm_Mul(env->dbg, env->irg, env->block, op1, op2, env->mode); } - /** - * Creates an arm floating Div. + * Creates an arm floating point Div. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm fDiv node */ -static ir_node *gen_Quot(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - // assert(mode_is_float(env->mode) && "only floating point supported"); - assert(get_irn_mode(op1)->sort == get_irn_mode(op2)->sort); +static ir_node *gen_Quot(arm_transform_env_t *env) { + ir_node *irn = env->irn; + ir_node *op1 = get_Quot_left(irn); + ir_node *op2 = get_Quot_right(irn); + assert(mode_is_float(get_irn_mode(op1))); assert(get_irn_mode(op1) != mode_E && "IEEE Extended FP not supported"); - if (get_irn_mode(op1) == mode_F) { - return new_rd_arm_fDivs(env->dbg, env->irg, env->block, op1, op2, env->mode); - } - return new_rd_arm_fDivd(env->dbg, env->irg, env->block, op1, op2, env->mode); + return new_rd_arm_fDiv(env->dbg, env->irg, env->block, op1, op2, env->mode); +} + +#define GEN_INT_OP(op) \ +static ir_node *gen_ ## op(arm_transform_env_t *env) { \ + ir_node *irn = env->irn; \ + ir_node *op1 = get_ ## op ## _left(irn); \ + ir_node *op2 = get_ ## op ## _right(irn); \ + int v; \ + arm_shift_modifier mod; \ + \ + if (is_arm_Mov_i(op1)) \ + return new_rd_arm_ ## op ## _i(env->dbg, env->irg, env->block, op2, env->mode, \ + get_arm_value(op1)); \ + if (is_arm_Mov_i(op2)) \ + return new_rd_arm_ ## op ## _i(env->dbg, env->irg, env->block, op1, env->mode, \ + get_arm_value(op2)); \ + /* is the first a shifter */ \ + v = is_shifter_operand(op1, &mod); \ + if (v) { \ + op1 = get_irn_n(op1, 0); \ + return new_rd_arm_ ## op(env->dbg, env->irg, env->block, op2, op1, env->mode, \ + mod, new_tarval_from_long(v, mode_Iu)); \ + } \ + /* is the second a shifter */ \ + v = is_shifter_operand(op2, &mod); \ + if (v) { \ + op2 = get_irn_n(op2, 0); \ + return new_rd_arm_ ## op(env->dbg, env->irg, env->block, op1, op2, env->mode, \ + mod, new_tarval_from_long(v, mode_Iu)); \ + } \ + /* Normal op */ \ + return new_rd_arm_ ## op(env->dbg, env->irg, env->block, op1, op2, env->mode, ARM_SHF_NONE, NULL); \ } /** * Creates an arm And. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm And node */ -static ir_node *gen_And(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - ir_node *result; - if (is_arm_Const(op1)) { - result = new_rd_arm_And_i(env->dbg, env->irg, env->block, op2, env->mode); - set_arm_value(result, get_arm_value(op1)); - } else if (is_arm_Const(op2)) { - result = new_rd_arm_And_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); - } else { - result = new_rd_arm_And(env->dbg, env->irg, env->block, op1, op2, env->mode); - } - return result; -} - - +static ir_node *gen_And(arm_transform_env_t *env); +GEN_INT_OP(And) /** - * Creates an arm Or. + * Creates an arm Orr. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Or node */ -static ir_node *gen_Or(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - ir_node *result; - if (is_arm_Const(op1)) { - result = new_rd_arm_Or_i(env->dbg, env->irg, env->block, op2, env->mode); - set_arm_value(result, get_arm_value(op1)); - } else if (is_arm_Const(op2)) { - result = new_rd_arm_Or_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); - } else { - result = new_rd_arm_Or(env->dbg, env->irg, env->block, op1, op2, env->mode); - } - return result; -} - - +static ir_node *gen_Or(arm_transform_env_t *env); +GEN_INT_OP(Or) /** * Creates an arm Eor. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Eor node */ -static ir_node *gen_Eor(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - ir_node *result; - if (is_arm_Const(op1)) { - result = new_rd_arm_Eor_i(env->dbg, env->irg, env->block, op2, env->mode); - set_arm_value(result, get_arm_value(op1)); - } else if (is_arm_Const(op2)) { - result = new_rd_arm_Eor_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); - } else { - result = new_rd_arm_Eor(env->dbg, env->irg, env->block, op1, op2, env->mode); - } - return result; -} - - +static ir_node *gen_Eor(arm_transform_env_t *env); +GEN_INT_OP(Eor) /** * Creates an arm Sub. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Sub node */ -static ir_node *gen_Sub(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { - ir_node *result = NULL; - assert(!mode_is_float(env->mode) || (get_irn_mode(op1)->sort == get_irn_mode(op2)->sort)); +static ir_node *gen_Sub(arm_transform_env_t *env) { + ir_node *irn = env->irn; + ir_node *op1 = get_Sub_left(irn); + ir_node *op2 = get_Sub_right(irn); + int v; + arm_shift_modifier mod; + assert(env->mode != mode_E && "IEEE Extended FP not supported"); - if (env->mode == mode_F) { - result = new_rd_arm_fSubs(env->dbg, env->irg, env->block, op1, op2, env->mode); - } else if (env->mode == mode_D) { - result = new_rd_arm_fSubd(env->dbg, env->irg, env->block, op1, op2, env->mode); - } else if (mode_is_numP(env->mode)) { - if (is_arm_Const(op2)) { - result = new_rd_arm_Sub_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); - } else { - result = new_rd_arm_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode); + if (mode_is_float(env->mode)) { + env->cg->have_fp = 1; + return new_rd_arm_fSub(env->dbg, env->irg, env->block, op1, op2, env->mode); + } + if (mode_is_numP(env->mode)) { + if (is_arm_Mov_i(op1)) + return new_rd_arm_Rsb_i(env->dbg, env->irg, env->block, op2, env->mode, + get_arm_value(op1)); + if (is_arm_Mov_i(op2)) + return new_rd_arm_Sub_i(env->dbg, env->irg, env->block, op1, env->mode, + get_arm_value(op2)); + + /* is the first a shifter */ + v = is_shifter_operand(op1, &mod); + if (v) { + op1 = get_irn_n(op1, 0); + return new_rd_arm_Rsb(env->dbg, env->irg, env->block, op2, op1, env->mode, + mod, new_tarval_from_long(v, mode_Iu)); } - } else { - assert(0 && "unknown mode for sub"); + /* is the second a shifter */ + v = is_shifter_operand(op2, &mod); + if (v) { + op2 = get_irn_n(op2, 0); + return new_rd_arm_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode, + mod, new_tarval_from_long(v, mode_Iu)); + } + /* normal sub */ + return new_rd_arm_Sub(env->dbg, env->irg, env->block, op1, op2, env->mode, ARM_SHF_NONE, NULL); } - return result; + assert(0 && "unknown mode for sub"); + return NULL; } /** * Creates an arm Shl. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Shl node */ -static ir_node *gen_Shl(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { +static ir_node *gen_Shl(arm_transform_env_t *env) { ir_node *result; - if (is_arm_Const(op2)) { - result = new_rd_arm_Shl_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); + ir_node *irn = env->irn; + ir_node *op1 = get_Shl_left(irn); + ir_node *op2 = get_Shl_right(irn); + + if (is_arm_Mov_i(op2)) { + result = new_rd_arm_Mov(env->dbg, env->irg, env->block, op1, env->mode, + ARM_SHF_LSL, get_arm_value(op2)); } else { result = new_rd_arm_Shl(env->dbg, env->irg, env->block, op1, op2, env->mode); } return result; } - - /** * Creates an arm Shr. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Shr node */ -static ir_node *gen_Shr(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { +static ir_node *gen_Shr(arm_transform_env_t *env) { ir_node *result; - if (is_arm_Const(op2)) { - result = new_rd_arm_Shr_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); + ir_node *irn = env->irn; + ir_node *op1 = get_Shr_left(irn); + ir_node *op2 = get_Shr_right(irn); + + if (is_arm_Mov_i(op2)) { + result = new_rd_arm_Mov(env->dbg, env->irg, env->block, op1, env->mode, + ARM_SHF_LSR, get_arm_value(op2)); } else { result = new_rd_arm_Shr(env->dbg, env->irg, env->block, op1, op2, env->mode); } @@ -539,18 +579,18 @@ static ir_node *gen_Shr(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { /** * Creates an arm Shrs. * - * @param dbg firm node dbg - * @param block the block the new node should belong to - * @param op1 first operator - * @param op2 second operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Shrs node */ -static ir_node *gen_Shrs(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { +static ir_node *gen_Shrs(arm_transform_env_t *env) { ir_node *result; - if (is_arm_Const(op2)) { - result = new_rd_arm_Shrs_i(env->dbg, env->irg, env->block, op1, env->mode); - set_arm_value(result, get_arm_value(op2)); + ir_node *irn = env->irn; + ir_node *op1 = get_Shrs_left(irn); + ir_node *op2 = get_Shrs_right(irn); + + if (is_arm_Mov_i(op2)) { + result = new_rd_arm_Mov(env->dbg, env->irg, env->block, op1, env->mode, + ARM_SHF_ASR, get_arm_value(op2)); } else { result = new_rd_arm_Shrs(env->dbg, env->irg, env->block, op1, op2, env->mode); } @@ -560,50 +600,57 @@ static ir_node *gen_Shrs(arm_transform_env_t *env, ir_node *op1, ir_node *op2) { /** * Transforms a Not node. * - * @param mod the debug module - * @param block the block the new node should belong to - * @param node the ir Not node - * @param op operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Not node */ -static ir_node *gen_Not(arm_transform_env_t *env, ir_node *op) { - return new_rd_arm_Not(env->dbg, env->irg, env->block, op, env->mode); +static ir_node *gen_Not(arm_transform_env_t *env) { + ir_node *op = get_Not_op(env->irn); + int v; + arm_shift_modifier mod = ARM_SHF_NONE; + tarval *tv = NULL; + + v = is_shifter_operand(op, &mod); + if (v) { + op = get_irn_n(op, 0); + tv = new_tarval_from_long(v, mode_Iu); + } + return new_rd_arm_Mvn(env->dbg, env->irg, env->block, op, env->mode, mod, tv); } +/** + * Transforms an Abs node. + * + * @param env The transformation environment + * @return the created arm Abs node + */ +static ir_node *gen_Abs(arm_transform_env_t *env) { + ir_node *op = get_Abs_op(env->irn); -static ir_node *gen_Abs(arm_transform_env_t *env, ir_node *op) { assert(env->mode != mode_E && "IEEE Extended FP not supported"); - if (env->mode == mode_F) { - return new_rd_arm_fAbss(env->dbg, env->irg, env->block, op, env->mode); - } - if (env->mode == mode_D) { - return new_rd_arm_fAbsd(env->dbg, env->irg, env->block, op, env->mode); + if (mode_is_float(env->mode)) { + env->cg->have_fp = 1; + return new_rd_arm_fAbs(env->dbg, env->irg, env->block, op, env->mode); } return new_rd_arm_Abs(env->dbg, env->irg, env->block, op, env->mode); } - /** * Transforms a Minus node. * - * @param mod the debug module - * @param block the block the new node should belong to - * @param node the ir Minus node - * @param op operator - * @param mode node mode + * @param env The transformation environment * @return the created arm Minus node */ -static ir_node *gen_Minus(arm_transform_env_t *env, ir_node *op) { +static ir_node *gen_Minus(arm_transform_env_t *env) { + ir_node *op = get_Minus_op(env->irn); + if (mode_is_float(env->mode)) { return new_rd_arm_fMinus(env->dbg, env->irg, env->block, op, env->mode); } - return new_rd_arm_Minus(env->dbg, env->irg, env->block, op, env->mode); + return new_rd_arm_Rsb_i(env->dbg, env->irg, env->block, op, env->mode, get_mode_null(env->mode)); } - /** * Transforms a Load. * @@ -617,22 +664,10 @@ static ir_node *gen_Load(arm_transform_env_t *env) { ir_node *node = env->irn; ir_mode *mode = get_Load_mode(node); -// const ir_edge_t *edge; -// -// foreach_out_edge(node, edge) { -// ir_node* proj = get_edge_src_irn(edge); -// long nr = get_Proj_proj(proj); -// if ( nr == pn_Load_res ) -// mode = proj->mode; -// } -// besser: get_Load_mode() verwenden! - - assert(mode!=NULL && "irgendwie hat das load kein proj fuers result"); - if (mode==mode_F) { - return new_rd_arm_fLoads(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); - } - if (mode==mode_D) { - return new_rd_arm_fLoadd(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); + if (mode_is_float(mode)) { + env->cg->have_fp = 1; + /* FIXME: set the load mode */ + return new_rd_arm_fLoad(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); } if (mode == mode_Bu) { return new_rd_arm_Loadb(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); @@ -652,8 +687,6 @@ static ir_node *gen_Load(arm_transform_env_t *env) { return new_rd_arm_Load(env->dbg, env->irg, env->block, get_Load_ptr(node), get_Load_mem(node), env->mode); } - - /** * Transforms a Store. * @@ -668,11 +701,10 @@ static ir_node *gen_Store(arm_transform_env_t *env) { ir_mode *mode = get_irn_mode(get_Store_value(node)); assert(env->mode != mode_E && "IEEE Extended FP not supported"); - if (mode == mode_F) { - return new_rd_arm_fStores(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode); - } - if (mode == mode_D) { - return new_rd_arm_fStored(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode); + if (mode_is_float(mode)) { + env->cg->have_fp = 1; + /* FIXME: set the store mode */ + return new_rd_arm_fStore(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode); } if (mode == mode_Bu) { return new_rd_arm_Storeb(env->dbg, env->irg, env->block, get_Store_ptr(node), get_Store_value(node), get_Store_mem(node), env->mode); @@ -753,7 +785,7 @@ static ir_node *gen_Cond(arm_transform_env_t *env) { const_env.mode = mode_Is; const_env.irn = const_node; const_graph = gen_Const(&const_env); - sub = new_rd_arm_Sub(env->dbg, env->irg, env->block, op, const_graph, get_irn_mode(op)); + sub = new_rd_arm_Sub(env->dbg, env->irg, env->block, op, const_graph, get_irn_mode(op), ARM_SHF_NONE, NULL); result = new_rd_arm_SwitchJmp(env->dbg, env->irg, env->block, sub, mode_T); set_arm_n_projs(result, n_projs); set_arm_default_proj_num(result, get_Cond_defaultProj(irn)-translation); @@ -785,17 +817,12 @@ const char *get_sc_name(ir_node *symc) { } static ir_node *gen_SymConst(arm_transform_env_t *env) { - ir_node *result; - const char *str = get_sc_name(env->irn); - result = new_rd_arm_SymConst(env->dbg, env->irg, env->block, env->mode); - set_arm_symconst_label(result, str); - return result; + return new_rd_arm_SymConst(env->dbg, env->irg, env->block, + env->mode, get_sc_name(env->irn)); } - - /** * Transforms a CopyB node. * @@ -824,8 +851,8 @@ static ir_node *gen_CopyB(arm_transform_env_t *env) { DEBUG_ONLY(const_env.mod = env->mod;) const_env.mode = mode_Iu; - src_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], irg, block, src); - dst_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], irg, block, dst); + src_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], irg, block, src); + dst_copy = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], irg, block, dst); res = new_rd_arm_CopyB( dbg, irg, block, dst_copy, src_copy, new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), new_rd_arm_EmptyReg(dbg, irg, block, mode_Iu), mem, mode); set_arm_value(res, new_tarval_from_long(size, mode_Iu)); @@ -837,10 +864,182 @@ static ir_node *gen_CopyB(arm_transform_env_t *env) { -// /************************************************************************/ -// /* be transforms */ -// /************************************************************************/ -// +/******************************************** + * _ _ + * | | | | + * | |__ ___ _ __ ___ __| | ___ ___ + * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __| + * | |_) | __/ | | | (_) | (_| | __/\__ \ + * |_.__/ \___|_| |_|\___/ \__,_|\___||___/ + * + ********************************************/ + +/** + * Return an expanding stack offset. + * Note that function is called in the transform phase + * where the stack offsets are still relative regarding + * the first (frame allocating) IncSP. + * However this is exactly what we want because frame + * access must be done relative the the fist IncSP ... + */ +static int get_sp_expand_offset(ir_node *inc_sp) { + unsigned offset = be_get_IncSP_offset(inc_sp); + be_stack_dir_t dir = be_get_IncSP_direction(inc_sp); + + if (offset == BE_STACK_FRAME_SIZE) + return 0; + return dir == be_stack_dir_expand ? (int)offset : -(int)offset; +} + +static ir_node *gen_StackParam(arm_transform_env_t *env) { +#if 0 + ir_node *new_op = NULL; + ir_node *node = env->irn; + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *mem = new_rd_NoMem(env->irg); + ir_node *ptr = get_irn_n(node, 0); + entity *ent = be_get_frame_entity(node); + ir_mode *mode = env->mode; + +// /* If the StackParam has only one user -> */ +// /* put it in the Block where the user resides */ +// if (get_irn_n_edges(node) == 1) { +// env->block = get_nodes_block(get_edge_src_irn(get_irn_out_edge_first(node))); +// } + + if (mode_is_float(mode)) { + if (USE_SSE2(env->cg)) + new_op = new_rd_ia32_fLoad(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T); + else { + env->cg->used_x87 = 1; + new_op = new_rd_ia32_vfld(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T); + } + } + else { + new_op = new_rd_ia32_Load(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T); + } + + set_ia32_frame_ent(new_op, ent); + set_ia32_use_frame(new_op); + + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); + set_ia32_am_flavour(new_op, ia32_B); + set_ia32_ls_mode(new_op, mode); + + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn)); + + return new_rd_Proj(env->dbg, env->irg, env->block, new_op, mode, 0); +#endif +} + +/** + * Transforms a FrameAddr into an ia32 Add. + */ +static ir_node *gen_be_FrameAddr(arm_transform_env_t *env) { + ir_node *node = env->irn; + entity *ent = be_get_frame_entity(node); + int offset = get_entity_offset_bytes(ent); + ir_node *op = get_irn_n(node, 0); + ir_node *cnst; + + if (be_is_IncSP(op)) { + /* BEWARE: we get an offset which is absolute from an offset that + is relative. Both must be merged */ + offset += get_sp_expand_offset(op); + } + cnst = create_const_graph_value(env, (unsigned)offset); + if (is_arm_Mov_i(cnst)) { + return new_rd_arm_Add_i(env->dbg, env->irg, env->block, op, env->mode, + get_arm_value(cnst)); + } + return new_rd_arm_Add(env->dbg, env->irg, env->block, op, cnst, env->mode, ARM_SHF_NONE, NULL); +} + +/** + * Transforms a FrameLoad into an ia32 Load. + */ +static ir_node *gen_FrameLoad(arm_transform_env_t *env) { +#if 0 + ir_node *new_op = NULL; + ir_node *node = env->irn; + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *mem = get_irn_n(node, 0); + ir_node *ptr = get_irn_n(node, 1); + entity *ent = be_get_frame_entity(node); + ir_mode *mode = get_type_mode(get_entity_type(ent)); + + if (mode_is_float(mode)) { + if (USE_SSE2(env->cg)) + new_op = new_rd_ia32_fLoad(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T); + else { + env->cg->used_x87 = 1; + new_op = new_rd_ia32_vfld(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T); + } + } + else { + new_op = new_rd_ia32_Load(env->dbg, env->irg, env->block, ptr, noreg, mem, mode_T); + } + + set_ia32_frame_ent(new_op, ent); + set_ia32_use_frame(new_op); + + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_op_type(new_op, ia32_AddrModeS); + set_ia32_am_flavour(new_op, ia32_B); + set_ia32_ls_mode(new_op, mode); + + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn)); + + return new_op; +#endif +} + + +/** + * Transforms a FrameStore into an ia32 Store. + */ +static ir_node *gen_FrameStore(arm_transform_env_t *env) { +#if 0 + ir_node *new_op = NULL; + ir_node *node = env->irn; + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *mem = get_irn_n(node, 0); + ir_node *ptr = get_irn_n(node, 1); + ir_node *val = get_irn_n(node, 2); + entity *ent = be_get_frame_entity(node); + ir_mode *mode = get_irn_mode(val); + + if (mode_is_float(mode)) { + if (USE_SSE2(env->cg)) + new_op = new_rd_ia32_fStore(env->dbg, env->irg, env->block, ptr, noreg, val, mem, mode_T); + else { + env->cg->used_x87 = 1; + new_op = new_rd_ia32_vfst(env->dbg, env->irg, env->block, ptr, noreg, val, mem, mode_T); + } + } + else if (get_mode_size_bits(mode) == 8) { + new_op = new_rd_ia32_Store8Bit(env->dbg, env->irg, env->block, ptr, noreg, val, mem, mode_T); + } + else { + new_op = new_rd_ia32_Store(env->dbg, env->irg, env->block, ptr, noreg, val, mem, mode_T); + } + + set_ia32_frame_ent(new_op, ent); + set_ia32_use_frame(new_op); + + set_ia32_am_support(new_op, ia32_am_Dest); + set_ia32_op_type(new_op, ia32_AddrModeD); + set_ia32_am_flavour(new_op, ia32_B); + set_ia32_ls_mode(new_op, mode); + + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn)); + + return new_op; +#endif +} + + // static ir_node *gen_be_Copy(arm_transform_env_t *env, ir_node *op) { // return new_rd_arm_Copy(env->dbg, env->irg, env->block, op, env->mode); // } @@ -860,21 +1059,24 @@ static ir_node *gen_CopyB(arm_transform_env_t *env) { /************************************************************************/ void arm_move_consts(ir_node *node, void *env) { arm_code_gen_t *cgenv = (arm_code_gen_t *)env; + arm_transform_env_t tenv; int i; + if (is_Block(node)) return; + + tenv.irg = current_ir_graph; + DEBUG_ONLY(tenv.mod = cgenv->mod); + if (is_Phi(node)) { - for (i=0; imod;) tenv.mode = get_irn_mode(pred); const_graph = create_const_graph(&tenv); set_irn_n(node, i, const_graph); @@ -882,33 +1084,30 @@ void arm_move_consts(ir_node *node, void *env) { const char *str = get_sc_name(pred); ir_node *symconst_node; symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred), - current_ir_graph, get_nodes_block(get_irn_n(get_nodes_block(node),i)), get_irn_mode(pred)); - set_arm_symconst_label(symconst_node, str); + current_ir_graph, get_nodes_block(get_irn_n(get_nodes_block(node),i)), + get_irn_mode(pred), str); set_irn_n(node, i, symconst_node); } } return; } - for (i=0; imod;) - tenv.mode = get_irn_mode(pred); + tenv.block = get_nodes_block(node); + tenv.dbg = get_irn_dbg_info(pred); + tenv.irn = pred; + tenv.mode = get_irn_mode(pred); const_graph = create_const_graph(&tenv); set_irn_n(node, i, const_graph); } else if (pred_code == iro_SymConst) { const char *str = get_sc_name(pred); ir_node *symconst_node; symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred), - current_ir_graph, get_nodes_block(node), get_irn_mode(pred)); - set_arm_symconst_label(symconst_node, str); + current_ir_graph, get_nodes_block(node), + get_irn_mode(pred), str); set_irn_n(node, i, symconst_node); } } @@ -924,7 +1123,7 @@ void arm_move_symconsts(ir_node *node, void *env) { if (is_Block(node)) return; - for (i = 0; i < get_irn_arity(node); i++) { + for (i = 0; i < get_irn_arity(node); i++) { ir_node *pred = get_irn_n(node,i); opcode pred_code = get_irn_opcode(pred); @@ -933,14 +1132,118 @@ void arm_move_symconsts(ir_node *node, void *env) { ir_node *symconst_node; symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred), - current_ir_graph, get_nodes_block(node), get_irn_mode(pred)); - - set_arm_symconst_label(symconst_node, str); + current_ir_graph, get_nodes_block(node), get_irn_mode(pred), str); set_irn_n(node, i, symconst_node); } } } +/** + * the BAD transformer. + */ +static ir_node *bad_transform(arm_transform_env_t *env) { + ir_fprintf(stderr, "Not implemented: %+F\n", env->irn); + assert(0); + return NULL; +} + +/** + * Enters all transform functions into the generic pointer + */ +void arm_register_transformers(void) { + ir_op *op_Max, *op_Min, *op_Mulh; + + /* first clear the generic function pointer for all ops */ + clear_irp_opcodes_generic_func(); + +#define FIRM_OP(a) op_##a->ops.generic = (op_func)gen_##a +#define BAD(a) op_##a->ops.generic = (op_func)bad_transform +#define IGN(a) + + FIRM_OP(Add); // done + FIRM_OP(Mul); // done + FIRM_OP(Quot); // done + FIRM_OP(And); // done + FIRM_OP(Or); // done + FIRM_OP(Eor); // done + + FIRM_OP(Sub); // done + FIRM_OP(Shl); // done + FIRM_OP(Shr); // done + FIRM_OP(Shrs); // done + + FIRM_OP(Minus); // done + FIRM_OP(Not); // done + FIRM_OP(Abs); // done + + FIRM_OP(CopyB); // done + FIRM_OP(Const); // TODO: floating point consts + FIRM_OP(Conv); // TODO: floating point conversions + + FIRM_OP(Load); // done + FIRM_OP(Store); // done + + FIRM_OP(SymConst); + FIRM_OP(Cond); // integer done + + /* TODO: implement these nodes */ + + IGN(Div); // intrinsic lowering + IGN(Mod); // intrinsic lowering + IGN(DivMod); // TODO: implement DivMod + + IGN(Mux); + IGN(Unknown); + IGN(Cmp); // done, implemented in cond + + /* You probably don't need to handle the following nodes */ + + IGN(Call); + IGN(Proj); + IGN(Alloc); + + IGN(Block); + IGN(Start); + IGN(End); + IGN(NoMem); + IGN(Phi); + IGN(IJmp); + IGN(Jmp); // emitter done + IGN(Break); + IGN(Sync); + + BAD(Raise); + BAD(Sel); + BAD(InstOf); + BAD(Cast); + BAD(Free); + BAD(Tuple); + BAD(Id); + BAD(Bad); + BAD(Confirm); + BAD(Filter); + BAD(CallBegin); + BAD(EndReg); + BAD(EndExcept); + + FIRM_OP(be_FrameAddr); + + op_Max = get_op_Max(); + if (op_Max) + BAD(Max); + op_Min = get_op_Min(); + if (op_Min) + BAD(Min); + op_Mulh = get_op_Mulh(); + if (op_Mulh) + BAD(Mulh); + +#undef IGN +#undef FIRM_OP +#undef BAD +} + +typedef ir_node *(transform_func)(arm_transform_env_t *env); /** * Transforms the given firm node (and maybe some other related nodes) @@ -950,115 +1253,35 @@ void arm_move_symconsts(ir_node *node, void *env) { * @param env the debug module */ void arm_transform_node(ir_node *node, void *env) { - arm_code_gen_t *cgenv = (arm_code_gen_t *)env; - opcode code = get_irn_opcode(node); - ir_node *asm_node = NULL; - arm_transform_env_t tenv; + arm_code_gen_t *cg = (arm_code_gen_t *)env; + ir_op *op = get_irn_op(node); + ir_node *asm_node = NULL; - if (is_Block(node)) + if (op == op_Block) return; - tenv.block = get_nodes_block(node); - tenv.dbg = get_irn_dbg_info(node); - tenv.irg = current_ir_graph; - tenv.irn = node; - DEBUG_ONLY(tenv.mod = cgenv->mod;) - tenv.mode = get_irn_mode(node); - -#define UNOP(a) case iro_##a: asm_node = gen_##a(&tenv, get_##a##_op(node)); break -#define BINOP(a) case iro_##a: asm_node = gen_##a(&tenv, get_##a##_left(node), get_##a##_right(node)); break -#define GEN(a) case iro_##a: asm_node = gen_##a(&tenv); break -#define IGN(a) case iro_##a: break -#define BAD(a) case iro_##a: goto bad - - DBG((tenv.mod, LEVEL_1, "check %+F ... ", node)); - - switch (code) { - BINOP(Add); // done - BINOP(Mul); // done - BINOP(Quot); // done - BINOP(And); // done - BINOP(Or); // done - BINOP(Eor); // done - - BINOP(Sub); // done - BINOP(Shl); // done - BINOP(Shr); // done - BINOP(Shrs); // done - - UNOP(Minus); // done - UNOP(Not); // done - UNOP(Abs); // done - - GEN(CopyB); // done - GEN(Const); // TODO: floating point consts - UNOP(Conv); // TODO: floating point conversions - - GEN(Load); // done - GEN(Store); // done - - GEN(SymConst); - GEN(Cond); // integer done - - /* TODO: implement these nodes */ - - IGN(Div); // intrinsic lowering - IGN(Mod); // intrinsic lowering - IGN(DivMod); // TODO: implement DivMod - - IGN(Mux); - IGN(Unknown); - IGN(Cmp); // done, implemented in cond - - /* You probably don't need to handle the following nodes */ - - IGN(Call); - IGN(Proj); - IGN(Alloc); - - IGN(Block); - IGN(Start); - IGN(End); - IGN(NoMem); - IGN(Phi); - IGN(IJmp); - IGN(Jmp); // emitter done - IGN(Break); - IGN(Sync); - - BAD(Raise); - BAD(Sel); - BAD(InstOf); - BAD(Cast); - BAD(Free); - BAD(Tuple); - BAD(Id); - BAD(Bad); - BAD(Confirm); - BAD(Filter); - BAD(CallBegin); - BAD(EndReg); - BAD(EndExcept); + DBG((cg->mod, LEVEL_1, "check %+F ... ", node)); - default: - if (get_irn_op(node) == get_op_Max() || - get_irn_op(node) == get_op_Min() || - get_irn_op(node) == get_op_Mulh()) - { - /* TODO: implement */ - /* ignore for now */ - } - break; -bad: - fprintf(stderr, "Not implemented: %s\n", get_irn_opname(node)); - assert(0); + if (op->ops.generic) { + arm_transform_env_t tenv; + transform_func *transform = (transform_func *)op->ops.generic; + + tenv.cg = cg; + tenv.block = get_nodes_block(node); + tenv.dbg = get_irn_dbg_info(node); + tenv.irg = current_ir_graph; + tenv.irn = node; + tenv.mode = get_irn_mode(node); + DEBUG_ONLY(tenv.mod = cg->mod); + + asm_node = (*transform)(&tenv); } if (asm_node) { exchange(node, asm_node); - DB((tenv.mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node)); + DB((cg->mod, LEVEL_1, "created node %+F[%p]\n", asm_node, asm_node)); } else { - DB((tenv.mod, LEVEL_1, "ignored\n")); + DB((cg->mod, LEVEL_1, "ignored\n")); } } diff --git a/ir/be/arm/arm_transform.h b/ir/be/arm/arm_transform.h index b61ac20c6..bfecd8e33 100644 --- a/ir/be/arm/arm_transform.h +++ b/ir/be/arm/arm_transform.h @@ -3,6 +3,8 @@ void arm_move_consts(ir_node *node, void *env); void arm_move_symconsts(ir_node *node, void *env); + +void arm_register_transformers(void); void arm_transform_node(ir_node *node, void *env); #endif /* _ARM_TRANSFORM_H_ */ diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index 64f0022fa..7ade4654b 100644 --- a/ir/be/arm/bearch_arm.c +++ b/ir/be/arm/bearch_arm.c @@ -122,10 +122,10 @@ static const arch_register_req_t *arm_get_irn_reg_req(const void *self, arch_reg DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn)); if (mode_is_float(mode)) { - memcpy(req, &(arm_default_req_arm_floating_point.req), sizeof(*req)); + memcpy(req, &(arm_default_req_arm_fp.req), sizeof(*req)); } else if (mode_is_int(mode) || mode_is_reference(mode)) { - memcpy(req, &(arm_default_req_arm_general_purpose.req), sizeof(*req)); + memcpy(req, &(arm_default_req_arm_gp.req), sizeof(*req)); } else if (mode == mode_T || mode == mode_M) { DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn)); @@ -265,12 +265,13 @@ arm_irn_ops_t arm_irn_ops = { **************************************************/ /** - * Transforms the standard firm graph into - * a ARM firm graph + * Transforms the standard Firm graph into + * a ARM firm graph. */ static void arm_prepare_graph(void *self) { arm_code_gen_t *cg = self; + arm_register_transformers(); irg_walk_blkwise_graph(cg->irg, arm_move_consts, arm_transform_node, cg); } @@ -470,7 +471,7 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) { arm_isa_t *isa = (arm_isa_t *)birg->main_env->arch_env->isa; arm_code_gen_t *cg; - if (! int_tp) { + if (! int_tp) { /* create an integer type with machine size */ int_tp = new_type_primitive(new_id_from_chars("int", 3), mode_Is); } @@ -483,6 +484,7 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) { cg->arch_env = birg->main_env->arch_env; cg->birg = birg; cg->int_tp = int_tp; + cg->have_fp = 0; FIRM_DBG_REGISTER(cg->mod, "firm.be.arm.cg"); isa->num_codegens++; @@ -496,6 +498,9 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) { arm_irn_ops.cg = cg; + /* enter the current code generator */ + isa->cg = cg; + return (arch_code_generator_t *)cg; } @@ -505,7 +510,7 @@ static void *arm_cg_init(FILE *F, const be_irg_t *birg) { * and map all instructions the backend did not support * to runtime calls. */ -void arm_global_init(void) { +static void arm_global_init(void) { ir_type *tp, *int_tp, *uint_tp; i_record records[8]; int n_records = 0; @@ -515,6 +520,7 @@ void arm_global_init(void) { int_tp = new_type_primitive(ID("int"), mode_Is); uint_tp = new_type_primitive(ID("uint"), mode_Iu); + /* ARM has neither a signed div instruction ... */ { runtime_rt rt_Div; i_instr_record *map_Div = &records[n_records++].i_instr; @@ -538,6 +544,7 @@ void arm_global_init(void) { map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall; map_Div->ctx = &rt_Div; } + /* ... nor a signed div instruction ... */ { runtime_rt rt_Div; i_instr_record *map_Div = &records[n_records++].i_instr; @@ -561,6 +568,7 @@ void arm_global_init(void) { map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall; map_Div->ctx = &rt_Div; } + /* ... nor a signed mod instruction ... */ { runtime_rt rt_Mod; i_instr_record *map_Mod = &records[n_records++].i_instr; @@ -584,6 +592,7 @@ void arm_global_init(void) { map_Mod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall; map_Mod->ctx = &rt_Mod; } + /* ... nor a unsigned mod. */ { runtime_rt rt_Mod; i_instr_record *map_Mod = &records[n_records++].i_instr; @@ -623,11 +632,13 @@ void arm_global_init(void) { *****************************************************************/ static arm_isa_t arm_isa_template = { - &arm_isa_if, /* isa interface */ - &arm_general_purpose_regs[REG_R13], /* stack pointer */ - &arm_general_purpose_regs[REG_R11], /* base pointer */ - -1, /* stack direction */ - 0 /* number of codegenerator objects */ + &arm_isa_if, /* isa interface */ + &arm_gp_regs[REG_SP], /* stack pointer */ + &arm_gp_regs[REG_R11], /* base pointer */ + -1, /* stack direction */ + 0, /* number of codegenerator objects */ + 0, /* use generic register names instead of SP, LR, PC */ + NULL /* current code generator */ }; /** @@ -640,39 +651,57 @@ static void *arm_init(void) { if(inited) return NULL; - isa = xcalloc(1, sizeof(*isa)); + isa = xmalloc(sizeof(*isa)); memcpy(isa, &arm_isa_template, sizeof(*isa)); arm_register_init(isa); + if (isa->gen_reg_names) { + /* patch register names */ + arm_gp_regs[REG_R11].name = "r11"; + arm_gp_regs[REG_SP].name = "r13"; + arm_gp_regs[REG_LR].name = "r14"; + arm_gp_regs[REG_PC].name = "r15"; + } + + isa->cg = NULL; + arm_create_opcodes(); + arm_global_init(); + arm_switch_section(NULL, NO_SECTION); inited = 1; - return isa; } /** - * Closes the output file and frees the ISA structure. + * frees the ISA structure. */ static void arm_done(void *self) { free(self); } - +/** + * Report the number of register classes. + * If we don't have fp instructions, report only GP + * here to speed up register allocation (and makes dumps + * smaller and more readable). + */ static int arm_get_n_reg_class(const void *self) { - return N_CLASSES; + const arm_isa_t *isa = self; + + return isa->cg->have_fp ? 2 : 1; } +/** + * Return the register class with requested index. + */ static const arch_register_class_t *arm_get_reg_class(const void *self, int i) { - assert(i >= 0 && i < N_CLASSES && "Invalid arm register class requested."); - return &arm_reg_classes[i]; + return i == 0 ? &arm_reg_classes[CLASS_arm_gp] : &arm_reg_classes[CLASS_arm_fp]; } - - /** * Get the register class which shall be used to store a value of a given mode. * @param self The this pointer. @@ -681,13 +710,11 @@ static const arch_register_class_t *arm_get_reg_class(const void *self, int i) { */ const arch_register_class_t *arm_get_reg_class_for_mode(const void *self, const ir_mode *mode) { if (mode_is_float(mode)) - return &arm_reg_classes[CLASS_arm_floating_point]; + return &arm_reg_classes[CLASS_arm_fp]; else - return &arm_reg_classes[CLASS_arm_general_purpose]; + return &arm_reg_classes[CLASS_arm_gp]; } - - /** * Produces the type which sits between the stack args and the locals on the stack. * it will contain the return address and space to store the old base pointer. @@ -715,12 +742,6 @@ static ir_type *arm_get_between_type(void *self) { } - - - - - - typedef struct { be_abi_call_flags_bits_t flags; const arch_env_t *arch_env; @@ -730,7 +751,7 @@ typedef struct { static void *arm_abi_init(const be_abi_call_t *call, const arch_env_t *arch_env, ir_graph *irg) { - arm_abi_env_t *env = xmalloc(sizeof(env[0])); + arm_abi_env_t *env = xmalloc(sizeof(env[0])); be_abi_call_flags_t fl = be_abi_call_get_flags(call); env->flags = fl.bits; env->irg = irg; @@ -758,37 +779,37 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * ir_node *block = get_irg_start_block(irg); // ir_node *regs[16]; // int n_regs = 0; - arch_register_class_t *gp = &arm_reg_classes[CLASS_arm_general_purpose]; + arch_register_class_t *gp = &arm_reg_classes[CLASS_arm_gp]; static const arm_register_req_t *fp_req[] = { - &arm_default_req_arm_general_purpose_r11 + &arm_default_req_arm_gp_r11 }; ir_node *fp = be_abi_reg_map_get(reg_map, env->isa->bp); - ir_node *ip = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R12]); + ir_node *ip = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R12]); ir_node *sp = be_abi_reg_map_get(reg_map, env->isa->sp); - ir_node *lr = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R14]); - ir_node *pc = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R15]); -// ir_node *r0 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R0]); -// ir_node *r1 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R1]); -// ir_node *r2 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R2]); -// ir_node *r3 = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R3]); + ir_node *lr = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_LR]); + ir_node *pc = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_PC]); +// ir_node *r0 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R0]); +// ir_node *r1 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R1]); +// ir_node *r2 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R2]); +// ir_node *r3 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R3]); if(env->flags.try_omit_fp) return env->isa->sp; ip = be_new_Copy(gp, irg, block, sp ); - arch_set_irn_register(env->arch_env, ip, &arm_general_purpose_regs[REG_R12]); - be_set_constr_single_reg(ip, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R12] ); + arch_set_irn_register(env->arch_env, ip, &arm_gp_regs[REG_R12]); + be_set_constr_single_reg(ip, BE_OUT_POS(0), &arm_gp_regs[REG_R12] ); // if (r0) regs[n_regs++] = r0; // if (r1) regs[n_regs++] = r1; // if (r2) regs[n_regs++] = r2; // if (r3) regs[n_regs++] = r3; // sp = new_r_arm_StoreStackMInc(irg, block, *mem, sp, n_regs, regs, get_irn_mode(sp)); -// set_arm_req_out(sp, &arm_default_req_arm_general_purpose_r13, 0); +// set_arm_req_out(sp, &arm_default_req_arm_gp_sp, 0); // arch_set_irn_register(env->arch_env, sp, env->isa->sp); store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem, mode_T); - set_arm_req_out(store, &arm_default_req_arm_general_purpose_r13, 0); + set_arm_req_out(store, &arm_default_req_arm_gp_sp, 0); // arch_set_irn_register(env->arch_env, store, env->isa->sp); sp = new_r_Proj(irg, block, store, env->isa->sp->reg_class->mode, 0); @@ -797,24 +818,24 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * keep = be_new_CopyKeep_single(gp, irg, block, ip, sp, get_irn_mode(ip)); be_node_set_reg_class(keep, 1, gp); - arch_set_irn_register(env->arch_env, keep, &arm_general_purpose_regs[REG_R12]); - be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R12] ); + arch_set_irn_register(env->arch_env, keep, &arm_gp_regs[REG_R12]); + be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_gp_regs[REG_R12] ); - fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp) ); - set_arm_value(fp, new_tarval_from_long(4, mode_Iu)); + fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp), + new_tarval_from_long(4, get_irn_mode(fp))); set_arm_req_out_all(fp, fp_req); - //set_arm_req_out(fp, &arm_default_req_arm_general_purpose_r11, 0); + //set_arm_req_out(fp, &arm_default_req_arm_gp_r11, 0); arch_set_irn_register(env->arch_env, fp, env->isa->bp); -// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R0], r0); -// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R1], r1); -// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R2], r2); -// be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R3], r3); +// be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R0], r0); +// be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R1], r1); +// be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R2], r2); +// be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R3], r3); be_abi_reg_map_set(reg_map, env->isa->bp, fp); - be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R12], keep); + be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R12], keep); be_abi_reg_map_set(reg_map, env->isa->sp, sp); - be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R14], lr); - be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R15], pc); + be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_LR], lr); + be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_PC], pc); return env->isa->bp; } @@ -823,47 +844,47 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m arm_abi_env_t *env = self; ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp); ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp); - ir_node *curr_pc = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R15]); - ir_node *curr_lr = be_abi_reg_map_get(reg_map, &arm_general_purpose_regs[REG_R14]); + ir_node *curr_pc = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_PC]); + ir_node *curr_lr = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_LR]); static const arm_register_req_t *sub12_req[] = { - &arm_default_req_arm_general_purpose_r13 + &arm_default_req_arm_gp_sp }; // TODO: Activate Omit fp in epilogue if(env->flags.try_omit_fp) { curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink); - curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_general_purpose], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr)); - be_node_set_reg_class(curr_lr, 1, &arm_reg_classes[CLASS_arm_general_purpose]); - arch_set_irn_register(env->arch_env, curr_lr, &arm_general_purpose_regs[REG_R14]); - be_set_constr_single_reg(curr_lr, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R14] ); + curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr)); + be_node_set_reg_class(curr_lr, 1, &arm_reg_classes[CLASS_arm_gp]); + arch_set_irn_register(env->arch_env, curr_lr, &arm_gp_regs[REG_LR]); + be_set_constr_single_reg(curr_lr, BE_OUT_POS(0), &arm_gp_regs[REG_LR] ); - curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_general_purpose], env->irg, bl, curr_lr ); - arch_set_irn_register(env->arch_env, curr_pc, &arm_general_purpose_regs[REG_R15]); - be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_general_purpose_regs[REG_R15] ); + curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr ); + arch_set_irn_register(env->arch_env, curr_pc, &arm_gp_regs[REG_PC]); + be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_gp_regs[REG_PC] ); } else { ir_node *sub12_node; ir_node *load_node; - sub12_node = new_rd_arm_Sub_i(NULL, env->irg, bl, curr_bp, mode_Iu ); - set_arm_value(sub12_node, new_tarval_from_long(12,mode_Iu)); + tarval *tv = new_tarval_from_long(12,mode_Iu); + sub12_node = new_rd_arm_Sub_i(NULL, env->irg, bl, curr_bp, mode_Iu, tv); set_arm_req_out_all(sub12_node, sub12_req); arch_set_irn_register(env->arch_env, sub12_node, env->isa->sp); load_node = new_rd_arm_LoadStackM3( NULL, env->irg, bl, sub12_node, *mem, mode_T ); - set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r11, 0); - set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r13, 1); - set_arm_req_out(load_node, &arm_default_req_arm_general_purpose_r15, 2); + set_arm_req_out(load_node, &arm_default_req_arm_gp_r11, 0); + set_arm_req_out(load_node, &arm_default_req_arm_gp_sp, 1); + set_arm_req_out(load_node, &arm_default_req_arm_gp_pc, 2); curr_bp = new_r_Proj(env->irg, bl, load_node, env->isa->bp->reg_class->mode, 0); curr_sp = new_r_Proj(env->irg, bl, load_node, env->isa->sp->reg_class->mode, 1); curr_pc = new_r_Proj(env->irg, bl, load_node, mode_Iu, 2); *mem = new_r_Proj(env->irg, bl, load_node, mode_M, 3); arch_set_irn_register(env->arch_env, curr_bp, env->isa->bp); arch_set_irn_register(env->arch_env, curr_sp, env->isa->sp); - arch_set_irn_register(env->arch_env, curr_pc, &arm_general_purpose_regs[REG_R15]); + arch_set_irn_register(env->arch_env, curr_pc, &arm_gp_regs[REG_PC]); } be_abi_reg_map_set(reg_map, env->isa->sp, curr_sp); be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp); - be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R14], curr_lr); - be_abi_reg_map_set(reg_map, &arm_general_purpose_regs[REG_R15], curr_pc); + be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_LR], curr_lr); + be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_PC], curr_pc); } static const be_abi_callbacks_t arm_abi_callbacks = { @@ -917,7 +938,7 @@ void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi mode = get_type_mode(tp); be_abi_call_res_reg(abi, 0, - mode_is_float(mode) ? &arm_floating_point_regs[REG_F0] : &arm_general_purpose_regs[REG_R0]); + mode_is_float(mode) ? &arm_fp_regs[REG_F0] : &arm_gp_regs[REG_R0]); } } @@ -964,15 +985,26 @@ static int arm_get_reg_class_alignment(const void *self, const arch_register_cla } #ifdef WITH_LIBCORE +static const lc_opt_table_entry_t arm_options[] = { + LC_OPT_ENT_BOOL("gen_reg_names", "use generic register names", &arm_isa_template.gen_reg_names), + { NULL } +}; + +/** + * Register command line options for the ARM backend. + * + * Options so far: + * + * arm-gen_reg_names use generic register names instead of SP, LR, PC + */ static void arm_register_options(lc_opt_entry_t *ent) { + lc_opt_entry_t *be_grp_arm = lc_opt_get_grp(ent, "arm"); + lc_opt_add_table(be_grp_arm, arm_options); } #endif /* WITH_LIBCORE */ const arch_isa_if_t arm_isa_if = { -#ifdef WITH_LIBCORE - arm_register_options, -#endif arm_init, arm_done, arm_get_n_reg_class, @@ -982,5 +1014,8 @@ const arch_isa_if_t arm_isa_if = { arm_get_irn_handler, arm_get_code_generator_if, arm_get_list_sched_selector, - arm_get_reg_class_alignment + arm_get_reg_class_alignment, +#ifdef WITH_LIBCORE + arm_register_options +#endif }; diff --git a/ir/be/arm/bearch_arm.h b/ir/be/arm/bearch_arm.h index 077733ba9..e87608da5 100644 --- a/ir/be/arm/bearch_arm.h +++ b/ir/be/arm/bearch_arm.h @@ -4,7 +4,5 @@ #include "../bearch.h" extern const arch_isa_if_t arm_isa_if; -void arm_global_init(void); - #endif /* _BEARCH_ARM_H_ */ diff --git a/ir/be/arm/bearch_arm_t.h b/ir/be/arm/bearch_arm_t.h index 7f59bfee4..7b63b1f85 100644 --- a/ir/be/arm/bearch_arm_t.h +++ b/ir/be/arm/bearch_arm_t.h @@ -1,12 +1,13 @@ #ifndef _BEARCH_ARM_T_H_ #define _BEARCH_ARM_T_H_ +#include + #include "debug.h" #include "bearch_arm.h" #include "arm_nodes_attr.h" #include "../be.h" #include "set.h" -#include typedef struct _arm_code_gen_t { const arch_code_generator_if_t *impl; /**< implementation */ @@ -17,7 +18,8 @@ typedef struct _arm_code_gen_t { int emit_decls; /**< flag indicating if decls were already emitted */ const be_irg_t *birg; /**< The be-irg (contains additional information about the irg) */ ir_type *int_tp; /**< the int type, needed for Call conversion */ - DEBUG_ONLY(firm_dbg_module_t *mod;) /**< debugging module */ + int have_fp; /**< non-zero, if fp hardware instructions are emitted */ + DEBUG_ONLY(firm_dbg_module_t *mod;) /**< debugging module */ } arm_code_gen_t; @@ -27,6 +29,8 @@ typedef struct _arm_isa_t { const arch_register_t *bp; /**< The base pointer register. */ const int stack_dir; /**< -1 for decreasing, 1 for increasing. */ int num_codegens; + int gen_reg_names; /**< use generic register names instead of SP, LR, PC */ + arm_code_gen_t *cg; /**< current code generator */ } arm_isa_t; @@ -39,6 +43,7 @@ typedef struct _arm_irn_ops_t { /* this is a struct to minimize the number of parameters for transformation walker */ typedef struct _arm_transform_env_t { + arm_code_gen_t *cg; /**< current code generator */ dbg_info *dbg; /**< The node debug info */ ir_graph *irg; /**< The irg, the node should be created in */ ir_node *block; /**< The block, the node should belong to */ -- 2.20.1