📄 xtensa.c
字号:
case LABEL_REF: case SYMBOL_REF: case CONST_INT: case CONST: output_addr_const (file, addr); break; }}voidxtensa_output_literal (file, x, mode, labelno) 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 (size) int size; /* # of var. bytes allocated */{ /* add space for the incoming static chain value */ if (current_function_needs_context) 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 (){ /* 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_reorg (first) rtx first;{ unsigned long tsize = compute_frame_size (get_frame_size ()); if (tsize < (1 << (12+3))) frame_size_const = 0; else { frame_size_const = force_const_mem (SImode, GEN_INT (tsize - 16));; /* make sure the constant is used so it doesn't get eliminated from the constant pool */ emit_insn_before (gen_rtx_USE (SImode, frame_size_const), first); } if (!frame_pointer_needed) return; if (cfun->machine->set_frame_ptr_insn) { rtx insn; /* 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 the frame pointer move immediately after the NOTE that starts the function */ emit_insn_after (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx), first); }}/* Set up the stack and frame (if desired) for the function. */voidxtensa_function_prologue (file, size) FILE *file; int size ATTRIBUTE_UNUSED;{ unsigned long tsize = compute_frame_size (get_frame_size ()); if (frame_pointer_needed) fprintf (file, "\t.frame\ta7, %ld\n", tsize); else fprintf (file, "\t.frame\tsp, %ld\n", tsize); if (tsize < (1 << (12+3))) { fprintf (file, "\tentry\tsp, %ld\n", tsize); } else { fprintf (file, "\tentry\tsp, 16\n"); /* use a8 as a temporary since a0-a7 may be live */ fprintf (file, "\tl32r\ta8, "); print_operand (file, frame_size_const, 0); fprintf (file, "\n\tsub\ta8, sp, a8\n"); fprintf (file, "\tmovsp\tsp, a8\n"); }}/* Do any necessary cleanup after a function to restore stack, frame, and regs. */voidxtensa_function_epilogue (file, size) FILE *file; int size ATTRIBUTE_UNUSED;{ rtx insn = get_last_insn (); /* If the last insn was a BARRIER, we don't have to write anything. */ if (GET_CODE (insn) == NOTE) insn = prev_nonnote_insn (insn); if (insn == 0 || GET_CODE (insn) != BARRIER) fprintf (file, TARGET_DENSITY ? "\tretw.n\n" : "\tretw\n"); xtensa_current_frame_size = 0;}rtxxtensa_return_addr (count, frame) int count; rtx frame;{ rtx result, retaddr; if (count == -1) retaddr = gen_rtx_REG (Pmode, 0); 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. E.G., if there are 6 argument registers, and each register is 4 bytes, then __va_stk is set to $sp - (6 * 4); then __va_reg[N*4] references argument word N for 0 <= N < 6, and __va_stk[N*4] references argument word N for N >= 6. */treextensa_build_va_list (){ 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. */rtxxtensa_builtin_saveregs (){ rtx gp_regs, dest; int arg_words = current_function_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, gp_left * UNITS_PER_WORD); 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 (valist, nextarg) 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); reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg); ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx); /* Call __builtin_saveregs; save the result in __va_reg */ current_function_arg_words = arg_words; 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 - (size of __va_reg area) */ u = make_tree (ptr_type_node, virtual_incoming_args_rtx); u = fold (build (PLUS_EXPR, ptr_type_node, u, build_int_2 (-MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, -1))); 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. */ u = build_int_2 (arg_words * UNITS_PER_WORD, 0); 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'. */rtxxtensa_va_arg (valist, type) tree valist, type;{ tree f_stk, stk; tree f_reg, reg; tree f_ndx, ndx; tree tmp, addr_tree, type_size; rtx array, orig_ndx, r, addr, size, va_size; rtx lab_false, lab_over, lab_false2; 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); reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg); ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx); type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type)); va_size = gen_reg_rtx (SImode); tmp = fold (build (MULT_EXPR, sizetype, fold (build (TRUNC_DIV_EXPR, sizetype, fold (build (PLUS_EXPR, sizetype, type_size, size_int (UNITS_PER_WORD - 1))), size_int (UNITS_PER_WORD))), size_int (UNITS_PER_WORD))); r = expand_expr (tmp, va_size, SImode, EXPAND_NORMAL); if (r != va_size) emit_move_insn (va_size, r); /* First align __va_ndx to a double word boundary if necessary for this arg: if (__alignof__ (TYPE) > 4) (AP).__va_ndx = (((AP).__va_ndx + 7) & -8) */ if (TYPE_ALIGN (type) > BITS_PER_WORD) { tmp = build (PLUS_EXPR, integer_type_node, ndx, build_int_2 ((2 * UNITS_PER_WORD) - 1, 0)); tmp = build (BIT_AND_EXPR, integer_type_node, tmp, build_int_2 (-2 * UNITS_PER_WORD, -1)); tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp); TREE_SIDE_EFFECTS (tmp) = 1; expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL); } /* Increment __va_ndx to point past the argument: orig_ndx = (AP).__va_ndx; (AP).__va_ndx += __va_size (TYPE); */ orig_ndx = gen_reg_rtx (SImode); r = expand_expr (ndx, orig_ndx, SImode, EXPAND_NORMAL); if (r != orig_ndx) emit_move_insn (orig_ndx, r); tmp = build (PLUS_EXPR, integer_type_node, ndx, make_tree (intSI_type_node, va_size)); tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp); TREE_SIDE_EFFECTS (tmp) = 1; expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL); /* 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 = gen_reg_rtx (Pmode); lab_over = NULL_RTX; if (!MUST_PASS_IN_STACK (VOIDmode, type)) { lab_false = gen_label_rtx (); lab_over = gen_label_rtx (); emit_cmp_and_jump_insns (expand_expr (ndx, NULL_RTX, SImode, EXPAND_NORMAL), GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD), GT, const1_rtx, SImode, 0, lab_false); r = expand_expr (reg, array, Pmode, EXPAND_NORMAL); if (r != array) emit_move_insn (array, r); emit_jump_insn (gen_jump (lab_over)); emit_barrier (); emit_label (lab_false); } /* ...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 = __MAX_ARGS_IN_REGISTERS * 4 + __va_size (TYPE); __array = (AP).__va_stk; } */ lab_false2 = gen_label_rtx (); emit_cmp_and_jump_insns (orig_ndx, GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD), GE, const1_rtx, SImode, 0, lab_false2); tmp = build (PLUS_EXPR, sizetype, make_tree (intSI_type_node, va_size), build_int_2 (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, 0)); tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp); TREE_SIDE_EFFECTS (tmp) = 1; expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL); emit_label (lab_false2); r = expand_expr (stk, array, Pmode, EXPAND_NORMAL); if (r != array) emit_move_insn (array, r); if (lab_over != NULL_RTX) emit_label (lab_over); /* 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. */ size = gen_reg_rtx (SImode); emit_move_insn (size, va_size); if (BYTES_BIG_ENDIAN) { rtx lab_use_va_size = gen_label_rtx (); emit_cmp_and_jump_insns (expand_expr (type_size, NULL_RTX, SImode, EXPAND_NORMAL), GEN_INT (PARM_BOUNDARY / BITS_PER_UNIT), GE, const1_rtx, SImode, 0, lab_use_va_size); r = expand_expr (type_size, size, SImode, EXPAND_NORMAL); if (r != size) emit_move_insn (size, r); emit_label (lab_use_va_size); } ad
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -