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 + -
显示快捷键?