typedef enum produces_flag_t {
produces_no_flag,
- produces_flag_zero,
- produces_flag_carry
+ produces_zero_sign,
+ produces_zero_in_carry
} produces_flag_t;
/**
- * Return which usable flag the given node produces
+ * Return which usable flag the given node produces about the result.
+ * That is zero (ZF) and sign(SF).
+ * We do not check for carry (CF) or overflow (OF).
*
* @param node the node to check
* @param pn the projection number of the used result
*/
-static produces_flag_t produces_test_flag(ir_node *node, int pn)
+static produces_flag_t check_produces_zero_sign(ir_node *node, int pn)
{
ir_node *count;
const ia32_immediate_attr_t *imm_attr;
case iro_ia32_Mul:
return pn == pn_ia32_Mul_res_high ?
- produces_flag_carry : produces_no_flag;
+ produces_zero_in_carry : produces_no_flag;
default:
return produces_no_flag;
}
- return pn == pn_ia32_res ?
- produces_flag_zero : produces_no_flag;
+ return pn == pn_ia32_res ? produces_zero_sign : produces_no_flag;
}
/**
ir_mode *op_mode;
ir_node *schedpoint;
const ir_edge_t *edge;
+ produces_flag_t produced;
if (get_nodes_block(left) != block)
return;
panic("couldn't find left");
}
- /* make sure only Lg/Eq tests are used */
+ produced = check_produces_zero_sign(op, pn);
+ if (produced == produces_no_flag)
+ return;
+
+ /* make sure users only look at the sign/zero flag */
foreach_out_edge(node, edge) {
ir_node *user = get_edge_src_irn(edge);
ia32_condition_code_t cc = get_ia32_condcode(user);
- if (cc != ia32_cc_equal && cc != ia32_cc_not_equal) {
- return;
+ if (cc == ia32_cc_equal || cc == ia32_cc_not_equal)
+ continue;
+ if (produced == produces_zero_sign
+ && (cc == ia32_cc_sign || cc == ia32_cc_not_sign)) {
+ continue;
}
- }
-
- switch (produces_test_flag(op, pn)) {
- case produces_flag_zero:
- break;
-
- case produces_flag_carry:
- foreach_out_edge(node, edge) {
- ir_node *user = get_edge_src_irn(edge);
- ia32_condition_code_t cc = get_ia32_condcode(user);
-
- switch (cc) {
- case ia32_cc_equal: cc = ia32_cc_above_equal; break; /* CF = 0 */
- case ia32_cc_not_equal: cc = ia32_cc_below; break; /* CF = 1 */
- default: panic("unexpected pn");
- }
- set_ia32_condcode(user, cc);
- }
- break;
-
- default:
- return;
+ return;
}
op_mode = get_ia32_ls_mode(op);
if (get_mode_size_bits(op_mode) != get_mode_size_bits(get_ia32_ls_mode(node)))
return;
+ if (produced == produces_zero_in_carry) {
+ /* patch users to look at the carry instead of the zero flag */
+ foreach_out_edge(node, edge) {
+ ir_node *user = get_edge_src_irn(edge);
+ ia32_condition_code_t cc = get_ia32_condcode(user);
+
+ switch (cc) {
+ case ia32_cc_equal: cc = ia32_cc_above_equal; break;
+ case ia32_cc_not_equal: cc = ia32_cc_below; break;
+ default: panic("unexpected pn");
+ }
+ set_ia32_condcode(user, cc);
+ }
+ }
+
if (get_irn_mode(op) != mode_T) {
set_irn_mode(op, mode_T);