diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 157a716..e89d567 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -820,6 +820,14 @@ struct noce_if_info /* Estimated cost of the particular branch instruction. */ unsigned int branch_cost; + + /* For if-convert transformations, the legacy way to decide whether + the transformation should be applied is a comparison of a magic + number against BRANCH_COST. Ultimately, this should go away, but + to avoid regressing targets this field encodes that number so the + profitability analysis can remain unchanged. */ + unsigned int magic_number; + }; static rtx noce_emit_store_flag (struct noce_if_info *, rtx, int, int); @@ -836,6 +844,19 @@ static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **); static int noce_try_minmax (struct noce_if_info *); static int noce_try_abs (struct noce_if_info *); static int noce_try_sign_mask (struct noce_if_info *); +static bool noce_is_profitable_p (rtx_insn *, struct noce_if_info *); + +/* Given SEQ, which is a sequence we might want to generate after + if-conversion, and a basic-block structure in IF_INFO which represents + the code generation before if-conversion, return TRUE if this would + be a profitable transformation. */ + +static bool +noce_is_profitable_p (rtx_insn *seq ATTRIBUTE_UNUSED, + struct noce_if_info *if_info) +{ + return (if_info->branch_cost >= if_info->magic_number); +} /* Helper function for noce_try_store_flag*. */ @@ -1192,8 +1213,13 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) HOST_WIDE_INT itrue, ifalse, diff, tmp; int normalize; bool can_reverse; + bool no_cost_model = false; machine_mode mode = GET_MODE (if_info->x);; rtx common = NULL_RTX; + /* ??? There are paths through this function from which no cost function + is checked before conversion. Maintain that behaviour by setting + the magic number used by noce_is_profitable_p to zero. */ + if_info->magic_number = 0; rtx a = if_info->a; rtx b = if_info->b; @@ -1204,9 +1230,9 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) && CONST_INT_P (XEXP (a, 1)) && CONST_INT_P (XEXP (b, 1)) && rtx_equal_p (XEXP (a, 0), XEXP (b, 0)) - && noce_operand_ok (XEXP (a, 0)) - && if_info->branch_cost >= 2) + && noce_operand_ok (XEXP (a, 0))) { + if_info->magic_number = 2; common = XEXP (a, 0); a = XEXP (a, 1); b = XEXP (b, 1); @@ -1278,23 +1304,33 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) else gcc_unreachable (); } - else if (ifalse == 0 && exact_log2 (itrue) >= 0 - && (STORE_FLAG_VALUE == 1 - || if_info->branch_cost >= 2)) - normalize = 1; - else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse - && (STORE_FLAG_VALUE == 1 || if_info->branch_cost >= 2)) + else if (ifalse == 0 && exact_log2 (itrue) >= 0) { + if_info->magic_number = 2; + if (STORE_FLAG_VALUE == 1) + no_cost_model = true; + normalize = 1; + } + else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse) + { + if_info->magic_number = 2; + if (STORE_FLAG_VALUE == 1) + no_cost_model = true; normalize = 1; reversep = true; } - else if (itrue == -1 - && (STORE_FLAG_VALUE == -1 - || if_info->branch_cost >= 2)) - normalize = -1; - else if (ifalse == -1 && can_reverse - && (STORE_FLAG_VALUE == -1 || if_info->branch_cost >= 2)) + else if (itrue == -1) { + if_info->magic_number = 2; + if (STORE_FLAG_VALUE == -1) + no_cost_model = true; + normalize = -1; + } + else if (ifalse == -1 && can_reverse) + { + if_info->magic_number = 2; + if (STORE_FLAG_VALUE == -1) + no_cost_model = true; normalize = -1; reversep = true; } @@ -1385,6 +1421,10 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) if (!seq) return FALSE; + /* Check if this is actually beneficial. */ + if (!no_cost_model && !noce_is_profitable_p (seq, if_info)) + return FALSE; + emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); return TRUE; @@ -1446,8 +1486,7 @@ noce_try_addcc (struct noce_if_info *if_info) /* If that fails, construct conditional increment or decrement using setcc. */ - if (if_info->branch_cost >= 2 - && (XEXP (if_info->a, 1) == const1_rtx + if ((XEXP (if_info->a, 1) == const1_rtx || XEXP (if_info->a, 1) == constm1_rtx)) { start_sequence (); @@ -1477,6 +1516,11 @@ noce_try_addcc (struct noce_if_info *if_info) if (!seq) return FALSE; + /* Check if this is actually beneficial. */ + if_info->magic_number = 2; + if (!noce_is_profitable_p (seq, if_info)) + return FALSE; + emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); return TRUE; @@ -1501,15 +1545,14 @@ noce_try_store_flag_mask (struct noce_if_info *if_info) return FALSE; reversep = 0; - if ((if_info->branch_cost >= 2 - || STORE_FLAG_VALUE == -1) - && ((if_info->a == const0_rtx + + if ((if_info->a == const0_rtx && rtx_equal_p (if_info->b, if_info->x)) || ((reversep = (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)) && if_info->b == const0_rtx - && rtx_equal_p (if_info->a, if_info->x)))) + && rtx_equal_p (if_info->a, if_info->x))) { start_sequence (); target = noce_emit_store_flag (if_info, @@ -1523,7 +1566,7 @@ noce_try_store_flag_mask (struct noce_if_info *if_info) if (target) { - int old_cost, new_cost, insn_cost; + int new_cost, old_cost; int speed_p; if (target != if_info->x) @@ -1533,12 +1576,26 @@ noce_try_store_flag_mask (struct noce_if_info *if_info) if (!seq) return FALSE; + /* The previous costing code here calculated everything in the + rtx_cost base, and compared it against + COSTS_N_INSNS (if_info->branch_cost). As we don't want to + multiply branch cost, instead divide through by + COSTS_N_INSNS (1) to get our magic_number. We also need to + take account of a possible magic_number of 2 which should + be applied if STORE_FLAG_VALUE != -1. */ speed_p = optimize_bb_for_speed_p (BLOCK_FOR_INSN (if_info->insn_a)); - insn_cost = insn_rtx_cost (PATTERN (if_info->insn_a), speed_p); - old_cost = COSTS_N_INSNS (if_info->branch_cost) + insn_cost; + old_cost = insn_rtx_cost (PATTERN (if_info->insn_a), speed_p); new_cost = seq_cost (seq, speed_p); + if_info->magic_number = (new_cost - old_cost); + if_info->magic_number + = (if_info->magic_number / COSTS_N_INSNS (1)) + + ((if_info->magic_number % COSTS_N_INSNS (1)) ? 1 : 0); - if (new_cost > old_cost) + if_info->magic_number + = MAX (((STORE_FLAG_VALUE != -1) ? 2 : 0), + (if_info->magic_number)); + + if (!noce_is_profitable_p (seq, if_info)) return FALSE; emit_insn_before_setloc (seq, if_info->jump, @@ -1703,9 +1760,7 @@ noce_try_cmove (struct noce_if_info *if_info) we don't know about, so give them a chance before trying this approach. */ else if (!targetm.have_conditional_execution () - && CONST_INT_P (if_info->a) && CONST_INT_P (if_info->b) - && ((if_info->branch_cost >= 2 && STORE_FLAG_VALUE == -1) - || if_info->branch_cost >= 3)) + && CONST_INT_P (if_info->a) && CONST_INT_P (if_info->b)) { machine_mode mode = GET_MODE (if_info->x); HOST_WIDE_INT ifalse = INTVAL (if_info->a); @@ -1744,6 +1799,12 @@ noce_try_cmove (struct noce_if_info *if_info) if (!seq) return FALSE; + /* Check if this is actually beneficial. */ + if_info->magic_number = STORE_FLAG_VALUE == -1 + ? 2 : 3; + if (!noce_is_profitable_p (seq, if_info)) + return FALSE; + emit_insn_before_setloc (seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); return TRUE; @@ -1930,7 +1991,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info) conditional on their addresses followed by a load. Don't do this early because it'll screw alias analysis. Note that we've already checked for no side effects. */ - /* ??? FIXME: Magic number 5. */ + /* ??? FIXME: Magic number 5. We cost this here rather than through + noce_is_profitable_p as the fallback cases below can produce viable + transformations in the case where (if_info->branch_cost < 5). */ if (cse_not_expected && MEM_P (a) && MEM_P (b) && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b) @@ -1973,10 +2036,12 @@ noce_try_cmove_arith (struct noce_if_info *if_info) else else_cost = 0; - /* We're going to execute one of the basic blocks anyway, so - bail out if the most expensive of the two blocks is unacceptable. */ - if (MAX (then_cost, else_cost) > COSTS_N_INSNS (if_info->branch_cost)) - return FALSE; + /* We want the most expensive of the above, divided through by + COSTS_N_INSNS (1). */ + if_info->magic_number = MAX (then_cost, else_cost); + if_info->magic_number + = (if_info->magic_number / COSTS_N_INSNS (1)) + + ((if_info->magic_number % COSTS_N_INSNS (1)) ? 1 : 0); /* Possibly rearrange operands to make things come out more natural. */ if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN) @@ -2115,6 +2180,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info) if (!ifcvt_seq) return FALSE; + if (!noce_is_profitable_p (ifcvt_seq, if_info)) + return FALSE; + emit_insn_before_setloc (ifcvt_seq, if_info->jump, INSN_LOCATION (if_info->insn_a)); return TRUE; @@ -2571,7 +2639,12 @@ noce_try_sign_mask (struct noce_if_info *if_info) non-zero (T) value and if INSN_B was taken from TEST_BB, or there was no INSN_B which can happen for e.g. conditional stores to memory. For the cost computation use the block TEST_BB where the evaluation will end up - after the transformation. */ + after the transformation. + ??? The underlying calculation is a natural fit for the long term + direction of noce_is_profitable_p, but there is no way to transform + this cost calculation in to a comparison against branch_cost. When + noce_is_profitable_p becomes a proper cost calulcation, this logic + should be cleaned up. */ t_unconditional = (t == if_info->b && (if_info->insn_b == NULL_RTX