void moxie_expand_epilogue (void) { int regno; rtx insn, reg, cfa_restores = NULL; if (cfun->machine->callee_saved_reg_size != 0) { reg = gen_rtx_REG (Pmode, MOXIE_R5); if (cfun->machine->callee_saved_reg_size <= 255) { emit_move_insn (reg, hard_frame_pointer_rtx); emit_insn (gen_subsi3 (reg, reg, GEN_INT (cfun->machine->callee_saved_reg_size))); } else { emit_move_insn (reg, GEN_INT (-cfun->machine->callee_saved_reg_size)); emit_insn (gen_addsi3 (reg, reg, hard_frame_pointer_rtx)); } for (regno = FIRST_PSEUDO_REGISTER; regno-- > 0; ) if (!fixed_regs[regno] && !call_used_regs[regno] && df_regs_ever_live_p (regno)) { rtx preg = gen_rtx_REG (Pmode, regno); insn = emit_insn (gen_movsi_pop (reg, preg)); } } emit_jump_insn (gen_returner ()); }
static bool nds32_expand_setmem_loop_v3m (rtx dstmem, rtx size, rtx value) { rtx base_reg = copy_to_mode_reg (Pmode, XEXP (dstmem, 0)); rtx need_align_bytes = gen_reg_rtx (SImode); rtx last_2_bit = gen_reg_rtx (SImode); rtx byte_loop_base = gen_reg_rtx (SImode); rtx byte_loop_size = gen_reg_rtx (SImode); rtx remain_size = gen_reg_rtx (SImode); rtx new_base_reg; rtx value4byte, value4doubleword; rtx byte_mode_size; rtx last_byte_loop_label = gen_label_rtx (); size = force_reg (SImode, size); value4doubleword = nds32_gen_dup_8_byte_to_double_word_value (value); value4byte = simplify_gen_subreg (QImode, value4doubleword, DImode, subreg_lowpart_offset (QImode, DImode)); emit_move_insn (byte_loop_size, size); emit_move_insn (byte_loop_base, base_reg); /* Jump to last byte loop if size is less than 16. */ emit_cmp_and_jump_insns (size, gen_int_mode (16, SImode), LE, NULL, SImode, 1, last_byte_loop_label); /* Make sure align to 4 byte first since v3m can't unalign access. */ emit_insn (gen_andsi3 (last_2_bit, base_reg, gen_int_mode (0x3, SImode))); emit_insn (gen_subsi3 (need_align_bytes, gen_int_mode (4, SImode), last_2_bit)); /* Align to 4 byte. */ new_base_reg = emit_setmem_byte_loop (base_reg, need_align_bytes, value4byte, true); /* Calculate remain size. */ emit_insn (gen_subsi3 (remain_size, size, need_align_bytes)); /* Set memory word by word. */ byte_mode_size = emit_setmem_doubleword_loop (new_base_reg, remain_size, value4doubleword); emit_move_insn (byte_loop_base, new_base_reg); emit_move_insn (byte_loop_size, byte_mode_size); emit_label (last_byte_loop_label); /* And set memory for remain bytes. */ emit_setmem_byte_loop (byte_loop_base, byte_loop_size, value4byte, false); return true; }
bool nds32_expand_strlen (rtx result, rtx str, rtx target_char, rtx align ATTRIBUTE_UNUSED) { rtx base_reg, backup_base_reg; rtx ffb_result; rtx target_char_ptr, length; rtx loop_label, tmp; if (optimize_size || optimize < 3) return false; gcc_assert (MEM_P (str)); gcc_assert (CONST_INT_P (target_char) || REG_P (target_char)); base_reg = copy_to_mode_reg (SImode, XEXP (str, 0)); loop_label = gen_label_rtx (); ffb_result = gen_reg_rtx (Pmode); tmp = gen_reg_rtx (SImode); backup_base_reg = gen_reg_rtx (SImode); /* Emit loop version of strlen. move $backup_base, $base .Lloop: lmw.bim $tmp, [$base], $tmp, 0 ffb $ffb_result, $tmp, $target_char ! is there $target_char? beqz $ffb_result, .Lloop add $last_char_ptr, $base, $ffb_result sub $length, $last_char_ptr, $backup_base */ /* move $backup_base, $base */ emit_move_insn (backup_base_reg, base_reg); /* .Lloop: */ emit_label (loop_label); /* lmw.bim $tmp, [$base], $tmp, 0 */ emit_insn (gen_unaligned_load_update_base_w (base_reg, tmp, base_reg)); /* ffb $ffb_result, $tmp, $target_char ! is there $target_char? */ emit_insn (gen_unspec_ffb (ffb_result, tmp, target_char)); /* beqz $ffb_result, .Lloop */ emit_cmp_and_jump_insns (ffb_result, const0_rtx, EQ, NULL, SImode, 1, loop_label); /* add $target_char_ptr, $base, $ffb_result */ target_char_ptr = expand_binop (Pmode, add_optab, base_reg, ffb_result, NULL_RTX, 0, OPTAB_WIDEN); /* sub $length, $target_char_ptr, $backup_base */ length = expand_binop (Pmode, sub_optab, target_char_ptr, backup_base_reg, NULL_RTX, 0, OPTAB_WIDEN); emit_move_insn (result, length); return true; }
/* Generate code for transformations 3 and 4 (with MODE and OPERATION, operands OP1 and OP2, result TARGET, at most SUB subtractions, and probability of taking the optimal path(s) PROB1 and PROB2). */ static rtx gen_mod_subtract (enum machine_mode mode, enum rtx_code operation, rtx target, rtx op1, rtx op2, int sub, int prob1, int prob2) { rtx tmp, tmp1, jump; rtx end_label = gen_label_rtx (); rtx sequence; int i; start_sequence (); if (!REG_P (op2)) { tmp = gen_reg_rtx (mode); emit_move_insn (tmp, copy_rtx (op2)); } else tmp = op2; emit_move_insn (target, copy_rtx (op1)); do_compare_rtx_and_jump (target, tmp, LTU, 0, mode, NULL_RTX, NULL_RTX, end_label); /* Add branch probability to jump we just created. */ jump = get_last_insn (); REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob1), REG_NOTES (jump)); for (i = 0; i < sub; i++) { tmp1 = expand_simple_binop (mode, MINUS, target, tmp, target, 0, OPTAB_WIDEN); if (tmp1 != target) emit_move_insn (target, tmp1); do_compare_rtx_and_jump (target, tmp, LTU, 0, mode, NULL_RTX, NULL_RTX, end_label); /* Add branch probability to jump we just created. */ jump = get_last_insn (); REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob2), REG_NOTES (jump)); } tmp1 = simplify_gen_binary (operation, mode, copy_rtx (target), copy_rtx (tmp)); tmp1 = force_operand (tmp1, target); if (tmp1 != target) emit_move_insn (target, tmp1); emit_label (end_label); sequence = get_insns (); end_sequence (); rebuild_jump_labels (sequence); return sequence; }
/* Generate and emit RTL to save or restore callee save registers. */ static void expand_save_restore (struct lm32_frame_info *info, int op) { unsigned int reg_save_mask = info->reg_save_mask; int regno; HOST_WIDE_INT offset; rtx insn; /* Callee saves are below locals and above outgoing arguments. */ offset = info->args_size + info->callee_size; for (regno = 0; regno <= 31; regno++) { if ((reg_save_mask & (1 << regno)) != 0) { rtx offset_rtx; rtx mem; offset_rtx = GEN_INT (offset); if (satisfies_constraint_K (offset_rtx)) { mem = gen_rtx_MEM (word_mode, gen_rtx_PLUS (Pmode, stack_pointer_rtx, offset_rtx)); } else { /* r10 is caller saved so it can be used as a temp reg. */ rtx r10; r10 = gen_rtx_REG (word_mode, 10); insn = emit_move_insn (r10, offset_rtx); if (op == 0) RTX_FRAME_RELATED_P (insn) = 1; insn = emit_add (r10, r10, stack_pointer_rtx); if (op == 0) RTX_FRAME_RELATED_P (insn) = 1; mem = gen_rtx_MEM (word_mode, r10); } if (op == 0) insn = emit_move_insn (mem, gen_rtx_REG (word_mode, regno)); else insn = emit_move_insn (gen_rtx_REG (word_mode, regno), mem); /* only prologue instructions which set the sp fp or save a register should be marked as frame related. */ if (op == 0) RTX_FRAME_RELATED_P (insn) = 1; offset -= UNITS_PER_WORD; } } }
static void nds32_emit_load_store (rtx reg, rtx mem, enum machine_mode mode, int offset, bool load_p) { rtx new_mem; new_mem = adjust_address (mem, mode, offset); if (load_p) emit_move_insn (reg, new_mem); else emit_move_insn (new_mem, reg); }
/* Generate code for transformation 2 (with MODE and OPERATION, operands OP1 and OP2, result TARGET and probability of taking the optimal path PROB). */ static rtx gen_mod_pow2 (enum machine_mode mode, enum rtx_code operation, rtx target, rtx op1, rtx op2, int prob) { rtx tmp, tmp1, tmp2, tmp3, jump; rtx neq_label = gen_label_rtx (); rtx end_label = gen_label_rtx (); rtx sequence; start_sequence (); if (!REG_P (op2)) { tmp = gen_reg_rtx (mode); emit_move_insn (tmp, copy_rtx (op2)); } else tmp = op2; tmp1 = expand_simple_binop (mode, PLUS, tmp, constm1_rtx, NULL_RTX, 0, OPTAB_WIDEN); tmp2 = expand_simple_binop (mode, AND, tmp, tmp1, NULL_RTX, 0, OPTAB_WIDEN); do_compare_rtx_and_jump (tmp2, const0_rtx, NE, 0, mode, NULL_RTX, NULL_RTX, neq_label); /* Add branch probability to jump we just created. */ jump = get_last_insn (); REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (REG_BR_PROB_BASE - prob), REG_NOTES (jump)); tmp3 = expand_simple_binop (mode, AND, op1, tmp1, target, 0, OPTAB_WIDEN); if (tmp3 != target) emit_move_insn (copy_rtx (target), tmp3); emit_jump_insn (gen_jump (end_label)); emit_barrier (); emit_label (neq_label); tmp1 = simplify_gen_binary (operation, mode, copy_rtx (op1), copy_rtx (tmp)); tmp1 = force_operand (tmp1, target); if (tmp1 != target) emit_move_insn (target, tmp1); emit_label (end_label); sequence = get_insns (); end_sequence (); rebuild_jump_labels (sequence); return sequence; }
/* Generate code for transformation 1 (with MODE and OPERATION, operands OP1 and OP2, whose value is expected to be VALUE, result TARGET and probability of taking the optimal path PROB). */ static rtx gen_divmod_fixed_value (enum machine_mode mode, enum rtx_code operation, rtx target, rtx op1, rtx op2, gcov_type value, int prob) { rtx tmp, tmp1, jump; rtx neq_label = gen_label_rtx (); rtx end_label = gen_label_rtx (); rtx sequence; start_sequence (); if (!REG_P (op2)) { tmp = gen_reg_rtx (mode); emit_move_insn (tmp, copy_rtx (op2)); } else tmp = op2; do_compare_rtx_and_jump (tmp, GEN_INT (value), NE, 0, mode, NULL_RTX, NULL_RTX, neq_label); /* Add branch probability to jump we just created. */ jump = get_last_insn (); REG_NOTES (jump) = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (REG_BR_PROB_BASE - prob), REG_NOTES (jump)); tmp1 = simplify_gen_binary (operation, mode, copy_rtx (op1), GEN_INT (value)); tmp1 = force_operand (tmp1, target); if (tmp1 != target) emit_move_insn (copy_rtx (target), copy_rtx (tmp1)); emit_jump_insn (gen_jump (end_label)); emit_barrier (); emit_label (neq_label); tmp1 = simplify_gen_binary (operation, mode, copy_rtx (op1), copy_rtx (tmp)); tmp1 = force_operand (tmp1, target); if (tmp1 != target) emit_move_insn (copy_rtx (target), copy_rtx (tmp1)); emit_label (end_label); sequence = get_insns (); end_sequence (); rebuild_jump_labels (sequence); return sequence; }
static void moxie_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) { rtx mem, fnaddr = XEXP (DECL_RTL (fndecl), 0); emit_block_move (m_tramp, assemble_trampoline_template (), GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); mem = adjust_address (m_tramp, SImode, 4); emit_move_insn (mem, chain_value); mem = adjust_address (m_tramp, SImode, 16); emit_move_insn (mem, fnaddr); }
static void lm32_block_move_inline (rtx dest, rtx src, HOST_WIDE_INT length, HOST_WIDE_INT alignment) { HOST_WIDE_INT offset, delta; unsigned HOST_WIDE_INT bits; int i; enum machine_mode mode; rtx *regs; /* Work out how many bits to move at a time. */ switch (alignment) { case 1: bits = 8; break; case 2: bits = 16; break; case 4: bits = 32; break; default: abort (); } mode = mode_for_size (bits, MODE_INT, 0); delta = bits / BITS_PER_UNIT; /* Allocate a buffer for the temporary registers. */ regs = alloca (sizeof (rtx) * length / delta); /* Load as many BITS-sized chunks as possible. */ for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++) { regs[i] = gen_reg_rtx (mode); emit_move_insn (regs[i], adjust_address (src, mode, offset)); } /* Copy the chunks to the destination. */ for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++) emit_move_insn (adjust_address (dest, mode, offset), regs[i]); /* Mop up any left-over bytes. */ if (offset < length) { src = adjust_address (src, BLKmode, offset); dest = adjust_address (dest, BLKmode, offset); move_by_pieces (dest, src, length - offset, MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0); } }
static void stack_adjust (HOST_WIDE_INT amount) { rtx insn; if (!IN_RANGE (amount, -32776, 32768)) { /* r10 is caller saved so it can be used as a temp reg. */ rtx r10; r10 = gen_rtx_REG (word_mode, 10); insn = emit_move_insn (r10, GEN_INT (amount)); if (amount < 0) RTX_FRAME_RELATED_P (insn) = 1; insn = emit_add (stack_pointer_rtx, stack_pointer_rtx, r10); if (amount < 0) RTX_FRAME_RELATED_P (insn) = 1; } else { insn = emit_add (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (amount)); if (amount < 0) RTX_FRAME_RELATED_P (insn) = 1; } }
void crx_expand_epilogue (void) { rtx return_reg; /* Nonzero if we need to return and pop only RA. This will generate a * different insn. This differentiate is for the peepholes for call as last * statement in function. */ int only_popret_RA = (save_regs[RETURN_ADDRESS_REGNUM] && (sum_regs == UNITS_PER_WORD)); /* Return register. */ return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM); if (frame_pointer_needed) /* Restore the stack pointer with the frame pointers value */ emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); if (size_for_adjusting_sp > 0) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (size_for_adjusting_sp))); if (crx_interrupt_function_p ()) emit_jump_insn (gen_interrupt_return ()); else if (last_reg_to_save == -1) /* Nothing to pop */ /* Don't output jump for interrupt routine, only retx. */ emit_jump_insn (gen_indirect_jump_return ()); else if (only_popret_RA) emit_jump_insn (gen_popret_RA_return ()); else emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs))); }
static void moxie_setup_incoming_varargs (cumulative_args_t cum_v, machine_mode mode ATTRIBUTE_UNUSED, tree type ATTRIBUTE_UNUSED, int *pretend_size, int no_rtl) { CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v); int regno; int regs = 8 - *cum; *pretend_size = regs < 0 ? 0 : GET_MODE_SIZE (SImode) * regs; if (no_rtl) return; for (regno = *cum; regno < 8; regno++) { rtx reg = gen_rtx_REG (SImode, regno); rtx slot = gen_rtx_PLUS (Pmode, gen_rtx_REG (SImode, ARG_POINTER_REGNUM), GEN_INT (UNITS_PER_WORD * (3 + (regno-2)))); emit_move_insn (gen_rtx_MEM (SImode, slot), reg); } }
static rtx emit_setmem_doubleword_loop (rtx itr, rtx size, rtx value) { rtx word_mode_label = gen_label_rtx (); rtx word_mode_end_label = gen_label_rtx (); rtx byte_mode_size = gen_reg_rtx (SImode); rtx byte_mode_size_tmp = gen_reg_rtx (SImode); rtx word_mode_end = gen_reg_rtx (SImode); rtx size_for_word = gen_reg_rtx (SImode); /* and $size_for_word, $size, #~0x7 */ size_for_word = expand_binop (SImode, and_optab, size, gen_int_mode (~0x7, SImode), NULL_RTX, 0, OPTAB_WIDEN); emit_move_insn (byte_mode_size, size); /* beqz $size_for_word, .Lbyte_mode_entry */ emit_cmp_and_jump_insns (size_for_word, const0_rtx, EQ, NULL, SImode, 1, word_mode_end_label); /* add $word_mode_end, $dst, $size_for_word */ word_mode_end = expand_binop (Pmode, add_optab, itr, size_for_word, NULL_RTX, 0, OPTAB_WIDEN); /* andi $byte_mode_size, $size, 0x7 */ byte_mode_size_tmp = expand_binop (SImode, and_optab, size, GEN_INT (0x7), NULL_RTX, 0, OPTAB_WIDEN); emit_move_insn (byte_mode_size, byte_mode_size_tmp); /* .Lword_mode: */ emit_label (word_mode_label); /* ! word-mode set loop smw.bim $value4word, [$dst_itr], $value4word, 0 bne $word_mode_end, $dst_itr, .Lword_mode */ emit_insn (gen_unaligned_store_update_base_dw (itr, itr, value)); emit_cmp_and_jump_insns (word_mode_end, itr, NE, NULL, Pmode, 1, word_mode_label); emit_label (word_mode_end_label); return byte_mode_size; }
static rtx nds32_gen_dup_4_byte_to_word_value_aux (rtx value, rtx value4word) { gcc_assert (GET_MODE (value) == QImode || CONST_INT_P (value)); if (CONST_INT_P (value)) { unsigned HOST_WIDE_INT val = UINTVAL (value) & GET_MODE_MASK(QImode); rtx new_val = gen_int_mode (val | (val << 8) | (val << 16) | (val << 24), SImode); /* Just calculate at here if it's constant value. */ emit_move_insn (value4word, new_val); } else { if (NDS32_EXT_DSP_P ()) { /* ! prepare word insb $tmp, $value, 1 ! $tmp <- 0x0000abab pkbb16 $tmp6, $tmp2, $tmp2 ! $value4word <- 0xabababab */ rtx tmp = gen_reg_rtx (SImode); convert_move (tmp, value, true); emit_insn ( gen_insvsi_internal (tmp, gen_int_mode (0x8, SImode), tmp)); emit_insn (gen_pkbbsi_1 (value4word, tmp, tmp)); } else { /* ! prepare word andi $tmp1, $value, 0xff ! $tmp1 <- 0x000000ab slli $tmp2, $tmp1, 8 ! $tmp2 <- 0x0000ab00 or $tmp3, $tmp1, $tmp2 ! $tmp3 <- 0x0000abab slli $tmp4, $tmp3, 16 ! $tmp4 <- 0xabab0000 or $val4word, $tmp3, $tmp4 ! $value4word <- 0xabababab */ rtx tmp1, tmp2, tmp3, tmp4; tmp1 = expand_binop (SImode, and_optab, value, gen_int_mode (0xff, SImode), NULL_RTX, 0, OPTAB_WIDEN); tmp2 = expand_binop (SImode, ashl_optab, tmp1, gen_int_mode (8, SImode), NULL_RTX, 0, OPTAB_WIDEN); tmp3 = expand_binop (SImode, ior_optab, tmp1, tmp2, NULL_RTX, 0, OPTAB_WIDEN); tmp4 = expand_binop (SImode, ashl_optab, tmp3, gen_int_mode (16, SImode), NULL_RTX, 0, OPTAB_WIDEN); emit_insn (gen_iorsi3 (value4word, tmp3, tmp4)); } } return value4word; }
void crx_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase, rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p) { rtx addr, mem; unsigned HOST_WIDE_INT offset = *offset_p; /* Load */ addr = plus_constant (src, offset); mem = adjust_automodify_address (srcbase, SImode, addr, offset); emit_move_insn (tmp_reg, mem); /* Store */ addr = plus_constant (dst, offset); mem = adjust_automodify_address (dstbase, SImode, addr, offset); emit_move_insn (mem, tmp_reg); *offset_p = offset + 4; }
static void insert_value_copy_on_edge (edge e, int dest, tree src, source_location locus) { rtx seq, x; enum machine_mode dest_mode, src_mode; int unsignedp; tree var; if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Inserting a value copy on edge BB%d->BB%d : PART.%d = ", e->src->index, e->dest->index, dest); print_generic_expr (dump_file, src, TDF_SLIM); fprintf (dump_file, "\n"); } gcc_assert (SA.partition_to_pseudo[dest]); set_location_for_edge (e); /* If a locus is provided, override the default. */ if (locus) set_curr_insn_source_location (locus); start_sequence (); var = SSA_NAME_VAR (partition_to_var (SA.map, dest)); src_mode = TYPE_MODE (TREE_TYPE (src)); dest_mode = GET_MODE (SA.partition_to_pseudo[dest]); gcc_assert (src_mode == TYPE_MODE (TREE_TYPE (var))); gcc_assert (!REG_P (SA.partition_to_pseudo[dest]) || dest_mode == promote_decl_mode (var, &unsignedp)); if (src_mode != dest_mode) { x = expand_expr (src, NULL, src_mode, EXPAND_NORMAL); x = convert_modes (dest_mode, src_mode, x, unsignedp); } else if (src_mode == BLKmode) { x = SA.partition_to_pseudo[dest]; store_expr (src, x, 0, false); } else x = expand_expr (src, SA.partition_to_pseudo[dest], dest_mode, EXPAND_NORMAL); if (x != SA.partition_to_pseudo[dest]) emit_move_insn (SA.partition_to_pseudo[dest], x); seq = get_insns (); end_sequence (); insert_insn_on_edge (seq, e); }
static rtx nds32_gen_dup_8_byte_to_double_word_value (rtx value) { rtx value4doubleword = gen_reg_rtx (DImode); nds32_gen_dup_4_byte_to_word_value_aux ( value, nds32_di_low_part_subreg(value4doubleword)); emit_move_insn (nds32_di_high_part_subreg(value4doubleword), nds32_di_low_part_subreg(value4doubleword)); return value4doubleword; }
static rtx insert_move_insn_before (rtx next_insn, rtx dest_reg, rtx src_reg) { rtx insns; start_sequence (); emit_move_insn (dest_reg, src_reg); insns = get_insns (); end_sequence (); emit_insn_before (insns, next_insn); return insns; }
static void nds32_emit_post_inc_load_store (rtx reg, rtx base_reg, enum machine_mode mode, bool load_p) { gcc_assert (GET_MODE (reg) == mode); gcc_assert (GET_MODE (base_reg) == Pmode); /* Do not gen (set (reg) (mem (post_inc (reg)))) directly here since it may not recognize by gcc, so let gcc combine it at auto_inc_dec pass. */ if (load_p) emit_move_insn (reg, gen_rtx_MEM (mode, base_reg)); else emit_move_insn (gen_rtx_MEM (mode, base_reg), reg); emit_move_insn (base_reg, plus_constant(Pmode, base_reg, GET_MODE_SIZE (mode))); }
/* Generate and emit RTL to save or restore callee save registers */ static void expand_save_restore (struct lm32_frame_info *info, int op) { unsigned int reg_save_mask = info->reg_save_mask; int regno; HOST_WIDE_INT offset; rtx insn; /* Callee saves are below locals and above outgoing arguments */ offset = info->args_size + info->callee_size; for (regno = 0; regno <= 31; regno++) { if ((reg_save_mask & (1 << regno)) != 0) { if (op == 0) { insn = emit_move_insn (gen_rtx_MEM (word_mode, gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset))), gen_rtx_REG (word_mode, regno)); } else { insn = emit_move_insn (gen_rtx_REG (word_mode, regno), gen_rtx_MEM (word_mode, gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)))); } /* only prologue instructions which set the sp fp or save a register should be marked as frame related */ if (op==0) RTX_FRAME_RELATED_P (insn) = 1; offset -= UNITS_PER_WORD; } } }
void moxie_expand_prologue (void) { int regno; rtx insn; moxie_compute_frame (); if (flag_stack_usage_info) current_function_static_stack_size = cfun->machine->size_for_adjusting_sp; /* Save callee-saved registers. */ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) { if (!fixed_regs[regno] && df_regs_ever_live_p (regno) && !call_used_regs[regno]) { insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno))); RTX_FRAME_RELATED_P (insn) = 1; } } if (cfun->machine->size_for_adjusting_sp > 0) { int i = cfun->machine->size_for_adjusting_sp; while ((i >= 255) && (i <= 510)) { insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (255))); RTX_FRAME_RELATED_P (insn) = 1; i -= 255; } if (i <= 255) { insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (i))); RTX_FRAME_RELATED_P (insn) = 1; } else { rtx reg = gen_rtx_REG (SImode, MOXIE_R12); insn = emit_move_insn (reg, GEN_INT (i)); RTX_FRAME_RELATED_P (insn) = 1; insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, reg)); RTX_FRAME_RELATED_P (insn) = 1; } } }
static void expand_BUILTIN_EXPECT (gimple stmt) { /* When guessing was done, the hints should be already stripped away. */ gcc_assert (!flag_guess_branch_prob || optimize == 0 || seen_error ()); rtx target; tree lhs = gimple_call_lhs (stmt); if (lhs) target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE); else target = const0_rtx; rtx val = expand_expr (gimple_call_arg (stmt, 0), target, VOIDmode, EXPAND_NORMAL); if (lhs && val != target) emit_move_insn (target, val); }
static void do_jump_by_parts_zero_rtx (enum machine_mode mode, rtx op0, rtx if_false_label, rtx if_true_label) { int nwords = GET_MODE_SIZE (mode) / UNITS_PER_WORD; rtx part; int i; rtx drop_through_label = 0; /* The fastest way of doing this comparison on almost any machine is to "or" all the words and compare the result. If all have to be loaded from memory and this is a very wide item, it's possible this may be slower, but that's highly unlikely. */ part = gen_reg_rtx (word_mode); emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0))); for (i = 1; i < nwords && part != 0; i++) part = expand_binop (word_mode, ior_optab, part, operand_subword_force (op0, i, GET_MODE (op0)), part, 1, OPTAB_WIDEN); if (part != 0) { do_compare_rtx_and_jump (part, const0_rtx, EQ, 1, word_mode, NULL_RTX, if_false_label, if_true_label); return; } /* If we couldn't do the "or" simply, do this with a series of compares. */ if (! if_false_label) drop_through_label = if_false_label = gen_label_rtx (); for (i = 0; i < nwords; i++) do_compare_rtx_and_jump (operand_subword_force (op0, i, GET_MODE (op0)), const0_rtx, EQ, 1, word_mode, NULL_RTX, if_false_label, NULL_RTX); if (if_true_label) emit_jump (if_true_label); if (drop_through_label) emit_label (drop_through_label); }
void c54x_expand_prologue() { int r; for(r = 0; r < FIRST_PSEUDO_REGISTER; r++) { if(c54x_save_register_p(r)) { emit_insn(gen_pushqi(gen_rtx_REG(QImode, r))); } } if(frame_pointer_needed) { emit_move_insn(gen_rtx_REG (QImode, FRAME_POINTER_REGNUM), gen_rtx_REG (QImode, STACK_POINTER_REGNUM)); } emit_insn(gen_frame(gen_rtx_REG (QImode, STACK_POINTER_REGNUM), gen_rtx_CONST_INT(VOIDmode, get_frame_size()))); }
unsigned int emit_initial_value_sets (void) { struct initial_value_struct *ivs = crtl->hard_reg_initial_vals; int i; rtx seq; if (ivs == 0) return 0; start_sequence (); for (i = 0; i < ivs->num_entries; i++) emit_move_insn (ivs->entries[i].pseudo, ivs->entries[i].hard_reg); seq = get_insns (); end_sequence (); emit_insn_at_entry (seq); return 0; }
static inline rtx emit_partition_copy (rtx dest, rtx src, int unsignedsrcp, tree sizeexp) { rtx seq; start_sequence (); if (GET_MODE (src) != VOIDmode && GET_MODE (src) != GET_MODE (dest)) src = convert_to_mode (GET_MODE (dest), src, unsignedsrcp); if (GET_MODE (src) == BLKmode) { gcc_assert (GET_MODE (dest) == BLKmode); emit_block_move (dest, src, expr_size (sizeexp), BLOCK_OP_NORMAL); } else emit_move_insn (dest, src); seq = get_insns (); end_sequence (); return seq; }
void crx_expand_prologue (void) { crx_compute_frame (); crx_compute_save_regs (); /* If there is no need in push and adjustment to sp, return. */ if (size_for_adjusting_sp + sum_regs == 0) return; if (last_reg_to_save != -1) /* If there are registers to push. */ emit_insn (gen_push_for_prologue (GEN_INT (sum_regs))); if (size_for_adjusting_sp > 0) emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size_for_adjusting_sp))); if (frame_pointer_needed) /* Initialize the frame pointer with the value of the stack pointer * pointing now to the locals. */ emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); }
/* Create and emit instructions for a functions prologue. */ void lm32_expand_prologue (void) { rtx insn; lm32_compute_frame_size (get_frame_size ()); if (current_frame_info.total_size > 0) { /* Add space on stack new frame. */ stack_adjust (-current_frame_info.total_size); /* Save callee save registers. */ if (current_frame_info.reg_save_mask != 0) expand_save_restore (¤t_frame_info, 0); /* Setup frame pointer if it's needed. */ if (frame_pointer_needed == 1) { /* Move sp to fp. */ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; /* Add offset - Don't use total_size, as that includes pretend_size, which isn't part of this frame? */ insn = emit_add (frame_pointer_rtx, frame_pointer_rtx, GEN_INT (current_frame_info.args_size + current_frame_info.callee_size + current_frame_info.locals_size)); RTX_FRAME_RELATED_P (insn) = 1; } /* Prevent prologue from being scheduled into function body. */ emit_insn (gen_blockage ()); } }
static void gen_int_relational (enum rtx_code code, rtx result, rtx cmp0, rtx cmp1, rtx destination) { machine_mode mode; int branch_p; mode = GET_MODE (cmp0); if (mode == VOIDmode) mode = GET_MODE (cmp1); /* Is this a branch or compare. */ branch_p = (destination != 0); /* Instruction set doesn't support LE or LT, so swap operands and use GE, GT. */ switch (code) { case LE: case LT: case LEU: case LTU: { rtx temp; code = swap_condition (code); temp = cmp0; cmp0 = cmp1; cmp1 = temp; break; } default: break; } if (branch_p) { rtx insn, cond, label; /* Operands must be in registers. */ if (!register_operand (cmp0, mode)) cmp0 = force_reg (mode, cmp0); if (!register_operand (cmp1, mode)) cmp1 = force_reg (mode, cmp1); /* Generate conditional branch instruction. */ cond = gen_rtx_fmt_ee (code, mode, cmp0, cmp1); label = gen_rtx_LABEL_REF (VOIDmode, destination); insn = gen_rtx_SET (pc_rtx, gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label, pc_rtx)); emit_jump_insn (insn); } else { /* We can't have const_ints in cmp0, other than 0. */ if ((GET_CODE (cmp0) == CONST_INT) && (INTVAL (cmp0) != 0)) cmp0 = force_reg (mode, cmp0); /* If the comparison is against an int not in legal range move it into a register. */ if (GET_CODE (cmp1) == CONST_INT) { switch (code) { case EQ: case NE: case LE: case LT: case GE: case GT: if (!satisfies_constraint_K (cmp1)) cmp1 = force_reg (mode, cmp1); break; case LEU: case LTU: case GEU: case GTU: if (!satisfies_constraint_L (cmp1)) cmp1 = force_reg (mode, cmp1); break; default: gcc_unreachable (); } } /* Generate compare instruction. */ emit_move_insn (result, gen_rtx_fmt_ee (code, mode, cmp0, cmp1)); } }