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

📄 xtensa.c

📁 linux下编程用 编译软件
💻 C
📖 第 1 页 / 共 5 页
字号:
    default:      gcc_unreachable ();    }}/* Emit insns to move operands[1] into operands[0].   Return 1 if we have written out everything that needs to be done to   do the move.  Otherwise, return 0 and the caller will emit the move   normally.  */intxtensa_emit_move_sequence (rtx *operands, enum machine_mode mode){  if (CONSTANT_P (operands[1])      && (GET_CODE (operands[1]) != CONST_INT	  || !xtensa_simm12b (INTVAL (operands[1]))))    {      if (!TARGET_CONST16)	operands[1] = force_const_mem (SImode, operands[1]);      /* PC-relative loads are always SImode, and CONST16 is only	 supported in the movsi pattern, so add a SUBREG for any other	 (smaller) mode.  */      if (mode != SImode)	{	  if (register_operand (operands[0], mode))	    {	      operands[0] = simplify_gen_subreg (SImode, operands[0], mode, 0);	      emit_move_insn (operands[0], operands[1]);	      return 1;	    }	  else	    {	      operands[1] = force_reg (SImode, operands[1]);	      operands[1] = gen_lowpart_SUBREG (mode, operands[1]);	    }	}    }  if (!(reload_in_progress | reload_completed)      && !xtensa_valid_move (mode, operands))    operands[1] = force_reg (mode, operands[1]);  operands[1] = xtensa_copy_incoming_a7 (operands[1]);  /* During reload we don't want to emit (subreg:X (mem:Y)) since that     instruction won't be recognized after reload, so we remove the     subreg and adjust mem accordingly.  */  if (reload_in_progress)    {      operands[0] = fixup_subreg_mem (operands[0]);      operands[1] = fixup_subreg_mem (operands[1]);    }  return 0;}static rtxfixup_subreg_mem (rtx x){  if (GET_CODE (x) == SUBREG      && GET_CODE (SUBREG_REG (x)) == REG      && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)    {      rtx temp =	gen_rtx_SUBREG (GET_MODE (x),			reg_equiv_mem [REGNO (SUBREG_REG (x))],			SUBREG_BYTE (x));      x = alter_subreg (&temp);    }  return x;}/* Check if an incoming argument in a7 is expected to be used soon and   if OPND is a register or register pair that includes a7.  If so,   create a new pseudo and copy a7 into that pseudo at the very   beginning of the function, followed by the special "set_frame_ptr"   unspec_volatile insn.  The return value is either the original   operand, if it is not a7, or the new pseudo containing a copy of   the incoming argument.  This is necessary because the register   allocator will ignore conflicts with a7 and may either assign some   other pseudo to a7 or use a7 as the hard_frame_pointer, clobbering   the incoming argument in a7.  By copying the argument out of a7 as   the very first thing, and then immediately following that with an   unspec_volatile to keep the scheduler away, we should avoid any   problems.  Putting the set_frame_ptr insn at the beginning, with   only the a7 copy before it, also makes it easier for the prologue   expander to initialize the frame pointer after the a7 copy and to   fix up the a7 copy to use the stack pointer instead of the frame   pointer.  */rtxxtensa_copy_incoming_a7 (rtx opnd){  rtx entry_insns = 0;  rtx reg, tmp;  enum machine_mode mode;  if (!cfun->machine->need_a7_copy)    return opnd;  /* This function should never be called again once a7 has been copied.  */  gcc_assert (!cfun->machine->set_frame_ptr_insn);  mode = GET_MODE (opnd);  /* The operand using a7 may come in a later instruction, so just return     the original operand if it doesn't use a7.  */  reg = opnd;  if (GET_CODE (reg) == SUBREG)    {      gcc_assert (SUBREG_BYTE (reg) == 0);      reg = SUBREG_REG (reg);    }  if (GET_CODE (reg) != REG      || REGNO (reg) > A7_REG      || REGNO (reg) + HARD_REGNO_NREGS (A7_REG, mode) <= A7_REG)    return opnd;  /* 1-word args will always be in a7; 2-word args in a6/a7.  */  gcc_assert (REGNO (reg) + HARD_REGNO_NREGS (A7_REG, mode) - 1 == A7_REG);  cfun->machine->need_a7_copy = false;  /* Copy a7 to a new pseudo at the function entry.  Use gen_raw_REG to     create the REG for a7 so that hard_frame_pointer_rtx is not used.  */  push_to_sequence (entry_insns);  tmp = gen_reg_rtx (mode);  switch (mode)    {    case DFmode:    case DImode:      emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 0),				     gen_rtx_REG (SImode, A7_REG - 1)));      emit_insn (gen_movsi_internal (gen_rtx_SUBREG (SImode, tmp, 4),				     gen_raw_REG (SImode, A7_REG)));      break;    case SFmode:      emit_insn (gen_movsf_internal (tmp, gen_raw_REG (mode, A7_REG)));      break;    case SImode:      emit_insn (gen_movsi_internal (tmp, gen_raw_REG (mode, A7_REG)));      break;    case HImode:      emit_insn (gen_movhi_internal (tmp, gen_raw_REG (mode, A7_REG)));      break;    case QImode:      emit_insn (gen_movqi_internal (tmp, gen_raw_REG (mode, A7_REG)));      break;    default:      gcc_unreachable ();    }  cfun->machine->set_frame_ptr_insn = emit_insn (gen_set_frame_ptr ());  entry_insns = get_insns ();  end_sequence ();  if (cfun->machine->vararg_a7)    {      /* This is called from within builtin_savereg, so we're already	 inside a start_sequence that will be placed at the start of	 the function.  */      emit_insn (entry_insns);    }  else    {      /* Put entry_insns after the NOTE that starts the function.  If	 this is inside a start_sequence, make the outer-level insn	 chain current, so the code is placed at the start of the	 function.  */      push_topmost_sequence ();      emit_insn_after (entry_insns, get_insns ());      pop_topmost_sequence ();    }  return tmp;}/* Try to expand a block move operation to a sequence of RTL move   instructions.  If not optimizing, or if the block size is not a   constant, or if the block is too large, the expansion fails and GCC   falls back to calling memcpy().   operands[0] is the destination   operands[1] is the source   operands[2] is the length   operands[3] is the alignment */intxtensa_expand_block_move (rtx *operands){  static const enum machine_mode mode_from_align[] =  {    VOIDmode, QImode, HImode, VOIDmode, SImode,  };  rtx dst_mem = operands[0];  rtx src_mem = operands[1];  HOST_WIDE_INT bytes, align;  int num_pieces, move_ratio;  rtx temp[2];  enum machine_mode mode[2];  int amount[2];  bool active[2];  int phase = 0;  int next;  int offset_ld = 0;  int offset_st = 0;  rtx x;  /* If this is not a fixed size move, just call memcpy.  */  if (!optimize || (GET_CODE (operands[2]) != CONST_INT))    return 0;  bytes = INTVAL (operands[2]);  align = INTVAL (operands[3]);  /* Anything to move?  */  if (bytes <= 0)    return 0;  if (align > MOVE_MAX)    align = MOVE_MAX;  /* Decide whether to expand inline based on the optimization level.  */  move_ratio = 4;  if (optimize > 2)    move_ratio = LARGEST_MOVE_RATIO;  num_pieces = (bytes / align) + (bytes % align); /* Close enough anyway.  */  if (num_pieces > move_ratio)    return 0;  x = XEXP (dst_mem, 0);  if (!REG_P (x))    {      x = force_reg (Pmode, x);      dst_mem = replace_equiv_address (dst_mem, x);    }  x = XEXP (src_mem, 0);  if (!REG_P (x))    {      x = force_reg (Pmode, x);      src_mem = replace_equiv_address (src_mem, x);    }  active[0] = active[1] = false;  do    {      next = phase;      phase ^= 1;      if (bytes > 0)	{	  int next_amount;	  next_amount = (bytes >= 4 ? 4 : (bytes >= 2 ? 2 : 1));	  next_amount = MIN (next_amount, align);	  amount[next] = next_amount;	  mode[next] = mode_from_align[next_amount];	  temp[next] = gen_reg_rtx (mode[next]);	  x = adjust_address (src_mem, mode[next], offset_ld);	  emit_insn (gen_rtx_SET (VOIDmode, temp[next], x));	  offset_ld += next_amount;	  bytes -= next_amount;	  active[next] = true;	}      if (active[phase])	{	  active[phase] = false;	  	  x = adjust_address (dst_mem, mode[phase], offset_st);	  emit_insn (gen_rtx_SET (VOIDmode, x, temp[phase]));	  offset_st += amount[phase];	}    }  while (active[next]);  return 1;}voidxtensa_expand_nonlocal_goto (rtx *operands){  rtx goto_handler = operands[1];  rtx containing_fp = operands[3];  /* Generate a call to "__xtensa_nonlocal_goto" (in libgcc); the code     is too big to generate in-line.  */  if (GET_CODE (containing_fp) != REG)    containing_fp = force_reg (Pmode, containing_fp);  goto_handler = replace_rtx (copy_rtx (goto_handler),			      virtual_stack_vars_rtx,			      containing_fp);  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_nonlocal_goto"),		     0, VOIDmode, 2,		     containing_fp, Pmode,		     goto_handler, Pmode);}static struct machine_function *xtensa_init_machine_status (void){  return ggc_alloc_cleared (sizeof (struct machine_function));}voidxtensa_setup_frame_addresses (void){  /* Set flag to cause FRAME_POINTER_REQUIRED to be set.  */  cfun->machine->accesses_prev_frame = 1;  emit_library_call    (gen_rtx_SYMBOL_REF (Pmode, "__xtensa_libgcc_window_spill"),     0, VOIDmode, 0);}/* Emit the assembly for the end of a zero-cost loop.  Normally we just emit   a comment showing where the end of the loop is.  However, if there is a   label or a branch at the end of the loop then we need to place a nop   there.  If the loop ends with a label we need the nop so that branches   targeting that label will target the nop (and thus remain in the loop),   instead of targeting the instruction after the loop (and thus exiting   the loop).  If the loop ends with a branch, we need the nop in case the   branch is targeting a location inside the loop.  When the branch   executes it will cause the loop count to be decremented even if it is   taken (because it is the last instruction in the loop), so we need to   nop after the branch to prevent the loop count from being decremented   when the branch is taken.  */voidxtensa_emit_loop_end (rtx insn, rtx *operands){  char done = 0;  for (insn = PREV_INSN (insn); insn && !done; insn = PREV_INSN (insn))    {      switch (GET_CODE (insn))	{	case NOTE:	case BARRIER:	  break;	case CODE_LABEL:	  output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands);	  done = 1;	  break;	default:	  {	    rtx body = PATTERN (insn);	    if (GET_CODE (body) == JUMP_INSN)	      {		output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands);		done = 1;	      }	    else if ((GET_CODE (body) != USE)		     && (GET_CODE (body) != CLOBBER))	      done = 1;	  }	  break;        }    }  output_asm_insn ("# loop end for %0", operands);}char *xtensa_emit_call (int callop, rtx *operands){  static char result[64];  rtx tgt = operands[callop];  if (GET_CODE (tgt) == CONST_INT)    sprintf (result, "call8\t0x%lx", INTVAL (tgt));  else if (register_operand (tgt, VOIDmode))    sprintf (result, "callx8\t%%%d", callop);  else    sprintf (result, "call8\t%%%d", callop);  return result;}/* Return the debugger register number to use for 'regno'.  */intxtensa_dbx_register_number (int regno){  int first = -1;  if (GP_REG_P (regno))    {      regno -= GP_REG_FIRST;      first = 0;    }  else if (BR_REG_P (regno))    {      regno -= BR_REG_FIRST;      first = 16;    }  else if (FP_REG_P (regno))    {      regno -= FP_REG_FIRST;      first = 48;    }  else if (ACC_REG_P (regno))    {      first = 0x200;	/* Start of Xtensa special registers.  */      regno = 16;	/* ACCLO is special register 16.  */    }  /* When optimizing, we sometimes get asked about pseudo-registers     that don't represent hard registers.  Return 0 for these.  */  if (first == -1)    return 0;  return first + regno;}/* Argument support functions.  *//* Initialize CUMULATIVE_ARGS for a function.  */voidinit_cumulative_args (CUMULATIVE_ARGS *cum, int incoming){  cum->arg_words = 0;  cum->incoming = incoming;}/* Advance the argument to the next argument position.  */voidfunction_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type){  int words, max;  int *arg_words;  arg_words = &cum->arg_words;  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 (*arg_words < max      && (targetm.calls.must_pass_in_stack (mode, type)	  || *arg_words + words > max))    *arg_words = max;  *arg_words += words;}/* Return an RTL expression containing the register for the given mode,   or 0 if the argument is to be passed on the stack.  INCOMING_P is nonzero   if this is an incoming argument to the current function.  */rtxfunction_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,	      int incoming_p){

⌨️ 快捷键说明

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