📄 regclass.c
字号:
It should be a fixed register if FIXED and a call-used register if CALL_USED. */voidfix_register (name, fixed, call_used) char *name; int fixed, call_used;{ int i; if (output_bytecode) { warning ("request to mark `%s' as %s ignored by bytecode compiler", name, call_used ? "call-used" : "fixed"); return; } /* Decode the name and update the primary form of the register info. */ if ((i = decode_reg_name (name)) >= 0) { fixed_regs[i] = fixed; call_used_regs[i] = call_used; } else { warning ("unknown register name: %s", name); }}/* Mark register number I as global. */voidglobalize_reg (i) int i;{ if (global_regs[i]) { warning ("register used for two global register variables"); return; } if (call_used_regs[i] && ! fixed_regs[i]) warning ("call-clobbered register used for global register variable"); global_regs[i] = 1; /* If already fixed, nothing else to do. */ if (fixed_regs[i]) return; fixed_regs[i] = call_used_regs[i] = call_fixed_regs[i] = 1; n_non_fixed_regs--; SET_HARD_REG_BIT (fixed_reg_set, i); SET_HARD_REG_BIT (call_used_reg_set, i); SET_HARD_REG_BIT (call_fixed_reg_set, i);}/* 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 void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *, char **, rtx));static int copy_cost PROTO((rtx, enum machine_mode, enum reg_class, int));static void record_address_regs PROTO((rtx, enum reg_class, int));static auto_inc_dec_reg_p PROTO((rtx, enum machine_mode));static void reg_scan_mark_refs PROTO((rtx, rtx, int));/* 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 a register is not directly suitable for an auto-increment or decrement addressing mode and requires secondary reloads, disallow its class from being used in such addresses. */ 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 ) && ! auto_inc_dec_reg_p (r, m)) 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 ((char *) 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 aggressive 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; } 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. We must do this even if one operand is a constant--see addsi3 in m68k.md. */ for (i = 0; i < noperands - 1; i++) if (constraints[i][0] == '%') { 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; } } } /* Now for each register look at how desirable each class is and find which class is preferred. Store that in `prefclass[REGNO]'. Record in `altclass[REGNO]' the largest register class any of whose registers is better than memory. */ if (pass == 0) { prefclass = (char *) oballoc (nregs); altclass = (char *) oballoc (nregs); } for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++) { register int best_cost = (1 << (HOST_BITS_PER_INT - 2)) - 1; enum reg_class best = ALL_REGS, alt = NO_REGS; /* This is an enum reg_class, but we call it an int to save lots of casts. */ register int class; register struct costs *p = &costs[i]; for (class = (int) ALL_REGS - 1; class > 0; class--) { /* Ignore classes that are too small for this operand or invalid for a operand that was auto-incremented. */ if (CLASS_MAX_NREGS (class, PSEUDO_REGNO_MODE (i)) > reg_class_size[class]#ifdef FORBIDDEN_INC_DEC_CLASSES || (in_inc_dec[i] && forbidden_inc_dec_class[class])#endif ) ; else if (p->cost[class] < best_cost) { best_cost = p->cost[class]; best = (enum reg_class) class; } else if (p->cost[class] == best_cost) best = reg_class_subunion[(int)best][class]; } /* Record the alternate register class; i.e., a class for which every register in it is better than using memory. If adding a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -