📄 regclass.c
字号:
if (alt_fail) continue; /* Finally, update the costs with the information we've calculated about this alternative. */ for (i = 0; i < n_ops; i++) if (GET_CODE (ops[i]) == REG && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER) { struct costs *pp = &op_costs[i], *qq = &this_op_costs[i]; int scale = 1 + (op_types[i] == OP_READ_WRITE); pp->mem_cost = MIN (pp->mem_cost, (qq->mem_cost + alt_cost) * scale); for (class = 0; class < N_REG_CLASSES; class++) pp->cost[class] = MIN (pp->cost[class], (qq->cost[class] + alt_cost) * scale); } }}/* Compute the cost of loading X into (if TO_P is non-zero) or from (if TO_P is zero) a register of class CLASS in mode MODE. X must not be a pseudo. */static intcopy_cost (x, mode, class, to_p) rtx x; enum machine_mode mode; enum reg_class class; int to_p;{ enum reg_class secondary_class = NO_REGS; /* If X is a SCRATCH, there is actually nothing to move since we are assuming optimal allocation. */ if (GET_CODE (x) == SCRATCH) return 0; /* Get the class we will actually use for a reload. */ class = PREFERRED_RELOAD_CLASS (x, class);#ifdef HAVE_SECONDARY_RELOADS /* If we need a secondary reload (we assume here that we are using the secondary reload as an intermediate, not a scratch register), the cost is that to load the input into the intermediate register, then to copy them. We use a special value of TO_P to avoid recursion. */#ifdef SECONDARY_INPUT_RELOAD_CLASS if (to_p == 1) secondary_class = SECONDARY_INPUT_RELOAD_CLASS (class, mode, x);#endif#ifdef SECONDARY_OUTPUT_RELOAD_CLASS if (! to_p) secondary_class = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, x);#endif if (secondary_class != NO_REGS) return (move_cost[(int) secondary_class][(int) class] + copy_cost (x, mode, secondary_class, 2));#endif /* HAVE_SECONDARY_RELOADS */ /* For memory, use the memory move cost, for (hard) registers, use the cost to move between the register classes, and use 2 for everything else (constants). */ if (GET_CODE (x) == MEM || class == NO_REGS) return MEMORY_MOVE_COST (mode); else if (GET_CODE (x) == REG) return move_cost[(int) REGNO_REG_CLASS (REGNO (x))][(int) class]; else /* If this is a constant, we may eventually want to call rtx_cost here. */ return 2;}/* Record the pseudo registers we must reload into hard registers in a subexpression of a memory address, X. CLASS is the class that the register needs to be in and is either BASE_REG_CLASS or INDEX_REG_CLASS. SCALE is twice the amount to multiply the cost by (it is twice so we can represent half-cost adjustments). */static voidrecord_address_regs (x, class, scale) rtx x; enum reg_class class; int scale;{ register enum rtx_code code = GET_CODE (x); switch (code) { case CONST_INT: case CONST: case CC0: case PC: case SYMBOL_REF: case LABEL_REF: return; case PLUS: /* When we have an address that is a sum, we must determine whether registers are "base" or "index" regs. If there is a sum of two registers, we must choose one to be the "base". Luckily, we can use the REGNO_POINTER_FLAG to make a good choice most of the time. We only need to do this on machines that can have two registers in an address and where the base and index register classes are different. ??? This code used to set REGNO_POINTER_FLAG in some cases, but that seems bogus since it should only be set when we are sure the register is being used as a pointer. */ { rtx arg0 = XEXP (x, 0); rtx arg1 = XEXP (x, 1); register enum rtx_code code0 = GET_CODE (arg0); register enum rtx_code code1 = GET_CODE (arg1); /* Look inside subregs. */ if (code0 == SUBREG) arg0 = SUBREG_REG (arg0), code0 = GET_CODE (arg0); if (code1 == SUBREG) arg1 = SUBREG_REG (arg1), code1 = GET_CODE (arg1); /* If this machine only allows one register per address, it must be in the first operand. */ if (MAX_REGS_PER_ADDRESS == 1) record_address_regs (arg0, class, scale); /* If index and base registers are the same on this machine, just record registers in any non-constant operands. We assume here, as well as in the tests below, that all addresses are in canonical form. */ else if (INDEX_REG_CLASS == BASE_REG_CLASS) { record_address_regs (arg0, class, scale); if (! CONSTANT_P (arg1)) record_address_regs (arg1, class, scale); } /* If the second operand is a constant integer, it doesn't change what class the first operand must be. */ else if (code1 == CONST_INT || code1 == CONST_DOUBLE) record_address_regs (arg0, class, scale); /* If the second operand is a symbolic constant, the first operand must be an index register. */ else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF) record_address_regs (arg0, INDEX_REG_CLASS, scale); /* If this the sum of two registers where the first is known to be a pointer, it must be a base register with the second an index. */ else if (code0 == REG && code1 == REG && REGNO_POINTER_FLAG (REGNO (arg0))) { record_address_regs (arg0, BASE_REG_CLASS, scale); record_address_regs (arg1, INDEX_REG_CLASS, scale); } /* If this is the sum of two registers and neither is known to be a pointer, count equal chances that each might be a base or index register. This case should be rare. */ else if (code0 == REG && code1 == REG && ! REGNO_POINTER_FLAG (REGNO (arg0)) && ! REGNO_POINTER_FLAG (REGNO (arg1))) { record_address_regs (arg0, BASE_REG_CLASS, scale / 2); record_address_regs (arg0, INDEX_REG_CLASS, scale / 2); record_address_regs (arg1, BASE_REG_CLASS, scale / 2); record_address_regs (arg1, INDEX_REG_CLASS, scale / 2); } /* In all other cases, the first operand is an index and the second is the base. */ else { record_address_regs (arg0, INDEX_REG_CLASS, scale); record_address_regs (arg1, BASE_REG_CLASS, scale); } } break; case POST_INC: case PRE_INC: case POST_DEC: case PRE_DEC: /* Double the importance of a pseudo register that is incremented or decremented, since it would take two extra insns if it ends up in the wrong place. If the operand is a pseudo, show it is being used in an INC_DEC context. */#ifdef FORBIDDEN_INC_DEC_CLASSES if (GET_CODE (XEXP (x, 0)) == REG && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER) in_inc_dec[REGNO (XEXP (x, 0))] = 1;#endif record_address_regs (XEXP (x, 0), class, 2 * scale); break; case REG: { register struct costs *pp = &costs[REGNO (x)]; register int i; pp->mem_cost += (MEMORY_MOVE_COST (Pmode) * scale) / 2; for (i = 0; i < N_REG_CLASSES; i++) pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2; } break; default: { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') record_address_regs (XEXP (x, i), class, scale); } }}#endif /* REGISTER_CONSTRAINTS *//* This is the `regscan' pass of the compiler, run just before cse and again just before loop. It finds the first and last use of each pseudo-register and records them in the vectors regno_first_uid, regno_last_uid and counts the number of sets in the vector reg_n_sets. REPEAT is nonzero the second time this is called. *//* Indexed by pseudo register number, gives uid of first insn using the reg (as of the time reg_scan is called). */int *regno_first_uid;/* Indexed by pseudo register number, gives uid of last insn using the reg (as of the time reg_scan is called). */int *regno_last_uid;/* Record the number of registers we used when we allocated the above two tables. If we are called again with more than this, we must re-allocate the tables. */static int highest_regno_in_uid_map;/* Maximum number of parallel sets and clobbers in any insn in this fn. Always at least 3, since the combiner could put that many togetherm and we want this to remain correct for all the remaining passes. */int max_parallel;void reg_scan_mark_refs ();voidreg_scan (f, nregs, repeat) rtx f; int nregs; int repeat;{ register rtx insn; if (!repeat || nregs > highest_regno_in_uid_map) { /* Leave some spare space in case more regs are allocated. */ highest_regno_in_uid_map = nregs + nregs / 20; regno_first_uid = (int *) oballoc (highest_regno_in_uid_map * sizeof (int)); regno_last_uid = (int *) oballoc (highest_regno_in_uid_map * sizeof (int)); reg_n_sets = (short *) oballoc (highest_regno_in_uid_map * sizeof (short)); } bzero (regno_first_uid, highest_regno_in_uid_map * sizeof (int)); bzero (regno_last_uid, highest_regno_in_uid_map * sizeof (int)); bzero (reg_n_sets, highest_regno_in_uid_map * sizeof (short)); max_parallel = 3; for (insn = f; insn; insn = NEXT_INSN (insn)) if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN) { if (GET_CODE (PATTERN (insn)) == PARALLEL && XVECLEN (PATTERN (insn), 0) > max_parallel) max_parallel = XVECLEN (PATTERN (insn), 0); reg_scan_mark_refs (PATTERN (insn), INSN_UID (insn)); }}voidreg_scan_mark_refs (x, uid) rtx x; int uid;{ register enum rtx_code code = GET_CODE (x); register rtx dest; switch (code) { case CONST_INT: case CONST: case CONST_DOUBLE: case CC0: case PC: case SYMBOL_REF: case LABEL_REF: case ADDR_VEC: case ADDR_DIFF_VEC: return; case REG: { register int regno = REGNO (x); regno_last_uid[regno] = uid; if (regno_first_uid[regno] == 0) regno_first_uid[regno] = uid; } break; case SET: /* Count a set of the destination if it is a register. */ for (dest = SET_DEST (x); GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == ZERO_EXTEND; dest = XEXP (dest, 0)) ; if (GET_CODE (dest) == REG) reg_n_sets[REGNO (dest)]++; /* ... fall through ... */ default: { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') reg_scan_mark_refs (XEXP (x, i), uid); else if (fmt[i] == 'E' && XVEC (x, i) != 0) { register int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) reg_scan_mark_refs (XVECEXP (x, i, j), uid); } } } }}/* Return nonzero if C1 is a subset of C2, i.e., if every register in C1 is also in C2. */intreg_class_subset_p (c1, c2) register enum reg_class c1; register enum reg_class c2;{ if (c1 == c2) return 1; if (c2 == ALL_REGS) win: return 1; GO_IF_HARD_REG_SUBSET (reg_class_contents[(int)c1], reg_class_contents[(int)c2], win); return 0;}/* Return nonzero if there is a register that is in both C1 and C2. */intreg_classes_intersect_p (c1, c2) register enum reg_class c1; register enum reg_class c2;{#ifdef HARD_REG_SET register#endif HARD_REG_SET c; if (c1 == c2) return 1; if (c1 == ALL_REGS || c2 == ALL_REGS) return 1; COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]); AND_HARD_REG_SET (c, reg_class_contents[(int) c2]); GO_IF_HARD_REG_SUBSET (c, reg_class_contents[(int) NO_REGS], lose); return 1; lose: return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -