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 7 This file is part of GCC. 8 9 GCC is free software; you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free 11 Software Foundation; either version 3, or (at your option) any later 12 version. 13 14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15 WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17 for more details. 18 19 You should have received a copy of the GNU General Public License 20 along 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 58 void 59 lto_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 104 static unsigned 105 streamer_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 154 void 155 streamer_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 173 void 174 streamer_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 192 void 193 bp_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 208 void 209 bp_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 222 void 223 streamer_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 231 void 232 streamer_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 240 void 241 streamer_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 248 void 249 streamer_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 256 void 257 streamer_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 306 void 307 streamer_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 363 void 364 streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work) 365 { 366 gcc_assert ((HOST_WIDE_INT) work == work); 367 streamer_write_hwi_stream (obs, work); 368 } 369 370 /* Write raw DATA of length LEN to the output block OB. */ 371 372 void 373 streamer_write_data_stream (struct lto_output_stream *obs, const void *data, 374 size_t len) 375 { 376 while (len) 377 { 378 size_t copy; 379 380 /* No space left. */ 381 if (obs->left_in_block == 0) 382 lto_append_block (obs); 383 384 /* Determine how many bytes to copy in this loop. */ 385 if (len <= obs->left_in_block) 386 copy = len; 387 else 388 copy = obs->left_in_block; 389 390 /* Copy the data and do bookkeeping. */ 391 memcpy (obs->current_pointer, data, copy); 392 obs->current_pointer += copy; 393 obs->total_size += copy; 394 obs->left_in_block -= copy; 395 data = (const char *) data + copy; 396 len -= copy; 397 } 398 } 399 400