X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Farm%2Farm_transform.c;h=053d90d0bdafbe7cc2a5d81af90b25609c07d164;hb=6e5fd745c70d70f56fbe65df64983675897eb304;hp=bccdabfe09782812a4d3263bb6f070aa7bf00f6d;hpb=84bb5671d163da15a968fb9240fe3e90ec636485;p=libfirm diff --git a/ir/be/arm/arm_transform.c b/ir/be/arm/arm_transform.c index bccdabfe0..053d90d0b 100644 --- a/ir/be/arm/arm_transform.c +++ b/ir/be/arm/arm_transform.c @@ -30,7 +30,6 @@ #include "irmode_t.h" #include "irgmod.h" #include "iredges.h" -#include "irvrfy.h" #include "ircons.h" #include "irprintf.h" #include "dbginfo.h" @@ -64,6 +63,7 @@ static arm_code_gen_t *env_cg; static const arch_register_t *sp_reg = &arm_gp_regs[REG_SP]; static ir_mode *mode_gp; +static ir_mode *mode_fp; static beabi_helper_env_t *abihelper; static calling_convention_t *cconv = NULL; @@ -219,14 +219,18 @@ static ir_node *gen_Conv(ir_node *node) if (mode_is_float(src_mode)) { if (mode_is_float(dst_mode)) { /* from float to float */ - return new_bd_arm_fpaMvf(dbg, block, new_op, dst_mode); + return new_bd_arm_Mvf(dbg, block, new_op, dst_mode); } else { /* from float to int */ - return new_bd_arm_fpaFix(dbg, block, new_op, dst_mode); + panic("TODO"); } } else { /* from int to float */ - return new_bd_arm_fpaFlt(dbg, block, new_op, dst_mode); + if (!mode_is_signed(src_mode)) { + panic("TODO"); + } else { + return new_bd_arm_FltX(dbg, block, new_op, dst_mode); + } } } else if (USE_VFP(env_cg->isa)) { panic("VFP not supported yet"); @@ -347,15 +351,28 @@ static ir_node *arm_skip_downconv(ir_node *node) typedef enum { MATCH_NONE = 0, - MATCH_COMMUTATIVE = 1 << 0, - MATCH_SIZE_NEUTRAL = 1 << 1, + MATCH_COMMUTATIVE = 1 << 0, /**< commutative node */ + MATCH_REVERSE = 1 << 1, /**< support reverse opcode */ + MATCH_SIZE_NEUTRAL = 1 << 2, + MATCH_SKIP_NOT = 1 << 3, /**< skip Not on ONE input */ } match_flags_t; -typedef ir_node* (*new_binop_reg_func) (dbg_info *dbgi, ir_node *block, ir_node *op1, ir_node *op2); -typedef ir_node* (*new_binop_imm_func) (dbg_info *dbgi, ir_node *block, ir_node *op1, unsigned char imm8, unsigned char imm_rot); +/** + * possible binop constructors. + */ +typedef struct arm_binop_factory_t { + /** normal reg op reg operation. */ + ir_node *(*new_binop_reg)(dbg_info *dbgi, ir_node *block, ir_node *op1, ir_node *op2); + /** normal reg op imm operation. */ + ir_node *(*new_binop_imm)(dbg_info *dbgi, ir_node *block, ir_node *op1, unsigned char imm8, unsigned char imm_rot); + /** barrel shifter reg op (reg shift reg operation. */ + ir_node *(*new_binop_reg_shift_reg)(dbg_info *dbgi, ir_node *block, ir_node *left, ir_node *right, ir_node *shift, arm_shift_modifier_t shift_modifier); + /** barrel shifter reg op (reg shift imm operation. */ + ir_node *(*new_binop_reg_shift_imm)(dbg_info *dbgi, ir_node *block, ir_node *left, ir_node *right, arm_shift_modifier_t shift_modifier, unsigned shift_immediate); +} arm_binop_factory_t; static ir_node *gen_int_binop(ir_node *node, match_flags_t flags, - new_binop_reg_func new_reg, new_binop_imm_func new_imm) + const arm_binop_factory_t *factory) { ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op1 = get_binop_left(node); @@ -365,6 +382,14 @@ static ir_node *gen_int_binop(ir_node *node, match_flags_t flags, dbg_info *dbgi = get_irn_dbg_info(node); arm_immediate_t imm; + if (flags & MATCH_SKIP_NOT) { + if (is_Not(op1)) + op1 = get_Not_op(op1); + else if (is_Not(op2)) + op2 = get_Not_op(op2); + else + panic("cannot execute MATCH_SKIP_NOT"); + } if (flags & MATCH_SIZE_NEUTRAL) { op1 = arm_skip_downconv(op1); op2 = arm_skip_downconv(op2); @@ -374,15 +399,91 @@ static ir_node *gen_int_binop(ir_node *node, match_flags_t flags, if (try_encode_as_immediate(op2, &imm)) { ir_node *new_op1 = be_transform_node(op1); - return new_imm(dbgi, block, new_op1, imm.imm_8, imm.rot); + return factory->new_binop_imm(dbgi, block, new_op1, imm.imm_8, imm.rot); } new_op2 = be_transform_node(op2); - if ((flags & MATCH_COMMUTATIVE) && try_encode_as_immediate(op1, &imm)) { - return new_imm(dbgi, block, new_op2, imm.imm_8, imm.rot); + if ((flags & (MATCH_COMMUTATIVE|MATCH_REVERSE)) && try_encode_as_immediate(op1, &imm)) { + if (flags & MATCH_REVERSE) + return factory[1].new_binop_imm(dbgi, block, new_op2, imm.imm_8, imm.rot); + else + return factory[0].new_binop_imm(dbgi, block, new_op2, imm.imm_8, imm.rot); } new_op1 = be_transform_node(op1); - return new_reg(dbgi, block, new_op1, new_op2); + /* check if we can fold in a Mov */ + if (is_arm_Mov(new_op2)) { + const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(new_op2); + + switch (attr->shift_modifier) { + case ARM_SHF_IMM: + case ARM_SHF_ASR_IMM: + case ARM_SHF_LSL_IMM: + case ARM_SHF_LSR_IMM: + case ARM_SHF_ROR_IMM: + if (factory->new_binop_reg_shift_imm) { + ir_node *mov_op = get_irn_n(new_op2, 0); + return factory->new_binop_reg_shift_imm(dbgi, block, new_op1, mov_op, + attr->shift_modifier, attr->shift_immediate); + } + break; + + case ARM_SHF_ASR_REG: + case ARM_SHF_LSL_REG: + case ARM_SHF_LSR_REG: + case ARM_SHF_ROR_REG: + if (factory->new_binop_reg_shift_reg) { + ir_node *mov_op = get_irn_n(new_op2, 0); + ir_node *mov_sft = get_irn_n(new_op2, 1); + return factory->new_binop_reg_shift_reg(dbgi, block, new_op1, mov_op, mov_sft, + attr->shift_modifier); + } + break; + case ARM_SHF_REG: + case ARM_SHF_RRX: + break; + case ARM_SHF_INVALID: + panic("invalid shift"); + } + } + if ((flags & (MATCH_COMMUTATIVE|MATCH_REVERSE)) && is_arm_Mov(new_op1)) { + const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(new_op1); + int idx = flags & MATCH_REVERSE ? 1 : 0; + + switch (attr->shift_modifier) { + ir_node *mov_op, *mov_sft; + + case ARM_SHF_IMM: + case ARM_SHF_ASR_IMM: + case ARM_SHF_LSL_IMM: + case ARM_SHF_LSR_IMM: + case ARM_SHF_ROR_IMM: + if (factory[idx].new_binop_reg_shift_imm) { + mov_op = get_irn_n(new_op1, 0); + return factory[idx].new_binop_reg_shift_imm(dbgi, block, new_op2, mov_op, + attr->shift_modifier, attr->shift_immediate); + } + break; + + case ARM_SHF_ASR_REG: + case ARM_SHF_LSL_REG: + case ARM_SHF_LSR_REG: + case ARM_SHF_ROR_REG: + if (factory[idx].new_binop_reg_shift_reg) { + mov_op = get_irn_n(new_op1, 0); + mov_sft = get_irn_n(new_op1, 1); + return factory[idx].new_binop_reg_shift_reg(dbgi, block, new_op2, mov_op, mov_sft, + attr->shift_modifier); + } + break; + + case ARM_SHF_REG: + case ARM_SHF_RRX: + break; + case ARM_SHF_INVALID: + panic("invalid shift"); + } + } + return factory->new_binop_reg(dbgi, block, new_op1, new_op2); } /** @@ -392,7 +493,14 @@ static ir_node *gen_int_binop(ir_node *node, match_flags_t flags, */ static ir_node *gen_Add(ir_node *node) { - ir_mode *mode = get_irn_mode(node); + static const arm_binop_factory_t add_factory = { + new_bd_arm_Add_reg, + new_bd_arm_Add_imm, + new_bd_arm_Add_reg_shift_reg, + new_bd_arm_Add_reg_shift_imm + }; + + ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { ir_node *block = be_transform_node(get_nodes_block(node)); @@ -402,13 +510,7 @@ static ir_node *gen_Add(ir_node *node) ir_node *new_op1 = be_transform_node(op1); ir_node *new_op2 = be_transform_node(op2); if (USE_FPA(env_cg->isa)) { -#if 0 - if (is_arm_fpaMvf_i(new_op1)) - return new_bd_arm_fpaAdf_i(dbgi, block, new_op2, mode, get_arm_imm_value(new_op1)); - if (is_arm_fpaMvf_i(new_op2)) - return new_bd_arm_fpaAdf_i(dbgi, block, new_op1, mode, get_arm_imm_value(new_op2)); -#endif - return new_bd_arm_fpaAdf(dbgi, block, new_op1, new_op2, mode); + return new_bd_arm_Adf(dbgi, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -434,8 +536,7 @@ static ir_node *gen_Add(ir_node *node) } #endif - return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, - new_bd_arm_Add_reg, new_bd_arm_Add_imm); + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &add_factory); } } @@ -456,13 +557,7 @@ static ir_node *gen_Mul(ir_node *node) if (mode_is_float(mode)) { if (USE_FPA(env_cg->isa)) { -#if 0 - if (is_arm_Mov_i(new_op1)) - return new_bd_arm_fpaMuf_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); - if (is_arm_Mov_i(new_op2)) - return new_bd_arm_fpaMuf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); -#endif - return new_bd_arm_fpaMuf(dbg, block, new_op1, new_op2, mode); + return new_bd_arm_Muf(dbg, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -487,13 +582,7 @@ static ir_node *gen_Quot(ir_node *node) assert(mode != mode_E && "IEEE Extended FP not supported"); if (USE_FPA(env_cg->isa)) { -#if 0 - if (is_arm_Mov_i(new_op1)) - return new_bd_arm_fpaRdf_i(dbg, block, new_op2, mode, get_arm_imm_value(new_op1)); - if (is_arm_Mov_i(new_op2)) - return new_bd_arm_fpaDvf_i(dbg, block, new_op1, mode, get_arm_imm_value(new_op2)); -#endif - return new_bd_arm_fpaDvf(dbg, block, new_op1, new_op2, mode); + return new_bd_arm_Dvf(dbg, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -504,24 +593,72 @@ static ir_node *gen_Quot(ir_node *node) static ir_node *gen_And(ir_node *node) { - return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, - new_bd_arm_And_reg, new_bd_arm_And_imm); + static const arm_binop_factory_t and_factory = { + new_bd_arm_And_reg, + new_bd_arm_And_imm, + new_bd_arm_And_reg_shift_reg, + new_bd_arm_And_reg_shift_imm + }; + static const arm_binop_factory_t bic_factory = { + new_bd_arm_Bic_reg, + new_bd_arm_Bic_imm, + new_bd_arm_Bic_reg_shift_reg, + new_bd_arm_Bic_reg_shift_imm + }; + + /* check for and not */ + ir_node *left = get_And_left(node); + ir_node *right = get_And_right(node); + + if (is_Not(left) || is_Not(right)) { + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL | MATCH_SKIP_NOT, + &bic_factory); + } + + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &and_factory); } static ir_node *gen_Or(ir_node *node) { - return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, - new_bd_arm_Or_reg, new_bd_arm_Or_imm); + static const arm_binop_factory_t or_factory = { + new_bd_arm_Or_reg, + new_bd_arm_Or_imm, + new_bd_arm_Or_reg_shift_reg, + new_bd_arm_Or_reg_shift_imm + }; + + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &or_factory); } static ir_node *gen_Eor(ir_node *node) { - return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, - new_bd_arm_Eor_reg, new_bd_arm_Eor_imm); + static const arm_binop_factory_t eor_factory = { + new_bd_arm_Eor_reg, + new_bd_arm_Eor_imm, + new_bd_arm_Eor_reg_shift_reg, + new_bd_arm_Eor_reg_shift_imm + }; + + return gen_int_binop(node, MATCH_COMMUTATIVE | MATCH_SIZE_NEUTRAL, &eor_factory); } static ir_node *gen_Sub(ir_node *node) { + static const arm_binop_factory_t sub_rsb_factory[2] = { + { + new_bd_arm_Sub_reg, + new_bd_arm_Sub_imm, + new_bd_arm_Sub_reg_shift_reg, + new_bd_arm_Sub_reg_shift_imm + }, + { + new_bd_arm_Rsb_reg, + new_bd_arm_Rsb_imm, + new_bd_arm_Rsb_reg_shift_reg, + new_bd_arm_Rsb_reg_shift_imm + } + }; + ir_node *block = be_transform_node(get_nodes_block(node)); ir_node *op1 = get_Sub_left(node); ir_node *new_op1 = be_transform_node(op1); @@ -532,13 +669,7 @@ static ir_node *gen_Sub(ir_node *node) if (mode_is_float(mode)) { if (USE_FPA(env_cg->isa)) { -#if 0 - if (is_arm_Mov_i(new_op1)) - return new_bd_arm_fpaRsf_i(dbgi, block, new_op2, mode, get_arm_imm_value(new_op1)); - if (is_arm_Mov_i(new_op2)) - return new_bd_arm_fpaSuf_i(dbgi, block, new_op1, mode, get_arm_imm_value(new_op2)); -#endif - return new_bd_arm_fpaSuf(dbgi, block, new_op1, new_op2, mode); + return new_bd_arm_Suf(dbgi, block, new_op1, new_op2, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -546,8 +677,7 @@ static ir_node *gen_Sub(ir_node *node) panic("Softfloat not supported yet"); } } else { - return gen_int_binop(node, MATCH_SIZE_NEUTRAL, - new_bd_arm_Sub_reg, new_bd_arm_Sub_imm); + return gen_int_binop(node, MATCH_SIZE_NEUTRAL | MATCH_REVERSE, sub_rsb_factory); } } @@ -715,31 +845,40 @@ static ir_node *gen_Not(ir_node *node) ir_node *new_op = be_transform_node(op); dbg_info *dbgi = get_irn_dbg_info(node); - /* TODO: we could do alot more here with all the Mvn variations */ - - return new_bd_arm_Mvn_reg(dbgi, block, new_op); -} - -static ir_node *gen_Abs(ir_node *node) -{ - ir_node *block = be_transform_node(get_nodes_block(node)); - ir_node *op = get_Abs_op(node); - ir_node *new_op = be_transform_node(op); - dbg_info *dbgi = get_irn_dbg_info(node); - ir_mode *mode = get_irn_mode(node); - - if (mode_is_float(mode)) { - if (USE_FPA(env_cg->isa)) { - return new_bd_arm_fpaAbs(dbgi, block, new_op, mode); - } else if (USE_VFP(env_cg->isa)) { - assert(mode != mode_E && "IEEE Extended FP not supported"); - panic("VFP not supported yet"); - } else { - panic("Softfloat not supported yet"); + /* check if we can fold in a Mov */ + if (is_arm_Mov(new_op)) { + const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(new_op); + + switch (attr->shift_modifier) { + ir_node *mov_op, *mov_sft; + + case ARM_SHF_IMM: + case ARM_SHF_ASR_IMM: + case ARM_SHF_LSL_IMM: + case ARM_SHF_LSR_IMM: + case ARM_SHF_ROR_IMM: + mov_op = get_irn_n(new_op, 0); + return new_bd_arm_Mvn_reg_shift_imm(dbgi, block, mov_op, + attr->shift_modifier, attr->shift_immediate); + + case ARM_SHF_ASR_REG: + case ARM_SHF_LSL_REG: + case ARM_SHF_LSR_REG: + case ARM_SHF_ROR_REG: + mov_op = get_irn_n(new_op, 0); + mov_sft = get_irn_n(new_op, 1); + return new_bd_arm_Mvn_reg_shift_reg(dbgi, block, mov_op, mov_sft, + attr->shift_modifier); + + case ARM_SHF_REG: + case ARM_SHF_RRX: + break; + case ARM_SHF_INVALID: + panic("invalid shift"); } } - assert(mode_is_data(mode)); - return new_bd_arm_Abs(dbgi, block, new_op); + + return new_bd_arm_Mvn_reg(dbgi, block, new_op); } static ir_node *gen_Minus(ir_node *node) @@ -752,7 +891,7 @@ static ir_node *gen_Minus(ir_node *node) if (mode_is_float(mode)) { if (USE_FPA(env_cg->isa)) { - return new_bd_arm_fpaMvf(dbgi, block, op, mode); + return new_bd_arm_Mvf(dbgi, block, op, mode); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -777,7 +916,8 @@ static ir_node *gen_Load(ir_node *node) if (mode_is_float(mode)) { if (USE_FPA(env_cg->isa)) { - new_load = new_bd_arm_fpaLdf(dbgi, block, new_ptr, new_mem, mode); + new_load = new_bd_arm_Ldf(dbgi, block, new_ptr, new_mem, mode, + NULL, 0, 0, false); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -816,8 +956,8 @@ static ir_node *gen_Store(ir_node *node) if (mode_is_float(mode)) { if (USE_FPA(env_cg->isa)) { - new_store = new_bd_arm_fpaStf(dbgi, block, new_ptr, new_val, - new_mem, mode); + new_store = new_bd_arm_Stf(dbgi, block, new_ptr, new_val, + new_mem, mode, NULL, 0, 0, false); } else if (USE_VFP(env_cg->isa)) { assert(mode != mode_E && "IEEE Extended FP not supported"); panic("VFP not supported yet"); @@ -901,39 +1041,11 @@ static ir_node *gen_Cmp(ir_node *node) new_op2 = be_transform_node(op2); return new_bd_arm_Cmfe(dbgi, block, new_op1, new_op2, false); - - panic("FloatCmp NIY"); -#if 0 - ir_node *new_op2 = be_transform_node(op2); - /* floating point compare */ - pn_Cmp pnc = get_Proj_proj(selector); - - if (pnc & pn_Cmp_Uo) { - /* check for unordered, need cmf */ - return new_bd_arm_fpaCmfBra(dbgi, block, new_op1, new_op2, pnc); - } - /* Hmm: use need cmfe */ - return new_bd_arm_fpaCmfeBra(dbgi, block, new_op1, new_op2, pnc); -#endif } assert(get_irn_mode(op2) == cmp_mode); is_unsigned = !mode_is_signed(cmp_mode); - /* compare with 0 can be done with Tst */ - if (is_Const(op2) && tarval_is_null(get_Const_tarval(op2))) { - new_op1 = be_transform_node(op1); - new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode); - return new_bd_arm_Tst_reg(dbgi, block, new_op1, new_op1, false, - is_unsigned); - } - if (is_Const(op1) && tarval_is_null(get_Const_tarval(op1))) { - new_op2 = be_transform_node(op2); - new_op2 = gen_extension(dbgi, block, new_op2, cmp_mode); - return new_bd_arm_Tst_reg(dbgi, block, new_op2, new_op2, true, - is_unsigned); - } - /* integer compare, TODO: use shifter_op in all its combinations */ new_op1 = be_transform_node(op1); new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode); @@ -1008,20 +1120,7 @@ static ir_node *gen_Const(ir_node *node) if (mode_is_float(mode)) { if (USE_FPA(env_cg->isa)) { tarval *tv = get_Const_tarval(node); -#if 0 - int imm = is_fpa_immediate(tv); - - if (imm != fpa_max) { - if (imm > 0) { - node = new_bd_arm_fpaMvf_i(dbg, block, mode, imm); - } else { - node = new_bd_arm_fpaMnf_i(dbg, block, mode, -imm); - } - } else -#endif - { - node = new_bd_arm_fpaConst(dbg, block, tv); - } + node = new_bd_arm_fConst(dbg, block, tv); be_dep_on_frame(node); return node; } else if (USE_VFP(env_cg->isa)) { @@ -1046,6 +1145,83 @@ static ir_node *gen_SymConst(ir_node *node) return new_node; } +static ir_node *ints_to_double(dbg_info *dbgi, ir_node *block, ir_node *node0, + ir_node *node1) +{ + /* the good way to do this would be to use the stm (store multiple) + * instructions, since our input is nearly always 2 consecutive 32bit + * registers... */ + ir_graph *irg = current_ir_graph; + ir_node *stack = get_irg_frame(irg); + ir_node *nomem = new_NoMem(); + ir_node *str0 = new_bd_arm_Str(dbgi, block, stack, node0, nomem, mode_gp, + NULL, 0, 0, true); + ir_node *str1 = new_bd_arm_Str(dbgi, block, stack, node1, nomem, mode_gp, + NULL, 0, 4, true); + ir_node *in[2] = { str0, str1 }; + ir_node *sync = new_r_Sync(block, 2, in); + ir_node *ldf; + set_irn_pinned(str0, op_pin_state_floats); + set_irn_pinned(str1, op_pin_state_floats); + + ldf = new_bd_arm_Ldf(dbgi, block, stack, sync, mode_D, NULL, 0, 0, true); + set_irn_pinned(ldf, op_pin_state_floats); + + return new_Proj(ldf, mode_fp, pn_arm_Ldf_res); +} + +static ir_node *int_to_float(dbg_info *dbgi, ir_node *block, ir_node *node) +{ + ir_graph *irg = current_ir_graph; + ir_node *stack = get_irg_frame(irg); + ir_node *nomem = new_NoMem(); + ir_node *str = new_bd_arm_Str(dbgi, block, stack, node, nomem, mode_gp, + NULL, 0, 0, true); + ir_node *ldf; + set_irn_pinned(str, op_pin_state_floats); + + ldf = new_bd_arm_Ldf(dbgi, block, stack, str, mode_F, NULL, 0, 0, true); + set_irn_pinned(ldf, op_pin_state_floats); + + return new_Proj(ldf, mode_fp, pn_arm_Ldf_res); +} + +static ir_node *float_to_int(dbg_info *dbgi, ir_node *block, ir_node *node) +{ + ir_graph *irg = current_ir_graph; + ir_node *stack = get_irg_frame(irg); + ir_node *nomem = new_NoMem(); + ir_node *stf = new_bd_arm_Stf(dbgi, block, stack, node, nomem, mode_F, + NULL, 0, 0, true); + ir_node *ldr; + set_irn_pinned(stf, op_pin_state_floats); + + ldr = new_bd_arm_Ldr(dbgi, block, stack, stf, mode_gp, NULL, 0, 0, true); + set_irn_pinned(ldr, op_pin_state_floats); + + return new_Proj(ldr, mode_gp, pn_arm_Ldr_res); +} + +static void double_to_ints(dbg_info *dbgi, ir_node *block, ir_node *node, + ir_node **out_value0, ir_node **out_value1) +{ + ir_graph *irg = current_ir_graph; + ir_node *stack = get_irg_frame(irg); + ir_node *nomem = new_NoMem(); + ir_node *stf = new_bd_arm_Stf(dbgi, block, stack, node, nomem, mode_D, + NULL, 0, 0, true); + ir_node *ldr0, *ldr1; + set_irn_pinned(stf, op_pin_state_floats); + + ldr0 = new_bd_arm_Ldr(dbgi, block, stack, stf, mode_gp, NULL, 0, 0, true); + set_irn_pinned(ldr0, op_pin_state_floats); + ldr1 = new_bd_arm_Ldr(dbgi, block, stack, stf, mode_gp, NULL, 0, 4, true); + set_irn_pinned(ldr1, op_pin_state_floats); + + *out_value0 = new_Proj(ldr0, mode_gp, pn_arm_Ldr_res); + *out_value1 = new_Proj(ldr1, mode_gp, pn_arm_Ldr_res); +} + static ir_node *gen_CopyB(ir_node *node) { ir_node *block = be_transform_node(get_nodes_block(node)); @@ -1070,6 +1246,82 @@ static ir_node *gen_CopyB(ir_node *node) new_mem, size); } +/** + * Transform builtin clz. + */ +static ir_node *gen_clz(ir_node *node) +{ + ir_node *block = be_transform_node(get_nodes_block(node)); + dbg_info *dbg = get_irn_dbg_info(node); + ir_node *op = get_irn_n(node, 1); + ir_node *new_op = be_transform_node(op); + + /* TODO armv5 instruction, otherwise create a call */ + return new_bd_arm_Clz(dbg, block, new_op); +} + +/** + * Transform Builtin node. + */ +static ir_node *gen_Builtin(ir_node *node) +{ + ir_builtin_kind kind = get_Builtin_kind(node); + + switch (kind) { + case ir_bk_trap: + case ir_bk_debugbreak: + case ir_bk_return_address: + case ir_bk_frame_address: + case ir_bk_prefetch: + case ir_bk_ffs: + break; + case ir_bk_clz: + return gen_clz(node); + case ir_bk_ctz: + case ir_bk_parity: + case ir_bk_popcount: + case ir_bk_bswap: + case ir_bk_outport: + case ir_bk_inport: + case ir_bk_inner_trampoline: + break; + } + panic("Builtin %s not implemented in ARM", get_builtin_kind_name(kind)); +} + +/** + * Transform Proj(Builtin) node. + */ +static ir_node *gen_Proj_Builtin(ir_node *proj) +{ + ir_node *node = get_Proj_pred(proj); + ir_node *new_node = be_transform_node(node); + ir_builtin_kind kind = get_Builtin_kind(node); + + switch (kind) { + case ir_bk_return_address: + case ir_bk_frame_address: + case ir_bk_ffs: + case ir_bk_clz: + case ir_bk_ctz: + case ir_bk_parity: + case ir_bk_popcount: + case ir_bk_bswap: + assert(get_Proj_proj(proj) == pn_Builtin_1_result); + return new_node; + case ir_bk_trap: + case ir_bk_debugbreak: + case ir_bk_prefetch: + case ir_bk_outport: + assert(get_Proj_proj(proj) == pn_Builtin_M); + return new_node; + case ir_bk_inport: + case ir_bk_inner_trampoline: + break; + } + panic("Builtin %s not implemented in ARM", get_builtin_kind_name(kind)); +} + static ir_node *gen_Proj_Load(ir_node *node) { ir_node *load = get_Proj_pred(node); @@ -1087,12 +1339,12 @@ static ir_node *gen_Proj_Load(ir_node *node) return new_rd_Proj(dbgi, new_load, mode_M, pn_arm_Ldr_M); } break; - case iro_arm_fpaLdf: + case iro_arm_Ldf: if (proj == pn_Load_res) { ir_mode *mode = get_Load_mode(load); - return new_rd_Proj(dbgi, new_load, mode, pn_arm_fpaLdf_res); + return new_rd_Proj(dbgi, new_load, mode, pn_arm_Ldf_res); } else if (proj == pn_Load_M) { - return new_rd_Proj(dbgi, new_load, mode_M, pn_arm_fpaLdf_M); + return new_rd_Proj(dbgi, new_load, mode_M, pn_arm_Ldf_M); } break; default: @@ -1130,25 +1382,13 @@ static ir_node *gen_Proj_Quot(ir_node *node) switch (proj) { case pn_Quot_M: - if (is_arm_fpaDvf(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_fpaDvf_M); - } else if (is_arm_fpaRdf(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_fpaRdf_M); - } else if (is_arm_fpaFdv(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_fpaFdv_M); - } else if (is_arm_fpaFrd(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_fpaFrd_M); + if (is_arm_Dvf(new_pred)) { + return new_rd_Proj(dbgi, new_pred, mode_M, pn_arm_Dvf_M); } break; case pn_Quot_res: - if (is_arm_fpaDvf(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode, pn_arm_fpaDvf_res); - } else if (is_arm_fpaRdf(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode, pn_arm_fpaRdf_res); - } else if (is_arm_fpaFdv(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode, pn_arm_fpaFdv_res); - } else if (is_arm_fpaFrd(new_pred)) { - return new_rd_Proj(dbgi, new_pred, mode, pn_arm_fpaFrd_res); + if (is_arm_Dvf(new_pred)) { + return new_rd_Proj(dbgi, new_pred, mode, pn_arm_Dvf_res); } break; default: @@ -1189,7 +1429,7 @@ static ir_node *gen_Proj_Start(ir_node *node) return be_prolog_get_reg_value(abihelper, sp_reg); case pn_Start_P_tls: - return new_bd_arm_LdTls(NULL, new_block); + return new_Bad(); case pn_Start_max: break; @@ -1199,7 +1439,12 @@ static ir_node *gen_Proj_Start(ir_node *node) static ir_node *gen_Proj_Proj_Start(ir_node *node) { - long pn = get_Proj_proj(node); + long pn = get_Proj_proj(node); + ir_node *block = get_nodes_block(node); + ir_node *new_block = be_transform_node(block); + ir_entity *entity = get_irg_entity(current_ir_graph); + ir_type *method_type = get_entity_type(entity); + ir_type *param_type = get_method_param_type(method_type, pn); const reg_or_stackslot_t *param; /* Proj->Proj->Start must be a method argument */ @@ -1209,18 +1454,50 @@ static ir_node *gen_Proj_Proj_Start(ir_node *node) if (param->reg0 != NULL) { /* argument transmitted in register */ - return be_prolog_get_reg_value(abihelper, param->reg0); + ir_mode *mode = get_type_mode(param_type); + ir_node *value = be_prolog_get_reg_value(abihelper, param->reg0); + + if (mode_is_float(mode)) { + ir_node *value1 = NULL; + + if (param->reg1 != NULL) { + value1 = be_prolog_get_reg_value(abihelper, param->reg1); + } else if (param->entity != NULL) { + ir_graph *irg = get_irn_irg(node); + ir_node *fp = get_irg_frame(irg); + ir_node *mem = be_prolog_get_memory(abihelper); + ir_node *ldr = new_bd_arm_Ldr(NULL, new_block, fp, mem, + mode_gp, param->entity, + 0, 0, true); + value1 = new_Proj(ldr, mode_gp, pn_arm_Ldr_res); + } + + /* convert integer value to float */ + if (value1 == NULL) { + value = int_to_float(NULL, new_block, value); + } else { + value = ints_to_double(NULL, new_block, value, value1); + } + } + return value; } else { /* argument transmitted on stack */ - ir_graph *irg = get_irn_irg(node); - ir_node *block = get_nodes_block(node); - ir_node *new_block = be_transform_node(block); - ir_node *fp = get_irg_frame(irg); - ir_node *mem = be_prolog_get_memory(abihelper); - ir_mode *mode = get_type_mode(param->type); - ir_node *load = new_bd_arm_Ldr(NULL, new_block, fp, mem, mode, - param->entity, 0, 0, true); - ir_node *value = new_r_Proj(load, mode_gp, pn_arm_Ldr_res); + ir_graph *irg = get_irn_irg(node); + ir_node *fp = get_irg_frame(irg); + ir_node *mem = be_prolog_get_memory(abihelper); + ir_mode *mode = get_type_mode(param->type); + ir_node *load; + ir_node *value; + + if (mode_is_float(mode)) { + load = new_bd_arm_Ldf(NULL, new_block, fp, mem, mode, + param->entity, 0, 0, true); + value = new_r_Proj(load, mode_fp, pn_arm_Ldf_res); + } else { + load = new_bd_arm_Ldr(NULL, new_block, fp, mem, mode, + param->entity, 0, 0, true); + value = new_r_Proj(load, mode_gp, pn_arm_Ldr_res); + } set_irn_pinned(load, op_pin_state_floats); return value; @@ -1250,7 +1527,7 @@ static ir_node *gen_Proj_Proj_Call(ir_node *node) ir_node *call = get_Proj_pred(get_Proj_pred(node)); ir_node *new_call = be_transform_node(call); ir_type *function_type = get_Call_type(call); - calling_convention_t *cconv = decide_calling_convention(function_type); + calling_convention_t *cconv = arm_decide_calling_convention(function_type); const reg_or_stackslot_t *res = &cconv->results[pn]; ir_mode *mode; int regn; @@ -1263,7 +1540,7 @@ static ir_node *gen_Proj_Proj_Call(ir_node *node) } mode = res->reg0->reg_class->mode; - free_calling_convention(cconv); + arm_free_calling_convention(cconv); return new_r_Proj(new_call, mode, regn); } @@ -1326,6 +1603,8 @@ static ir_node *gen_Proj(ir_node *node) } /* FALLTHROUGH */ } + case iro_Builtin: + return gen_Proj_Builtin(node); default: panic("code selection didn't expect Proj after %+F\n", pred); } @@ -1359,7 +1638,7 @@ static ir_node *gen_Unknown(ir_node *node) ir_mode *mode = get_irn_mode(node); if (mode_is_float(mode)) { tarval *tv = get_mode_null(mode); - ir_node *node = new_bd_arm_fpaConst(dbgi, new_block, tv); + ir_node *node = new_bd_arm_fConst(dbgi, new_block, tv); be_dep_on_frame(node); return node; } else if (mode_needs_gp_reg(mode)) { @@ -1512,14 +1791,10 @@ static ir_node *gen_Return(ir_node *node) ir_node *new_mem = be_transform_node(mem); int n_callee_saves = sizeof(callee_saves)/sizeof(callee_saves[0]); ir_node *sp_proj = get_stack_pointer_for(node); + int n_res = get_Return_n_ress(node); ir_node *bereturn; ir_node *incsp; int i; - int n_res; - const arch_register_t *const result_regs[] = { - &arm_gp_regs[REG_R0], - &arm_gp_regs[REG_R1] - }; be_epilog_begin(abihelper); be_epilog_set_memory(abihelper, new_mem); @@ -1530,14 +1805,12 @@ static ir_node *gen_Return(ir_node *node) sp_proj); /* result values */ - n_res = get_Return_n_ress(node); - if (n_res > (int) (sizeof(result_regs)/sizeof(result_regs[0]))) { - panic("Too many return values for arm backend (%+F)", node); - } for (i = 0; i < n_res; ++i) { - ir_node *res_value = get_Return_res(node, i); - ir_node *new_res_value = be_transform_node(res_value); - const arch_register_t *reg = result_regs[i]; + ir_node *res_value = get_Return_res(node, i); + ir_node *new_res_value = be_transform_node(res_value); + const reg_or_stackslot_t *slot = &cconv->results[i]; + const arch_register_t *reg = slot->reg0; + assert(slot->reg1 == NULL); be_epilog_add_reg(abihelper, reg, 0, new_res_value); } @@ -1573,7 +1846,7 @@ static ir_node *gen_Call(ir_node *node) ir_node *new_mem = be_transform_node(mem); dbg_info *dbgi = get_irn_dbg_info(node); ir_type *type = get_Call_type(node); - calling_convention_t *cconv = decide_calling_convention(type); + calling_convention_t *cconv = arm_decide_calling_convention(type); int n_params = get_Call_n_params(node); int n_param_regs = sizeof(param_regs)/sizeof(param_regs[0]); /* max inputs: memory, callee, register arguments */ @@ -1605,35 +1878,61 @@ static ir_node *gen_Call(ir_node *node) ++in_arity; /* parameters */ for (p = 0; p < n_params; ++p) { - ir_node *value = get_Call_param(node, p); - ir_node *new_value = be_transform_node(value); - const reg_or_stackslot_t *param = &cconv->parameters[p]; - const arch_register_t *reg = param->reg0; - - /* double not implemented yet */ - assert(get_mode_size_bits(get_irn_mode(value)) <= 32); - assert(param->reg1 == NULL); - - if (reg != NULL) { - in[in_arity] = new_value; - /* this should not happen, LR cannot be a parameter register ... */ - assert(reg != &arm_gp_regs[REG_LR]); - in_req[in_arity] = reg->single_req; - ++in_arity; - } else { - ir_mode *mode; - ir_node *str; - if (incsp == NULL) { - /* create a parameter frame */ - ir_node *new_frame = get_stack_pointer_for(node); - incsp = be_new_IncSP(sp_reg, new_block, new_frame, cconv->param_stack_size, 1); + ir_node *value = get_Call_param(node, p); + ir_node *new_value = be_transform_node(value); + ir_node *new_value1 = NULL; + const reg_or_stackslot_t *param = &cconv->parameters[p]; + ir_type *param_type = get_method_param_type(type, p); + ir_mode *mode = get_type_mode(param_type); + ir_node *str; + + if (mode_is_float(mode) && param->reg0 != NULL) { + unsigned size_bits = get_mode_size_bits(mode); + if (size_bits == 64) { + double_to_ints(dbgi, new_block, new_value, &new_value, + &new_value1); + } else { + assert(size_bits == 32); + new_value = float_to_int(dbgi, new_block, new_value); } - mode = get_irn_mode(value); - str = new_bd_arm_Str(dbgi, new_block, incsp, value, new_mem, mode, - NULL, 0, param->offset, true); + } + + /* put value into registers */ + if (param->reg0 != NULL) { + in[in_arity] = new_value; + in_req[in_arity] = param->reg0->single_req; + ++in_arity; + if (new_value1 == NULL) + continue; + } + if (param->reg1 != NULL) { + assert(new_value1 != NULL); + in[in_arity] = new_value1; + in_req[in_arity] = param->reg1->single_req; + ++in_arity; + continue; + } - sync_ins[sync_arity++] = str; + /* we need a store if we're here */ + if (new_value1 != NULL) { + new_value = new_value1; + mode = mode_gp; + } + + /* create a parameter frame if necessary */ + if (incsp == NULL) { + ir_node *new_frame = get_stack_pointer_for(node); + incsp = be_new_IncSP(sp_reg, new_block, new_frame, + cconv->param_stack_size, 1); + } + if (mode_is_float(mode)) { + str = new_bd_arm_Stf(dbgi, new_block, incsp, new_value, new_mem, + mode, NULL, 0, param->offset, true); + } else { + str = new_bd_arm_Str(dbgi, new_block, incsp, new_value, new_mem, + mode, NULL, 0, param->offset, true); } + sync_ins[sync_arity++] = str; } assert(in_arity <= max_inputs); @@ -1701,7 +2000,7 @@ static ir_node *gen_Call(ir_node *node) pmap_insert(node_to_stack, node, incsp); } - set_arm_in_req_all(res, in_req); + arch_set_in_register_reqs(res, in_req); /* create output register reqs */ arch_set_out_register_req(res, 0, arch_no_register_req); @@ -1713,7 +2012,7 @@ static ir_node *gen_Call(ir_node *node) /* copy pinned attribute */ set_irn_pinned(res, get_irn_pinned(node)); - free_calling_convention(cconv); + arm_free_calling_convention(cconv); return res; } @@ -1781,7 +2080,6 @@ static void arm_register_transformers(void) { be_start_transform_setup(); - be_set_transform_function(op_Abs, gen_Abs); be_set_transform_function(op_Add, gen_Add); be_set_transform_function(op_And, gen_And); be_set_transform_function(op_Call, gen_Call); @@ -1811,6 +2109,7 @@ static void arm_register_transformers(void) be_set_transform_function(op_Sub, gen_Sub); be_set_transform_function(op_SymConst, gen_SymConst); be_set_transform_function(op_Unknown, gen_Unknown); + be_set_transform_function(op_Builtin, gen_Builtin); } /** @@ -1858,6 +2157,7 @@ void arm_transform_graph(arm_code_gen_t *cg) ir_type *frame_type; mode_gp = mode_Iu; + mode_fp = mode_E; if (! imm_initialized) { arm_init_fpa_immediate(); @@ -1872,7 +2172,7 @@ void arm_transform_graph(arm_code_gen_t *cg) abihelper = be_abihelper_prepare(irg); be_collect_stacknodes(abihelper); assert(cconv == NULL); - cconv = decide_calling_convention(get_entity_type(entity)); + cconv = arm_decide_calling_convention(get_entity_type(entity)); create_stacklayout(irg); be_transform_graph(cg->irg, NULL); @@ -1880,7 +2180,7 @@ void arm_transform_graph(arm_code_gen_t *cg) be_abihelper_finish(abihelper); abihelper = NULL; - free_calling_convention(cconv); + arm_free_calling_convention(cconv); cconv = NULL; frame_type = get_irg_frame_type(irg);