1/* Routines for saving various data types to a file stream. This deals 2 with various data types like strings, integers, enums, etc. 3 4 Copyright (C) 2011-2015 Free Software Foundation, Inc. 5 Contributed by Diego Novillo <dnovillo@google.com> 6 7This file is part of GCC. 8 9GCC is free software; you can redistribute it and/or modify it under 10the terms of the GNU General Public License as published by the Free 11Software Foundation; either version 3, or (at your option) any later 12version. 13 14GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15WARRANTY; without even the implied warranty of MERCHANTABILITY or 16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17for more details. 18 19You should have received a copy of the GNU General Public License 20along with GCC; see the file COPYING3. If not see 21<http://www.gnu.org/licenses/>. */ 22 23#include "config.h" 24#include "system.h" 25#include "coretypes.h" 26#include "hash-set.h" 27#include "machmode.h" 28#include "vec.h" 29#include "double-int.h" 30#include "input.h" 31#include "alias.h" 32#include "symtab.h" 33#include "options.h" 34#include "wide-int.h" 35#include "inchash.h" 36#include "tree.h" 37#include "fold-const.h" 38#include "predict.h" 39#include "tm.h" 40#include "hard-reg-set.h" 41#include "input.h" 42#include "function.h" 43#include "basic-block.h" 44#include "tree-ssa-alias.h" 45#include "internal-fn.h" 46#include "gimple-expr.h" 47#include "is-a.h" 48#include "gimple.h" 49#include "hash-map.h" 50#include "plugin-api.h" 51#include "ipa-ref.h" 52#include "cgraph.h" 53#include "data-streamer.h" 54 55 56/* Adds a new block to output stream OBS. */ 57 58void 59lto_append_block (struct lto_output_stream *obs) 60{ 61 struct lto_char_ptr_base *new_block; 62 63 gcc_assert (obs->left_in_block == 0); 64 65 if (obs->first_block == NULL) 66 { 67 /* This is the first time the stream has been written 68 into. */ 69 obs->block_size = 1024; 70 new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); 71 obs->first_block = new_block; 72 } 73 else 74 { 75 struct lto_char_ptr_base *tptr; 76 /* Get a new block that is twice as big as the last block 77 and link it into the list. */ 78 obs->block_size *= 2; 79 new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); 80 /* The first bytes of the block are reserved as a pointer to 81 the next block. Set the chain of the full block to the 82 pointer to the new block. */ 83 tptr = obs->current_block; 84 tptr->ptr = (char *) new_block; 85 } 86 87 /* Set the place for the next char at the first position after the 88 chain to the next block. */ 89 obs->current_pointer 90 = ((char *) new_block) + sizeof (struct lto_char_ptr_base); 91 obs->current_block = new_block; 92 /* Null out the newly allocated block's pointer to the next block. */ 93 new_block->ptr = NULL; 94 obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base); 95} 96 97 98/* Return index used to reference STRING of LEN characters in the string table 99 in OB. The string might or might not include a trailing '\0'. 100 Then put the index onto the INDEX_STREAM. 101 When PERSISTENT is set, the string S is supposed to not change during 102 duration of the OB and thus OB can keep pointer into it. */ 103 104static unsigned 105streamer_string_index (struct output_block *ob, const char *s, unsigned int len, 106 bool persistent) 107{ 108 struct string_slot **slot; 109 struct string_slot s_slot; 110 111 s_slot.s = s; 112 s_slot.len = len; 113 s_slot.slot_num = 0; 114 115 slot = ob->string_hash_table->find_slot (&s_slot, INSERT); 116 if (*slot == NULL) 117 { 118 struct lto_output_stream *string_stream = ob->string_stream; 119 unsigned int start = string_stream->total_size; 120 struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot); 121 const char *string; 122 123 if (!persistent) 124 { 125 char *tmp; 126 string = tmp = XOBNEWVEC (&ob->obstack, char, len); 127 memcpy (tmp, s, len); 128 } 129 else 130 string = s; 131 132 new_slot->s = string; 133 new_slot->len = len; 134 new_slot->slot_num = start; 135 *slot = new_slot; 136 streamer_write_uhwi_stream (string_stream, len); 137 streamer_write_data_stream (string_stream, string, len); 138 return start + 1; 139 } 140 else 141 { 142 struct string_slot *old_slot = *slot; 143 return old_slot->slot_num + 1; 144 } 145} 146 147 148/* Output STRING of LEN characters to the string table in OB. The 149 string might or might not include a trailing '\0'. Then put the 150 index onto the INDEX_STREAM. 151 When PERSISTENT is set, the string S is supposed to not change during 152 duration of the OB and thus OB can keep pointer into it. */ 153 154void 155streamer_write_string_with_length (struct output_block *ob, 156 struct lto_output_stream *index_stream, 157 const char *s, unsigned int len, 158 bool persistent) 159{ 160 if (s) 161 streamer_write_uhwi_stream (index_stream, 162 streamer_string_index (ob, s, len, persistent)); 163 else 164 streamer_write_char_stream (index_stream, 0); 165} 166 167 168/* Output the '\0' terminated STRING to the string 169 table in OB. Then put the index onto the INDEX_STREAM. 170 When PERSISTENT is set, the string S is supposed to not change during 171 duration of the OB and thus OB can keep pointer into it. */ 172 173void 174streamer_write_string (struct output_block *ob, 175 struct lto_output_stream *index_stream, 176 const char *string, bool persistent) 177{ 178 if (string) 179 streamer_write_string_with_length (ob, index_stream, string, 180 strlen (string) + 1, 181 persistent); 182 else 183 streamer_write_char_stream (index_stream, 0); 184} 185 186 187/* Output STRING of LEN characters to the string table in OB. Then 188 put the index into BP. 189 When PERSISTENT is set, the string S is supposed to not change during 190 duration of the OB and thus OB can keep pointer into it. */ 191 192void 193bp_pack_string_with_length (struct output_block *ob, struct bitpack_d *bp, 194 const char *s, unsigned int len, bool persistent) 195{ 196 unsigned index = 0; 197 if (s) 198 index = streamer_string_index (ob, s, len, persistent); 199 bp_pack_var_len_unsigned (bp, index); 200} 201 202 203/* Output the '\0' terminated STRING to the string 204 table in OB. Then put the index onto the bitpack BP. 205 When PERSISTENT is set, the string S is supposed to not change during 206 duration of the OB and thus OB can keep pointer into it. */ 207 208void 209bp_pack_string (struct output_block *ob, struct bitpack_d *bp, 210 const char *s, bool persistent) 211{ 212 unsigned index = 0; 213 if (s) 214 index = streamer_string_index (ob, s, strlen (s) + 1, persistent); 215 bp_pack_var_len_unsigned (bp, index); 216} 217 218 219 220/* Write a zero to the output stream. */ 221 222void 223streamer_write_zero (struct output_block *ob) 224{ 225 streamer_write_char_stream (ob->main_stream, 0); 226} 227 228 229/* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream. */ 230 231void 232streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work) 233{ 234 streamer_write_uhwi_stream (ob->main_stream, work); 235} 236 237 238/* Write a HOST_WIDE_INT value WORK to OB->main_stream. */ 239 240void 241streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work) 242{ 243 streamer_write_hwi_stream (ob->main_stream, work); 244} 245 246/* Write a gcov counter value WORK to OB->main_stream. */ 247 248void 249streamer_write_gcov_count (struct output_block *ob, gcov_type work) 250{ 251 streamer_write_gcov_count_stream (ob->main_stream, work); 252} 253 254/* Write an unsigned HOST_WIDE_INT value WORK to OBS. */ 255 256void 257streamer_write_uhwi_stream (struct lto_output_stream *obs, 258 unsigned HOST_WIDE_INT work) 259{ 260 if (obs->left_in_block == 0) 261 lto_append_block (obs); 262 char *current_pointer = obs->current_pointer; 263 unsigned int left_in_block = obs->left_in_block; 264 unsigned int size = 0; 265 do 266 { 267 unsigned int byte = (work & 0x7f); 268 work >>= 7; 269 if (work != 0) 270 /* More bytes to follow. */ 271 byte |= 0x80; 272 273 *(current_pointer++) = byte; 274 left_in_block--; 275 size++; 276 } 277 while (work != 0 && left_in_block > 0); 278 if (work != 0) 279 { 280 obs->left_in_block = 0; 281 lto_append_block (obs); 282 current_pointer = obs->current_pointer; 283 left_in_block = obs->left_in_block; 284 do 285 { 286 unsigned int byte = (work & 0x7f); 287 work >>= 7; 288 if (work != 0) 289 /* More bytes to follow. */ 290 byte |= 0x80; 291 292 *(current_pointer++) = byte; 293 left_in_block--; 294 size++; 295 } 296 while (work != 0); 297 } 298 obs->current_pointer = current_pointer; 299 obs->left_in_block = left_in_block; 300 obs->total_size += size; 301} 302 303 304/* Write a HOST_WIDE_INT value WORK to OBS. */ 305 306void 307streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work) 308{ 309 if (obs->left_in_block == 0) 310 lto_append_block (obs); 311 char *current_pointer = obs->current_pointer; 312 unsigned int left_in_block = obs->left_in_block; 313 unsigned int size = 0; 314 bool more; 315 do 316 { 317 unsigned int byte = (work & 0x7f); 318 /* If the lower 7-bits are sign-extended 0 or -1 we are finished. */ 319 work >>= 6; 320 more = !(work == 0 || work == -1); 321 if (more) 322 { 323 /* More bits to follow. */ 324 work >>= 1; 325 byte |= 0x80; 326 } 327 328 *(current_pointer++) = byte; 329 left_in_block--; 330 size++; 331 } 332 while (more && left_in_block > 0); 333 if (more) 334 { 335 obs->left_in_block = 0; 336 lto_append_block (obs); 337 current_pointer = obs->current_pointer; 338 left_in_block = obs->left_in_block; 339 do 340 { 341 unsigned int byte = (work & 0x7f); 342 work >>= 6; 343 more = !(work == 0 || work == -1); 344 if (more) 345 { 346 work >>= 1; 347 byte |= 0x80; 348 } 349 350 *(current_pointer++) = byte; 351 left_in_block--; 352 size++; 353 } 354 while (more); 355 } 356 obs->current_pointer = current_pointer; 357 obs->left_in_block = left_in_block; 358 obs->total_size += size; 359} 360 361/* Write a GCOV counter value WORK to OBS. */ 362 363void 364streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work) 365{ 366 gcc_assert (work >= 0); 367 gcc_assert ((HOST_WIDE_INT) work == work); 368 streamer_write_hwi_stream (obs, work); 369} 370 371/* Write raw DATA of length LEN to the output block OB. */ 372 373void 374streamer_write_data_stream (struct lto_output_stream *obs, const void *data, 375 size_t len) 376{ 377 while (len) 378 { 379 size_t copy; 380 381 /* No space left. */ 382 if (obs->left_in_block == 0) 383 lto_append_block (obs); 384 385 /* Determine how many bytes to copy in this loop. */ 386 if (len <= obs->left_in_block) 387 copy = len; 388 else 389 copy = obs->left_in_block; 390 391 /* Copy the data and do bookkeeping. */ 392 memcpy (obs->current_pointer, data, copy); 393 obs->current_pointer += copy; 394 obs->total_size += copy; 395 obs->left_in_block -= copy; 396 data = (const char *) data + copy; 397 len -= copy; 398 } 399} 400 401