explow.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,396 行 · 第 1/3 页
C
1,396 行
then we generate that address in a register and index off of it. We do this because it often makes shorter code, and because the addresses thus generated in registers often become common subexpressions. */ if (GET_CODE (x) == PLUS) { rtx constant_term = const0_rtx; rtx y = eliminate_constant_term (x, &constant_term); if (constant_term == const0_rtx || ! memory_address_p (mode, y)) x = force_operand (x, NULL_RTX); else { y = gen_rtx (PLUS, GET_MODE (x), copy_to_reg (y), constant_term); if (! memory_address_p (mode, y)) x = force_operand (x, NULL_RTX); else x = y; } } else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS) x = force_operand (x, NULL_RTX); /* If we have a register that's an invalid address, it must be a hard reg of the wrong class. Copy it to a pseudo. */ else if (GET_CODE (x) == REG) x = copy_to_reg (x); /* Last resort: copy the value to a register, since the register is a valid address. */ else x = force_reg (Pmode, x); goto done; win2: x = oldx; win: if (flag_force_addr && ! cse_not_expected && GET_CODE (x) != REG /* Don't copy an addr via a reg if it is one of our stack slots. */ && ! (GET_CODE (x) == PLUS && (XEXP (x, 0) == virtual_stack_vars_rtx || XEXP (x, 0) == virtual_incoming_args_rtx))) { if (general_operand (x, Pmode)) x = force_reg (Pmode, x); else x = force_operand (x, NULL_RTX); } } done: /* If we didn't change the address, we are done. Otherwise, mark a reg as a pointer if we have REG or REG + CONST_INT. */ if (oldx == x) return x; else if (GET_CODE (x) == REG) mark_reg_pointer (x, 1); else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT) mark_reg_pointer (XEXP (x, 0), 1); /* OLDX may have been the address on a temporary. Update the address to indicate that X is now used. */ update_temp_slot_address (oldx, x); return x;}/* Like `memory_address' but pretend `flag_force_addr' is 0. */rtxmemory_address_noforce (mode, x) enum machine_mode mode; rtx x;{ int ambient_force_addr = flag_force_addr; rtx val; flag_force_addr = 0; val = memory_address (mode, x); flag_force_addr = ambient_force_addr; return val;}/* Convert a mem ref into one with a valid memory address. Pass through anything else unchanged. */rtxvalidize_mem (ref) rtx ref;{ if (GET_CODE (ref) != MEM) return ref; if (memory_address_p (GET_MODE (ref), XEXP (ref, 0))) return ref; /* Don't alter REF itself, since that is probably a stack slot. */ return change_address (ref, GET_MODE (ref), XEXP (ref, 0));}/* Return a modified copy of X with its memory address copied into a temporary register to protect it from side effects. If X is not a MEM, it is returned unchanged (and not copied). Perhaps even if it is a MEM, if there is no need to change it. */rtxstabilize (x) rtx x;{ register rtx addr; if (GET_CODE (x) != MEM) return x; addr = XEXP (x, 0); if (rtx_unstable_p (addr)) { rtx temp = copy_all_regs (addr); rtx mem; if (GET_CODE (temp) != REG) temp = copy_to_reg (temp); mem = gen_rtx (MEM, GET_MODE (x), temp); /* Mark returned memref with in_struct if it's in an array or structure. Copy const and volatile from original memref. */ MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (x) || GET_CODE (addr) == PLUS; RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (x); MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (x); return mem; } return x;}/* Copy the value or contents of X to a new temp reg and return that reg. */rtxcopy_to_reg (x) rtx x;{ register rtx temp = gen_reg_rtx (GET_MODE (x)); /* If not an operand, must be an address with PLUS and MULT so do the computation. */ if (! general_operand (x, VOIDmode)) x = force_operand (x, temp); if (x != temp) emit_move_insn (temp, x); return temp;}/* Like copy_to_reg but always give the new register mode Pmode in case X is a constant. */rtxcopy_addr_to_reg (x) rtx x;{ return copy_to_mode_reg (Pmode, x);}/* Like copy_to_reg but always give the new register mode MODE in case X is a constant. */rtxcopy_to_mode_reg (mode, x) enum machine_mode mode; rtx x;{ register rtx temp = gen_reg_rtx (mode); /* If not an operand, must be an address with PLUS and MULT so do the computation. */ if (! general_operand (x, VOIDmode)) x = force_operand (x, temp); if (GET_MODE (x) != mode && GET_MODE (x) != VOIDmode) abort (); if (x != temp) emit_move_insn (temp, x); return temp;}/* Load X into a register if it is not already one. Use mode MODE for the register. X should be valid for mode MODE, but it may be a constant which is valid for all integer modes; that's why caller must specify MODE. The caller must not alter the value in the register we return, since we mark it as a "constant" register. */rtxforce_reg (mode, x) enum machine_mode mode; rtx x;{ register rtx temp, insn, set; if (GET_CODE (x) == REG) return x; temp = gen_reg_rtx (mode); insn = emit_move_insn (temp, x); /* Let optimizers know that TEMP's value never changes and that X can be substituted for it. Don't get confused if INSN set something else (such as a SUBREG of TEMP). */ if (CONSTANT_P (x) && (set = single_set (insn)) != 0 && SET_DEST (set) == temp) { rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX); if (note) XEXP (note, 0) = x; else REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, x, REG_NOTES (insn)); } return temp;}/* If X is a memory ref, copy its contents to a new temp reg and return that reg. Otherwise, return X. */rtxforce_not_mem (x) rtx x;{ register rtx temp; if (GET_CODE (x) != MEM || GET_MODE (x) == BLKmode) return x; temp = gen_reg_rtx (GET_MODE (x)); emit_move_insn (temp, x); return temp;}/* Copy X to TARGET (if it's nonzero and a reg) or to a new temp reg and return that reg. MODE is the mode to use for X in case it is a constant. */rtxcopy_to_suggested_reg (x, target, mode) rtx x, target; enum machine_mode mode;{ register rtx temp; if (target && GET_CODE (target) == REG) temp = target; else temp = gen_reg_rtx (mode); emit_move_insn (temp, x); return temp;}/* Return the mode to use to store a scalar of TYPE and MODE. PUNSIGNEDP points to the signedness of the type and may be adjusted to show what signedness to use on extension operations. FOR_CALL is non-zero if this call is promoting args for a call. */enum machine_modepromote_mode (type, mode, punsignedp, for_call) tree type; enum machine_mode mode; int *punsignedp; int for_call;{ enum tree_code code = TREE_CODE (type); int unsignedp = *punsignedp;#ifdef PROMOTE_FOR_CALL_ONLY if (! for_call) return mode;#endif switch (code) {#ifdef PROMOTE_MODE case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: case CHAR_TYPE: case REAL_TYPE: case OFFSET_TYPE: PROMOTE_MODE (mode, unsignedp, type); break;#endif#ifdef POINTERS_EXTEND_UNSIGNED case REFERENCE_TYPE: case POINTER_TYPE: mode = Pmode; unsignedp = POINTERS_EXTEND_UNSIGNED; break;#endif default: break; } *punsignedp = unsignedp; return mode;}/* Adjust the stack pointer by ADJUST (an rtx for a number of bytes). This pops when ADJUST is positive. ADJUST need not be constant. */voidadjust_stack (adjust) rtx adjust;{ rtx temp; adjust = protect_from_queue (adjust, 0); if (adjust == const0_rtx) return; temp = expand_binop (Pmode,#ifdef STACK_GROWS_DOWNWARD add_optab,#else sub_optab,#endif stack_pointer_rtx, adjust, stack_pointer_rtx, 0, OPTAB_LIB_WIDEN); if (temp != stack_pointer_rtx) emit_move_insn (stack_pointer_rtx, temp);}/* Adjust the stack pointer by minus ADJUST (an rtx for a number of bytes). This pushes when ADJUST is positive. ADJUST need not be constant. */voidanti_adjust_stack (adjust) rtx adjust;{ rtx temp; adjust = protect_from_queue (adjust, 0); if (adjust == const0_rtx) return; temp = expand_binop (Pmode,#ifdef STACK_GROWS_DOWNWARD sub_optab,#else add_optab,#endif stack_pointer_rtx, adjust, stack_pointer_rtx, 0, OPTAB_LIB_WIDEN); if (temp != stack_pointer_rtx) emit_move_insn (stack_pointer_rtx, temp);}/* Round the size of a block to be pushed up to the boundary required by this machine. SIZE is the desired size, which need not be constant. */rtxround_push (size) rtx size;{#ifdef STACK_BOUNDARY int align = STACK_BOUNDARY / BITS_PER_UNIT; if (align == 1) return size; if (GET_CODE (size) == CONST_INT) { int new = (INTVAL (size) + align - 1) / align * align; if (INTVAL (size) != new) size = GEN_INT (new); } else { /* CEIL_DIV_EXPR needs to worry about the addition overflowing, but we know it can't. So add ourselves and then do TRUNC_DIV_EXPR. */ size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1), NULL_RTX, 1, OPTAB_LIB_WIDEN); size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align), NULL_RTX, 1); size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1); }#endif /* STACK_BOUNDARY */ return size;}/* Save the stack pointer for the purpose in SAVE_LEVEL. PSAVE is a pointer to a previously-created save area. If no save area has been allocated, this function will allocate one. If a save area is specified, it must be of the proper mode. The insns are emitted after insn AFTER, if nonzero, otherwise the insns are emitted at the current position. */voidemit_stack_save (save_level, psave, after) enum save_level save_level; rtx *psave; rtx after;{ rtx sa = *psave; /* The default is that we use a move insn and save in a Pmode object. */ rtx (*fcn) () = gen_move_insn; enum machine_mode mode = Pmode; /* See if this machine has anything special to do for this kind of save. */ switch (save_level) {#ifdef HAVE_save_stack_block case SAVE_BLOCK: if (HAVE_save_stack_block) { fcn = gen_save_stack_block; mode = insn_operand_mode[CODE_FOR_save_stack_block][0]; } break;#endif#ifdef HAVE_save_stack_function case SAVE_FUNCTION: if (HAVE_save_stack_function) { fcn = gen_save_stack_function; mode = insn_operand_mode[CODE_FOR_save_stack_function][0]; } break;#endif#ifdef HAVE_save_stack_nonlocal case SAVE_NONLOCAL: if (HAVE_save_stack_nonlocal) { fcn = gen_save_stack_nonlocal; mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0]; } break;#endif default: break; } /* If there is no save area and we have to allocate one, do so. Otherwise verify the save area is the proper mode. */ if (sa == 0) { if (mode != VOIDmode) { if (save_level == SAVE_NONLOCAL) *psave = sa = assign_stack_local (mode, GET_MODE_SIZE (mode), 0); else *psave = sa = gen_reg_rtx (mode); } } else { if (mode == VOIDmode || GET_MODE (sa) != mode) abort (); } if (after) { rtx seq; start_sequence (); /* We must validize inside the sequence, to ensure that any instructions
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?