*/
static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
{
- ir_node *phi;
+ ir_node *phi, *left;
+ ir_node *cmp = NULL;
+ ir_mode *cmp_mode;
+
+ if (ia32_cg_config.use_cmov) {
+ /* we can't handle psis with 64bit compares yet */
+ if (is_Proj(sel)) {
+ cmp = get_Proj_pred(sel);
+ if (is_Cmp(cmp)) {
+ left = get_Cmp_left(cmp);
+ cmp_mode = get_irn_mode(left);
+ if (!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
+ return 0;
+ } else {
+ cmp = NULL;
+ }
+ }
- (void)sel;
- (void)i;
- (void)j;
+ if (ia32_cg_config.use_sse2 && cmp != NULL) {
+ /* check the Phi nodes: no 64bit and no floating point cmov */
+ for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+ ir_mode *mode = get_irn_mode(phi);
+
+ if (mode_is_float(mode)) {
+ /* check for Min, Max */
+ ir_node *t = get_Phi_pred(phi, i);
+ ir_node *f = get_Phi_pred(phi, j);
+ pn_Cmp pn = get_Proj_proj(sel);
+ ir_node *cl = get_Cmp_left(cmp);
+ ir_node *cr = get_Cmp_right(cmp);
+ int res = 0;
+
+ /* SSE2 supports Min & Max */
+ if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
+ if (cl == t && cr == f) {
+ /* Psi(a <=/>= b, a, b) => MIN, MAX */
+ res = 1;
+ } else if (cl == f && cr == t) {
+ /* Psi(a <=/>= b, b, a) => MAX, MIN */
+ res = 1;
+ }
+ }
+ if (! res)
+ return 0;
+
+ } else if (get_mode_size_bits(mode) > 32)
+ return 0;
+ }
+ } else {
+ /* check the Phi nodes: no 64bit and no floating point cmov */
+ for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+ ir_mode *mode = get_irn_mode(phi);
- if(!ia32_cg_config.use_cmov) {
- /* TODO: we could still handle abs(x)... */
- return 0;
- }
+ if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+ return 0;
+ }
+ }
- /* we can't handle psis with 64bit compares yet */
- if(is_Proj(sel)) {
- ir_node *pred = get_Proj_pred(sel);
- if(is_Cmp(pred)) {
- ir_node *left = get_Cmp_left(pred);
- ir_mode *cmp_mode = get_irn_mode(left);
- if(!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
+ return 1;
+ } else {
+ /* No cmov, only some special cases */
+ if (! is_Proj(sel))
+ return 0;
+ cmp = get_Proj_pred(sel);
+ if (! is_Cmp(cmp))
+ return 0;
+
+ left = get_Cmp_left(cmp);
+ cmp_mode = get_irn_mode(left);
+
+ /* no floating point and no 64bit yet */
+ for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+ ir_mode *mode = get_irn_mode(phi);
+
+ if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
return 0;
}
- }
-
- /* check the Phi nodes */
- for (phi = phi_list; phi; phi = get_irn_link(phi)) {
- ir_mode *mode = get_irn_mode(phi);
+ /* Add checks for some supported cases here */
- if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
- return 0;
+ return 0;
}
-
- return 1;
+ return 0;
}
/**
ir_node *psi_true = get_Psi_val(node, 0);
ir_node *psi_default = get_Psi_default(node);
ir_node *cond = get_Psi_cond(node, 0);
+ ir_mode *mode = get_irn_mode(node);
ir_node *flags = NULL;
ir_node *new_node;
pn_Cmp pnc;
assert(get_Psi_n_conds(node) == 1);
assert(get_irn_mode(cond) == mode_b);
- assert(mode_needs_gp_reg(get_irn_mode(node)));
- flags = get_flags_node(cond, &pnc);
+ if (mode_is_float(mode)) {
+ ir_node *cmp = get_Proj_pred(cond);
+ ir_node *cmp_left = get_Cmp_left(cmp);
+ ir_node *cmp_right = get_Cmp_right(cmp);
+ pn_Cmp pnc = get_Proj_proj(cond);
+
+ if (ia32_cg_config.use_sse2) {
+ if (pnc == pn_Cmp_Lt || pnc == pn_Cmp_Le) {
+ if (cmp_left == psi_true && cmp_right == psi_default) {
+ /* psi(a <= b, a, b) => MIN */
+ return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMin,
+ match_commutative | match_am);
+ } else if (cmp_left == psi_default && cmp_right == psi_true) {
+ /* psi(a <= b, b, a) => MAX */
+ return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMax,
+ match_commutative | match_am);
+ }
+ } else if (pnc == pn_Cmp_Gt || pnc == pn_Cmp_Ge) {
+ if (cmp_left == psi_true && cmp_right == psi_default) {
+ /* psi(a >= b, a, b) => MAX */
+ return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMax,
+ match_commutative | match_am);
+ } else if (cmp_left == psi_default && cmp_right == psi_true) {
+ /* psi(a >= b, b, a) => MIN */
+ return gen_binop(node, cmp_left, cmp_right, new_rd_ia32_xMin,
+ match_commutative | match_am);
+ }
+ }
+ }
+ panic("cannot transform floating point Psi");
- if(is_Const_1(psi_true) && is_Const_0(psi_default)) {
- new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 0);
- } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
- new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 1);
} else {
- new_node = create_CMov(node, cond, flags, pnc);
+ assert(mode_needs_gp_reg(mode));
+
+ flags = get_flags_node(cond, &pnc);
+
+ if (is_Const_1(psi_true) && is_Const_0(psi_default)) {
+ new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 0);
+ } else if(is_Const_0(psi_true) && is_Const_1(psi_default)) {
+ new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, 1);
+ } else {
+ new_node = create_CMov(node, cond, flags, pnc);
+ }
}
return new_node;
}