📄 i860.c
字号:
}/* Return 1 if OP is an indexed memory reference of mode MODE. */intindexed_operand (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == MEM && GET_MODE (op) == mode && GET_CODE (XEXP (op, 0)) == PLUS && GET_MODE (XEXP (op, 0)) == SImode && register_operand (XEXP (XEXP (op, 0), 0), SImode) && register_operand (XEXP (XEXP (op, 0), 1), SImode));}/* Return 1 if OP is a suitable source operand for a load insn with mode MODE. */intload_operand (op, mode) rtx op; enum machine_mode mode;{ return (memory_operand (op, mode) || indexed_operand (op, mode));}/* Return truth value of whether OP is a integer which fits the range constraining immediate operands in add/subtract insns. */intsmall_int (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && SMALL_INT (op));}/* Return truth value of whether OP is a integer which fits the range constraining immediate operands in logic insns. */intlogic_int (op, mode) rtx op; enum machine_mode mode;{ return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));}/* Test for a valid operand for a call instruction. Don't allow the arg pointer register or virtual regs since they may change into reg + const, which the patterns can't handle yet. */intcall_insn_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) == MEM && (CONSTANT_ADDRESS_P (XEXP (op, 0)) || (GET_CODE (XEXP (op, 0)) == REG && XEXP (op, 0) != arg_pointer_rtx && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER)))) return 1; return 0;}/* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */static char *singlemove_string (operands) rtx *operands;{ if (GET_CODE (operands[0]) == MEM) { if (GET_CODE (operands[1]) != MEM) if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) && (cc_prev_status.flags & CC_HI_R31_ADJ) && cc_prev_status.mdep == XEXP (operands[0], 0))) { CC_STATUS_INIT; output_asm_insn ("orh %h0,%?r0,%?r31", operands); } cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = XEXP (operands[0], 0); return "st.l %r1,%L0(%?r31)"; } else return "st.l %r1,%0"; else abort ();#if 0 { rtx xoperands[2]; cc_status.flags &= ~CC_F0_IS_0; xoperands[0] = gen_rtx (REG, SFmode, 32); xoperands[1] = operands[1]; output_asm_insn (singlemove_string (xoperands), xoperands); xoperands[1] = xoperands[0]; xoperands[0] = operands[0]; output_asm_insn (singlemove_string (xoperands), xoperands); return ""; }#endif } if (GET_CODE (operands[1]) == MEM) { if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) && (cc_prev_status.flags & CC_HI_R31_ADJ) && cc_prev_status.mdep == XEXP (operands[1], 0))) { CC_STATUS_INIT; output_asm_insn ("orh %h1,%?r0,%?r31", operands); } cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = XEXP (operands[1], 0); return "ld.l %L1(%?r31),%0"; } return "ld.l %m1,%0"; } if (GET_CODE (operands[1]) == CONST_INT) { if (operands[1] == const0_rtx) return "mov %?r0,%0"; if((INTVAL (operands[1]) & 0xffff0000) == 0) return "or %L1,%?r0,%0"; if((INTVAL (operands[1]) & 0xffff8000) == 0xffff8000) return "adds %1,%?r0,%0"; if((INTVAL (operands[1]) & 0x0000ffff) == 0) return "orh %H1,%?r0,%0"; } return "mov %1,%0";}/* Output assembler code to perform a doubleword move insn with operands OPERANDS. */char *output_move_double (operands) rtx *operands;{ enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; rtx addreg0 = 0, addreg1 = 0; int highest_first = 0; int no_addreg1_decrement = 0; /* First classify both operands. */ if (REG_P (operands[0])) optype0 = REGOP; else if (offsettable_memref_p (operands[0])) optype0 = OFFSOP; else if (GET_CODE (operands[0]) == MEM) optype0 = MEMOP; else optype0 = RNDOP; if (REG_P (operands[1])) optype1 = REGOP; else if (CONSTANT_P (operands[1])) optype1 = CNSTOP; else if (offsettable_memref_p (operands[1])) optype1 = OFFSOP; else if (GET_CODE (operands[1]) == MEM) optype1 = MEMOP; else optype1 = RNDOP; /* Check for the cases that the operand constraints are not supposed to allow to happen. Abort if we get one, because generating code for these cases is painful. */ if (optype0 == RNDOP || optype1 == RNDOP) abort (); /* If an operand is an unoffsettable memory ref, find a register we can increment temporarily to make it refer to the second word. */ if (optype0 == MEMOP) addreg0 = find_addr_reg (XEXP (operands[0], 0)); if (optype1 == MEMOP) addreg1 = find_addr_reg (XEXP (operands[1], 0));/* ??? Perhaps in some cases move double words if there is a spare pair of floating regs. */ /* Ok, we can do one word at a time. Normally we do the low-numbered word first, but if either operand is autodecrementing then we do the high-numbered word first. In either case, set up in LATEHALF the operands to use for the high-numbered word and in some cases alter the operands in OPERANDS to be suitable for the low-numbered word. */ if (optype0 == REGOP) latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1); else if (optype0 == OFFSOP) latehalf[0] = adj_offsettable_operand (operands[0], 4); else latehalf[0] = operands[0]; if (optype1 == REGOP) latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1); else if (optype1 == OFFSOP) latehalf[1] = adj_offsettable_operand (operands[1], 4); else if (optype1 == CNSTOP) { if (GET_CODE (operands[1]) == CONST_DOUBLE) split_double (operands[1], &operands[1], &latehalf[1]); else if (CONSTANT_P (operands[1])) latehalf[1] = const0_rtx; } else latehalf[1] = operands[1]; /* If the first move would clobber the source of the second one, do them in the other order. RMS says "This happens only for registers; such overlap can't happen in memory unless the user explicitly sets it up, and that is an undefined circumstance." but it happens on the sparc when loading parameter registers, so I am going to define that circumstance, and make it work as expected. */ if (optype0 == REGOP && optype1 == REGOP && REGNO (operands[0]) == REGNO (latehalf[1])) { CC_STATUS_PARTIAL_INIT; /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) output_asm_insn ("adds 0x4,%0,%0", &addreg0); if (addreg1) output_asm_insn ("adds 0x4,%0,%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("adds -0x4,%0,%0", &addreg0); if (addreg1) output_asm_insn ("adds -0x4,%0,%0", &addreg1); /* Do low-numbered word. */ return singlemove_string (operands); } else if (optype0 == REGOP && optype1 != REGOP && reg_overlap_mentioned_p (operands[0], operands[1])) { /* If both halves of dest are used in the src memory address, add the two regs and put them in the low reg (operands[0]). Then it works to load latehalf first. */ if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) { rtx xops[2]; xops[0] = latehalf[0]; xops[1] = operands[0]; output_asm_insn ("adds %1,%0,%1", xops); operands[1] = gen_rtx (MEM, DImode, operands[0]); latehalf[1] = adj_offsettable_operand (operands[1], 4); addreg1 = 0; highest_first = 1; } /* Only one register in the dest is used in the src memory address, and this is the first register of the dest, so we want to do the late half first here also. */ else if (! reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) highest_first = 1; /* Only one register in the dest is used in the src memory address, and this is the second register of the dest, so we want to do the late half last. If addreg1 is set, and addreg1 is the same register as latehalf, then we must suppress the trailing decrement, because it would clobber the value just loaded. */ else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0])) no_addreg1_decrement = 1; } /* Normal case: do the two words, low-numbered first. Overlap case (highest_first set): do high-numbered word first. */ if (! highest_first) output_asm_insn (singlemove_string (operands), operands); CC_STATUS_PARTIAL_INIT; /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) output_asm_insn ("adds 0x4,%0,%0", &addreg0); if (addreg1) output_asm_insn ("adds 0x4,%0,%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("adds -0x4,%0,%0", &addreg0); if (addreg1 && !no_addreg1_decrement) output_asm_insn ("adds -0x4,%0,%0", &addreg1); if (highest_first) output_asm_insn (singlemove_string (operands), operands); return "";}char *output_fp_move_double (operands) rtx *operands;{ /* If the source operand is any sort of zero, use f0 instead. */ if (operands[1] == CONST0_RTX (GET_MODE (operands[1]))) operands[1] = gen_rtx (REG, DFmode, F0_REGNUM); if (FP_REG_P (operands[0])) { if (FP_REG_P (operands[1])) return "fmov.dd %1,%0"; if (GET_CODE (operands[1]) == REG) { output_asm_insn ("ixfr %1,%0", operands); operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); return "ixfr %1,%0"; } if (operands[1] == CONST0_RTX (DFmode)) return "fmov.dd f0,%0"; if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) && (cc_prev_status.flags & CC_HI_R31_ADJ) && cc_prev_status.mdep == XEXP (operands[1], 0))) { CC_STATUS_INIT; output_asm_insn ("orh %h1,%?r0,%?r31", operands); } cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = XEXP (operands[1], 0); return "fld.d %L1(%?r31),%0"; } return "fld.d %1,%0"; } else if (FP_REG_P (operands[1])) { if (GET_CODE (operands[0]) == REG) { output_asm_insn ("fxfr %1,%0", operands); operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1); operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1); return "fxfr %1,%0"; } if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0))) { if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) && (cc_prev_status.flags & CC_HI_R31_ADJ) && cc_prev_status.mdep == XEXP (operands[0], 0))) { CC_STATUS_INIT; output_asm_insn ("orh %h0,%?r0,%?r31", operands); } cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = XEXP (operands[0], 0); return "fst.d %1,%L0(%?r31)"; } return "fst.d %1,%0"; } else abort (); /* NOTREACHED */ return NULL;}/* Return a REG that occurs in ADDR with coefficient 1. ADDR can be effectively incremented by incrementing REG. */static rtxfind_addr_reg (addr) rtx addr;{ while (GET_CODE (addr) == PLUS) { if (GET_CODE (XEXP (addr, 0)) == REG) addr = XEXP (addr, 0); else if (GET_CODE (XEXP (addr, 1)) == REG) addr = XEXP (addr, 1); else if (CONSTANT_P (XEXP (addr, 0))) addr = XEXP (addr, 1); else if (CONSTANT_P (XEXP (addr, 1))) addr = XEXP (addr, 0); else abort (); } if (GET_CODE (addr) == REG) return addr; abort (); /* NOTREACHED */ return NULL;}/* Return a template for a load instruction with mode MODE and arguments from the string ARGS. This string is in static storage. */static char *load_opcode (mode, args, reg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -