📄 varasm.c
字号:
rounded = size; /* Don't allocate zero bytes of common, since that means "undefined external" in the linker. */ if (size == 0) rounded = 1; /* Round size up to multiple of BIGGEST_ALIGNMENT bits so that each uninitialized object starts on such a boundary. */ rounded = ((rounded + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1) / (BIGGEST_ALIGNMENT / BITS_PER_UNIT) * (BIGGEST_ALIGNMENT / BITS_PER_UNIT)); if (flag_shared_data) data_section (); if (TREE_PUBLIC (decl)) ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded); else ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); return; } /* Handle initialized definitions. */ /* First make the assembler name(s) global if appropriate. */ if (TREE_PUBLIC (decl) && DECL_NAME (decl)) ASM_GLOBALIZE_LABEL (asm_out_file, name);#if 0 for (d = equivalents; d; d = TREE_CHAIN (d)) { tree e = TREE_VALUE (d); if (TREE_PUBLIC (e) && DECL_NAME (e)) ASM_GLOBALIZE_LABEL (asm_out_file, XSTR (XEXP (DECL_RTL (e), 0), 0)); }#endif /* Output any data that we will need to use the address of. */ if (DECL_INITIAL (decl)) output_addressed_constants (DECL_INITIAL (decl)); /* Switch to the proper section for this data. */#ifdef SELECT_SECTION SELECT_SECTION (decl);#else if (TREE_READONLY (decl) && ! TREE_VOLATILE (decl)) text_section (); else data_section ();#endif /* Output the alignment of this data. */ for (i = 0; DECL_ALIGN (decl) >= BITS_PER_UNIT << (i + 1); i++); if (i > 0) ASM_OUTPUT_ALIGN (asm_out_file, i); /* Output the name(s) of this data. */ ASM_OUTPUT_LABEL (asm_out_file, name);#if 0 for (d = equivalents; d; d = TREE_CHAIN (d)) { tree e = TREE_VALUE (d); ASM_OUTPUT_LABEL (asm_out_file, XSTR (XEXP (DECL_RTL (e), 0), 0)); }#endif if (DECL_INITIAL (decl)) /* Output the actual data. */ output_constant (DECL_INITIAL (decl), int_size_in_bytes (TREE_TYPE (decl))); else /* Leave space for it. */ ASM_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (decl)));}/* Output something to declare an external symbol to the assembler. (Most assemblers don't need this, so we normally output nothing.) */voidassemble_external (decl) tree decl;{ rtx rtl = DECL_RTL (decl); if (GET_CODE (rtl) == MEM && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF) {#ifdef ASM_OUTPUT_EXTERNAL /* Some systems do require some output. */ ASM_OUTPUT_EXTERNAL (asm_out_file, decl, XSTR (XEXP (rtl, 0), 0));#endif }}/* 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 (flag_shared_data) data_section (); 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); ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded); return x;}/* 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. */static rtx real_constant_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) int i0, i1; enum machine_mode mode;{ register rtx r; if (mode == DImode && i0 == 0 && i1 == 0) return const0_rtx; /* Search the chain for an existing CONST_DOUBLE with the right value. If one is found, return it. */ for (r = real_constant_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. */ r = gen_rtx (CONST_DOUBLE, mode, 0, i0, i1); CONST_DOUBLE_CHAIN (r) = real_constant_chain; real_constant_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_double_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; /* 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 zero. */ if (! bcmp (&CONST_DOUBLE_LOW (dconst0_rtx), &u, sizeof u)) return (mode == DFmode ? dconst0_rtx : fconst0_rtx); if (sizeof u == 2 * sizeof (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 = real_constant_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. */ r = rtx_alloc (CONST_DOUBLE); PUT_MODE (r, mode); bcopy (&u, &CONST_DOUBLE_LOW (r), sizeof u); CONST_DOUBLE_CHAIN (r) = real_constant_chain; real_constant_chain = r; /* Store const0_rtx in slot 2 since this CONST_DOUBLE is on the chain. Actual use of slot 2 is only through force_const_double_mem. */ CONST_DOUBLE_MEM (r) = const0_rtx; return r;}/* Return a CONST_DOUBLE rtx for a value specified by EXP, which must be a REAL_CST tree node. */rtximmed_real_const (exp) tree exp;{ return immed_real_const_1 (TREE_REAL_CST (exp), TYPE_MODE (TREE_TYPE (exp)));}/* Given a CONST_DOUBLE, cause a constant in memory to be created (unless we already have one for the same value) and return a MEM rtx to refer to it. Put the CONST_DOUBLE on real_constant_chain if it isn't already there. */rtxforce_const_double_mem (r) rtx r;{ if (CONST_DOUBLE_MEM (r) == cc0_rtx) { CONST_DOUBLE_CHAIN (r) = real_constant_chain; real_constant_chain = r; CONST_DOUBLE_MEM (r) = const0_rtx; } if (CONST_DOUBLE_MEM (r) == const0_rtx) { CONST_DOUBLE_MEM (r) = force_const_mem (GET_MODE (r), r); } /* CONST_DOUBLE_MEM (r) is now a MEM with a constant address. If that is legitimate, return it. Othewise it will need reloading, so return a copy of it. */ if (memory_address_p (GET_MODE (r), XEXP (CONST_DOUBLE_MEM (r), 0))) return CONST_DOUBLE_MEM (r); return gen_rtx (MEM, GET_MODE (r), XEXP (CONST_DOUBLE_MEM (r), 0));}/* At the end of a function, forget the memory-constants previously made for CONST_DOUBLEs. Mark them as not on real_constant_chain. Also clear out real_constant_chain and clear out all the chain-pointers. */voidclear_const_double_mem (){ register rtx r, next; for (r = real_constant_chain; r; r = next) { next = CONST_DOUBLE_CHAIN (r); CONST_DOUBLE_CHAIN (r) = 0; CONST_DOUBLE_MEM (r) = cc0_rtx; } real_constant_chain = 0;}/* Given an expression EXP with a constant value, reduce it to the sum of an assembler symbol and an integer. Store them both in the structure *VALUE. Abort if EXP does not reduce. */struct addr_const{ rtx base; int offset;};static voiddecode_addr_const (exp, value) tree exp; struct addr_const *value;{ register tree target = TREE_OPERAND (exp, 0); register int offset = 0; register rtx x; while (1) { if (TREE_CODE (target) == COMPONENT_REF) { offset += DECL_OFFSET (TREE_OPERAND (target, 1)) / BITS_PER_UNIT; target = TREE_OPERAND (target, 0); } else if (TREE_CODE (target) == ARRAY_REF) { if (TREE_CODE (TREE_OPERAND (target, 1)) != INTEGER_CST || TREE_CODE (TYPE_SIZE (TREE_TYPE (target))) != INTEGER_CST) abort (); offset += ((TYPE_SIZE_UNIT (TREE_TYPE (target)) * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (target))) * TREE_INT_CST_LOW (TREE_OPERAND (target, 1))) / BITS_PER_UNIT); target = TREE_OPERAND (target, 0); } else break; } if (TREE_CODE (target) == VAR_DECL || TREE_CODE (target) == FUNCTION_DECL) x = DECL_RTL (target); else if (TREE_LITERAL (target)) x = TREE_CST_RTL (target); else abort (); if (GET_CODE (x) != MEM) abort (); x = XEXP (x, 0); value->base = x; value->offset = offset;}/* Uniquize all constants that appear in memory. Each constant in memory thus far output is recorded in `const_hash_table' with a `struct constant_descriptor' that contains a polish representation of the value of the constant. We cannot store the trees in the hash table because the trees may be temporary. */struct constant_descriptor{ struct constant_descriptor *next; char *label; char contents[1];};#define HASHBITS 30#define MAX_HASH_TABLE 1007static struct constant_descriptor *const_hash_table[MAX_HASH_TABLE];/* Compute a hash code for a constant expression. */intconst_hash (exp) tree exp;{ register char *p; register int len, hi, i; register enum tree_code code = TREE_CODE (exp); if (code == INTEGER_CST) { p = (char *) &TREE_INT_CST_LOW (exp); len = 2 * sizeof TREE_INT_CST_LOW (exp); } else if (code == REAL_CST) { p = (char *) &TREE_REAL_CST (exp); len = sizeof TREE_REAL_CST (exp); } else if (code == STRING_CST) p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp); else if (code == COMPLEX_CST) return const_hash (TREE_REALPART (exp)) * 5 + const_hash (TREE_IMAGPART (exp)); else if (code == CONSTRUCTOR) { register tree link; /* For record type, include the type in the hashing. We do not do so for array types because (1) the sizes of the elements are sufficient and (2) distinct array types can have the same constructor. */ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) hi = ((int) TREE_TYPE (exp) & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE; else hi = 5; for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE; return hi; } else if (code == ADDR_EXPR) { struct addr_const value; decode_addr_const (exp, &value); p = (char *) &value; len = sizeof value; } else if (code == PLUS_EXPR || code == MINUS_EXPR) return const_hash (TREE_OPERAND (exp, 0)) * 9 + const_hash (TREE_OPERAND (exp, 1)); else if (code == NOP_EXPR || code == CONVERT_EXPR) return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2; /* Compute hashing function */ hi = len; for (i = 0; i < len; i++) hi = ((hi * 613) + (unsigned)(p[i])); hi &= (1 << HASHBITS) - 1; hi %= MAX_HASH_TABLE; return hi;}/* Compare a constant expression EXP with a constant-descriptor DESC. Return 1 if DESC describes a constant with the same value as EXP. */static intcompare_constant (exp, desc) tree exp; struct constant_descriptor *desc;{ return 0 != compare_constant_1 (exp, desc->contents);}/* Compare constant expression EXP with a substring P of a constant descriptor. If they match, return a pointer to the end of the substring matched. If they do not match, return 0. Since descriptors are written in polish prefix notation, this function can be used recursively to test one operand of EXP against a subdescriptor, and if it succeeds it returns the address of the subdescriptor for the next operand. */static char *compare_constant_1 (exp, p) tree exp; char *p;{ register char *strp; register int len; register enum tree_code code = TREE_CODE (exp); if (code != (enum tree_code) *p++) return 0; if (code == INTEGER_CST) { /* Integer constants are the same only if the same width of type. */ if (*p++ != TYPE_PRECISION (TREE_TYPE (exp))) return 0; strp = (char *) &TREE_INT_CST_LOW (exp); len = 2 * sizeof TREE_INT_CST_LOW (exp); } else if (code == REAL_CST) { /* Real constants are the same only if the same width of type. */ if (*p++ != TYPE_PRECISION (TREE_TYPE (exp))) return 0; strp = (char *) &TREE_REAL_CST (exp); len = sizeof TREE_REAL_CST (exp); } else if (code == STRING_CST) { if (flag_writable_strings) return 0; strp = TREE_STRING_POINTER (exp); len = TREE_STRING_LENGTH (exp); if (bcmp (&TREE_STRING_LENGTH (exp), p, sizeof TREE_STRING_LENGTH (exp))) return 0; p += sizeof TREE_STRING_LENGTH (exp); } else if (code == COMPLEX_CST) { p = compare_constant_1 (TREE_REALPART (exp), p); if (p == 0) return 0; p = compare_constant_1 (TREE_IMAGPART (exp), p); return p; } else if (code == CONSTRUCTOR) { register tree link; int length = list_length (CONSTRUCTOR_ELTS (exp)); tree type; if (bcmp (&length, p, sizeof length))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -