📄 varasm.c
字号:
dbxout_symbol (decl, 0);#else /* There must be a statement after a label. */ ;#endif}/* Output something to declare an external symbol to the assembler. (Most assemblers don't need this, so we normally output nothing.) Do nothing if DECL is not external. */voidassemble_external (decl) tree decl;{#ifdef ASM_OUTPUT_EXTERNAL if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd' && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl)) { rtx rtl = DECL_RTL (decl); if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF && ! SYMBOL_REF_USED (XEXP (rtl, 0))) { /* Some systems do require some output. */ SYMBOL_REF_USED (XEXP (rtl, 0)) = 1; ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0)); } }#endif}/* Similar, for calling a library function FUN. */voidassemble_external_libcall (fun) rtx fun;{#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL /* Declare library function name external when first used, if nec. */ if (! SYMBOL_REF_USED (fun)) { SYMBOL_REF_USED (fun) = 1; ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun); }#endif}/* Declare the label NAME global. */voidassemble_global (name) char *name;{ ASM_GLOBALIZE_LABEL (asm_out_file, name);}/* Assemble a label named NAME. */voidassemble_label (name) char *name;{ ASM_OUTPUT_LABEL (asm_out_file, name);}/* Output to FILE a reference to the assembler name of a C-level name NAME. If NAME starts with a *, the rest of NAME is output verbatim. Otherwise NAME is transformed in an implementation-defined way (usually by the addition of an underscore). Many macros in the tm file are defined to call this function. */voidassemble_name (file, name) FILE *file; char *name;{ if (name[0] == '*') fputs (&name[1], file); else ASM_OUTPUT_LABELREF (file, name);}/* Allocate SIZE bytes writable static space with a gensym name and return an RTX to refer to its address. */rtxassemble_static_space (size) int size;{ char name[12]; char *namestring; rtx x; /* Round size up to multiple of BIGGEST_ALIGNMENT bits so that each uninitialized object starts on such a boundary. */ int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1) / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));#if 0 if (flag_shared_data) data_section ();#endif ASM_GENERATE_INTERNAL_LABEL (name, "LF", const_labelno); ++const_labelno; namestring = (char *) obstack_alloc (saveable_obstack, strlen (name) + 2); strcpy (namestring, name); x = gen_rtx (SYMBOL_REF, Pmode, namestring);#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 return x;}/* Assemble the static constant template for function entry trampolines. This is done at most once per compilation. Returns an RTX for the address of the template. */rtxassemble_trampoline_template (){ char label[256]; char *name; int align; /* By default, put trampoline templates in read-only data section. */#ifdef TRAMPOLINE_SECTION TRAMPOLINE_SECTION ();#else readonly_data_section ();#endif /* Write the assembler code to define one. */ align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT); if (align > 0) ASM_OUTPUT_ALIGN (asm_out_file, align); ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LTRAMP", 0); TRAMPOLINE_TEMPLATE (asm_out_file); /* Record the rtl to refer to it. */ ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0); name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); return gen_rtx (SYMBOL_REF, Pmode, name);}/* Assemble the integer constant X into an object of SIZE bytes. X must be either a CONST_INT or CONST_DOUBLE. Return 1 if we were able to output the constant, otherwise 0. If FORCE is non-zero, abort if we can't output the constant. */intassemble_integer (x, size, force) rtx x; int size; int force;{ /* First try to use the standard 1, 2, 4, 8, and 16 byte ASM_OUTPUT... macros. */ switch (size) {#ifdef ASM_OUTPUT_CHAR case 1: ASM_OUTPUT_CHAR (asm_out_file, x); return 1;#endif#ifdef ASM_OUTPUT_SHORT case 2: ASM_OUTPUT_SHORT (asm_out_file, x); return 1;#endif#ifdef ASM_OUTPUT_INT case 4: ASM_OUTPUT_INT (asm_out_file, x); return 1;#endif#ifdef ASM_OUTPUT_DOUBLE_INT case 8: ASM_OUTPUT_DOUBLE_INT (asm_out_file, x); return 1;#endif#ifdef ASM_OUTPUT_QUADRUPLE_INT case 16: ASM_OUTPUT_QUADRUPLE_INT (asm_out_file, x); return 1;#endif } /* If we couldn't do it that way, there are two other possibilities: First, if the machine can output an explicit byte and this is a 1 byte constant, we can use ASM_OUTPUT_BYTE. */#ifdef ASM_OUTPUT_BYTE if (size == 1 && GET_CODE (x) == CONST_INT) { ASM_OUTPUT_BYTE (asm_out_file, INTVAL (x)); return 1; }#endif /* Finally, if SIZE is larger than a single word, try to output the constant one word at a time. */ if (size > UNITS_PER_WORD) { int i; enum machine_mode mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0); rtx word; for (i = 0; i < size / UNITS_PER_WORD; i++) { word = operand_subword (x, i, 0, mode); if (word == 0) break; if (! assemble_integer (word, UNITS_PER_WORD, 0)) break; } if (i == size / UNITS_PER_WORD) return 1; /* If we output at least one word and then could not finish, there is no valid way to continue. */ if (i > 0) abort (); } if (force) abort (); return 0;}/* Assemble the floating-point constant D into an object of size MODE. */voidassemble_real (d, mode) REAL_VALUE_TYPE d; enum machine_mode mode;{ jmp_buf output_constant_handler; if (setjmp (output_constant_handler)) { error ("floating point trap outputting a constant");#ifdef REAL_IS_NOT_DOUBLE bzero (&d, sizeof d); d = dconst0;#else d = 0;#endif } set_float_handler (output_constant_handler); switch (mode) {#ifdef ASM_OUTPUT_FLOAT case SFmode: ASM_OUTPUT_FLOAT (asm_out_file, d); break;#endif#ifdef ASM_OUTPUT_DOUBLE case DFmode: ASM_OUTPUT_DOUBLE (asm_out_file, d); break;#endif#ifdef ASM_OUTPUT_LONG_DOUBLE case TFmode: ASM_OUTPUT_LONG_DOUBLE (asm_out_file, d); break;#endif default: abort (); } set_float_handler (NULL_PTR);}/* Here we combine duplicate floating constants to make CONST_DOUBLE rtx's, and force those out to memory when necessary. *//* Chain of all CONST_DOUBLE rtx's constructed for the current function. They are chained through the CONST_DOUBLE_CHAIN. A CONST_DOUBLE rtx has CONST_DOUBLE_MEM != cc0_rtx iff it is on this chain. In that case, CONST_DOUBLE_MEM is either a MEM, or const0_rtx if no MEM has been made for this CONST_DOUBLE yet. (CONST_DOUBLE_MEM is used only for top-level functions. See force_const_mem for explanation.) */static rtx const_double_chain;/* Return a CONST_DOUBLE for a value specified as a pair of ints. For an integer, I0 is the low-order word and I1 is the high-order word. For a real number, I0 is the word with the low address and I1 is the word with the high address. */rtximmed_double_const (i0, i1, mode) HOST_WIDE_INT i0, i1; enum machine_mode mode;{ register rtx r; int in_current_obstack; if (GET_MODE_CLASS (mode) == MODE_INT) { /* We clear out all bits that don't belong in MODE, unless they and our sign bit are all one. So we get either a reasonable negative value or a reasonable unsigned value for this mode. */ int width = GET_MODE_BITSIZE (mode); if (width < HOST_BITS_PER_WIDE_INT && ((i0 & ((HOST_WIDE_INT) (-1) << (width - 1))) != ((HOST_WIDE_INT) (-1) << (width - 1)))) i0 &= ((HOST_WIDE_INT) 1 << width) - 1, i1 = 0; else if (width == HOST_BITS_PER_WIDE_INT && ! (i1 == ~0 && i0 < 0)) i1 = 0; else if (width > 2 * HOST_BITS_PER_WIDE_INT) /* We cannot represent this value as a constant. */ abort (); /* If MODE fits within HOST_BITS_PER_WIDE_INT, always use a CONST_INT. ??? Strictly speaking, this is wrong if we create a CONST_INT for a large unsigned constant with the size of MODE being HOST_BITS_PER_WIDE_INT and later try to interpret that constant in a wider mode. In that case we will mis-interpret it as a negative number. Unfortunately, the only alternative is to make a CONST_DOUBLE for any constant in any mode if it is an unsigned constant larger than the maximum signed integer in an int on the host. However, doing this will break everyone that always expects to see a CONST_INT for SImode and smaller. We have always been making CONST_INTs in this case, so nothing new is being broken. */ if (width <= HOST_BITS_PER_WIDE_INT) i1 = (i0 < 0) ? ~0 : 0; /* If this integer fits in one word, return a CONST_INT. */ if ((i1 == 0 && i0 >= 0) || (i1 == ~0 && i0 < 0)) return GEN_INT (i0); /* We use VOIDmode for integers. */ mode = VOIDmode; } /* Search the chain for an existing CONST_DOUBLE with the right value. If one is found, return it. */ for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r)) if (CONST_DOUBLE_LOW (r) == i0 && CONST_DOUBLE_HIGH (r) == i1 && GET_MODE (r) == mode) return r; /* No; make a new one and add it to the chain. We may be called by an optimizer which may be discarding any memory allocated during its processing (such as combine and loop). However, we will be leaving this constant on the chain, so we cannot tolerate freed memory. So switch to saveable_obstack for this allocation and then switch back if we were in current_obstack. */ in_current_obstack = rtl_in_saveable_obstack (); r = gen_rtx (CONST_DOUBLE, mode, 0, i0, i1); if (in_current_obstack) rtl_in_current_obstack (); /* Don't touch const_double_chain in nested function; see force_const_mem. */ if (outer_function_chain == 0) { CONST_DOUBLE_CHAIN (r) = const_double_chain; const_double_chain = r; } /* Store const0_rtx in mem-slot since this CONST_DOUBLE is on the chain. Actual use of mem-slot is only through force_const_mem. */ CONST_DOUBLE_MEM (r) = const0_rtx; return r;}/* Return a CONST_DOUBLE for a specified `double' value and machine mode. */rtximmed_real_const_1 (d, mode) REAL_VALUE_TYPE d; enum machine_mode mode;{ union real_extract u; register rtx r; int in_current_obstack; /* Get the desired `double' value as a sequence of ints since that is how they are stored in a CONST_DOUBLE. */ u.d = d; /* Detect special cases. */ /* Avoid REAL_VALUES_EQUAL here in order to distinguish minus zero. */ if (!bcmp (&dconst0, &d, sizeof d)) return CONST0_RTX (mode); else if (REAL_VALUES_EQUAL (dconst1, d)) return CONST1_RTX (mode); if (sizeof u == 2 * sizeof (HOST_WIDE_INT)) return immed_double_const (u.i[0], u.i[1], mode); /* The rest of this function handles the case where a float value requires more than 2 ints of space. It will be deleted as dead code on machines that don't need it. */ /* Search the chain for an existing CONST_DOUBLE with the right value. If one is found, return it. */ for (r = const_double_chain; r; r = CONST_DOUBLE_CHAIN (r)) if (! bcmp (&CONST_DOUBLE_LOW (r), &u, sizeof u) && GET_MODE (r) == mode) return r; /* No; make a new one and add it to the chain. We may be called by an optimizer which may be discarding any memory allocated during its processing (such as combine and loop). However, we will be leaving this constant on the chain, so we cannot tolerate freed memory. So switch to saveable_obstack for this allocation and then switch back if we were in current_obstack. */ in_current_obstack = rtl_in_saveable_obstack (); r = rtx_alloc (CONST_DOUBLE); PUT_MODE (r, mode); bcopy (&u, &CONST_DOUBLE_LOW (r), sizeof u); if (in_current_obstack) rtl_in_current_obstack (); /* Don't touch const_double_chain in nested function; see force_const_mem. */ if (outer_function_chain == 0) { CONST_DOUBLE_CHAIN (r) = const_double_chain; const_double_chain = r; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -