📄 xtensa.c
字号:
error ("PRINT_OPERAND_ADDRESS, null pointer"); switch (GET_CODE (addr)) { default: fatal_insn ("invalid address", addr); break; case REG: fprintf (file, "%s, 0", reg_names [REGNO (addr)]); break; case PLUS: { rtx reg = (rtx)0; rtx offset = (rtx)0; rtx arg0 = XEXP (addr, 0); rtx arg1 = XEXP (addr, 1); if (GET_CODE (arg0) == REG) { reg = arg0; offset = arg1; } else if (GET_CODE (arg1) == REG) { reg = arg1; offset = arg0; } else fatal_insn ("no register in address", addr); if (CONSTANT_P (offset)) { fprintf (file, "%s, ", reg_names [REGNO (reg)]); output_addr_const (file, offset); } else fatal_insn ("address offset not a constant", addr); } break; case LABEL_REF: case SYMBOL_REF: case CONST_INT: case CONST: output_addr_const (file, addr); break; }}voidxtensa_output_literal (FILE *file, rtx x, enum machine_mode mode, int labelno){ long value_long[2]; REAL_VALUE_TYPE r; int size; fprintf (file, "\t.literal .LC%u, ", (unsigned) labelno); switch (GET_MODE_CLASS (mode)) { case MODE_FLOAT: if (GET_CODE (x) != CONST_DOUBLE) abort (); REAL_VALUE_FROM_CONST_DOUBLE (r, x); switch (mode) { case SFmode: REAL_VALUE_TO_TARGET_SINGLE (r, value_long[0]); fprintf (file, "0x%08lx\n", value_long[0]); break; case DFmode: REAL_VALUE_TO_TARGET_DOUBLE (r, value_long); fprintf (file, "0x%08lx, 0x%08lx\n", value_long[0], value_long[1]); break; default: abort (); } break; case MODE_INT: case MODE_PARTIAL_INT: size = GET_MODE_SIZE (mode); if (size == 4) { output_addr_const (file, x); fputs ("\n", file); } else if (size == 8) { output_addr_const (file, operand_subword (x, 0, 0, DImode)); fputs (", ", file); output_addr_const (file, operand_subword (x, 1, 0, DImode)); fputs ("\n", file); } else abort (); break; default: abort (); }}/* Return the bytes needed to compute the frame pointer from the current stack pointer. */#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)#define XTENSA_STACK_ALIGN(LOC) (((LOC) + STACK_BYTES-1) & ~(STACK_BYTES-1))longcompute_frame_size (int size){ /* Add space for the incoming static chain value. */ if (cfun->static_chain_decl != NULL) size += (1 * UNITS_PER_WORD); xtensa_current_frame_size = XTENSA_STACK_ALIGN (size + current_function_outgoing_args_size + (WINDOW_SIZE * UNITS_PER_WORD)); return xtensa_current_frame_size;}intxtensa_frame_pointer_required (void){ /* The code to expand builtin_frame_addr and builtin_return_addr currently uses the hard_frame_pointer instead of frame_pointer. This seems wrong but maybe it's necessary for other architectures. This function is derived from the i386 code. */ if (cfun->machine->accesses_prev_frame) return 1; return 0;}voidxtensa_expand_prologue (void){ HOST_WIDE_INT total_size; rtx size_rtx; total_size = compute_frame_size (get_frame_size ()); size_rtx = GEN_INT (total_size); if (total_size < (1 << (12+3))) emit_insn (gen_entry (size_rtx, size_rtx)); else { /* Use a8 as a temporary since a0-a7 may be live. */ rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG); emit_insn (gen_entry (size_rtx, GEN_INT (MIN_FRAME_SIZE))); emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE)); emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg)); emit_move_insn (stack_pointer_rtx, tmp_reg); } if (frame_pointer_needed) { 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -