📄 varasm.c
字号:
/* Align the location counter as required by EXP's data type. */ align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode); if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT) align = BIGGEST_ALIGNMENT / BITS_PER_UNIT; if (align > 1) ASM_OUTPUT_ALIGN (asm_out_file, exact_log2 (align)); /* Output the label itself. */ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", const_labelno); /* Output the value of EXP. */ if (GET_CODE (x) == CONST_DOUBLE) { union real_extract u; bcopy (&CONST_DOUBLE_LOW (x), &u, sizeof u); switch (mode) { /* Perhaps change the following to use CONST_DOUBLE_LOW and CONST_DOUBLE_HIGH, rather than u.i. */ case DImode:#ifdef ASM_OUTPUT_DOUBLE_INT ASM_OUTPUT_DOUBLE_INT (asm_out_file, x);#else /* no ASM_OUTPUT_DOUBLE_INT */#ifndef WORDS_BIG_ENDIAN /* Output two ints. */ ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, u.i[0])); ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, u.i[1]));#else /* Output two ints. */ ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, u.i[1])); ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, u.i[0]));#endif /* WORDS_BIG_ENDIAN */#endif /* no ASM_OUTPUT_DOUBLE_INT */ break; case DFmode: ASM_OUTPUT_DOUBLE (asm_out_file, u.d); break; case SFmode: ASM_OUTPUT_FLOAT (asm_out_file, u.d); } } else switch (mode) { case SImode: ASM_OUTPUT_INT (asm_out_file, x); break; case HImode: ASM_OUTPUT_SHORT (asm_out_file, x); break; case QImode: ASM_OUTPUT_CHAR (asm_out_file, x); break; } /* Create a string containing the label name, in LABEL. */ ASM_GENERATE_INTERNAL_LABEL (label, "LC", const_labelno); ++const_labelno; desc->label = found = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label)); } /* We have a symbol name; construct the SYMBOL_REF and the MEM. */ def = gen_rtx (MEM, mode, gen_rtx (SYMBOL_REF, Pmode, desc->label)); RTX_UNCHANGING_P (def) = 1; /* Mark the symbol_ref as belonging to this constants pool. */ CONSTANT_POOL_ADDRESS_P (XEXP (def, 0)) = 1; if (GET_CODE (x) == CONST_DOUBLE) { if (CONST_DOUBLE_MEM (x) == cc0_rtx) { CONST_DOUBLE_CHAIN (x) = real_constant_chain; real_constant_chain = x; } CONST_DOUBLE_MEM (x) = def; } return def;}/* Find all the constants whose addresses are referenced inside of EXP, and make sure assembler code with a label has been output for each one. */voidoutput_addressed_constants (exp) tree exp;{ switch (TREE_CODE (exp)) { case ADDR_EXPR: { register tree constant = TREE_OPERAND (exp, 0); while (TREE_CODE (constant) == COMPONENT_REF) { constant = TREE_OPERAND (constant, 0); } if (TREE_LITERAL (constant)) /* No need to do anything here for addresses of variables or functions. */ output_constant_def (constant); } break; case PLUS_EXPR: case MINUS_EXPR: output_addressed_constants (TREE_OPERAND (exp, 0)); output_addressed_constants (TREE_OPERAND (exp, 1)); break; case NOP_EXPR: case CONVERT_EXPR: output_addressed_constants (TREE_OPERAND (exp, 0)); break; case CONSTRUCTOR: { register tree link; for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link)) output_addressed_constants (TREE_VALUE (link)); } break; case ERROR_MARK: break; default: if (! TREE_LITERAL (exp)) abort (); }}/* Output assembler code for constant EXP to FILE, with no label. This includes the pseudo-op such as ".int" or ".byte", and a newline. Assumes output_addressed_constants has been done on EXP already. Generate exactly SIZE bytes of assembler data, padding at the end with zeros if necessary. SIZE must always be specified. SIZE is important for structure constructors, since trailing members may have been omitted from the constructor. It is also important for initialization of arrays from string constants since the full length of the string constant might not be wanted. It is also needed for initialization of unions, where the initializer's type is just one member, and that may not be as long as the union. There a case in which we would fail to output exactly SIZE bytes: for a structure constructor that wants to produce more than SIZE bytes. But such constructors will never be generated for any possible input. */voidoutput_constant (exp, size) register tree exp; register int size;{ register enum tree_code code = TREE_CODE (TREE_TYPE (exp)); rtx x; if (size == 0) return; /* Eliminate the NOP_EXPR that makes a cast not be an lvalue. That way we get the constant (we hope) inside it. */ if (TREE_CODE (exp) == NOP_EXPR && TREE_TYPE (exp) == TREE_TYPE (TREE_OPERAND (exp, 0))) exp = TREE_OPERAND (exp, 0); switch (code) { case INTEGER_TYPE: case ENUMERAL_TYPE: case POINTER_TYPE: case REFERENCE_TYPE: /* ??? What about (int)((float)(int)&foo + 4) */ while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR) exp = TREE_OPERAND (exp, 0);#ifndef ASM_OUTPUT_DOUBLE_INT if (TYPE_MODE (TREE_TYPE (exp)) == DImode) { if (TREE_CODE (exp) == INTEGER_CST) {#ifndef WORDS_BIG_ENDIAN ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp))); ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_HIGH (exp)));#else ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_HIGH (exp))); ASM_OUTPUT_INT (asm_out_file, gen_rtx (CONST_INT, VOIDmode, TREE_INT_CST_LOW (exp)));#endif size -= 8; break; } else error ("8-byte integer constant expression too complicated"); break; }#endif /* no ASM_OUTPUT_DOUBLE_INT */ x = expand_expr (exp, 0, VOIDmode, EXPAND_SUM); if (size == 1) { ASM_OUTPUT_CHAR (asm_out_file, x); size -= 1; } else if (size == 2) { ASM_OUTPUT_SHORT (asm_out_file, x); size -= 2; } else if (size == 4) { ASM_OUTPUT_INT (asm_out_file, x); size -= 4; }#ifdef ASM_OUTPUT_DOUBLE_INT else if (size == 8) { ASM_OUTPUT_DOUBLE_INT (asm_out_file, x); size -= 8; }#endif /* ASM_OUTPUT_DOUBLE_INT */ else abort (); break; case REAL_TYPE: if (TREE_CODE (exp) != REAL_CST) error ("initializer for floating value is not a floating constant"); else { REAL_VALUE_TYPE d; jmp_buf output_constant_handler; d = TREE_REAL_CST (exp); if (setjmp (output_constant_handler)) { error ("floating point trap outputting a constant");#ifdef REAL_IS_NOT_DOUBLE bzero (&d, sizeof d); d = REAL_VALUE_ATOF ("0");#else d = 0;#endif } set_float_handler (output_constant_handler); if (size < 4) break; else if (size < 8) { ASM_OUTPUT_FLOAT (asm_out_file, d); size -= 4; } else { ASM_OUTPUT_DOUBLE (asm_out_file, d); size -= 8; } set_float_handler (0); } break; case COMPLEX_TYPE: output_constant (TREE_REALPART (exp), size / 2); output_constant (TREE_IMAGPART (exp), size / 2); size -= (size / 2) * 2; break; case ARRAY_TYPE: if (TREE_CODE (exp) == CONSTRUCTOR) { output_constructor (exp, size); return; } else if (TREE_CODE (exp) == STRING_CST) { int excess = 0; if (size > TREE_STRING_LENGTH (exp)) { excess = size - TREE_STRING_LENGTH (exp); size = TREE_STRING_LENGTH (exp); } assemble_string (TREE_STRING_POINTER (exp), size); size = excess; } else abort (); break; case RECORD_TYPE: case UNION_TYPE: if (TREE_CODE (exp) == CONSTRUCTOR) output_constructor (exp, size); else abort (); return; } if (size > 0) ASM_OUTPUT_SKIP (asm_out_file, size);}/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants). Generate at least SIZE bytes, padding if necessary. */voidoutput_constructor (exp, size) tree exp; int size;{ register tree link, field = 0; /* Number of bytes output or skipped so far. In other words, current position within the constructor. */ int total_bytes = 0; /* Non-zero means BYTE contains part of a byte, to be output. */ int byte_buffer_in_use = 0; register int byte; if (HOST_BITS_PER_INT < BITS_PER_UNIT) abort (); if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE) field = TYPE_FIELDS (TREE_TYPE (exp)); /* As LINK goes through the elements of the constant, FIELD goes through the structure fields, if the constant is a structure. But the constant could also be an array. Then FIELD is zero. */ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link), field = field ? TREE_CHAIN (field) : 0) { tree val = TREE_VALUE (link); /* Eliminate the NOP_EXPR that makes a cast not be an lvalue. */ if (TREE_CODE (val) == NOP_EXPR && TREE_TYPE (val) == TREE_TYPE (TREE_OPERAND (val, 0))) val = TREE_OPERAND (val, 0); if (field == 0 || (DECL_MODE (field) != BImode)) { register int fieldsize; /* An element that is not a bit-field. Output any buffered-up bit-fields preceding it. */ if (byte_buffer_in_use) { ASM_OUTPUT_BYTE (asm_out_file, byte); total_bytes++; byte_buffer_in_use = 0; } /* Advance to offset of this element. Note no alignment needed in an array, since that is guaranteed if each element has the proper size. */ if (field != 0 && DECL_OFFSET (field) / BITS_PER_UNIT != total_bytes) { ASM_OUTPUT_SKIP (asm_out_file, (DECL_OFFSET (field) / BITS_PER_UNIT - total_bytes)); total_bytes = DECL_OFFSET (field) / BITS_PER_UNIT; } /* Determine size this element should occupy. */ if (field) { if (! TREE_LITERAL (DECL_SIZE (field))) abort (); fieldsize = TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field); fieldsize = (fieldsize + BITS_PER_UNIT - 1) / BITS_PER_UNIT; } else fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp))); /* Output the element's initial value. */ output_constant (val, fieldsize); /* Count its size. */ total_bytes += fieldsize; } else if (TREE_CODE (val) != INTEGER_CST) error ("invalid initial value for member `%s'", IDENTIFIER_POINTER (DECL_NAME (field))); else { /* Element that is a bit-field. */ int next_offset = DECL_OFFSET (field); int end_offset = (next_offset + (TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field))); /* If this field does not start in this (or, next) byte, skip some bytes. */ if (next_offset / BITS_PER_UNIT != total_bytes) { /* Output remnant of any bit field in previous bytes. */ if (byte_buffer_in_use) { ASM_OUTPUT_BYTE (asm_out_file, byte); total_bytes++; byte_buffer_in_use = 0; } /* If still not at proper byte, advance to there. */ if (next_offset / BITS_PER_UNIT != total_bytes) { ASM_OUTPUT_SKIP (asm_out_file, next_offset / BITS_PER_UNIT - total_bytes); total_bytes = next_offset / BITS_PER_UNIT; } } if (! byte_buffer_in_use) byte = 0; /* We must split the element into pieces that fall within separate bytes, and combine each byte with previous or following bit-fields. */ /* next_offset is the offset n fbits from the begining of the structure to the next bit of this element to be processed. end_offset is the offset of the first bit past the end of this element. */ while (next_offset < end_offset) { int this_time; int next_byte = next_offset / BITS_PER_UNIT; int next_bit = next_offset % BITS_PER_UNIT; /* Advance from byte to byte within this element when necessary. */ while (next_byte != total_bytes) { ASM_OUTPUT_BYTE (asm_out_file, byte); total_bytes++; byte = 0; } /* Number of bits we can process at once (all part of the same byte). */ this_time = MIN (end_offset - next_offset, BITS_PER_UNIT - next_bit);#ifdef BYTES_BIG_ENDIAN /* On big-endian machine, take the most significant bits first (of the bits that are significant) and put them into bytes from the most significant end. */ byte |= (((TREE_INT_CST_LOW (val) >> (end_offset - next_offset - this_time)) & ((1 << this_time) - 1)) << (BITS_PER_UNIT - this_time - next_bit));#else /* On little-endian machines, take first the least significant bits of the value and pack them starting at the least significant bits of the bytes. */ byte |= ((TREE_INT_CST_LOW (val) >> (next_offset - DECL_OFFSET (field))) & ((1 << this_time) - 1)) << next_bit;#endif next_offset += this_time; byte_buffer_in_use = 1; } } } if (byte_buffer_in_use) { ASM_OUTPUT_BYTE (asm_out_file, byte); total_bytes++; } if (total_bytes < size) ASM_OUTPUT_SKIP (asm_out_file, size - total_bytes);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -