📄 rs6000.c
字号:
if (count <= 1 || GET_CODE (XVECEXP (op, 0, 0)) != SET || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG) return 0; src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0))); dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0); for (i = 1; i < count; i++) { rtx elt = XVECEXP (op, 0, i + 1); if (GET_CODE (elt) != SET || GET_CODE (SET_SRC (elt)) != REG || GET_MODE (SET_SRC (elt)) != SImode || REGNO (SET_SRC (elt)) != src_regno + i || GET_CODE (SET_DEST (elt)) != MEM || GET_MODE (SET_DEST (elt)) != SImode || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr) || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4) return 0; } 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 shift_mask = ~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 (); }}/* Print an operand. Recognize special options, documented below. */voidprint_operand (file, x, code) FILE *file; rtx x; char code;{ int i; int val; /* These macros test for integers and extract the low-order bits. */#define INT_P(X) \((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE) \ && GET_MODE (X) == VOIDmode)#define INT_LOWPART(X) \ (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X)) switch (code) { case '.': /* Write out an instruction after the call which may be replaced with glue code by the loader. This depends on the AIX version. */ asm_fprintf (file, RS6000_CALL_GLUE); return; case '*': /* Write the register number of the TOC register. */ fputs (TARGET_MINIMAL_TOC ? reg_names[30] : reg_names[2], file); return; case 'A': /* If X is a constant integer whose low-order 5 bits are zero, write 'l'. Otherwise, write 'r'. This is a kludge to fix a bug in the AIX assembler where "sri" with a zero shift count write a trash instruction. */ if (GET_CODE (x) == CONST_INT && (INTVAL (x) & 31) == 0) putc ('l', file); else putc ('r', file); return; case 'b': /* Low-order 16 bits of constant, unsigned. */ if (! INT_P (x)) output_operand_lossage ("invalid %%b value"); fprintf (file, "%d", INT_LOWPART (x) & 0xffff); return; case 'C': /* This is an optional cror needed for LE or GE floating-point comparisons. Otherwise write nothing. */ if ((GET_CODE (x) == LE || GET_CODE (x) == GE) && GET_MODE (XEXP (x, 0)) == CCFPmode) { int base_bit = 4 * (REGNO (XEXP (x, 0)) - 68); fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3, base_bit + 2, base_bit + (GET_CODE (x) == GE)); } return; case 'D': /* Similar, except that this is for an scc, so we must be able to encode the test in a single bit that is one. We do the above for any LE, GE, GEU, or LEU and invert the bit for NE. */ if (GET_CODE (x) == LE || GET_CODE (x) == GE || GET_CODE (x) == LEU || GET_CODE (x) == GEU) { int base_bit = 4 * (REGNO (XEXP (x, 0)) - 68); fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3, base_bit + 2, base_bit + (GET_CODE (x) == GE || GET_CODE (x) == GEU)); } else if (GET_CODE (x) == NE) { int base_bit = 4 * (REGNO (XEXP (x, 0)) - 68); fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 3, base_bit + 2, base_bit + 2); } return; case 'E': /* X is a CR register. Print the number of the third bit of the CR */ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) output_operand_lossage ("invalid %%E value"); fprintf(file, "%d", 4 * (REGNO (x) - 68) + 3); return; case 'f': /* X is a CR register. Print the shift count needed to move it to the high-order four bits. */ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) output_operand_lossage ("invalid %%f value"); else fprintf (file, "%d", 4 * (REGNO (x) - 68)); return; case 'F': /* Similar, but print the count for the rotate in the opposite direction. */ if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x))) output_operand_lossage ("invalid %%F value"); else fprintf (file, "%d", 32 - 4 * (REGNO (x) - 68)); return; case 'G': /* X is a constant integer. If it is negative, print "m", otherwise print "z". This is to make a aze or ame insn. */ if (GET_CODE (x) != CONST_INT) output_operand_lossage ("invalid %%G value"); else if (INTVAL (x) >= 0) putc ('z', file); else putc ('m', file); return; case 'h': /* If constant, output low-order five bits. Otherwise, write normally. */ if (INT_P (x)) fprintf (file, "%d", INT_LOWPART (x) & 31); else print_operand (file, x, 0); return; case 'I': /* Print `i' if this is a constant, else nothing. */ if (INT_P (x)) putc ('i', file); return; case 'j': /* Write the bit number in CCR for jump. */ i = ccr_bit (x, 0); if (i == -1) output_operand_lossage ("invalid %%j code"); else fprintf (file, "%d", i); return; case 'J': /* Similar, but add one for shift count in rlinm for scc and pass scc flag to `ccr_bit'. */ i = ccr_bit (x, 1); if (i == -1) output_operand_lossage ("invalid %%J code"); else /* If we want bit 31, write a shift count of zero, not 32. */ fprintf (file, "%d", i == 31 ? 0 : i + 1); return; case 'k': /* X must be a constant. Write the 1's complement of the constant. */ if (! INT_P (x)) output_operand_lossage ("invalid %%k value"); fprintf (file, "%d", ~ INT_LOWPART (x)); return; case 'L': /* Write second word of DImode or DFmode reference. Works on register or non-indexed memory only. */ if (GET_CODE (x) == REG) fprintf (file, "%d", REGNO (x) + 1); else if (GET_CODE (x) == MEM) { /* Handle possible auto-increment. Since it is pre-increment and we have already done it, we can just use an offset of four. */ if (GET_CODE (XEXP (x, 0)) == PRE_INC || GET_CODE (XEXP (x, 0)) == PRE_DEC) output_address (plus_constant (XEXP (XEXP (x, 0), 0), 4)); else output_address (plus_constant (XEXP (x, 0), 4)); } return; case 'm': /* MB value for a mask operand. */ if (! mask_operand (x, VOIDmode)) output_operand_lossage ("invalid %%m value"); val = INT_LOWPART (x);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -