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-2014 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 "tree.h"
27 #include "basic-block.h"
28 #include "tree-ssa-alias.h"
29 #include "internal-fn.h"
30 #include "gimple-expr.h"
31 #include "is-a.h"
32 #include "gimple.h"
33 #include "data-streamer.h"
34 
35 /* Return index used to reference STRING of LEN characters in the string table
36    in OB.  The string might or might not include a trailing '\0'.
37    Then put the index onto the INDEX_STREAM.
38    When PERSISTENT is set, the string S is supposed to not change during
39    duration of the OB and thus OB can keep pointer into it.  */
40 
41 unsigned
streamer_string_index(struct output_block * ob,const char * s,unsigned int len,bool persistent)42 streamer_string_index (struct output_block *ob, const char *s, unsigned int len,
43 		       bool persistent)
44 {
45   struct string_slot **slot;
46   struct string_slot s_slot;
47 
48   s_slot.s = s;
49   s_slot.len = len;
50   s_slot.slot_num = 0;
51 
52   slot = ob->string_hash_table.find_slot (&s_slot, INSERT);
53   if (*slot == NULL)
54     {
55       struct lto_output_stream *string_stream = ob->string_stream;
56       unsigned int start = string_stream->total_size;
57       struct string_slot *new_slot = XOBNEW (&ob->obstack, struct string_slot);
58       const char *string;
59 
60       if (!persistent)
61 	{
62 	  char *tmp;
63 	  string = tmp = XOBNEWVEC (&ob->obstack, char, len);
64           memcpy (tmp, s, len);
65         }
66       else
67 	string = s;
68 
69       new_slot->s = string;
70       new_slot->len = len;
71       new_slot->slot_num = start;
72       *slot = new_slot;
73       streamer_write_uhwi_stream (string_stream, len);
74       lto_output_data_stream (string_stream, string, len);
75       return start + 1;
76     }
77   else
78     {
79       struct string_slot *old_slot = *slot;
80       return old_slot->slot_num + 1;
81     }
82 }
83 
84 
85 /* Output STRING of LEN characters to the string table in OB. The
86    string might or might not include a trailing '\0'. Then put the
87    index onto the INDEX_STREAM.
88    When PERSISTENT is set, the string S is supposed to not change during
89    duration of the OB and thus OB can keep pointer into it.  */
90 
91 void
streamer_write_string_with_length(struct output_block * ob,struct lto_output_stream * index_stream,const char * s,unsigned int len,bool persistent)92 streamer_write_string_with_length (struct output_block *ob,
93 				   struct lto_output_stream *index_stream,
94 				   const char *s, unsigned int len,
95 				   bool persistent)
96 {
97   if (s)
98     streamer_write_uhwi_stream (index_stream,
99 			        streamer_string_index (ob, s, len, persistent));
100   else
101     streamer_write_char_stream (index_stream, 0);
102 }
103 
104 
105 /* Output the '\0' terminated STRING to the string
106    table in OB.  Then put the index onto the INDEX_STREAM.
107    When PERSISTENT is set, the string S is supposed to not change during
108    duration of the OB and thus OB can keep pointer into it.  */
109 
110 void
streamer_write_string(struct output_block * ob,struct lto_output_stream * index_stream,const char * string,bool persistent)111 streamer_write_string (struct output_block *ob,
112 		       struct lto_output_stream *index_stream,
113 		       const char *string, bool persistent)
114 {
115   if (string)
116     streamer_write_string_with_length (ob, index_stream, string,
117 				       strlen (string) + 1,
118 				       persistent);
119   else
120     streamer_write_char_stream (index_stream, 0);
121 }
122 
123 
124 /* Output STRING of LEN characters to the string table in OB.  Then
125    put the index into BP.
126    When PERSISTENT is set, the string S is supposed to not change during
127    duration of the OB and thus OB can keep pointer into it.  */
128 
129 void
bp_pack_string_with_length(struct output_block * ob,struct bitpack_d * bp,const char * s,unsigned int len,bool persistent)130 bp_pack_string_with_length (struct output_block *ob, struct bitpack_d *bp,
131 			    const char *s, unsigned int len, bool persistent)
132 {
133   unsigned index = 0;
134   if (s)
135     index = streamer_string_index (ob, s, len, persistent);
136   bp_pack_var_len_unsigned (bp, index);
137 }
138 
139 
140 /* Output the '\0' terminated STRING to the string
141    table in OB.  Then put the index onto the bitpack BP.
142    When PERSISTENT is set, the string S is supposed to not change during
143    duration of the OB and thus OB can keep pointer into it.  */
144 
145 void
bp_pack_string(struct output_block * ob,struct bitpack_d * bp,const char * s,bool persistent)146 bp_pack_string (struct output_block *ob, struct bitpack_d *bp,
147 		const char *s, bool persistent)
148 {
149   unsigned index = 0;
150   if (s)
151     index = streamer_string_index (ob, s, strlen (s) + 1, persistent);
152   bp_pack_var_len_unsigned (bp, index);
153 }
154 
155 
156 
157 /* Write a zero to the output stream.  */
158 
159 void
streamer_write_zero(struct output_block * ob)160 streamer_write_zero (struct output_block *ob)
161 {
162   streamer_write_char_stream (ob->main_stream, 0);
163 }
164 
165 
166 /* Write an unsigned HOST_WIDE_INT value WORK to OB->main_stream.  */
167 
168 void
streamer_write_uhwi(struct output_block * ob,unsigned HOST_WIDE_INT work)169 streamer_write_uhwi (struct output_block *ob, unsigned HOST_WIDE_INT work)
170 {
171   streamer_write_uhwi_stream (ob->main_stream, work);
172 }
173 
174 
175 /* Write a HOST_WIDE_INT value WORK to OB->main_stream.  */
176 
177 void
streamer_write_hwi(struct output_block * ob,HOST_WIDE_INT work)178 streamer_write_hwi (struct output_block *ob, HOST_WIDE_INT work)
179 {
180   streamer_write_hwi_stream (ob->main_stream, work);
181 }
182 
183 /* Write a gcov counter value WORK to OB->main_stream.  */
184 
185 void
streamer_write_gcov_count(struct output_block * ob,gcov_type work)186 streamer_write_gcov_count (struct output_block *ob, gcov_type work)
187 {
188   streamer_write_gcov_count_stream (ob->main_stream, work);
189 }
190 
191 /* Write an unsigned HOST_WIDE_INT value WORK to OBS.  */
192 
193 void
streamer_write_uhwi_stream(struct lto_output_stream * obs,unsigned HOST_WIDE_INT work)194 streamer_write_uhwi_stream (struct lto_output_stream *obs,
195                             unsigned HOST_WIDE_INT work)
196 {
197   if (obs->left_in_block == 0)
198     lto_append_block (obs);
199   char *current_pointer = obs->current_pointer;
200   unsigned int left_in_block = obs->left_in_block;
201   unsigned int size = 0;
202   do
203     {
204       unsigned int byte = (work & 0x7f);
205       work >>= 7;
206       if (work != 0)
207 	/* More bytes to follow.  */
208 	byte |= 0x80;
209 
210       *(current_pointer++) = byte;
211       left_in_block--;
212       size++;
213     }
214   while (work != 0 && left_in_block > 0);
215   if (work != 0)
216     {
217       obs->left_in_block = 0;
218       lto_append_block (obs);
219       current_pointer = obs->current_pointer;
220       left_in_block = obs->left_in_block;
221       do
222 	{
223 	  unsigned int byte = (work & 0x7f);
224 	  work >>= 7;
225 	  if (work != 0)
226 	    /* More bytes to follow.  */
227 	    byte |= 0x80;
228 
229 	  *(current_pointer++) = byte;
230 	  left_in_block--;
231 	  size++;
232 	}
233       while (work != 0);
234     }
235   obs->current_pointer = current_pointer;
236   obs->left_in_block = left_in_block;
237   obs->total_size += size;
238 }
239 
240 
241 /* Write a HOST_WIDE_INT value WORK to OBS.  */
242 
243 void
streamer_write_hwi_stream(struct lto_output_stream * obs,HOST_WIDE_INT work)244 streamer_write_hwi_stream (struct lto_output_stream *obs, HOST_WIDE_INT work)
245 {
246   if (obs->left_in_block == 0)
247     lto_append_block (obs);
248   char *current_pointer = obs->current_pointer;
249   unsigned int left_in_block = obs->left_in_block;
250   unsigned int size = 0;
251   bool more;
252   do
253     {
254       unsigned int byte = (work & 0x7f);
255       /* If the lower 7-bits are sign-extended 0 or -1 we are finished.  */
256       work >>= 6;
257       more = !(work == 0 || work == -1);
258       if (more)
259 	{
260 	  /* More bits to follow.  */
261 	  work >>= 1;
262 	  byte |= 0x80;
263 	}
264 
265       *(current_pointer++) = byte;
266       left_in_block--;
267       size++;
268     }
269   while (more && left_in_block > 0);
270   if (more)
271     {
272       obs->left_in_block = 0;
273       lto_append_block (obs);
274       current_pointer = obs->current_pointer;
275       left_in_block = obs->left_in_block;
276       do
277 	{
278 	  unsigned int byte = (work & 0x7f);
279 	  work >>= 6;
280 	  more = !(work == 0 || work == -1);
281 	  if (more)
282 	    {
283 	      work >>= 1;
284 	      byte |= 0x80;
285 	    }
286 
287 	  *(current_pointer++) = byte;
288 	  left_in_block--;
289 	  size++;
290 	}
291       while (more);
292     }
293   obs->current_pointer = current_pointer;
294   obs->left_in_block = left_in_block;
295   obs->total_size += size;
296 }
297 
298 /* Write a GCOV counter value WORK to OBS.  */
299 
300 void
streamer_write_gcov_count_stream(struct lto_output_stream * obs,gcov_type work)301 streamer_write_gcov_count_stream (struct lto_output_stream *obs, gcov_type work)
302 {
303   gcc_assert (work >= 0);
304   gcc_assert ((HOST_WIDE_INT) work == work);
305   streamer_write_hwi_stream (obs, work);
306 }
307