📄 varasm.c
字号:
/* Store const0_rtx in CONST_DOUBLE_MEM since this CONST_DOUBLE is on the chain, but has not been allocated memory. Actual use of CONST_DOUBLE_MEM is only through force_const_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)));}/* 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; /* Don't touch CONST_DOUBLE_MEM for nested functions. See force_const_mem for explanation. */ if (outer_function_chain != 0) return; for (r = const_double_chain; r; r = next) { next = CONST_DOUBLE_CHAIN (r); CONST_DOUBLE_CHAIN (r) = 0; CONST_DOUBLE_MEM (r) = cc0_rtx; } const_double_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; HOST_WIDE_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 && (TREE_CODE (DECL_FIELD_BITPOS (TREE_OPERAND (target, 1))) == INTEGER_CST)) { offset += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (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 += ((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; } switch (TREE_CODE (target)) { case VAR_DECL: case FUNCTION_DECL: x = DECL_RTL (target); break; case LABEL_DECL: x = gen_rtx (MEM, FUNCTION_MODE, gen_rtx (LABEL_REF, VOIDmode, label_rtx (TREE_OPERAND (exp, 0)))); break; case REAL_CST: case STRING_CST: case COMPLEX_CST: case CONSTRUCTOR: x = TREE_CST_RTL (target); break; default: 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 1009static 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. Instead, we include the array size because the constructor could be shorter. */ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE; else hi = ((5 + int_size_in_bytes (TREE_TYPE (exp))) & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE; for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) if (TREE_VALUE (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); if (GET_CODE (value.base) == SYMBOL_REF) { /* Don't hash the address of the SYMBOL_REF; only use the offset and the symbol name. */ hi = value.offset; p = XSTR (value.base, 0); for (i = 0; p[i] != 0; i++) hi = ((hi * 613) + (unsigned)(p[i])); } else if (GET_CODE (value.base) == LABEL_REF) hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13; hi &= (1 << HASHBITS) - 1; hi %= MAX_HASH_TABLE; return hi; } 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)) return 0; p += sizeof length; /* For record constructors, insist that the types match. For arrays, just verify both constructors are for arrays. */ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) type = TREE_TYPE (exp); else type = 0; if (bcmp (&type, p, sizeof type)) return 0; p += sizeof type; /* For arrays, insist that the size in bytes match. */ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) { int size = int_size_in_bytes (TREE_TYPE (exp)); if (bcmp (&size, p, sizeof size)) return 0; p += sizeof size; } for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) { if (TREE_VALUE (link)) { if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0) return 0; } else { tree zero = 0; if (bcmp (&zero, p, sizeof zero)) return 0; p += sizeof zero; } } return p; } else if (code == ADDR_EXPR) { struct addr_const value; decode_addr_const (exp, &value); strp = (char *) &value.offset; len = sizeof value.offset; /* Compare the offset. */ while (--len >= 0) if (*p++ != *strp++) return 0; /* Compare symbol name. */ strp = XSTR (value.base, 0); len = strlen (strp) + 1; } else if (code == PLUS_EXPR || code == MINUS_EXPR) { p = compare_constant_1 (TREE_OPERAND (exp, 0), p); if (p == 0) return 0; p = compare_constant_1 (TREE_OPERAND (exp, 1), p); return p; } else if (code == NOP_EXPR || code == CONVERT_EXPR) { p = compare_constant_1 (TREE_OPERAND (exp, 0), p); return p; } /* Compare constant contents. */ while (--len >= 0) if (*p++ != *strp++) return 0; return p;}/* Construct a constant descriptor for the expression EXP. It is up to the caller to enter the descriptor in the hash table. */static struct constant_descriptor *record_constant (exp) tree exp;{ struct constant_descriptor *ptr = 0; int buf; obstack_grow (&permanent_obstack, &ptr, sizeof ptr); obstack_grow (&permanent_obstack, &buf, sizeof buf); record_constant_1 (exp); return (struct constant_descriptor *) obstack_finish (&permanent_obstack);}/* Add a description of constant expression EXP to the object growing in `permanent_obstack'. No need to return its address; the caller will get that from the obstack when the object is complete. */static voidrecord_constant_1 (exp) tree exp;{ register char *strp; register int len; register enum tree_code code = TREE_CODE (exp); obstack_1grow (&permanent_obstack, (unsigned int) code); if (code == INTEGER_CST) { obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp))); strp = (char *) &TREE_INT_CST_LOW (exp); len = 2 * sizeof TREE_INT_CST_LOW (exp); } else if (code == REAL_CST) { obstack_1grow (&permanent_obstack, TYPE_PRECISION (TREE_TYPE (exp))); strp = (char *) &TREE_REAL_CST (exp); len = sizeof TREE_REAL_CST (exp); } else if (code == STRING_CST) { if (flag_writable_strings) return; strp = TREE_STRING_POINTER (exp); len = TREE_STRING_LENGTH (exp); obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp), sizeof TREE_STRING_LENGTH (exp)); } else if (code == COMPLEX_CST) { record_constant_1 (TREE_REALPART (exp)); record_constant_1 (TREE_IMAGPART (exp)); return; } else if (code == CONSTRUCTOR) { register tree link; int length = list_length (CONSTRUCTOR_ELTS (exp)); tree type; obstack_grow (&permanent_obstack, (char *) &length, sizeof length); /* For record constructors, insist that the types match. For arrays, just verify both constructors are for arrays. */ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE) type = TREE_TYPE (exp); else type = 0; obstack_grow (&permanent_obstack, (char *) &type, sizeof type); /* For arrays, insist that the size in bytes match. */ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE) { int size = int_size_in_bytes (TREE_TYPE (exp)); obstack_grow (&permanent_obstack, (char *) &size, sizeof size); } for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) { if (TREE_VALUE (link)) record_constant_1 (TREE_VALUE (link)); else { tree zero = 0; obstack_grow (&permanent_obstack, (char *) &zero, sizeof zero); } } return; } else if (code == ADDR_EXPR) { struct addr_const value; decode_addr_const (exp, &value); /* Record the offset. */ obstack_grow (&permanent_obstack,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -