📄 varasm.c
字号:
{ 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 (DECL_REGISTER (decl) && reg_number == -1) error_with_decl (decl, "register name not specified for `%s'"); else if (DECL_REGISTER (decl) && reg_number < 0) error_with_decl (decl, "invalid register name for `%s'"); else if ((reg_number >= 0 || reg_number == -3) && ! DECL_REGISTER (decl)) error_with_decl (decl, "register name given for non-register variable `%s'"); else if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL) error ("function declared `register'"); else if (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 (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 the data type"); /* Now handle properly declared static register variables. */ else if (DECL_REGISTER (decl)) { int nregs;#if 0 /* yylex should print the warning for this */ if (pedantic) pedwarn ("ANSI C forbids global register variables");#endif 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 an uninitialized variable does not (and cannot) cause it to be put in the given section. The linker can only put initialized objects in specific sections, everything else goes in bss for the linker to sort out later (otherwise the linker would give a duplicate definition error for each compilation unit that behaved thusly). So warn the user. */ else if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl) != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE && DECL_COMMON (decl) && ! flag_no_common) { warning_with_decl (decl, "section attribute ignored for uninitialized variable `%s'"); /* Remove the section name so subsequent declarations won't see it. We are ignoring it, remember. */ DECL_SECTION_NAME (decl) = NULL_TREE; } /* 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 && !DECL_EXTERNAL (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 (); 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) { /* Now tell GNU LD that this is part of the static constructor set. */ /* This code works for any machine provided you use GNU as/ld. */ fprintf (asm_out_file, "%s \"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP); assemble_name (asm_out_file, name); fputc ('\n', asm_out_file); }#endif}/* Likewise for entries we want to record for garbage collection. Garbage collection is still under development. */voidassemble_gc_entry (name) char *name;{#ifdef ASM_OUTPUT_GC_ENTRY ASM_OUTPUT_GC_ENTRY (asm_out_file, name);#else if (flag_gnu_linker) { /* Now tell GNU LD that this is part of the static constructor set. */ fprintf (asm_out_file, "%s \"___PTR_LIST__\",22,0,0,", ASM_STABS_OP); assemble_name (asm_out_file, name); fputc ('\n', asm_out_file); }#endif}/* Output assembler code for the constant pool of a function and associated with defining the name of the function. DECL describes the function. NAME is the function's name. For the constant pool, we use the current constant pool data. */voidassemble_start_function (decl, fnname) tree decl; char *fnname;{ int align; /* The following code does not need preprocessing in the assembler. */ app_disable (); output_constant_pool (fnname, decl); function_section (decl); /* Tell assembler to move to target machine's alignment for functions. */ align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); if (align > 0) { if (output_bytecode) BC_OUTPUT_ALIGN (asm_out_file, align); else ASM_OUTPUT_ALIGN (asm_out_file, align); }#ifdef ASM_OUTPUT_FUNCTION_PREFIX ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);#endif#ifdef SDB_DEBUGGING_INFO /* Output SDB definition of the function. */ if (write_symbols == SDB_DEBUG) sdbout_mark_begin_function ();#endif#ifdef DBX_DEBUGGING_INFO /* Output DBX definition of the function. */ if (write_symbols == DBX_DEBUG) dbxout_begin_function (decl);#endif /* Make function name accessible from other files, if appropriate. */ if (TREE_PUBLIC (decl)) { if (!first_global_object_name) { char *p; STRIP_NAME_ENCODING (p, fnname); first_global_object_name = permalloc (strlen (p) + 1); strcpy (first_global_object_name, p); }#ifdef ASM_WEAKEN_LABEL if (DECL_WEAK (decl)) ASM_WEAKEN_LABEL (asm_out_file, fnname); else#endif if (output_bytecode) BC_GLOBALIZE_LABEL (asm_out_file, fnname); else ASM_GLOBALIZE_LABEL (asm_out_file, fnname); } /* Do any machine/system dependent processing of the function name */#ifdef ASM_DECLARE_FUNCTION_NAME ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);#else /* Standard thing is just output label for the function. */ if (output_bytecode) BC_OUTPUT_LABEL (asm_out_file, fnname); else ASM_OUTPUT_LABEL (asm_out_file, fnname);#endif /* ASM_DECLARE_FUNCTION_NAME */}/* Output assembler code associated with defining the size of the function. DECL describes the function. NAME is the function's name. */voidassemble_end_function (decl, fnname) tree decl; char *fnname;{#ifdef ASM_DECLARE_FUNCTION_SIZE ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);#endif}/* Assemble code to leave SIZE bytes of zeros. */voidassemble_zeros (size) int size;{ if (output_bytecode) { bc_emit_const_skip (size); return; }#ifdef ASM_NO_SKIP_IN_TEXT /* The `space' pseudo in the text section outputs nop insns rather than 0s, so we must output 0s explicitly in the text section. */ if (ASM_NO_SKIP_IN_TEXT && in_text_section ()) { int i; for (i = 0; i < size - 20; i += 20) {#ifdef ASM_BYTE_OP fprintf (asm_out_file, "%s 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n", ASM_BYTE_OP);#else fprintf (asm_out_file, "\tbyte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n");#endif } if (i < size) {#ifdef ASM_BYTE_OP fprintf (asm_out_file, "%s 0", ASM_BYTE_OP);#else fprintf (asm_out_file, "\tbyte 0");#endif i++; for (; i < size; i++) fprintf (asm_out_file, ",0"); fprintf (asm_out_file, "\n"); } } else#endif if (size > 0) { if (output_bytecode) BC_OUTPUT_SKIP (asm_out_file, size); else ASM_OUTPUT_SKIP (asm_out_file, size); }}/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */voidassemble_align (align) int align;{ if (align > BITS_PER_UNIT) ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));}/* Assemble a string constant with the specified C string as contents. */voidassemble_string (p, size) char *p; int size;{ register int i; int pos = 0; int maximum = 2000; if (output_bytecode) { bc_emit (p, size); return; } /* If the string is very long, split it up. */ while (pos < size) { int thissize = size - pos; if (thissize > maximum) thissize = maximum;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -