📄 rs6000.c
字号:
return 1;}/* Return 1 if OP is a comparison operation that is valid for a branch insn. We only check the opcode against the mode of the CC value here. */intbranch_comparison_operator (op, mode) register rtx op; enum machine_mode mode;{ enum rtx_code code = GET_CODE (op); enum machine_mode cc_mode; if (GET_RTX_CLASS (code) != '<') return 0; cc_mode = GET_MODE (XEXP (op, 0)); if (GET_MODE_CLASS (cc_mode) != MODE_CC) return 0; if ((code == GT || code == LT || code == GE || code == LE) && cc_mode == CCUNSmode) return 0; if ((code == GTU || code == LTU || code == GEU || code == LEU) && (cc_mode != CCUNSmode)) return 0; return 1;}/* Return 1 if OP is a comparison operation that is valid for an scc insn. We check the opcode against the mode of the CC value and disallow EQ or NE comparisons for integers. */intscc_comparison_operator (op, mode) register rtx op; enum machine_mode mode;{ enum rtx_code code = GET_CODE (op); enum machine_mode cc_mode; if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_RTX_CLASS (code) != '<') return 0; cc_mode = GET_MODE (XEXP (op, 0)); if (GET_MODE_CLASS (cc_mode) != MODE_CC) return 0; if (code == NE && cc_mode != CCFPmode) return 0; if ((code == GT || code == LT || code == GE || code == LE) && cc_mode == CCUNSmode) return 0; if ((code == GTU || code == LTU || code == GEU || code == LEU) && (cc_mode != CCUNSmode)) return 0; if (cc_mode == CCEQmode && code != EQ && code != NE) return 0; return 1;}/* Return 1 if ANDOP is a mask that has no bits on that are not in the mask required to convert the result of a rotate insn into a shift left insn of SHIFTOP bits. Both are known to be CONST_INT. */intincludes_lshift_p (shiftop, andop) register rtx shiftop; register rtx andop;{ int shift_mask = (~0 << INTVAL (shiftop)); return (INTVAL (andop) & ~shift_mask) == 0;}/* Similar, but for right shift. */intincludes_rshift_p (shiftop, andop) register rtx shiftop; register rtx andop;{ unsigned HOST_WIDE_INT shift_mask = ~(unsigned HOST_WIDE_INT) 0; shift_mask >>= INTVAL (shiftop); return (INTVAL (andop) & ~ shift_mask) == 0;}/* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates for lfq and stfq insns. Note reg1 and reg2 *must* be hard registers. To be sure we will abort if we are passed pseudo registers. */intregisters_ok_for_quad_peep (reg1, reg2) rtx reg1, reg2;{ /* We might have been passed a SUBREG. */ if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) return 0; return (REGNO (reg1) == REGNO (reg2) - 1);}/* Return 1 if addr1 and addr2 are suitable for lfq or stfq insn. addr1 and addr2 must be in consecutive memory locations (addr2 == addr1 + 8). */intaddrs_ok_for_quad_peep (addr1, addr2) register rtx addr1; register rtx addr2;{ int reg1; int offset1; /* Extract an offset (if used) from the first addr. */ if (GET_CODE (addr1) == PLUS) { /* If not a REG, return zero. */ if (GET_CODE (XEXP (addr1, 0)) != REG) return 0; else { reg1 = REGNO (XEXP (addr1, 0)); /* The offset must be constant! */ if (GET_CODE (XEXP (addr1, 1)) != CONST_INT) return 0; offset1 = INTVAL (XEXP (addr1, 1)); } } else if (GET_CODE (addr1) != REG) return 0; else { reg1 = REGNO (addr1); /* This was a simple (mem (reg)) expression. Offset is 0. */ offset1 = 0; } /* Make sure the second address is a (mem (plus (reg) (const_int). */ if (GET_CODE (addr2) != PLUS) return 0; if (GET_CODE (XEXP (addr2, 0)) != REG || GET_CODE (XEXP (addr2, 1)) != CONST_INT) return 0; if (reg1 != REGNO (XEXP (addr2, 0))) return 0; /* The offset for the second addr must be 8 more than the first addr. */ if (INTVAL (XEXP (addr2, 1)) != offset1 + 8) return 0; /* All the tests passed. addr1 and addr2 are valid for lfq or stfq instructions. */ return 1;}/* Return the register class of a scratch register needed to copy IN into or out of a register in CLASS in MODE. If it can be done directly, NO_REGS is returned. */enum reg_classsecondary_reload_class (class, mode, in) enum reg_class class; enum machine_mode mode; rtx in;{ int regno = true_regnum (in); if (regno >= FIRST_PSEUDO_REGISTER) regno = -1; /* We can place anything into GENERAL_REGS and can put GENERAL_REGS into anything. */ if (class == GENERAL_REGS || class == BASE_REGS || (regno >= 0 && INT_REGNO_P (regno))) return NO_REGS; /* Constants, memory, and FP registers can go into FP registers. */ if ((regno == -1 || FP_REGNO_P (regno)) && (class == FLOAT_REGS || class == NON_SPECIAL_REGS)) return NO_REGS; /* We can copy among the CR registers. */ if ((class == CR_REGS || class == CR0_REGS) && regno >= 0 && CR_REGNO_P (regno)) return NO_REGS; /* Otherwise, we need GENERAL_REGS. */ return GENERAL_REGS;}/* Given a comparison operation, return the bit number in CCR to test. We know this is a valid comparison. SCC_P is 1 if this is for an scc. That means that %D will have been used instead of %C, so the bits will be in different places. Return -1 if OP isn't a valid comparison for some reason. */intccr_bit (op, scc_p) register rtx op; int scc_p;{ enum rtx_code code = GET_CODE (op); enum machine_mode cc_mode; int cc_regnum; int base_bit; if (GET_RTX_CLASS (code) != '<') return -1; cc_mode = GET_MODE (XEXP (op, 0)); cc_regnum = REGNO (XEXP (op, 0)); base_bit = 4 * (cc_regnum - 68); /* In CCEQmode cases we have made sure that the result is always in the third bit of the CR field. */ if (cc_mode == CCEQmode) return base_bit + 3; switch (code) { case NE: return scc_p ? base_bit + 3 : base_bit + 2; case EQ: return base_bit + 2; case GT: case GTU: return base_bit + 1; case LT: case LTU: return base_bit; case GE: case GEU: /* If floating-point, we will have done a cror to put the bit in the unordered position. So test that bit. For integer, this is ! LT unless this is an scc insn. */ return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit; case LE: case LEU: return cc_mode == CCFPmode || scc_p ? base_bit + 3 : base_bit + 1; default: abort (); }}/* Return the GOT register, creating it if needed. */struct rtx_def *rs6000_got_register (value) rtx value;{ if (!current_function_uses_pic_offset_table || !pic_offset_table_rtx) { if (reload_in_progress || reload_completed) fatal_insn ("internal error -- needed new GOT register during reload phase to load:", value); current_function_uses_pic_offset_table = 1; pic_offset_table_rtx = gen_rtx (REG, Pmode, GOT_TOC_REGNUM); } return pic_offset_table_rtx;}/* Replace all occurrences of register FROM with an new pseudo register in an insn X. Store the pseudo register used in REG. This is only safe during FINALIZE_PIC, since the registers haven't been setup yet. */static rtxrs6000_replace_regno (x, from, reg) rtx x; int from; rtx *reg;{ register int i, j; register char *fmt; /* Allow this function to make replacements in EXPR_LISTs. */ if (!x) return x; switch (GET_CODE (x)) { case SCRATCH: case PC: case CC0: case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: return x; case REG: if (REGNO (x) == from) { if (! *reg) *reg = pic_offset_table_rtx = gen_reg_rtx (Pmode); return *reg; } return x; } fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { if (fmt[i] == 'e') XEXP (x, i) = rs6000_replace_regno (XEXP (x, i), from, reg); else if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) XVECEXP (x, i, j) = rs6000_replace_regno (XVECEXP (x, i, j), from, reg); } return x;} /* By generating position-independent code, when two different programs (A and B) share a common library (libC.a), the text of the library can be shared whether or not the library is linked at the same address for both programs. In some of these environments, position-independent code requires not only the use of different addressing modes, but also special code to enable the use of these addressing modes. The `FINALIZE_PIC' macro serves as a hook to emit these special codes once the function is being compiled into assembly code, but not before. (It is not done before, because in the case of compiling an inline function, it would lead to multiple PIC prologues being included in functions which used inline functions and were compiled to assembly language.) */voidrs6000_finalize_pic (){ /* Loop through all of the insns, replacing the special GOT_TOC_REGNUM with an appropriate pseudo register. If we find we need GOT/TOC, add the appropriate init code. */ if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)) { rtx insn = get_insns (); rtx reg = NULL_RTX; rtx first_insn; rtx last_insn = NULL_RTX; if (GET_CODE (insn) == NOTE) insn = next_nonnote_insn (insn); first_insn = insn; for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn)) { if (GET_RTX_CLASS (GET_CODE (insn)) == 'i') { PATTERN (insn) = rs6000_replace_regno (PATTERN (insn), GOT_TOC_REGNUM, ®); if (REG_NOTES (insn)) REG_NOTES (insn) = rs6000_replace_regno (REG_NOTES (insn), GOT_TOC_REGNUM, ®); } if (GET_CODE (insn) != NOTE) last_insn = insn; } if (reg) { rtx init = gen_init_v4_pic (reg); emit_insn_before (init, first_insn); if (!optimize && last_insn) emit_insn_after (gen_rtx (USE, VOIDmode, reg), last_insn); } }}/* Search for any occurrence of the GOT_TOC register marker that should have been eliminated, but may have crept back in. */voidrs6000_reorg (insn) rtx insn;{ if (flag_pic && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)) { rtx got_reg = gen_rtx (REG, Pmode, GOT_TOC_REGNUM); for ( ; insn != NULL_RTX; insn = NEXT_INSN (insn)) if (GET_RTX_CLASS (GET_CODE (insn)) == 'i' && reg_mentioned_p (got_reg, PATTERN (insn))) fatal_insn ("GOT/TOC register marker not removed:", PATTERN (insn)); }}/* Define the structure for the machine field in struct function. */struct machine_function{ int sysv_varargs_p; int save_toc_p; int fpmem_size; int fpmem_offset; rtx pic_offset_table_rtx;};/* Functions to save and restore rs6000_fpmem_size. These will be called, via pointer variables, from push_function_context and pop_function_context. */voidrs6000_save_machine_status (p) struct function *p;{ struct machine_function *machine = (struct machine_function *) xmalloc (sizeof (struct machine_function)); p->machine = machine; machine->sysv_varargs_p = rs6000_sysv_varargs_p; machine->fpmem_size = rs6000_fpmem_size; machine->fpmem_offset = rs6000_fpmem_offset; machine->pic_offset_table_rtx = pic_offset_table_rtx;}voidrs6000_restore_machine_status (p) struct function *p;{ struct machine_function *machine = p->machine; rs6000_sysv_varargs_p = machine->sysv_varargs_p; rs6000_fpmem_size = machine->fpmem_size; rs6000_fpmem_offset = machine->fpmem_offset; pic_offset_table_rtx = machine->pic_offset_table_rtx; free (machine); p->machine = (struct machine_function *)0;}/* Do anything needed before RTL is emitted for each function. */voidrs6000_init_expanders (){ /* Reset varargs and save TOC indicator */ rs6000_sysv_varargs_p = 0; rs6000_fpmem_size = 0; rs6000_fpmem_offset = 0; pic_offset_table_rtx = (rtx)0; /* Arrange to save and restore machine status aro
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -