X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fbe%2Fia32%2Fia32_transform.c;h=c2a255a5f44f58f61e6f3ca99bb82a424318893a;hb=e407e33d9fdb18b3acde96b249d4c78c58650fab;hp=97a42049016f1375b70ca6b372c1fdd538d408a5;hpb=9905f68b9f900599c15ea2674537fca6dd021419;p=libfirm diff --git a/ir/be/ia32/ia32_transform.c b/ir/be/ia32/ia32_transform.c index 97a420490..c2a255a5f 100644 --- a/ir/be/ia32/ia32_transform.c +++ b/ir/be/ia32/ia32_transform.c @@ -78,6 +78,20 @@ 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. */ @@ -538,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); } @@ -862,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); } @@ -1600,6 +1614,9 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) { 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. @@ -1608,23 +1625,138 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) { * @return The transformed node. */ static ir_node *gen_Psi(ia32_transform_env_t *env) { - ir_node *node = env->irn; - ir_node *cmp_proj = get_Mux_sel(node); - ir_node *cmp, *cmp_a, *cmp_b, *new_op; + 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_CMov(env->dbg, env->irg, env->block, \ - cmp_a, cmp_b, get_Psi_val(node, 0), get_Psi_default(node), env->mode); + 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; + } - set_ia32_pncode(new_op, get_Proj_proj(cmp_proj)); + /* create the nodes */ - SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn)); + 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; } @@ -1767,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) { @@ -1793,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) ...")); @@ -1802,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); @@ -1814,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; } } } @@ -1831,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); } @@ -1846,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; } } } @@ -1861,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; @@ -2228,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);