📄 i860.c
字号:
frame_upper_bytes = must_preserve_bytes + preserved_reg_bytes; /* Round-up frame_upper_bytes so that t is a multiple of 16. */ frame_upper_bytes = (frame_upper_bytes + STACK_ALIGNMENT - 1) & -STACK_ALIGNMENT; /* Restore all of the "preserved" registers that need restoring. */ mask = 2; for (i = 1; i < 32; i++, mask<<=1) if (regs_ever_live[i] && ! call_used_regs[i]) { fprintf (asm_file, "\tld.l %d(%sfp),%s%s\n", must_preserve_bytes + (4 * restored_so_far++), i860_reg_prefix, i860_reg_prefix, reg_names[i]); if (i > 3 && i < 16) flags->iregs |= mask; } int_restored = restored_so_far; mask = 1; for (i = 32; i < 64; i++) { if (regs_ever_live[i] && ! call_used_regs[i]) { fprintf (asm_file, "\tfld.l %d(%sfp),%s%s\n", must_preserve_bytes + (4 * restored_so_far++), i860_reg_prefix, i860_reg_prefix, reg_names[i]); if (i > 33 && i < 40) flags->fregs |= mask; } if (i > 33 && i < 40) mask<<=1; } /* Get the value we plan to use to restore the stack pointer into r31. */ fprintf (asm_file, "\tadds " HOST_WIDE_INT_PRINT_DEC ",%sfp,%sr31\n", frame_upper_bytes, i860_reg_prefix, i860_reg_prefix); /* Restore the return address and the old frame pointer. */ if (must_preserve_r1) { fprintf (asm_file, "\tld.l 4(%sfp),%sr1\n", i860_reg_prefix, i860_reg_prefix); flags->iregs |= 2; } fprintf (asm_file, "\tld.l 0(%sfp),%sfp\n", i860_reg_prefix, i860_reg_prefix); /* Return and restore the old stack pointer value. */ fprintf (asm_file, "\tbri %sr1\n\tmov %sr31,%ssp\n", i860_reg_prefix, i860_reg_prefix, i860_reg_prefix);#ifdef OUTPUT_TDESC /* Output an ABI-compliant TDESC entry. */ if (! frame_lower_bytes) { flags->version--; if (! frame_upper_bytes) { flags->version--; if (restored_so_far == int_restored) /* No FP saves. */ flags->version--; } } assemble_name(asm_file,current_function_original_name); fputs(".TDESC:\n", asm_file); fprintf(asm_file, "%s 0x%0x\n", long_op, intflags); fprintf(asm_file, "%s %d\n", long_op, int_restored ? must_preserve_bytes : 0); if (flags->version > 1) { fprintf(asm_file, "%s %d\n", long_op, (restored_so_far == int_restored) ? 0 : must_preserve_bytes + (4 * int_restored)); if (flags->version > 2) { fprintf(asm_file, "%s %d\n", long_op, frame_upper_bytes); if (flags->version > 3) fprintf(asm_file, "%s %d\n", long_op, frame_lower_bytes); } } tdesc_section(); fprintf(asm_file, "%s ", long_op); assemble_name(asm_file, current_function_original_name); fprintf(asm_file, "\n%s ", long_op); assemble_name(asm_file, current_function_original_name); fputs(".TDESC\n", asm_file); text_section();#endif}/* Expand a library call to __builtin_saveregs. */static rtxi860_saveregs (void){ rtx fn = gen_rtx_SYMBOL_REF (Pmode, "__builtin_saveregs"); rtx save = gen_reg_rtx (Pmode); rtx valreg = LIBCALL_VALUE (Pmode); rtx ret; /* The return value register overlaps the first argument register. Save and restore it around the call. */ emit_move_insn (save, valreg); ret = emit_library_call_value (fn, NULL_RTX, 1, Pmode, 0); if (GET_CODE (ret) != REG || REGNO (ret) < FIRST_PSEUDO_REGISTER) ret = copy_to_reg (ret); emit_move_insn (valreg, save); return ret;}/* Create the va_list data type. The SVR4 ABI requires the following structure: typedef struct { unsigned long ireg_used; unsigned long freg_used; long *reg_base; long *mem_ptr; } va_list; Otherwise, this structure is used: typedef struct { long *reg_base; long *mem_ptr; unsigned long ireg_used; unsigned long freg_used; } va_list; The tree representing the va_list declaration is returned. */static treei860_build_builtin_va_list (void){ tree f_gpr, f_fpr, f_mem, f_sav, record, type_decl; record = (*lang_hooks.types.make_type) (RECORD_TYPE); type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); f_gpr = build_decl (FIELD_DECL, get_identifier ("__ireg_used"), unsigned_type_node); f_fpr = build_decl (FIELD_DECL, get_identifier ("__freg_used"), unsigned_type_node); f_sav = build_decl (FIELD_DECL, get_identifier ("__reg_base"), ptr_type_node); f_mem = build_decl (FIELD_DECL, get_identifier ("__mem_ptr"), ptr_type_node); DECL_FIELD_CONTEXT (f_gpr) = record; DECL_FIELD_CONTEXT (f_fpr) = record; DECL_FIELD_CONTEXT (f_sav) = record; DECL_FIELD_CONTEXT (f_mem) = record; TREE_CHAIN (record) = type_decl; TYPE_NAME (record) = type_decl;#ifdef I860_SVR4_VA_LIST TYPE_FIELDS (record) = f_gpr; TREE_CHAIN (f_gpr) = f_fpr; TREE_CHAIN (f_fpr) = f_sav; TREE_CHAIN (f_sav) = f_mem;#else TYPE_FIELDS (record) = f_sav; TREE_CHAIN (f_sav) = f_mem; TREE_CHAIN (f_mem) = f_gpr; TREE_CHAIN (f_gpr) = f_fpr;#endif layout_type (record); return record;}/* Initialize the va_list structure. */voidi860_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED){ tree saveregs, t; tree f_gpr, f_fpr, f_mem, f_sav; tree gpr, fpr, mem, sav; int off = 0; saveregs = make_tree (ptr_type_node, expand_builtin_saveregs ());#ifdef I860_SVR4_VA_LIST f_gpr = TYPE_FIELDS (va_list_type_node); f_fpr = TREE_CHAIN (f_gpr); f_sav = TREE_CHAIN (f_fpr); f_mem = TREE_CHAIN (f_sav);#else f_sav = TYPE_FIELDS (va_list_type_node); f_mem = TREE_CHAIN (f_sav); f_gpr = TREE_CHAIN (f_mem); f_fpr = TREE_CHAIN (f_gpr);#endif gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem, NULL_TREE); /* Initialize the `mem_ptr' field to the address of the first anonymous stack argument. */ t = make_tree (TREE_TYPE (mem), virtual_incoming_args_rtx); off = INTVAL (current_function_arg_offset_rtx); off = off < 0 ? 0 : off; t = build (PLUS_EXPR, TREE_TYPE (mem), t, build_int_cst (NULL_TREE, off, 0)); t = build (MODIFY_EXPR, TREE_TYPE (mem), mem, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); /* Initialize the `ireg_used' field. */ t = build_int_cst (NULL_TREE, current_function_args_info.ints / UNITS_PER_WORD, 0); t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); /* Initialize the `freg_used' field. */ t = build_int_cst (NULL_TREE, current_function_args_info.floats / UNITS_PER_WORD, 0); t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); /* Initialize the `reg_base' field. */ t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, saveregs); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);}#define NUM_PARM_FREGS 8#define NUM_PARM_IREGS 12#ifdef I860_SVR4_VA_LIST#define FREG_OFFSET 0#define IREG_OFFSET (NUM_PARM_FREGS * UNITS_PER_WORD)#else#define FREG_OFFSET (NUM_PARM_IREGS * UNITS_PER_WORD)#define IREG_OFFSET 0#endif/* Update the VALIST structure as necessary for an argument of the given TYPE, and return the argument. */static treei860_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p){ tree f_gpr, f_fpr, f_mem, f_sav; tree gpr, fpr, mem, sav; tree size, t, u, addr, type_ptr; tree reg, n_reg, sav_ofs, lim_reg; HOST_WIDE_INT isize; bool indirect;#ifdef I860_SVR4_VA_LIST f_gpr = TYPE_FIELDS (va_list_type_node); f_fpr = TREE_CHAIN (f_gpr); f_sav = TREE_CHAIN (f_fpr); f_mem = TREE_CHAIN (f_sav);#else f_sav = TYPE_FIELDS (va_list_type_node); f_mem = TREE_CHAIN (f_sav); f_gpr = TREE_CHAIN (f_mem); f_fpr = TREE_CHAIN (f_gpr);#endif gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE); fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE); mem = build (COMPONENT_REF, TREE_TYPE (f_mem), valist, f_mem, NULL_TREE); sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE); indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); if (indirect) type = build_pointer_type (type); size = size_in_bytes (type); type_ptr = build_pointer_type (type); if (AGGREGATE_TYPE_P (type)) { /* Aggregates are passed on the stack. */ HOST_WIDE_INT align; align = TYPE_ALIGN (type); if (align < BITS_PER_WORD) align = BITS_PER_WORD; align /= BITS_PER_UNIT; u = fold_convert (ptr_type_node, size_int (align - 1)); t = build (PLUS_EXPR, ptr_type_node, mem, u); u = fold (build (BIT_NOT_EXPR, ptr_type_node, u)); t = build (BIT_AND_EXPR, ptr_type_node, t, u); addr = get_initialized_tmp_var (t, pre_p, post_p); u = fold_convert (ptr_type_node, size); t = build (PLUS_EXPR, ptr_type_node, addr, size); t = build (MODIFY_EXPR, ptr_type_node, mem, t); gimplify_and_add (t, pre_p); } else { isize = tree_low_cst (size, 0); if (FLOAT_TYPE_P (type) || (INTEGRAL_TYPE_P (type) && isize == 8)) { /* Floats and long longs are passed in the fp registers. */ reg = fpr; n_reg = size_int (isize / UNITS_PER_WORD); n_reg = fold_convert (unsigned_type_node, n_reg); lim_reg = size_int (NUM_PARM_FREGS - (isize / UNITS_PER_WORD)); lim_reg = fold_convert (unsigned_type_node, lim_reg); sav_ofs = size_int (FREG_OFFSET); } else { /* Everything else is passed in general registers. */ reg = gpr; if ((isize + UNITS_PER_WORD - 1) / UNITS_PER_WORD > 1) abort (); n_reg = fold_convert (unsigned_type_node, integer_one_node); lim_reg = size_int (NUM_PARM_IREGS - 1); lim_reg = fold_convert (unsigned_type_node, lim_reg); sav_ofs = size_int (IREG_OFFSET); } u = build (LE_EXPR, boolean_type_node, reg, lim_reg); addr = build (COND_EXPR, ptr_type_node, u, NULL, NULL); /* The value was passed in a register, so read it from the register save area initialized by __builtin_saveregs. */ sav_ofs = fold_convert (ptr_type_node, sav_ofs); sav_ofs = fold (build (PLUS_EXPR, ptr_type_node, sav, sav_ofs)); u = fold_convert (unsigned_type_node, size_int (UNITS_PER_WORD)); u = build (MULT_EXPR, unsigned_type_node, reg, u); u = fold_convert (ptr_type_node, u); u = build (PLUS_EXPR, ptr_type_node, sav_ofs, u); COND_EXPR_THEN (addr) = u; /* The value was passed in memory, so read it from the overflow area. */ t = fold_convert (ptr_type_node, size); u = build (POSTINCREMENT_EXPR, ptr_type_node, mem, t); COND_EXPR_ELSE (addr) = u; /* Increment either the ireg_used or freg_used field. */ t = build (PLUS_EXPR, unsigned_type_node, reg, n_reg); t = build (MODIFY_EXPR, unsigned_type_node, reg, t); gimplify_and_add (t, post_p); } addr = fold_convert (type_ptr, addr); if (indirect) addr = build_fold_indirect_ref (addr); return build_fold_indirect_ref (addr);}/* Compute a (partial) cost for rtx X. Return true if the complete cost has been computed, and false if subexpressions should be scanned. In either case, *TOTAL contains the cost result. */static booli860_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total){ switch (code) { case CONST_INT: if (INTVAL (x) == 0) *total = 0; else if (INTVAL (x) < 0x2000 && INTVAL (x) >= -0x2000) *total = 1; return true; case CONST: case LABEL_REF: case SYMBOL_REF: *total = 4; return true; case CONST_DOUBLE: *total = 6; return true; default: return false; }}static voidi860_internal_label (FILE *stream, const char *prefix, unsigned long labelno){ fprintf (stream, ".%s%ld:\n", prefix, labelno);}static voidi860_file_start (void){ output_file_directive (asm_out_file, main_input_filename); fprintf (asm_out_file, "\t.version\t\"01.01\"\n");}static voidi860_init_libfuncs (void){ set_optab_libfunc (sdiv_optab, SImode, "*.div"); set_optab_libfunc (udiv_optab, SImode, "*.udiv"); set_optab_libfunc (smod_optab, SImode, "*.rem"); set_optab_libfunc (umod_optab, SImode, "*.urem");}static rtxi860_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED, int incoming ATTRIBUTE_UNUSED){ return gen_rtx_REG (Pmode, I860_STRUCT_VALUE_REGNUM);}/* Initialize the GCC target structure. */#undef TARGET_RTX_COSTS#define TARGET_RTX_COSTS i860_rtx_costs#undef TARGET_ASM_INTERNAL_LABEL#define TARGET_ASM_INTERNAL_LABEL i8
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -