📄 iq2000.c
字号:
|| ! host_integerp (TYPE_SIZE_UNIT (type), 1)) ret = gen_rtx_REG (mode, regbase + *arg_words + bias); else { tree field; for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD && host_integerp (bit_position (field), 0) && int_bit_position (field) % BITS_PER_WORD == 0) break; /* If the whole struct fits a DFmode register, we don't need the PARALLEL. */ if (! field || mode == DFmode) ret = gen_rtx_REG (mode, regbase + *arg_words + bias); else { unsigned int chunks; HOST_WIDE_INT bitpos; unsigned int regno; unsigned int i; /* ??? If this is a packed structure, then the last hunk won't be 64 bits. */ chunks = tree_low_cst (TYPE_SIZE_UNIT (type), 1) / UNITS_PER_WORD; if (chunks + *arg_words + bias > (unsigned) MAX_ARGS_IN_REGISTERS) chunks = MAX_ARGS_IN_REGISTERS - *arg_words - bias; /* Assign_parms checks the mode of ENTRY_PARM, so we must use the actual mode here. */ ret = gen_rtx_PARALLEL (mode, rtvec_alloc (chunks)); bitpos = 0; regno = regbase + *arg_words + bias; field = TYPE_FIELDS (type); for (i = 0; i < chunks; i++) { rtx reg; for (; field; field = TREE_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && int_bit_position (field) >= bitpos) break; if (field && int_bit_position (field) == bitpos && TREE_CODE (TREE_TYPE (field)) == REAL_TYPE && TYPE_PRECISION (TREE_TYPE (field)) == BITS_PER_WORD) reg = gen_rtx_REG (DFmode, regno++); else reg = gen_rtx_REG (word_mode, regno); XVECEXP (ret, 0, i) = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (bitpos / BITS_PER_UNIT)); bitpos += 64; regno++; } } } if (TARGET_DEBUG_D_MODE) fprintf (stderr, "%s%s\n", reg_names[regbase + *arg_words + bias], struct_p ? ", [struct]" : ""); } /* We will be called with a mode of VOIDmode after the last argument has been seen. Whatever we return will be passed to the call insn. If we need any shifts for small structures, return them in a PARALLEL. */ if (mode == VOIDmode) { if (cum->num_adjusts > 0) ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code, gen_rtvec_v (cum->num_adjusts, cum->adjust)); } return ret;}static intiq2000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED){ if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1) { if (TARGET_DEBUG_D_MODE) fprintf (stderr, "iq2000_arg_partial_bytes=%d\n", UNITS_PER_WORD); return UNITS_PER_WORD; } return 0;}/* Implement va_start. */voidiq2000_va_start (tree valist, rtx nextarg){ int int_arg_words; /* Find out how many non-float named formals. */ int gpr_save_area_size; /* Note UNITS_PER_WORD is 4 bytes. */ int_arg_words = current_function_args_info.arg_words; if (int_arg_words < 8 ) /* Adjust for the prologue's economy measure. */ gpr_save_area_size = (8 - int_arg_words) * UNITS_PER_WORD; else gpr_save_area_size = 0; /* Everything is in the GPR save area, or in the overflow area which is contiguous with it. */ nextarg = plus_constant (nextarg, - gpr_save_area_size); std_expand_builtin_va_start (valist, nextarg);}/* Allocate a chunk of memory for per-function machine-dependent data. */static struct machine_function *iq2000_init_machine_status (void){ struct machine_function *f; f = ggc_alloc_cleared (sizeof (struct machine_function)); return f;}static enum processor_typeiq2000_parse_cpu (const char * cpu_string){ const char *p = cpu_string; enum processor_type cpu; cpu = PROCESSOR_DEFAULT; switch (p[2]) { case '1': if (!strcmp (p, "iq10")) cpu = PROCESSOR_IQ10; break; case '2': if (!strcmp (p, "iq2000")) cpu = PROCESSOR_IQ2000; break; } return cpu;}/* Detect any conflicts in the switches. */voidoverride_options (void){ enum processor_type iq2000_cpu; target_flags &= ~MASK_GPOPT; iq2000_isa = IQ2000_ISA_DEFAULT; /* Identify the processor type. */ if (iq2000_cpu_string != 0) { iq2000_cpu = iq2000_parse_cpu (iq2000_cpu_string); if (iq2000_cpu == PROCESSOR_DEFAULT) { error ("bad value (%s) for -mcpu= switch", iq2000_arch_string); iq2000_cpu_string = "default"; } iq2000_arch = iq2000_cpu; iq2000_tune = iq2000_cpu; } if (iq2000_arch_string == 0 || ! strcmp (iq2000_arch_string, "default") || ! strcmp (iq2000_arch_string, "DEFAULT")) { switch (iq2000_isa) { default: iq2000_arch_string = "iq2000"; iq2000_arch = PROCESSOR_IQ2000; break; } } else { iq2000_arch = iq2000_parse_cpu (iq2000_arch_string); if (iq2000_arch == PROCESSOR_DEFAULT) { error ("bad value (%s) for -march= switch", iq2000_arch_string); iq2000_arch_string = "default"; } if (iq2000_arch == PROCESSOR_IQ10) { error ("The compiler does not support -march=%s.", iq2000_arch_string); iq2000_arch_string = "default"; } } 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -