📄 expr.c
字号:
emit_library_call (bzero_libfunc, 0, VOIDmode, 2, XEXP (object, 0), Pmode, convert_to_mode (TYPE_MODE (sizetype), size, TREE_UNSIGNED (sizetype)), TYPE_MODE (sizetype));#endif } else emit_move_insn (object, const0_rtx);}/* Generate code to copy Y into X. Both Y and X must have the same mode, except that Y can be a constant with VOIDmode. This mode cannot be BLKmode; use emit_block_move for that. Return the last instruction emitted. */rtxemit_move_insn (x, y) rtx x, y;{ enum machine_mode mode = GET_MODE (x); x = protect_from_queue (x, 1); y = protect_from_queue (y, 0); if (mode == BLKmode || (GET_MODE (y) != mode && GET_MODE (y) != VOIDmode)) abort (); if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y)) y = force_const_mem (mode, y); /* If X or Y are memory references, verify that their addresses are valid for the machine. */ if (GET_CODE (x) == MEM && ((! memory_address_p (GET_MODE (x), XEXP (x, 0)) && ! push_operand (x, GET_MODE (x))) || (flag_force_addr && CONSTANT_ADDRESS_P (XEXP (x, 0))))) x = change_address (x, VOIDmode, XEXP (x, 0)); if (GET_CODE (y) == MEM && (! memory_address_p (GET_MODE (y), XEXP (y, 0)) || (flag_force_addr && CONSTANT_ADDRESS_P (XEXP (y, 0))))) y = change_address (y, VOIDmode, XEXP (y, 0)); if (mode == BLKmode) abort (); return emit_move_insn_1 (x, y);}/* Low level part of emit_move_insn. Called just like emit_move_insn, but assumes X and Y are basically valid. */rtxemit_move_insn_1 (x, y) rtx x, y;{ enum machine_mode mode = GET_MODE (x); enum machine_mode submode; enum mode_class class = GET_MODE_CLASS (mode); int i; if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing) return emit_insn (GEN_FCN (mov_optab->handlers[(int) mode].insn_code) (x, y)); /* Expand complex moves by moving real part and imag part, if possible. */ else if ((class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT) && BLKmode != (submode = mode_for_size ((GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT), (class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT), 0)) && (mov_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)) { /* Don't split destination if it is a stack push. */ int stack = push_operand (x, GET_MODE (x)); rtx insns; /* If this is a stack, push the highpart first, so it will be in the argument order. In that case, change_address is used only to convert the mode, not to change the address. */ if (stack) { /* Note that the real part always precedes the imag part in memory regardless of machine's endianness. */#ifdef STACK_GROWS_DOWNWARD emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code) (gen_rtx (MEM, submode, (XEXP (x, 0))), gen_imagpart (submode, y))); emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code) (gen_rtx (MEM, submode, (XEXP (x, 0))), gen_realpart (submode, y)));#else emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code) (gen_rtx (MEM, submode, (XEXP (x, 0))), gen_realpart (submode, y))); emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code) (gen_rtx (MEM, submode, (XEXP (x, 0))), gen_imagpart (submode, y)));#endif } else { emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code) (gen_realpart (submode, x), gen_realpart (submode, y))); emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code) (gen_imagpart (submode, x), gen_imagpart (submode, y))); } return get_last_insn (); } /* This will handle any multi-word mode that lacks a move_insn pattern. However, you will get better code if you define such patterns, even if they must turn into multiple assembler instructions. */ else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) { rtx last_insn = 0; rtx insns; #ifdef PUSH_ROUNDING /* If X is a push on the stack, do the push now and replace X with a reference to the stack pointer. */ if (push_operand (x, GET_MODE (x))) { anti_adjust_stack (GEN_INT (GET_MODE_SIZE (GET_MODE (x)))); x = change_address (x, VOIDmode, stack_pointer_rtx); }#endif /* Show the output dies here. */ emit_insn (gen_rtx (CLOBBER, VOIDmode, x)); for (i = 0; i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; i++) { rtx xpart = operand_subword (x, i, 1, mode); rtx ypart = operand_subword (y, i, 1, mode); /* If we can't get a part of Y, put Y into memory if it is a constant. Otherwise, force it into a register. If we still can't get a part of Y, abort. */ if (ypart == 0 && CONSTANT_P (y)) { y = force_const_mem (mode, y); ypart = operand_subword (y, i, 1, mode); } else if (ypart == 0) ypart = operand_subword_force (y, i, mode); if (xpart == 0 || ypart == 0) abort (); last_insn = emit_move_insn (xpart, ypart); } return last_insn; } else abort ();}/* Pushing data onto the stack. *//* Push a block of length SIZE (perhaps variable) and return an rtx to address the beginning of the block. Note that it is not possible for the value returned to be a QUEUED. The value may be virtual_outgoing_args_rtx. EXTRA is the number of bytes of padding to push in addition to SIZE. BELOW nonzero means this padding comes at low addresses; otherwise, the padding comes at high addresses. */rtxpush_block (size, extra, below) rtx size; int extra, below;{ register rtx temp; size = convert_modes (Pmode, ptr_mode, size, 1); if (CONSTANT_P (size)) anti_adjust_stack (plus_constant (size, extra)); else if (GET_CODE (size) == REG && extra == 0) anti_adjust_stack (size); else { rtx temp = copy_to_mode_reg (Pmode, size); if (extra != 0) temp = expand_binop (Pmode, add_optab, temp, GEN_INT (extra), temp, 0, OPTAB_LIB_WIDEN); anti_adjust_stack (temp); }#ifdef STACK_GROWS_DOWNWARD temp = virtual_outgoing_args_rtx; if (extra != 0 && below) temp = plus_constant (temp, extra);#else if (GET_CODE (size) == CONST_INT) temp = plus_constant (virtual_outgoing_args_rtx, - INTVAL (size) - (below ? 0 : extra)); else if (extra != 0 && !below) temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx, negate_rtx (Pmode, plus_constant (size, extra))); else temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx, negate_rtx (Pmode, size));#endif return memory_address (GET_CLASS_NARROWEST_MODE (MODE_INT), temp);}rtxgen_push_operand (){ return gen_rtx (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);}/* Generate code to push X onto the stack, assuming it has mode MODE and type TYPE. MODE is redundant except when X is a CONST_INT (since they don't carry mode info). SIZE is an rtx for the size of data to be copied (in bytes), needed only if X is BLKmode. ALIGN (in bytes) is maximum alignment we can assume. If PARTIAL and REG are both nonzero, then copy that many of the first words of X into registers starting with REG, and push the rest of X. The amount of space pushed is decreased by PARTIAL words, rounded *down* to a multiple of PARM_BOUNDARY. REG must be a hard register in this case. If REG is zero but PARTIAL is not, take any all others actions for an argument partially in registers, but do not actually load any registers. EXTRA is the amount in bytes of extra space to leave next to this arg. This is ignored if an argument block has already been allocated. On a machine that lacks real push insns, ARGS_ADDR is the address of the bottom of the argument block for this call. We use indexing off there to store the arg. On machines with push insns, ARGS_ADDR is 0 when a argument block has not been preallocated. ARGS_SO_FAR is the size of args previously pushed for this call. */voidemit_push_insn (x, mode, type, size, align, partial, reg, extra, args_addr, args_so_far) register rtx x; enum machine_mode mode; tree type; rtx size; int align; int partial; rtx reg; int extra; rtx args_addr; rtx args_so_far;{ rtx xinner; enum direction stack_direction#ifdef STACK_GROWS_DOWNWARD = downward;#else = upward;#endif /* Decide where to pad the argument: `downward' for below, `upward' for above, or `none' for don't pad it. Default is below for small data on big-endian machines; else above. */ enum direction where_pad = FUNCTION_ARG_PADDING (mode, type); /* Invert direction if stack is post-update. */ if (STACK_PUSH_CODE == POST_INC || STACK_PUSH_CODE == POST_DEC) if (where_pad != none) where_pad = (where_pad == downward ? upward : downward); xinner = x = protect_from_queue (x, 0); if (mode == BLKmode) { /* Copy a block into the stack, entirely or partially. */ register rtx temp; int used = partial * UNITS_PER_WORD; int offset = used % (PARM_BOUNDARY / BITS_PER_UNIT); int skip; if (size == 0) abort (); used -= offset; /* USED is now the # of bytes we need not copy to the stack because registers will take care of them. */ if (partial != 0) xinner = change_address (xinner, BLKmode, plus_constant (XEXP (xinner, 0), used)); /* If the partial register-part of the arg counts in its stack size, skip the part of stack space corresponding to the registers. Otherwise, start copying to the beginning of the stack space, by setting SKIP to 0. */#ifndef REG_PARM_STACK_SPACE skip = 0;#else skip = used;#endif#ifdef PUSH_ROUNDING /* Do it with several push insns if that doesn't take lots of insns and if there is no difficulty with push insns that skip bytes on the stack for alignment purposes. */ if (args_addr == 0 && GET_CODE (size) == CONST_INT && skip == 0 && (move_by_pieces_ninsns ((unsigned) INTVAL (size) - used, align) < MOVE_RATIO) /* Here we avoid the case of a structure whose weak alignment forces many pushes of a small amount of data, and such small pushes do rounding that causes trouble. */ && ((! SLOW_UNALIGNED_ACCESS) || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT || PUSH_ROUNDING (align) == align) && PUSH_ROUNDING (INTVAL (size)) == INTVAL (size)) { /* Push padding now if padding above and stack grows down, or if padding below and stack grows up. But if space already allocated, this has already been done. */ if (extra && args_addr == 0 && where_pad != none && where_pad != stack_direction) anti_adjust_stack (GEN_INT (extra)); move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner, INTVAL (size) - used, align); } else#endif /* PUSH_ROUNDING */ { /* Otherwise make space on the stack and copy the data to the address of that space. */ /* Deduct words put into registers from the size we must copy. */ if (partial != 0) { if (GET_CODE (size) == CONST_INT) size = GEN_INT (INTVAL (size) - used); else size = expand_binop (GET_MODE (size), sub_optab, size, GEN_INT (used), NULL_RTX, 0, OPTAB_LIB_WIDEN); } /* Get the address of the stack space. In this case, we do not deal with EXTRA separately. A single stack adjust will do. */ if (! args_addr) { temp = push_block (size, extra, where_pad == downward); extra = 0; } else if (GET_CODE (args_so_far) == CONST_INT) temp = memory_address (BLKmode, plus_constant (args_addr, skip + INTVAL (args_so_far))); else temp = memory_address (BLKmode, plus_constant (gen_rtx (PLUS, Pmode, args_addr, args_so_far), skip)); /* TEMP is the address of the block. Copy the data there. */ if (GET_CODE (size) == CONST_INT && (move_by_pieces_ninsns ((unsigned) INTVAL (size), align) < MOVE_RATIO)) { move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner, INTVAL (size), align); goto ret; } /* Try the most limited insn first, because there's no point including more than one in the machine description unless the more limited one has some advantage. */#ifdef HAVE_movstrqi if (HAVE_movstrqi && GET_CODE (size) == CONST_INT && ((unsigned) INTVAL (size) < (1 << (GET_MODE_BITSIZE (QImode) - 1)))) { rtx pat = gen_movstrqi (gen_rtx (MEM, BLKmode, temp), xinner, size, GEN_INT (align)); if (pat != 0) { emit_insn (pat); goto ret; } }#endif#ifdef HAVE_movstrhi if (HAVE_movstrhi && GET_CODE (size) == CONST_INT && ((unsigned) INTVAL (size) < (1 << (GET_MODE_BITSIZE (HImode) - 1)))) { rtx pat = gen_movstrhi (gen_rtx (MEM, BLKmode, temp), xinner, size, GEN_INT (align)); if (pat != 0) { emit_insn (pat); goto ret; } }#endif#ifdef HAVE_movstrsi if (HAVE_movstrsi) { rtx pat = gen_movstrsi (gen_rtx (MEM, BLKmode, temp), xinner, size, GEN_INT (align)); if (pat != 0) { emit_insn (pat); goto ret; } }#endif#ifdef HAVE_movstrdi if (HAVE_movstrdi) { rtx pat = gen_movstrdi (gen_rtx (MEM, BLKmode, temp), xinner, size, GEN_INT (align)); if (pat != 0) { emit_insn (pat); goto ret; } }#endif#ifndef ACCUMULATE_OUTGOING_ARGS /* If the source is referenced relative to the stack pointer, copy it to another register to stabilize it. We do not need to do this if we know that we won't be changing sp. */ if (reg_mentioned_p (virtual_stack_dynamic_rtx, temp) ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -