data-streamer-out.c 10 KB

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