📄 i960.c
字号:
are 4. Indexed addresses are cost 6. *//* ??? Try using just RTX_COST, i.e. not defining ADDRESS_COST. */inti960_address_cost (x) rtx x;{#if 0 /* Handled before calling here. */ if (GET_CODE (x) == REG) return 1;#endif /* This is a MEMA operand -- it's free. */ if (GET_CODE (x) == CONST_INT && INTVAL (x) >= 0 && INTVAL (x) < 4096) return 0; if (GET_CODE (x) == PLUS) { rtx base = XEXP (x, 0); rtx offset = XEXP (x, 1); if (GET_CODE (base) == SUBREG) base = SUBREG_REG (base); if (GET_CODE (offset) == SUBREG) offset = SUBREG_REG (offset); if (GET_CODE (base) == REG) { if (GET_CODE (offset) == REG) return 2; if (GET_CODE (offset) == CONST_INT) { if ((unsigned)INTVAL (offset) < 2047) return 2; return 4; } if (CONSTANT_P (offset)) return 4; } if (GET_CODE (base) == PLUS || GET_CODE (base) == MULT) return 6; /* This is an invalid address. The return value doesn't matter, but for convenience we make this more expensive than anything else. */ return 12; } if (GET_CODE (x) == MULT) return 6; /* Symbol_refs and other unrecognized addresses are cost 4. */ return 4;}/* 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;{ /* We can only store registers to memory. */ if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) != REG && (operands[1] != const0_rtx || current_function_args_size || current_function_varargs || current_function_stdarg || rtx_equal_function_value_matters)) /* Here we use the same test as movsi+1 pattern -- see i960.md. */ operands[1] = force_reg (mode, operands[1]); /* Storing multi-word values in unaligned hard registers to memory may require a scratch since we have to store them a register at a time and adding 4 to the memory address may not yield a valid insn. */ /* ??? We don't always need the scratch, but that would complicate things. Maybe later. */ /* ??? We must also handle stores to pseudos here, because the pseudo may be replaced with a MEM later. This would be cleaner if we didn't have a separate pattern for unaligned DImode/TImode stores. */ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD && (GET_CODE (operands[0]) == MEM || (GET_CODE (operands[0]) == REG && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)) && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && ! HARD_REGNO_MODE_OK (REGNO (operands[1]), mode)) { emit_insn (gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2, gen_rtx (SET, VOIDmode, operands[0], operands[1]), gen_rtx (CLOBBER, VOIDmode, gen_rtx (SCRATCH, Pmode))))); return 1; } return 0;}/* Output assembler to move a double word value. */char *i960_output_move_double (dst, src) rtx dst, src;{ rtx operands[5]; if (GET_CODE (dst) == REG && GET_CODE (src) == REG) { if ((REGNO (src) & 1) || (REGNO (dst) & 1)) { /* We normally copy the low-numbered register first. However, if the second source register is the same as the first destination register, we must copy in the opposite order. */ if (REGNO (src) + 1 == REGNO (dst)) return "mov %D1,%D0\n\tmov %1,%0"; else return "mov %1,%0\n\tmov %D1,%D0"; } else return "movl %1,%0"; } else if (GET_CODE (dst) == REG && GET_CODE (src) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (src), 'I')) { if (REGNO (dst) & 1) return "mov %1,%0\n\tmov 0,%D0"; else return "movl %1,%0"; } else if (GET_CODE (dst) == REG && GET_CODE (src) == MEM) { if (REGNO (dst) & 1) { /* One can optimize a few cases here, but you have to be careful of clobbering registers used in the address and edge conditions. */ operands[0] = dst; operands[1] = src; operands[2] = gen_rtx (REG, Pmode, REGNO (dst) + 1); operands[3] = gen_rtx (MEM, word_mode, operands[2]); operands[4] = adj_offsettable_operand (operands[3], UNITS_PER_WORD); output_asm_insn ("lda %1,%2\n\tld %3,%0\n\tld %4,%D0", operands); return ""; } else return "ldl %1,%0"; } else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG) { if (REGNO (src) & 1) { operands[0] = dst; operands[1] = adj_offsettable_operand (dst, UNITS_PER_WORD); if (! memory_address_p (word_mode, XEXP (operands[1], 0))) abort (); operands[2] = src; output_asm_insn ("st %2,%0\n\tst %D2,%1", operands); return ""; } return "stl %1,%0"; } else abort ();}/* Output assembler to move a double word zero. */char *i960_output_move_double_zero (dst) rtx dst;{ rtx operands[2]; operands[0] = dst; { operands[1] = adj_offsettable_operand (dst, 4); output_asm_insn ("st g14,%0\n\tst g14,%1", operands); } return "";}/* Output assembler to move a quad word value. */char *i960_output_move_quad (dst, src) rtx dst, src;{ rtx operands[7]; if (GET_CODE (dst) == REG && GET_CODE (src) == REG) { if ((REGNO (src) & 3) || (REGNO (dst) & 3)) { /* We normally copy starting with the low numbered register. However, if there is an overlap such that the first dest reg is <= the last source reg but not < the first source reg, we must copy in the opposite order. */ if (REGNO (dst) <= REGNO (src) + 3 && REGNO (dst) >= REGNO (src)) return "mov %F1,%F0\n\tmov %E1,%E0\n\tmov %D1,%D0\n\tmov %1,%0"; else return "mov %1,%0\n\tmov %D1,%D0\n\tmov %E1,%E0\n\tmov %F1,%F0"; } else return "movq %1,%0"; } else if (GET_CODE (dst) == REG && GET_CODE (src) == CONST_INT && CONST_OK_FOR_LETTER_P (INTVAL (src), 'I')) { if (REGNO (dst) & 3) return "mov %1,%0\n\tmov 0,%D0\n\tmov 0,%E0\n\tmov 0,%F0"; else return "movq %1,%0"; } else if (GET_CODE (dst) == REG && GET_CODE (src) == MEM) { if (REGNO (dst) & 3) { /* One can optimize a few cases here, but you have to be careful of clobbering registers used in the address and edge conditions. */ operands[0] = dst; operands[1] = src; operands[2] = gen_rtx (REG, Pmode, REGNO (dst) + 3); operands[3] = gen_rtx (MEM, word_mode, operands[2]); operands[4] = adj_offsettable_operand (operands[3], UNITS_PER_WORD); operands[5] = adj_offsettable_operand (operands[4], UNITS_PER_WORD); operands[6] = adj_offsettable_operand (operands[5], UNITS_PER_WORD); output_asm_insn ("lda %1,%2\n\tld %3,%0\n\tld %4,%D0\n\tld %5,%E0\n\tld %6,%F0", operands); return ""; } else return "ldq %1,%0"; } else if (GET_CODE (dst) == MEM && GET_CODE (src) == REG) { if (REGNO (src) & 3) { operands[0] = dst; operands[1] = adj_offsettable_operand (dst, UNITS_PER_WORD); operands[2] = adj_offsettable_operand (dst, 2*UNITS_PER_WORD); operands[3] = adj_offsettable_operand (dst, 3*UNITS_PER_WORD); if (! memory_address_p (word_mode, XEXP (operands[3], 0))) abort (); operands[4] = src; output_asm_insn ("st %4,%0\n\tst %D4,%1\n\tst %E4,%2\n\tst %F4,%3", operands); return ""; } return "stq %1,%0"; } else abort ();}/* Output assembler to move a quad word zero. */char *i960_output_move_quad_zero (dst) rtx dst;{ rtx operands[4]; operands[0] = dst; { operands[1] = adj_offsettable_operand (dst, 4); operands[2] = adj_offsettable_operand (dst, 8); operands[3] = adj_offsettable_operand (dst, 12); output_asm_insn ("st g14,%0\n\tst g14,%1\n\tst g14,%2\n\tst g14,%3", operands); } return "";}/* Emit insns to load a constant to non-floating point registers. Uses several strategies to try to use as few insns as possible. */char *i960_output_ldconst (dst, src) register rtx dst, src;{ register int rsrc1; register unsigned rsrc2; enum machine_mode mode = GET_MODE (dst); rtx operands[4]; operands[0] = operands[2] = dst; operands[1] = operands[3] = src; /* Anything that isn't a compile time constant, such as a SYMBOL_REF, must be a ldconst insn. */ if (GET_CODE (src) != CONST_INT && GET_CODE (src) != CONST_DOUBLE) { output_asm_insn ("ldconst %1,%0", operands); return ""; } else if (mode == XFmode) { REAL_VALUE_TYPE d; long value_long[3]; int i; if (fp_literal_zero (src, XFmode)) return "movt 0,%0"; REAL_VALUE_FROM_CONST_DOUBLE (d, src); REAL_VALUE_TO_TARGET_LONG_DOUBLE (d, value_long); output_asm_insn ("# ldconst %1,%0",operands); for (i = 0; i < 3; i++) { operands[0] = gen_rtx (REG, SImode, REGNO (dst) + i); operands[1] = GEN_INT (value_long[i]); output_asm_insn (i960_output_ldconst (operands[0], operands[1]), operands); } return ""; } else if (mode == DFmode) { rtx first, second; if (fp_literal_zero (src, DFmode)) return "movl 0,%0"; split_double (src, &first, &second); output_asm_insn ("# ldconst %1,%0",operands); operands[0] = gen_rtx (REG, SImode, REGNO (dst)); operands[1] = first; output_asm_insn (i960_output_ldconst (operands[0], operands[1]), operands); operands[0] = gen_rtx (REG, SImode, REGNO (dst) + 1); operands[1] = second; output_asm_insn (i960_output_ldconst (operands[0], operands[1]), operands); return ""; } else if (mode == SFmode) { REAL_VALUE_TYPE d; long value; REAL_VALUE_FROM_CONST_DOUBLE (d, src); REAL_VALUE_TO_TARGET_SINGLE (d, value); output_asm_insn ("# ldconst %1,%0",operands); operands[0] = gen_rtx (REG, SImode, REGNO (dst)); operands[1] = GEN_INT (value); output_asm_insn (i960_output_ldconst (operands[0], operands[1]), operands); return ""; } else if (mode == TImode) { /* ??? This is currently not handled at all. */ abort (); /* Note: lowest order word goes in lowest numbered reg. */ rsrc1 = INTVAL (src); if (rsrc1 >= 0 && rsrc1 < 32) return "movq %1,%0"; else output_asm_insn ("movq\t0,%0\t# ldconstq %1,%0",operands); /* Go pick up the low-order word. */ } else if (mode == DImode) { rtx upperhalf, lowerhalf, xoperands[2]; if (GET_CODE (src) == CONST_DOUBLE || GET_CODE (src) == CONST_INT) split_double (src, &lowerhalf, &upperhalf); else abort (); /* Note: lowest order word goes in lowest numbered reg. */ /* Numbers from 0 to 31 can be handled with a single insn. */ rsrc1 = INTVAL (lowerhalf); if (upperhalf == const0_rtx && rsrc1 >= 0 && rsrc1 < 32) return "movl %1,%0"; /* Output the upper half with a recursive call. */ xoperands[0] = gen_rtx (REG, SImode, REGNO (dst) + 1); xoperands[1] = upperhalf; output_asm_insn (i960_output_ldconst (xoperands[0], xoperands[1]), xoperands); /* The lower word is emitted as normally. */ } else { rsrc1 = INTVAL (src); if (mode == QImode) { if (rsrc1 > 0xff) rsrc1 &= 0xff; } else if (mode == HImode) { if (rsrc1 > 0xffff) rsrc1 &= 0xffff; } } if (rsrc1 >= 0) { /* ldconst 0..31,X -> mov 0..31,X */ if (rsrc1 < 32) { if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) return "lda %1,%0"; return "mov %1,%0"; } /* ldconst 32..63,X -> add 31,nn,X */ if (rsrc1 < 63) { if (i960_last_insn_type == I_TYPE_REG && TARGET_C_SERIES) return "lda %1,%0"; operands[1] = GEN_INT (rsrc1 - 31); output_asm_insn ("addo\t31,%1,%0\t# ldconst %3,%0", operands); return ""; } } else if (rsrc1 < 0) { /* ldconst -1..-31 -> sub 0,0..31,X */ if (rsrc1 >= -31) { /* return 'sub -(%1),0,%0' */ operands[1] = GEN_INT (- rsrc1); output_asm_insn ("subo\t%1,0,%0\t# ldconst %3,%0", operands); return ""; } /* ldconst -32 -> not 31,X */ if (rsrc1 == -32) { operands[1] = GEN_INT (~rsrc1); output_asm_insn ("not\t%1,%0 # ldconst %3,%0", operands); return ""; } } /* If const is a single bit. */ if (bitpos (rsrc1) >= 0) { operands[1] = GEN_INT (bitpos (rsrc1)); output_asm_insn ("setbit\t%1,0,%0\t# ldconst %3,%0", operands); return ""; } /* If const is a bit string of less than 6 bits (1..31 shifted). */ if (is_mask (rsrc1)) { int s, e; if (bitstr (rsrc1, &s, &e) < 6) { rsrc2 = ((unsigned int) rsrc1) >> s; operands[1] = GEN_INT (rsrc2); operands[2] = GEN_INT (s); output_asm_insn ("shlo\t%2,%1,%0\t# ldconst %3,%0", operands); return ""; } } /* Unimplemented cases: const is in range 0..31 but rotated around end of word: ror 31,3,g0 -> ldconst 0xe0000003,g0 and any 2 instruction cases that might be worthwhile */ output_asm_insn ("ldconst %1,%0", operands); return "";}/* Determine if there is an opportunity for a bypass optimization. Bypass succeeds on the 960K* if the destination of the previous instruction is the second operand of the current instruction. Bypass always succeeds on the C*. Return 1 if the pattern should interchange the operands. CMPBR_FLAG is true if this is for a compare-and-branch insn. OP1 and OP2 are the two source operands of a 3 operand insn. */inti960_bypass (insn, op1, op2, cmpbr_flag) register rtx insn, op1, op2; int cmpbr_flag;{ register rtx prev_insn, prev_dest; if (TARGET_C_SERIES) return 0; /* Can't do this if op1 isn't a register. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -