📄 out-i860.c
字号:
/* Return 1 if OP is a valid first operand for either a logical insn or an add insn of mode MODE. */intcompare_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));}/* Return truth value of whether OP can be used as an operand of a bte insn. */intbte_operand (op, mode) rtx op; enum machine_mode mode;{ return (register_operand (op, mode) || (GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x20));}/* 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));}/* 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))) output_asm_insn ("orh ha%%%m0,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,l%%%m0(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))) output_asm_insn ("orh ha%%%m1,r0,r31", operands); cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = XEXP (operands[1], 0); return "ld.l l%%%m1(r31),%0"; } return "ld.l %1,%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; /* 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]) || GET_CODE (operands[1]) == CONST_DOUBLE) 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 (CONSTANT_P (operands[1])) latehalf[1] = const0_rtx; else if (GET_CODE (operands[1]) == CONST_DOUBLE) { latehalf[1] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_HIGH (operands[1])); operands[1] = gen_rtx (CONST_INT, VOIDmode, CONST_DOUBLE_LOW (operands[1])); } } 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])) { /* 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])) { /* Do the late half first. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Then clobber. */ return singlemove_string (operands); } /* Normal case: do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands); /* 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); return "";}static char *output_fp_move_double (operands) rtx *operands;{ 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] == dconst0_rtx) 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))) output_asm_insn ("orh ha%%%m1,r0,r31", operands); cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = XEXP (operands[1], 0); return "fld.d l%%%m1(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))) output_asm_insn ("orh ha%%%m0,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,l%%%m0(r31)"; } return "fst.d %1,%0"; } else abort ();}/* 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 ();}/* 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) enum machine_mode mode; char *args; rtx reg;{ static char buf[30]; char *opcode; switch (mode) { case QImode: opcode = "ld.b"; break; case HImode: opcode = "ld.s"; break; case SImode: case SFmode: if (FP_REG_P (reg)) opcode = "fld.l"; else opcode = "ld.l"; break; case DImode: if (!FP_REG_P (reg)) abort (); case DFmode: opcode = "fld.d"; break; default: abort (); } sprintf (buf, "%s %s", opcode, args); return buf;}/* Return a template for a store instruction with mode MODE and arguments from the string ARGS. This string is in static storage. */static char *store_opcode (mode, args, reg) enum machine_mode mode; char *args; rtx reg;{ static char buf[30]; char *opcode; switch (mode) { case QImode: opcode = "st.b"; break; case HImode: opcode = "st.s"; break; case SImode: case SFmode: if (FP_REG_P (reg)) opcode = "fst.l"; else opcode = "st.l"; break; case DImode: if (!FP_REG_P (reg)) abort (); case DFmode: opcode = "fst.d"; break; default: abort (); } sprintf (buf, "%s %s", opcode, args); return buf;}/* Output a store-in-memory whose operands are OPERANDS[0,1]. OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero. This function returns a template for an insn. This is in static storage. It may also output some insns directly. It may alter the values of operands[0] and operands[1]. */char *output_store (operands) rtx *operands;{ enum machine_mode mode = GET_MODE (operands[0]); rtx address = XEXP (operands[0], 0); char *string; cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ; cc_status.mdep = address; if (! ((cc_prev_status.flags & CC_KNOW_HI_R31) && (cc_prev_status.flags & CC_HI_R31_ADJ) && address == cc_prev_status.mdep)) { output_asm_insn ("orh ha%%%m0,r0,r31", operands); cc_prev_status.mdep = address; } /* Store zero in two parts when appropriate. */ if (mode == DFmode && operands[1] == dconst0_rtx) return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]); /* Code below isn't smart enough to move a doubleword in two parts, so use output_move_double to do that in the cases that require it. */ if ((mode == DImode || mode == DFmode) && ! FP_REG_P (operands[1])) return output_move_double (operands); return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);}/* Output a load-from-memory whose operands are OPERANDS[0,1]. OPERANDS[0] is a reg, and OPERANDS[1] is a mem. This function returns a template for an insn. This is in static storage. It may also output some insns directly. It may alter the values of operands[0] and operands[1]. */char *output_load (operands)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -