| /* Routines for restoring various data types from a file stream. This deals |
| with various data types like strings, integers, enums, etc. |
| |
| Copyright (C) 2011-2017 Free Software Foundation, Inc. |
| Contributed by Diego Novillo <dnovillo@google.com> |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "backend.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "cgraph.h" |
| #include "data-streamer.h" |
| |
| /* Read a string from the string table in DATA_IN using input block |
| IB. Write the length to RLEN. */ |
| |
| static const char * |
| string_for_index (struct data_in *data_in, unsigned int loc, unsigned int *rlen) |
| { |
| unsigned int len; |
| const char *result; |
| |
| if (!loc) |
| { |
| *rlen = 0; |
| return NULL; |
| } |
| |
| /* Get the string stored at location LOC in DATA_IN->STRINGS. */ |
| lto_input_block str_tab (data_in->strings, loc - 1, data_in->strings_len, NULL); |
| len = streamer_read_uhwi (&str_tab); |
| *rlen = len; |
| |
| if (str_tab.p + len > data_in->strings_len) |
| internal_error ("bytecode stream: string too long for the string table"); |
| |
| result = (const char *)(data_in->strings + str_tab.p); |
| |
| return result; |
| } |
| |
| |
| /* Read a string from the string table in DATA_IN using input block |
| IB. Write the length to RLEN. */ |
| |
| const char * |
| streamer_read_indexed_string (struct data_in *data_in, |
| struct lto_input_block *ib, unsigned int *rlen) |
| { |
| return string_for_index (data_in, streamer_read_uhwi (ib), rlen); |
| } |
| |
| |
| /* Read a NULL terminated string from the string table in DATA_IN. */ |
| |
| const char * |
| streamer_read_string (struct data_in *data_in, struct lto_input_block *ib) |
| { |
| unsigned int len; |
| const char *ptr; |
| |
| ptr = streamer_read_indexed_string (data_in, ib, &len); |
| if (!ptr) |
| return NULL; |
| if (ptr[len - 1] != '\0') |
| internal_error ("bytecode stream: found non-null terminated string"); |
| |
| return ptr; |
| } |
| |
| |
| /* Read a string from the string table in DATA_IN using the bitpack BP. |
| Write the length to RLEN. */ |
| |
| const char * |
| bp_unpack_indexed_string (struct data_in *data_in, |
| struct bitpack_d *bp, unsigned int *rlen) |
| { |
| return string_for_index (data_in, bp_unpack_var_len_unsigned (bp), rlen); |
| } |
| |
| |
| /* Read a NULL terminated string from the string table in DATA_IN. */ |
| |
| const char * |
| bp_unpack_string (struct data_in *data_in, struct bitpack_d *bp) |
| { |
| unsigned int len; |
| const char *ptr; |
| |
| ptr = bp_unpack_indexed_string (data_in, bp, &len); |
| if (!ptr) |
| return NULL; |
| if (ptr[len - 1] != '\0') |
| internal_error ("bytecode stream: found non-null terminated string"); |
| |
| return ptr; |
| } |
| |
| |
| /* Read an unsigned HOST_WIDE_INT number from IB. */ |
| |
| unsigned HOST_WIDE_INT |
| streamer_read_uhwi (struct lto_input_block *ib) |
| { |
| unsigned HOST_WIDE_INT result; |
| int shift; |
| unsigned HOST_WIDE_INT byte; |
| unsigned int p = ib->p; |
| unsigned int len = ib->len; |
| |
| const char *data = ib->data; |
| result = data[p++]; |
| if ((result & 0x80) != 0) |
| { |
| result &= 0x7f; |
| shift = 7; |
| do |
| { |
| byte = data[p++]; |
| result |= (byte & 0x7f) << shift; |
| shift += 7; |
| } |
| while ((byte & 0x80) != 0); |
| } |
| |
| /* We check for section overrun after the fact for performance reason. */ |
| if (p > len) |
| lto_section_overrun (ib); |
| |
| ib->p = p; |
| return result; |
| } |
| |
| |
| /* Read a HOST_WIDE_INT number from IB. */ |
| |
| HOST_WIDE_INT |
| streamer_read_hwi (struct lto_input_block *ib) |
| { |
| HOST_WIDE_INT result = 0; |
| int shift = 0; |
| unsigned HOST_WIDE_INT byte; |
| |
| while (true) |
| { |
| byte = streamer_read_uchar (ib); |
| result |= (byte & 0x7f) << shift; |
| shift += 7; |
| if ((byte & 0x80) == 0) |
| { |
| if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40)) |
| result |= - (HOST_WIDE_INT_1U << shift); |
| |
| return result; |
| } |
| } |
| } |
| |
| /* Read gcov_type value from IB. */ |
| |
| gcov_type |
| streamer_read_gcov_count (struct lto_input_block *ib) |
| { |
| gcov_type ret = streamer_read_hwi (ib); |
| return ret; |
| } |
| |
| /* Read the physical representation of a wide_int val from |
| input block IB. */ |
| |
| wide_int |
| streamer_read_wide_int (struct lto_input_block *ib) |
| { |
| HOST_WIDE_INT a[WIDE_INT_MAX_ELTS]; |
| int i; |
| int prec = streamer_read_uhwi (ib); |
| int len = streamer_read_uhwi (ib); |
| for (i = 0; i < len; i++) |
| a[i] = streamer_read_hwi (ib); |
| return wide_int::from_array (a, len, prec); |
| } |
| |
| /* Read the physical representation of a widest_int val from |
| input block IB. */ |
| |
| widest_int |
| streamer_read_widest_int (struct lto_input_block *ib) |
| { |
| HOST_WIDE_INT a[WIDE_INT_MAX_ELTS]; |
| int i; |
| int prec ATTRIBUTE_UNUSED = streamer_read_uhwi (ib); |
| int len = streamer_read_uhwi (ib); |
| for (i = 0; i < len; i++) |
| a[i] = streamer_read_hwi (ib); |
| return widest_int::from_array (a, len); |
| } |
| |