📄 regclass.c
字号:
} else { warning ("unknown register name: %s", name); }}/* Now the data and code for the `regclass' pass, which happens just before local-alloc. *//* The `costs' struct records the cost of using a hard register of each class and of using memory for each pseudo. We use this data to set up register class preferences. */struct costs{ int cost[N_REG_CLASSES]; int mem_cost;};/* Record the cost of each class for each pseudo. */static struct costs *costs;/* Record the same data by operand number, accumulated for each alternative in an insn. The contribution to a pseudo is that of the minimum-cost alternative. */static struct costs op_costs[MAX_RECOG_OPERANDS];/* (enum reg_class) prefclass[R] is the preferred class for pseudo number R. This is available after `regclass' is run. */static char *prefclass;/* altclass[R] is a register class that we should use for allocating pseudo number R if no register in the preferred class is available. If no register in this class is available, memory is preferred. It might appear to be more general to have a bitmask of classes here, but since it is recommended that there be a class corresponding to the union of most major pair of classes, that generality is not required. This is available after `regclass' is run. */static char *altclass;/* Record the depth of loops that we are in. */static int loop_depth;/* Account for the fact that insns within a loop are executed very commonly, but don't keep doing this as loops go too deep. */static int loop_cost;static int copy_cost ();static void record_reg_classes ();static void record_address_regs ();/* Return the reg_class in which pseudo reg number REGNO is best allocated. This function is sometimes called before the info has been computed. When that happens, just return GENERAL_REGS, which is innocuous. */enum reg_classreg_preferred_class (regno) int regno;{ if (prefclass == 0) return GENERAL_REGS; return (enum reg_class) prefclass[regno];}enum reg_classreg_alternate_class (regno){ if (prefclass == 0) return ALL_REGS; return (enum reg_class) altclass[regno];}/* This prevents dump_flow_info from losing if called before regclass is run. */voidregclass_init (){ prefclass = 0;}/* This is a pass of the compiler that scans all instructions and calculates the preferred class for each pseudo-register. This information can be accessed later by calling `reg_preferred_class'. This pass comes just before local register allocation. */voidregclass (f, nregs) rtx f; int nregs;{#ifdef REGISTER_CONSTRAINTS register rtx insn; register int i, j; struct costs init_cost; rtx set; int pass; init_recog (); costs = (struct costs *) alloca (nregs * sizeof (struct costs));#ifdef FORBIDDEN_INC_DEC_CLASSES in_inc_dec = (char *) alloca (nregs); /* Initialize information about which register classes can be used for pseudos that are auto-incremented or auto-decremented. It would seem better to put this in init_reg_sets, but we need to be able to allocate rtx, which we can't do that early. */ for (i = 0; i < N_REG_CLASSES; i++) { rtx r = gen_rtx (REG, VOIDmode, 0); enum machine_mode m; for (j = 0; j < FIRST_PSEUDO_REGISTER; j++) if (TEST_HARD_REG_BIT (reg_class_contents[i], j)) { REGNO (r) = j; for (m = VOIDmode; (int) m < (int) MAX_MACHINE_MODE; m = (enum machine_mode) ((int) m) + 1) if (HARD_REGNO_MODE_OK (j, m)) { PUT_MODE (r, m); if (0#ifdef SECONDARY_INPUT_RELOAD_CLASS || (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r) != NO_REGS)#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS || (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r) != NO_REGS)#endif ) forbidden_inc_dec_class[i] = 1; } } }#endif /* FORBIDDEN_INC_DEC_CLASSES */ init_cost.mem_cost = 10000; for (i = 0; i < N_REG_CLASSES; i++) init_cost.cost[i] = 10000; /* Normally we scan the insns once and determine the best class to use for each register. However, if -fexpensive_optimizations are on, we do so twice, the second time using the tentative best classes to guide the selection. */ for (pass = 0; pass <= flag_expensive_optimizations; pass++) { /* Zero out our accumulation of the cost of each class for each reg. */ bzero (costs, nregs * sizeof (struct costs));#ifdef FORBIDDEN_INC_DEC_CLASSES bzero (in_inc_dec, nregs);#endif loop_depth = 0, loop_cost = 1; /* Scan the instructions and record each time it would save code to put a certain register in a certain class. */ for (insn = f; insn; insn = NEXT_INSN (insn)) { char *constraints[MAX_RECOG_OPERANDS]; enum machine_mode modes[MAX_RECOG_OPERANDS]; int nalternatives; int noperands; /* Show that an insn inside a loop is likely to be executed three times more than insns outside a loop. This is much more agressive than the assumptions made elsewhere and is being tried as an experiment. */ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG) loop_depth++, loop_cost = 1 << (2 * MIN (loop_depth, 5)); else if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END) loop_depth--, loop_cost = 1 << (2 * MIN (loop_depth, 5)); else if ((GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER && GET_CODE (PATTERN (insn)) != ASM_INPUT) || (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) != ADDR_VEC && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC) || GET_CODE (insn) == CALL_INSN) { if (GET_CODE (insn) == INSN && (noperands = asm_noperands (PATTERN (insn))) >= 0) { decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR, constraints, modes); nalternatives = (noperands == 0 ? 0 : n_occurrences (',', constraints[0]) + 1); } else { int insn_code_number = recog_memoized (insn); rtx note; set = single_set (insn); insn_extract (insn); nalternatives = insn_n_alternatives[insn_code_number]; noperands = insn_n_operands[insn_code_number]; /* If this insn loads a parameter from its stack slot, then it represents a savings, rather than a cost, if the parameter is stored in memory. Record this fact. */ if (set != 0 && GET_CODE (SET_DEST (set)) == REG && GET_CODE (SET_SRC (set)) == MEM && (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0 && GET_CODE (XEXP (note, 0)) == MEM) { costs[REGNO (SET_DEST (set))].mem_cost -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set))) * loop_cost); record_address_regs (XEXP (SET_SRC (set), 0), BASE_REG_CLASS, loop_cost * 2); continue; } /* Improve handling of two-address insns such as (set X (ashift CONST Y)) where CONST must be made to match X. Change it into two insns: (set X CONST) (set X (ashift X Y)). If we left this for reloading, it would probably get three insns because X and Y might go in the same place. This prevents X and Y from receiving the same hard reg. We can only do this if the modes of operands 0 and 1 (which might not be the same) are tieable and we only need do this during our first pass. */ if (pass == 0 && optimize && noperands >= 3 && insn_operand_constraint[insn_code_number][1][0] == '0' && insn_operand_constraint[insn_code_number][1][1] == 0 && CONSTANT_P (recog_operand[1]) && ! rtx_equal_p (recog_operand[0], recog_operand[1]) && ! rtx_equal_p (recog_operand[0], recog_operand[2]) && GET_CODE (recog_operand[0]) == REG && MODES_TIEABLE_P (GET_MODE (recog_operand[0]), insn_operand_mode[insn_code_number][1])) { rtx previnsn = prev_real_insn (insn); rtx dest = gen_lowpart (insn_operand_mode[insn_code_number][1], recog_operand[0]); rtx newinsn = emit_insn_before (gen_move_insn (dest, recog_operand[1]), insn); /* If this insn was the start of a basic block, include the new insn in that block. We need not check for code_label here; while a basic block can start with a code_label, INSN could not be at the beginning of that block. */ if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN) { int b; for (b = 0; b < n_basic_blocks; b++) if (insn == basic_block_head[b]) basic_block_head[b] = newinsn; } /* This makes one more setting of new insns's dest. */ reg_n_sets[REGNO (recog_operand[0])]++; *recog_operand_loc[1] = recog_operand[0]; for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--) if (recog_dup_num[i] == 1) *recog_dup_loc[i] = recog_operand[0]; insn = PREV_INSN (newinsn); continue; } /* If this is setting a pseudo from another pseudo or the sum of a pseudo and a constant integer and the other pseudo is known to be a pointer, set the destination to be a pointer as well. Likewise if it is setting the destination from an address or from a value equivalent to an address or to the sum of an address and something else. But don't do any of this if the pseudo corresponds to a user variable since it should have already been set as a pointer based on the type. There is no point in doing this during our second pass since not enough should have changed. */ if (pass == 0 && set != 0 && GET_CODE (SET_DEST (set)) == REG && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER && ! REG_USERVAR_P (SET_DEST (set)) && ! REGNO_POINTER_FLAG (REGNO (SET_DEST (set))) && ((GET_CODE (SET_SRC (set)) == REG && REGNO_POINTER_FLAG (REGNO (SET_SRC (set)))) || ((GET_CODE (SET_SRC (set)) == PLUS || GET_CODE (SET_SRC (set)) == LO_SUM) && (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT) && GET_CODE (XEXP (SET_SRC (set), 0)) == REG && REGNO_POINTER_FLAG (REGNO (XEXP (SET_SRC (set), 0)))) || GET_CODE (SET_SRC (set)) == CONST || GET_CODE (SET_SRC (set)) == SYMBOL_REF || GET_CODE (SET_SRC (set)) == LABEL_REF || (GET_CODE (SET_SRC (set)) == HIGH && (GET_CODE (XEXP (SET_SRC (set), 0)) == CONST || (GET_CODE (XEXP (SET_SRC (set), 0)) == SYMBOL_REF) || (GET_CODE (XEXP (SET_SRC (set), 0)) == LABEL_REF))) || ((GET_CODE (SET_SRC (set)) == PLUS || GET_CODE (SET_SRC (set)) == LO_SUM) && (GET_CODE (XEXP (SET_SRC (set), 1)) == CONST || (GET_CODE (XEXP (SET_SRC (set), 1)) == SYMBOL_REF) || (GET_CODE (XEXP (SET_SRC (set), 1)) == LABEL_REF))) || ((note = find_reg_note (insn, REG_EQUAL, 0)) != 0 && (GET_CODE (XEXP (note, 0)) == CONST || GET_CODE (XEXP (note, 0)) == SYMBOL_REF || GET_CODE (XEXP (note, 0)) == LABEL_REF)))) REGNO_POINTER_FLAG (REGNO (SET_DEST (set))) = 1; for (i = 0; i < noperands; i++) { constraints[i] = insn_operand_constraint[insn_code_number][i]; modes[i] = insn_operand_mode[insn_code_number][i]; } } /* If we get here, we are set up to record the costs of all the operands for this insn. Start by initializing the costs. Then handle any address registers. Finally record the desired classes for any pseudos, doing it twice if some pair of operands are commutative. */ for (i = 0; i < noperands; i++) { op_costs[i] = init_cost; if (GET_CODE (recog_operand[i]) == SUBREG) recog_operand[i] = SUBREG_REG (recog_operand[i]); if (GET_CODE (recog_operand[i]) == MEM) record_address_regs (XEXP (recog_operand[i], 0), BASE_REG_CLASS, loop_cost * 2); else if (constraints[i][0] == 'p') record_address_regs (recog_operand[i], BASE_REG_CLASS, loop_cost * 2); } /* Check for commutative in a separate loop so everything will have been initialized. Don't bother doing anything if the second operand is a constant since that is the case for which the constraints should have been written. */ for (i = 0; i < noperands - 1; i++) if (constraints[i][0] == '%' && ! CONSTANT_P (recog_operand[i+1])) { char *xconstraints[MAX_RECOG_OPERANDS]; int j; /* Handle commutative operands by swapping the constraints. We assume the modes are the same. */ for (j = 0; j < noperands; j++) xconstraints[j] = constraints[j]; xconstraints[i] = constraints[i+1]; xconstraints[i+1] = constraints[i]; record_reg_classes (nalternatives, noperands, recog_operand, modes, xconstraints, insn); } record_reg_classes (nalternatives, noperands, recog_operand, modes, constraints, insn); /* Now add the cost for each operand to the total costs for its register. */ for (i = 0; i < noperands; i++) if (GET_CODE (recog_operand[i]) == REG && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER) { int regno = REGNO (recog_operand[i]); struct costs *p = &costs[regno], *q = &op_costs[i]; p->mem_cost += q->mem_cost * loop_cost; for (j = 0; j < N_REG_CLASSES; j++) p->cost[j] += q->cost[j] * loop_cost; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -