📄 regclass.c
字号:
/* 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 class would make a smaller class (i.e., no union of just those classes exists), skip that class. The major unions of classes should be provided as a register class. Don't do this if we will be doing it again later. */ if (pass == 1 || ! flag_expensive_optimizations) for (class = 0; class < N_REG_CLASSES; class++) if (p->cost[class] < p->mem_cost && (reg_class_size[(int) reg_class_subunion[(int) alt][class]] > reg_class_size[(int) alt])#ifdef FORBIDDEN_INC_DEC_CLASSES && ! (in_inc_dec[i] && forbidden_inc_dec_class[class])#endif ) alt = reg_class_subunion[(int) alt][class]; /* If we don't add any classes, nothing to try. */ if (alt == best) alt = (int) NO_REGS; /* We cast to (int) because (char) hits bugs in some compilers. */ prefclass[i] = (int) best; altclass[i] = (int) alt; } }#endif /* REGISTER_CONSTRAINTS */}#ifdef REGISTER_CONSTRAINTS/* Record the cost of using memory or registers of various classes for the operands in INSN. N_ALTS is the number of alternatives. N_OPS is the number of operands. OPS is an array of the operands. MODES are the modes of the operands, in case any are VOIDmode. CONSTRAINTS are the constraints to use for the operands. This array is modified by this procedure. This procedure works alternative by alternative. For each alternative we assume that we will be able to allocate all pseudos to their ideal register class and calculate the cost of using that alternative. Then we compute for each operand that is a pseudo-register, the cost of having the pseudo allocated to each register class and using it in that alternative. To this cost is added the cost of the alternative. The cost of each class for this insn is its lowest cost among all the alternatives. */static voidrecord_reg_classes (n_alts, n_ops, ops, modes, constraints, insn) int n_alts; int n_ops; rtx *ops; enum machine_mode *modes; char **constraints; rtx insn;{ int alt; enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS]; int i, j; /* By default, each operand is an input operand. */ for (i = 0; i < n_ops; i++) op_types[i] = OP_READ; /* Process each alternative, each time minimizing an operand's cost with the cost for each operand in that alternative. */ for (alt = 0; alt < n_alts; alt++) { struct costs this_op_costs[MAX_RECOG_OPERANDS]; int alt_fail = 0; int alt_cost = 0; enum reg_class classes[MAX_RECOG_OPERANDS]; int class; for (i = 0; i < n_ops; i++) { char *p = constraints[i]; rtx op = ops[i]; enum machine_mode mode = modes[i]; int allows_mem = 0; int win = 0; char c; /* If this operand has no constraints at all, we can conclude nothing about it since anything is valid. */ if (*p == 0) { if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) bzero ((char *) &this_op_costs[i], sizeof this_op_costs[i]); continue; } if (*p == '%') p++; /* If this alternative is only relevant when this operand matches a previous operand, we do different things depending on whether this operand is a pseudo-reg or not. */ if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0)) { j = p[0] - '0'; classes[i] = classes[j]; if (GET_CODE (op) != REG || REGNO (op) < FIRST_PSEUDO_REGISTER) { /* If this matches the other operand, we have no added cost. */ if (rtx_equal_p (ops[j], op)) ; /* If we can't put the other operand into a register, this alternative can't be used. */ else if (classes[j] == NO_REGS) alt_fail = 1; /* Otherwise, add to the cost of this alternative the cost to copy this operand to the register used for the other operand. */ else alt_cost += copy_cost (op, mode, classes[j], 1); } else if (GET_CODE (ops[j]) != REG || REGNO (ops[j]) < FIRST_PSEUDO_REGISTER) { /* This op is a pseudo but the one it matches is not. */ /* If we can't put the other operand into a register, this alternative can't be used. */ if (classes[j] == NO_REGS) alt_fail = 1; /* Otherwise, add to the cost of this alternative the cost to copy the other operand to the register used for this operand. */ else alt_cost += copy_cost (ops[j], mode, classes[j], 1); } else { /* The costs of this operand are the same as that of the other operand. However, if we cannot tie them, this alternative needs to do a copy, which is one instruction. */ this_op_costs[i] = this_op_costs[j]; if (! find_reg_note (insn, REG_DEAD, op)) alt_cost += 2; /* This is in place of ordinary cost computation for this operand. */ continue; } } /* Scan all the constraint letters. See if the operand matches any of the constraints. Collect the valid register classes and see if this operand accepts memory. */ classes[i] = NO_REGS; while (*p && (c = *p++) != ',') switch (c) { case '=': op_types[i] = OP_WRITE; break; case '+': op_types[i] = OP_READ_WRITE; break; case '*': /* Ignore the next letter for this pass. */ p++; break; case '%': case '?': case '!': case '#': case '&': case '0': case '1': case '2': case '3': case '4': case 'p': break; case 'm': case 'o': case 'V': /* It doesn't seem worth distingishing between offsettable and non-offsettable addresses here. */ allows_mem = 1; if (GET_CODE (op) == MEM) win = 1; break; case '<': if (GET_CODE (op) == MEM && (GET_CODE (XEXP (op, 0)) == PRE_DEC || GET_CODE (XEXP (op, 0)) == POST_DEC)) win = 1; break; case '>': if (GET_CODE (op) == MEM && (GET_CODE (XEXP (op, 0)) == PRE_INC || GET_CODE (XEXP (op, 0)) == POST_INC)) win = 1; break; case 'E': /* Match any floating double constant, but only if we can examine the bits of it reliably. */ if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD) && GET_MODE (op) != VOIDmode && ! flag_pretend_float) break; if (GET_CODE (op) == CONST_DOUBLE) win = 1; break; case 'F': if (GET_CODE (op) == CONST_DOUBLE) win = 1; break; case 'G': case 'H': if (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_LETTER_P (op, c)) win = 1; break; case 's': if (GET_CODE (op) == CONST_INT || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)) break; case 'i': if (CONSTANT_P (op)#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))#endif ) win = 1; break; case 'n': if (GET_CODE (op) == CONST_INT || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)) win = 1; break; case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': if (GET_CODE (op) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (op), c)) win = 1; break; case 'X': win = 1; break;#ifdef EXTRA_CONSTRAINT case 'Q': case 'R': case 'S': case 'T': case 'U': if (EXTRA_CONSTRAINT (op, c)) win = 1; break;#endif case 'g': if (GET_CODE (op) == MEM || (CONSTANT_P (op)#ifdef LEGITIMATE_PIC_OPERAND_P && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))#endif )) win = 1; allows_mem = 1; case 'r': classes[i] = reg_class_subunion[(int) classes[i]][(int) GENERAL_REGS]; break; default: classes[i] = reg_class_subunion[(int) classes[i]] [(int) REG_CLASS_FROM_LETTER (c)]; } constraints[i] = p; /* How we account for this operand now depends on whether it is a pseudo register or not. If it is, we first check if any register classes are valid. If not, we ignore this alternative, since we want to assume that all pseudos get allocated for register preferencing. If some register class is valid, compute the costs of moving the pseudo into that class. */ if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) { if (classes[i] == NO_REGS) alt_fail = 1; else { struct costs *pp = &this_op_costs[i]; for (class = 0; class < N_REG_CLASSES; class++) pp->cost[class] = may_move_cost[class][(int) classes[i]]; /* If the alternative actually allows memory, make things a bit cheaper since we won't need an extra insn to load it. */ pp->mem_cost = MEMORY_MOVE_COST (mode) - allows_mem; /* If we have assigned a class to this register in our first pass, add a cost to this alternative corresponding to what we would add if this register were not in the appropriate class. */ if (prefclass) alt_cost += may_move_cost[prefclass[REGNO (op)]][(int) classes[i]]; } } /* Otherwise, if this alternative wins, either because we have already determined that or if we have a hard register of the proper class, there is no cost for this alternative. */ else if (win || (GET_CODE (op) == REG && reg_fits_class_p (op, classes[i], 0, GET_MODE (op)))) ; /* If registers are valid, the cost of this alternative includes copying the object to and/or from a register. */ else if (classes[i] != NO_REGS) { if (op_types[i] != OP_WRITE) alt_cost += copy_cost (op, mode, classes[i], 1); if (op_types[i] != OP_READ) alt_cost += copy_cost (op, mode, classes[i], 0); } /* The only other way this alternative can be used is if this is a constant that could be placed into memory. */ else if (CONSTANT_P (op) && allows_mem) alt_cost += MEMORY_MOVE_COST (mode); else alt_fail = 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -