bool default_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr ATTRIBUTE_UNUSED, bool strict ATTRIBUTE_UNUSED) { #ifdef GO_IF_LEGITIMATE_ADDRESS /* Defer to the old implementation using a goto. */ if (strict) return strict_memory_address_p (mode, addr); else return memory_address_p (mode, addr); #else gcc_unreachable (); #endif }
void init_caller_save () { char *first_obj = (char *) oballoc (0); rtx addr_reg; int offset; rtx address; int i, j; /* First find all the registers that we need to deal with and all the modes that they can have. If we can't find a mode to use, we can't have the register live over calls. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (call_used_regs[i] && ! call_fixed_regs[i]) { for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++) { regno_save_mode[i][j] = choose_hard_reg_mode (i, j); if (regno_save_mode[i][j] == VOIDmode && j == 1) { call_fixed_regs[i] = 1; SET_HARD_REG_BIT (call_fixed_reg_set, i); } } } else regno_save_mode[i][1] = VOIDmode; } /* The following code tries to approximate the conditions under which we can easily save and restore a register without scratch registers or other complexities. It will usually work, except under conditions where the validity of an insn operand is dependent on the address offset. No such cases are currently known. We first find a typical offset from some BASE_REG_CLASS register. This address is chosen by finding the first register in the class and by finding the smallest power of two that is a valid offset from that register in every mode we will use to save registers. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (reg_class_contents[(int) BASE_REG_CLASS], i)) break; if (i == FIRST_PSEUDO_REGISTER) abort (); addr_reg = gen_rtx_REG (Pmode, i); for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1) { address = gen_rtx_PLUS (Pmode, addr_reg, GEN_INT (offset)); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (regno_save_mode[i][1] != VOIDmode && ! strict_memory_address_p (regno_save_mode[i][1], address)) break; if (i == FIRST_PSEUDO_REGISTER) break; } /* If we didn't find a valid address, we must use register indirect. */ if (offset == 0) address = addr_reg; /* Next we try to form an insn to save and restore the register. We see if such an insn is recognized and meets its constraints. */ start_sequence (); for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++) if (regno_save_mode[i][j] != VOIDmode) { rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address); rtx reg = gen_rtx_REG (regno_save_mode[i][j], i); rtx savepat = gen_rtx_SET (VOIDmode, mem, reg); rtx restpat = gen_rtx_SET (VOIDmode, reg, mem); rtx saveinsn = emit_insn (savepat); rtx restinsn = emit_insn (restpat); int ok; reg_save_code[i][j] = recog_memoized (saveinsn); reg_restore_code[i][j] = recog_memoized (restinsn); /* Now extract both insns and see if we can meet their constraints. */ ok = (reg_save_code[i][j] != -1 && reg_restore_code[i][j] != -1); if (ok) { insn_extract (saveinsn); ok = constrain_operands (reg_save_code[i][j], 1); insn_extract (restinsn); ok &= constrain_operands (reg_restore_code[i][j], 1); } if (! ok) { regno_save_mode[i][j] = VOIDmode; if (j == 1) { call_fixed_regs[i] = 1; SET_HARD_REG_BIT (call_fixed_reg_set, i); } } } end_sequence (); obfree (first_obj); }