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