📄 alpha.c
字号:
value = CONST_DOUBLE_HIGH (x); for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++, value >>= 8) if (value & 0xff) mask |= (1 << (i + sizeof (int))); fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask & 0xff); } else if (GET_CODE (x) == CONST_INT) { HOST_WIDE_INT mask = 0, value = INTVAL (x); for (i = 0; i < 8; i++, value >>= 8) if (value & 0xff) mask |= (1 << i); fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask); } else output_operand_lossage ("invalid %%m value"); break; case 'M': /* 'b', 'w', or 'l' as the value of the constant. */ if (GET_CODE (x) != CONST_INT || (INTVAL (x) != 8 && INTVAL (x) != 16 && INTVAL (x) != 32)) output_operand_lossage ("invalid %%M value"); fprintf (file, "%s", INTVAL (x) == 8 ? "b" : INTVAL (x) == 16 ? "w" : "l"); break; case 'U': /* Similar, except do it from the mask. */ if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xff) fprintf (file, "b"); else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffff) fprintf (file, "w");#if HOST_BITS_PER_WIDE_INT == 32 else if (GET_CODE (x) == CONST_DOUBLE && CONST_DOUBLE_HIGH (x) == 0 && CONST_DOUBLE_LOW (x) == -1) fprintf (file, "l");#else else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff) fprintf (file, "l");#endif else output_operand_lossage ("invalid %%U value"); break; case 's': /* Write the constant value divided by 8. */ if (GET_CODE (x) != CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 && (INTVAL (x) & 7) != 8) output_operand_lossage ("invalid %%s value"); fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8); break; case 'S': /* Same, except compute (64 - c) / 8 */ if (GET_CODE (x) != CONST_INT && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64 && (INTVAL (x) & 7) != 8) output_operand_lossage ("invalid %%s value"); fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8); break; case 'C': case 'D': case 'c': case 'd': /* Write out comparison name. */ { enum rtx_code c = GET_CODE (x); if (GET_RTX_CLASS (c) != '<') output_operand_lossage ("invalid %%C value"); if (code == 'D') c = reverse_condition (c); else if (code == 'c') c = swap_condition (c); else if (code == 'd') c = swap_condition (reverse_condition (c)); if (c == LEU) fprintf (file, "ule"); else if (c == LTU) fprintf (file, "ult"); else fprintf (file, "%s", GET_RTX_NAME (c)); } break; case 'E': /* Write the divide or modulus operator. */ switch (GET_CODE (x)) { case DIV: fprintf (file, "div%s", GET_MODE (x) == SImode ? "l" : "q"); break; case UDIV: fprintf (file, "div%su", GET_MODE (x) == SImode ? "l" : "q"); break; case MOD: fprintf (file, "rem%s", GET_MODE (x) == SImode ? "l" : "q"); break; case UMOD: fprintf (file, "rem%su", GET_MODE (x) == SImode ? "l" : "q"); break; default: output_operand_lossage ("invalid %%E value"); break; } break; case 'A': /* Write "_u" for unaligned access. */ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND) fprintf (file, "_u"); break; case 0: if (GET_CODE (x) == REG) fprintf (file, "%s", reg_names[REGNO (x)]); else if (GET_CODE (x) == MEM) output_address (XEXP (x, 0)); else output_addr_const (file, x); break; default: output_operand_lossage ("invalid %%xn code"); }}/* Do what is necessary for `va_start'. The argument is ignored; We look at the current function to determine if stdarg or varargs is used and fill in an initial va_list. A pointer to this constructor is returned. */struct rtx_def *alpha_builtin_saveregs (arglist) tree arglist;{ rtx block, addr, dest, argsize; tree fntype = TREE_TYPE (current_function_decl); int stdarg = (TYPE_ARG_TYPES (fntype) != 0 && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype))) != void_type_node)); /* Compute the current position into the args, taking into account both registers and memory. Both of these are already included in NUM_ARGS. */ argsize = GEN_INT (NUM_ARGS * UNITS_PER_WORD); /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base up by 48, storing fp arg registers in the first 48 bytes, and the integer arg registers in the next 48 bytes. This is only done, however, if any integer registers need to be stored. If no integer registers need be stored, then we must subtract 48 in order to account for the integer arg registers which are counted in argsize above, but which are not actually stored on the stack. */ if (TARGET_OPEN_VMS) addr = plus_constant (virtual_incoming_args_rtx, NUM_ARGS <= 5 + stdarg ? UNITS_PER_WORD : - 6 * UNITS_PER_WORD); else addr = (NUM_ARGS <= 5 + stdarg ? plus_constant (virtual_incoming_args_rtx, 6 * UNITS_PER_WORD) : plus_constant (virtual_incoming_args_rtx, - (6 * UNITS_PER_WORD))); /* For VMS, we include the argsize, while on Unix, it's handled as a separate field. */ if (TARGET_OPEN_VMS) addr = plus_constant (addr, INTVAL (argsize)); addr = force_operand (addr, NULL_RTX);#ifdef POINTERS_EXTEND_UNSIGNED addr = convert_memory_address (ptr_mode, addr);#endif if (TARGET_OPEN_VMS) return addr; else { /* Allocate the va_list constructor */ block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD); RTX_UNCHANGING_P (block) = 1; RTX_UNCHANGING_P (XEXP (block, 0)) = 1; /* Store the address of the first integer register in the __base member. */ dest = change_address (block, ptr_mode, XEXP (block, 0)); emit_move_insn (dest, addr); if (flag_check_memory_usage) emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, dest, ptr_mode, GEN_INT (GET_MODE_SIZE (ptr_mode)), TYPE_MODE (sizetype), GEN_INT (MEMORY_USE_RW), TYPE_MODE (integer_type_node)); /* Store the argsize as the __va_offset member. */ dest = change_address (block, TYPE_MODE (integer_type_node), plus_constant (XEXP (block, 0), POINTER_SIZE/BITS_PER_UNIT)); emit_move_insn (dest, argsize); if (flag_check_memory_usage) emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3, dest, ptr_mode, GEN_INT (GET_MODE_SIZE (TYPE_MODE (integer_type_node))), TYPE_MODE (sizetype), GEN_INT (MEMORY_USE_RW), TYPE_MODE (integer_type_node)); /* Return the address of the va_list constructor, but don't put it in a register. Doing so would fail when not optimizing and produce worse code when optimizing. */ return XEXP (block, 0); }}#if OPEN_VMS#define REG_PV 27#define REG_RA 26#else#define REG_RA 26#endif/* Find the current function's return address. ??? It would be better to arrange things such that if we would ordinarily have been a leaf function and we didn't spill the hard reg that we wouldn't have to save the register in the prolog. But it's not clear how to get the right information at the right time. */static rtx alpha_return_addr_rtx;rtxalpha_return_addr (){ rtx ret; if ((ret = alpha_return_addr_rtx) == NULL) { alpha_return_addr_rtx = ret = gen_reg_rtx (Pmode); emit_insn_after (gen_rtx (SET, VOIDmode, ret, gen_rtx (REG, Pmode, REG_RA)), get_insns ()); } return ret;}/* This page contains routines that are used to determine what the function prologue and epilogue code will do and write them out. *//* Compute the size of the save area in the stack. */#if OPEN_VMS/* These variables are used for communication between the following functions. They indicate various things about the current function being compiled that are used to tell what kind of prologue, epilogue and procedure descriptior to generate. *//* Nonzero if we need a stack procedure. */static int is_stack_procedure;/* Register number (either FP or SP) that is used to unwind the frame. */static int unwind_regno;/* Register number used to save FP. We need not have one for RA since we don't modify it for register procedures. This is only defined for register frame procedures. */static int save_fp_regno;/* Register number used to reference objects off our PV. */static int base_regno;/* Compute register masks for saved registers. */static voidalpha_sa_mask (imaskP, fmaskP) unsigned long *imaskP; unsigned long *fmaskP;{ unsigned long imask = 0; unsigned long fmask = 0; int i; if (is_stack_procedure) imask |= (1L << HARD_FRAME_POINTER_REGNUM); /* One for every register we have to save. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i]) { if (i < 32) imask |= (1L << i); else fmask |= (1L << (i - 32)); } *imaskP = imask; *fmaskP = fmask; return;}intalpha_sa_size (){ int sa_size = 0; HOST_WIDE_INT stack_needed; int i; /* One for every register we have to save. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i]) sa_size++; /* Start by assuming we can use a register procedure if we don't make any calls (REG_RA not used) or need to save any registers and a stack procedure if we do. */ is_stack_procedure = regs_ever_live[REG_RA] || sa_size != 0; /* Decide whether to refer to objects off our PV via FP or PV. If we need need FP for something else or if we receive a nonlocal goto (which expects PV to contain the value), we must use PV. Otherwise, start by assuming we can use FP. */ base_regno = (frame_pointer_needed || current_function_has_nonlocal_label || is_stack_procedure || current_function_outgoing_args_size ? REG_PV : HARD_FRAME_POINTER_REGNUM); /* If we want to copy PV into FP, we need to find some register in which to save FP. */ save_fp_regno = -1; if (base_regno == HARD_FRAME_POINTER_REGNUM) for (i = 0; i < 32; i++) if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i]) save_fp_regno = i; if (save_fp_regno == -1) base_regno = REG_PV, is_stack_procedure = 1; /* Stack unwinding should be done via FP unless we use it for PV. */ unwind_regno = base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM; /* If this is a stack procedure, allow space for saving FP and RA. */ if (is_stack_procedure) sa_size += 2; return sa_size * 8;}intalpha_pv_save_size (){ alpha_sa_size (); return is_stack_procedure ? 8 : 0;}intalpha_using_fp (){ alpha_sa_size (); return unwind_regno == HARD_FRAME_POINTER_REGNUM;}#else /* ! OPEN_VMS */intalpha_sa_size (){ int size = 0; int i; for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i]) size++; /* If some registers were saved but not reg 26, reg 26 must also be saved, so leave space for it. */ if (size != 0 && ! regs_ever_live[26]) size++; /* Our size must be even (multiple of 16 bytes). */ if (size & 1) size ++; return size * 8;}#endif /* ! OPEN_VMS *//* Return 1 if this function can directly return via $26. */intdirect_return (){ return (! TARGET_OPEN_VMS && reload_completed && alpha_sa_size () == 0 && get_frame_size () == 0 && current_function_outgoing_args_size == 0 && current_function_pretend_args_size == 0);}/* Write a version stamp. Don't write anything if we are running as a cross-compiler. Otherwise, use the versions in /usr/include/stamp.h. */#if !defined(CROSS_COMPILE) && !defined(_WIN32) && !defined(__linux__) && !defined(VMS)#include <stamp.h>#endifvoidalpha_write_verstamp (file) FILE *file;{#ifdef MS_STAMP fprintf (file, "\t.verstamp %d %d\n", MS_STAMP, LS_STAMP);#endif}/* Write code to add constant C to register number IN_REG (possibly 31) and put the result into OUT_REG. Use TEMP_REG as a scratch register; usually this will be OUT_REG, but should not be if OUT_REG is STACK_POINTER_REGNUM, since it must be updated in a single instruction. Write the code to FILE. */static voidadd_long_const (file, c, in_reg, out_reg, temp_reg) FILE *file; HOST_WIDE_INT c; int in_reg, out_reg, temp_reg;{ HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000); HOST_WIDE_INT tmp1 = c - low; HOST_WIDE_INT high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000); HOST_WIDE_INT extra = 0; /* We don't have code to write out constants larger than 32 bits. */#if HOST_BITS_PER_LONG_INT == 64 if ((unsigned HOST_WIDE_INT) c >> 32 != 0) abort ();#endif /* If HIGH will be interpreted as negative, we must adjust it to do two ldha insns. Note that we will never be building a negative constant here. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -