📄 m68k.c
字号:
if (mode != VOIDmode && GET_MODE(x) != mode) return 0; switch (GET_CODE(x)) { case SIGN_EXTEND : case ZERO_EXTEND : return 1; default : return 0; }}/* Legitimize PIC addresses. If the address is already position-independent, we return ORIG. Newly generated position-independent addresses go to REG. If we need more than one register, we lose. An address is legitimized by making an indirect reference through the Global Offset Table with the name of the symbol used as an offset. The assembler and linker are responsible for placing the address of the symbol in the GOT. The function prologue is responsible for initializing a5 to the starting address of the GOT. The assembler is also responsible for translating a symbol name into a constant displacement from the start of the GOT. A quick example may make things a little clearer: When not generating PIC code to store the value 12345 into _foo we would generate the following code: movel #12345, _foo When generating PIC two transformations are made. First, the compiler loads the address of foo into a register. So the first transformation makes: lea _foo, a0 movel #12345, a0@ The code in movsi will intercept the lea instruction and call this routine which will transform the instructions into: movel a5@(_foo:w), a0 movel #12345, a0@ That (in a nutshell) is how *all* symbol and label references are handled. */rtxlegitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, rtx reg){ rtx pic_ref = orig; /* First handle a simple SYMBOL_REF or LABEL_REF */ if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF) { if (reg == 0) abort (); pic_ref = gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, pic_offset_table_rtx, orig)); current_function_uses_pic_offset_table = 1; MEM_READONLY_P (pic_ref) = 1; emit_move_insn (reg, pic_ref); return reg; } else if (GET_CODE (orig) == CONST) { rtx base; /* Make sure this has not already been legitimized. */ if (GET_CODE (XEXP (orig, 0)) == PLUS && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) return orig; if (reg == 0) abort (); /* legitimize both operands of the PLUS */ if (GET_CODE (XEXP (orig, 0)) == PLUS) { base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg); orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, base == reg ? 0 : reg); } else abort (); if (GET_CODE (orig) == CONST_INT) return plus_constant (base, INTVAL (orig)); pic_ref = gen_rtx_PLUS (Pmode, base, orig); /* Likewise, should we set special REG_NOTEs here? */ } return pic_ref;}typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ, MVS, MVZ } CONST_METHOD;static CONST_METHOD const_method (rtx);#define USE_MOVQ(i) ((unsigned)((i) + 128) <= 255)static CONST_METHODconst_method (rtx constant){ int i; unsigned u; i = INTVAL (constant); if (USE_MOVQ (i)) return MOVQ; /* The ColdFire doesn't have byte or word operations. */ /* FIXME: This may not be useful for the m68060 either. */ if (!TARGET_COLDFIRE) { /* if -256 < N < 256 but N is not in range for a moveq N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */ if (USE_MOVQ (i ^ 0xff)) return NOTB; /* Likewise, try with not.w */ if (USE_MOVQ (i ^ 0xffff)) return NOTW; /* This is the only value where neg.w is useful */ if (i == -65408) return NEGW; } /* Try also with swap. */ u = i; if (USE_MOVQ ((u >> 16) | (u << 16))) return SWAP; if (TARGET_CFV4) { /* Try using MVZ/MVS with an immediate value to load constants. */ if (i >= 0 && i <= 65535) return MVZ; if (i >= -32768 && i <= 32767) return MVS; } /* Otherwise, use move.l */ return MOVL;}static intconst_int_cost (rtx constant){ switch (const_method (constant)) { case MOVQ : /* Constants between -128 and 127 are cheap due to moveq */ return 0; case MVZ: case MVS: case NOTB : case NOTW : case NEGW : case SWAP : /* Constants easily generated by moveq + not.b/not.w/neg.w/swap */ return 1; case MOVL : return 2; default : abort (); }}static boolm68k_rtx_costs (rtx x, int code, int outer_code, int *total){ switch (code) { case CONST_INT: /* Constant zero is super cheap due to clr instruction. */ if (x == const0_rtx) *total = 0; else *total = const_int_cost (x); return true; case CONST: case LABEL_REF: case SYMBOL_REF: *total = 3; return true; case CONST_DOUBLE: /* Make 0.0 cheaper than other floating constants to encourage creating tstsf and tstdf insns. */ if (outer_code == COMPARE && (x == CONST0_RTX (SFmode) || x == CONST0_RTX (DFmode))) *total = 4; else *total = 5; return true; /* These are vaguely right for a 68020. */ /* The costs for long multiply have been adjusted to work properly in synth_mult on the 68020, relative to an average of the time for add and the time for shift, taking away a little more because sometimes move insns are needed. */ /* div?.w is relatively cheaper on 68000 counted in COSTS_N_INSNS terms. */#define MULL_COST (TARGET_68060 ? 2 : TARGET_68040 ? 5 : (TARGET_COLDFIRE && !TARGET_5200) ? 3 : TARGET_COLDFIRE ? 10 : 13)#define MULW_COST (TARGET_68060 ? 2 : TARGET_68040 ? 3 : TARGET_68020 ? 8 : \ (TARGET_COLDFIRE && !TARGET_5200) ? 2 : 5)#define DIVW_COST (TARGET_68020 ? 27 : TARGET_CF_HWDIV ? 11 : 12) case PLUS: /* An lea costs about three times as much as a simple add. */ if (GET_MODE (x) == SImode && GET_CODE (XEXP (x, 1)) == REG && GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT && (INTVAL (XEXP (XEXP (x, 0), 1)) == 2 || INTVAL (XEXP (XEXP (x, 0), 1)) == 4 || INTVAL (XEXP (XEXP (x, 0), 1)) == 8)) { /* lea an@(dx:l:i),am */ *total = COSTS_N_INSNS (TARGET_COLDFIRE ? 2 : 3); return true; } return false; case ASHIFT: case ASHIFTRT: case LSHIFTRT: if (TARGET_68060) { *total = COSTS_N_INSNS(1); return true; } if (! TARGET_68020 && ! TARGET_COLDFIRE) { if (GET_CODE (XEXP (x, 1)) == CONST_INT) { if (INTVAL (XEXP (x, 1)) < 16) *total = COSTS_N_INSNS (2) + INTVAL (XEXP (x, 1)) / 2; else /* We're using clrw + swap for these cases. */ *total = COSTS_N_INSNS (4) + (INTVAL (XEXP (x, 1)) - 16) / 2; } else *total = COSTS_N_INSNS (10); /* worst case */ return true; } /* A shift by a big integer takes an extra instruction. */ if (GET_CODE (XEXP (x, 1)) == CONST_INT && (INTVAL (XEXP (x, 1)) == 16)) { *total = COSTS_N_INSNS (2); /* clrw;swap */ return true; } if (GET_CODE (XEXP (x, 1)) == CONST_INT && !(INTVAL (XEXP (x, 1)) > 0 && INTVAL (XEXP (x, 1)) <= 8)) { *total = COSTS_N_INSNS (TARGET_COLDFIRE ? 1 : 3); /* lsr #i,dn */ return true; } return false; case MULT: if ((GET_CODE (XEXP (x, 0)) == ZERO_EXTEND || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND) && GET_MODE (x) == SImode) *total = COSTS_N_INSNS (MULW_COST); else if (GET_MODE (x) == QImode || GET_MODE (x) == HImode) *total = COSTS_N_INSNS (MULW_COST); else *total = COSTS_N_INSNS (MULL_COST); return true; case DIV: case UDIV: case MOD: case UMOD: if (GET_MODE (x) == QImode || GET_MODE (x) == HImode) *total = COSTS_N_INSNS (DIVW_COST); /* div.w */ else if (TARGET_CF_HWDIV) *total = COSTS_N_INSNS (18); else *total = COSTS_N_INSNS (43); /* div.l */ return true; default: return false; }}const char *output_move_const_into_data_reg (rtx *operands){ int i; i = INTVAL (operands[1]); switch (const_method (operands[1])) { case MVZ: return "mvsw %1,%0"; case MVS: return "mvzw %1,%0"; case MOVQ : return "moveq %1,%0"; case NOTB : CC_STATUS_INIT; operands[1] = GEN_INT (i ^ 0xff); return "moveq %1,%0\n\tnot%.b %0"; case NOTW : CC_STATUS_INIT; operands[1] = GEN_INT (i ^ 0xffff); return "moveq %1,%0\n\tnot%.w %0"; case NEGW : CC_STATUS_INIT; return "moveq #-128,%0\n\tneg%.w %0"; case SWAP : { unsigned u = i; operands[1] = GEN_INT ((u << 16) | (u >> 16)); return "moveq %1,%0\n\tswap %0"; } case MOVL : return "move%.l %1,%0"; default : abort (); }}/* Return 1 if 'constant' can be represented by mov3q on a ColdFire V4 core. */intvalid_mov3q_const (rtx constant){ int i; if (TARGET_CFV4 && GET_CODE (constant) == CONST_INT) { i = INTVAL (constant); if ((i == -1) || (i >= 1 && i <= 7)) return 1; } return 0;}const char *output_move_simode_const (rtx *operands){ if (operands[1] == const0_rtx && (DATA_REG_P (operands[0]) || GET_CODE (operands[0]) == MEM) /* clr insns on 68000 read before writing. This isn't so on the 68010, but we have no TARGET_68010. */ && ((TARGET_68020 || TARGET_COLDFIRE) || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) return "clr%.l %0"; else if ((GET_MODE (operands[0]) == SImode) && valid_mov3q_const (operands[1])) return "mov3q%.l %1,%0"; else if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0])) return "sub%.l %0,%0"; else if (DATA_REG_P (operands[0])) return output_move_const_into_data_reg (operands); else if (ADDRESS_REG_P (operands[0]) && INTVAL (operands[1]) < 0x8000 && INTVAL (operands[1]) >= -0x8000) { if (valid_mov3q_const (operands[1])) return "mov3q%.l %1,%0"; return "move%.w %1,%0"; } else if (GET_CODE (operands[0]) == MEM && GET_CODE (XEXP (operands[0], 0)) == PRE_DEC && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM && INTVAL (operands[1]) < 0x8000 && INTVAL (operands[1]) >= -0x8000) { if (valid_mov3q_const (operands[1])) return "mov3q%.l %1,%-"; return "pea %a1"; } return "move%.l %1,%0";}const char *output_move_simode (rtx *operands){ if (GET_CODE (operands[1]) == CONST_INT) return output_move_simode_const (operands); else if ((GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) && push_operand (operands[0], SImode)) return "pea %a1"; else if ((GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) && ADDRESS_REG_P (operands[0])) return "lea %a1,%0"; return "move%.l %1,%0";}const char *output_move_himode (rtx *operands){ if (GET_CODE (operands[1]) == CONST_INT) { if (operands[1] == const0_rtx && (DATA_REG_P (operands[0]) || GET_CODE (operands[0]) == MEM) /* clr insns on 68000 read before writing. This isn't so on the 68010, but we have no TARGET_68010. */ && ((TARGET_68020 || TARGET_COLDFIRE) || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))) return "clr%.w %0"; else if (operands[1] == const0_rtx && ADDRESS_REG_P (operands[0])) return "sub%.l %0,%0"; else if (DATA_REG_P (operands[0]) && INTVAL (operands[1]) < 128 && INTVAL (operands[1]) >= -128) { return "moveq %1,%0"; } else if (INTVAL (operands[1]) < 0x8000 && INTVAL (operands[1]) >= -0x8000) return "move%.w %1,%0"; } else if (CONSTANT_P (operands[1]))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -