/* FIXME: This is the function that we need rtl.h and optabs.h for. This function (and similar RTL-related cost code in e.g. IVOPTS) should be moved to some kind of interface file for GIMPLE/RTL interactions. */ static bool lshift_cheap_p (void) { /* FIXME: This should be made target dependent via this "this_target" mechanism, similar to e.g. can_copy_init_p in gcse.c. */ static bool init[2] = {false, false}; static bool cheap[2] = {true, true}; bool speed_p; /* If the targer has no lshift in word_mode, the operation will most probably not be cheap. ??? Does GCC even work for such targets? */ if (optab_handler (ashl_optab, word_mode) == CODE_FOR_nothing) return false; speed_p = optimize_insn_for_speed_p (); if (!init[speed_p]) { rtx reg = gen_raw_REG (word_mode, 10000); int cost = set_src_cost (gen_rtx_ASHIFT (word_mode, const1_rtx, reg), speed_p); cheap[speed_p] = cost < COSTS_N_INSNS (MAX_CASE_BIT_TESTS); init[speed_p] = true; } return cheap[speed_p]; }
/* Call struct_equiv_make_checkpoint (P, INFO) if the current partial block is suitable to split off - i.e. there is no dangling cc0 user - and if the current cost of the common instructions, minus the cost for setting up the inputs, is higher than what has been recorded before in CHECKPOINT[N]. Also, if we do so, confirm or cancel any pending changes. */ static void struct_equiv_improve_checkpoint (struct struct_equiv_checkpoint *p, struct equiv_info *info) { #ifdef HAVE_cc0 if (reg_mentioned_p (cc0_rtx, info->cur.x_start) && !sets_cc0_p (info->cur.x_start)) return; #endif if (info->cur.input_count >= IMPOSSIBLE_MOVE_FACTOR) return; if (info->input_cost >= 0 ? (COSTS_N_INSNS(info->cur.ninsns - p->ninsns) > info->input_cost * (info->cur.input_count - p->input_count)) : info->cur.ninsns > p->ninsns && !info->cur.input_count) { if (info->check_input_conflict && ! resolve_input_conflict (info)) return; /* We have a profitable set of changes. If this is the final pass, commit them now. Otherwise, we don't know yet if we can make any change, so put the old code back for now. */ if (info->mode & STRUCT_EQUIV_FINAL) confirm_change_group (); else cancel_changes (0); struct_equiv_make_checkpoint (p, info); } }
static int compute_rtx_cost (rtx insn) { struct hash_bucket_def tmp_bucket; p_hash_bucket bucket; struct hash_elem_def tmp_elem; p_hash_elem elem = NULL; int cost = -1; /* Compute hash value for INSN. */ tmp_bucket.hash = compute_hash (insn); /* Select the hash group. */ bucket = (p_hash_bucket) htab_find (hash_buckets, &tmp_bucket); if (bucket) { tmp_elem.insn = insn; /* Select the insn. */ elem = (p_hash_elem) htab_find (bucket->seq_candidates, &tmp_elem); /* If INSN is parsed the cost will be the cached length. */ if (elem) cost = elem->length; } /* If we can't parse the INSN cost will be the instruction length. */ if (cost == -1) { cost = get_attr_length (insn); /* Cache the length. */ if (elem) elem->length = cost; } /* If we can't get an accurate estimate for a complex instruction, assume that it has the same cost as a single fast instruction. */ return cost != 0 ? cost : COSTS_N_INSNS (1); }
static bool lm32_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UNUSED, int *total, bool speed) { int code = GET_CODE (x); bool small_mode; const int arithmetic_latency = 1; const int shift_latency = 1; const int compare_latency = 2; const int multiply_latency = 3; const int load_latency = 3; const int libcall_size_cost = 5; /* Determine if we can handle the given mode size in a single instruction. */ small_mode = (mode == QImode) || (mode == HImode) || (mode == SImode); switch (code) { case PLUS: case MINUS: case AND: case IOR: case XOR: case NOT: case NEG: if (!speed) *total = COSTS_N_INSNS (LM32_NUM_REGS (mode)); else *total = COSTS_N_INSNS (arithmetic_latency + (LM32_NUM_REGS (mode) - 1)); break; case COMPARE: if (small_mode) { if (!speed) *total = COSTS_N_INSNS (1); else *total = COSTS_N_INSNS (compare_latency); } else { /* FIXME. Guessing here. */ *total = COSTS_N_INSNS (LM32_NUM_REGS (mode) * (2 + 3) / 2); } break; case ASHIFT: case ASHIFTRT: case LSHIFTRT: if (TARGET_BARREL_SHIFT_ENABLED && small_mode) { if (!speed) *total = COSTS_N_INSNS (1); else *total = COSTS_N_INSNS (shift_latency); } else if (TARGET_BARREL_SHIFT_ENABLED) { /* FIXME: Guessing here. */ *total = COSTS_N_INSNS (LM32_NUM_REGS (mode) * 4); } else if (small_mode && GET_CODE (XEXP (x, 1)) == CONST_INT) { *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))); } else { /* Libcall. */ if (!speed) *total = COSTS_N_INSNS (libcall_size_cost); else *total = COSTS_N_INSNS (100); } break; case MULT: if (TARGET_MULTIPLY_ENABLED && small_mode) { if (!speed) *total = COSTS_N_INSNS (1); else *total = COSTS_N_INSNS (multiply_latency); } else { /* Libcall. */ if (!speed) *total = COSTS_N_INSNS (libcall_size_cost); else *total = COSTS_N_INSNS (100); } break; case DIV: case MOD: case UDIV: case UMOD: if (TARGET_DIVIDE_ENABLED && small_mode) { if (!speed) *total = COSTS_N_INSNS (1); else { if (GET_CODE (XEXP (x, 1)) == CONST_INT) { int cycles = 0; unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1)); while (i) { i >>= 2; cycles++; } if (IN_RANGE (i, 0, 65536)) *total = COSTS_N_INSNS (1 + 1 + cycles); else *total = COSTS_N_INSNS (2 + 1 + cycles); return true; } else if (GET_CODE (XEXP (x, 1)) == REG) { *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode) / 2); return true; } else { *total = COSTS_N_INSNS (1 + GET_MODE_SIZE (mode) / 2); return false; } } }
bool nds32_rtx_costs_impl (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED, int *total, bool speed) { /* According to 'speed', goto suitable cost model section. */ if (speed) goto performance_cost; else goto size_cost; performance_cost: /* This is section for performance cost model. */ /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4. We treat it as 4-cycle cost for each instruction under performance consideration. */ switch (code) { case SET: /* For 'SET' rtx, we need to return false so that it can recursively calculate costs. */ return false; case USE: /* Used in combine.c as a marker. */ *total = 0; break; case MULT: *total = COSTS_N_INSNS (1); break; case DIV: case UDIV: case MOD: case UMOD: *total = COSTS_N_INSNS (7); break; default: *total = COSTS_N_INSNS (1); break; } return true; size_cost: /* This is section for size cost model. */ /* In gcc/rtl.h, the default value of COSTS_N_INSNS(N) is N*4. We treat it as 4-byte cost for each instruction under code size consideration. */ switch (code) { case SET: /* For 'SET' rtx, we need to return false so that it can recursively calculate costs. */ return false; case USE: /* Used in combine.c as a marker. */ *total = 0; break; case CONST_INT: /* All instructions involving constant operation need to be considered for cost evaluation. */ if (outer_code == SET) { /* (set X imm5s), use movi55, 2-byte cost. (set X imm20s), use movi, 4-byte cost. (set X BIG_INT), use sethi/ori, 8-byte cost. */ if (satisfies_constraint_Is05 (x)) *total = COSTS_N_INSNS (1) - 2; else if (satisfies_constraint_Is20 (x)) *total = COSTS_N_INSNS (1); else *total = COSTS_N_INSNS (2); } else if (outer_code == PLUS || outer_code == MINUS) { /* Possible addi333/subi333 or subi45/addi45, 2-byte cost. General case, cost 1 instruction with 4-byte. */ if (satisfies_constraint_Iu05 (x)) *total = COSTS_N_INSNS (1) - 2; else *total = COSTS_N_INSNS (1); } else if (outer_code == ASHIFT) { /* Possible slli333, 2-byte cost. General case, cost 1 instruction with 4-byte. */ if (satisfies_constraint_Iu03 (x)) *total = COSTS_N_INSNS (1) - 2; else *total = COSTS_N_INSNS (1); } else if (outer_code == ASHIFTRT || outer_code == LSHIFTRT) { /* Possible srai45 or srli45, 2-byte cost. General case, cost 1 instruction with 4-byte. */ if (satisfies_constraint_Iu05 (x)) *total = COSTS_N_INSNS (1) - 2; else *total = COSTS_N_INSNS (1); } else { /* For other cases, simply set it 4-byte cost. */ *total = COSTS_N_INSNS (1); } break; case CONST_DOUBLE: /* It requires high part and low part processing, set it 8-byte cost. */ *total = COSTS_N_INSNS (2); break; default: /* For other cases, generally we set it 4-byte cost and stop resurively traversing. */ *total = COSTS_N_INSNS (1); break; } return true; }
int nds32_address_cost_impl (rtx address, enum machine_mode mode ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED, bool speed) { rtx plus0, plus1; enum rtx_code code; code = GET_CODE (address); /* According to 'speed', goto suitable cost model section. */ if (speed) goto performance_cost; else goto size_cost; performance_cost: /* This is section for performance cost model. */ /* FALLTHRU, currently we use same cost model as size_cost. */ size_cost: /* This is section for size cost model. */ switch (code) { case POST_MODIFY: case POST_INC: case POST_DEC: /* We encourage that rtx contains POST_MODIFY/POST_INC/POST_DEC behavior. */ return 0; case SYMBOL_REF: /* We can have gp-relative load/store for symbol_ref. Have it 4-byte cost. */ return COSTS_N_INSNS (1); case CONST: /* It is supposed to be the pattern (const (plus symbol_ref const_int)). Have it 4-byte cost. */ return COSTS_N_INSNS (1); case REG: /* Simply return 4-byte costs. */ return COSTS_N_INSNS (1); case PLUS: /* We do not need to check if the address is a legitimate address, because this hook is never called with an invalid address. But we better check the range of const_int value for cost, if it exists. */ plus0 = XEXP (address, 0); plus1 = XEXP (address, 1); if (REG_P (plus0) && CONST_INT_P (plus1)) { /* If it is possible to be lwi333/swi333 form, make it 2-byte cost. */ if (satisfies_constraint_Iu05 (plus1)) return (COSTS_N_INSNS (1) - 2); else return COSTS_N_INSNS (1); } /* For other 'plus' situation, make it cost 4-byte. */ return COSTS_N_INSNS (1); default: break; } return COSTS_N_INSNS (4); }
/* Expand conditional compare gimple G. A typical CCMP sequence is like: CC0 = CMP (a, b); CC1 = CCMP (NE (CC0, 0), CMP (e, f)); ... CCn = CCMP (NE (CCn-1, 0), CMP (...)); hook gen_ccmp_first is used to expand the first compare. hook gen_ccmp_next is used to expand the following CCMP. PREP_SEQ returns all insns to prepare opearand. GEN_SEQ returns all compare insns. */ static rtx expand_ccmp_expr_1 (gimple *g, rtx_insn **prep_seq, rtx_insn **gen_seq) { tree exp = gimple_assign_rhs_to_tree (g); tree_code code = TREE_CODE (exp); gimple *gs0 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 0)); gimple *gs1 = get_gimple_for_ssa_name (TREE_OPERAND (exp, 1)); rtx tmp; tree_code code0 = gimple_assign_rhs_code (gs0); tree_code code1 = gimple_assign_rhs_code (gs1); gcc_assert (code == BIT_AND_EXPR || code == BIT_IOR_EXPR); gcc_assert (gs0 && gs1 && is_gimple_assign (gs0) && is_gimple_assign (gs1)); if (TREE_CODE_CLASS (code0) == tcc_comparison) { if (TREE_CODE_CLASS (code1) == tcc_comparison) { int unsignedp0, unsignedp1; rtx_code rcode0, rcode1; int speed_p = optimize_insn_for_speed_p (); rtx tmp2 = NULL_RTX, ret = NULL_RTX, ret2 = NULL_RTX; unsigned cost1 = MAX_COST; unsigned cost2 = MAX_COST; unsignedp0 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs0))); unsignedp1 = TYPE_UNSIGNED (TREE_TYPE (gimple_assign_rhs1 (gs1))); rcode0 = get_rtx_code (code0, unsignedp0); rcode1 = get_rtx_code (code1, unsignedp1); rtx_insn *prep_seq_1, *gen_seq_1; tmp = targetm.gen_ccmp_first (&prep_seq_1, &gen_seq_1, rcode0, gimple_assign_rhs1 (gs0), gimple_assign_rhs2 (gs0)); if (tmp != NULL) { ret = expand_ccmp_next (gs1, code, tmp, &prep_seq_1, &gen_seq_1); cost1 = seq_cost (prep_seq_1, speed_p); cost1 += seq_cost (gen_seq_1, speed_p); } /* FIXME: Temporary workaround for PR69619. Avoid exponential compile time due to expanding gs0 and gs1 twice. If gs0 and gs1 are complex, the cost will be high, so avoid reevaluation if above an arbitrary threshold. */ rtx_insn *prep_seq_2, *gen_seq_2; if (tmp == NULL || cost1 < COSTS_N_INSNS (25)) tmp2 = targetm.gen_ccmp_first (&prep_seq_2, &gen_seq_2, rcode1, gimple_assign_rhs1 (gs1), gimple_assign_rhs2 (gs1)); if (!tmp && !tmp2) return NULL_RTX; if (tmp2 != NULL) { ret2 = expand_ccmp_next (gs0, code, tmp2, &prep_seq_2, &gen_seq_2); cost2 = seq_cost (prep_seq_2, speed_p); cost2 += seq_cost (gen_seq_2, speed_p); } if (cost2 < cost1) { *prep_seq = prep_seq_2; *gen_seq = gen_seq_2; return ret2; } *prep_seq = prep_seq_1; *gen_seq = gen_seq_1; return ret; } else { tmp = expand_ccmp_expr_1 (gs1, prep_seq, gen_seq); if (!tmp) return NULL_RTX; return expand_ccmp_next (gs0, code, tmp, prep_seq, gen_seq); } } else { gcc_assert (gimple_assign_rhs_code (gs0) == BIT_AND_EXPR || gimple_assign_rhs_code (gs0) == BIT_IOR_EXPR); if (TREE_CODE_CLASS (gimple_assign_rhs_code (gs1)) == tcc_comparison) { tmp = expand_ccmp_expr_1 (gs0, prep_seq, gen_seq); if (!tmp) return NULL_RTX; return expand_ccmp_next (gs1, code, tmp, prep_seq, gen_seq); } else { gcc_assert (gimple_assign_rhs_code (gs1) == BIT_AND_EXPR || gimple_assign_rhs_code (gs1) == BIT_IOR_EXPR); } } return NULL_RTX; }