⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xtensa.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
  int regbase, words, max;  int *arg_words;  int regno;  arg_words = &cum->arg_words;  regbase = (incoming_p ? GP_ARG_FIRST : GP_OUTGOING_ARG_FIRST);  max = MAX_ARGS_IN_REGISTERS;  words = (((mode != BLKmode)	    ? (int) GET_MODE_SIZE (mode)	    : int_size_in_bytes (type)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;  if (type && (TYPE_ALIGN (type) > BITS_PER_WORD))    {      int align = TYPE_ALIGN (type) / BITS_PER_WORD;      *arg_words = (*arg_words + align - 1) & -align;    }  if (*arg_words + words > max)    return (rtx)0;  regno = regbase + *arg_words;  if (cum->incoming && regno <= A7_REG && regno + words > A7_REG)    cfun->machine->need_a7_copy = true;  return gen_rtx_REG (mode, regno);}static boolxtensa_return_in_msb (tree valtype){  return (TARGET_BIG_ENDIAN	  && AGGREGATE_TYPE_P (valtype)	  && int_size_in_bytes (valtype) >= UNITS_PER_WORD);}voidoverride_options (void){  int regno;  enum machine_mode mode;  if (!TARGET_BOOLEANS && TARGET_HARD_FLOAT)    error ("boolean registers required for the floating-point option");  xtensa_char_to_class['q'] = SP_REG;  xtensa_char_to_class['a'] = GR_REGS;  xtensa_char_to_class['b'] = ((TARGET_BOOLEANS) ? BR_REGS : NO_REGS);  xtensa_char_to_class['f'] = ((TARGET_HARD_FLOAT) ? FP_REGS : NO_REGS);  xtensa_char_to_class['A'] = ((TARGET_MAC16) ? ACC_REG : NO_REGS);  xtensa_char_to_class['B'] = ((TARGET_SEXT) ? GR_REGS : NO_REGS);  xtensa_char_to_class['C'] = ((TARGET_MUL16) ? GR_REGS: NO_REGS);  xtensa_char_to_class['D'] = ((TARGET_DENSITY) ? GR_REGS: NO_REGS);  xtensa_char_to_class['d'] = ((TARGET_DENSITY) ? AR_REGS: NO_REGS);  xtensa_char_to_class['W'] = ((TARGET_CONST16) ? GR_REGS: NO_REGS);  /* Set up array giving whether a given register can hold a given mode.  */  for (mode = VOIDmode;       mode != MAX_MACHINE_MODE;       mode = (enum machine_mode) ((int) mode + 1))    {      int size = GET_MODE_SIZE (mode);      enum mode_class class = GET_MODE_CLASS (mode);      for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)	{	  int temp;	  if (ACC_REG_P (regno))	    temp = (TARGET_MAC16		    && (class == MODE_INT) && (size <= UNITS_PER_WORD));	  else if (GP_REG_P (regno))	    temp = ((regno & 1) == 0 || (size <= UNITS_PER_WORD));	  else if (FP_REG_P (regno))	    temp = (TARGET_HARD_FLOAT && (mode == SFmode));	  else if (BR_REG_P (regno))	    temp = (TARGET_BOOLEANS && (mode == CCmode));	  else	    temp = FALSE;	  xtensa_hard_regno_mode_ok[(int) mode][regno] = temp;	}    }  init_machine_status = xtensa_init_machine_status;  /* Check PIC settings.  PIC is only supported when using L32R     instructions, and some targets need to always use PIC.  */  if (flag_pic && TARGET_CONST16)    error ("-f%s is not supported with CONST16 instructions",	   (flag_pic > 1 ? "PIC" : "pic"));  else if (XTENSA_ALWAYS_PIC)    {      if (TARGET_CONST16)	error ("PIC is required but not supported with CONST16 instructions");      flag_pic = 1;    }  /* There's no need for -fPIC (as opposed to -fpic) on Xtensa.  */  if (flag_pic > 1)    flag_pic = 1;  /* Hot/cold partitioning does not work on this architecture, because of     constant pools (the load instruction cannot necessarily reach that far).     Therefore disable it on this architecture.  */  if (flag_reorder_blocks_and_partition)    {      flag_reorder_blocks_and_partition = 0;      flag_reorder_blocks = 1;    }}/* A C compound statement to output to stdio stream STREAM the   assembler syntax for an instruction operand X.  X is an RTL   expression.   CODE is a value that can be used to specify one of several ways   of printing the operand.  It is used when identical operands   must be printed differently depending on the context.  CODE   comes from the '%' specification that was used to request   printing of the operand.  If the specification was just '%DIGIT'   then CODE is 0; if the specification was '%LTR DIGIT' then CODE   is the ASCII code for LTR.   If X is a register, this macro should print the register's name.   The names can be found in an array 'reg_names' whose type is   'char *[]'.  'reg_names' is initialized from 'REGISTER_NAMES'.   When the machine description has a specification '%PUNCT' (a '%'   followed by a punctuation character), this macro is called with   a null pointer for X and the punctuation character for CODE.   'a', 'c', 'l', and 'n' are reserved.   The Xtensa specific codes are:   'd'  CONST_INT, print as signed decimal   'x'  CONST_INT, print as signed hexadecimal   'K'  CONST_INT, print number of bits in mask for EXTUI   'R'  CONST_INT, print (X & 0x1f)   'L'  CONST_INT, print ((32 - X) & 0x1f)   'D'  REG, print second register of double-word register operand   'N'  MEM, print address of next word following a memory operand   'v'  MEM, if memory reference is volatile, output a MEMW before it   't'  any constant, add "@h" suffix for top 16 bits   'b'  any constant, add "@l" suffix for bottom 16 bits*/static voidprintx (FILE *file, signed int val){  /* Print a hexadecimal value in a nice way.  */  if ((val > -0xa) && (val < 0xa))    fprintf (file, "%d", val);  else if (val < 0)    fprintf (file, "-0x%x", -val);  else    fprintf (file, "0x%x", val);}voidprint_operand (FILE *file, rtx x, int letter){  if (!x)    error ("PRINT_OPERAND null pointer");  switch (letter)    {    case 'D':      if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)	fprintf (file, "%s", reg_names[xt_true_regnum (x) + 1]);      else	output_operand_lossage ("invalid %%D value");      break;    case 'v':      if (GET_CODE (x) == MEM)	{	  /* For a volatile memory reference, emit a MEMW before the	     load or store.  */	  if (MEM_VOLATILE_P (x))	    fprintf (file, "memw\n\t");	}      else	output_operand_lossage ("invalid %%v value");      break;    case 'N':      if (GET_CODE (x) == MEM	  && (GET_MODE (x) == DFmode || GET_MODE (x) == DImode))	{	  x = adjust_address (x, GET_MODE (x) == DFmode ? SFmode : SImode, 4);	  output_address (XEXP (x, 0));	}      else	output_operand_lossage ("invalid %%N value");      break;    case 'K':      if (GET_CODE (x) == CONST_INT)	{	  int num_bits = 0;	  unsigned val = INTVAL (x);	  while (val & 1)	    {	      num_bits += 1;	      val = val >> 1;	    }	  if ((val != 0) || (num_bits == 0) || (num_bits > 16))	    fatal_insn ("invalid mask", x);	  fprintf (file, "%d", num_bits);	}      else	output_operand_lossage ("invalid %%K value");      break;    case 'L':      if (GET_CODE (x) == CONST_INT)	fprintf (file, "%ld", (32 - INTVAL (x)) & 0x1f);      else	output_operand_lossage ("invalid %%L value");      break;    case 'R':      if (GET_CODE (x) == CONST_INT)	fprintf (file, "%ld", INTVAL (x) & 0x1f);      else	output_operand_lossage ("invalid %%R value");      break;    case 'x':      if (GET_CODE (x) == CONST_INT)	printx (file, INTVAL (x));      else	output_operand_lossage ("invalid %%x value");      break;    case 'd':      if (GET_CODE (x) == CONST_INT)	fprintf (file, "%ld", INTVAL (x));      else	output_operand_lossage ("invalid %%d value");      break;    case 't':    case 'b':      if (GET_CODE (x) == CONST_INT)	{	  printx (file, INTVAL (x));	  fputs (letter == 't' ? "@h" : "@l", file);	}      else if (GET_CODE (x) == CONST_DOUBLE)	{	  REAL_VALUE_TYPE r;	  REAL_VALUE_FROM_CONST_DOUBLE (r, x);	  if (GET_MODE (x) == SFmode)	    {	      long l;	      REAL_VALUE_TO_TARGET_SINGLE (r, l);	      fprintf (file, "0x%08lx@%c", l, letter == 't' ? 'h' : 'l');	    }	  else	    output_operand_lossage ("invalid %%t/%%b value");	}      else if (GET_CODE (x) == CONST)	{	  /* X must be a symbolic constant on ELF.  Write an expression	     suitable for 'const16' that sets the high or low 16 bits.  */	  if (GET_CODE (XEXP (x, 0)) != PLUS	      || (GET_CODE (XEXP (XEXP (x, 0), 0)) != SYMBOL_REF		  && GET_CODE (XEXP (XEXP (x, 0), 0)) != LABEL_REF)	      || GET_CODE (XEXP (XEXP (x, 0), 1)) != CONST_INT)	    output_operand_lossage ("invalid %%t/%%b value");	  print_operand (file, XEXP (XEXP (x, 0), 0), 0);	  fputs (letter == 't' ? "@h" : "@l", file);	  /* There must be a non-alphanumeric character between 'h' or 'l'	     and the number.  The '-' is added by print_operand() already.  */	  if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)	    fputs ("+", file);	  print_operand (file, XEXP (XEXP (x, 0), 1), 0);	}      else	{	  output_addr_const (file, x);	  fputs (letter == 't' ? "@h" : "@l", file);	}      break;    default:      if (GET_CODE (x) == REG || GET_CODE (x) == SUBREG)	fprintf (file, "%s", reg_names[xt_true_regnum (x)]);      else if (GET_CODE (x) == MEM)	output_address (XEXP (x, 0));      else if (GET_CODE (x) == CONST_INT)	fprintf (file, "%ld", INTVAL (x));      else	output_addr_const (file, x);    }}/* A C compound statement to output to stdio stream STREAM the   assembler syntax for an instruction operand that is a memory   reference whose address is ADDR.  ADDR is an RTL expression.  */voidprint_operand_address (FILE *file, rtx addr){  if (!addr)    error ("PRINT_OPERAND_ADDRESS, null pointer");  switch (GET_CODE (addr))    {    default:      fatal_insn ("invalid address", addr);      break;    case REG:      fprintf (file, "%s, 0", reg_names [REGNO (addr)]);      break;    case PLUS:      {	rtx reg = (rtx)0;	rtx offset = (rtx)0;	rtx arg0 = XEXP (addr, 0);	rtx arg1 = XEXP (addr, 1);	if (GET_CODE (arg0) == REG)	  {	    reg = arg0;	    offset = arg1;	  }	else if (GET_CODE (arg1) == REG)	  {	    reg = arg1;	    offset = arg0;	  }	else	  fatal_insn ("no register in address", addr);	if (CONSTANT_P (offset))	  {	    fprintf (file, "%s, ", reg_names [REGNO (reg)]);	    output_addr_const (file, offset);	  }	else	  fatal_insn ("address offset not a constant", addr);      }      break;    case LABEL_REF:    case SYMBOL_REF:    case CONST_INT:    case CONST:      output_addr_const (file, addr);      break;    }}voidxtensa_output_literal (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:      gcc_assert (GET_CODE (x) == CONST_DOUBLE);      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:	  gcc_unreachable ();	}      break;    case MODE_INT:    case MODE_PARTIAL_INT:      size = GET_MODE_SIZE (mode);      switch (size)	{	case 4:	  output_addr_const (file, x);	  fputs ("\n", file);	  break;	case 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);	  break;	default:	  gcc_unreachable ();	}      break;    default:      gcc_unreachable ();    }}/* 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 (int size){  /* Add space for the incoming static chain value.  */  if (cfun->static_chain_decl != NULL)    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 (void){  /* 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_expand_prologue (void){  HOST_WIDE_INT total_size;  rtx size_rtx;  total_size = compute_frame_size (get_frame_size ());  size_rtx = GEN_INT (total_size);  if (total_size < (1 << (12+3)))    emit_insn (gen_entry (size_rtx, size_rtx));  else    {      /* Use a8 as a temporary since a0-a7 may be live.  */      rtx tmp_reg = gen_rtx_REG (Pmode, A8_REG);      emit_insn (gen_entry (size_rtx, GEN_INT (MIN_FRAME_SIZE)));      emit_move_insn (tmp_reg, GEN_INT (total_size - MIN_FRAME_SIZE));      emit_insn (gen_subsi3 (tmp_reg, stack_pointer_rtx, tmp_reg));      emit_move_insn (stack_pointer_rtx, tmp_reg);    }  if (frame_pointer_needed)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -