final.c

来自「GCC编译器源代码」· C语言 代码 · 共 2,287 行 · 第 1/5 页

C
2,287
字号
	    ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);	  else#endif#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL	    ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,					      BIGGEST_ALIGNMENT);#else#ifdef ASM_OUTPUT_ALIGNED_LOCAL	    ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,				      BIGGEST_ALIGNMENT);#else	    ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);#endif#endif	}      /* Output any basic block strings */      if (profile_block_flag)	{	  readonly_data_section ();	  if (sbb_head)	    {	      ASM_OUTPUT_ALIGN (asm_out_file, align);	      for (sptr = sbb_head; sptr != 0; sptr = sptr->next)		{		  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC",					     sptr->label_num);		  assemble_string (sptr->string, sptr->length);		}	    }	}      /* Output the table of addresses.  */      if (profile_block_flag)	{	  /* Realign in new section */	  ASM_OUTPUT_ALIGN (asm_out_file, align);	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);	  for (i = 0; i < count_basic_blocks; i++)	    {	      ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);	      assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),				pointer_bytes, 1);	    }	}      /* Output the table of function names.  */      if (profile_block_flag)	{	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)	    {	      if (ptr->func_label_num >= 0)		{		  ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",					       ptr->func_label_num);		  assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),				    pointer_bytes, 1);		}	      else		assemble_integer (const0_rtx, pointer_bytes, 1);	    }	  for ( ; i < count_basic_blocks; i++)	    assemble_integer (const0_rtx, pointer_bytes, 1);	}      if (write_symbols != NO_DEBUG && profile_block_flag)	{	  /* Output the table of line numbers.  */	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5);	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)	    assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1);	  for ( ; i < count_basic_blocks; i++)	    assemble_integer (const0_rtx, long_bytes, 1);	  /* Output the table of file names.  */	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6);	  for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)	    {	      if (ptr->file_label_num >= 0)		{		  ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",					       ptr->file_label_num);		  assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),				    pointer_bytes, 1);		}	      else		assemble_integer (const0_rtx, pointer_bytes, 1);	    }	  for ( ; i < count_basic_blocks; i++)	    assemble_integer (const0_rtx, pointer_bytes, 1);	}      /* End with the address of the table of addresses,	 so we can find it easily, as the last word in the file's text.  */      if (profile_block_flag)	{	  ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);	  assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), pointer_bytes,			    1);	}    }}/* Enable APP processing of subsequent output.   Used before the output from an `asm' statement.  */voidapp_enable (){  if (! app_on)    {      fprintf (asm_out_file, ASM_APP_ON);      app_on = 1;    }}/* Disable APP processing of subsequent output.   Called from varasm.c before most kinds of output.  */voidapp_disable (){  if (app_on)    {      fprintf (asm_out_file, ASM_APP_OFF);      app_on = 0;    }}/* Return the number of slots filled in the current    delayed branch sequence (we don't count the insn needing the   delay slot).   Zero if not in a delayed branch sequence.  */#ifdef DELAY_SLOTSintdbr_sequence_length (){  if (final_sequence != 0)    return XVECLEN (final_sequence, 0) - 1;  else    return 0;}#endif/* The next two pages contain routines used to compute the length of an insn   and to shorten branches.  *//* Arrays for insn lengths, and addresses.  The latter is referenced by   `insn_current_length'.  */static short *insn_lengths;int *insn_addresses;/* Address of insn being processed.  Used by `insn_current_length'.  */int insn_current_address;/* Indicate that branch shortening hasn't yet been done.  */voidinit_insn_lengths (){  insn_lengths = 0;}/* Obtain the current length of an insn.  If branch shortening has been done,   get its actual length.  Otherwise, get its maximum length.  */intget_attr_length (insn)     rtx insn;{#ifdef HAVE_ATTR_length  rtx body;  int i;  int length = 0;  if (insn_lengths)    return insn_lengths[INSN_UID (insn)];  else    switch (GET_CODE (insn))      {      case NOTE:      case BARRIER:      case CODE_LABEL:	return 0;      case CALL_INSN:	length = insn_default_length (insn);	break;      case JUMP_INSN:	body = PATTERN (insn);        if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)	  {	    /* This only takes room if jump tables go into the text section.  */#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)	    length = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)		      * GET_MODE_SIZE (GET_MODE (body)));	    /* Be pessimistic and assume worst-case alignment.  */	    length += (GET_MODE_SIZE (GET_MODE (body)) - 1);#else	    return 0;#endif	  }	else	  length = insn_default_length (insn);	break;      case INSN:	body = PATTERN (insn);	if (GET_CODE (body) == USE || GET_CODE (body) == CLOBBER)	  return 0;	else if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0)	  length = asm_insn_count (body) * insn_default_length (insn);	else if (GET_CODE (body) == SEQUENCE)	  for (i = 0; i < XVECLEN (body, 0); i++)	    length += get_attr_length (XVECEXP (body, 0, i));	else	  length = insn_default_length (insn);	break;      default:	break;      }#ifdef ADJUST_INSN_LENGTH  ADJUST_INSN_LENGTH (insn, length);#endif  return length;#else /* not HAVE_ATTR_length */  return 0;#endif /* not HAVE_ATTR_length */}/* Make a pass over all insns and compute their actual lengths by shortening   any branches of variable length if possible.  *//* Give a default value for the lowest address in a function.  */#ifndef FIRST_INSN_ADDRESS#define FIRST_INSN_ADDRESS 0#endifvoidshorten_branches (first)     rtx first;{#ifdef HAVE_ATTR_length  rtx insn;  int something_changed = 1;  int max_uid = 0;  char *varying_length;  rtx body;  int uid;  /* In order to make sure that all instructions have valid length info,     we must split them before we compute the address/length info.  */  for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')      insn = try_split (PATTERN (insn), insn, 1);  /* Compute maximum UID and allocate arrays.  */  for (insn = first; insn; insn = NEXT_INSN (insn))    if (INSN_UID (insn) > max_uid)      max_uid = INSN_UID (insn);  max_uid++;  insn_lengths = (short *) oballoc (max_uid * sizeof (short));  insn_addresses = (int *) oballoc (max_uid * sizeof (int));  varying_length = (char *) oballoc (max_uid * sizeof (char));  /* Compute initial lengths, addresses, and varying flags for each insn.  */  for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;       insn != 0;       insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))    {      uid = INSN_UID (insn);      insn_addresses[uid] = insn_current_address;      insn_lengths[uid] = 0;      varying_length[uid] = 0;            if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER	  || GET_CODE (insn) == CODE_LABEL)	continue;      if (INSN_DELETED_P (insn))	continue;      body = PATTERN (insn);      if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)	{	  /* This only takes room if read-only data goes into the text	     section.  */#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)	  int unitsize = GET_MODE_SIZE (GET_MODE (body));	  insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)			       * GET_MODE_SIZE (GET_MODE (body)));	  /* We don't know what address the ADDR_VEC/ADDR_DIFF_VEC will end	     up at after branch shortening.  As a result, it is impossible	     to determine how much padding we need at this point.  Therefore,	     assume worst possible alignment.  */	  insn_lengths[uid] += unitsize - 1;#else	  ;#endif	}      else if (asm_noperands (body) >= 0)	insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);      else if (GET_CODE (body) == SEQUENCE)	{	  int i;	  int const_delay_slots;#ifdef DELAY_SLOTS	  const_delay_slots = const_num_delay_slots (XVECEXP (body, 0, 0));#else	  const_delay_slots = 0;#endif	  /* Inside a delay slot sequence, we do not do any branch shortening	     if the shortening could change the number of delay slots	     of the branch.  */	  for (i = 0; i < XVECLEN (body, 0); i++)	    {	      rtx inner_insn = XVECEXP (body, 0, i);	      int inner_uid = INSN_UID (inner_insn);	      int inner_length;	      if (asm_noperands (PATTERN (XVECEXP (body, 0, i))) >= 0)		inner_length = (asm_insn_count (PATTERN (inner_insn))				* insn_default_length (inner_insn));	      else		inner_length = insn_default_length (inner_insn);	      	      insn_lengths[inner_uid] = inner_length;	      if (const_delay_slots)		{		  if ((varying_length[inner_uid]		       = insn_variable_length_p (inner_insn)) != 0)		    varying_length[uid] = 1;		  insn_addresses[inner_uid] = (insn_current_address +					       insn_lengths[uid]);		}	      else		varying_length[inner_uid] = 0;	      insn_lengths[uid] += inner_length;	    }	}      else if (GET_CODE (body) != USE && GET_CODE (body) != CLOBBER)	{	  insn_lengths[uid] = insn_default_length (insn);	  varying_length[uid] = insn_variable_length_p (insn);	}      /* If needed, do any adjustment.  */#ifdef ADJUST_INSN_LENGTH      ADJUST_INSN_LENGTH (insn, insn_lengths[uid]);#endif    }  /* Now loop over all the insns finding varying length insns.  For each,     get the current insn length.  If it has changed, reflect the change.     When nothing changes for a full pass, we are done.  */  while (something_changed)    {      something_changed = 0;      for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;	   insn != 0;	   insn = NEXT_INSN (insn))	{	  int new_length;	  int tmp_length;	  uid = INSN_UID (insn);	  insn_addresses[uid] = insn_current_address;	  if (! varying_length[uid])	    {	      insn_current_address += insn_lengths[uid];	      continue;	    }	  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)	    {	      int i;	      	      body = PATTERN (insn);	      new_length = 0;	      for (i = 0; i < XVECLEN (body, 0); i++)		{		  rtx inner_insn = XVECEXP (body, 0, i);		  int inner_uid = INSN_UID (inner_insn);		  int inner_length;		  insn_addresses[inner_uid] = insn_current_address;		  /* insn_current_length returns 0 for insns with a		     non-varying length.  */		  if (! varying_length[inner_uid])		    inner_length = insn_lengths[inner_uid];		  else		    inner_length = insn_current_length (inner_insn);		  if (inner_length != insn_lengths[inner_uid])		    {		      insn_lengths[inner_uid] = inner_length;		      something_changed = 1;		    }		  insn_current_address += insn_lengths[inner_uid];		  new_length += inner_length;		}	    }	  else	    {	      new_length = insn_current_length (insn);	      insn_current_address += new_length;	    }#ifdef SHORTEN_WITH_ADJUST_INSN_LENGTH#ifdef ADJUST_INSN_LENGTH	  /* If needed, do any adjustment.  */	  tmp_length = new_length;	  ADJUST_INSN_LENGTH (insn, new_length);	  insn_current_address += (new_length - tmp_length);#endif#endif	  if (new_length != insn_lengths[uid])	    {	      insn_lengths[uid] = new_length;	      something_changed = 1;	    }	}      /* For a non-optimizing compile, do only a single pass.  */      if (!optimize)	break;    }#endif /* HAVE_ATTR_length */}#ifdef HAVE_ATTR_length/* Given the body of an INSN known to be generated by an ASM statement, return   the number of machine instructions likely to be generated for this insn.   This is used to compute its length.  */static intasm_insn_count (body)     rtx body;{  char *template;  int count = 1;

⌨️ 快捷键说明

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