📄 m68k.c
字号:
CODE_LABEL_NUMBER (XEXP (labelref, 0)));#ifdef SGS_SWITCH_TABLES /* Set flag saying we need to define the symbol LD%n (with value L%n-LI%n) at the end of the switch table. */ switch_table_difference_label_flag = 1;#endif /* SGS_SWITCH_TABLES */#endif /* SGS_SWITCH_TABLES or not MOTOROLA */ }#endif /* SGS_NO_LI */ return "move%.w %1,%0";}const char *output_move_qimode (operands) rtx *operands;{ rtx xoperands[4]; /* This is probably useless, since it loses for pushing a struct of several bytes a byte at a time. */ /* 68k family always modifies the stack pointer by at least 2, even for byte pushes. The 5200 (coldfire) does not do this. */ if (GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC && XEXP (XEXP (operands[0], 0), 0) == stack_pointer_rtx && ! ADDRESS_REG_P (operands[1]) && ! TARGET_5200) { xoperands[1] = operands[1]; xoperands[2] = gen_rtx_MEM (QImode, gen_rtx_PLUS (VOIDmode, stack_pointer_rtx, const1_rtx)); /* Just pushing a byte puts it in the high byte of the halfword. */ /* We must put it in the low-order, high-numbered byte. */ if (!reg_mentioned_p (stack_pointer_rtx, operands[1])) { xoperands[3] = stack_pointer_rtx;#ifndef NO_ADDSUB_Q output_asm_insn ("subq%.l %#2,%3\n\tmove%.b %1,%2", xoperands);#else output_asm_insn ("sub%.l %#2,%3\n\tmove%.b %1,%2", xoperands);#endif } else output_asm_insn ("move%.b %1,%-\n\tmove%.b %@,%2", xoperands); return ""; } /* clr and st insns on 68000 read before writing. This isn't so on the 68010, but we have no TARGET_68010. */ if (!ADDRESS_REG_P (operands[0]) && ((TARGET_68020 || TARGET_5200) || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) { if (operands[1] == const0_rtx) return "clr%.b %0"; if ((!TARGET_5200 || DATA_REG_P (operands[0])) && GET_CODE (operands[1]) == CONST_INT && (INTVAL (operands[1]) & 255) == 255) { CC_STATUS_INIT; return "st %0"; } } if (GET_CODE (operands[1]) == CONST_INT && DATA_REG_P (operands[0]) && INTVAL (operands[1]) < 128 && INTVAL (operands[1]) >= -128) {#if defined(MOTOROLA) && !defined(CRDS) return "moveq%.l %1,%0";#else return "moveq %1,%0";#endif } if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0])) return "sub%.l %0,%0"; if (GET_CODE (operands[1]) != CONST_INT && CONSTANT_P (operands[1])) return "move%.l %1,%0"; /* 68k family (including the 5200 coldfire) does not support byte moves to from address registers. */ if (ADDRESS_REG_P (operands[0]) || ADDRESS_REG_P (operands[1])) return "move%.w %1,%0"; return "move%.b %1,%0";}const char *output_move_stricthi (operands) rtx *operands;{ if (operands[1] == const0_rtx /* clr insns on 68000 read before writing. This isn't so on the 68010, but we have no TARGET_68010. */ && ((TARGET_68020 || TARGET_5200) || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) return "clr%.w %0"; return "move%.w %1,%0";}const char *output_move_strictqi (operands) rtx *operands;{ if (operands[1] == const0_rtx /* clr insns on 68000 read before writing. This isn't so on the 68010, but we have no TARGET_68010. */ && ((TARGET_68020 || TARGET_5200) || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) return "clr%.b %0"; return "move%.b %1,%0";}/* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */static const char *singlemove_string (operands) rtx *operands;{#ifdef SUPPORT_SUN_FPA if (FPA_REG_P (operands[0]) || FPA_REG_P (operands[1])) return "fpmoves %1,%0";#endif if (GET_CODE (operands[1]) == CONST_INT) return output_move_simode_const (operands); return "move%.l %1,%0";}/* Output assembler code to perform a doubleword move insn with operands OPERANDS. */const char *output_move_double (operands) rtx *operands;{ enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; rtx middlehalf[2]; rtx xops[2]; rtx addreg0 = 0, addreg1 = 0; int dest_overlapped_low = 0; int size = GET_MODE_SIZE (GET_MODE (operands[0])); middlehalf[0] = 0; middlehalf[1] = 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 (XEXP (operands[0], 0)) == POST_INC) optype0 = POPOP; else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) optype0 = PUSHOP; 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 (XEXP (operands[1], 0)) == POST_INC) optype1 = POPOP; else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) optype1 = PUSHOP; 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 one operand is decrementing and one is incrementing decrement the former register explicitly and change that operand into ordinary indexing. */ if (optype0 == PUSHOP && optype1 == POPOP) { operands[0] = XEXP (XEXP (operands[0], 0), 0); if (size == 12) output_asm_insn ("sub%.l %#12,%0", operands); else output_asm_insn ("subq%.l %#8,%0", operands); if (GET_MODE (operands[1]) == XFmode) operands[0] = gen_rtx_MEM (XFmode, operands[0]); else if (GET_MODE (operands[0]) == DFmode) operands[0] = gen_rtx_MEM (DFmode, operands[0]); else operands[0] = gen_rtx_MEM (DImode, operands[0]); optype0 = OFFSOP; } if (optype0 == POPOP && optype1 == PUSHOP) { operands[1] = XEXP (XEXP (operands[1], 0), 0); if (size == 12) output_asm_insn ("sub%.l %#12,%1", operands); else output_asm_insn ("subq%.l %#8,%1", operands); if (GET_MODE (operands[1]) == XFmode) operands[1] = gen_rtx_MEM (XFmode, operands[1]); else if (GET_MODE (operands[1]) == DFmode) operands[1] = gen_rtx_MEM (DFmode, operands[1]); else operands[1] = gen_rtx_MEM (DImode, operands[1]); optype1 = OFFSOP; } /* 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)); /* 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 (size == 12) { if (optype0 == REGOP) { latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2); middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); } else if (optype0 == OFFSOP) { middlehalf[0] = adjust_address (operands[0], SImode, 4); latehalf[0] = adjust_address (operands[0], SImode, size - 4); } else { middlehalf[0] = operands[0]; latehalf[0] = operands[0]; } if (optype1 == REGOP) { latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2); middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); } else if (optype1 == OFFSOP) { middlehalf[1] = adjust_address (operands[1], SImode, 4); latehalf[1] = adjust_address (operands[1], SImode, size - 4); } else if (optype1 == CNSTOP) { if (GET_CODE (operands[1]) == CONST_DOUBLE) { REAL_VALUE_TYPE r; long l[3]; REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]); REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l); operands[1] = GEN_INT (l[0]); middlehalf[1] = GEN_INT (l[1]); latehalf[1] = GEN_INT (l[2]); } else if (CONSTANT_P (operands[1])) { /* actually, no non-CONST_DOUBLE constant should ever appear here. */ abort (); if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0) latehalf[1] = constm1_rtx; else latehalf[1] = const0_rtx; } } else { middlehalf[1] = operands[1]; latehalf[1] = operands[1]; } } else /* size is not 12: */ { if (optype0 == REGOP) latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); else if (optype0 == OFFSOP) latehalf[0] = adjust_address (operands[0], SImode, size - 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] = adjust_address (operands[1], SImode, size - 4); else if (optype1 == CNSTOP) split_double (operands[1], &operands[1], &latehalf[1]); else latehalf[1] = operands[1]; } /* If insn is effectively movd N(sp),-(sp) then we will do the high word first. We should use the adjusted operand 1 (which is N+4(sp)) for the low word as well, to compensate for the first decrement of sp. */ if (optype0 == PUSHOP && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) operands[1] = middlehalf[1] = latehalf[1]; /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), if the upper part of reg N does not appear in the MEM, arrange to emit the move late-half first. Otherwise, compute the MEM address into the upper part of N and use that as a pointer to the memory operand. */ if (optype0 == REGOP && (optype1 == OFFSOP || optype1 == MEMOP)) { rtx testlow = gen_rtx_REG (SImode, REGNO (operands[0])); if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) { /* If both halves of dest are used in the src memory address, compute the address into latehalf of dest. Note that this can't happen if the dest is two data regs. */compadr: xops[0] = latehalf[0]; xops[1] = XEXP (operands[1], 0); output_asm_insn ("lea %a1,%0", xops); if (GET_MODE (operands[1]) == XFmode ) { operands[1] = gen_rtx_MEM (XFmode, latehalf[0]); middlehalf[1] = adjust_address (operands[1], DImode, size - 8); latehalf[1] = adjust_address (operands[1], DImode, size - 4); } else { operands[1] = gen_rtx_MEM (DImode, latehalf[0]); latehalf[1] = adjust_address (operands[1], DImode, size - 4); } } else if (size == 12 && reg_overlap_mentioned_p (middlehalf[0], XEXP (operands[1], 0))) { /* Check for two regs used by both source and dest. Note that this can't happen if the dest is all data regs. It can happen if the dest is d6, d7, a0. But in that case, latehalf is an addr reg, so the code at compadr does ok. */ if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) goto compadr; /* JRV says this can't happen: */ if (addreg0 || addreg1) abort (); /* Only the middle reg conflicts; simply put it last. */ output_asm_insn (singlemove_string (operands), operands); output_asm_insn (singlemove_string (latehalf), latehalf); output_asm_insn (singlemove_string (middlehalf), middlehalf); return ""; } else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))) /* If the low half of dest is mentioned in the source memory address, the arrange to emit the move late half first. */ dest_overlapped_low = 1; } /* If one or both operands autodecrementing, do the two words, high-numbered first. */ /* Likewise, the first move would clobber the source of the second one, do them in the other order. 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. */ if (optype0 == PUSHOP || optype1 == PUSHOP || (optype0 == REGOP && optype1 == REGOP && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) || REGNO (operands[0]) == REGNO (latehalf[1]))) || dest_overlapped_low) { /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) { if (size == 12) output_asm_insn ("addq%.l %#8,%0", &addreg0); else output_asm_insn ("addq%.l %#4,%0", &addreg0); } if (addreg1) { if (size == 12) output_asm_insn ("addq%.l %#8,%0", &addreg1); else output_asm_insn ("addq%.l %#4,%0", &addreg1); } /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) output_asm_insn ("subq%.l %#4,%0", &addreg0); if (addreg1) output_asm_insn ("subq%.l %#4,%0", &addreg1); if (size == 12) { output_asm_insn (singlemove_string (middlehalf), middlehalf); if (addreg0) output_asm_insn ("subq%.l %#4,%0", &addreg0); if (addreg1) output_asm_insn ("subq%.l %#4,%0", &addreg1); } /* Do low-numbered word. */ return singlemove_string (operands); } /* Normal case: do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands); /* Do the middle one of the three words for long double */ if (size == 12) { if (addreg0) output_asm_insn ("addq%.l %#4,%0", &addreg0); if (addreg1) output_asm_insn ("addq%.l %#4,%0", &addreg1); output_asm_insn (singlemove_string (middlehalf), middlehalf); } /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) output_asm_insn ("addq%.l %#4,%0", &addreg0); if (addreg1) output_asm_insn ("addq%.l %#4,%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); /* Undo the adds we just did. */ if (addreg0) { if (size == 12) output_asm_insn (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -