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

📄 arm.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
  if (fp_needed)    {      live_regs_mask |= 0xA800;      if (frame_pointer_needed)        live_regs_mask |= (1 << FRAME_POINTER_REGNUM);    }  else if (regs_ever_live[14])    live_regs_mask |= 0x4000;  for (reg = 20; reg < 24; reg++)    if (regs_ever_live[reg])      {	fprintf (f, "\tldfe\t%s, [%s], #12\n", reg_names[reg],		 frame_pointer_needed ? "rfp" : "sp");	code_size += 4;      }  if (fp_needed)    {      print_multi_reg (f, "ldmea\tfp", live_regs_mask, TRUE);      code_size += 4;    }  else    {      /* Restore stack pointer if necessary.  */      if (frame_size)	{	  operands[0] = operands[1] = stack_pointer_rtx;	  operands[2] = gen_rtx (CONST_INT, VOIDmode, frame_size);	  output_add_immediate (operands);	}      if (current_function_pretend_args_size == 0 && regs_ever_live[14])	{	  print_multi_reg (f, "ldmfd\tsp!",			   (live_regs_mask & ~0x4000) | 0x8000, TRUE);	  code_size += 4;	}      else	{	  if (live_regs_mask)	    {	      print_multi_reg (f, "ldmfd\tsp!", live_regs_mask, FALSE);	      code_size += 4;	    }	  if (current_function_pretend_args_size)	    {	      operands[0] = operands[1] = stack_pointer_rtx;	      operands[2] = gen_rtx (CONST_INT, VOIDmode,				     current_function_pretend_args_size);	      output_add_immediate (operands);	    }	  fputs ("\tmovs\tpc, lr\n", f);	  code_size += 4;	}    }  arm_increase_location (code_size);  current_function_anonymous_args = 0;} /* output_epilogue *//* Increase the `arm_text_location' by AMOUNT if we're in the text   segment.  */voidarm_increase_location (amount)     int amount;{  if (in_text_section ())    arm_text_location += amount;} /* arm_increase_location *//* Like output_asm_insn (), but also increases the arm_text_location (if in   the .text segment, of course, even though this will always be true).   Returns the empty string.  */char *arm_output_asm_insn (template, operands)     char *template;     rtx *operands;{  extern FILE *asm_out_file;  output_asm_insn (template, operands);  if (in_text_section ())    arm_text_location += 4;  fflush (asm_out_file);  return ("");} /* arm_output_asm_insn *//* Output a label definition.  If this label is within the .text segment, it   is stored in OFFSET_TABLE, to be used when building `llc' instructions.   Maybe GCC remembers names not starting with a `*' for a long time, but this   is a minority anyway, so we just make a copy.  Do not store the leading `*'   if the name starts with one.  */voidarm_asm_output_label (stream, name)     FILE *stream;     char *name;{  char *real_name, *s;  struct label_offset *cur;  int hash = 0;  assemble_name (stream, name);  fputs (":\n", stream);  if (! in_text_section ())    return;  if (name[0] == '*')    {      real_name = xmalloc (1 + strlen (&name[1]));      strcpy (real_name, &name[1]);    }  else    {      real_name = xmalloc (2 + strlen (name));      strcpy (real_name, "_");      strcat (real_name, name);    }  for (s = real_name; *s; s++)    hash += *s;  hash = hash % LABEL_HASH_SIZE;  cur = (struct label_offset *) xmalloc (sizeof (struct label_offset));  cur->name = real_name;  cur->offset = arm_text_location;  cur->cdr = offset_table[hash];  offset_table[hash] = cur;} /* arm_asm_output_label *//* Output the instructions needed to perform what Martin's /bin/as called   llc: load an SImode thing from the function's constant pool.   XXX This could be enhanced in that we do not really need a pointer in the   constant pool pointing to the real thing.  If we can address this pointer,   we can also address what it is pointing at, in fact, anything in the text   segment which has been defined already within this .s file.  */char *arm_output_llc (operands)     rtx *operands;{  char *s, *name = XSTR (XEXP (operands[1], 0), 0);  struct label_offset *he;  int hash = 0, conditional = (arm_ccfsm_state == 3 || arm_ccfsm_state == 4);  if (*name != '*')    abort ();  for (s = &name[1]; *s; s++)    hash += *s;  hash = hash % LABEL_HASH_SIZE;  he = offset_table[hash];  while (he && strcmp (he->name, &name[1]))    he = he->cdr;  if (!he)    abort ();  if (arm_text_location + 8 - he->offset < 4095)    {      fprintf (asm_out_file, "\tldr%s\t%s, [pc, #%s - . - 8]\n",	       conditional ? arm_condition_codes[arm_current_cc] : "",	       reg_names[REGNO (operands[0])], &name[1]);      arm_increase_location (4);      return ("");    }  else    {      int offset = - (arm_text_location + 8 - he->offset);      char *reg_name = reg_names[REGNO (operands[0])];      /* ??? This is a hack, assuming the constant pool never is more than	 (1 + 255) * 4096 == 1Meg away from the PC.  */      if (offset > 1000000)	abort ();      fprintf (asm_out_file, "\tsub%s\t%s, pc, #(8 + . - %s) & ~4095\n",	       conditional ? arm_condition_codes[arm_current_cc] : "",	       reg_name, &name[1]);      fprintf (asm_out_file, "\tldr%s\t%s, [%s, #- ((4 + . - %s) & 4095)]\n",	       conditional ? arm_condition_codes[arm_current_cc] : "",	       reg_name, reg_name, &name[1]);      arm_increase_location (8);    }  return ("");} /* arm_output_llc *//* Output code resembling an .lcomm directive.  /bin/as doesn't have this   directive hence this hack, which works by reserving some `.space' in the   bss segment directly.   XXX This is a severe hack, which is guaranteed NOT to work since it doesn't   define STATIC COMMON space but merely STATIC BSS space.  */voidoutput_lcomm_directive (stream, name, size, rounded)     FILE *stream;     char *name;     int size, rounded;{  fputs ("\n\t.bss\t@ .lcomm\n", stream);  assemble_name (stream, name);  fprintf (stream, ":\t.space\t%d\n", rounded);  if (in_text_section ())    fputs ("\n\t.text\n", stream);  else    fputs ("\n\t.data\n", stream);} /* output_lcomm_directive *//* A finite state machine takes care of noticing whether or not instructions   can be conditionally executed, and thus decrease execution time and code   size by deleting branch instructions.  The fsm is controlled by   final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE.  *//* The state of the fsm controlling condition codes are:   0: normal, do nothing special   1: make ASM_OUTPUT_OPCODE not output this instruction   2: make ASM_OUTPUT_OPCODE not output this instruction   3: make instructions conditional   4: make instructions conditional   State transitions (state->state by whom under condition):   0 -> 1 final_prescan_insn if the `target' is a label   0 -> 2 final_prescan_insn if the `target' is an unconditional branch   1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch   2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch   3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached          (the target label has CODE_LABEL_NUMBER equal to arm_target_label).   4 -> 0 final_prescan_insn if the `target' unconditional branch is reached          (the target insn is arm_target_insn).   XXX In case the `target' is an unconditional branch, this conditionalising   of the instructions always reduces code size, but not always execution   time.  But then, I want to reduce the code size to somewhere near what   /bin/cc produces.  *//* The condition codes of the ARM, and the inverse function.  */char *arm_condition_codes[] ={  "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",  "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};#define ARM_INVERSE_CONDITION_CODE(X)  ((X) ^ 1)/* Returns the index of the ARM condition code string in   `arm_condition_codes'.  COMPARISON should be an rtx like   `(eq (...) (...))'.  */intget_arm_condition_code (comparison)     rtx comparison;{  switch (GET_CODE (comparison))    {    case NE: return (1);    case EQ: return (0);    case GE: return (10);    case GT: return (12);    case LE: return (13);    case LT: return (11);    case GEU: return (2);    case GTU: return (8);    case LEU: return (9);    case LTU: return (3);    default: abort ();    }  /*NOTREACHED*/  return (42);} /* get_arm_condition_code */voidfinal_prescan_insn (insn, opvec, noperands)     rtx insn;     rtx *opvec;     int noperands;{  /* BODY will hold the body of INSN.  */  register rtx body = PATTERN (insn);  /* This will be 1 if trying to repeat the trick, and things need to be     reversed if it appears to fail.  */  int reverse = 0;  /* START_INSN will hold the insn from where we start looking.  This is the     first insn after the following code_label if REVERSE is true.  */  rtx start_insn = insn;  /* If in state 4, check if the target branch is reached, in order to     change back to state 0.  */  if (arm_ccfsm_state == 4)    {      if (insn == arm_target_insn)	arm_ccfsm_state = 0;      return;    }  /* If in state 3, it is possible to repeat the trick, if this insn is an     unconditional branch to a label, and immediately following this branch     is the previous target label which is only used once, and the label this     branch jumps to is not too far off.  */  if (arm_ccfsm_state == 3)    {      if (simplejump_p (insn))	{	  start_insn = next_nonnote_insn (start_insn);	  if (GET_CODE (start_insn) == BARRIER)	    {	      /* XXX Isn't this always a barrier?  */	      start_insn = next_nonnote_insn (start_insn);	    }	  if (GET_CODE (start_insn) == CODE_LABEL	      && CODE_LABEL_NUMBER (start_insn) == arm_target_label	      && LABEL_NUSES (start_insn) == 1)	    reverse = TRUE;	  else	    return;	}      else	return;    }  if (arm_ccfsm_state != 0 && !reverse)    abort ();  if (GET_CODE (insn) != JUMP_INSN)    return;  if (reverse      || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC	  && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))    {      int insns_skipped = 0, fail = FALSE, succeed = FALSE;      /* Flag which part of the IF_THEN_ELSE is the LABEL_REF.  */      int then_not_else = TRUE;      rtx this_insn = start_insn, label;      /* Register the insn jumped to.  */      if (reverse)	label = XEXP (SET_SRC (body), 0);      else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)	label = XEXP (XEXP (SET_SRC (body), 1), 0);      else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)	{	  label = XEXP (XEXP (SET_SRC (body), 2), 0);	  then_not_else = FALSE;	}      else	abort ();      /* See how many insns this branch skips, and what kind of insns.  If all	 insns are okay, and the label or unconditional branch to the same	 label is not too far away, succeed.  */      for (insns_skipped = 0;	   !fail && !succeed && insns_skipped < MAX_INSNS_SKIPPED;	   insns_skipped++)	{	  rtx scanbody;	  this_insn = next_nonnote_insn (this_insn);	  if (!this_insn)	    break;	  scanbody = PATTERN (this_insn);	  switch (GET_CODE (this_insn))	    {	    case CODE_LABEL:	      /* Succeed if it is the target label, otherwise fail since		 control falls in from somewhere else.  */	      if (this_insn == label)		{		  arm_ccfsm_state = 1;		  succeed = TRUE;		}	      else		fail = TRUE;	      break;	    case BARRIER:	/* XXX Is this case necessary?  */	      /* Succeed if the following insn is the target label.		 Otherwise fail.  */	      this_insn = next_nonnote_insn (this_insn);	      if (this_insn == label)		{		  arm_ccfsm_state = 1;		  succeed = TRUE;		}	      else		fail = TRUE;	      break;	    case JUMP_INSN:      	      /* If this is an unconditional branch to the same label, succeed.		 If it is to another label, do nothing.  If it is conditional,		 fail.  */	      /* XXX Probably, the test for the SET and the PC are unnecessary. */	      if (GET_CODE (scanbody) == SET && GET_CODE (SET_DEST (scanbody)) == PC)		{		  if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF		      && XEXP (SET_SRC (scanbody), 0) == label && !reverse)		    {		      arm_ccfsm_state = 2;		      succeed = TRUE;		    }		  else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)		    fail = TRUE;		}	      break;	    case INSN:	      /* Instructions affecting the condition codes make it fail.  */	      if (sets_cc0_p (scanbody))		fail = TRUE;	      break;	    default:	      break;	    }	}      if (succeed)	{	  if (arm_ccfsm_state == 1 || reverse)	    arm_target_label = CODE_LABEL_NUMBER (label);	  else if (arm_ccfsm_state == 2)	    arm_target_insn = this_insn;	  else	    abort ();	  /* If REVERSE is true, ARM_CURRENT_CC needs to be inverted from what	     it was.  */	  if (!reverse)	    arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body), 0));	  if (reverse || then_not_else)	    arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);	}    }} /* final_prescan_insn *//* EOF */

⌨️ 快捷键说明

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