-static ir_node *gen_int_downscale_conv(ia32_transform_env_t *env, ir_node *op,
- ir_mode *src_mode, ir_mode *tgt_mode)
-{
- int n = get_mode_size_bits(src_mode);
- int m = get_mode_size_bits(tgt_mode);
- dbg_info *dbg = env->dbg;
- ir_graph *irg = env->irg;
- ir_node *block = env->block;
- ir_node *noreg = ia32_new_NoReg_gp(env->cg);
- ir_node *nomem = new_rd_NoMem(irg);
- ir_node *new_op, *proj;
-
- assert(n > m && "downscale expected");
-
- if (mode_is_signed(src_mode) && mode_is_signed(tgt_mode)) {
- /* ASHL Sn, n - m */
- new_op = new_rd_ia32_Shl(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
- proj = new_rd_Proj(dbg, irg, block, new_op, src_mode, 0);
- set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
- set_ia32_am_support(new_op, ia32_am_Source);
- SET_IA32_ORIG_NODE(new_op, get_old_node_name(env));
-
- /* ASHR Sn, n - m */
- new_op = new_rd_ia32_Shrs(dbg, irg, block, noreg, noreg, proj, noreg, nomem, mode_T);
- set_ia32_Immop_tarval(new_op, new_tarval_from_long(n - m, mode_Is));
- }
- else {
- new_op = new_rd_ia32_And(dbg, irg, block, noreg, noreg, op, noreg, nomem, mode_T);
- set_ia32_Immop_tarval(new_op, new_tarval_from_long((1 << m) - 1, mode_Is));
- }
+ 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))) {
+ cmp_a = gen_sse_conv_int2float(cg, dbg, irg, block, cmp_a, node, mode_D);
+ cmp_b = gen_sse_conv_int2float(cg, dbg, irg, block, cmp_b, node, mode_D);
+
+ pnc |= 8; /* 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_None);
+ 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, new_op, psi_default, nomem);
+ set_ia32_am_support(and2, ia32_am_None);
+ 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_None);
+ 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 */
+ construct_binop_func *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;
+ }
+
+ pnc &= 7; /* fp compare -> int compare */
+ }
+ else {
+ /* 2nd case: compare operand are integer too */
+ set_func = new_rd_ia32_CmpSet;
+ cmov_func = new_rd_ia32_CmpCMov;
+ }
+
+ /* create the nodes */
+
+ /* check for special case first: And/Or -- Cmp with 0 -- Psi */
+ if (is_ia32_Const_0(cmp_b) && is_Proj(cmp_a) && (is_ia32_And(get_Proj_pred(cmp_a)) || is_ia32_Or(get_Proj_pred(cmp_a)))) {
+ 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 = new_rd_ia32_PsiCondSet(dbg, irg, block, cmp_a, 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 = new_rd_ia32_PsiCondSet(dbg, irg, block, cmp_a, mode);
+ set_ia32_pncode(new_op, get_inversed_pnc(pnc));
+ }
+ else {
+ /* otherwise: use CMOVcc */
+ new_op = new_rd_ia32_PsiCondCMov(dbg, irg, block, cmp_a, psi_true, psi_default, mode);
+ set_ia32_pncode(new_op, pnc);
+ }
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, node));
+ }
+ else {
+ env->irn = cmp;
+ 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 = gen_binop(env, cmp_a, cmp_b, set_func);
+ set_ia32_pncode(get_Proj_pred(new_op), pnc);
+ set_ia32_am_support(get_Proj_pred(new_op), ia32_am_Source);
+ }
+ 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 = gen_binop(env, cmp_a, cmp_b, set_func);
+ set_ia32_pncode(get_Proj_pred(new_op), get_inversed_pnc(pnc));
+ set_ia32_am_support(get_Proj_pred(new_op), ia32_am_Source);
+ }
+ 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));
+ }
+ }
+ }