📄 sparc.c
字号:
case CCXmode : case CCFPEmode : case CCFPmode : break; default : abort (); } emit_insn (gen_rtx (SET, VOIDmode, operands[0], const0_rtx)); emit_insn (gen_rtx (SET, VOIDmode, operands[0], gen_rtx (IF_THEN_ELSE, VOIDmode, gen_rtx (compare_code, GET_MODE (operands[1]), operands[1], const0_rtx), const1_rtx, operands[0]))); return 1; }}/* Emit a conditional jump insn for the v9 architecture using comparison code CODE and jump target LABEL. This function exists to take advantage of the v9 brxx insns. */voidemit_v9_brxx_insn (code, op0, label) enum rtx_code code; rtx op0, label;{ emit_jump_insn (gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (IF_THEN_ELSE, VOIDmode, gen_rtx (code, GET_MODE (op0), op0, const0_rtx), gen_rtx (LABEL_REF, VOIDmode, label), pc_rtx)));}/* Return nonzero if a return peephole merging return with setting of output register is ok. */intleaf_return_peephole_ok (){ return (actual_fsize == 0);}/* Return nonzero if TRIAL can go into the function epilogue's delay slot. SLOT is the slot we are trying to fill. */inteligible_for_epilogue_delay (trial, slot) rtx trial; int slot;{ rtx pat, src; if (slot >= 1) return 0; if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) return 0; if (get_attr_length (trial) != 1) return 0; /* In the case of a true leaf function, anything can go into the delay slot. A delay slot only exists however if the frame size is zero, otherwise we will put an insn to adjust the stack after the return. */ if (leaf_function) { if (leaf_return_peephole_ok ()) return (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE); return 0; } /* Otherwise, only operations which can be done in tandem with a `restore' insn can go into the delay slot. */ pat = PATTERN (trial); if (GET_CODE (SET_DEST (pat)) != REG || REGNO (SET_DEST (pat)) == 0 || REGNO (SET_DEST (pat)) >= 32 || REGNO (SET_DEST (pat)) < 24) return 0; src = SET_SRC (pat); if (arith_operand (src, GET_MODE (src))) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode); if (arith_double_operand (src, GET_MODE (src))) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); if (GET_CODE (src) == PLUS) { if (register_operand (XEXP (src, 0), SImode) && arith_operand (XEXP (src, 1), SImode)) return 1; if (register_operand (XEXP (src, 1), SImode) && arith_operand (XEXP (src, 0), SImode)) return 1; if (register_operand (XEXP (src, 0), DImode) && arith_double_operand (XEXP (src, 1), DImode)) return 1; if (register_operand (XEXP (src, 1), DImode) && arith_double_operand (XEXP (src, 0), DImode)) return 1; } if (GET_CODE (src) == MINUS && register_operand (XEXP (src, 0), SImode) && small_int (XEXP (src, 1), VOIDmode)) return 1; if (GET_CODE (src) == MINUS && register_operand (XEXP (src, 0), DImode) && !register_operand (XEXP (src, 1), DImode) && arith_double_operand (XEXP (src, 1), DImode)) return 1; return 0;}intshort_branch (uid1, uid2) int uid1, uid2;{ unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2]; if (delta + 1024 < 2048) return 1; /* warning ("long branch, distance %d", delta); */ return 0;}/* Return non-zero if REG is not used after INSN. We assume REG is a reload reg, and therefore does not live past labels or calls or jumps. */intreg_unused_after (reg, insn) rtx reg; rtx insn;{ enum rtx_code code, prev_code = UNKNOWN; while (insn = NEXT_INSN (insn)) { if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)]) return 1; code = GET_CODE (insn); if (GET_CODE (insn) == CODE_LABEL) return 1; if (GET_RTX_CLASS (code) == 'i') { rtx set = single_set (insn); int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set)); if (set && in_src) return 0; if (set && reg_overlap_mentioned_p (reg, SET_DEST (set))) return 1; if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn))) return 0; } prev_code = code; } return 1;}/* The rtx for the global offset table which is a special form that *is* a position independent symbolic constant. */static rtx pic_pc_rtx;/* Ensure that we are not using patterns that are not OK with PIC. */intcheck_pic (i) int i;{ switch (flag_pic) { case 1: if (GET_CODE (recog_operand[i]) == SYMBOL_REF || (GET_CODE (recog_operand[i]) == CONST && ! rtx_equal_p (pic_pc_rtx, recog_operand[i]))) abort (); case 2: default: return 1; }}/* Return true if X is an address which needs a temporary register when reloaded while generating PIC code. */intpic_address_needs_scratch (x) rtx x;{ /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && ! SMALL_INT (XEXP (XEXP (x, 0), 1))) return 1; return 0;}/* Legitimize PIC addresses. If the address is already position-independent, we return ORIG. Newly generated position-independent addresses go into a reg. This is REG if non zero, otherwise we allocate register(s) as necessary. */rtxlegitimize_pic_address (orig, mode, reg) rtx orig; enum machine_mode mode; rtx reg;{ if (GET_CODE (orig) == SYMBOL_REF) { rtx pic_ref, address; rtx insn; if (reg == 0) { if (reload_in_progress || reload_completed) abort (); else reg = gen_reg_rtx (Pmode); } if (flag_pic == 2) { /* If not during reload, allocate another temp reg here for loading in the address, so that these instructions can be optimized properly. */ rtx temp_reg = ((reload_in_progress || reload_completed) ? reg : gen_reg_rtx (Pmode)); /* Must put the SYMBOL_REF inside an UNSPEC here so that cse won't get confused into thinking that these two instructions are loading in the true address of the symbol. If in the future a PIC rtx exists, that should be used instead. */ emit_insn (gen_rtx (SET, VOIDmode, temp_reg, gen_rtx (HIGH, Pmode, gen_rtx (UNSPEC, Pmode, gen_rtvec (1, orig), 0)))); emit_insn (gen_rtx (SET, VOIDmode, temp_reg, gen_rtx (LO_SUM, Pmode, temp_reg, gen_rtx (UNSPEC, Pmode, gen_rtvec (1, orig), 0)))); address = temp_reg; } else address = orig; pic_ref = gen_rtx (MEM, Pmode, gen_rtx (PLUS, Pmode, pic_offset_table_rtx, address)); current_function_uses_pic_offset_table = 1; RTX_UNCHANGING_P (pic_ref) = 1; insn = emit_move_insn (reg, pic_ref); /* Put a REG_EQUAL note on this insn, so that it can be optimized by loop. */ REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, orig, REG_NOTES (insn)); return reg; } else if (GET_CODE (orig) == CONST) { rtx base, offset; if (GET_CODE (XEXP (orig, 0)) == PLUS && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) return orig; if (reg == 0) { if (reload_in_progress || reload_completed) abort (); else reg = gen_reg_rtx (Pmode); } if (GET_CODE (XEXP (orig, 0)) == PLUS) { base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, base == reg ? 0 : reg); } else abort (); if (GET_CODE (offset) == CONST_INT) { if (SMALL_INT (offset)) return plus_constant_for_output (base, INTVAL (offset)); else if (! reload_in_progress && ! reload_completed) offset = force_reg (Pmode, offset); else /* If we reach here, then something is seriously wrong. */ abort (); } return gen_rtx (PLUS, Pmode, base, offset); } else if (GET_CODE (orig) == LABEL_REF) current_function_uses_pic_offset_table = 1; return orig;}/* Set up PIC-specific rtl. This should not cause any insns to be emitted. */voidinitialize_pic (){}/* Emit special PIC prologues and epilogues. */voidfinalize_pic (){ /* The table we use to reference PIC data. */ rtx global_offset_table; /* Labels to get the PC in the prologue of this function. */ rtx l1, l2; rtx seq; int orig_flag_pic = flag_pic; if (current_function_uses_pic_offset_table == 0) return; if (! flag_pic) abort (); flag_pic = 0; l1 = gen_label_rtx (); l2 = gen_label_rtx (); start_sequence (); emit_label (l1); /* Note that we pun calls and jumps here! */ emit_jump_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, pc_rtx, gen_rtx (LABEL_REF, VOIDmode, l2)), gen_rtx (SET, VOIDmode, gen_rtx (REG, SImode, 15), gen_rtx (LABEL_REF, VOIDmode, l2))))); emit_label (l2); /* Initialize every time through, since we can't easily know this to be permanent. */ global_offset_table = gen_rtx (SYMBOL_REF, Pmode, "_GLOBAL_OFFSET_TABLE_"); pic_pc_rtx = gen_rtx (CONST, Pmode, gen_rtx (MINUS, Pmode, global_offset_table, gen_rtx (CONST, Pmode, gen_rtx (MINUS, Pmode, gen_rtx (LABEL_REF, VOIDmode, l1), pc_rtx)))); if (Pmode == DImode) emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, pic_offset_table_rtx, gen_rtx (HIGH, Pmode, pic_pc_rtx)), gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, Pmode, 1))))); else emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx, gen_rtx (HIGH, Pmode, pic_pc_rtx))); emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx, gen_rtx (LO_SUM, Pmode, pic_offset_table_rtx, pic_pc_rtx))); emit_insn (gen_rtx (SET, VOIDmode, pic_offset_table_rtx, gen_rtx (PLUS, Pmode, pic_offset_table_rtx, gen_rtx (REG, Pmode, 15)))); /* emit_insn (gen_rtx (ASM_INPUT, VOIDmode, "!#PROLOGUE# 1")); */ LABEL_PRESERVE_P (l1) = 1; LABEL_PRESERVE_P (l2) = 1; flag_pic = orig_flag_pic; seq = gen_sequence (); end_sequence (); emit_insn_after (seq, get_insns ()); /* Need to emit this whether or not we obey regdecls, since setjmp/longjmp can cause life info to screw up. */ emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx));}/* Emit insns to move operands[1] into operands[0]. Return 1 if we have written out everything that needs to be done to do the move. Otherwise, return 0 and the caller will emit the move normally. */intemit_move_sequence (operands, mode) rtx *operands; enum machine_mode mode;{ register rtx operand0 = operands[0]; register rtx operand1 = operands[1]; if (CONSTANT_P (operand1) && flag_pic && pic_address_needs_scratch (operand1)) operands[1] = operand1 = legitimize_pic_address (operand1, mode, 0); /* Handle most common case first: storing into a register. */ if (register_operand (operand0, mode)) { if (register_operand (operand1, mode) || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1)) || (GET_CODE (operand1) == CONST_DOUBLE && arith_double_operand (operand1, DImode)) || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode) /* Only `general_operands' can come here, so MEM is ok. */ || GET_CODE (operand1) == MEM) { /* Run this case quickly. */ emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); return 1; } } else if (GET_CODE (operand0) == MEM) { if (register_operand (operand1, mode) || operand1 == const0_rtx) { /* Run this case quickly. */ emit_insn (gen_rtx (SET, VOIDmode, operand0, operand1)); return 1; } if (! reload_in_progress) { operands[0] = validize_mem (operand0); operands[1] = operand1 = force_reg (mode, operand1); } } /* Simplify the source if we need to. Must handle DImode HIGH operators here because such a move needs a clobber added. */ if ((GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode)) || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode)) { if (flag_pic && symbolic_operand (operand1, mode)) { rtx temp_reg = reload_in_progress ? operand0 : 0; operands[1] = legitimize_pic_address (operand1, mode, temp_reg); } else if (GET_CODE (operand1) == CONST_INT ? (! SMALL_INT (operand1) && (INTVAL (operand1) & 0x3ff) != 0) : (GET_CODE (operand1) == CONST_DOUBLE ? ! arith_double_operand (operand1, DImode) : 1)) { /* For DImode values, temp must be operand0 because of the way HI and LO_SUM work. The LO_SUM operator only copies half of the LSW from the dest of the HI operator. If the LO_SUM dest is
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -