📄 iq2000.c
字号:
iq2000_print_operand_punct['?'] = 1; iq2000_print_operand_punct['#'] = 1; iq2000_print_operand_punct['&'] = 1; iq2000_print_operand_punct['!'] = 1; iq2000_print_operand_punct['*'] = 1; iq2000_print_operand_punct['@'] = 1; iq2000_print_operand_punct['.'] = 1; iq2000_print_operand_punct['('] = 1; iq2000_print_operand_punct[')'] = 1; iq2000_print_operand_punct['['] = 1; iq2000_print_operand_punct[']'] = 1; iq2000_print_operand_punct['<'] = 1; iq2000_print_operand_punct['>'] = 1; iq2000_print_operand_punct['{'] = 1; iq2000_print_operand_punct['}'] = 1; iq2000_print_operand_punct['^'] = 1; iq2000_print_operand_punct['$'] = 1; iq2000_print_operand_punct['+'] = 1; iq2000_print_operand_punct['~'] = 1; /* Save GPR registers in word_mode sized hunks. word_mode hasn't been initialized yet, so we can't use that here. */ gpr_mode = SImode; /* Function to allocate machine-dependent function status. */ init_machine_status = iq2000_init_machine_status;}/* The arg pointer (which is eliminated) points to the virtual frame pointer, while the frame pointer (which may be eliminated) points to the stack pointer after the initial adjustments. */HOST_WIDE_INTiq2000_debugger_offset (rtx addr, HOST_WIDE_INT offset){ rtx offset2 = const0_rtx; rtx reg = eliminate_constant_term (addr, & offset2); if (offset == 0) offset = INTVAL (offset2); if (reg == stack_pointer_rtx || reg == frame_pointer_rtx || reg == hard_frame_pointer_rtx) { HOST_WIDE_INT frame_size = (!cfun->machine->initialized) ? compute_frame_size (get_frame_size ()) : cfun->machine->total_size; offset = offset - frame_size; } return offset;}/* If defined, a C statement to be executed just prior to the output of assembler code for INSN, to modify the extracted operands so they will be output differently. Here the argument OPVEC is the vector containing the operands extracted from INSN, and NOPERANDS is the number of elements of the vector which contain meaningful data for this insn. The contents of this vector are what will be used to convert the insn template into assembler code, so you can change the assembler output by changing the contents of the vector. We use it to check if the current insn needs a nop in front of it because of load delays, and also to update the delay slot statistics. */voidfinal_prescan_insn (rtx insn, rtx opvec[] ATTRIBUTE_UNUSED, int noperands ATTRIBUTE_UNUSED){ if (dslots_number_nops > 0) { rtx pattern = PATTERN (insn); int length = get_attr_length (insn); /* Do we need to emit a NOP? */ if (length == 0 || (iq2000_load_reg != 0 && reg_mentioned_p (iq2000_load_reg, pattern)) || (iq2000_load_reg2 != 0 && reg_mentioned_p (iq2000_load_reg2, pattern)) || (iq2000_load_reg3 != 0 && reg_mentioned_p (iq2000_load_reg3, pattern)) || (iq2000_load_reg4 != 0 && reg_mentioned_p (iq2000_load_reg4, pattern))) fputs ("\tnop\n", asm_out_file); else dslots_load_filled ++; while (--dslots_number_nops > 0) fputs ("\tnop\n", asm_out_file); iq2000_load_reg = 0; iq2000_load_reg2 = 0; iq2000_load_reg3 = 0; iq2000_load_reg4 = 0; } if ( (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN || (GET_CODE (PATTERN (insn)) == RETURN)) && NEXT_INSN (PREV_INSN (insn)) == insn) { rtx nop_insn = emit_insn_after (gen_nop (), insn); INSN_ADDRESSES_NEW (nop_insn, -1); } if (TARGET_STATS && (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN)) dslots_jump_total ++;}/* Return the bytes needed to compute the frame pointer from the current stack pointer where SIZE is the # of var. bytes allocated. IQ2000 stack frames look like: Before call After call +-----------------------+ +-----------------------+ high | | | | mem. | | | | | caller's temps. | | caller's temps. | | | | | +-----------------------+ +-----------------------+ | | | | | arguments on stack. | | arguments on stack. | | | | | +-----------------------+ +-----------------------+ | 4 words to save | | 4 words to save | | arguments passed | | arguments passed | | in registers, even | | in registers, even | SP->| if not passed. | VFP->| if not passed. | +-----------------------+ +-----------------------+ | | | fp register save | | | +-----------------------+ | | | gp register save | | | +-----------------------+ | | | local variables | | | +-----------------------+ | | | alloca allocations | | | +-----------------------+ | | | GP save for V.4 abi | | | +-----------------------+ | | | arguments on stack | | | +-----------------------+ | 4 words to save | | arguments passed | | in registers, even | low SP->| if not passed. | memory +-----------------------+ */HOST_WIDE_INTcompute_frame_size (HOST_WIDE_INT size){ int regno; HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */ HOST_WIDE_INT var_size; /* # bytes that variables take up. */ HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */ HOST_WIDE_INT extra_size; /* # extra bytes. */ HOST_WIDE_INT gp_reg_rounded; /* # bytes needed to store gp after rounding. */ HOST_WIDE_INT gp_reg_size; /* # bytes needed to store gp regs. */ HOST_WIDE_INT fp_reg_size; /* # bytes needed to store fp regs. */ long mask; /* mask of saved gp registers. */ int fp_inc; /* 1 or 2 depending on the size of fp regs. */ long fp_bits; /* bitmask to use for each fp register. */ gp_reg_size = 0; fp_reg_size = 0; mask = 0; extra_size = IQ2000_STACK_ALIGN ((0)); var_size = IQ2000_STACK_ALIGN (size); args_size = IQ2000_STACK_ALIGN (current_function_outgoing_args_size); /* If a function dynamically allocates the stack and has 0 for STACK_DYNAMIC_OFFSET then allocate some stack space. */ if (args_size == 0 && current_function_calls_alloca) args_size = 4 * UNITS_PER_WORD; total_size = var_size + args_size + extra_size; /* Calculate space needed for gp registers. */ for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++) { if (MUST_SAVE_REGISTER (regno)) { gp_reg_size += GET_MODE_SIZE (gpr_mode); mask |= 1L << (regno - GP_REG_FIRST); } } /* We need to restore these for the handler. */ if (current_function_calls_eh_return) { unsigned int i; for (i = 0; ; ++i) { regno = EH_RETURN_DATA_REGNO (i); if (regno == (int) INVALID_REGNUM) break; gp_reg_size += GET_MODE_SIZE (gpr_mode); mask |= 1L << (regno - GP_REG_FIRST); } } fp_inc = 2; fp_bits = 3; gp_reg_rounded = IQ2000_STACK_ALIGN (gp_reg_size); total_size += gp_reg_rounded + IQ2000_STACK_ALIGN (fp_reg_size); /* The gp reg is caller saved, so there is no need for leaf routines (total_size == extra_size) to save the gp reg. */ if (total_size == extra_size && ! profile_flag) total_size = extra_size = 0; total_size += IQ2000_STACK_ALIGN (current_function_pretend_args_size); /* Save other computed information. */ cfun->machine->total_size = total_size; cfun->machine->var_size = var_size; cfun->machine->args_size = args_size; cfun->machine->extra_size = extra_size; cfun->machine->gp_reg_size = gp_reg_size; cfun->machine->fp_reg_size = fp_reg_size; cfun->machine->mask = mask; cfun->machine->initialized = reload_completed; cfun->machine->num_gp = gp_reg_size / UNITS_PER_WORD; if (mask) { unsigned long offset; offset = (args_size + extra_size + var_size + gp_reg_size - GET_MODE_SIZE (gpr_mode)); cfun->machine->gp_sp_offset = offset; cfun->machine->gp_save_offset = offset - total_size; } else { cfun->machine->gp_sp_offset = 0; cfun->machine->gp_save_offset = 0; } cfun->machine->fp_sp_offset = 0; cfun->machine->fp_save_offset = 0; /* Ok, we're done. */ return total_size;}/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame pointer, argument pointer, or return address pointer. TO is either the stack pointer or hard frame pointer. */intiq2000_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED){ int offset; compute_frame_size (get_frame_size ()); if ((from) == FRAME_POINTER_REGNUM) (offset) = 0; else if ((from) == ARG_POINTER_REGNUM) (offset) = (cfun->machine->total_size); else if ((from) == RETURN_ADDRESS_POINTER_REGNUM) { if (leaf_function_p ()) (offset) = 0; else (offset) = cfun->machine->gp_sp_offset + ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)) * (BYTES_BIG_ENDIAN != 0)); } return offset;}/* Common code to emit the insns (or to write the instructions to a file) to save/restore registers. Other parts of the code assume that IQ2000_TEMP1_REGNUM (aka large_reg) is not modified within save_restore_insns. */#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)/* Emit instructions to load the value (SP + OFFSET) into IQ2000_TEMP2_REGNUM and return an rtl expression for the register. Write the assembly instructions directly to FILE if it is not null, otherwise emit them as rtl. This function is a subroutine of save_restore_insns. It is used when OFFSET is too large to add in a single instruction. */static rtxiq2000_add_large_offset_to_sp (HOST_WIDE_INT offset){ rtx reg = gen_rtx_REG (Pmode, IQ2000_TEMP2_REGNUM); rtx offset_rtx = GEN_INT (offset); emit_move_insn (reg, offset_rtx); emit_insn (gen_addsi3 (reg, reg, stack_pointer_rtx)); return reg;}/* Make INSN frame related and note that it performs the frame-related operation DWARF_PATTERN. */static voidiq2000_annotate_frame_insn (rtx insn, rtx dwarf_pattern){ RTX_FRAME_RELATED_P (insn) = 1; REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf_pattern, REG_NOTES (insn));}/* Emit a move instruction that stores REG in MEM. Make the instruction frame related and note that it stores REG at (SP + OFFSET). */static voidiq2000_emit_frame_related_store (rtx mem, rtx reg, HOST_WIDE_INT offset){ rtx dwarf_address = plus_constant (stack_pointer_rtx, offset); rtx dwarf_mem = gen_rtx_MEM (GET_MODE (reg), dwarf_address); iq2000_annotate_frame_insn (emit_move_insn (mem, reg), gen_rtx_SET (GET_MODE (reg), dwarf_mem, reg));}/* Emit instructions to save/restore registers, as determined by STORE_P. */static voidsave_restore_insns (int store_p){ long mask = cfun->machine->mask; int regno; rtx base_reg_rtx; HOST_WIDE_INT base_offset; HOST_WIDE_INT gp_offset; HOST_WIDE_INT end_offset; gcc_assert (!frame_pointer_needed || BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST)); if (mask == 0) { base_reg_rtx = 0, base_offset = 0; return; } /* Save registers starting from high to low. The debuggers prefer at least the return register be stored at func+4, and also it allows us not to need a nop in the epilog if at least one register is reloaded in addition to return address. */ /* Save GP registers if needed. */ /* Pick which pointer to use as a base register. For small frames, just use the stack pointer. Otherwise, use a temporary register. Save 2 cycles if the save area is near the end of a large frame, by reusing the constant created in the prologue/epilogue to adjust the stack frame. */ gp_offset = cfun->machine->gp_sp_offset; end_offset = gp_offset - (cfun->machine->gp_reg_size - GET_MODE_SIZE (gpr_mode)); if (gp_offset < 0 || end_offset < 0) internal_error ("gp_offset (%ld) or end_offset (%ld) is less than zero", (long) gp_offset, (long) end_offset); else if (gp_offset < 32768) base_reg_rtx = stack_pointer_rtx, base_offset = 0; else { int regno; int reg_save_count = 0; for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) if (BITSET_P (mask, regno - GP_REG_FIRST)) reg_save_count += 1; base_offset = gp_offset - ((reg_save_count - 1) * 4); base_reg_rtx = iq2000_add_large_offset_to_sp (base_offset); } for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) { if (BITSET_P (mask, regno - GP_REG_FIRST)) { rtx reg_rtx; rtx mem_rtx = gen_rtx_MEM (gpr_mode, gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset - base_offset))); reg_rtx = gen_rtx_REG (gpr_mode, regno); if (store_p) iq2000_emit_frame_related_store (mem_rtx, reg_rtx, gp_offset); else { emit_move_insn (reg_rtx, mem_rtx); } gp_offset -= GET_MODE_SIZE (gpr_mode); } }}/* Expand the prologue into a bunch of separate insns. */voidiq2000_expand_prologue (void){ int regno; HOST_WIDE_INT tsize; int last_arg_is_vararg_marker = 0; tree fndecl = current_function_decl; tree fntype = TREE_TYPE (fndecl); tree fnargs = DECL_ARGUMENTS (fndecl); rtx next_arg_reg; int i; tree next_arg; tree cur_arg; CUMULATIVE_ARGS args_so_far; int store_args_on_stack = (iq2000_can_use_return_insn ()); /* If struct value address is treated as the first argument. */ if (aggregate_value_p (DECL_RESULT (fndecl), fndecl) && ! current_function_returns_pcc_struct && targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0) { tree type = build_pointer_type (fntype); tree function_result_decl = build_decl (PARM_DECL, NULL_TREE, type); DECL_ARG_TYPE (function_result_decl) = type; TREE_CHAIN (function_result_decl) = fnargs; fnargs = function_result_decl; } /* For arguments passed in registers, find the register number of the first argument in the variable part of the argument list, otherwise GP_ARG_LAST+1. Note also if the last argument is the varargs special argument, and treat it as part of the variable arguments. This is only needed if store_args_on_stack is true. */ INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0); regno = GP_ARG_FIRST; for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg) { tree passed_type = DECL_ARG_TYPE (cur_arg); enum machine_mode passed_mode = TYPE_MODE (passed_type); rtx entry_parm; if (TREE_ADDRESSABLE (passed_type)) { passed_type = build_pointer_type (passed_type); passed_mode = Pmode; } entry_parm = FUNCTION_ARG (args_so_far, passed_mode, passed_type, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -