X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fregclass.c;h=f31ccd15e4026ddf4213c65b25abf6caeb6ed67c;hb=6a167a57b73f180e3bdb2482a43db877c73f3084;hp=200f3eefa5812634f32b17ee0d8a656c5876f137;hpb=20099e352f87c3265c44cd3341fd3aec25cb0fb4;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/regclass.c b/gcc/regclass.c index 200f3eefa58..f31ccd15e40 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -145,6 +145,16 @@ char global_regs[FIRST_PSEUDO_REGISTER]; HARD_REG_SET regs_invalidated_by_call; +/* Same information as REGS_INVALIDATED_BY_CALL but in regset form to be used + in dataflow more conveniently. */ + +regset regs_invalidated_by_call_regset; + +/* The bitmap_obstack is used to hold some static variables that + should not be reset after each function is compiled. */ + +static bitmap_obstack persistent_obstack; + /* Table of register numbers in the order in which to try to use them. */ #ifdef REG_ALLOC_ORDER int reg_alloc_order[FIRST_PSEUDO_REGISTER] = REG_ALLOC_ORDER; @@ -178,7 +188,7 @@ static enum reg_class reg_class_superclasses[N_REG_CLASSES][N_REG_CLASSES]; /* For each reg class, table listing all the classes contained in it. */ -static enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES]; +enum reg_class reg_class_subclasses[N_REG_CLASSES][N_REG_CLASSES]; /* For each pair of reg classes, a largest reg class contained in their union. */ @@ -211,24 +221,22 @@ bool have_regs_of_mode [MAX_MACHINE_MODE]; /* 1 if class does contain register of given mode. */ -static char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE]; - -typedef unsigned short move_table[N_REG_CLASSES]; +char contains_reg_of_mode [N_REG_CLASSES] [MAX_MACHINE_MODE]; /* Maximum cost of moving from a register in one class to a register in another class. Based on REGISTER_MOVE_COST. */ -static move_table *move_cost[MAX_MACHINE_MODE]; +move_table *move_cost[MAX_MACHINE_MODE]; /* Similar, but here we don't have to move if the first index is a subset of the second so in that case the cost is zero. */ -static move_table *may_move_in_cost[MAX_MACHINE_MODE]; +move_table *may_move_in_cost[MAX_MACHINE_MODE]; /* Similar, but here we don't have to move if the first index is a superset of the second so in that case the cost is zero. */ -static move_table *may_move_out_cost[MAX_MACHINE_MODE]; +move_table *may_move_out_cost[MAX_MACHINE_MODE]; /* Keep track of the last mode we initialized move costs for. */ static int last_mode_for_init_move_cost; @@ -313,7 +321,7 @@ init_reg_sets (void) /* Initialize may_move_cost and friends for mode M. */ -static void +void init_move_cost (enum machine_mode m) { static unsigned short last_move_cost[N_REG_CLASSES][N_REG_CLASSES]; @@ -570,6 +578,13 @@ init_reg_sets_1 (void) CLEAR_HARD_REG_SET (call_fixed_reg_set); CLEAR_HARD_REG_SET (regs_invalidated_by_call); CLEAR_HARD_REG_SET (losing_caller_save_reg_set); + if (!regs_invalidated_by_call_regset) + { + bitmap_obstack_initialize (&persistent_obstack); + regs_invalidated_by_call_regset = ALLOC_REG_SET (&persistent_obstack); + } + else + CLEAR_REG_SET (regs_invalidated_by_call_regset); memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs); @@ -604,7 +619,10 @@ init_reg_sets_1 (void) if (i == STACK_POINTER_REGNUM) ; else if (global_regs[i]) - SET_HARD_REG_BIT (regs_invalidated_by_call, i); + { + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + SET_REGNO_REG_SET (regs_invalidated_by_call_regset, i); + } else if (i == FRAME_POINTER_REGNUM) ; #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM @@ -620,7 +638,10 @@ init_reg_sets_1 (void) ; #endif else if (CALL_REALLY_USED_REGNO_P (i)) - SET_HARD_REG_BIT (regs_invalidated_by_call, i); + { + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + SET_REGNO_REG_SET (regs_invalidated_by_call_regset, i); + } } /* Preserve global registers if called more than once. */ @@ -738,7 +759,7 @@ init_fake_stack_mems (void) Only needed if secondary reloads are required for memory moves. */ int -memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in) +memory_move_secondary_cost (enum machine_mode mode, enum reg_class rclass, int in) { enum reg_class altclass; int partial_cost = 0; @@ -747,17 +768,17 @@ memory_move_secondary_cost (enum machine_mode mode, enum reg_class class, int in rtx mem ATTRIBUTE_UNUSED = top_of_stack[(int) mode]; - altclass = secondary_reload_class (in ? 1 : 0, class, mode, mem); + altclass = secondary_reload_class (in ? 1 : 0, rclass, mode, mem); if (altclass == NO_REGS) return 0; if (in) - partial_cost = REGISTER_MOVE_COST (mode, altclass, class); + partial_cost = REGISTER_MOVE_COST (mode, altclass, rclass); else - partial_cost = REGISTER_MOVE_COST (mode, class, altclass); + partial_cost = REGISTER_MOVE_COST (mode, rclass, altclass); - if (class == altclass) + if (rclass == altclass) /* This isn't simply a copy-to-temporary situation. Can't guess what it is, so MEMORY_MOVE_COST really ought not to be calling here in that case. @@ -914,7 +935,10 @@ globalize_reg (int i) appropriate regs_invalidated_by_call bit, even if it's already set in fixed_regs. */ if (i != STACK_POINTER_REGNUM) - SET_HARD_REG_BIT (regs_invalidated_by_call, i); + { + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + SET_REGNO_REG_SET (regs_invalidated_by_call_regset, i); + } /* If already fixed, nothing else to do. */ if (fixed_regs[i]) @@ -1024,6 +1048,7 @@ reg_preferred_class (int regno) { if (reg_pref == 0) return GENERAL_REGS; + return (enum reg_class) reg_pref[regno].prefclass; } @@ -1087,23 +1112,23 @@ dump_regclass (FILE *dump) int i; for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) { - int /* enum reg_class */ class; + int /* enum reg_class */ rclass; if (REG_N_REFS (i)) { fprintf (dump, " Register %i costs:", i); - for (class = 0; class < (int) N_REG_CLASSES; class++) - if (contains_reg_of_mode [(enum reg_class) class][PSEUDO_REGNO_MODE (i)] + for (rclass = 0; rclass < (int) N_REG_CLASSES; rclass++) + if (contains_reg_of_mode [(enum reg_class) rclass][PSEUDO_REGNO_MODE (i)] #ifdef FORBIDDEN_INC_DEC_CLASSES && (!in_inc_dec[i] - || !forbidden_inc_dec_class[(enum reg_class) class]) + || !forbidden_inc_dec_class[(enum reg_class) rclass]) #endif #ifdef CANNOT_CHANGE_MODE_CLASS - && ! invalid_mode_change_p (i, (enum reg_class) class, + && ! invalid_mode_change_p (i, (enum reg_class) rclass, PSEUDO_REGNO_MODE (i)) #endif ) - fprintf (dump, " %s:%i", reg_class_names[class], - costs[i].cost[(enum reg_class) class]); + fprintf (dump, " %s:%i", reg_class_names[rclass], + costs[i].cost[(enum reg_class) rclass]); fprintf (dump, " MEM:%i\n", costs[i].mem_cost); } } @@ -1143,8 +1168,9 @@ record_operand_costs (rtx insn, struct costs *op_costs, record_address_regs (GET_MODE (recog_data.operand[i]), XEXP (recog_data.operand[i], 0), 0, MEM, SCRATCH, frequency * 2); - else if (constraints[i][0] == 'p' - || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i])) + else if (recog_data.alternative_enabled_p[0] + && (constraints[i][0] == 'p' + || EXTRA_ADDRESS_CONSTRAINT (constraints[i][0], constraints[i]))) record_address_regs (VOIDmode, recog_data.operand[i], 0, ADDRESS, SCRATCH, frequency * 2); } @@ -1309,7 +1335,7 @@ regclass (rtx f, int nregs) init_recog (); - reg_renumber = xmalloc (max_regno * sizeof (short)); + reg_renumber = XNEWVEC (short, max_regno); reg_pref = XCNEWVEC (struct reg_pref, max_regno); memset (reg_renumber, -1, max_regno * sizeof (short)); @@ -1381,7 +1407,7 @@ regclass (rtx f, int nregs) 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. */ - int class; + int rclass; struct costs *p = &costs[i]; if (regno_reg_rtx[i] == NULL) @@ -1392,27 +1418,27 @@ regclass (rtx f, int nregs) if (optimize && !REG_N_REFS (i) && !REG_N_SETS (i)) continue; - for (class = (int) ALL_REGS - 1; class > 0; class--) + for (rclass = (int) ALL_REGS - 1; rclass > 0; rclass--) { /* Ignore classes that are too small for this operand or invalid for an operand that was auto-incremented. */ - if (!contains_reg_of_mode [class][PSEUDO_REGNO_MODE (i)] + if (!contains_reg_of_mode [rclass][PSEUDO_REGNO_MODE (i)] #ifdef FORBIDDEN_INC_DEC_CLASSES - || (in_inc_dec[i] && forbidden_inc_dec_class[class]) + || (in_inc_dec[i] && forbidden_inc_dec_class[rclass]) #endif #ifdef CANNOT_CHANGE_MODE_CLASS - || invalid_mode_change_p (i, (enum reg_class) class, + || invalid_mode_change_p (i, (enum reg_class) rclass, PSEUDO_REGNO_MODE (i)) #endif ) ; - else if (p->cost[class] < best_cost) + else if (p->cost[rclass] < best_cost) { - best_cost = p->cost[class]; - best = (enum reg_class) class; + best_cost = p->cost[rclass]; + best = (enum reg_class) rclass; } - else if (p->cost[class] == best_cost) - best = reg_class_subunion[(int) best][class]; + else if (p->cost[rclass] == best_cost) + best = reg_class_subunion[(int) best][rclass]; } /* If no register class is better than memory, use memory. */ @@ -1427,19 +1453,19 @@ regclass (rtx f, int nregs) will be doing it again later. */ if ((pass == 1 || dump_file) || ! 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]] + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + if (p->cost[rclass] < p->mem_cost + && (reg_class_size[(int) reg_class_subunion[(int) alt][rclass]] > reg_class_size[(int) alt]) #ifdef FORBIDDEN_INC_DEC_CLASSES - && ! (in_inc_dec[i] && forbidden_inc_dec_class[class]) + && ! (in_inc_dec[i] && forbidden_inc_dec_class[rclass]) #endif #ifdef CANNOT_CHANGE_MODE_CLASS - && ! invalid_mode_change_p (i, (enum reg_class) class, + && ! invalid_mode_change_p (i, (enum reg_class) rclass, PSEUDO_REGNO_MODE (i)) #endif ) - alt = reg_class_subunion[(int) alt][class]; + alt = reg_class_subunion[(int) alt][rclass]; /* If we don't add any classes, nothing to try. */ if (alt == best) @@ -1516,7 +1542,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, int alt_cost = 0; enum reg_class classes[MAX_RECOG_OPERANDS]; int allows_mem[MAX_RECOG_OPERANDS]; - int class; + int rclass; for (i = 0; i < n_ops; i++) { @@ -1616,17 +1642,17 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, switch (recog_data.operand_type[i]) { case OP_INOUT: - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = (intable[class][op_class] - + outtable[op_class][class]); + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = (intable[rclass][op_class] + + outtable[op_class][rclass]); break; case OP_IN: - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = intable[class][op_class]; + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = intable[rclass][op_class]; break; case OP_OUT: - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = outtable[op_class][class]; + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = outtable[op_class][rclass]; break; } @@ -1701,7 +1727,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)]; break; - case 'm': case 'o': case 'V': + case TARGET_MEM_CONSTRAINT: case 'o': case 'V': /* It doesn't seem worth distinguishing between offsettable and non-offsettable addresses here. */ allows_mem[i] = 1; @@ -1860,17 +1886,17 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, switch (recog_data.operand_type[i]) { case OP_INOUT: - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = (intable[class][op_class] - + outtable[op_class][class]); + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = (intable[rclass][op_class] + + outtable[op_class][rclass]); break; case OP_IN: - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = intable[class][op_class]; + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = intable[rclass][op_class]; break; case OP_OUT: - for (class = 0; class < N_REG_CLASSES; class++) - pp->cost[class] = outtable[op_class][class]; + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = outtable[op_class][rclass]; break; } @@ -1932,6 +1958,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, if (alt_fail) continue; + if (!recog_data.alternative_enabled_p[alt]) + continue; + /* Finally, update the costs with the information we've calculated about this alternative. */ @@ -1945,9 +1974,9 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, 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); + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + pp->cost[rclass] = MIN (pp->cost[rclass], + (qq->cost[rclass] + alt_cost) * scale); } } @@ -1957,7 +1986,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, we may want to adjust the cost of that register class to -1. Avoid the adjustment if the source does not die to avoid stressing of - register allocator by preferrencing two colliding registers into single + register allocator by preferencing two colliding registers into single class. Also avoid the adjustment if a copy between registers of the class @@ -1974,7 +2003,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, { unsigned int regno = REGNO (ops[!i]); enum machine_mode mode = GET_MODE (ops[!i]); - int class; + int rclass; if (regno >= FIRST_PSEUDO_REGISTER && reg_pref != 0 && reg_pref[regno].prefclass != NO_REGS) @@ -1987,15 +2016,15 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, op_costs[i].cost[(unsigned char) pref] = -1; } else if (regno < FIRST_PSEUDO_REGISTER) - for (class = 0; class < N_REG_CLASSES; class++) - if (TEST_HARD_REG_BIT (reg_class_contents[class], regno) - && reg_class_size[class] == (unsigned) CLASS_MAX_NREGS (class, mode)) + for (rclass = 0; rclass < N_REG_CLASSES; rclass++) + if (TEST_HARD_REG_BIT (reg_class_contents[rclass], regno) + && reg_class_size[rclass] == (unsigned) CLASS_MAX_NREGS (rclass, mode)) { - if (reg_class_size[class] == 1) - op_costs[i].cost[class] = -1; - else if (in_hard_reg_set_p (reg_class_contents[class], + if (reg_class_size[rclass] == 1) + op_costs[i].cost[rclass] = -1; + else if (in_hard_reg_set_p (reg_class_contents[rclass], mode, regno)) - op_costs[i].cost[class] = -1; + op_costs[i].cost[rclass] = -1; } } } @@ -2006,7 +2035,7 @@ record_reg_classes (int n_alts, int n_ops, rtx *ops, X must not be a pseudo. */ static int -copy_cost (rtx x, enum machine_mode mode, enum reg_class class, int to_p, +copy_cost (rtx x, enum machine_mode mode, enum reg_class rclass, int to_p, secondary_reload_info *prev_sri) { enum reg_class secondary_class = NO_REGS; @@ -2019,7 +2048,7 @@ copy_cost (rtx x, enum machine_mode mode, enum reg_class class, int to_p, return 0; /* Get the class we will actually use for a reload. */ - class = PREFERRED_RELOAD_CLASS (x, class); + rclass = PREFERRED_RELOAD_CLASS (x, rclass); /* If we need a secondary reload for an intermediate, the cost is that to load the input into the intermediate register, then @@ -2027,13 +2056,13 @@ copy_cost (rtx x, enum machine_mode mode, enum reg_class class, int to_p, sri.prev_sri = prev_sri; sri.extra_cost = 0; - secondary_class = targetm.secondary_reload (to_p, x, class, mode, &sri); + secondary_class = targetm.secondary_reload (to_p, x, rclass, mode, &sri); if (!move_cost[mode]) init_move_cost (mode); if (secondary_class != NO_REGS) - return (move_cost[mode][(int) secondary_class][(int) class] + return (move_cost[mode][(int) secondary_class][(int) rclass] + sri.extra_cost + copy_cost (x, mode, secondary_class, to_p, &sri)); @@ -2041,12 +2070,12 @@ copy_cost (rtx x, enum machine_mode mode, enum reg_class class, int to_p, cost to move between the register classes, and use 2 for everything else (constants). */ - if (MEM_P (x) || class == NO_REGS) - return sri.extra_cost + MEMORY_MOVE_COST (mode, class, to_p); + if (MEM_P (x) || rclass == NO_REGS) + return sri.extra_cost + MEMORY_MOVE_COST (mode, rclass, to_p); else if (REG_P (x)) return (sri.extra_cost - + move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) class]); + + move_cost[mode][(int) REGNO_REG_CLASS (REGNO (x))][(int) rclass]); else /* If this is a constant, we may eventually want to call rtx_cost here. */ @@ -2072,12 +2101,12 @@ record_address_regs (enum machine_mode mode, rtx x, int context, int scale) { enum rtx_code code = GET_CODE (x); - enum reg_class class; + enum reg_class rclass; if (context == 1) - class = INDEX_REG_CLASS; + rclass = INDEX_REG_CLASS; else - class = base_reg_class (mode, outer_code, index_code); + rclass = base_reg_class (mode, outer_code, index_code); switch (code) { @@ -2230,12 +2259,12 @@ record_address_regs (enum machine_mode mode, rtx x, int context, struct costs *pp = &costs[REGNO (x)]; int i; - pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2; + pp->mem_cost += (MEMORY_MOVE_COST (Pmode, rclass, 1) * scale) / 2; if (!move_cost[Pmode]) init_move_cost (Pmode); for (i = 0; i < N_REG_CLASSES; i++) - pp->cost[i] += (may_move_in_cost[Pmode][i][(int) class] * scale) / 2; + pp->cost[i] += (may_move_in_cost[Pmode][i][(int) rclass] * scale) / 2; } break; @@ -2279,6 +2308,32 @@ auto_inc_dec_reg_p (rtx reg, enum machine_mode mode) } #endif + +/* Allocate space for reg info. */ +void +allocate_reg_info (void) +{ + int size = max_reg_num (); + + gcc_assert (! reg_pref && ! reg_renumber); + reg_renumber = XNEWVEC (short, size); + reg_pref = XCNEWVEC (struct reg_pref, size); + memset (reg_renumber, -1, size * sizeof (short)); +} + + +/* Resize reg info. The new elements will be uninitialized. */ +void +resize_reg_info (void) +{ + int size = max_reg_num (); + + gcc_assert (reg_pref && reg_renumber); + reg_renumber = XRESIZEVEC (short, reg_renumber, size); + reg_pref = XRESIZEVEC (struct reg_pref, reg_pref, size); +} + + /* Free up the space allocated by allocate_reg_info. */ void free_reg_info (void) @@ -2296,6 +2351,21 @@ free_reg_info (void) } } + + + +/* Set up preferred and alternate classes for REGNO as PREFCLASS and + ALTCLASS. */ +void +setup_reg_classes (int regno, + enum reg_class prefclass, enum reg_class altclass) +{ + if (reg_pref == NULL) + return; + reg_pref[regno].prefclass = prefclass; + reg_pref[regno].altclass = altclass; +} + /* 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 @@ -2496,15 +2566,18 @@ static htab_t subregs_of_mode; static hashval_t som_hash (const void *x) { - const struct subregs_of_mode_node *a = x; + const struct subregs_of_mode_node *const a = + (const struct subregs_of_mode_node *) x; return a->block; } static int som_eq (const void *x, const void *y) { - const struct subregs_of_mode_node *a = x; - const struct subregs_of_mode_node *b = y; + const struct subregs_of_mode_node *const a = + (const struct subregs_of_mode_node *) x; + const struct subregs_of_mode_node *const b = + (const struct subregs_of_mode_node *) y; return a->block == b->block; } @@ -2529,7 +2602,7 @@ record_subregs_of_mode (rtx subreg) dummy.block = regno & -8; slot = htab_find_slot_with_hash (subregs_of_mode, &dummy, dummy.block, INSERT); - node = *slot; + node = (struct subregs_of_mode_node *) *slot; if (node == NULL) { node = XCNEW (struct subregs_of_mode_node); @@ -2601,7 +2674,8 @@ cannot_change_mode_set_regs (HARD_REG_SET *used, enum machine_mode from, gcc_assert (subregs_of_mode); dummy.block = regno & -8; - node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); + node = (struct subregs_of_mode_node *) + htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); if (node == NULL) return; @@ -2619,7 +2693,7 @@ cannot_change_mode_set_regs (HARD_REG_SET *used, enum machine_mode from, bool invalid_mode_change_p (unsigned int regno, - enum reg_class class ATTRIBUTE_UNUSED, + enum reg_class rclass ATTRIBUTE_UNUSED, enum machine_mode from) { struct subregs_of_mode_node dummy, *node; @@ -2628,14 +2702,15 @@ invalid_mode_change_p (unsigned int regno, gcc_assert (subregs_of_mode); dummy.block = regno & -8; - node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); + node = (struct subregs_of_mode_node *) + htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); if (node == NULL) return false; mask = 1 << (regno & 7); for (to = VOIDmode; to < NUM_MACHINE_MODES; to++) if (node->modes[to] & mask) - if (CANNOT_CHANGE_MODE_CLASS (from, to, class)) + if (CANNOT_CHANGE_MODE_CLASS (from, to, rclass)) return true; return false;