From: Michael Beck Date: Thu, 20 Apr 2006 13:40:30 +0000 (+0000) Subject: Implemented basic FPA support X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=fbc27d3a198b65b7519a88ec3cc97c76fd1d8509;p=libfirm Implemented basic FPA support --- diff --git a/ir/be/arm/arm_emitter.c b/ir/be/arm/arm_emitter.c index b16eb893a..038c03186 100644 --- a/ir/be/arm/arm_emitter.c +++ b/ir/be/arm/arm_emitter.c @@ -264,15 +264,15 @@ 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; + ir_node *irn = arg->v_ptr; arm_shift_modifier mod; - if (!X) + if (!irn) return lc_appendable_snadd(app, "(null)", 6); - mod = get_arm_shift_modifier(X); + mod = get_arm_shift_modifier(irn); if (ARM_HAS_SHIFT(mod)) { - long v = get_tarval_long(get_arm_value(X)); + long v = get_tarval_long(get_arm_value(irn)); snprintf(buffer, sizeof(buffer), " %s #%ld", arm_shf_mod_name(mod), v); return lc_appendable_snadd(app, buffer, strlen(buffer)); @@ -286,15 +286,24 @@ static int arm_shift_str(lc_appendable_t *app, static int arm_get_mode_suffix(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *arg) { - ir_node *X = arg->v_ptr; + ir_node *irn = arg->v_ptr; + arm_attr_t *attr; + ir_mode *mode; + int bits; - if (!X) + if (! irn) return lc_appendable_snadd(app, "(null)", 6); - if (get_mode_size_bits(get_irn_mode(X)) == 32) + attr = get_arm_attr(irn); + mode = attr->op_mode ? attr->op_mode : get_irn_mode(irn); + bits = get_mode_size_bits(mode); + + if (bits == 32) return lc_appendable_chadd(app, 's'); - else + else if (bits == 64) return lc_appendable_chadd(app, 'd'); + else + return lc_appendable_chadd(app, 'e'); } /** @@ -332,13 +341,12 @@ static void arm_fprintf_format(FILE *F, char *cmd_buf, char *cmnt_buf, ir_node * lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F (%G) */\n", cmd_buf, cmnt_buf, irn, irn); } -/* - * Add a number to a prefix. This number will not be used a second time. +/** + * Returns a unique label. This number will not be used a second time. */ -static char *get_unique_label(char *buf, size_t buflen, const char *prefix) { - static unsigned long id = 0; - snprintf(buf, buflen, "%s%lu", prefix, ++id); - return buf; +static unsigned get_unique_label(void) { + static unsigned id = 0; + return ++id; } @@ -352,24 +360,20 @@ static char *get_cfop_target(const ir_node *irn, char *buf) { return buf; } -/************************************************************************/ -/* emit_arm */ -/************************************************************************/ - +/** + * Emit a SymConst + */ static void emit_arm_SymConst(ir_node *irn, void *env) { arm_emit_env_t *emit_env = env; FILE *out = emit_env->out; - char buffer1[SNPRINTF_BUF_LEN]; - char *skip_label = get_unique_label(buffer1, SNPRINTF_BUF_LEN, ".L"); - char buffer2[SNPRINTF_BUF_LEN]; - char *indi_label = get_unique_label(buffer2, SNPRINTF_BUF_LEN, ".L"); - fprintf( out, "\tB %s\t\t\t\t\t/* start of indirect SymConst */\n", skip_label ); - fprintf( out, "\t.align 2\n" ); - fprintf( out, "%s:\n", indi_label ); - lc_efprintf(arm_get_arg_env(), out, "\t.word\t%C\n", irn); - fprintf( out, "\t.align 2\n" ); - fprintf( out, "%s:\n", skip_label ); - lc_efprintf(arm_get_arg_env(), out, "\tLDR %1D, %s\t\t\t/* end of indirect SymConst */\n", irn, indi_label); + SymConstEntry *entry = obstack_alloc(&emit_env->obst, sizeof(*entry)); + + entry->label = get_unique_label(); + entry->symconst = irn; + entry->next = emit_env->symbols; + emit_env->symbols = entry; + + lc_efprintf(arm_get_arg_env(), out, "\tldr %1D, .L%u\t\t\t/* end of indirect SymConst */\n", irn, entry->label); } /** @@ -410,21 +414,21 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { 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)); + 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)); + 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"; - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FCMP %1S, %2S", irn, irn); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fcmp %1S, %2S", irn, irn); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> FCPSR */", irn, irn ); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FMSTAT", irn, irn); + 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); } else { @@ -433,23 +437,23 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { 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; - case pn_Cmp_Le: suffix = "LE"; break; - case pn_Cmp_Gt: suffix = "GT"; break; - 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"); suffix = "AL"; + case pn_Cmp_Eq: suffix = "eq"; break; + case pn_Cmp_Lt: suffix = "lt"; break; + case pn_Cmp_Le: suffix = "le"; break; + case pn_Cmp_Gt: suffix = "gt"; break; + 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"); suffix = "al"; } - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, %2S", irn, irn); + 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(), 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, "/* false case */"); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); @@ -457,7 +461,7 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { 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(), 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); @@ -466,7 +470,7 @@ static void emit_arm_CondJmp(ir_node *irn, void *env) { 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(), 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); } @@ -491,29 +495,29 @@ static void emit_arm_CopyB(ir_node *irn, void *env) { case 0: break; case 1: - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, [%2S, #0]!", irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r12, [%2S, #0]!", irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STR %%r12, [%1S, #0]!", irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "str %%r12, [%1S, #0]!", irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); break; case 2: - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S}", irn, irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S}", irn, irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S}", irn, irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S}", irn, irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); break; case 3: - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S}", irn, irn, irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S, %4S}", irn, irn, irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S}", irn, irn, irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S, %4S}", irn, irn, irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); break; } size >>= 2; while (size) { - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); - lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn); + lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn); arm_fprintf_format(out, cmd_buf, cmnt_buf, irn); --size; } @@ -551,24 +555,24 @@ static void emit_arm_SwitchJmp(ir_node *irn, void *env) { - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, #%u", irn, n_projs - 1); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, #%u", irn, n_projs - 1); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn); lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "BHI BLOCK_%d", default_block_num); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "bhi BLOCK_%d", default_block_num); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn); lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, TABLE_%d_START", block_nr); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r12, TABLE_%d_START", block_nr); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn); lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %%r12, %%r12, %1S, LSL #2", irn); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %%r12, %%r12, %1S, LSL #2", irn); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn); lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r15, [%%r12, #0]"); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r15, [%%r12, #0]"); lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn); lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn); @@ -607,7 +611,7 @@ static void emit_be_Call(ir_node *irn, void *env) { 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)); + 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); @@ -620,7 +624,7 @@ static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) { unsigned offs = be_get_IncSP_offset(irn); if (offs) { char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN]; - lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, #%O", irn, irn, irn ); + lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, %1S, #%O", irn, irn, irn ); 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 { @@ -652,17 +656,17 @@ static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) { if (mode == mode_F) { 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(), 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[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(), 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[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(), 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 { @@ -677,7 +681,7 @@ static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) { assert( (mode != mode_E) && "IEEE Extended FP not supported"); if (mode_is_dataM(mode)) { 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(), 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 { @@ -691,7 +695,7 @@ static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) { assert( (mode != mode_E) && "IEEE Extended FP not supported"); if (mode_is_dataM(mode)) { 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(), 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 { @@ -703,9 +707,9 @@ static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) { FILE *F = emit_env->out; ir_mode *mode = get_irn_mode(irn); assert( (mode != mode_E) && "IEEE Extended FP not supported"); - lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* begin Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn); - lc_efprintf(arm_get_arg_env(), F, "\tEOR %2S, %1S, %2S\n", irn, irn, irn); - lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* end Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn); + lc_efprintf(arm_get_arg_env(), F, "\teor %1S, %1S, %2S\t\t\t/* begin Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn); + lc_efprintf(arm_get_arg_env(), F, "\teor %2S, %1S, %2S\n", irn, irn, irn); + lc_efprintf(arm_get_arg_env(), F, "\teor %1S, %1S, %2S\t\t\t/* end Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn); } static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) { @@ -714,7 +718,7 @@ static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) { 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, SNPRINTF_BUF_LEN, "LDR %1D, [%1S, #%O]", irn, irn, irn ); + 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); } @@ -728,13 +732,24 @@ static void emit_Jmp(ir_node *irn, void *env) { FILE *out = emit_env->out; const ir_edge_t *edge = get_irn_out_edge_first(irn); ir_node *target_block = get_edge_src_irn(edge); - fprintf(out, "\tB BLOCK_%ld\t\t\t/* unconditional Jump */\n", get_irn_node_nr(target_block)); + fprintf(out, "\tb BLOCK_%ld\t\t\t/* unconditional Jump */\n", get_irn_node_nr(target_block)); } -static void emit_silence(ir_node *irn, void *env) { +static void emit_arm_fpaDbl2GP(const ir_node *n, arm_emit_env_t *env) { + FILE *F = env->out; + char cmd_buf[256]; + const lc_arg_env_t *arg_env = arm_get_arg_env(); + + lc_esnprintf(arg_env, cmd_buf, 256, "stfd %1S, [sp, #-8]! ", n); + lc_efprintf(arg_env, F, "\t%-35s %-60s /* %+F (%+G) */\n", cmd_buf, "/* Push fp to stack */", n, n); + lc_esnprintf(arg_env, cmd_buf, 256, "ldmfd sp!, {%2D, %1D} ", n, n); + lc_efprintf(arg_env, F, "\t%-35s %-60s /* %+F (%+G) */\n", cmd_buf, "/* Pop destination */", n, n); } +static void emit_silence(ir_node *irn, void *env) { + +} /*********************************************************************************** @@ -771,6 +786,7 @@ static void arm_register_emitters(void) { // ARM_EMIT(Const); ARM_EMIT(SymConst); ARM_EMIT(SwitchJmp); + ARM_EMIT(fpaDbl2GP); /* benode emitter */ BE_EMIT(Call); @@ -853,6 +869,7 @@ void arm_emit_start(FILE *F, ir_graph *irg) { * Emits code for function end */ void arm_emit_end(FILE *F, ir_graph *irg) { + fprintf(F, "\t.ident \"firmcc\"\n"); } /** @@ -871,9 +888,10 @@ void arm_gen_labels(ir_node *block, void *env) { /** -* Main driver. Emits the code for one routine. + * Main driver. Emits the code for one routine. */ void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) { + SymConstEntry *entry; arm_emit_env_t emit_env; ir_node **blk_sched; int i, n; @@ -881,6 +899,8 @@ void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) { emit_env.out = F; emit_env.arch_env = cg->arch_env; emit_env.cg = cg; + emit_env.symbols = NULL; + obstack_init(&emit_env.obst); FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit"); /* set the global arch_env (needed by print hooks) */ @@ -907,5 +927,14 @@ void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) { arm_gen_block(block, &emit_env); } - arm_emit_end(F, irg); + /* emit SymConst values */ + if (emit_env.symbols) + fprintf(F, "\t.align 2\n"); + + for (entry = emit_env.symbols; entry; entry = entry->next) { + fprintf(F, ".L%u:\n", entry->label); + lc_efprintf(arm_get_arg_env(), F, "\t.word\t%C\n", entry->symconst); + } + + obstack_free(&emit_env.obst, NULL); } diff --git a/ir/be/arm/arm_emitter.h b/ir/be/arm/arm_emitter.h index 8c0b4145c..8dad6d22b 100644 --- a/ir/be/arm/arm_emitter.h +++ b/ir/be/arm/arm_emitter.h @@ -1,18 +1,32 @@ #ifndef _ARM_EMITTER_H_ #define _ARM_EMITTER_H_ -#include "irargs_t.h" // this also inlucdes -#include "irnode.h" +#include "firm_types.h" +#include "irargs_t.h" #include "debug.h" #include "../bearch.h" #include "bearch_arm_t.h" +/** + * A SymConst entry. + */ +typedef struct _SymConstEntry { + unsigned label; /**< a label number for this label */ + ir_node *symconst; /**< the node holding this label */ + struct _SymConstEntry *next; /**< links all entries */ +} SymConstEntry; + +/** + * The ARM emitter environment. + */ typedef struct _arm_emit_env_t { - FILE *out; - const arch_env_t *arch_env; - const arm_code_gen_t *cg; + FILE *out; /**< the output stream */ + const arch_env_t *arch_env; /**< the architecture environment */ + const arm_code_gen_t *cg; /**< the code generator object */ + struct obstack obst; /**< an temporary store for SymConstEntries */ + SymConstEntry *symbols; /**< list containing all SymConstEntries */ DEBUG_ONLY(firm_dbg_module_t *mod;) } arm_emit_env_t; @@ -25,12 +39,15 @@ 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); +/** + * Sections. + */ 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 */ + NO_SECTION, /**< no section selected yet. */ + SECTION_TEXT, /**< text section */ + SECTION_DATA, /**< data section */ + SECTION_RODATA, /**< rodata section */ + SECTION_COMMON, /**< common section */ } sections; /** diff --git a/ir/be/arm/arm_map_regs.c b/ir/be/arm/arm_map_regs.c index f8b756987..2ebbe2387 100644 --- a/ir/be/arm/arm_map_regs.c +++ b/ir/be/arm/arm_map_regs.c @@ -71,15 +71,15 @@ 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_fLoad(pred)) { + if (is_arm_Load(pred) || is_arm_fpaLdf(pred)) { if (nr == pn_Load_res) return 0; assert(0 && "unsupported Proj(Load) number"); } - else if (is_arm_Store(pred) || is_arm_fStore(pred)) { + else if (is_arm_Store(pred) || is_arm_fpaStf(pred)) { return 0; } - else if (is_arm_fDiv(pred)) { + else if (is_arm_fpaDiv(pred) || is_arm_fpaRdv(pred)) { if (nr == pn_Quot_res) return 0; else diff --git a/ir/be/arm/arm_nodes_attr.h b/ir/be/arm/arm_nodes_attr.h index 89ab590e5..6b9fa4551 100644 --- a/ir/be/arm/arm_nodes_attr.h +++ b/ir/be/arm/arm_nodes_attr.h @@ -71,8 +71,9 @@ typedef struct _arm_attr_t { const arch_register_t **slots; /**< register slots for assigned registers */ - unsigned instr_fl; /**< condition code, shift modifier */ - tarval *value; /**< immediate */ + ir_mode *op_mode; /**< operation mode */ + unsigned instr_fl; /**< condition code, shift modifier */ + tarval *value; /**< immediate */ const char *symconst_label; int proj_num; int n_projs; diff --git a/ir/be/arm/arm_spec.pl b/ir/be/arm/arm_spec.pl index 8701dd275..73e353ec9 100644 --- a/ir/be/arm/arm_spec.pl +++ b/ir/be/arm/arm_spec.pl @@ -6,7 +6,6 @@ $arch = "arm"; -# $comment_string = 'WIRHABENKEINEKOMMENTARE'; $comment_string = '/*'; # the number of additional opcodes you want to register @@ -31,6 +30,8 @@ $comment_string = '/*'; # "reg_req" => { "in" => [ "reg_class|register" ], "out" => [ "reg_class|register|in_rX" ] }, # "cmp_attr" => "c source code for comparing node attributes", # "emit" => "emit code with templates", +# "attr" => "attitional attribute arguments for constructor" +# "init_attr" => "emit attribute initialization template" # "rd_constructor" => "c source code which constructs an ir_node" # }, # @@ -115,7 +116,7 @@ $comment_string = '/*'; { "name" => "pc", "type" => 6 }, # this is our program counter { "mode" => "mode_Iu" } ], - "fp" => [ + "fpa" => [ { "name" => "f0", "type" => 1 }, { "name" => "f1", "type" => 1 }, { "name" => "f2", "type" => 1 }, @@ -124,7 +125,7 @@ $comment_string = '/*'; { "name" => "f5", "type" => 2 }, { "name" => "f6", "type" => 2 }, { "name" => "f7", "type" => 2 }, - { "mode" => "mode_D" } + { "mode" => "mode_E" } ] ); # %reg_classes @@ -162,7 +163,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. add %D1, %S1, %S2%X0 /* Add(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Add_i" => { @@ -172,7 +173,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. add %D1, %S1, %C /* Add(%C, %S1) -> %D1, (%A1, const) */' }, "Mul" => { @@ -180,7 +181,7 @@ $comment_string = '/*'; "irn_flags" => "R", "comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b", "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "!in_r1" ] }, - "emit" =>'. MUL %D1, %S1, %S2 /* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' + "emit" =>'. mul %D1, %S1, %S2 /* Mul(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Mla" => { @@ -188,7 +189,7 @@ $comment_string = '/*'; "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) */' + "emit" =>'. mla %D1, %S1, %S2, %S3 /* Mla(%S1, %S2, %S3) -> %D1, (%A1, %A2, %A3) */' }, "And" => { @@ -199,7 +200,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. and %D1, %S1, %S2%X0 /* And(%S1, %S2) -> %D1, (%A1, %A2) */' }, "And_i" => { @@ -208,7 +209,7 @@ $comment_string = '/*'; "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) */', + "emit" => '. and %D1, %S1, %C /* And(%C, %S1) -> %D1, (%A1, const) */', "cmp_attr" => 'return attr_a->value != attr_b->value;' }, @@ -220,7 +221,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. orr %D1, %S1, %S2%X0 /* Or(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Or_i" => { @@ -230,7 +231,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. orr %D1, %S1, %C /* Or(%C, %S1) -> %D1, (%A1, const) */' }, "Eor" => { @@ -241,7 +242,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. eor %D1, %S1, %S2%X0 /* Xor(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Eor_i" => { @@ -251,7 +252,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. eor %D1, %S1, %C /* Xor(%C, %S1) -> %D1, (%A1, const) */' }, # not commutative operations @@ -263,7 +264,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. bic %D1, %S1, %S2%X0 /* AndNot(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Bic_i" => { @@ -272,7 +273,7 @@ $comment_string = '/*'; "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) */', + "emit" => '. bic %D1, %S1, %C /* AndNot(%C, %S1) -> %D1, (%A1, const) */', "cmp_attr" => 'return attr_a->value != attr_b->value;' }, @@ -283,7 +284,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. sub %D1, %S1, %S2%X0 /* Sub(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Sub_i" => { @@ -293,7 +294,7 @@ $comment_string = '/*'; "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) */', + "emit" => '. sub %D1, %S1, %C /* Sub(%S1, %C) -> %D1, (%A1, const) */', }, "Rsb" => { @@ -303,7 +304,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. rsb %D1, %S1, %S2%X0 /* Rsb(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Rsb_i" => { @@ -312,7 +313,7 @@ $comment_string = '/*'; "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) */', + "emit" => '. rsb %D1, %S1, %C /* Rsb(%S1, %C) -> %D1, (%A1, const) */', "cmp_attr" => 'return attr_a->value != attr_b->value;' }, @@ -320,28 +321,28 @@ $comment_string = '/*'; "irn_flags" => "R", "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) */' + "emit" => '. mov %D1, %S1, LSL %S2\t/* Shl(%S1, %S2) -> %D1, (%A1, %A2) */' }, "Shr" => { "irn_flags" => "R", "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) */' + "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" => [ "gp", "gp" ], "out" => [ "in_r1" ] }, - "emit" => '. MOV %D1, %S1, ASR %S2\t\t /* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */' + "emit" => '. mov %D1, %S1, ASR %S2\t\t /* Shrs(%S1, %S2) -> %D1, (%A1, %A2) */' }, #"RotR" => { # "irn_flags" => "R", # "comment" => "construct RotR: RotR(a, b) = a ROTR b", # "reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] }, -# "emit" => '. MOV %D1, %S1, ROR %S2 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' +# "emit" => '. mov %D1, %S1, ROR %S2 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' ## "emit" => '. ror %S1, %S2, %D1 /* RotR(%S1, %S2) -> %D1, (%A1, %A2) */' #}, @@ -366,7 +367,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. mov %D1, %S1%X0\t/* Mov(%S1%X0) -> %D1, (%A1) */' }, "Mov_i" => { @@ -375,7 +376,7 @@ $comment_string = '/*'; "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 */', + "emit" => '. mov %D1, %C /* Mov Const into register */', "cmp_attr" => 'return attr_a->value != attr_b->value;' }, @@ -386,7 +387,7 @@ $comment_string = '/*'; "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) */' + "emit" => '. mvn %D1, %S1%X0 /* ~(%S1%X0) -> %D1, (%A1) */' }, "Mvn_i" => { @@ -396,7 +397,7 @@ $comment_string = '/*'; "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 */', + "emit" => '. mvn %D1, %C /* Mov ~Const into register */', }, "Abs" => { @@ -404,8 +405,8 @@ $comment_string = '/*'; "comment" => "construct Abs: Abs(a) = |a|", "reg_req" => { "in" => [ "gp" ], "out" => [ "gp" ] }, "emit" => -'. MOVS %S1, %S1, #0 /* set condition flag */\n -. RSBMI %D1, %S1, #0 /* Neg(%S1) -> %D1, (%A1) */' +'. movs %S1, %S1, #0 /* set condition flag */\n +. rsbmi %D1, %S1, #0 /* Neg(%S1) -> %D1, (%A1) */' }, # other operations @@ -438,7 +439,7 @@ $comment_string = '/*'; "attr" => "const char *label", "init_attr" => ' attr->symconst_label = label;', "reg_req" => { "out" => [ "gp" ] }, -# "emit" => '. LDR %D1, %C /* Mov Const into register */', +# "emit" => '. ldr %D1, %C /* Mov Const into register */', "cmp_attr" => ' /* should be identical but ...*/ return strcmp(attr_a->symconst_label, attr_b->symconst_label);' @@ -466,8 +467,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. LDR %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', -# "emit" => '. LDR %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */', + "emit" => '. ldr %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', "outs" => [ "res", "M" ], }, @@ -477,8 +477,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. LDRB %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', -# "emit" => '. LDRB %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */', + "emit" => '. ldrb %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', "outs" => [ "res", "M" ], }, @@ -488,8 +487,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. LDRSB %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', -# "emit" => '. LDRSB %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */', + "emit" => '. ldrsb %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', "outs" => [ "res", "M" ], }, @@ -499,8 +497,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. LDRH %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', -# "emit" => '. LDRH %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */', + "emit" => '. ldrh %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', "outs" => [ "res", "M" ], }, @@ -510,8 +507,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. LDRSH %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', -# "emit" => '. LDRSH %D1, %S1, %O /* Load((%S1)) -> %D1, (%A1) */', + "emit" => '. ldrsh %D1, [%S1, #0] /* Load((%S1)) -> %D1, (%A1) */', "outs" => [ "res", "M" ], }, @@ -521,8 +517,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "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) */', + "emit" => '. strb %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */', "outs" => [ "M" ], }, @@ -532,8 +527,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "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) */', + "emit" => '. strsb %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */', "outs" => [ "M" ], }, @@ -543,8 +537,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "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) */', + "emit" => '. strh %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */', "outs" => [ "M" ], }, @@ -554,8 +547,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "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) */', + "emit" => '. strsh%S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */', "outs" => [ "M" ], }, @@ -565,8 +557,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "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) */', + "emit" => '. str %S2, [%S1, #0] /* Store(%S2) -> (%S1), (%A1, %A2) */', "outs" => [ "M" ], }, @@ -576,7 +567,7 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", "reg_req" => { "in" => [ "sp", "gp", "gp", "gp", "gp", "none" ], "out" => [ "gp", "none" ] }, - "emit" => '. STMFD %S1!, {%S2, %S3, %S4, %S5} /* Store multiple on Stack*/', + "emit" => '. stmfd %S1!, {%S2, %S3, %S4, %S5} /* Store multiple on Stack*/', "outs" => [ "ptr", "M" ], }, @@ -586,136 +577,195 @@ $comment_string = '/*'; "state" => "exc_pinned", "comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg", "reg_req" => { "in" => [ "sp", "none" ], "out" => [ "gp", "gp", "gp", "none" ] }, - "emit" => '. LDMFD %S1, {%D1, %D2, %D3} /* Load multiple from Stack */', + "emit" => '. ldmfd %S1, {%D1, %D2, %D3} /* Load multiple from Stack */', "outs" => [ "res0", "res1", "res2", "M" ], }, - - - - - - -#--------------------------------------------------------# -# __ _ _ _ # -# / _| | | | | | # -# | |_| | ___ __ _| |_ _ __ ___ __| | ___ ___ # -# | _| |/ _ \ / _` | __| | '_ \ / _ \ / _` |/ _ \/ __| # -# | | | | (_) | (_| | |_ | | | | (_) | (_| | __/\__ \ # -# |_| |_|\___/ \__,_|\__| |_| |_|\___/ \__,_|\___||___/ # -#--------------------------------------------------------# +#---------------------------------------------------# +# __ _ # +# / _| | | # +# | |_ _ __ __ _ _ __ ___ __| | ___ ___ # +# | _| '_ \ / _` | | '_ \ / _ \ / _` |/ _ \/ __| # +# | | | |_) | (_| | | | | | (_) | (_| | __/\__ \ # +# |_| | .__/ \__,_| |_| |_|\___/ \__,_|\___||___/ # +# | | # +# |_| # +#---------------------------------------------------# # commutative operations -"fAdd" => { +"fpaAdd" => { "op_flags" => "C", "irn_flags" => "R", - "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 */', + "comment" => "construct FPA Add: Add(a, b) = Add(b, a) = a + b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" => '. adf%M %D1, %S1, %S2 /* FPA Add(%S1, %S2) -> %D1 */', }, -"fMul" => { +"fpaMul" => { "op_flags" => "C", - "comment" => "construct FP Mul: Mul(a, b) = Mul(b, a) = a * b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. FMUL%Mx %D1, %S1, %S2 /* FP Mul(%S1, %S2) -> %D1 */', + "comment" => "construct FPA Mul: Mul(a, b) = Mul(b, a) = a * b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. muf%M %D1, %S1, %S2 /* FPA Mul(%S1, %S2) -> %D1 */', }, -"fDiv" => { - "comment" => "construct FP Div: Div(a, b) = a / b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. FDIV%Mx %D1, %S1, %S2 /* FP Div(%S1, %S2) -> %D1 */', +"fpaFMul" => { + "op_flags" => "C", + "comment" => "construct FPA Fast Mul: Mul(a, b) = Mul(b, a) = a * b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. fml%M %D1, %S1, %S2 /* FPA Fast Mul(%S1, %S2) -> %D1 */', }, -"fMax" => { +"fpaMax" => { "op_flags" => "C", "irn_flags" => "R", - "comment" => "construct FP Max: Max(a, b) = Max(b, a) = a > b ? a : b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. fmax %S1, %S2, %D1 /* FP Max(%S1, %S2) -> %D1 */', + "comment" => "construct FPA Max: Max(a, b) = Max(b, a) = a > b ? a : b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. fmax %S1, %S2, %D1 /* FPA Max(%S1, %S2) -> %D1 */', }, -"fMin" => { +"fpaMin" => { "op_flags" => "C", "irn_flags" => "R", - "comment" => "construct FP Min: Min(a, b) = Min(b, a) = a < b ? a : b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" =>'. fmin %S1, %S2, %D1 /* FP Min(%S1, %S2) -> %D1 */', + "comment" => "construct FPA Min: Min(a, b) = Min(b, a) = a < b ? a : b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. fmin %S1, %S2, %D1 /* FPA Min(%S1, %S2) -> %D1 */', }, # not commutative operations -"fSub" => { +"fpaSub" => { + "irn_flags" => "R", + "comment" => "construct FPA Sub: Sub(a, b) = a - b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" => '. suf%M %D1, %S1, %S2 /* FPA Sub(%S1, %S2) -> %D1 */' +}, + +"fpaRsb" => { + "irn_flags" => "R", + "comment" => "construct FPA reverse Sub: Sub(a, b) = b - a", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" => '. rsf%M %D1, %S1, %S2 /* FPA reverse Sub(%S1, %S2) -> %D1 */' +}, + +"fpaDiv" => { + "comment" => "construct FPA Div: Div(a, b) = a / b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. dvf%M %D1, %S1, %S2 /* FPA Div(%S1, %S2) -> %D1 */', +}, + +"fpaRdv" => { + "comment" => "construct FPA reverse Div: Div(a, b) = b / a", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. rdf%M %D1, %S1, %S2 /* FPA reverse Div(%S1, %S2) -> %D1 */', +}, + +"fpaFDiv" => { + "comment" => "construct FPA Fast Div: Div(a, b) = a / b", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. fdv%M %D1, %S1, %S2 /* FPA Fast Div(%S1, %S2) -> %D1 */', +}, + +"fpaFRdv" => { + "comment" => "construct FPA Fast reverse Div: Div(a, b) = b / a", + "reg_req" => { "in" => [ "fpa", "fpa" ], "out" => [ "fpa" ] }, + "emit" =>'. frd%M %D1, %S1, %S2 /* FPA Fast reverse Div(%S1, %S2) -> %D1 */', +}, + +"fpaMov" => { "irn_flags" => "R", - "comment" => "construct FP Sub: Sub(a, b) = a - b", - "reg_req" => { "in" => [ "fp", "fp" ], "out" => [ "fp" ] }, - "emit" => '. FSUB%Mx %D1, %S1, %S2 /* FP Sub(%S1, %S2) -> %D1 */' + "comment" => "construct FPA Move: b = a", + "reg_req" => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, + "emit" => '. mvf%M %S1, %D1 /* FPA Mov %S1 -> %D1 */', }, -"fNeg" => { +"fpaMnv" => { "irn_flags" => "R", - "comment" => "construct FP Neg: Neg(a) = -a", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. fneg %S1, %D1 /* FP Neg(%S1) -> %D1 */', + "comment" => "construct FPA Move Negated: b = -a", + "reg_req" => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, + "emit" => '. mnf%M %S1, %D1 /* FPA Neg(%S1) -> %D1 */', }, -"fAbs" => { +"fpaAbs" => { "irn_flags" => "R", - "comment" => "construct FP Absolute value: fAbsd(a) = |a|", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. FABS%Mx %D1, %S1 /* FP Absd(%S1) -> %D1 */', + "comment" => "construct FPA Absolute value: fAbsd(a) = |a|", + "reg_req" => { "in" => [ "fpa" ], "out" => [ "fpa" ] }, + "emit" => '. abs%M %D1, %S1 /* FPA Abs(%S1) -> %D1 */', }, # other operations -"fConst" => { +"fpaConst" => { "op_flags" => "c", "irn_flags" => "R", - "comment" => "represents a FP constant", + "comment" => "represents a FPA constant", "attr" => "tarval *val", "init_attr" => 'attr->value = val;', - "reg_req" => { "out" => [ "fp" ] }, - "emit" => '. FMOV %D1, %C /* Mov fConst into register */', + "reg_req" => { "out" => [ "fpa" ] }, + "emit" => '. fmov %D1, %C /* Mov fConst into register */', "cmp_attr" => 'return attr_a->value != attr_b->value;', }, -"fConvD2S" => { +"fpaFlt" => { "irn_flags" => "R", - "comment" => "convert double to single", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. FCVTSD %D1, %S1 /* Convert double to single */', + "comment" => "construct a FPA integer->float conversion", + "reg_req" => { "in" => ["gp"], "out" => [ "fpa" ] }, + "emit" => '. flt%M %D1, %S1 /* convert int to fp */', }, -"fConvS2D" => { +"fpaFix" => { "irn_flags" => "R", - "comment" => "convert single to double", - "reg_req" => { "in" => [ "fp" ], "out" => [ "fp" ] }, - "emit" => '. FCVTDS %D1, %S1 /* Convert single to double */', + "comment" => "construct a FPA float->integer conversion", + "reg_req" => { "in" => ["fpa"], "out" => [ "gp" ] }, + "emit" => '. fix %D1, %S1 /* convert fp to int */', }, - # Load / Store -"fLoad" => { +"fpaLdf" => { "op_flags" => "L|F", "irn_flags" => "R", "state" => "exc_pinned", - "comment" => "construct FP Load: Load(ptr, mem) = LD ptr", - "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "fp", "none" ] }, - "emit" => '. FLD%Mx %D1, %S1 /* Load((%S1)) -> %D1 */', + "comment" => "construct FPA Load: Load(ptr, mem) = LD ptr", + "attr" => "ir_mode *op_mode", + "init_attr" => "attr->op_mode = op_mode;", + "reg_req" => { "in" => [ "gp", "none" ], "out" => [ "fpa", "none" ] }, + "emit" => '. ldf%M %D1, [%S1, #0] /* Load((%S1)) -> %D1 */', "outs" => [ "res", "M" ], }, -"fStore" => { +"fpaStf" => { "op_flags" => "L|F", "irn_flags" => "R", "state" => "exc_pinned", "comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val", - "reg_req" => { "in" => [ "gp", "fp", "none" ] }, - "emit" => '. FST%Mx %S2, %S1 /* Store(%S2) -> (%S1), (%A1, %A2) */', + "attr" => "ir_mode *op_mode", + "init_attr" => "attr->op_mode = op_mode;", + "reg_req" => { "in" => [ "gp", "fpa", "none" ] }, + "emit" => '. stf%M [%S2, #0], %S1 /* Store(%S2) -> (%S1), (%A1, %A2) */', "outs" => [ "M" ], }, +"fpaDbl2GP" => { + "op_flags" => "L|F", + "irn_flags" => "R", + "state" => "exc_pinned", + "comment" => "construct fp double to 2 gp register transfer", + "reg_req" => { "in" => [ "fpa", "none" ], "out" => [ "gp", "gp" ] }, + "outs" => [ "low", "high", "M" ], +}, + + +#---------------------------------------------------# +# __ _ # +# / _| | | # +# __ _| |_ _ __ _ __ ___ __| | ___ ___ # +# \ \ / / _| '_ \ | '_ \ / _ \ / _` |/ _ \/ __| # +# \ V /| | | |_) | | | | | (_) | (_| | __/\__ \ # +# \_/ |_| | .__/ |_| |_|\___/ \__,_|\___||___/ # +# | | # +# |_| # +#---------------------------------------------------# + ); # end of %nodes diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c index e665bb4fd..02cc859af 100644 --- a/ir/be/arm/arm_transform.c +++ b/ir/be/arm/arm_transform.c @@ -1,4 +1,4 @@ -/* The codegenrator (transform FIRM into arm FIRM */ +/* The codegenerator (transform FIRM into arm FIRM */ /* $Id$ */ #ifdef HAVE_CONFIG_H @@ -182,24 +182,25 @@ static ir_node *create_const_graph(ir_node *irn, ir_node *block) { } - +/** + * Creates code for a Firm Const node. + */ static ir_node *gen_Const(ir_node *irn, arm_code_gen_t *cg) { - ir_node *result; ir_graph *irg = current_ir_graph; ir_node *block = get_nodes_block(irn); ir_mode *mode = get_irn_mode(irn); dbg_info *dbg = get_irn_dbg_info(irn); - assert(mode != mode_E && "IEEE Extended FP not supported"); - if (mode == mode_F) - result = new_rd_arm_fConst(dbg, irg, block, mode, get_Const_tarval(irn)); - else if (mode == mode_D) - result = new_rd_arm_fConst(dbg, irg, block, mode, get_Const_tarval(irn)); - else if (mode == mode_P) + if (mode_is_float(mode)) { + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaConst(dbg, irg, block, mode, get_Const_tarval(irn)); + else if (USE_VFP(cg->isa)) + assert(mode != mode_E && "IEEE Extended FP not supported"); + assert(0 && "NYI"); + } + else if (mode_is_reference(mode)) return irn; - else - result = create_const_graph(irn, block); - return result; + return create_const_graph(irn, block); } static ir_node *gen_mask(ir_node *irn, ir_node *op, int result_bits) { @@ -235,21 +236,34 @@ static ir_node *gen_Conv(ir_node *irn, arm_code_gen_t *cg) { ir_mode *out_mode = get_irn_mode(irn); dbg_info *dbg = get_irn_dbg_info(irn); - assert( in_mode != mode_E && ""); - assert( in_mode != mode_Ls && ""); - assert( in_mode != mode_Lu && ""); - assert( out_mode != mode_E && ""); - assert( out_mode != mode_Ls && ""); - assert( out_mode != mode_Lu && ""); - if (in_mode == out_mode) return op; - if ((mode_is_int(in_mode) || mode_is_reference(in_mode)) - && (mode_is_reference(out_mode) || mode_is_int(out_mode))) { - int in_bits = get_mode_size_bits(in_mode); + if (mode_is_float(in_mode) || mode_is_float(out_mode)) { + cg->have_fp = 1; + + if (USE_FPA(cg->isa)) { + if (mode_is_float(in_mode)) { + if (mode_is_float(out_mode)) { + /* from float to float */ + return new_rd_arm_fpaMov(dbg, irg, block, op, out_mode); + } + else { + /* from float to int */ + return new_rd_arm_fpaFix(dbg, irg, block, op, out_mode); + } + } + else { + /* from int to float */ + return new_rd_arm_fpaFlt(dbg, irg, block, op, out_mode); + } + } + assert(0 && "NYI"); + } + else { /* complete in gp registers */ + int in_bits = get_mode_size_bits(in_mode); int out_bits = get_mode_size_bits(out_mode); - int in_sign = get_mode_sign(in_mode); + int in_sign = get_mode_sign(in_mode); int out_sign = get_mode_sign(out_mode); // 32 -> 32 @@ -309,20 +323,8 @@ static ir_node *gen_Conv(ir_node *irn, arm_code_gen_t *cg) { } assert(0 && "recheck integer conversion logic!"); return irn; - } else if (in_mode == mode_D && out_mode == mode_F) { - return new_rd_arm_fConvD2S(dbg, irg, block, op, out_mode); - } else if (in_mode == mode_F && out_mode == mode_D) { - return new_rd_arm_fConvS2D(dbg, irg, block, op, out_mode); - } else if (mode_is_int(in_mode) && mode_is_float(out_mode)) { - cg->have_fp = 1; - return irn; /* TODO: implement int->float conversion*/ - } else if (mode_is_float(in_mode) && mode_is_int(out_mode)) { - cg->have_fp = 1; - return irn; /* TODO: implement float->int conversion*/ - } else { - assert(0 && "not implemented conversion"); - return irn; } + return NULL; } /** @@ -360,11 +362,14 @@ static ir_node *gen_Add(ir_node *irn, arm_code_gen_t *cg) { arm_shift_modifier mod; dbg_info *dbg = get_irn_dbg_info(irn); - assert(mode != mode_E && "IEEE Extended FP not supported"); - if (mode_is_float(mode)) { cg->have_fp = 1; - return new_rd_arm_fAdd(dbg, irg, block, op1, op2, mode); + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaAdd(dbg, irg, block, op1, op2, mode); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } if (mode_is_numP(mode)) { if (is_arm_Mov_i(op1)) @@ -423,11 +428,14 @@ static ir_node *gen_Mul(ir_node *irn, arm_code_gen_t *cg) { ir_graph *irg = current_ir_graph; dbg_info *dbg = get_irn_dbg_info(irn); - assert(mode != mode_E && "IEEE Extended FP not supported"); - if (mode_is_float(mode)) { cg->have_fp = 1; - return new_rd_arm_fMul(dbg, irg, block, op1, op2, mode); + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaMul(dbg, irg, block, op1, op2, mode); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } return new_rd_arm_Mul(dbg, irg, block, op1, op2, mode); } @@ -447,7 +455,15 @@ static ir_node *gen_Quot(ir_node *irn, arm_code_gen_t *cg) { assert(mode != mode_E && "IEEE Extended FP not supported"); - return new_rd_arm_fDiv(dbg, current_ir_graph, block, op1, op2, mode); + cg->have_fp = 1; + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaDiv(dbg, current_ir_graph, block, op1, op2, mode); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); + + return NULL; } #define GEN_INT_OP(op) \ @@ -525,11 +541,14 @@ static ir_node *gen_Sub(ir_node *irn, arm_code_gen_t *cg) { ir_graph *irg = current_ir_graph; dbg_info *dbg = get_irn_dbg_info(irn); - assert(mode != mode_E && "IEEE Extended FP not supported"); - if (mode_is_float(mode)) { cg->have_fp = 1; - return new_rd_arm_fSub(dbg, irg, block, op1, op2, mode); + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaSub(dbg, irg, block, op1, op2, mode); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } if (mode_is_numP(mode)) { if (is_arm_Mov_i(op1)) @@ -658,11 +677,14 @@ static ir_node *gen_Abs(ir_node *irn, arm_code_gen_t *cg) { ir_mode *mode = get_irn_mode(irn); dbg_info *dbg = get_irn_dbg_info(irn); - assert(mode != mode_E && "IEEE Extended FP not supported"); - if (mode_is_float(mode)) { cg->have_fp = 1; - return new_rd_arm_fAbs(dbg, current_ir_graph, block, op, mode); + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaAbs(dbg, current_ir_graph, block, op, mode); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } return new_rd_arm_Abs(dbg, current_ir_graph, block, op, mode); } @@ -681,7 +703,13 @@ static ir_node *gen_Minus(ir_node *irn, arm_code_gen_t *cg) { dbg_info *dbg = get_irn_dbg_info(irn); if (mode_is_float(mode)) { - return new_rd_arm_fNeg(dbg, irg, block, op, mode); + cg->have_fp = 1; + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaMnv(dbg, irg, block, op, mode); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } return new_rd_arm_Rsb_i(dbg, irg, block, op, mode, get_mode_null(mode)); } @@ -703,8 +731,13 @@ static ir_node *gen_Load(ir_node *irn, arm_code_gen_t *cg) { if (mode_is_float(mode)) { cg->have_fp = 1; - /* FIXME: set the load mode */ - return new_rd_arm_fLoad(dbg, irg, block, get_Load_ptr(irn), get_Load_mem(irn)); + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaLdf(dbg, irg, block, get_Load_ptr(irn), get_Load_mem(irn), + get_Load_mode(irn)); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } if (mode == mode_Bu) { return new_rd_arm_Loadb(dbg, irg, block, get_Load_ptr(irn), get_Load_mem(irn)); @@ -742,8 +775,13 @@ static ir_node *gen_Store(ir_node *irn, arm_code_gen_t *cg) { assert(mode != mode_E && "IEEE Extended FP not supported"); if (mode_is_float(mode)) { cg->have_fp = 1; - /* FIXME: set the store mode */ - return new_rd_arm_fStore(dbg, irg, block, get_Store_ptr(irn), get_Store_value(irn), get_Store_mem(irn)); + if (USE_FPA(cg->isa)) + return new_rd_arm_fpaStf(dbg, irg, block, get_Store_ptr(irn), get_Store_value(irn), + get_Store_mem(irn), get_irn_mode(get_Store_value(irn))); + else if (USE_VFP(cg->isa)) { + assert(mode != mode_E && "IEEE Extended FP not supported"); + } + assert(0 && "NYI"); } if (mode == mode_Bu) { return new_rd_arm_Storeb(dbg, irg, block, get_Store_ptr(irn), get_Store_value(irn), get_Store_mem(irn)); @@ -1082,9 +1120,9 @@ static ir_node *gen_FrameStore(ir_node *irn, arm_code_gen_t *cg) { * *********************************************************/ -/************************************************************************/ -/* move constants out of startblock */ -/************************************************************************/ +/** + * move constants out of the start block + */ void arm_move_consts(ir_node *node, void *env) { arm_code_gen_t *cgenv = (arm_code_gen_t *)env; int i; @@ -1093,14 +1131,18 @@ void arm_move_consts(ir_node *node, void *env) { return; if (is_Phi(node)) { - for (i = 0; i < get_irn_arity(node); i++) { + for (i = get_irn_arity(node) - 1; i >= 0; --i) { ir_node *pred = get_irn_n(node,i); opcode pred_code = get_irn_opcode(pred); if (pred_code == iro_Const) { ir_node *const_graph; const_graph = create_const_graph(pred, get_nodes_block(get_irn_n(get_nodes_block(node),i))); set_irn_n(node, i, const_graph); - } else if (pred_code == iro_SymConst) { + } + else if (pred_code == iro_SymConst) { + /* FIXME: in general, SymConst always require a load, so it + might be better to place them into the first real block + and let the spiller rematerialize them. */ const char *str = get_sc_name(pred); ir_node *symconst_node; symconst_node = new_rd_arm_SymConst(get_irn_dbg_info(pred), diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index f42a52b7c..4345c464b 100644 --- a/ir/be/arm/bearch_arm.c +++ b/ir/be/arm/bearch_arm.c @@ -5,6 +5,11 @@ #include "config.h" #endif +#ifdef WITH_LIBCORE +#include +#include +#endif /* WITH_LIBCORE */ + #include "pseudo_irg.h" #include "irgwalk.h" #include "irprog.h" @@ -122,7 +127,7 @@ 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_fp.req), sizeof(*req)); + memcpy(req, &(arm_default_req_arm_fpa.req), sizeof(*req)); } else if (mode_is_int(mode) || mode_is_reference(mode)) { memcpy(req, &(arm_default_req_arm_gp.req), sizeof(*req)); @@ -324,20 +329,84 @@ static void arm_emit_and_done(void *self) { free(self); } -enum convert_which { low, high }; +/** + * Move a double floating point value into an integer register. + * Place the move operation into block bl. + * + * Handle some special cases here: + * 1.) A constant: simply split into two + * 2.) A load: siply split into two + */ +static ir_node *convert_dbl_to_int(ir_node *bl, ir_node *arg, ir_node *mem, + ir_node **resH, ir_node **resL) { + if (is_Const(arg)) { + tarval *tv = get_Const_tarval(arg); + unsigned v; + + /* get the upper 32 bits */ + v = get_tarval_sub_bits(tv, 7); + v = (v << 8) | get_tarval_sub_bits(tv, 6); + v = (v << 8) | get_tarval_sub_bits(tv, 5); + v = (v << 8) | get_tarval_sub_bits(tv, 4); + *resH = new_Const_long(mode_Is, v); + + /* get the lower 32 bits */ + v = get_tarval_sub_bits(tv, 3); + v = (v << 8) | get_tarval_sub_bits(tv, 2); + v = (v << 8) | get_tarval_sub_bits(tv, 1); + v = (v << 8) | get_tarval_sub_bits(tv, 0); + *resL = new_Const_long(mode_Is, v); + } + else if (get_irn_op(skip_Proj(arg)) == op_Load) { + /* FIXME: handling of low/high depends on LE/BE here */ + assert(0); + } + else { + ir_graph *irg = current_ir_graph; + ir_node *conv; + + conv = new_rd_arm_fpaDbl2GP(NULL, irg, bl, arg, mem); + /* move high/low */ + *resL = new_r_Proj(irg, bl, conv, mode_Is, pn_arm_fpaDbl2GP_low); + *resH = new_r_Proj(irg, bl, conv, mode_Is, pn_arm_fpaDbl2GP_high); + mem = new_r_Proj(irg, bl, conv, mode_M, pn_arm_fpaDbl2GP_M); + } + return mem; +} /** - * Move an floating point value to a integer register. + * Move a single floating point value into an integer register. * Place the move operation into block bl. + * + * Handle some special cases here: + * 1.) A constant: simply move + * 2.) A load: siply load */ -static ir_node *convert_to_int(ir_node *bl, ir_node *arg, enum convert_which which) { +static ir_node *convert_sng_to_int(ir_node *bl, ir_node *arg) { + if (is_Const(arg)) { + tarval *tv = get_Const_tarval(arg); + unsigned v; + + /* get the lower 32 bits */ + v = get_tarval_sub_bits(tv, 3); + v = (v << 8) | get_tarval_sub_bits(tv, 2); + v = (v << 8) | get_tarval_sub_bits(tv, 1); + v = (v << 8) | get_tarval_sub_bits(tv, 0); + return new_Const_long(mode_Is, v); + } + else if (get_irn_op(skip_Proj(arg)) == op_Load) { + ir_node *load; + + load = skip_Proj(arg); + } + assert(0); return NULL; } /** * Convert the arguments of a call to support the * ARM calling convention of general purpose AND floating - * point arguments + * point arguments. */ static void handle_calls(ir_node *call, void *env) { @@ -373,18 +442,20 @@ static void handle_calls(ir_node *call, void *env) if (mode_is_float(mode)) { if (get_mode_size_bits(mode) > 32) { + ir_node *mem = get_Call_mem(call); + + /* Beware: ARM wants the high part first */ size += 2 * 4; - new_tp[idx] = cg->int_tp; - new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low); - ++idx; - new_tp[idx] = cg->int_tp; - new_in[idx] = convert_to_int(bl, get_Call_param(call, i), high); - ++idx; + new_tp[idx] = cg->int_tp; + new_tp[idx+1] = cg->int_tp; + mem = convert_dbl_to_int(bl, get_Call_param(call, i), mem, &new_in[idx], &new_in[idx+1]); + idx += 2; + set_Call_mem(call, mem); } else { size += 4; new_tp[idx] = cg->int_tp; - new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low); + new_in[idx] = convert_sng_to_int(bl, get_Call_param(call, i)); ++idx; } flag = 1; @@ -443,7 +514,7 @@ static void handle_calls(ir_node *call, void *env) } /** - * Handle graph transformations before the abi converter does it's work + * Handle graph transformations before the abi converter does its work. */ static void arm_before_abi(void *self) { arm_code_gen_t *cg = self; @@ -459,7 +530,7 @@ static const arch_code_generator_if_t arm_code_gen_if = { arm_prepare_graph, arm_before_sched, /* before scheduling hook */ arm_before_ra, /* before register allocation hook */ - NULL, /* after register allocation */ + NULL, /* after register allocation */ arm_emit_and_done, }; @@ -641,6 +712,7 @@ static arm_isa_t arm_isa_template = { 0, /* use generic register names instead of SP, LR, PC */ NULL, /* current code generator */ NULL, /* output file */ + ARM_FPU_ARCH_FPE, /* FPU architecture */ }; /** @@ -702,7 +774,7 @@ static int arm_get_n_reg_class(const void *self) { * Return the register class with requested index. */ static const arch_register_class_t *arm_get_reg_class(const void *self, int i) { - return i == 0 ? &arm_reg_classes[CLASS_arm_gp] : &arm_reg_classes[CLASS_arm_fp]; + return i == 0 ? &arm_reg_classes[CLASS_arm_gp] : &arm_reg_classes[CLASS_arm_fpa]; } /** @@ -713,7 +785,7 @@ 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_fp]; + return &arm_reg_classes[CLASS_arm_fpa]; else return &arm_reg_classes[CLASS_arm_gp]; } @@ -766,7 +838,7 @@ static void *arm_abi_init(const be_abi_call_t *call, const arch_env_t *arch_env, static void arm_abi_dont_save_regs(void *self, pset *s) { arm_abi_env_t *env = self; - if(env->flags.try_omit_fp) + if (env->flags.try_omit_fp) pset_insert_ptr(s, env->isa->bp); } @@ -941,7 +1013,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_fp_regs[REG_F0] : &arm_gp_regs[REG_R0]); + mode_is_float(mode) ? &arm_fpa_regs[REG_F0] : &arm_gp_regs[REG_R0]); } } @@ -988,7 +1060,24 @@ static int arm_get_reg_class_alignment(const void *self, const arch_register_cla } #ifdef WITH_LIBCORE + +/* fpu set architectures. */ +static const lc_opt_enum_int_items_t arm_fpu_items[] = { + { "softfloat", ARM_FPU_ARCH_SOFTFLOAT }, + { "fpe", ARM_FPU_ARCH_FPE }, + { "fpa", ARM_FPU_ARCH_FPA }, + { "vfp1xd", ARM_FPU_ARCH_VFP_V1xD }, + { "vfp1", ARM_FPU_ARCH_VFP_V1 }, + { "vfp2", ARM_FPU_ARCH_VFP_V2 }, + { NULL, 0 } +}; + +static lc_opt_enum_int_var_t arch_fpu_var = { + &arm_isa_template.fpu_arch, arm_fpu_items +}; + static const lc_opt_table_entry_t arm_options[] = { + LC_OPT_ENT_ENUM_INT("fpunit", "select the floating point unit", &arch_fpu_var), LC_OPT_ENT_BOOL("gen_reg_names", "use generic register names", &arm_isa_template.gen_reg_names), { NULL } }; @@ -998,6 +1087,7 @@ static const lc_opt_table_entry_t arm_options[] = { * * Options so far: * + * arm-fpuunit=unit select the floating point unit * arm-gen_reg_names use generic register names instead of SP, LR, PC */ static void arm_register_options(lc_opt_entry_t *ent) diff --git a/ir/be/arm/bearch_arm_t.h b/ir/be/arm/bearch_arm_t.h index 01f781c57..7091dea31 100644 --- a/ir/be/arm/bearch_arm_t.h +++ b/ir/be/arm/bearch_arm_t.h @@ -11,6 +11,103 @@ typedef struct _arm_isa_t arm_isa_t; +/** The following bitmasks control CPU extensions: */ +enum arm_cpu_extensions { + ARM_EXT_V1 = 0x00000001, /**< All processors (core set). */ + ARM_EXT_V2 = 0x00000002, /**< Multiply instructions. */ + ARM_EXT_V2S = 0x00000004, /**< SWP instructions. */ + ARM_EXT_V3 = 0x00000008, /**< MSR MRS. */ + ARM_EXT_V3M = 0x00000010, /**< Allow long multiplies. */ + ARM_EXT_V4 = 0x00000020, /**< Allow half word loads. */ + ARM_EXT_V4T = 0x00000040, /**< Thumb v1. */ + ARM_EXT_V5 = 0x00000080, /**< Allow CLZ, etc. */ + ARM_EXT_V5T = 0x00000100, /**< Thumb v2.ยด*/ + ARM_EXT_V5ExP = 0x00000200, /**< DSP core set. */ + ARM_EXT_V5E = 0x00000400, /**< DSP Double transfers. */ + ARM_EXT_V5J = 0x00000800, /**< Jazelle extension. */ + + /* Co-processor space extensions. */ + ARM_CEXT_XSCALE = 0x00800000, /**< Allow MIA etc. */ + ARM_CEXT_MAVERICK = 0x00400000, /**< Use Cirrus/DSP coprocessor. */ + ARM_CEXT_IWMMXT = 0x00200000, /**< Intel Wireless MMX technology coprocessor. */ +}; + +/** + * Architectures are the sum of the base and extensions. The ARM ARM (rev E) + * defines the following: ARMv3, ARMv3M, ARMv4xM, ARMv4, ARMv4TxM, ARMv4T, + * ARMv5xM, ARMv5, ARMv5TxM, ARMv5T, ARMv5TExP, ARMv5TE. To these we add + * three more to cover cores prior to ARM6. Finally, there are cores which + * implement further extensions in the co-processor space. + */ +enum arm_architectiures { + ARM_ARCH_V1 = ARM_EXT_V1, + ARM_ARCH_V2 = ARM_ARCH_V1 | ARM_EXT_V2, + ARM_ARCH_V2S = ARM_ARCH_V2 | ARM_EXT_V2S, + ARM_ARCH_V3 = ARM_ARCH_V2S | ARM_EXT_V3, + ARM_ARCH_V3M = ARM_ARCH_V3 | ARM_EXT_V3M, + ARM_ARCH_V4xM = ARM_ARCH_V3 | ARM_EXT_V4, + ARM_ARCH_V4 = ARM_ARCH_V3M | ARM_EXT_V4, + ARM_ARCH_V4TxM = ARM_ARCH_V4xM | ARM_EXT_V4T, + ARM_ARCH_V4T = ARM_ARCH_V4 | ARM_EXT_V4T, + ARM_ARCH_V5xM = ARM_ARCH_V4xM| ARM_EXT_V5, + ARM_ARCH_V5 = ARM_ARCH_V4 | ARM_EXT_V5, + ARM_ARCH_V5TxM = ARM_ARCH_V5xM | ARM_EXT_V4T | ARM_EXT_V5T, + ARM_ARCH_V5T = ARM_ARCH_V5 | ARM_EXT_V4T | ARM_EXT_V5T, + ARM_ARCH_V5TExP = ARM_ARCH_V5T | ARM_EXT_V5ExP, + ARM_ARCH_V5TE = ARM_ARCH_V5TExP | ARM_EXT_V5E, + ARM_ARCH_V5TEJ = ARM_ARCH_V5TE | ARM_EXT_V5J, + + /* Processors with specific extensions in the co-processor space. */ + ARM_ARCH_XSCALE = ARM_ARCH_V5TE | ARM_CEXT_XSCALE, + ARM_ARCH_IWMMXT = ARM_ARCH_XSCALE | ARM_CEXT_IWMMXT, + + ARM_ARCH_MASK = 0x00ffffff, +}; + +/** Floating point instruction set. */ +enum arm_fp_architectures { + ARM_FPU_FPA_EXT_V1 = 0x80000000, /**< Base FPA instruction set. */ + ARM_FPU_FPA_EXT_V2 = 0x40000000, /**< LFM/SFM. */ + ARM_FPU_VFP_EXT_NONE = 0x20000000, /**< Use VFP word-ordering. */ + ARM_FPU_VFP_EXT_V1xD = 0x10000000, /**< Base VFP instruction set. */ + ARM_FPU_VFP_EXT_V1 = 0x08000000, /**< Double-precision insns. */ + ARM_FPU_VFP_EXT_V2 = 0x04000000, /**< ARM10E VFPr1. */ + + ARM_FPU_SOFTFLOAT = 0x01000000, /**< soft float library */ + ARM_FPU_NONE = 0, + + ARM_FPU_ARCH_FPE = ARM_FPU_FPA_EXT_V1, + ARM_FPU_ARCH_FPA = ARM_FPU_ARCH_FPE | ARM_FPU_FPA_EXT_V2, + + ARM_FPU_ARCH_VFP = ARM_FPU_VFP_EXT_NONE, + ARM_FPU_ARCH_VFP_V1xD = ARM_FPU_VFP_EXT_V1xD | ARM_FPU_VFP_EXT_NONE, + ARM_FPU_ARCH_VFP_V1 = ARM_FPU_ARCH_VFP_V1xD | ARM_FPU_VFP_EXT_V1, + ARM_FPU_ARCH_VFP_V2 = ARM_FPU_ARCH_VFP_V1 | ARM_FPU_VFP_EXT_V2, + + ARM_FPU_ARCH_SOFTFLOAT = ARM_FPU_SOFTFLOAT, + + ARM_FPU_MASK = 0xff000000, +}; + +/** Returns non-zero if FPA instructions should be issued. */ +#define USE_FPA(cg) ((cg)->fpu_arch & ARM_FPU_FPA_EXT_V1) + +/** Returns non-zero if VFP instructions should be issued. */ +#define USE_VFP(cg) ((cg)->fpu_arch & ARM_FPU_VFP_EXT_V1xD) + +/** Types of processor to generate code for. */ +enum arm_processor_types { + ARM_1 = ARM_ARCH_V1, + ARM_2 = ARM_ARCH_V2, + ARM_3 = ARM_ARCH_V2S, + ARM_250 = ARM_ARCH_V2S, + ARM_6 = ARM_ARCH_V3, + ARM_7 = ARM_ARCH_V3, + ARM_8 = ARM_ARCH_V4, + ARM_9 = ARM_ARCH_V4T, + ARM_STRONG = ARM_ARCH_V4, +}; + typedef struct _arm_code_gen_t { const arch_code_generator_if_t *impl; /**< implementation */ ir_graph *irg; /**< current irg */ @@ -34,6 +131,8 @@ struct _arm_isa_t { int gen_reg_names; /**< use generic register names instead of SP, LR, PC */ arm_code_gen_t *cg; /**< current code generator */ FILE *out; /**< output file */ + + unsigned fpu_arch; /**< FPU architecture */ };