m68k.c
来自「gcc3.2.1源代码」· C语言 代码 · 共 2,431 行 · 第 1/5 页
C
2,431 行
#else asm_fprintf (stream, "\taddqw %0I8,%Rsp\n\taddqw %0I%d,%Rsp\n", fsize + 4 - 8);#endif } else#endif /* not NO_ADDSUB_Q */ if (fsize + 4 < 0x8000) { if (TARGET_68040) { /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4);#else asm_fprintf (stream, "\taddw %0I%d,%Rsp\n", fsize + 4);#endif } else {#ifdef MOTOROLA asm_fprintf (stream, "\tlea (%d,%Rsp),%Rsp\n", fsize + 4);#else asm_fprintf (stream, "\tlea %Rsp@(%d),%Rsp\n", fsize + 4);#endif } } else { /* asm_fprintf() cannot handle %. */#ifdef MOTOROLA asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4);#else asm_fprintf (stream, "\taddl %0I%d,%Rsp\n", fsize + 4);#endif } } if (current_function_pops_args) asm_fprintf (stream, "\trtd %0I%d\n", current_function_pops_args); else fprintf (stream, "\trts\n");}#endif /* ! (DPX2 && MOTOROLA) */#endif /* ! (NEWS && MOTOROLA) */#endif /* !CRDS *//* Similar to general_operand, but exclude stack_pointer_rtx. */intnot_sp_operand (op, mode) register 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 (x, mode) 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 non-zero if flags are currently in the 68881 flag register. */intflags_in_68881 (){ /* We could add support for these in the future */ return cc_status.flags & CC_IN_68881;}/* 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 (operands) rtx *operands;{ switch (GET_CODE (operands[3])) { case EQ:#ifdef MOTOROLA output_asm_insn ("dbeq %0,%l1\n\tjbeq %l2", operands);#else output_asm_insn ("dbeq %0,%l1\n\tjeq %l2", operands);#endif break; case NE:#ifdef MOTOROLA output_asm_insn ("dbne %0,%l1\n\tjbne %l2", operands);#else output_asm_insn ("dbne %0,%l1\n\tjne %l2", operands);#endif break; case GT:#ifdef MOTOROLA output_asm_insn ("dbgt %0,%l1\n\tjbgt %l2", operands);#else output_asm_insn ("dbgt %0,%l1\n\tjgt %l2", operands);#endif break; case GTU:#ifdef MOTOROLA output_asm_insn ("dbhi %0,%l1\n\tjbhi %l2", operands);#else output_asm_insn ("dbhi %0,%l1\n\tjhi %l2", operands);#endif break; case LT:#ifdef MOTOROLA output_asm_insn ("dblt %0,%l1\n\tjblt %l2", operands);#else output_asm_insn ("dblt %0,%l1\n\tjlt %l2", operands);#endif break; case LTU:#ifdef MOTOROLA output_asm_insn ("dbcs %0,%l1\n\tjbcs %l2", operands);#else output_asm_insn ("dbcs %0,%l1\n\tjcs %l2", operands);#endif break; case GE:#ifdef MOTOROLA output_asm_insn ("dbge %0,%l1\n\tjbge %l2", operands);#else output_asm_insn ("dbge %0,%l1\n\tjge %l2", operands);#endif break; case GEU:#ifdef MOTOROLA output_asm_insn ("dbcc %0,%l1\n\tjbcc %l2", operands);#else output_asm_insn ("dbcc %0,%l1\n\tjcc %l2", operands);#endif break; case LE:#ifdef MOTOROLA output_asm_insn ("dble %0,%l1\n\tjble %l2", operands);#else output_asm_insn ("dble %0,%l1\n\tjle %l2", operands);#endif break; case LEU:#ifdef MOTOROLA output_asm_insn ("dbls %0,%l1\n\tjbls %l2", operands);#else output_asm_insn ("dbls %0,%l1\n\tjls %l2", operands);#endif 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:#ifdef MOTOROLA output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjbpl %l1", operands);#else output_asm_insn ("clr%.w %0\n\tsubq%.l %#1,%0\n\tjpl %l1", operands);#endif break; case HImode: break; default: abort (); }}const char *output_scc_di(op, operand1, operand2, dest) 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) {#ifdef MOTOROLA#ifdef SGS_CMP_ORDER output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands);#else output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands);#endif#else#ifdef SGS_CMP_ORDER output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands);#else output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands);#endif#endif } else { if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[0])) output_asm_insn ("tst%.l %0", loperands); else {#ifdef SGS_CMP_ORDER output_asm_insn ("cmp%.w %0,%#0", loperands);#else output_asm_insn ("cmp%.w %#0,%0", loperands);#endif }#ifdef MOTOROLA output_asm_insn ("jbne %l4", loperands);#else output_asm_insn ("jne %l4", loperands);#endif if (TARGET_68020 || TARGET_5200 || ! ADDRESS_REG_P (loperands[1])) output_asm_insn ("tst%.l %1", loperands); else {#ifdef SGS_CMP_ORDER output_asm_insn ("cmp%.w %1,%#0", loperands);#else output_asm_insn ("cmp%.w %#0,%1", loperands);#endif } } loperands[5] = dest; switch (op_code) { case EQ: ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("seq %5", loperands); break; case NE: ASM_OUTPUT_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();#ifdef MOTOROLA output_asm_insn ("shi %5\n\tjbra %l6", loperands);#else output_asm_insn ("shi %5\n\tjra %l6", loperands);#endif ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sgt %5", loperands); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case GTU: ASM_OUTPUT_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();#ifdef MOTOROLA output_asm_insn ("scs %5\n\tjbra %l6", loperands);#else output_asm_insn ("scs %5\n\tjra %l6", loperands);#endif ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("slt %5", loperands); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case LTU: ASM_OUTPUT_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();#ifdef MOTOROLA output_asm_insn ("scc %5\n\tjbra %l6", loperands);#else output_asm_insn ("scc %5\n\tjra %l6", loperands);#endif ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sge %5", loperands); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case GEU: ASM_OUTPUT_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();#ifdef MOTOROLA output_asm_insn ("sls %5\n\tjbra %l6", loperands);#else output_asm_insn ("sls %5\n\tjra %l6", loperands);#endif ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[4])); output_asm_insn ("sle %5", loperands); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (loperands[6])); break; case LEU: ASM_OUTPUT_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 (operands, countop, dataop, insn, signpos) rtx *operands; rtx countop, 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 1 if OP is either a symbol reference or a sum of a symbol reference and a constant. */intsymbolic_operand (op, mode) register rtx op; enum machine_mode mode ATTRIBUTE_UNUSED;{ switch (GET_CODE (op)) { case SYMBOL_REF: case LABEL_REF: return 1; 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 0; }}/* Check for sign_extend or zero_extend. Used for bit-count operands. */intextend_operator(x, mode) rtx x; enum machine_mode mode;{ if (mode != VOIDmode && GET_MODE(x) != mode) return 0; switch (GET_CODE(x)) { case SIGN_EXTEND : case ZERO_EXTEND : return 1; default : return 0; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?