📄 stormy16.c
字号:
saves of the caller saved registers. In some cases, it might be necessary to emit a barrier instruction as the last insn to prevent such scheduling. */voidxstormy16_expand_epilogue (void){ struct xstormy16_stack_layout layout; rtx mem_pop_rtx, insn; int regno; const int ifun = xstormy16_interrupt_function_p (); mem_pop_rtx = gen_rtx_PRE_DEC (Pmode, stack_pointer_rtx); mem_pop_rtx = gen_rtx_MEM (HImode, mem_pop_rtx); layout = xstormy16_compute_stack_layout (); /* Pop the stack for the locals. */ if (layout.locals_size) { if (frame_pointer_needed && layout.sp_minus_fp == layout.locals_size) emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx); else { insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (- layout.locals_size)); RTX_FRAME_RELATED_P (insn) = 1; } } /* Restore any call-saved registers. */ for (regno = FIRST_PSEUDO_REGISTER - 1; regno >= 0; regno--) if (REG_NEEDS_SAVE (regno, ifun)) { rtx dwarf; insn = emit_move_insn (gen_rtx_REG (HImode, regno), mem_pop_rtx); RTX_FRAME_RELATED_P (insn) = 1; dwarf = gen_rtx_SET (Pmode, stack_pointer_rtx, plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (Pmode))); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf, REG_NOTES (insn)); } /* Pop the stack for the stdarg save area. */ if (layout.stdarg_save_size) { insn = emit_addhi3_postreload (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (- layout.stdarg_save_size)); RTX_FRAME_RELATED_P (insn) = 1; } /* Return. */ if (ifun) emit_jump_insn (gen_return_internal_interrupt ()); else emit_jump_insn (gen_return_internal ());}intxstormy16_epilogue_uses (int regno){ if (reload_completed && call_used_regs[regno]) { const int ifun = xstormy16_interrupt_function_p (); return REG_NEEDS_SAVE (regno, ifun); } return 0;}voidxstormy16_function_profiler (void){ sorry ("function_profiler support");}/* Return an updated summarizer variable CUM to advance past an argument in the argument list. The values MODE, TYPE and NAMED describe that argument. Once this is done, the variable CUM is suitable for analyzing the *following* argument with `FUNCTION_ARG', etc. This function need not do anything if the argument in question was passed on the stack. The compiler knows how to track the amount of stack space used for arguments without any special help. However, it makes life easier for xstormy16_build_va_list if it does update the word count. */CUMULATIVE_ARGSxstormy16_function_arg_advance (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, int named ATTRIBUTE_UNUSED){ /* If an argument would otherwise be passed partially in registers, and partially on the stack, the whole of it is passed on the stack. */ if (cum < NUM_ARGUMENT_REGISTERS && cum + XSTORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS) cum = NUM_ARGUMENT_REGISTERS; cum += XSTORMY16_WORD_SIZE (type, mode); return cum;}rtxxstormy16_function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type, int named ATTRIBUTE_UNUSED){ if (mode == VOIDmode) return const0_rtx; if (targetm.calls.must_pass_in_stack (mode, type) || cum + XSTORMY16_WORD_SIZE (type, mode) > NUM_ARGUMENT_REGISTERS) return 0; return gen_rtx_REG (mode, cum + 2);}/* Build the va_list type. For this chip, va_list is a record containing a counter and a pointer. The counter is of type 'int' and indicates how many bytes have been used to date. The pointer indicates the stack position for arguments that have not been passed in registers. To keep the layout nice, the pointer is first in the structure. */static treexstormy16_build_builtin_va_list (void){ tree f_1, f_2, record, type_decl; record = (*lang_hooks.types.make_type) (RECORD_TYPE); type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); f_1 = build_decl (FIELD_DECL, get_identifier ("base"), ptr_type_node); f_2 = build_decl (FIELD_DECL, get_identifier ("count"), unsigned_type_node); DECL_FIELD_CONTEXT (f_1) = record; DECL_FIELD_CONTEXT (f_2) = record; TREE_CHAIN (record) = type_decl; TYPE_NAME (record) = type_decl; TYPE_FIELDS (record) = f_1; TREE_CHAIN (f_1) = f_2; layout_type (record); return record;}/* Implement the stdarg/varargs va_start macro. STDARG_P is nonzero if this is stdarg.h instead of varargs.h. VALIST is the tree of the va_list variable to initialize. NEXTARG is the machine independent notion of the 'next' argument after the variable arguments. */voidxstormy16_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED){ tree f_base, f_count; tree base, count; tree t; if (xstormy16_interrupt_function_p ()) error ("cannot use va_start in interrupt function"); f_base = TYPE_FIELDS (va_list_type_node); f_count = TREE_CHAIN (f_base); base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE); count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count, NULL_TREE); t = make_tree (TREE_TYPE (base), virtual_incoming_args_rtx); t = build (PLUS_EXPR, TREE_TYPE (base), t, build_int_cst (NULL_TREE, INCOMING_FRAME_SP_OFFSET)); t = build (MODIFY_EXPR, TREE_TYPE (base), base, t); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); t = build (MODIFY_EXPR, TREE_TYPE (count), count, build_int_cst (NULL_TREE, current_function_args_info * UNITS_PER_WORD)); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);}/* Implement the stdarg/varargs va_arg macro. VALIST is the variable of type va_list as a tree, TYPE is the type passed to va_arg. Note: This algorithm is documented in stormy-abi. */ static treexstormy16_expand_builtin_va_arg (tree valist, tree type, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED){ tree f_base, f_count; tree base, count; tree count_tmp, addr, t; tree lab_gotaddr, lab_fromstack; int size, size_of_reg_args, must_stack; tree size_tree; f_base = TYPE_FIELDS (va_list_type_node); f_count = TREE_CHAIN (f_base); base = build (COMPONENT_REF, TREE_TYPE (f_base), valist, f_base, NULL_TREE); count = build (COMPONENT_REF, TREE_TYPE (f_count), valist, f_count, NULL_TREE); must_stack = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type); size_tree = round_up (size_in_bytes (type), UNITS_PER_WORD); gimplify_expr (&size_tree, pre_p, NULL, is_gimple_val, fb_rvalue); size_of_reg_args = NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD; count_tmp = get_initialized_tmp_var (count, pre_p, NULL); lab_gotaddr = create_artificial_label (); lab_fromstack = create_artificial_label (); addr = create_tmp_var (ptr_type_node, NULL); if (!must_stack) { tree r; t = fold_convert (TREE_TYPE (count), size_tree); t = build (PLUS_EXPR, TREE_TYPE (count), count_tmp, t); r = fold_convert (TREE_TYPE (count), size_int (size_of_reg_args)); t = build (GT_EXPR, boolean_type_node, t, r); t = build (COND_EXPR, void_type_node, t, build (GOTO_EXPR, void_type_node, lab_fromstack), NULL); gimplify_and_add (t, pre_p); t = fold_convert (ptr_type_node, count_tmp); t = build (PLUS_EXPR, ptr_type_node, base, t); t = build (MODIFY_EXPR, void_type_node, addr, t); gimplify_and_add (t, pre_p); t = build (GOTO_EXPR, void_type_node, lab_gotaddr); gimplify_and_add (t, pre_p); t = build (LABEL_EXPR, void_type_node, lab_fromstack); gimplify_and_add (t, pre_p); } /* Arguments larger than a word might need to skip over some registers, since arguments are either passed entirely in registers or entirely on the stack. */ size = PUSH_ROUNDING (int_size_in_bytes (type)); if (size > 2 || size < 0 || must_stack) { tree r, u; r = size_int (NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD); u = build (MODIFY_EXPR, void_type_node, count_tmp, r); t = fold_convert (TREE_TYPE (count), r); t = build (GE_EXPR, boolean_type_node, count_tmp, t); t = build (COND_EXPR, void_type_node, t, NULL, u); gimplify_and_add (t, pre_p); } t = size_int (NUM_ARGUMENT_REGISTERS * UNITS_PER_WORD - INCOMING_FRAME_SP_OFFSET); t = fold_convert (TREE_TYPE (count), t); t = build (MINUS_EXPR, TREE_TYPE (count), count_tmp, t); t = build (PLUS_EXPR, TREE_TYPE (count), t, fold_convert (TREE_TYPE (count), size_tree)); t = fold_convert (TREE_TYPE (base), fold (t)); t = build (MINUS_EXPR, TREE_TYPE (base), base, t); t = build (MODIFY_EXPR, void_type_node, addr, t); gimplify_and_add (t, pre_p); t = build (LABEL_EXPR, void_type_node, lab_gotaddr); gimplify_and_add (t, pre_p); t = fold_convert (TREE_TYPE (count), size_tree); t = build (PLUS_EXPR, TREE_TYPE (count), count_tmp, t); t = build (MODIFY_EXPR, TREE_TYPE (count), count, t); gimplify_and_add (t, pre_p); addr = fold_convert (build_pointer_type (type), addr); return build_fold_indirect_ref (addr);}/* Initialize the variable parts of a trampoline. ADDR is an RTX for the address of the trampoline; FNADDR is an RTX for the address of the nested function; STATIC_CHAIN is an RTX for the static chain value that should be passed to the function when it is called. */voidxstormy16_initialize_trampoline (rtx addr, rtx fnaddr, rtx static_chain){ rtx reg_addr = gen_reg_rtx (Pmode); rtx temp = gen_reg_rtx (HImode); rtx reg_fnaddr = gen_reg_rtx (HImode); rtx reg_addr_mem; reg_addr_mem = gen_rtx_MEM (HImode, reg_addr); emit_move_insn (reg_addr, addr); emit_move_insn (temp, GEN_INT (0x3130 | STATIC_CHAIN_REGNUM)); emit_move_insn (reg_addr_mem, temp); emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx)); emit_move_insn (temp, static_chain); emit_move_insn (reg_addr_mem, temp); emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx)); emit_move_insn (reg_fnaddr, fnaddr); emit_move_insn (temp, reg_fnaddr); emit_insn (gen_andhi3 (temp, temp, GEN_INT (0xFF))); emit_insn (gen_iorhi3 (temp, temp, GEN_INT (0x0200))); emit_move_insn (reg_addr_mem, temp); emit_insn (gen_addhi3 (reg_addr, reg_addr, const2_rtx)); emit_insn (gen_lshrhi3 (reg_fnaddr, reg_fnaddr, GEN_INT (8))); emit_move_insn (reg_addr_mem, reg_fnaddr);}/* Worker function for FUNCTION_VALUE. */rtxxstormy16_function_value (tree valtype, tree func ATTRIBUTE_UNUSED){ enum machine_mode mode; mode = TYPE_MODE (valtype); PROMOTE_MODE (mode, 0, valtype); return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);}/* A C compound statement that outputs the assembler code for a thunk function, used to implement C++ virtual function calls with multiple inheritance. The thunk acts as a wrapper around a virtual function, adjusting the implicit object parameter before handing control off to the real function. First, emit code to add the integer DELTA to the location that contains the incoming first argument. Assume that this argument contains a pointer, and is the one used to pass the `this' pointer in C++. This is the incoming argument *before* the function prologue, e.g. `%o0' on a sparc. The addition must preserve the values of all other incoming arguments. After the addition, emit code to jump to FUNCTION, which is a `FUNCTION_DECL'. This is a direct pure jump, not a call, and does not touch the return address. Hence returning from FUNCTION will return to whoever called the current `thunk'. The effect must be as if @var{function} had been called directly with the adjusted first argument. This macro is responsible for emitting all of the code for a thunk function; TARGET_ASM_FUNCTION_PROLOGUE and TARGET_ASM_FUNCTION_EPILOGUE are not invoked. The THUNK_FNDECL is redundant. (DELTA and FUNCTION have already been extracted from it.) It might possibly be useful on some targets, but probably not. */static voidxstormy16_asm_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, tree function){ int regnum = FIRST_ARGUMENT_REGISTER; /* There might be a hidden first argument for a returned structure. */ if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) regnum += 1; fprintf (file, "\tadd %s,#0x%x\n", reg_names[regnum], (int) delta & 0xFFFF); fputs ("\tjmpf ", file); assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0)); putc ('\n', file);}/* The purpose of this function is to override the default behavior of BSS objects. Normally, they go into .bss or .sbss via ".common" directives, but we need to override that and put them in .bss_below100. We can't just use a section override (like we do for .data_below100), because that makes them initialized rather than uninitialized. */voidxstormy16_asm_output_aligned_common (FILE *stream, tree decl ATTRIBUTE_UNUSED, const char *name, int size, int align, int global){ if (name[0] == '@' && name[2] == '.') { const char *op = 0; switch (name[1]) { case 'b': bss100_section(); op = "space"; break; } if (op) { const char *name2; int p2align = 0; while (align > 8) { align /= 2; p2align ++; } name2 = xstormy16_strip_name_encoding (name); if (global) fprintf (stream, "\t.globl\t%s\n", name2); if (p2align) fprintf (stream, "\t.p2align %d\n", p2align); fprintf (stream, "\t.type\t%s, @object\n", name2); fprintf (stream, "\t.size\t%s, %d\n", name2, size); fprintf (stream, "%s:\n\t.%s\t%d\n", name2, op, size); return; } } if (!global) { fprintf (stream, "\t.local\t"); assemble_name (stream, name); fprintf (stream, "\n"); } fprintf (stream, "\t.comm\t"); assemble_name (stream, name); fprintf (stream, ",%u,%u\n", size, align / BITS_PER_UNIT);}/* Mark symbols with the "below100" attribute so that we can use the special addressing modes for them. */static voidxstormy16_encode_section_info (tree decl, rtx r, int first ATTRIBUTE_UNUSED){ if (TREE_CODE (decl) == VAR_DECL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -