📄 i960.c
字号:
/* Modes for quad-word quantities. */#define T_MODES (~C_MODES)/* Modes for single-float quantities. */#define SF_MODES ((1 << (int) SFmode))/* Modes for double-float quantities. */#define DF_MODES (SF_MODES | (1 << (int) DFmode) | (1 << (int) SCmode))/* Modes for quad-float quantities. */#define XF_MODES (DF_MODES | (1 << (int) XFmode) | (1 << (int) DCmode))unsigned int hard_regno_mode_ok[FIRST_PSEUDO_REGISTER] = { T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, XF_MODES, XF_MODES, XF_MODES, XF_MODES, C_MODES};/* Return the minimum alignment of an expression rtx X in bytes. This takes advantage of machine specific facts, such as knowing that the frame pointer is always 16 byte aligned. */inti960_expr_alignment (x, size) rtx x; int size;{ int align = 1; if (x == 0) return 1; switch (GET_CODE(x)) { case CONST_INT: align = INTVAL(x); if ((align & 0xf) == 0) align = 16; else if ((align & 0x7) == 0) align = 8; else if ((align & 0x3) == 0) align = 4; else if ((align & 0x1) == 0) align = 2; else align = 1; break; case PLUS: align = MIN (i960_expr_alignment (XEXP (x, 0), size), i960_expr_alignment (XEXP (x, 1), size)); break; case SYMBOL_REF: /* If this is a valid program, objects are guaranteed to be correctly aligned for whatever size the reference actually is. */ align = i960_object_bytes_bitalign (size) / BITS_PER_UNIT; break; case REG: if (REGNO (x) == FRAME_POINTER_REGNUM) align = 16; break; case ASHIFT: align = i960_expr_alignment (XEXP (x, 0)); if (GET_CODE (XEXP (x, 1)) == CONST_INT) { align = align << INTVAL (XEXP (x, 1)); align = MIN (align, 16); } break; case MULT: align = (i960_expr_alignment (XEXP (x, 0), size) * i960_expr_alignment (XEXP (x, 1), size)); align = MIN (align, 16); break; } return align;}/* Return true if it is possible to reference both BASE and OFFSET, which have alignment at least as great as 4 byte, as if they had alignment valid for an object of size SIZE. */inti960_improve_align (base, offset, size) rtx base; rtx offset; int size;{ int i, j; /* We have at least a word reference to the object, so we know it has to be aligned at least to 4 bytes. */ i = MIN (i960_expr_alignment (base, 4), i960_expr_alignment (offset, 4)); i = MAX (i, 4); /* We know the size of the request. If strict align is not enabled, we can guess that the alignment is OK for the requested size. */ if (! TARGET_STRICT_ALIGN) if ((j = (i960_object_bytes_bitalign (size) / BITS_PER_UNIT)) > i) i = j; return (i >= size);}/* Return true if it is possible to access BASE and OFFSET, which have 4 byte (SImode) alignment as if they had 16 byte (TImode) alignment. */inti960_si_ti (base, offset) rtx base; rtx offset;{ return i960_improve_align (base, offset, 16);}/* Return true if it is possible to access BASE and OFFSET, which have 4 byte (SImode) alignment as if they had 8 byte (DImode) alignment. */inti960_si_di (base, offset) rtx base; rtx offset;{ return i960_improve_align (base, offset, 8);}/* Return raw values of size and alignment (in words) for the data type being accessed. These values will be rounded by the caller. */static void i960_arg_size_and_align (mode, type, size_out, align_out) enum machine_mode mode; tree type; int *size_out; int *align_out;{ int size, align; /* Use formal alignment requirements of type being passed, except make it at least a word. If we don't have a type, this is a library call, and the parm has to be of scalar type. In this case, consider its formal alignment requirement to be its size in words. */ if (mode == BLKmode) size = (int_size_in_bytes (type) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; else if (mode == VOIDmode) { /* End of parm list. */ assert (type != 0 && TYPE_MODE (type) == VOIDmode); size = 1; } else size = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if (type == 0) { /* ??? This is a hack to properly correct the alignment of XFmode values without affecting anything else. */ if (size == 3) align = 4; else align = size; } else if (TYPE_ALIGN (type) >= BITS_PER_WORD) align = TYPE_ALIGN (type) / BITS_PER_WORD; else align = 1; *size_out = size; *align_out = align;}/* On the 80960 the first 12 args are in registers and the rest are pushed. Any arg that is bigger than 4 words is placed on the stack and all subsequent arguments are placed on the stack. Additionally, parameters with an alignment requirement stronger than a word must be aligned appropriately. Note that this means that a 64 bit object with a 32 bit alignment is not 64 bit aligned and may be passed in an odd/even register pair. *//* Update CUM to advance past an argument described by MODE and TYPE. */voidi960_function_arg_advance (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named;{ int size, align; i960_arg_size_and_align (mode, type, &size, &align); if (size > 4 || cum->ca_nstackparms != 0 || (size + ROUND_PARM (cum->ca_nregparms, align)) > NPARM_REGS || MUST_PASS_IN_STACK (mode, type)) { /* Indicate that all the registers are in use, even if all are not, so va_start will compute the right value. */ cum->ca_nregparms = NPARM_REGS; cum->ca_nstackparms = ROUND_PARM (cum->ca_nstackparms, align) + size; } else cum->ca_nregparms = ROUND_PARM (cum->ca_nregparms, align) + size;}/* Return the register that the argument described by MODE and TYPE is passed in, or else return 0 if it is passed on the stack. */rtxi960_function_arg (cum, mode, type, named) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int named;{ rtx ret; int size, align; i960_arg_size_and_align (mode, type, &size, &align); if (size > 4 || cum->ca_nstackparms != 0 || (size + ROUND_PARM (cum->ca_nregparms, align)) > NPARM_REGS || MUST_PASS_IN_STACK (mode, type)) { cum->ca_nstackparms = ROUND_PARM (cum->ca_nstackparms, align); ret = 0; } else { cum->ca_nregparms = ROUND_PARM (cum->ca_nregparms, align); ret = gen_rtx (REG, mode, cum->ca_nregparms); } return ret;}/* Floating-point support. */voidi960_output_long_double (file, value) FILE *file; REAL_VALUE_TYPE value;{ long value_long[3]; char dstr[30]; REAL_VALUE_TO_TARGET_LONG_DOUBLE (value, value_long); REAL_VALUE_TO_DECIMAL (value, "%.20g", dstr); fprintf (file, "\t.word\t0x%08lx\t\t# %s\n\t.word\t0x%08lx\n\t.word\t0x%08lx\n", value_long[0], dstr, value_long[1], value_long[2]); fprintf (file, "\t.word\t0x0\n");}voidi960_output_double (file, value) FILE *file; REAL_VALUE_TYPE value;{ long value_long[2]; char dstr[30]; REAL_VALUE_TO_TARGET_DOUBLE (value, value_long); REAL_VALUE_TO_DECIMAL (value, "%.20g", dstr); fprintf (file, "\t.word\t0x%08lx\t\t# %s\n\t.word\t0x%08lx\n", value_long[0], dstr, value_long[1]);} voidi960_output_float (file, value) FILE *file; REAL_VALUE_TYPE value;{ long value_long; char dstr[30]; REAL_VALUE_TO_TARGET_SINGLE (value, value_long); REAL_VALUE_TO_DECIMAL (value, "%.12g", dstr); fprintf (file, "\t.word\t0x%08lx\t\t# %s (float)\n", value_long, dstr);}/* Return the number of bits that an object of size N bytes is aligned to. */inti960_object_bytes_bitalign (n) int n;{ if (n > 8) n = 128; else if (n > 4) n = 64; else if (n > 2) n = 32; else if (n > 1) n = 16; else n = 8; return n;}/* Compute the alignment for an aggregate type TSIZE. Alignment is MAX (greatest member alignment, MIN (pragma align, structure size alignment)). */inti960_round_align (align, tsize) int align; tree tsize;{ int new_align; if (TREE_CODE (tsize) != INTEGER_CST) return align; new_align = i960_object_bytes_bitalign (TREE_INT_CST_LOW (tsize) / BITS_PER_UNIT); /* Handle #pragma align. */ if (new_align > i960_maxbitalignment) new_align = i960_maxbitalignment; if (align < new_align) align = new_align; return align;}/* Do any needed setup for a varargs function. For the i960, we must create a register parameter block if one doesn't exist, and then copy all register parameters to memory. */voidi960_setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl) CUMULATIVE_ARGS *cum; enum machine_mode mode; tree type; int *pretend_size; int no_rtl;{ /* Note: for a varargs fn with only a va_alist argument, this is 0. */ int first_reg = cum->ca_nregparms; /* Copy only unnamed register arguments to memory. If there are any stack parms, there are no unnamed arguments in registers, and an argument block was already allocated by the caller. Remember that any arg bigger than 4 words is passed on the stack as are all subsequent args. If there are no stack arguments but there are exactly NPARM_REGS registers, either there were no extra arguments or the caller allocated an argument block. */ if (cum->ca_nstackparms == 0 && first_reg < NPARM_REGS && !no_rtl) { rtx label = gen_label_rtx (); rtx regblock; /* If arg_pointer_rtx == 0, no arguments were passed on the stack and we need to allocate a chunk to save the registers (if any arguments were passed on the stack the caller would allocate the 48 bytes as well). We must allocate all 48 bytes (12*4) because va_start assumes it. */ emit_insn (gen_cmpsi (arg_pointer_rtx, const0_rtx)); emit_jump_insn (gen_bne (label)); emit_insn (gen_rtx (SET, VOIDmode, arg_pointer_rtx, stack_pointer_rtx)); emit_insn (gen_rtx (SET, VOIDmode, stack_pointer_rtx, memory_address (SImode, plus_constant (stack_pointer_rtx, 48)))); emit_label (label); /* ??? Note that we unnecessarily store one extra register for stdarg fns. We could optimize this, but it's kept as for now. */ regblock = gen_rtx (MEM, BLKmode, plus_constant (arg_pointer_rtx, first_reg * 4)); move_block_from_reg (first_reg, regblock, NPARM_REGS - first_reg, (NPARM_REGS - first_reg) * UNITS_PER_WORD); }}/* Calculate the final size of the reg parm stack space for the current function, based on how many bytes would be allocated on the stack. */inti960_final_reg_parm_stack_space (const_size, var_size) int const_size; tree var_size;{ if (var_size || const_size > 48) return 48; else return 0;}/* Calculate the size of the reg parm stack space. This is a bit complicated on the i960. */inti960_reg_parm_stack_space (fndecl) tree fndecl;{ /* In this case, we are called from emit_library_call, and we don't need to pretend we have more space for parameters than what's apparent. */ if (fndecl == 0) return 0; /* In this case, we are called from locate_and_pad_parms when we're not IN_REGS, so we have an arg block. */ if (fndecl != current_function_decl) return 48; /* Otherwise, we have an arg block if the current function has more than 48 bytes of parameters. */ if (current_function_args_size != 0 || VARARGS_STDARG_FUNCTION (fndecl)) return 48; else return 0;}/* Return the register class of a scratch register needed to copy IN into or out of a register in CLASS in MODE. If it can be done directly, NO_REGS is returned. */enum reg_classsecondary_reload_class (class, mode, in) enum reg_class class; enum machine_mode mode; rtx in;{ int regno = -1; if (GET_CODE (in) == REG || GET_CODE (in) == SUBREG) regno = true_regnum (in); /* We can place anything into LOCAL_OR_GLOBAL_REGS and can put LOCAL_OR_GLOBAL_REGS into anything. */ if (class == LOCAL_OR_GLOBAL_REGS || class == LOCAL_REGS || class == GLOBAL_REGS || (regno >= 0 && regno < 32)) return NO_REGS; /* We can place any hard register, 0.0, and 1.0 into FP_REGS. */ if (class == FP_REGS && ((regno >= 0 && regno < FIRST_PSEUDO_REGISTER) || in == CONST0_RTX (mode) || in == CONST1_RTX (mode))) return NO_REGS; return LOCAL_OR_GLOBAL_REGS;}/* Look at the opcode P, and set i96_last_insn_type to indicate which function unit it executed on. *//* ??? This would make more sense as an attribute. */voidi960_scan_opcode (p) char *p;{ switch (*p) { case 'a': case 'd': case 'e': case 'm': case 'n': case 'o': case 'r': /* Ret is not actually of type REG, but it won't matter, because no insn will ever follow it. */ case 'u': case 'x': i960_last_insn_type = I_TYPE_REG; break; case 'b': if (p[1] == 'x' || p[3] == 'x') i960_last_insn_type = I_TYPE_MEM; i960_last_insn_type = I_TYPE_CTRL; break; case 'f': case 't': i960_last_insn_type = I_TYPE_CTRL; break; case 'c': if (p[1] == 'a') { if (p[4] == 'x') i960_last_insn_type = I_TYPE_MEM; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -