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

📄 arm.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
  /* Try to use one MVN */  if (const_ok_for_arm(~n))    {      operands[1] = gen_rtx (CONST_INT, VOIDmode, ~n);      return (arm_output_asm_insn ("mvn\t%0, %1", operands));    }  /* If all else fails, make it out of ORRs or BICs as appropriate. */  for (i=0; i < 32; i++)    if (n & 1 << i)      n_ones++;  if (n_ones > 16)  /* Shorter to use MVN with BIC in this case. */    output_multi_immediate(operands, "mvn\t%0, %1", "bic\t%0, %0, %1", 1, ~n);  else    output_multi_immediate(operands, "mov\t%0, %1", "orr\t%0, %0, %1", 1, n);  return("");} /* output_mov_immediate *//* Output an ADD r, s, #n where n may be too big for one instruction.  If   adding zero to one register, output nothing.  */char *output_add_immediate (operands)     rtx operands[3];{  int n = INTVAL (operands[2]);  if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))    {      if (n < 0)	output_multi_immediate (operands,				"sub\t%0, %1, %2", "sub\t%0, %0, %2", 2, -n);      else	output_multi_immediate (operands,				"add\t%0, %1, %2", "add\t%0, %0, %2", 2, n);    }  return("");} /* output_add_immediate *//* Output a multiple immediate operation.   OPERANDS is the vector of operands referred to in the output patterns.   INSTR1 is the output pattern to use for the first constant.   INSTR2 is the output pattern to use for subsequent constants.   IMMED_OP is the index of the constant slot in OPERANDS.   N is the constant value.  */char *output_multi_immediate (operands, instr1, instr2, immed_op, n)     rtx operands[];     char *instr1, *instr2;     int immed_op, n;{  if (n == 0)    {      operands[immed_op] = const0_rtx;      arm_output_asm_insn (instr1, operands); /* Quick and easy output */    }  else    {      int i;      char *instr = instr1;      /* Note that n is never zero here (which would give no output) */      for (i = 0; i < 32; i += 2)	{	  if (n & (3 << i))	    {	      operands[immed_op] = gen_rtx (CONST_INT, VOIDmode,					    n & (255 << i));	      arm_output_asm_insn (instr, operands);	      instr = instr2;	      i += 6;	    }	}    }  return ("");} /* output_multi_immediate *//* Return the appropriate ARM instruction for the operation code.   The returned result should not be overwritten.  OP is the rtx of the   operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator   was shifted.  */char *arithmetic_instr (op, shift_first_arg)     rtx op;{  switch (GET_CODE(op))    {    case PLUS:      return ("add");    case MINUS:      if (shift_first_arg)	return ("rsb");      else	return ("sub");    case IOR:      return ("orr");    case XOR:      return ("eor");    case AND:      return ("and");    default:      abort();    }  return ("");			/* stupid cc */} /* arithmetic_instr *//* Ensure valid constant shifts and return the appropriate shift mnemonic   for the operation code.  The returned result should not be overwritten.   OP is the rtx code of the shift.   SHIFT_PTR points to the shift size operand.  */char *shift_instr (op, shift_ptr)     enum rtx_code op;     rtx *shift_ptr;{  int min_shift = 0;  int max_shift = 31;  char *mnem;  switch (op)    {    case ASHIFT:      mnem = "asl";      break;    case LSHIFT:      mnem = "lsl";      break;    case ASHIFTRT:      mnem = "asr";      max_shift = 32;      break;    case LSHIFTRT:      mnem = "lsr";      max_shift = 32;      break;    default:      abort();    }  if (GET_CODE (*shift_ptr) == CONST_INT)    {      int shift = INTVAL (*shift_ptr);      if (shift < min_shift)	*shift_ptr = gen_rtx (CONST_INT, VOIDmode, 0);      else if (shift > max_shift)	*shift_ptr = gen_rtx (CONST_INT, VOIDmode, max_shift);    }  return (mnem);} /* shift_instr *//* Obtain the shift from the POWER of two. */intint_log2 (power)     unsigned int power;{  int shift = 0;  while (((1 << shift) & power) == 0)    {      if (shift > 31)	abort();      shift++;    }  return (shift);} /* int_log2 *//* Output an arithmetic instruction which may set the condition code.   OPERANDS[0] is the destination register.   OPERANDS[1] is the arithmetic operator expression.   OPERANDS[2] is the left hand argument.   OPERANDS[3] is the right hand argument.   CONST_FIRST_ARG is TRUE if the first argument of the operator was constant.   SET_COND is TRUE when the condition code should be set.  */char *output_arithmetic (operands, const_first_arg, set_cond)     rtx operands[4];     int const_first_arg;     int set_cond;{  char mnemonic[80];  char *instr = arithmetic_instr (operands[1], const_first_arg);  sprintf (mnemonic, "%s%s\t%%0, %%2, %%3", instr, set_cond ? "s" : "");  return (arm_output_asm_insn (mnemonic, operands));} /* output_arithmetic *//* Output an arithmetic instruction with a shift.   OPERANDS[0] is the destination register.   OPERANDS[1] is the arithmetic operator expression.   OPERANDS[2] is the unshifted register.   OPERANDS[3] is the shift operator expression.   OPERANDS[4] is the shifted register.   OPERANDS[5] is the shift constant or register.   SHIFT_FIRST_ARG is TRUE if the first argument of the operator was shifted.   SET_COND is TRUE when the condition code should be set.  */char *output_arithmetic_with_shift (operands, shift_first_arg, set_cond)     rtx operands[6];     int shift_first_arg;     int set_cond;{  char mnemonic[80];  char *instr = arithmetic_instr (operands[1], shift_first_arg);  char *condbit = set_cond ? "s" : "";  char *shift = shift_instr (GET_CODE (operands[3]), &operands[5]);  sprintf (mnemonic, "%s%s\t%%0, %%2, %%4, %s %%5", instr, condbit, shift);  return (arm_output_asm_insn (mnemonic, operands));} /* output_arithmetic_with_shift *//* Output an arithmetic instruction with a power of two multiplication.   OPERANDS[0] is the destination register.   OPERANDS[1] is the arithmetic operator expression.   OPERANDS[2] is the unmultiplied register.   OPERANDS[3] is the multiplied register.   OPERANDS[4] is the constant multiple (power of two).   SHIFT_FIRST_ARG is TRUE if the first arg of the operator was multiplied.  */char *output_arithmetic_with_immediate_multiply (operands, shift_first_arg)     rtx operands[5];     int shift_first_arg;{  char mnemonic[80];  char *instr = arithmetic_instr (operands[1], shift_first_arg);  int shift = int_log2 (INTVAL (operands[4]));  sprintf (mnemonic, "%s\t%%0, %%2, %%3, asl#%d", instr, shift);  return (arm_output_asm_insn (mnemonic, operands));} /* output_arithmetic_with_immediate_multiply *//* Output a move with a shift.   OP is the shift rtx code.   OPERANDS[0] = destination register.   OPERANDS[1] = source register.   OPERANDS[2] = shift constant or register.  */char *output_shifted_move (op, operands)     enum rtx_code op;     rtx operands[2];{  char mnemonic[80];  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0)    sprintf (mnemonic, "mov\t%%0, %%1");  else    sprintf (mnemonic, "mov\t%%0, %%1, %s %%2",	     shift_instr (op, &operands[2]));  return (arm_output_asm_insn (mnemonic, operands));} /* output_shifted_move *//* Output a .ascii pseudo-op, keeping track of lengths.  This is because   /bin/as is horribly restrictive.  */voidoutput_ascii_pseudo_op (stream, p, len)     FILE *stream;     char *p;     int len;{  int i;  int len_so_far = 1000;  int chars_so_far = 0;  for (i = 0; i < len; i++)    {      register int c = p[i];      if (len_so_far > 50)	{	  if (chars_so_far)	    fputs ("\"\n", stream);	  fputs ("\t.ascii\t\"", stream);	  len_so_far = 0;	  arm_increase_location (chars_so_far);	  chars_so_far = 0;	}      if (c == '\"' || c == '\\')	{	  putc('\\', stream);	  len_so_far++;	}      if (c >= ' ' && c < 0177)	{	  putc (c, stream);	  len_so_far++;	}      else	{	  fprintf (stream, "\\%03o", c);	  len_so_far +=4;	}      chars_so_far++;    }  fputs ("\"\n", stream);  arm_increase_location (chars_so_far);} /* output_ascii_pseudo_op */voidoutput_prologue (f, frame_size)     FILE *f;     int frame_size;{  int reg, live_regs_mask = 0, code_size = 0;  rtx operands[3];  /* Nonzero if the `fp' (argument pointer) register is needed.  */  int fp_needed = 0;  /* Nonzero if we must stuff some register arguments onto the stack as if     they were passed there.  */  int store_arg_regs = 0;  fprintf (f, "\t@ args = %d, pretend = %d, frame = %d\n",	   current_function_args_size, current_function_pretend_args_size, frame_size);  fprintf (f, "\t@ frame_pointer_needed = %d, current_function_anonymous_args = %d\n",	   frame_pointer_needed, current_function_anonymous_args);  if (current_function_pretend_args_size || current_function_args_size      || frame_pointer_needed || current_function_anonymous_args || TARGET_APCS)    fp_needed = 1;  if (current_function_anonymous_args && current_function_pretend_args_size)    store_arg_regs = 1;  for (reg = 4; reg < 10; reg++)    if (regs_ever_live[reg])      live_regs_mask |= (1 << reg);  if (fp_needed)    {      live_regs_mask |= 0xD800;      /* The following statement is probably redundant now	 because the frame pointer is recorded in regs_ever_live.  */      if (frame_pointer_needed)	live_regs_mask |= (1 << FRAME_POINTER_REGNUM);      fputs ("\tmov\tip, sp\n", f);      code_size += 4;    }  else if (regs_ever_live[14])    live_regs_mask |= 0x4000;  /* If CURRENT_FUNCTION_PRETEND_ARGS_SIZE, adjust the stack pointer to make     room.  If also STORE_ARG_REGS store the argument registers involved in     the created slot (this is for stdarg and varargs).  */  if (current_function_pretend_args_size)    {      if (store_arg_regs)	{	  int arg_size, mask = 0;	  assert (current_function_pretend_args_size <= 16);	  for (reg = 3, arg_size = current_function_pretend_args_size;	       arg_size > 0; reg--, arg_size -= 4)	    mask |= (1 << reg);	  print_multi_reg (f, "stmfd\tsp!", mask, FALSE);	}      else	{	  operands[0] = operands[1] = stack_pointer_rtx;	  operands[2] = gen_rtx (CONST_INT, VOIDmode,				 -current_function_pretend_args_size);	  output_add_immediate (operands);	}    }  if (live_regs_mask)    {      print_multi_reg (f, "stmfd\tsp!", live_regs_mask, FALSE);      code_size += 4;    }  for (reg = 23; reg > 19; reg--)    if (regs_ever_live[reg])      {	fprintf (f, "\tstfe\t%s, [sp, #-12]!\n", reg_names[reg]);	code_size += 4;      }  if (fp_needed)    {      /* Make `fp' point to saved value of `pc'. */      operands[0] = arg_pointer_rtx;      operands[1] = gen_rtx (REG, SImode, 12);      operands[2] = gen_rtx (CONST_INT, VOIDmode,			     - (4 + current_function_pretend_args_size));      output_add_immediate (operands);    }  if (frame_pointer_needed)    {      fprintf (f, "\tmov\trfp, sp\n");      code_size += 4;    }  if (frame_size)    {      operands[0] = operands[1] = stack_pointer_rtx;      operands[2] = gen_rtx (CONST_INT, VOIDmode, -frame_size);      output_add_immediate (operands);    }  arm_increase_location (code_size);} /* output_prologue */voidoutput_epilogue (f, frame_size)     FILE *f;     int frame_size;{  int reg, live_regs_mask = 0, code_size = 0, fp_needed = 0;  rtx operands[3];  if (current_function_pretend_args_size || current_function_args_size      || frame_pointer_needed || current_function_anonymous_args || TARGET_APCS)    fp_needed = 1;  for (reg = 4; reg < 10; reg++)    if (regs_ever_live[reg])      live_regs_mask |= (1 << reg);

⌨️ 快捷键说明

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