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-2018 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 "backend.h" 27 #include "tree.h" 28 #include "gimple.h" 29 #include "cgraph.h" 30 #include "data-streamer.h" 31 32 33 /* Adds a new block to output stream OBS. */ 34 35 void 36 lto_append_block (struct lto_output_stream *obs) 37 { 38 struct lto_char_ptr_base *new_block; 39 40 gcc_assert (obs->left_in_block == 0); 41 42 if (obs->first_block == NULL) 43 { 44 /* This is the first time the stream has been written 45 into. */ 46 obs->block_size = 1024; 47 new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); 48 obs->first_block = new_block; 49 } 50 else 51 { 52 struct lto_char_ptr_base *tptr; 53 /* Get a new block that is twice as big as the last block 54 and link it into the list. */ 55 obs->block_size *= 2; 56 new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); 57 /* The first bytes of the block are reserved as a pointer to 58 the next block. Set the chain of the full block to the 59 pointer to the new block. */ 60 tptr = obs->current_block; 61 tptr->ptr = (char *) new_block; 62 } 63 64 /* Set the place for the next char at the first position after the 65 chain to the next block. */ 66 obs->current_pointer 67 = ((char *) new_block) + sizeof (struct lto_char_ptr_base); 68 obs->current_block = new_block; 69 /* Null out the newly allocated block's pointer to the next block. */ 70 new_block->ptr = NULL; 71 obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base); 72 } 73 74 75 /* Return index used to reference STRING of LEN characters in the string table 76 in OB. The string might or might not include a trailing '\0'. 77 Then put the index onto the INDEX_STREAM. 78 When PERSISTENT is set, the string S is supposed to not change during 79 duration of the OB and thus OB can keep pointer into it. */ 80 81 static unsigned 82 streamer_string_index (struct output_block *ob, const char *s, unsigned int len, 83 bool persistent) 84 { 85 struct string_slot **slot; 86 struct string_slot s_slot; 87 88 s_slot.s = s; 89 s_slot.len = len; 90 s_slot.slot_num = 0; 91 92 slot = ob->string_hash_table->find_slot (&s_slot, INSERT); 93 if (*slot == NULL) 94 { 95 struct lto_output_stream *string_stream = ob->string_stream; 96 unsigned int start = string_stream->total_size; 97 struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot); 98 const char *string; 99 100 if (!persistent) 101 { 102 char *tmp; 103 string = tmp = XOBNEWVEC (&ob->obstack, char, len); 104 memcpy (tmp, s, len); 105 } 106 else 107 string = s; 108 109 new_slot->s = string; 110 new_slot->len = len; 111 new_slot->slot_num = start; 112 *slot = new_slot; 113 streamer_write_uhwi_stream (string_stream, len); 114 streamer_write_data_stream (string_stream, string, len); 115 return start + 1; 116 } 117 else 118 { 119 struct string_slot *old_slot = *slot; 120 return old_slot->slot_num + 1; 121 } 122 } 123 124 125 /* Output STRING of LEN characters to the string table in OB. The 126 string might or might not include a trailing '\0'. Then put the 127 index onto the INDEX_STREAM. 128 When PERSISTENT is set, the string S is supposed to not change during 129 duration of the OB and thus OB can keep pointer into it. */ 130 131 void 132 streamer_write_string_with_length (struct output_block *ob, 133 struct lto_output_stream *index_stream, 134 const char *s, unsigned int len, 135 bool persistent) 136 { 137 if (s) 138 streamer_write_uhwi_stream (index_stream, 139 streamer_string_index (ob, s, len, persistent)); 140 else 141 streamer_write_char_stream (index_stream, 0); 142 } 143 144 145 /* Output the '\0' terminated STRING to the string 146 table in OB. Then put the index onto the INDEX_STREAM. 147 When PERSISTENT is set, the string S is supposed to not change during 148 duration of the OB and thus OB can keep pointer into it. */ 149 150 void 151 streamer_write_string (struct output_block *ob, 152 struct lto_output_stream *index_stream, 153 const char *string, bool persistent) 154 { 155 if (string) 156 streamer_write_string_with_length (ob, index_stream, string, 157 strlen (string) + 1, 158 persistent); 159 else 160 streamer_write_char_stream (index_stream, 0); 161 } 162 163 164 /* Output STRING of LEN characters to the string table in OB. Then 165 put the index into BP. 166 When PERSISTENT is set, the string S is supposed to not change during 167 duration of the OB and thus OB can keep pointer into it. */ 168 169 void 170 bp_pack_string_with_length (struct output_block *ob, struct bitpack_d *bp, 171 const char *s, unsigned int len, bool persistent) 172 { 173 unsigned index = 0; 174 if (s) 175 index = streamer_string_index (ob, s, len, persistent); 176 bp_pack_var_len_unsigned (bp, index); 177 } 178 179 180 /* Output the '\0' terminated STRING to the string 181 table in OB. Then put the index onto the bitpack BP. 182 When PERSISTENT is set, the string S is supposed to not change during 183 duration of the OB and thus OB can keep pointer into it. */ 184 185 void 186 bp_pack_string (struct output_block *ob, struct bitpack_d *bp, 187 const char *s, bool persistent) 188 { 189 unsigned index = 0; 190 if (s) 191 index = streamer_string_index (ob, s, strlen (s) + 1, persistent); 192 bp_pack_var_len_unsigned (bp, index); 193 } 194 195 196 197 /* Write a zero to the output stream. */ 198 199 void 200 streamer_write_zero (struct output_block *ob) 201 { 202 streamer_write_char_stream (ob->main_stream, 0); 203 } 204 205 206 /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream. */ 207 208 void 209 streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work) 210 { 211 streamer_write_uhwi_stream (ob->main_stream, work); 212 } 213 214 215 /* Write a HOST_WIDE_INT value WORK to OB->main_stream. */ 216 217 void 218 streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work) 219 { 220 streamer_write_hwi_stream (ob->main_stream, work); 221 } 222 223 /* Write a gcov counter value WORK to OB->main_stream. */ 224 225 void 226 streamer_write_gcov_count (struct output_block *ob, gcov_type work) 227 { 228 streamer_write_gcov_count_stream (ob->main_stream, work); 229 } 230 231 /* Write an unsigned HOST_WIDE_INT value WORK to OBS. */ 232 233 void 234 streamer_write_uhwi_stream (struct lto_output_stream *obs, 235 unsigned HOST_WIDE_INT work) 236 { 237 if (obs->left_in_block == 0) 238 lto_append_block (obs); 239 char *current_pointer = obs->current_pointer; 240 unsigned int left_in_block = obs->left_in_block; 241 unsigned int size = 0; 242 do 243 { 244 unsigned int byte = (work & 0x7f); 245 work >>= 7; 246 if (work != 0) 247 /* More bytes to follow. */ 248 byte |= 0x80; 249 250 *(current_pointer++) = byte; 251 left_in_block--; 252 size++; 253 } 254 while (work != 0 && left_in_block > 0); 255 if (work != 0) 256 { 257 obs->left_in_block = 0; 258 lto_append_block (obs); 259 current_pointer = obs->current_pointer; 260 left_in_block = obs->left_in_block; 261 do 262 { 263 unsigned int byte = (work & 0x7f); 264 work >>= 7; 265 if (work != 0) 266 /* More bytes to follow. */ 267 byte |= 0x80; 268 269 *(current_pointer++) = byte; 270 left_in_block--; 271 size++; 272 } 273 while (work != 0); 274 } 275 obs->current_pointer = current_pointer; 276 obs->left_in_block = left_in_block; 277 obs->total_size += size; 278 } 279 280 281 /* Write a HOST_WIDE_INT value WORK to OBS. */ 282 283 void 284 streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work) 285 { 286 if (obs->left_in_block == 0) 287 lto_append_block (obs); 288 char *current_pointer = obs->current_pointer; 289 unsigned int left_in_block = obs->left_in_block; 290 unsigned int size = 0; 291 bool more; 292 do 293 { 294 unsigned int byte = (work & 0x7f); 295 /* If the lower 7-bits are sign-extended 0 or -1 we are finished. */ 296 work >>= 6; 297 more = !(work == 0 || work == -1); 298 if (more) 299 { 300 /* More bits to follow. */ 301 work >>= 1; 302 byte |= 0x80; 303 } 304 305 *(current_pointer++) = byte; 306 left_in_block--; 307 size++; 308 } 309 while (more && left_in_block > 0); 310 if (more) 311 { 312 obs->left_in_block = 0; 313 lto_append_block (obs); 314 current_pointer = obs->current_pointer; 315 left_in_block = obs->left_in_block; 316 do 317 { 318 unsigned int byte = (work & 0x7f); 319 work >>= 6; 320 more = !(work == 0 || work == -1); 321 if (more) 322 { 323 work >>= 1; 324 byte |= 0x80; 325 } 326 327 *(current_pointer++) = byte; 328 left_in_block--; 329 size++; 330 } 331 while (more); 332 } 333 obs->current_pointer = current_pointer; 334 obs->left_in_block = left_in_block; 335 obs->total_size += size; 336 } 337 338 /* Write a GCOV counter value WORK to OBS. */ 339 340 void 341 streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work) 342 { 343 gcc_assert ((HOST_WIDE_INT) work == work); 344 streamer_write_hwi_stream (obs, work); 345 } 346 347 /* Write raw DATA of length LEN to the output block OB. */ 348 349 void 350 streamer_write_data_stream (struct lto_output_stream *obs, const void *data, 351 size_t len) 352 { 353 while (len) 354 { 355 size_t copy; 356 357 /* No space left. */ 358 if (obs->left_in_block == 0) 359 lto_append_block (obs); 360 361 /* Determine how many bytes to copy in this loop. */ 362 if (len <= obs->left_in_block) 363 copy = len; 364 else 365 copy = obs->left_in_block; 366 367 /* Copy the data and do bookkeeping. */ 368 memcpy (obs->current_pointer, data, copy); 369 obs->current_pointer += copy; 370 obs->total_size += copy; 371 obs->left_in_block -= copy; 372 data = (const char *) data + copy; 373 len -= copy; 374 } 375 } 376 377 /* Emit the physical representation of wide_int VAL to output block OB. */ 378 379 void 380 streamer_write_wide_int (struct output_block *ob, const wide_int &val) 381 { 382 int len = val.get_len (); 383 384 streamer_write_uhwi (ob, val.get_precision ()); 385 streamer_write_uhwi (ob, len); 386 for (int i = 0; i < len; i++) 387 streamer_write_hwi (ob, val.elt (i)); 388 } 389 390 /* Emit the physical representation of widest_int W to output block OB. */ 391 392 void 393 streamer_write_widest_int (struct output_block *ob, 394 const widest_int &w) 395 { 396 int len = w.get_len (); 397 398 streamer_write_uhwi (ob, w.get_precision ()); 399 streamer_write_uhwi (ob, len); 400 for (int i = 0; i < len; i++) 401 streamer_write_hwi (ob, w.elt (i)); 402 } 403 404