📄 xtensa.c
字号:
{ if (cfun->machine->set_frame_ptr_insn) { rtx first, insn; push_topmost_sequence (); first = get_insns (); pop_topmost_sequence (); /* For all instructions prior to set_frame_ptr_insn, replace hard_frame_pointer references with stack_pointer. */ for (insn = first; insn != cfun->machine->set_frame_ptr_insn; insn = NEXT_INSN (insn)) { if (INSN_P (insn)) PATTERN (insn) = replace_rtx (copy_rtx (PATTERN (insn)), hard_frame_pointer_rtx, stack_pointer_rtx); } } else emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); }}/* Clear variables at function end. */voidxtensa_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT size ATTRIBUTE_UNUSED){ xtensa_current_frame_size = 0;}rtxxtensa_return_addr (int count, rtx frame){ rtx result, retaddr; if (count == -1) retaddr = gen_rtx_REG (Pmode, A0_REG); else { rtx addr = plus_constant (frame, -4 * UNITS_PER_WORD); addr = memory_address (Pmode, addr); retaddr = gen_reg_rtx (Pmode); emit_move_insn (retaddr, gen_rtx_MEM (Pmode, addr)); } /* The 2 most-significant bits of the return address on Xtensa hold the register window size. To get the real return address, these bits must be replaced with the high bits from the current PC. */ result = gen_reg_rtx (Pmode); emit_insn (gen_fix_return_addr (result, retaddr)); return result;}/* Create the va_list data type. This structure is set up by __builtin_saveregs. The __va_reg field points to a stack-allocated region holding the contents of the incoming argument registers. The __va_ndx field is an index initialized to the position of the first unnamed (variable) argument. This same index is also used to address the arguments passed in memory. Thus, the __va_stk field is initialized to point to the position of the first argument in memory offset to account for the arguments passed in registers and to account for the size of the argument registers not being 16-byte aligned. E.G., there are 6 argument registers of 4 bytes each, but we want the __va_ndx for the first stack argument to have the maximal alignment of 16 bytes, so we offset the __va_stk address by 32 bytes so that __va_stk[32] references the first argument on the stack. */static treextensa_build_builtin_va_list (void){ tree f_stk, f_reg, f_ndx, record, type_decl; record = (*lang_hooks.types.make_type) (RECORD_TYPE); type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record); f_stk = build_decl (FIELD_DECL, get_identifier ("__va_stk"), ptr_type_node); f_reg = build_decl (FIELD_DECL, get_identifier ("__va_reg"), ptr_type_node); f_ndx = build_decl (FIELD_DECL, get_identifier ("__va_ndx"), integer_type_node); DECL_FIELD_CONTEXT (f_stk) = record; DECL_FIELD_CONTEXT (f_reg) = record; DECL_FIELD_CONTEXT (f_ndx) = record; TREE_CHAIN (record) = type_decl; TYPE_NAME (record) = type_decl; TYPE_FIELDS (record) = f_stk; TREE_CHAIN (f_stk) = f_reg; TREE_CHAIN (f_reg) = f_ndx; layout_type (record); return record;}/* Save the incoming argument registers on the stack. Returns the address of the saved registers. */static rtxxtensa_builtin_saveregs (void){ rtx gp_regs, dest; int arg_words = current_function_args_info.arg_words; int gp_left = MAX_ARGS_IN_REGISTERS - arg_words; if (gp_left <= 0) return const0_rtx; /* Allocate the general-purpose register space. */ gp_regs = assign_stack_local (BLKmode, MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, -1); set_mem_alias_set (gp_regs, get_varargs_alias_set ()); /* Now store the incoming registers. */ dest = change_address (gp_regs, SImode, plus_constant (XEXP (gp_regs, 0), arg_words * UNITS_PER_WORD)); cfun->machine->need_a7_copy = true; cfun->machine->vararg_a7 = true; move_block_from_reg (GP_ARG_FIRST + arg_words, dest, gp_left); return XEXP (gp_regs, 0);}/* Implement `va_start' for varargs and stdarg. We look at the current function to fill in an initial va_list. */voidxtensa_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED){ tree f_stk, stk; tree f_reg, reg; tree f_ndx, ndx; tree t, u; int arg_words; arg_words = current_function_args_info.arg_words; f_stk = TYPE_FIELDS (va_list_type_node); f_reg = TREE_CHAIN (f_stk); f_ndx = TREE_CHAIN (f_reg); stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk, NULL_TREE); reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg, NULL_TREE); ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx, NULL_TREE); /* Call __builtin_saveregs; save the result in __va_reg */ u = make_tree (ptr_type_node, expand_builtin_saveregs ()); t = build (MODIFY_EXPR, ptr_type_node, reg, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); /* Set the __va_stk member to ($arg_ptr - 32). */ u = make_tree (ptr_type_node, virtual_incoming_args_rtx); u = fold (build (PLUS_EXPR, ptr_type_node, u, build_int_cst (NULL_TREE, -32))); t = build (MODIFY_EXPR, ptr_type_node, stk, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); /* Set the __va_ndx member. If the first variable argument is on the stack, adjust __va_ndx by 2 words to account for the extra alignment offset for __va_stk. */ if (arg_words >= MAX_ARGS_IN_REGISTERS) arg_words += 2; u = build_int_cst (NULL_TREE, arg_words * UNITS_PER_WORD); t = build (MODIFY_EXPR, integer_type_node, ndx, u); TREE_SIDE_EFFECTS (t) = 1; expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);}/* Implement `va_arg'. */static treextensa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED){ tree f_stk, stk; tree f_reg, reg; tree f_ndx, ndx; tree type_size, array, orig_ndx, addr, size, va_size, t; tree lab_false, lab_over, lab_false2; bool indirect; indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); if (indirect) type = build_pointer_type (type); /* Handle complex values as separate real and imaginary parts. */ if (TREE_CODE (type) == COMPLEX_TYPE) { tree real_part, imag_part; real_part = xtensa_gimplify_va_arg_expr (valist, TREE_TYPE (type), pre_p, NULL); real_part = get_initialized_tmp_var (real_part, pre_p, NULL); imag_part = xtensa_gimplify_va_arg_expr (valist, TREE_TYPE (type), pre_p, NULL); imag_part = get_initialized_tmp_var (imag_part, pre_p, NULL); return build (COMPLEX_EXPR, type, real_part, imag_part); } f_stk = TYPE_FIELDS (va_list_type_node); f_reg = TREE_CHAIN (f_stk); f_ndx = TREE_CHAIN (f_reg); stk = build (COMPONENT_REF, TREE_TYPE (f_stk), valist, f_stk, NULL_TREE); reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg, NULL_TREE); ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx, NULL_TREE); type_size = size_in_bytes (type); va_size = round_up (type_size, UNITS_PER_WORD); gimplify_expr (&va_size, pre_p, NULL, is_gimple_val, fb_rvalue); /* First align __va_ndx if necessary for this arg: orig_ndx = (AP).__va_ndx; if (__alignof__ (TYPE) > 4 ) orig_ndx = ((orig_ndx + __alignof__ (TYPE) - 1) & -__alignof__ (TYPE)); */ orig_ndx = get_initialized_tmp_var (ndx, pre_p, NULL); if (TYPE_ALIGN (type) > BITS_PER_WORD) { int align = TYPE_ALIGN (type) / BITS_PER_UNIT; t = build (PLUS_EXPR, integer_type_node, orig_ndx, build_int_cst (NULL_TREE, align - 1)); t = build (BIT_AND_EXPR, integer_type_node, t, build_int_cst (NULL_TREE, -align)); t = build (MODIFY_EXPR, integer_type_node, orig_ndx, t); gimplify_and_add (t, pre_p); } /* Increment __va_ndx to point past the argument: (AP).__va_ndx = orig_ndx + __va_size (TYPE); */ t = fold_convert (integer_type_node, va_size); t = build (PLUS_EXPR, integer_type_node, orig_ndx, t); t = build (MODIFY_EXPR, integer_type_node, ndx, t); gimplify_and_add (t, pre_p); /* Check if the argument is in registers: if ((AP).__va_ndx <= __MAX_ARGS_IN_REGISTERS * 4 && !must_pass_in_stack (type)) __array = (AP).__va_reg; */ array = create_tmp_var (ptr_type_node, NULL); lab_over = NULL; if (!targetm.calls.must_pass_in_stack (TYPE_MODE (type), type)) { lab_false = create_artificial_label (); lab_over = create_artificial_label (); t = build_int_cst (NULL_TREE, MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD); t = build (GT_EXPR, boolean_type_node, ndx, t); t = build (COND_EXPR, void_type_node, t, build (GOTO_EXPR, void_type_node, lab_false), NULL); gimplify_and_add (t, pre_p); t = build (MODIFY_EXPR, void_type_node, array, reg); gimplify_and_add (t, pre_p); t = build (GOTO_EXPR, void_type_node, lab_over); gimplify_and_add (t, pre_p); t = build (LABEL_EXPR, void_type_node, lab_false); gimplify_and_add (t, pre_p); } /* ...otherwise, the argument is on the stack (never split between registers and the stack -- change __va_ndx if necessary): else { if (orig_ndx <= __MAX_ARGS_IN_REGISTERS * 4) (AP).__va_ndx = 32 + __va_size (TYPE); __array = (AP).__va_stk; } */ lab_false2 = create_artificial_label (); t = build_int_cst (NULL_TREE, MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD); t = build (GT_EXPR, boolean_type_node, orig_ndx, t); t = build (COND_EXPR, void_type_node, t, build (GOTO_EXPR, void_type_node, lab_false2), NULL); gimplify_and_add (t, pre_p); t = size_binop (PLUS_EXPR, va_size, size_int (32)); t = fold_convert (integer_type_node, t); t = build (MODIFY_EXPR, integer_type_node, ndx, t); gimplify_and_add (t, pre_p); t = build (LABEL_EXPR, void_type_node, lab_false2); gimplify_and_add (t, pre_p); t = build (MODIFY_EXPR, void_type_node, array, stk); gimplify_and_add (t, pre_p); if (lab_over) { t = build (LABEL_EXPR, void_type_node, lab_over); gimplify_and_add (t, pre_p); } /* Given the base array pointer (__array) and index to the subsequent argument (__va_ndx), find the address: __array + (AP).__va_ndx - (BYTES_BIG_ENDIAN && sizeof (TYPE) < 4 ? sizeof (TYPE) : __va_size (TYPE)) The results are endian-dependent because values smaller than one word are aligned differently. */ if (BYTES_BIG_ENDIAN && TREE_CODE (type_size) == INTEGER_CST) { t = size_int (PARM_BOUNDARY / BITS_PER_UNIT); t = fold (build (GE_EXPR, boolean_type_node, type_size, t)); t = fold (build (COND_EXPR, sizetype, t, va_size, type_size)); size = t; } else size = va_size; t = fold_convert (ptr_type_node, ndx); addr = build (PLUS_EXPR, ptr_type_node, array, t); t = fold_convert (ptr_type_node, size); addr = build (MINUS_EXPR, ptr_type_node, addr, t); addr = fold_convert (build_pointer_type (type), addr); if (indirect) addr = build_va_arg_indirect_ref (addr); return build_va_arg_indirect_ref (addr);}enum reg_classxtensa_preferred_reload_class (rtx x, enum reg_class class, int isoutput){ if (!isoutput && CONSTANT_P (x) && GET_CODE (x) == CONST_DOUBLE) return NO_REGS; /* Don't use the stack pointer or hard frame pointer for reloads! The hard frame pointer would normally be OK except that it may briefly hold an incoming argument in the prologue, and reload won't know that it is live because the hard frame pointer is treated specially. */ if (class == AR_REGS || class == GR_REGS) return RL_REGS; return class;}enum reg_classxtensa_secondary_reload_class (enum reg_class class, enum machine_mode mode ATTRIBUTE_UNUSED, rtx x, int isoutput){ int regno; if (GET_CODE (x) == SIGN_EXTEND) x = XEXP (x, 0); regno = xt_true_regnum (x); if (!isoutput) { if (class == FP_REGS && constantpool_mem_p (x)) return RL_REGS; } if (ACC_REG_P (regno)) return ((class == GR_REGS || class == RL_REGS) ? NO_REGS : RL_REGS); if (class == ACC_REG) return (GP_REG_P (regno) ? NO_REGS : RL_REGS); return NO_REGS;}voidorder_regs_for_local_alloc (void){ if (!leaf_function_p ()) { memcpy (reg_alloc_order, reg_nonleaf_alloc_order, FIRST_PSEUDO_REGISTER * sizeof (int)); } else { int i, num_arg_regs; int nxt = 0; /* Use the AR registers in increasing order (skipping a0 and a1) but save the incoming argument registers for a last resort. */ num_arg_regs = current_function_args_info.arg_words; if (num_arg_regs > MAX_ARGS_IN_REGISTERS) num_arg_regs = MAX_ARGS_IN_REGISTERS; for (i = GP_ARG_FIRST; i < 16 - num_arg_regs; i++) reg_alloc_order[nxt++] = i + num_arg_regs; for (i = 0; i < num_arg_regs; i++) reg_alloc_order[nxt++] = GP_ARG_FIRST + i; /* List the coprocessor registers in order. */ for (i = 0; i < BR_REG_NUM; i++) reg_alloc_order[nxt++] = BR_REG_FIRST + i; /* List the FP registers in order for now. */ for (i = 0; i < 16; i++) reg_alloc_order[nxt++] = FP_REG_FIRST + i; /* GCC requires that we list *all* the registers.... */ reg_alloc_order[nxt++] = 0; /* a0 = return address */ reg_alloc_order[nxt++] = 1; /* a1 = stack pointer */ reg_alloc_order[nxt++] = 16; /* pseudo frame pointer */ reg_alloc_order[nxt++] = 17; /* pseudo arg pointer */ reg_alloc_order[nxt++] = ACC_REG_FIRST; /* MAC16 accumulator */ }}/* Some Xtensa targets support multiple bss sections. If the section name ends with ".bss", add SECTION_BSS to the flags. */static unsigned intxtensa_multibss_section_type_flags (tree decl, const char *name, int reloc){ unsigned int flags = default_section_type_flags (decl, name, reloc); const char *suffix; suffix = strrchr (name, '.'); if (suffix && strcmp (suffix, ".bss") == 0) { if (!decl || (TREE_CODE (decl) == VAR_DECL && DECL_INITIAL (decl) == NULL_TREE)) flags |= SECTION_BSS; /* @nobits */ else warning (0, "only uninitialized variables can be placed in a " ".bss section"); } return flags;}/* The literal pool stays with the function. */static voidxtensa_select_rtx_section (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED){ function_section (current_f
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -