X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Farm%2Fbearch_arm.c;h=2ba456b8f860373d5dff42375b9944e947c09886;hb=abba32f7ea7e0362d2fbbad9b18b39bbd5e2b57d;hp=e37021ef33d021ad652c019fb4118c224497e3bb;hpb=50f482ecba37330c44324feafb85fad850a91650;p=libfirm diff --git a/ir/be/arm/bearch_arm.c b/ir/be/arm/bearch_arm.c index e37021ef3..2ba456b8f 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)); @@ -226,6 +231,10 @@ static entity *arm_get_frame_entity(const void *self, const ir_node *irn) { return NULL; } +static void arm_set_frame_entity(const void *self, ir_node *irn, entity *ent) { + /* TODO: set the entity assigned to the frame */ +} + /** * This function is called by the generic backend to correct offsets for * nodes accessing the stack. @@ -234,6 +243,10 @@ static void arm_set_stack_bias(const void *self, ir_node *irn, int bias) { /* TODO: correct offset if irn accesses the stack */ } +static int arm_get_sp_bias(const void *self, const ir_node *irn) { + return 0; +} + /* fill register allocator interface */ static const arch_irn_ops_if_t arm_irn_ops_if = { @@ -243,7 +256,13 @@ static const arch_irn_ops_if_t arm_irn_ops_if = { arm_classify, arm_get_flags, arm_get_frame_entity, - arm_set_stack_bias + arm_set_frame_entity, + arm_set_stack_bias, + arm_get_sp_bias, + NULL, /* get_inverse */ + NULL, /* get_op_estimated_cost */ + NULL, /* possible_memory_operand */ + NULL, /* perform_memory_operand */ }; arm_irn_ops_t arm_irn_ops = { @@ -280,7 +299,7 @@ static void arm_prepare_graph(void *self) { /** * Called immediately before emit phase. */ -static void arm_finish_irg(ir_graph *irg, arm_code_gen_t *cg) { +static void arm_finish_irg(void *self) { /* TODO: - fix offsets for nodes accessing stack - ... */ @@ -313,7 +332,6 @@ static void arm_emit_and_done(void *self) { cg->emit_decls = 0; } - arm_finish_irg(irg, cg); dump_ir_block_graph_sched(irg, "-arm-finished"); arm_gen_routine(out, irg, cg); @@ -324,20 +342,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 +455,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 +527,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 +543,8 @@ 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_finish_irg, arm_emit_and_done, }; @@ -511,7 +596,7 @@ static void *arm_cg_init(const be_irg_t *birg) { * and map all instructions the backend did not support * to runtime calls. */ -static void arm_global_init(void) { +static void arm_handle_intrinsics(void) { ir_type *tp, *int_tp, *uint_tp; i_record records[8]; int n_records = 0; @@ -641,6 +726,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 */ }; /** @@ -669,7 +755,7 @@ static void *arm_init(FILE *file_handle) { isa->out = file_handle; arm_create_opcodes(); - arm_global_init(); + arm_handle_intrinsics(); arm_switch_section(NULL, NO_SECTION); inited = 1; @@ -702,7 +788,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 +799,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 +852,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); } @@ -801,8 +887,8 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * return env->isa->sp; ip = be_new_Copy(gp, irg, block, sp ); - 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] ); + 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; @@ -811,13 +897,13 @@ static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap * // 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_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); + store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem); 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); + sp = new_r_Proj(irg, block, store, env->isa->sp->reg_class->mode, pn_arm_StoreStackM4Inc_ptr); arch_set_irn_register(env->arch_env, sp, env->isa->sp); - *mem = new_r_Proj(irg, block, store, mode_M, 1); + *mem = new_r_Proj(irg, block, store, mode_M, pn_arm_StoreStackM4Inc_M); keep = be_new_CopyKeep_single(gp, irg, block, ip, sp, get_irn_mode(ip)); be_node_set_reg_class(keep, 1, gp); @@ -855,7 +941,8 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m // 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_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK); + add_irn_dep(curr_sp, *mem); 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]); @@ -872,14 +959,14 @@ static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_m 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 ); + load_node = new_rd_arm_LoadStackM3( NULL, env->irg, bl, sub12_node, *mem ); 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); + curr_bp = new_r_Proj(env->irg, bl, load_node, env->isa->bp->reg_class->mode, pn_arm_LoadStackM3_res0); + curr_sp = new_r_Proj(env->irg, bl, load_node, env->isa->sp->reg_class->mode, pn_arm_LoadStackM3_res1); + curr_pc = new_r_Proj(env->irg, bl, load_node, mode_Iu, pn_arm_LoadStackM3_res2); + *mem = new_r_Proj(env->irg, bl, load_node, mode_M, pn_arm_LoadStackM3_M); 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_gp_regs[REG_PC]); @@ -941,7 +1028,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]); } } @@ -973,7 +1060,7 @@ list_sched_selector_t arm_sched_selector; /** * Returns the reg_pressure scheduler with to_appear_in_schedule() over\loaded */ -static const list_sched_selector_t *arm_get_list_sched_selector(const void *self) { +static const list_sched_selector_t *arm_get_list_sched_selector(const void *self, list_sched_selector_t *selector) { memcpy(&arm_sched_selector, reg_pressure_selector, sizeof(list_sched_selector_t)); arm_sched_selector.to_appear_in_schedule = arm_to_appear_in_schedule; return &arm_sched_selector; @@ -987,8 +1074,49 @@ static int arm_get_reg_class_alignment(const void *self, const arch_register_cla return get_mode_size_bytes(mode); } +/** + * Returns the libFirm configuration parameter for this backend. + */ +static const backend_params *arm_get_libfirm_params(void) { + static arch_dep_params_t ad = { + 1, /* allow subs */ + 0, /* Muls are fast enough on ARM */ + 31, /* shift would be ok */ + 0, /* SMUL is needed, only in Arch M*/ + 0, /* UMUL is needed, only in Arch M */ + 32, /* SMUL & UMUL available for 32 bit */ + }; + static backend_params p = { + NULL, /* no additional opcodes */ + NULL, /* will be set later */ + 1, /* need dword lowering */ + NULL, /* but yet no creator function */ + NULL, /* context for create_intrinsic_fkt */ + }; + + p.dep_param = &ad; + return &p; +} + #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 +1126,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) @@ -1018,6 +1147,7 @@ const arch_isa_if_t arm_isa_if = { arm_get_code_generator_if, arm_get_list_sched_selector, arm_get_reg_class_alignment, + arm_get_libfirm_params, #ifdef WITH_LIBCORE arm_register_options #endif