📄 ns32k.c
字号:
/* Normal case. Do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands); operands[0] = latehalf[0]; operands[1] = latehalf[1]; return singlemove_string (operands);}#define MAX_UNALIGNED_COPY (32)/* Expand string/block move operations. operands[0] is the pointer to the destination. operands[1] is the pointer to the source. operands[2] is the number of bytes to move. operands[3] is the alignment. */static voidmove_tail(operands, bytes, offset) rtx operands[]; int bytes; int offset;{ if (bytes & 2) { rtx src, dest; dest = change_address(operands[0], HImode, plus_constant(XEXP(operands[0], 0), offset)); src = change_address(operands[1], HImode, plus_constant(XEXP(operands[1], 0), offset)); emit_move_insn(dest, src); offset += 2; } if (bytes & 1) { rtx src, dest; dest = change_address(operands[0], QImode, plus_constant(XEXP(operands[0], 0), offset)); src = change_address(operands[1], QImode, plus_constant(XEXP(operands[1], 0), offset)); emit_move_insn(dest, src); }}voidexpand_block_move (operands) rtx operands[];{ rtx bytes_rtx = operands[2]; rtx align_rtx = operands[3]; int constp = (GET_CODE (bytes_rtx) == CONST_INT); int bytes = (constp ? INTVAL (bytes_rtx) : 0); int align = INTVAL (align_rtx); rtx src_reg = gen_rtx(REG, Pmode, 1); rtx dest_reg = gen_rtx(REG, Pmode, 2); rtx count_reg = gen_rtx(REG, SImode, 0); rtx insn; if (constp && bytes <= 0) return; if (constp && bytes < 20) { int words = bytes >> 2; if (words) if (words < 3 || flag_unroll_loops) { int offset = 0; for (; words; words--, offset += 4) { rtx src, dest; dest = change_address(operands[0], SImode, plus_constant(XEXP(operands[0], 0), offset)); src = change_address(operands[1], SImode, plus_constant(XEXP(operands[1], 0), offset)); emit_move_insn(dest, src); } } else { /* Use movmd. It is slower than multiple movd's but more compact. It is also slower than movsd for large copies but causes less registers reloading so is better than movsd for small copies. */ rtx src, dest; dest = copy_addr_to_reg (XEXP(operands[0], 0)); src = copy_addr_to_reg (XEXP(operands[1], 0)); emit_insn(gen_movstrsi2(dest, src, GEN_INT(words))); } move_tail(operands, bytes & 3, bytes & ~3); return; } if (align > UNITS_PER_WORD) align = UNITS_PER_WORD; /* Move the address into scratch registers. */ emit_insn(gen_rtx(CLOBBER, VOIDmode, dest_reg)); emit_move_insn(dest_reg, XEXP (operands[0], 0)); emit_insn(gen_rtx(CLOBBER, VOIDmode, src_reg)); emit_move_insn(src_reg, XEXP (operands[1], 0)); emit_insn(gen_rtx(CLOBBER, VOIDmode, count_reg)); if (constp && (align == UNITS_PER_WORD || bytes < MAX_UNALIGNED_COPY)) { rtx bytes_reg; /* constant no of bytes and aligned or small enough copy to not bother * aligning. Emit insns to copy by words. */ if (bytes >> 2) { emit_move_insn(count_reg, GEN_INT(bytes >> 2)); emit_insn(gen_movstrsi1 (GEN_INT(4))); } /* insns to copy rest */ move_tail(operands, bytes & 3, bytes & ~3); } else if (align == UNITS_PER_WORD) { /* insns to copy by words */ emit_insn(gen_lshrsi3 (count_reg, bytes_rtx, GEN_INT(2))); emit_insn(gen_movstrsi1 (GEN_INT(4))); /* insns to copy rest */ emit_insn(gen_andsi3 (count_reg, bytes_rtx, GEN_INT(3))); emit_insn(gen_movstrsi1 (const1_rtx)); } else { /* Not aligned and we may have a lot to copy so it is worth * aligning. */ rtx aligned_label = gen_label_rtx (); rtx bytes_reg; bytes_reg = copy_to_mode_reg(SImode, bytes_rtx); if (!constp) { /* Emit insns to test and skip over the alignment if it is * not worth it. This doubles as a test to ensure that the alignment * operation can't copy too many bytes */ emit_insn(gen_cmpsi (bytes_reg, GEN_INT(MAX_UNALIGNED_COPY))); emit_jump_insn (gen_blt (aligned_label)); } /* Emit insns to do alignment at run time */ emit_insn(gen_negsi2 (count_reg, src_reg)); emit_insn(gen_andsi3 (count_reg, count_reg, GEN_INT(3))); emit_insn(gen_subsi3 (bytes_reg, bytes_reg, count_reg)); emit_insn(gen_movstrsi1 (const1_rtx)); if (!constp) emit_label (aligned_label); /* insns to copy by words */ emit_insn (gen_lshrsi3 (count_reg, bytes_reg, GEN_INT(2))); emit_insn(gen_movstrsi1 (GEN_INT(4))); /* insns to copy rest */ emit_insn (gen_andsi3 (count_reg, bytes_reg, GEN_INT(3))); emit_insn(gen_movstrsi1 (const1_rtx)); }}/* Returns 1 if OP contains a global symbol reference */intglobal_symbolic_reference_mentioned_p (op, f) rtx op; int f;{ register char *fmt; register int i; if (GET_CODE (op) == SYMBOL_REF) { if (! SYMBOL_REF_FLAG (op)) return 1; else return 0; } else if (f && GET_CODE (op) != CONST) return 0; fmt = GET_RTX_FORMAT (GET_CODE (op)); for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) { if (fmt[i] == 'E') { register int j; for (j = XVECLEN (op, i) - 1; j >= 0; j--) if (global_symbolic_reference_mentioned_p (XVECEXP (op, i, j), 0)) return 1; } else if (fmt[i] == 'e' && global_symbolic_reference_mentioned_p (XEXP (op, i), 0)) return 1; } return 0;}/* Returns 1 if OP contains a symbol reference */intsymbolic_reference_mentioned_p (op) rtx op;{ register char *fmt; register int i; if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF) return 1; fmt = GET_RTX_FORMAT (GET_CODE (op)); for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) { if (fmt[i] == 'E') { register int j; for (j = XVECLEN (op, i) - 1; j >= 0; j--) if (symbolic_reference_mentioned_p (XVECEXP (op, i, j))) return 1; } else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i))) return 1; } return 0;}/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific attribute for DECL. The attributes in ATTRIBUTES have previously been assigned to DECL. */intns32k_valid_decl_attribute_p (decl, attributes, identifier, args) tree decl; tree attributes; tree identifier; tree args;{ return 0;}/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific attribute for TYPE. The attributes in ATTRIBUTES have previously been assigned to TYPE. */intns32k_valid_type_attribute_p (type, attributes, identifier, args) tree type; tree attributes; tree identifier; tree args;{ if (TREE_CODE (type) != FUNCTION_TYPE && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL) return 0; /* Stdcall attribute says callee is responsible for popping arguments if they are not variable. */ if (is_attribute_p ("stdcall", identifier)) return (args == NULL_TREE); /* Cdecl attribute says the callee is a normal C declaration */ if (is_attribute_p ("cdecl", identifier)) return (args == NULL_TREE); return 0;}/* Return 0 if the attributes for two types are incompatible, 1 if they are compatible, and 2 if they are nearly compatible (which causes a warning to be generated). */intns32k_comp_type_attributes (type1, type2) tree type1; tree type2;{ return 1;}/* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. FUNDECL is the declaration node of the function (as a tree), FUNTYPE is the data type of the function (as a tree), or for a library call it is an identifier node for the subroutine name. SIZE is the number of bytes of arguments passed on the stack. On the ns32k, the RET insn may be used to pop them if the number of args is fixed, but if the number is variable then the caller must pop them all. RET can't be used for library calls now because the library is compiled with the Unix compiler. Use of RET is a selectable option, since it is incompatible with standard Unix calling sequences. If the option is not selected, the caller must always pop the args. The attribute stdcall is equivalent to RET on a per module basis. */intns32k_return_pops_args (fundecl, funtype, size) tree fundecl; tree funtype; int size;{ int rtd = TARGET_RTD; if (TREE_CODE (funtype) == IDENTIFIER_NODE) return rtd ? size : 0; /* Cdecl functions override -mrtd, and never pop the stack */ if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) return 0; /* Stdcall functions will pop the stack if not variable args */ if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype))) rtd = 1; if (rtd) { if (TYPE_ARG_TYPES (funtype) == NULL_TREE || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node)) return size; } return 0;}/* PRINT_OPERAND is defined to call this function, which is easier to debug than putting all the code in a macro definition in ns32k.h. *//* XXX time 12% of cpu time is in fprintf for non optimizing */voidprint_operand (file, x, code) FILE *file; rtx x; char code;{ if (code == '$') PUT_IMMEDIATE_PREFIX (file); else if (code == '?') PUT_EXTERNAL_PREFIX (file); else if (GET_CODE (x) == REG) fprintf (file, "%s", ns32k_out_reg_names[REGNO (x)]); else if (GET_CODE (x) == MEM) { rtx tmp = XEXP (x, 0); output_address (XEXP (x, 0)); } else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode) { if (GET_MODE (x) == DFmode) { union { double d; int i[2]; } u; u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); PUT_IMMEDIATE_PREFIX(file);#ifdef SEQUENT_ASM /* Sequent likes its floating point constants as integers */ fprintf (file, "0Dx%08x%08x", u.i[1], u.i[0]);#else#ifdef ENCORE_ASM fprintf (file, "0f%.20e", u.d); #else fprintf (file, "0d%.20e", u.d); #endif#endif } else { union { double d; int i[2]; } u; u.i[0] = CONST_DOUBLE_LOW (x); u.i[1] = CONST_DOUBLE_HIGH (x); PUT_IMMEDIATE_PREFIX (file);#ifdef SEQUENT_ASM /* We have no way of winning if we can't get the bits for a sequent floating point number. */#if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT abort ();#endif { union { float f; long l; } uu; uu.f = u.d; fprintf (file, "0Fx%08x", uu.l); }#else fprintf (file, "0f%.20e", u.d); #endif } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -