📄 ia64.c
字号:
{ start_sequence (); if (! CONST_OK_FOR_I (disp)) { rtx tmp = gen_rtx_REG (DImode, next_scratch_gr_reg ()); emit_move_insn (tmp, disp_rtx); disp_rtx = tmp; } emit_insn (gen_adddi3 (spill_fill_data.iter_reg[iter], spill_fill_data.init_reg[iter], disp_rtx)); seq = gen_sequence (); end_sequence (); } /* Careful for being the first insn in a sequence. */ if (spill_fill_data.init_after) insn = emit_insn_after (seq, spill_fill_data.init_after); else { rtx first = get_insns (); if (first) insn = emit_insn_before (seq, first); else insn = emit_insn (seq); } spill_fill_data.init_after = insn; /* If DISP is 0, we may or may not have a further adjustment afterward. If we do, then the load/store insn may be modified to be a post-modify. If we don't, then this copy may be eliminated by copyprop_hardreg_forward, which makes this insn garbage, which runs afoul of the sanity check in propagate_one_insn. So mark this insn as legal to delete. */ if (disp == 0) REG_NOTES(insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, const0_rtx, REG_NOTES (insn)); } mem = gen_rtx_MEM (GET_MODE (reg), spill_fill_data.iter_reg[iter]); /* ??? Not all of the spills are for varargs, but some of them are. The rest of the spills belong in an alias set of their own. But it doesn't actually hurt to include them here. */ set_mem_alias_set (mem, get_varargs_alias_set ()); spill_fill_data.prev_addr[iter] = &XEXP (mem, 0); spill_fill_data.prev_off[iter] = cfa_off; if (++iter >= spill_fill_data.n_iter) iter = 0; spill_fill_data.next_iter = iter; return mem;}static voiddo_spill (move_fn, reg, cfa_off, frame_reg) rtx (*move_fn) PARAMS ((rtx, rtx, rtx)); rtx reg, frame_reg; HOST_WIDE_INT cfa_off;{ int iter = spill_fill_data.next_iter; rtx mem, insn; mem = spill_restore_mem (reg, cfa_off); insn = emit_insn ((*move_fn) (mem, reg, GEN_INT (cfa_off))); spill_fill_data.prev_insn[iter] = insn; if (frame_reg) { rtx base; HOST_WIDE_INT off; RTX_FRAME_RELATED_P (insn) = 1; /* Don't even pretend that the unwind code can intuit its way through a pair of interleaved post_modify iterators. Just provide the correct answer. */ if (frame_pointer_needed) { base = hard_frame_pointer_rtx; off = - cfa_off; } else { base = stack_pointer_rtx; off = current_frame_info.total_size - cfa_off; } REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, gen_rtx_MEM (GET_MODE (reg), plus_constant (base, off)), frame_reg), REG_NOTES (insn)); }}static voiddo_restore (move_fn, reg, cfa_off) rtx (*move_fn) PARAMS ((rtx, rtx, rtx)); rtx reg; HOST_WIDE_INT cfa_off;{ int iter = spill_fill_data.next_iter; rtx insn; insn = emit_insn ((*move_fn) (reg, spill_restore_mem (reg, cfa_off), GEN_INT (cfa_off))); spill_fill_data.prev_insn[iter] = insn;}/* Wrapper functions that discards the CONST_INT spill offset. These exist so that we can give gr_spill/gr_fill the offset they need and use a consistant function interface. */static rtxgen_movdi_x (dest, src, offset) rtx dest, src; rtx offset ATTRIBUTE_UNUSED;{ return gen_movdi (dest, src);}static rtxgen_fr_spill_x (dest, src, offset) rtx dest, src; rtx offset ATTRIBUTE_UNUSED;{ return gen_fr_spill (dest, src);}static rtxgen_fr_restore_x (dest, src, offset) rtx dest, src; rtx offset ATTRIBUTE_UNUSED;{ return gen_fr_restore (dest, src);}/* Called after register allocation to add any instructions needed for the prologue. Using a prologue insn is favored compared to putting all of the instructions in output_function_prologue(), since it allows the scheduler to intermix instructions with the saves of the caller saved registers. In some cases, it might be necessary to emit a barrier instruction as the last insn to prevent such scheduling. Also any insns generated here should have RTX_FRAME_RELATED_P(insn) = 1 so that the debug info generation code can handle them properly. The register save area is layed out like so: cfa+16 [ varargs spill area ] [ fr register spill area ] [ br register spill area ] [ ar register spill area ] [ pr register spill area ] [ gr register spill area ] *//* ??? Get inefficient code when the frame size is larger than can fit in an adds instruction. */voidia64_expand_prologue (){ rtx insn, ar_pfs_save_reg, ar_unat_save_reg; int i, epilogue_p, regno, alt_regno, cfa_off, n_varargs; rtx reg, alt_reg; ia64_compute_frame_size (get_frame_size ()); last_scratch_gr_reg = 15; /* If there is no epilogue, then we don't need some prologue insns. We need to avoid emitting the dead prologue insns, because flow will complain about them. */ if (optimize) { edge e; for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next) if ((e->flags & EDGE_FAKE) == 0 && (e->flags & EDGE_FALLTHRU) != 0) break; epilogue_p = (e != NULL); } else epilogue_p = 1; /* Set the local, input, and output register names. We need to do this for GNU libc, which creates crti.S/crtn.S by splitting initfini.c in half. If we use in/loc/out register names, then we get assembler errors in crtn.S because there is no alloc insn or regstk directive in there. */ if (! TARGET_REG_NAMES) { int inputs = current_frame_info.n_input_regs; int locals = current_frame_info.n_local_regs; int outputs = current_frame_info.n_output_regs; for (i = 0; i < inputs; i++) reg_names[IN_REG (i)] = ia64_reg_numbers[i]; for (i = 0; i < locals; i++) reg_names[LOC_REG (i)] = ia64_reg_numbers[inputs + i]; for (i = 0; i < outputs; i++) reg_names[OUT_REG (i)] = ia64_reg_numbers[inputs + locals + i]; } /* Set the frame pointer register name. The regnum is logically loc79, but of course we'll not have allocated that many locals. Rather than worrying about renumbering the existing rtxs, we adjust the name. */ /* ??? This code means that we can never use one local register when there is a frame pointer. loc79 gets wasted in this case, as it is renamed to a register that will never be used. See also the try_locals code in find_gr_spill. */ if (current_frame_info.reg_fp) { const char *tmp = reg_names[HARD_FRAME_POINTER_REGNUM]; reg_names[HARD_FRAME_POINTER_REGNUM] = reg_names[current_frame_info.reg_fp]; reg_names[current_frame_info.reg_fp] = tmp; } /* Fix up the return address placeholder. */ /* ??? We can fail if __builtin_return_address is used, and we didn't allocate a register in which to save b0. I can't think of a way to eliminate RETURN_ADDRESS_POINTER_REGNUM to a local register and then be sure that I got the right one. Further, reload doesn't seem to care if an eliminable register isn't used, and "eliminates" it anyway. */ if (regs_ever_live[RETURN_ADDRESS_POINTER_REGNUM] && current_frame_info.reg_save_b0 != 0) XINT (return_address_pointer_rtx, 0) = current_frame_info.reg_save_b0; /* We don't need an alloc instruction if we've used no outputs or locals. */ if (current_frame_info.n_local_regs == 0 && current_frame_info.n_output_regs == 0 && current_frame_info.n_input_regs <= current_function_args_info.int_regs) { /* If there is no alloc, but there are input registers used, then we need a .regstk directive. */ current_frame_info.need_regstk = (TARGET_REG_NAMES != 0); ar_pfs_save_reg = NULL_RTX; } else { current_frame_info.need_regstk = 0; if (current_frame_info.reg_save_ar_pfs) regno = current_frame_info.reg_save_ar_pfs; else regno = next_scratch_gr_reg (); ar_pfs_save_reg = gen_rtx_REG (DImode, regno); insn = emit_insn (gen_alloc (ar_pfs_save_reg, GEN_INT (current_frame_info.n_input_regs), GEN_INT (current_frame_info.n_local_regs), GEN_INT (current_frame_info.n_output_regs), GEN_INT (current_frame_info.n_rotate_regs))); RTX_FRAME_RELATED_P (insn) = (current_frame_info.reg_save_ar_pfs != 0); } /* Set up frame pointer, stack pointer, and spill iterators. */ n_varargs = cfun->machine->n_varargs; setup_spill_pointers (current_frame_info.n_spilled + n_varargs, stack_pointer_rtx, 0); if (frame_pointer_needed) { insn = emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); RTX_FRAME_RELATED_P (insn) = 1; } if (current_frame_info.total_size != 0) { rtx frame_size_rtx = GEN_INT (- current_frame_info.total_size); rtx offset; if (CONST_OK_FOR_I (- current_frame_info.total_size)) offset = frame_size_rtx; else { regno = next_scratch_gr_reg (); offset = gen_rtx_REG (DImode, regno); emit_move_insn (offset, frame_size_rtx); } insn = emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, offset)); if (! frame_pointer_needed) { RTX_FRAME_RELATED_P (insn) = 1; if (GET_CODE (offset) != CONST_INT) { REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, stack_pointer_rtx, gen_rtx_PLUS (DImode, stack_pointer_rtx, frame_size_rtx)), REG_NOTES (insn)); } } /* ??? At this point we must generate a magic insn that appears to modify the stack pointer, the frame pointer, and all spill iterators. This would allow the most scheduling freedom. For now, just hard stop. */ emit_insn (gen_blockage ()); } /* Must copy out ar.unat before doing any integer spills. */ if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM)) { if (current_frame_info.reg_save_ar_unat) ar_unat_save_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_unat); else { alt_regno = next_scratch_gr_reg (); ar_unat_save_reg = gen_rtx_REG (DImode, alt_regno); current_frame_info.gr_used_mask |= 1 << alt_regno; } reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); insn = emit_move_insn (ar_unat_save_reg, reg); RTX_FRAME_RELATED_P (insn) = (current_frame_info.reg_save_ar_unat != 0); /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ if (! epilogue_p && current_frame_info.reg_save_ar_unat) emit_insn (gen_prologue_use (ar_unat_save_reg)); } else ar_unat_save_reg = NULL_RTX; /* Spill all varargs registers. Do this before spilling any GR registers, since we want the UNAT bits for the GR registers to override the UNAT bits from varargs, which we don't care about. */ cfa_off = -16; for (regno = GR_ARG_FIRST + 7; n_varargs > 0; --n_varargs, --regno) { reg = gen_rtx_REG (DImode, regno); do_spill (gen_gr_spill, reg, cfa_off += 8, NULL_RTX); } /* Locate the bottom of the register save area. */ cfa_off = (current_frame_info.spill_cfa_off + current_frame_info.spill_size + current_frame_info.extra_spill_size); /* Save the predicate register block either in a register or in memory. */ if (TEST_HARD_REG_BIT (current_frame_info.mask, PR_REG (0))) { reg = gen_rtx_REG (DImode, PR_REG (0)); if (current_frame_info.reg_save_pr != 0) { alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_pr); insn = emit_move_insn (alt_reg, reg); /* ??? Denote pr spill/fill by a DImode move that modifies all 64 hard registers. */ RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, gen_rtx_SET (VOIDmode, alt_reg, reg), REG_NOTES (insn)); /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ if (! epilogue_p) emit_insn (gen_prologue_use (alt_reg)); } else { alt_regno = next_scratch_gr_reg (); alt_reg = gen_rtx_REG (DImode, alt_regno); insn = emit_move_insn (alt_reg, reg); do_spill (gen_movdi_x, alt_reg, cfa_off, reg); cfa_off -= 8; } } /* Handle AR regs in numerical order. All of them get special handling. */ if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_UNAT_REGNUM) && current_frame_info.reg_save_ar_unat == 0) { reg = gen_rtx_REG (DImode, AR_UNAT_REGNUM); do_spill (gen_movdi_x, ar_unat_save_reg, cfa_off, reg); cfa_off -= 8; } /* The alloc insn already copied ar.pfs into a general register. The only thing we have to do now is copy that register to a stack slot if we'd not allocated a local register for the job. */ if (current_frame_info.reg_save_ar_pfs == 0 && ! current_function_is_leaf) { reg = gen_rtx_REG (DImode, AR_PFS_REGNUM); do_spill (gen_movdi_x, ar_pfs_save_reg, cfa_off, reg); cfa_off -= 8; } if (TEST_HARD_REG_BIT (current_frame_info.mask, AR_LC_REGNUM)) { reg = gen_rtx_REG (DImode, AR_LC_REGNUM); if (current_frame_info.reg_save_ar_lc != 0) { alt_reg = gen_rtx_REG (DImode, current_frame_info.reg_save_ar_lc); insn = emit_move_insn (alt_reg, reg); RTX_FRAME_RELATED_P (insn) = 1; /* Even if we're not going to generate an epilogue, we still need to save the register so that EH works. */ if (! epilogue_p) emit_insn (gen_prologue_use (alt_reg)); } else { alt_regno = next_scratch_gr_reg (); alt_reg = gen_rtx_REG (DImode, alt_regno); emit_move_insn (alt_reg, reg); do_spill (gen_movdi_x, alt_reg, cfa_off, reg); cfa_off -= 8; } } /* We should now be at the base of the gr/br/fr spill area. */ if (cfa_off != (current_frame_info.spill_cfa_off + current_frame_info.spill_size)) abort (); /* Spill all general registers. */ for (regno = GR_REG (1); regno <= GR_REG (31); ++regno) if (TEST_HARD_REG_BIT (curre
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -