X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_transform.c;h=c2a255a5f44f58f61e6f3ca99bb82a424318893a;hb=e407e33d9fdb18b3acde96b249d4c78c58650fab;hp=074300fabb6994cbd426bd4838e63af56e7e25ae;hpb=399e9483347d0d5d1b5fddd0e91685174df3ad0a;p=libfirm diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 074300fab..c2a255a5f 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -28,6 +28,7 @@ #include "../benode_t.h" #include "../besched.h" +#include "../beabi.h" #include "bearch_ia32_t.h" @@ -77,6 +78,37 @@ typedef enum { * ****************************************************************************************************/ +/** + * Returns 1 if irn is a Const representing 0, 0 otherwise + */ +static INLINE int is_ia32_Const_0(ir_node *irn) { + return is_ia32_Const(irn) ? classify_tarval(get_ia32_Immop_tarval(irn)) == TV_CLASSIFY_NULL : 0; +} + +/** + * Returns 1 if irn is a Const representing 1, 0 otherwise + */ +static INLINE int is_ia32_Const_1(ir_node *irn) { + return is_ia32_Const(irn) ? classify_tarval(get_ia32_Immop_tarval(irn)) == TV_CLASSIFY_ONE : 0; +} + +/** + * Returns the Proj representing the UNKNOWN register for given mode. + */ +static ir_node *be_get_unknown_for_mode(ia32_code_gen_t *cg, ir_mode *mode) { + be_abi_irg_t *babi = cg->birg->abi; + const arch_register_t *unknwn_reg = NULL; + + if (mode_is_float(mode)) { + unknwn_reg = USE_SSE2(cg) ? &ia32_xmm_regs[REG_XMM_UKNWN] : &ia32_vfp_regs[REG_VFP_UKNWN]; + } + else { + unknwn_reg = &ia32_gp_regs[REG_GP_UKNWN]; + } + + return be_abi_get_callee_save_irn(babi, unknwn_reg); +} + /** * Gets the Proj with number pn from irn. */ @@ -472,11 +504,15 @@ static ir_node *gen_Add(ia32_transform_env_t *env) { new_op = new_rd_ia32_Lea(dbg, irg, block, op1, noreg, mode); set_ia32_am_sc(new_op, get_ia32_id_cnst(op2)); set_ia32_am_flavour(new_op, ia32_am_OB); + + DBG_OPT_LEA1(op2, new_op); } else { /* this is the 1st case */ new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg, mode); + DBG_OPT_LEA2(op1, op2, new_op); + if (get_ia32_op_type(op1) == ia32_SymConst) { set_ia32_am_sc(new_op, get_ia32_id_cnst(op1)); add_ia32_am_offs(new_op, get_ia32_cnst(op2)); @@ -516,7 +552,7 @@ static ir_node *gen_Add(ia32_transform_env_t *env) { set_ia32_res_mode(new_op, mode); - return new_rd_Proj(dbg, irg, block, new_op, mode, 0); + return new_rd_Proj(dbg, irg, block, new_op, mode, pn_ia32_Add_res); } @@ -792,11 +828,15 @@ static ir_node *gen_Sub(ia32_transform_env_t *env) { set_ia32_am_sc(new_op, get_ia32_id_cnst(op2)); set_ia32_am_sc_sign(new_op); set_ia32_am_flavour(new_op, ia32_am_OB); + + DBG_OPT_LEA1(op2, new_op); } else { /* this is the 1st case */ new_op = new_rd_ia32_Lea(dbg, irg, block, noreg, noreg, mode); + DBG_OPT_LEA2(op1, op2, new_op); + if (get_ia32_op_type(op1) == ia32_SymConst) { set_ia32_am_sc(new_op, get_ia32_id_cnst(op1)); sub_ia32_am_offs(new_op, get_ia32_cnst(op2)); @@ -836,7 +876,7 @@ static ir_node *gen_Sub(ia32_transform_env_t *env) { set_ia32_res_mode(new_op, mode); - return new_rd_Proj(dbg, irg, block, new_op, mode, 0); + return new_rd_Proj(dbg, irg, block, new_op, mode, pn_ia32_Sub_res); } @@ -1562,12 +1602,162 @@ static ir_node *gen_CopyB(ia32_transform_env_t *env) { * @return The transformed node. */ static ir_node *gen_Mux(ia32_transform_env_t *env) { +#if 0 ir_node *node = env->irn; ir_node *new_op = new_rd_ia32_CMov(env->dbg, env->irg, env->block, \ get_Mux_sel(node), get_Mux_false(node), get_Mux_true(node), env->mode); SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn)); + return new_op; +#endif + return NULL; +} + +typedef ir_node *set_func_t(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *cmp_a, ir_node *cmp_b, ir_mode *mode); +typedef ir_node *cmov_func_t(dbg_info *db, ir_graph *irg, ir_node *block, ir_node *cmp_a, ir_node *cmp_b, \ + ir_node *psi_true, ir_node *psi_default, ir_mode *mode); + +/** + * Transforms a Psi node into CMov. + * + * @param env The transformation environment + * @return The transformed node. + */ +static ir_node *gen_Psi(ia32_transform_env_t *env) { + ia32_code_gen_t *cg = env->cg; + dbg_info *dbg = env->dbg; + ir_graph *irg = env->irg; + ir_mode *mode = env->mode; + ir_node *block = env->block; + ir_node *node = env->irn; + ir_node *cmp_proj = get_Mux_sel(node); + ir_node *psi_true = get_Psi_val(node, 0); + ir_node *psi_default = get_Psi_default(node); + ir_node *noreg = ia32_new_NoReg_gp(cg); + ir_node *nomem = new_rd_NoMem(irg); + ir_node *cmp, *cmp_a, *cmp_b, *and1, *and2, *new_op, *c1, *c2 = NULL; + int pnc; + + + assert(get_irn_mode(cmp_proj) == mode_b && "Condition for Psi must have mode_b"); + + cmp = get_Proj_pred(cmp_proj); + cmp_a = get_Cmp_left(cmp); + cmp_b = get_Cmp_right(cmp); + pnc = get_Proj_proj(cmp_proj); + + if (mode_is_float(mode)) { + /* floating point psi */ + FP_USED(cg); + + /* 1st case: compare operands are float too */ + if (USE_SSE2(cg)) { + /* psi(cmp(a, b), t, f) can be done as: */ + /* tmp = cmp a, b */ + /* tmp2 = t and tmp */ + /* tmp3 = f and not tmp */ + /* res = tmp2 or tmp3 */ + + /* in case the compare operands are int, we move them into xmm register */ + if (! mode_is_float(get_irn_mode(cmp_a))) { + c1 = new_rd_ia32_Conv_I2FP(dbg, irg, block, noreg, noreg, cmp_a, nomem); + set_ia32_src_mode(c1, get_irn_mode(cmp_a)); + set_ia32_tgt_mode(c1, mode_D); + set_ia32_am_support(c1, ia32_am_Source); + SET_IA32_ORIG_NODE(c1, ia32_get_old_node_name(cg, node)); + c2 = new_rd_ia32_Conv_I2FP(dbg, irg, block, noreg, noreg, cmp_b, nomem); + set_ia32_src_mode(c2, get_irn_mode(cmp_b)); + set_ia32_tgt_mode(c2, mode_D); + set_ia32_am_support(c2, ia32_am_Source); + SET_IA32_ORIG_NODE(c2, ia32_get_old_node_name(cg, node)); + + cmp_a = new_rd_Proj(dbg, irg, block, c1, mode_D, pn_ia32_Conv_I2FP_res); + cmp_b = new_rd_Proj(dbg, irg, block, c2, mode_D, pn_ia32_Conv_I2FP_res); + + pnc += pn_Cmp_Uo; /* transform integer compare to fp compare */ + } + + new_op = new_rd_ia32_xCmp(dbg, irg, block, noreg, noreg, cmp_a, cmp_b, nomem); + set_ia32_pncode(new_op, pnc); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_res_mode(new_op, mode); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node)); + new_op = new_rd_Proj(dbg, irg, block, new_op, mode, pn_ia32_xCmp_res); + + and1 = new_rd_ia32_xAnd(dbg, irg, block, noreg, noreg, psi_true, new_op, nomem); + set_ia32_am_support(and1, ia32_am_Source); + set_ia32_res_mode(and1, mode); + SET_IA32_ORIG_NODE(and1, ia32_get_old_node_name(cg, node)); + and1 = new_rd_Proj(dbg, irg, block, and1, mode, pn_ia32_xAnd_res); + + and2 = new_rd_ia32_xAndNot(dbg, irg, block, noreg, noreg, psi_default, new_op, nomem); + set_ia32_am_support(and2, ia32_am_Source); + set_ia32_res_mode(and2, mode); + SET_IA32_ORIG_NODE(and2, ia32_get_old_node_name(cg, node)); + and2 = new_rd_Proj(dbg, irg, block, and2, mode, pn_ia32_xAndNot_res); + + new_op = new_rd_ia32_xOr(dbg, irg, block, noreg, noreg, and1, and2, nomem); + set_ia32_am_support(new_op, ia32_am_Source); + set_ia32_res_mode(new_op, mode); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node)); + new_op = new_rd_Proj(dbg, irg, block, new_op, mode, pn_ia32_xOr_res); + } + else { + /* x87 FPU */ + new_op = new_rd_ia32_vfCMov(dbg, irg, block, cmp_a, cmp_b, psi_true, psi_default, mode); + set_ia32_pncode(new_op, pnc); + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node)); + } + } + else { + /* integer psi */ + set_func_t *set_func = NULL; + cmov_func_t *cmov_func = NULL; + + if (mode_is_float(get_irn_mode(cmp_a))) { + /* 1st case: compare operands are floats */ + FP_USED(cg); + + if (USE_SSE2(cg)) { + /* SSE FPU */ + set_func = new_rd_ia32_xCmpSet; + cmov_func = new_rd_ia32_xCmpCMov; + } + else { + /* x87 FPU */ + set_func = new_rd_ia32_vfCmpSet; + cmov_func = new_rd_ia32_vfCmpCMov; + } + } + else { + /* 2nd case: compare operand are integer too */ + set_func = new_rd_ia32_Set; + cmov_func = new_rd_ia32_CMov; + } + + /* create the nodes */ + + if (is_ia32_Const_1(psi_true) && is_ia32_Const_0(psi_default)) { + /* first case for SETcc: default is 0, set to 1 iff condition is true */ + new_op = set_func(dbg, irg, block, cmp_a, cmp_b, mode); + set_ia32_pncode(new_op, pnc); + } + else if (is_ia32_Const_0(psi_true) && is_ia32_Const_1(psi_default)) { + /* second case for SETcc: default is 1, set to 0 iff condition is true: */ + /* we invert condition and set default to 0 */ + new_op = set_func(dbg, irg, block, cmp_a, cmp_b, mode); + set_ia32_pncode(new_op, get_negated_pnc(pnc, mode)); + } + else { + /* otherwise: use CMOVcc */ + new_op = cmov_func(dbg, irg, block, cmp_a, cmp_b, psi_true, psi_default, mode); + set_ia32_pncode(new_op, pnc); + } + + SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node)); + } + return new_op; } @@ -1709,18 +1899,19 @@ static ir_node *gen_x87_gp_to_fp(ia32_transform_env_t *env, ir_mode *src_mode) { * @return The created ia32 Conv node */ static ir_node *gen_Conv(ia32_transform_env_t *env) { - dbg_info *dbg = env->dbg; - ir_graph *irg = env->irg; - ir_node *op = get_Conv_op(env->irn); - ir_mode *src_mode = get_irn_mode(op); - ir_mode *tgt_mode = env->mode; - int src_bits = get_mode_size_bits(src_mode); - int tgt_bits = get_mode_size_bits(tgt_mode); - ir_node *block = env->block; - ir_node *new_op = NULL; - ir_node *noreg = ia32_new_NoReg_gp(env->cg); - ir_node *nomem = new_rd_NoMem(irg); - ir_node *proj; + dbg_info *dbg = env->dbg; + ir_graph *irg = env->irg; + ir_node *op = get_Conv_op(env->irn); + ir_mode *src_mode = get_irn_mode(op); + ir_mode *tgt_mode = env->mode; + int src_bits = get_mode_size_bits(src_mode); + int tgt_bits = get_mode_size_bits(tgt_mode); + int pn = -1; + ir_node *block = env->block; + ir_node *new_op = NULL; + ir_node *noreg = ia32_new_NoReg_gp(env->cg); + ir_node *nomem = new_rd_NoMem(irg); + ir_node *proj; DEBUG_ONLY(firm_dbg_module_t *mod = env->mod;) if (src_mode == tgt_mode) { @@ -1735,6 +1926,7 @@ static ir_node *gen_Conv(ia32_transform_env_t *env) { if (USE_SSE2(env->cg)) { DB((mod, LEVEL_1, "create Conv(float, float) ...")); new_op = new_rd_ia32_Conv_FP2FP(dbg, irg, block, noreg, noreg, op, nomem); + pn = pn_ia32_Conv_FP2FP_res; } else { DB((mod, LEVEL_1, "killed Conv(float, float) ...")); @@ -1744,8 +1936,10 @@ static ir_node *gen_Conv(ia32_transform_env_t *env) { else { /* ... to int */ DB((mod, LEVEL_1, "create Conv(float, int) ...")); - if (USE_SSE2(env->cg)) + if (USE_SSE2(env->cg)) { new_op = new_rd_ia32_Conv_FP2I(dbg, irg, block, noreg, noreg, op, nomem); + pn = pn_ia32_Conv_FP2I_res; + } else return gen_x87_fp_to_gp(env, tgt_mode); @@ -1756,13 +1950,15 @@ static ir_node *gen_Conv(ia32_transform_env_t *env) { set_ia32_tgt_mode(new_op, tgt_mode); set_ia32_src_mode(new_op, src_mode); - proj = new_rd_Proj(dbg, irg, block, new_op, mode_Is, 0); + proj = new_rd_Proj(dbg, irg, block, new_op, mode_Is, pn_ia32_Conv_FP2I_res); if (tgt_bits == 8 || src_bits == 8) { new_op = new_rd_ia32_Conv_I2I8Bit(dbg, irg, block, noreg, noreg, proj, nomem); + pn = pn_ia32_Conv_I2I8Bit_res; } else { new_op = new_rd_ia32_Conv_I2I(dbg, irg, block, noreg, noreg, proj, nomem); + pn = pn_ia32_Conv_I2I_res; } } } @@ -1773,8 +1969,10 @@ static ir_node *gen_Conv(ia32_transform_env_t *env) { FP_USED(env->cg); /* ... to float */ DB((mod, LEVEL_1, "create Conv(int, float) ...")); - if (USE_SSE2(env->cg)) + if (USE_SSE2(env->cg)) { new_op = new_rd_ia32_Conv_I2FP(dbg, irg, block, noreg, noreg, op, nomem); + pn = pn_ia32_Conv_I2FP_res; + } else return gen_x87_gp_to_fp(env, src_mode); } @@ -1788,9 +1986,11 @@ static ir_node *gen_Conv(ia32_transform_env_t *env) { DB((mod, LEVEL_1, "create Conv(int, int) ...", src_mode, tgt_mode)); if (tgt_bits == 8 || src_bits == 8) { new_op = new_rd_ia32_Conv_I2I8Bit(dbg, irg, block, noreg, noreg, op, nomem); + pn = pn_ia32_Conv_I2I8Bit_res; } else { new_op = new_rd_ia32_Conv_I2I(dbg, irg, block, noreg, noreg, op, nomem); + pn = pn_ia32_Conv_I2I_res; } } } @@ -1803,7 +2003,7 @@ static ir_node *gen_Conv(ia32_transform_env_t *env) { set_ia32_am_support(new_op, ia32_am_Source); - new_op = new_rd_Proj(dbg, irg, block, new_op, tgt_mode, 0); + new_op = new_rd_Proj(dbg, irg, block, new_op, tgt_mode, pn); } return new_op; @@ -2170,7 +2370,7 @@ void ia32_transform_lea_to_add(ir_node *irn, ia32_code_gen_t *cg) { DBG_OPT_LEA2ADD(irn, res); - res = new_rd_Proj(tenv.dbg, tenv.irg, tenv.block, res, tenv.mode, 0); + res = new_rd_Proj(tenv.dbg, tenv.irg, tenv.block, res, tenv.mode, pn_ia32_Add_res); /* add result Proj to schedule */ sched_add_before(irn, res); @@ -2233,6 +2433,7 @@ void ia32_register_transformers(void) { GEN(CopyB); GEN(Mux); + GEN(Psi); IGN(Call); IGN(Alloc); @@ -2302,10 +2503,17 @@ void ia32_transform_node(ir_node *node, void *env) { ia32_code_gen_t *cg = (ia32_code_gen_t *)env; ir_op *op = get_irn_op(node); ir_node *asm_node = NULL; + int i; if (is_Block(node)) return; + /* link arguments pointing to Unknown to the UNKNOWN Proj */ + for (i = get_irn_arity(node) - 1; i >= 0; i--) { + if (is_Unknown(get_irn_n(node, i))) + set_irn_n(node, i, be_get_unknown_for_mode(cg, get_irn_mode(get_irn_n(node, i)))); + } + DBG((cg->mod, LEVEL_1, "check %+F ... ", node)); if (op->ops.generic) { ia32_transform_env_t tenv;