📄 explow.c
字号:
/* We get better cse by rejecting indirect addressing at this stage. Let the combiner create indirect addresses where appropriate. For now, generate the code so that the subexpressions useful to share are visible. But not if cse won't be done! */ else { if (! cse_not_expected && GET_CODE (x) != REG) x = break_out_memory_refs (x); /* At this point, any valid address is accepted. */ GO_IF_LEGITIMATE_ADDRESS (mode, x, win); /* If it was valid before but breaking out memory refs invalidated it, use it the old way. */ if (memory_address_p (mode, oldx)) goto win2; /* Perform machine-dependent transformations on X in certain cases. This is not necessary since the code below can handle all possible cases, but machine-dependent transformations can make better code. */ LEGITIMIZE_ADDRESS (x, oldx, mode, win); /* PLUS and MULT can appear in special ways as the result of attempts to make an address usable for indexing. Usually they are dealt with by calling force_operand, below. But a sum containing constant terms is special if removing them makes the sum a valid address: 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); 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)); /* 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 POINTER_TYPE: mode = Pmode; unsignedp = POINTERS_EXTEND_UNSIGNED; break;#endif } *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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -