📄 m68k.c
字号:
fsize_with_regs); } else if (fsize_with_regs <= 16 && TARGET_CPU32) { /* On the CPU32 it is faster to use two addqw instructions to add a small integer (8 < N <= 16) to a register. */ asm_fprintf (stream, "\taddq" ASM_DOT "w %I8,%Rsp\n" "\taddq" ASM_DOT "w %I%wd,%Rsp\n", fsize_with_regs - 8); } else if (fsize_with_regs < 0x8000) { if (TARGET_68040) asm_fprintf (stream, "\tadd" ASM_DOT "w %I%wd,%Rsp\n", fsize_with_regs); else asm_fprintf (stream, MOTOROLA ? "\tlea (%wd,%Rsp),%Rsp\n" : "\tlea %Rsp@(%wd),%Rsp\n", fsize_with_regs); } else asm_fprintf (stream, "\tadd" ASM_DOT "l %I%wd,%Rsp\n", fsize_with_regs); } if (current_function_calls_eh_return) asm_fprintf (stream, "\tadd" ASM_DOT"l %Ra0,%Rsp\n"); if (m68k_interrupt_function_p (current_function_decl)) fprintf (stream, "\trte\n"); else if (current_function_pops_args) asm_fprintf (stream, "\trtd %I%d\n", current_function_pops_args); else fprintf (stream, "\trts\n");}/* Similar to general_operand, but exclude stack_pointer_rtx. */intnot_sp_operand (rtx op, enum machine_mode mode){ return op != stack_pointer_rtx && nonimmediate_operand (op, mode);}/* Return true if X is a valid comparison operator for the dbcc instruction. Note it rejects floating point comparison operators. (In the future we could use Fdbcc). It also rejects some comparisons when CC_NO_OVERFLOW is set. */ intvalid_dbcc_comparison_p (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED){ switch (GET_CODE (x)) { case EQ: case NE: case GTU: case LTU: case GEU: case LEU: return 1; /* Reject some when CC_NO_OVERFLOW is set. This may be over conservative */ case GT: case LT: case GE: case LE: return ! (cc_prev_status.flags & CC_NO_OVERFLOW); default: return 0; }}/* Return nonzero if flags are currently in the 68881 flag register. */intflags_in_68881 (void){ /* We could add support for these in the future */ return cc_status.flags & CC_IN_68881;}/* Output a BSR instruction suitable for PIC code. */voidm68k_output_pic_call(rtx dest){ const char *out; if (!(GET_CODE (dest) == MEM && GET_CODE (XEXP (dest, 0)) == SYMBOL_REF)) out = "jsr %0"; /* We output a BSR instruction if we're using -fpic or we're building for * a target that supports long branches. If we're building -fPIC on the * 68000, 68010 or ColdFire we generate one of two sequences: * a shorter one that uses a GOT entry or a longer one that doesn't. * We'll use the -Os command-line flag to decide which to generate. * Both sequences take the same time to execute on the ColdFire. */ else if (TARGET_PCREL) out = "bsr.l %o0"; else if ((flag_pic == 1) || TARGET_68020)#if defined(USE_GAS) out = "bsr.l %0@PLTPC";#else out = "bsr %0@PLTPC";#endif else if (optimize_size || TARGET_ID_SHARED_LIBRARY) out = "move.l %0@GOT(%%a5), %%a1\n\tjsr (%%a1)"; else out = "lea %0-.-8,%%a1\n\tjsr 0(%%pc,%%a1)"; output_asm_insn(out, &dest);}/* Output a dbCC; jCC sequence. Note we do not handle the floating point version of this sequence (Fdbcc). We also do not handle alternative conditions when CC_NO_OVERFLOW is set. It is assumed that valid_dbcc_comparison_p and flags_in_68881 will kick those out before we get here. */voidoutput_dbcc_and_branch (rtx *operands){ switch (GET_CODE (operands[3])) { case EQ: output_asm_insn (MOTOROLA ? "dbeq %0,%l1\n\tjbeq %l2" : "dbeq %0,%l1\n\tjeq %l2", operands); break; case NE: output_asm_insn (MOTOROLA ? "dbne %0,%l1\n\tjbne %l2" : "dbne %0,%l1\n\tjne %l2", operands); break; case GT: output_asm_insn (MOTOROLA ? "dbgt %0,%l1\n\tjbgt %l2" : "dbgt %0,%l1\n\tjgt %l2", operands); break; case GTU: output_asm_insn (MOTOROLA ? "dbhi %0,%l1\n\tjbhi %l2" : "dbhi %0,%l1\n\tjhi %l2", operands); break; case LT: output_asm_insn (MOTOROLA ? "dblt %0,%l1\n\tjblt %l2" : "dblt %0,%l1\n\tjlt %l2", operands); break; case LTU: output_asm_insn (MOTOROLA ? "dbcs %0,%l1\n\tjbcs %l2" : "dbcs %0,%l1\n\tjcs %l2", operands); break; case GE: output_asm_insn (MOTOROLA ? "dbge %0,%l1\n\tjbge %l2" : "dbge %0,%l1\n\tjge %l2", operands); break; case GEU: output_asm_insn (MOTOROLA ? "dbcc %0,%l1\n\tjbcc %l2" : "dbcc %0,%l1\n\tjcc %l2", operands); break; case LE: output_asm_insn (MOTOROLA ? "dble %0,%l1\n\tjble %l2" : "dble %0,%l1\n\tjle %l2", operands); break; case LEU: output_asm_insn (MOTOROLA ? "dbls %0,%l1\n\tjbls %l2" : "dbls %0,%l1\n\tjls %l2", operands); break; default: abort (); } /* If the decrement is to be done in SImode, then we have to compensate for the fact that dbcc decrements in HImode. */ switch (GET_MODE (operands[0])) { case SImode: output_asm_insn (MOTOROLA ? "clr%.w %0\n\tsubq%.l #1,%0\n\tjbpl %l1" : "clr%.w %0\n\tsubq%.l #1,%0\n\tjpl %l1", operands); break; case HImode: break; default: abort (); }}const char *output_scc_di(rtx op, rtx operand1, rtx operand2, rtx dest){ rtx loperands[7]; enum rtx_code op_code = GET_CODE (op); /* This does not produce a useful cc. */ CC_STATUS_INIT; /* The m68k cmp.l instruction requires operand1 to be a reg as used below. Swap the operands and change the op if these requirements are not fulfilled. */ if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG) { rtx tmp = operand1; operand1 = operand2; operand2 = tmp; op_code = swap_condition (op_code); } loperands[0] = operand1; if (GET_CODE (operand1) == REG) loperands[1] = gen_rtx_REG (SImode, REGNO (operand1) + 1); else loperands[1] = adjust_address (operand1, SImode, 4); if (operand2 != const0_rtx) { loperands[2] = operand2; if (GET_CODE (operand2) == REG) loperands[3] = gen_rtx_REG (SImode, REGNO (operand2) + 1); else loperands[3] = adjust_address (operand2, SImode, 4); } loperands[4] = gen_label_rtx (); if (operand2 != const0_rtx) { output_asm_insn (MOTOROLA ? "cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1" : "cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands); } else { if (TARGET_68020 || TARGET_COLDFIRE || ! ADDRESS_REG_P (loperands[0])) output_asm_insn ("tst%.l %0", loperands); else { output_asm_insn ("cmp%.w #0,%0", loperands); } output_asm_insn (MOTOROLA ? "jbne %l4" : "jne %l4", loperands); if (TARGET_68020 || TARGET_COLDFIRE || ! ADDRESS_REG_P (loperands[1])) output_asm_insn ("tst%.l %1", loperands); else output_asm_insn ("cmp%.w #0,%1", loperands); } loperands[5] = dest; switch (op_code) { case EQ: (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("seq %5", loperands); break; case NE: (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sne %5", loperands); break; case GT: loperands[6] = gen_label_rtx (); output_asm_insn (MOTOROLA ? "shi %5\n\tjbra %l6" : "shi %5\n\tjra %l6", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sgt %5", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case GTU: (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("shi %5", loperands); break; case LT: loperands[6] = gen_label_rtx (); output_asm_insn (MOTOROLA ? "scs %5\n\tjbra %l6" : "scs %5\n\tjra %l6", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("slt %5", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case LTU: (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("scs %5", loperands); break; case GE: loperands[6] = gen_label_rtx (); output_asm_insn (MOTOROLA ? "scc %5\n\tjbra %l6" : "scc %5\n\tjra %l6", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sge %5", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case GEU: (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("scc %5", loperands); break; case LE: loperands[6] = gen_label_rtx (); output_asm_insn (MOTOROLA ? "sls %5\n\tjbra %l6" : "sls %5\n\tjra %l6", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sle %5", loperands); (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case LEU: (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sls %5", loperands); break; default: abort (); } return "";}const char *output_btst (rtx *operands, rtx countop, rtx dataop, rtx insn, int signpos){ operands[0] = countop; operands[1] = dataop; if (GET_CODE (countop) == CONST_INT) { register int count = INTVAL (countop); /* If COUNT is bigger than size of storage unit in use, advance to the containing unit of same size. */ if (count > signpos) { int offset = (count & ~signpos) / 8; count = count & signpos; operands[1] = dataop = adjust_address (dataop, QImode, offset); } if (count == signpos) cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N; else cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N; /* These three statements used to use next_insns_test_no... but it appears that this should do the same job. */ if (count == 31 && next_insn_tests_no_inequality (insn)) return "tst%.l %1"; if (count == 15 && next_insn_tests_no_inequality (insn)) return "tst%.w %1"; if (count == 7 && next_insn_tests_no_inequality (insn)) return "tst%.b %1"; cc_status.flags = CC_NOT_NEGATIVE; } return "btst %0,%1";}/* Returns true if OP is either a symbol reference or a sum of a symbol reference and a constant. */intsymbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED){ switch (GET_CODE (op)) { case SYMBOL_REF: case LABEL_REF: return true; case CONST: op = XEXP (op, 0); return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF || GET_CODE (XEXP (op, 0)) == LABEL_REF) && GET_CODE (XEXP (op, 1)) == CONST_INT);#if 0 /* Deleted, with corresponding change in m68k.h, so as to fit the specs. No CONST_DOUBLE is ever symbolic. */ case CONST_DOUBLE: return GET_MODE (op) == mode;#endif default: return false; }}/* Check for sign_extend or zero_extend. Used for bit-count operands. */intextend_operator(rtx x, enum machine_mode mode){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -