varasm.c

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

C
2,382
字号
{#if defined (EXCEPTION_SECTION)  EXCEPTION_SECTION ();#else#ifdef ASM_OUTPUT_SECTION_NAME  named_section (NULL_TREE, ".gcc_except_table", 0);#else  if (flag_pic)    data_section ();  else    readonly_data_section ();#endif#endif}/* Create the rtl to represent a function, for a function definition.   DECL is a FUNCTION_DECL node which describes which function.   The rtl is stored into DECL.  */voidmake_function_rtl (decl)     tree decl;{  char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));  char *new_name = name;  if (output_bytecode)    {      if (DECL_RTL (decl) == 0)	DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);            /* Record that at least one function has been defined.  */      function_defined = 1;      return;    }  /* Rename a nested function to avoid conflicts.  */  if (decl_function_context (decl) != 0      && DECL_INITIAL (decl) != 0      && DECL_RTL (decl) == 0)    {      char *label;      name = IDENTIFIER_POINTER (DECL_NAME (decl));      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);      name = obstack_copy0 (saveable_obstack, label, strlen (label));      var_labelno++;    }  else    {      /* When -fprefix-function-name is used, every function name is         prefixed.  Even static functions are prefixed because they         could be declared latter.  Note that a nested function name         is not prefixed.  */      if (flag_prefix_function_name)        {          new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + 1);          strcpy (new_name, CHKR_PREFIX);          strcpy (new_name + CHKR_PREFIX_SIZE, name);          name = obstack_copy0 (saveable_obstack, new_name, strlen (new_name));        }    }  if (DECL_RTL (decl) == 0)    {      DECL_RTL (decl)	= gen_rtx (MEM, DECL_MODE (decl),		   gen_rtx (SYMBOL_REF, Pmode, name));      /* Optionally set flags or add text to the name to record information	 such as that it is a function name.  If the name is changed, the macro	 ASM_OUTPUT_LABELREF will have to know how to strip this information.  */#ifdef ENCODE_SECTION_INFO      ENCODE_SECTION_INFO (decl);#endif    }  /* Record at least one function has been defined.  */  function_defined = 1;}/* Create the DECL_RTL for a declaration for a static or external   variable or static or external function.   ASMSPEC, if not 0, is the string which the user specified   as the assembler symbol name.   TOP_LEVEL is nonzero if this is a file-scope variable.   This is never called for PARM_DECLs.  */static voidbc_make_decl_rtl (decl, asmspec, top_level)     tree decl;     char *asmspec;     int top_level;{  register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl));  if (DECL_RTL (decl) == 0)    {      /* Print an error message for register variables.  */      if (DECL_REGISTER (decl))	error ("global register variables not supported in the interpreter");      /* Handle ordinary static variables and functions.  */      if (DECL_RTL (decl) == 0)	{	  /* Can't use just the variable's own name for a variable	     whose scope is less than the whole file.	     Concatenate a distinguishing number.  */	  if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)	    {	      char *label;	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);	      name = obstack_copy0 (saveable_obstack, label, strlen (label));	      var_labelno++;	    }	  DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);	}    }}/* Given NAME, a putative register name, discard any customary prefixes.  */static char *strip_reg_name (name)     char *name;{#ifdef REGISTER_PREFIX  if (!strncmp (name, REGISTER_PREFIX, strlen (REGISTER_PREFIX)))    name += strlen (REGISTER_PREFIX);#endif  if (name[0] == '%' || name[0] == '#')    name++;  return name;}/* Decode an `asm' spec for a declaration as a register name.   Return the register number, or -1 if nothing specified,   or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,   or -3 if ASMSPEC is `cc' and is not recognized,   or -4 if ASMSPEC is `memory' and is not recognized.   Accept an exact spelling or a decimal number.   Prefixes such as % are optional.  */intdecode_reg_name (asmspec)     char *asmspec;{  if (asmspec != 0)    {      int i;      /* Get rid of confusing prefixes.  */      asmspec = strip_reg_name (asmspec);	      /* Allow a decimal number as a "register name".  */      for (i = strlen (asmspec) - 1; i >= 0; i--)	if (! (asmspec[i] >= '0' && asmspec[i] <= '9'))	  break;      if (asmspec[0] != 0 && i < 0)	{	  i = atoi (asmspec);	  if (i < FIRST_PSEUDO_REGISTER && i >= 0)	    return i;	  else	    return -2;	}      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)	if (reg_names[i][0]	    && ! strcmp (asmspec, strip_reg_name (reg_names[i])))	  return i;#ifdef ADDITIONAL_REGISTER_NAMES      {	static struct { char *name; int number; } table[]	  = ADDITIONAL_REGISTER_NAMES;	for (i = 0; i < sizeof (table) / sizeof (table[0]); i++)	  if (! strcmp (asmspec, table[i].name))	    return table[i].number;      }#endif /* ADDITIONAL_REGISTER_NAMES */      if (!strcmp (asmspec, "memory"))	return -4;      if (!strcmp (asmspec, "cc"))	return -3;      return -2;    }  return -1;}/* Create the DECL_RTL for a declaration for a static or external variable   or static or external function.   ASMSPEC, if not 0, is the string which the user specified   as the assembler symbol name.   TOP_LEVEL is nonzero if this is a file-scope variable.   This is never called for PARM_DECL nodes.  */voidmake_decl_rtl (decl, asmspec, top_level)     tree decl;     char *asmspec;     int top_level;{  register char *name = 0;  int reg_number;  if (output_bytecode)    {      bc_make_decl_rtl (decl, asmspec, top_level);      return;    }  reg_number = decode_reg_name (asmspec);  if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)    name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));  if (reg_number == -2)    {      /* ASMSPEC is given, and not the name of a register.  */      name = (char *) obstack_alloc (saveable_obstack,				     strlen (asmspec) + 2);      name[0] = '*';      strcpy (&name[1], asmspec);    }  /* For a duplicate declaration, we can be called twice on the     same DECL node.  Don't discard the RTL already made.  */  if (DECL_RTL (decl) == 0)    {      DECL_RTL (decl) = 0;      /* First detect errors in declaring global registers.  */      if (TREE_CODE (decl) != FUNCTION_DECL	  && DECL_REGISTER (decl) && reg_number == -1)	error_with_decl (decl,			 "register name not specified for `%s'");      else if (TREE_CODE (decl) != FUNCTION_DECL	       && DECL_REGISTER (decl) && reg_number < 0)	error_with_decl (decl,			 "invalid register name for `%s'");      else if ((reg_number >= 0 || reg_number == -3)	       && (TREE_CODE (decl) == FUNCTION_DECL		   && ! DECL_REGISTER (decl)))	error_with_decl (decl,			 "register name given for non-register variable `%s'");      else if (TREE_CODE (decl) != FUNCTION_DECL	       && DECL_REGISTER (decl)	       && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)	error_with_decl (decl,			 "data type of `%s' isn't suitable for a register");      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)	       && ! HARD_REGNO_MODE_OK (reg_number,					TYPE_MODE (TREE_TYPE (decl))))	error_with_decl (decl,			 "register number for `%s' isn't suitable for data type");      /* Now handle properly declared static register variables.  */      else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))	{	  int nregs;	  if (DECL_INITIAL (decl) != 0 && top_level)	    {	      DECL_INITIAL (decl) = 0;	      error ("global register variable has initial value");	    }	  if (fixed_regs[reg_number] == 0	      && function_defined && top_level)	    error ("global register variable follows a function definition");	  if (TREE_THIS_VOLATILE (decl))	    warning ("volatile register variables don't work as you might wish");	  /* If the user specified one of the eliminables registers here,	     e.g., FRAME_POINTER_REGNUM, we don't want to get this variable	     confused with that register and be eliminated.  Although this	     usage is somewhat suspect, we nevertheless use the following	     kludge to avoid setting DECL_RTL to frame_pointer_rtx.  */	  DECL_RTL (decl)	    = gen_rtx (REG, DECL_MODE (decl), FIRST_PSEUDO_REGISTER);	  REGNO (DECL_RTL (decl)) = reg_number;	  REG_USERVAR_P (DECL_RTL (decl)) = 1;	  if (top_level)	    {	      /* Make this register global, so not usable for anything		 else.  */	      nregs = HARD_REGNO_NREGS (reg_number, DECL_MODE (decl));	      while (nregs > 0)		globalize_reg (reg_number + --nregs);	    }	}      /* Specifying a section attribute on a variable forces it into a         non-.bss section, and thus it cannot be common. */      else if (TREE_CODE (decl) == VAR_DECL	       && DECL_SECTION_NAME (decl) != NULL_TREE	       && DECL_INITIAL (decl) == NULL_TREE	       && DECL_COMMON (decl))          DECL_COMMON (decl) = 0;      /* Now handle ordinary static variables and functions (in memory).	 Also handle vars declared register invalidly.  */      if (DECL_RTL (decl) == 0)	{	  /* Can't use just the variable's own name for a variable	     whose scope is less than the whole file.	     Concatenate a distinguishing number.  */	  if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)	    {	      char *label;	      ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);	      name = obstack_copy0 (saveable_obstack, label, strlen (label));	      var_labelno++;	    }	  if (name == 0)	    abort ();	  /* When -fprefix-function-name is used, the functions	     names are prefixed.  Only nested function names are not	     prefixed.  */	  if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)	    {	      char *new_name;	      new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE 	      				  + 1);	      strcpy (new_name, CHKR_PREFIX);	      strcpy (new_name + CHKR_PREFIX_SIZE, name);	      name = obstack_copy0 (saveable_obstack,	      			   new_name, strlen (new_name));	    }	  DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl),				     gen_rtx (SYMBOL_REF, Pmode, name));	  /* If this variable is to be treated as volatile, show its	     tree node has side effects.  If it has side effects, either	     because of this test or from TREE_THIS_VOLATILE also	     being set, show the MEM is volatile.  */	  if (flag_volatile_global && TREE_CODE (decl) == VAR_DECL	      && TREE_PUBLIC (decl))	    TREE_SIDE_EFFECTS (decl) = 1;	  if (TREE_SIDE_EFFECTS (decl))	    MEM_VOLATILE_P (DECL_RTL (decl)) = 1;	  if (TREE_READONLY (decl))	    RTX_UNCHANGING_P (DECL_RTL (decl)) = 1;	  MEM_IN_STRUCT_P (DECL_RTL (decl))	    = AGGREGATE_TYPE_P (TREE_TYPE (decl));	  /* Optionally set flags or add text to the name to record information	     such as that it is a function name.	     If the name is changed, the macro ASM_OUTPUT_LABELREF	     will have to know how to strip this information.  */#ifdef ENCODE_SECTION_INFO	  ENCODE_SECTION_INFO (decl);#endif	}    }  /* If the old RTL had the wrong mode, fix the mode.  */  else if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))    {      rtx rtl = DECL_RTL (decl);      PUT_MODE (rtl, DECL_MODE (decl));    }}/* Make the rtl for variable VAR be volatile.   Use this only for static variables.  */voidmake_var_volatile (var)     tree var;{  if (GET_CODE (DECL_RTL (var)) != MEM)    abort ();  MEM_VOLATILE_P (DECL_RTL (var)) = 1;}/* Output alignment directive to align for constant expression EXP.  */voidassemble_constant_align (exp)     tree exp;{  int align;  /* Align the location counter as required by EXP's data type.  */  align = TYPE_ALIGN (TREE_TYPE (exp));#ifdef CONSTANT_ALIGNMENT  align = CONSTANT_ALIGNMENT (exp, align);#endif  if (align > BITS_PER_UNIT)    ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));}/* Output a string of literal assembler code   for an `asm' keyword used between functions.  */voidassemble_asm (string)     tree string;{  if (output_bytecode)    {      error ("asm statements not allowed in interpreter");      return;    }  app_enable ();  if (TREE_CODE (string) == ADDR_EXPR)    string = TREE_OPERAND (string, 0);  fprintf (asm_out_file, "\t%s\n", TREE_STRING_POINTER (string));}#if 0 /* This should no longer be needed, because	 flag_gnu_linker should be 0 on these systems,	 which should prevent any output	 if ASM_OUTPUT_CONSTRUCTOR and ASM_OUTPUT_DESTRUCTOR are absent.  */#if !(defined(DBX_DEBUGGING_INFO) && !defined(FASCIST_ASSEMBLER))#ifndef ASM_OUTPUT_CONSTRUCTOR#define ASM_OUTPUT_CONSTRUCTOR(file, name)#endif#ifndef ASM_OUTPUT_DESTRUCTOR#define ASM_OUTPUT_DESTRUCTOR(file, name)#endif#endif#endif /* 0 *//* Record an element in the table of global destructors.   How this is done depends on what sort of assembler and linker   are in use.   NAME should be the name of a global function to be called   at exit time.  This name is output using assemble_name.  */voidassemble_destructor (name)     char *name;{#ifdef ASM_OUTPUT_DESTRUCTOR  ASM_OUTPUT_DESTRUCTOR (asm_out_file, name);#else  if (flag_gnu_linker)    {      /* Now tell GNU LD that this is part of the static destructor set.  */      /* This code works for any machine provided you use GNU as/ld.  */      fprintf (asm_out_file, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP);      assemble_name (asm_out_file, name);      fputc ('\n', asm_out_file);    }#endif}/* Likewise for global constructors.  */voidassemble_constructor (name)     char *name;{#ifdef ASM_OUTPUT_CONSTRUCTOR  ASM_OUTPUT_CONSTRUCTOR (asm_out_file, name);#else  if (flag_gnu_linker)

⌨️ 快捷键说明

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