📄 stormy16.c
字号:
xstormy16_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_va_arg_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, const char *name, int size, int align, int global){ rtx mem = DECL_RTL (decl); rtx symbol; if (mem != NULL_RTX && GET_CODE (mem) == MEM && GET_CODE (symbol = XEXP (mem, 0)) == SYMBOL_REF && SYMBOL_REF_FLAGS (symbol) & SYMBOL_FLAG_XSTORMY16_BELOW100) { const char *name2; int p2align = 0; bss100_section (); while (align > 8) { align /= 2; p2align ++; } name2 = default_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.space\t%d\n", name2, 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){ default_encode_section_info (decl, r, first); if (TREE_CODE (decl) == VAR_DECL && (lookup_attribute ("below100", DECL_ATTRIBUTES (decl)) || lookup_attribute ("BELOW100", DECL_ATTRIBUTES (decl)))) { rtx symbol = XEXP (r, 0); gcc_assert (GET_CODE (symbol) == SYMBOL_REF); SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_XSTORMY16_BELOW100; }}/* Output constructors and destructors. Just like default_named_section_asm_out_* but don't set the sections writable. */#undef TARGET_ASM_CONSTRUCTOR#define TARGET_ASM_CONSTRUCTOR xstormy16_asm_out_constructor#undef TARGET_ASM_DESTRUCTOR#define TARGET_ASM_DESTRUCTOR xstormy16_asm_out_destructorstatic voidxstormy16_asm_out_destructor (rtx symbol, int priority){ const char *section = ".dtors"; char buf[16]; /* ??? This only works reliably with the GNU linker. */ if (priority != DEFAULT_INIT_PRIORITY) { sprintf (buf, ".dtors.%.5u", /* Invert the numbering so the linker puts us in the proper order; constructors are run from right to left, and the linker sorts in increasing order. */ MAX_INIT_PRIORITY - priority); section = buf; } named_section_flags (section, 0); assemble_align (POINTER_SIZE); assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);}static voidxstormy16_asm_out_constructor (rtx symbol, int priority){ const char *section = ".ctors"; char buf[16]; /* ??? This only works reliably with the GNU linker. */ if (priority != DEFAULT_INIT_PRIORITY) { sprintf (buf, ".ctors.%.5u", /* Invert the numbering so the linker puts us in the proper order; constructors are run from right to left, and the linker sorts in increasing order. */ MAX_INIT_PRIORITY - priority); section = buf; } named_section_flags (section, 0); assemble_align (POINTER_SIZE); assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);}/* Print a memory address as an operand to reference that memory location. */voidxstormy16_print_operand_address (FILE *file, rtx address){ HOST_WIDE_INT offset; int pre_dec, post_inc; /* There are a few easy cases. */ if (GET_CODE (address) == CONST_INT) { fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (address) & 0xFFFF); return; } if (CONSTANT_P (address) || GET_CODE (address) == CODE_LABEL) { output_addr_const (file, address); return; } /* Otherwise, it's hopefully something of the form (plus:HI (pre_dec:HI (reg:HI ...)) (const_int ...)) */ if (GET_CODE (address) == PLUS) { gcc_assert (GET_CODE (XEXP (address, 1)) == CONST_INT); offset = INTVAL (XEXP (address, 1)); address = XEXP (address, 0); } else offset = 0; pre_dec = (GET_CODE (address) == PRE_DEC); post_inc = (GET_CODE (address) == POST_INC); if (pre_dec || post_inc) address = XEXP (address, 0); gcc_assert (GET_CODE (address) == REG); fputc ('(', file); if (pre_dec) fputs ("--", file); fputs (reg_names [REGNO (address)], file); if (post_inc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -