Revert "panfrost: Rework midgard_pair_load_store() to kill the nested foreach loop"
[mesa.git] / src / compiler / blob.c
1 /*
2 * Copyright © 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <string.h>
25
26 #include "main/macros.h"
27 #include "blob.h"
28
29 #ifdef HAVE_VALGRIND
30 #include <valgrind.h>
31 #include <memcheck.h>
32 #define VG(x) x
33 #else
34 #define VG(x)
35 #endif
36
37 #define BLOB_INITIAL_SIZE 4096
38
39 /* Ensure that \blob will be able to fit an additional object of size
40 * \additional. The growing (if any) will occur by doubling the existing
41 * allocation.
42 */
43 static bool
44 grow_to_fit(struct blob *blob, size_t additional)
45 {
46 size_t to_allocate;
47 uint8_t *new_data;
48
49 if (blob->out_of_memory)
50 return false;
51
52 if (blob->size + additional <= blob->allocated)
53 return true;
54
55 if (blob->fixed_allocation) {
56 blob->out_of_memory = true;
57 return false;
58 }
59
60 if (blob->allocated == 0)
61 to_allocate = BLOB_INITIAL_SIZE;
62 else
63 to_allocate = blob->allocated * 2;
64
65 to_allocate = MAX2(to_allocate, blob->allocated + additional);
66
67 new_data = realloc(blob->data, to_allocate);
68 if (new_data == NULL) {
69 blob->out_of_memory = true;
70 return false;
71 }
72
73 blob->data = new_data;
74 blob->allocated = to_allocate;
75
76 return true;
77 }
78
79 /* Align the blob->size so that reading or writing a value at (blob->data +
80 * blob->size) will result in an access aligned to a granularity of \alignment
81 * bytes.
82 *
83 * \return True unless allocation fails
84 */
85 static bool
86 align_blob(struct blob *blob, size_t alignment)
87 {
88 const size_t new_size = ALIGN(blob->size, alignment);
89
90 if (blob->size < new_size) {
91 if (!grow_to_fit(blob, new_size - blob->size))
92 return false;
93
94 if (blob->data)
95 memset(blob->data + blob->size, 0, new_size - blob->size);
96 blob->size = new_size;
97 }
98
99 return true;
100 }
101
102 static void
103 align_blob_reader(struct blob_reader *blob, size_t alignment)
104 {
105 blob->current = blob->data + ALIGN(blob->current - blob->data, alignment);
106 }
107
108 void
109 blob_init(struct blob *blob)
110 {
111 blob->data = NULL;
112 blob->allocated = 0;
113 blob->size = 0;
114 blob->fixed_allocation = false;
115 blob->out_of_memory = false;
116 }
117
118 void
119 blob_init_fixed(struct blob *blob, void *data, size_t size)
120 {
121 blob->data = data;
122 blob->allocated = size;
123 blob->size = 0;
124 blob->fixed_allocation = true;
125 blob->out_of_memory = false;
126 }
127
128 bool
129 blob_overwrite_bytes(struct blob *blob,
130 size_t offset,
131 const void *bytes,
132 size_t to_write)
133 {
134 /* Detect an attempt to overwrite data out of bounds. */
135 if (offset + to_write < offset || blob->size < offset + to_write)
136 return false;
137
138 VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
139
140 if (blob->data)
141 memcpy(blob->data + offset, bytes, to_write);
142
143 return true;
144 }
145
146 bool
147 blob_write_bytes(struct blob *blob, const void *bytes, size_t to_write)
148 {
149 if (! grow_to_fit(blob, to_write))
150 return false;
151
152 VG(VALGRIND_CHECK_MEM_IS_DEFINED(bytes, to_write));
153
154 if (blob->data)
155 memcpy(blob->data + blob->size, bytes, to_write);
156 blob->size += to_write;
157
158 return true;
159 }
160
161 intptr_t
162 blob_reserve_bytes(struct blob *blob, size_t to_write)
163 {
164 intptr_t ret;
165
166 if (! grow_to_fit (blob, to_write))
167 return -1;
168
169 ret = blob->size;
170 blob->size += to_write;
171
172 return ret;
173 }
174
175 intptr_t
176 blob_reserve_uint32(struct blob *blob)
177 {
178 align_blob(blob, sizeof(uint32_t));
179 return blob_reserve_bytes(blob, sizeof(uint32_t));
180 }
181
182 intptr_t
183 blob_reserve_intptr(struct blob *blob)
184 {
185 align_blob(blob, sizeof(intptr_t));
186 return blob_reserve_bytes(blob, sizeof(intptr_t));
187 }
188
189 bool
190 blob_write_uint32(struct blob *blob, uint32_t value)
191 {
192 align_blob(blob, sizeof(value));
193
194 return blob_write_bytes(blob, &value, sizeof(value));
195 }
196
197 #define ASSERT_ALIGNED(_offset, _align) \
198 assert(ALIGN((_offset), (_align)) == (_offset))
199
200 bool
201 blob_overwrite_uint32 (struct blob *blob,
202 size_t offset,
203 uint32_t value)
204 {
205 ASSERT_ALIGNED(offset, sizeof(value));
206 return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
207 }
208
209 bool
210 blob_write_uint64(struct blob *blob, uint64_t value)
211 {
212 align_blob(blob, sizeof(value));
213
214 return blob_write_bytes(blob, &value, sizeof(value));
215 }
216
217 bool
218 blob_write_intptr(struct blob *blob, intptr_t value)
219 {
220 align_blob(blob, sizeof(value));
221
222 return blob_write_bytes(blob, &value, sizeof(value));
223 }
224
225 bool
226 blob_overwrite_intptr (struct blob *blob,
227 size_t offset,
228 intptr_t value)
229 {
230 ASSERT_ALIGNED(offset, sizeof(value));
231 return blob_overwrite_bytes(blob, offset, &value, sizeof(value));
232 }
233
234 bool
235 blob_write_string(struct blob *blob, const char *str)
236 {
237 return blob_write_bytes(blob, str, strlen(str) + 1);
238 }
239
240 void
241 blob_reader_init(struct blob_reader *blob, const void *data, size_t size)
242 {
243 blob->data = data;
244 blob->end = blob->data + size;
245 blob->current = data;
246 blob->overrun = false;
247 }
248
249 /* Check that an object of size \size can be read from this blob.
250 *
251 * If not, set blob->overrun to indicate that we attempted to read too far.
252 */
253 static bool
254 ensure_can_read(struct blob_reader *blob, size_t size)
255 {
256 if (blob->overrun)
257 return false;
258
259 if (blob->current <= blob->end && blob->end - blob->current >= size)
260 return true;
261
262 blob->overrun = true;
263
264 return false;
265 }
266
267 const void *
268 blob_read_bytes(struct blob_reader *blob, size_t size)
269 {
270 const void *ret;
271
272 if (! ensure_can_read (blob, size))
273 return NULL;
274
275 ret = blob->current;
276
277 blob->current += size;
278
279 return ret;
280 }
281
282 void
283 blob_copy_bytes(struct blob_reader *blob, void *dest, size_t size)
284 {
285 const void *bytes;
286
287 bytes = blob_read_bytes(blob, size);
288 if (bytes == NULL)
289 return;
290
291 memcpy(dest, bytes, size);
292 }
293
294 void
295 blob_skip_bytes(struct blob_reader *blob, size_t size)
296 {
297 if (ensure_can_read (blob, size))
298 blob->current += size;
299 }
300
301 /* These next three read functions have identical form. If we add any beyond
302 * these first three we should probably switch to generating these with a
303 * preprocessor macro.
304 */
305 uint32_t
306 blob_read_uint32(struct blob_reader *blob)
307 {
308 uint32_t ret;
309 int size = sizeof(ret);
310
311 align_blob_reader(blob, size);
312
313 if (! ensure_can_read(blob, size))
314 return 0;
315
316 ret = *((uint32_t*) blob->current);
317
318 blob->current += size;
319
320 return ret;
321 }
322
323 uint64_t
324 blob_read_uint64(struct blob_reader *blob)
325 {
326 uint64_t ret;
327 int size = sizeof(ret);
328
329 align_blob_reader(blob, size);
330
331 if (! ensure_can_read(blob, size))
332 return 0;
333
334 ret = *((uint64_t*) blob->current);
335
336 blob->current += size;
337
338 return ret;
339 }
340
341 intptr_t
342 blob_read_intptr(struct blob_reader *blob)
343 {
344 intptr_t ret;
345 int size = sizeof(ret);
346
347 align_blob_reader(blob, size);
348
349 if (! ensure_can_read(blob, size))
350 return 0;
351
352 ret = *((intptr_t *) blob->current);
353
354 blob->current += size;
355
356 return ret;
357 }
358
359 char *
360 blob_read_string(struct blob_reader *blob)
361 {
362 int size;
363 char *ret;
364 uint8_t *nul;
365
366 /* If we're already at the end, then this is an overrun. */
367 if (blob->current >= blob->end) {
368 blob->overrun = true;
369 return NULL;
370 }
371
372 /* Similarly, if there is no zero byte in the data remaining in this blob,
373 * we also consider that an overrun.
374 */
375 nul = memchr(blob->current, 0, blob->end - blob->current);
376
377 if (nul == NULL) {
378 blob->overrun = true;
379 return NULL;
380 }
381
382 size = nul - blob->current + 1;
383
384 assert(ensure_can_read(blob, size));
385
386 ret = (char *) blob->current;
387
388 blob->current += size;
389
390 return ret;
391 }