1/*
2 * Copyright (c) 2017-2018, Intel Corporation
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * * Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Intel Corporation nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "rose_build_instructions.h"
30
31#include "rose_build_engine_blob.h"
32#include "util/multibit_build.h"
33#include "util/verify_types.h"
34
35#include <algorithm>
36
37using namespace std;
38
39namespace ue2 {
40/* Destructors to avoid weak vtables. */
41
42RoseInstruction::~RoseInstruction() = default;
43RoseInstrCatchUp::~RoseInstrCatchUp() = default;
44RoseInstrCatchUpMpv::~RoseInstrCatchUpMpv() = default;
45RoseInstrSomZero::~RoseInstrSomZero() = default;
46RoseInstrSuffixesEod::~RoseInstrSuffixesEod() = default;
47RoseInstrMatcherEod::~RoseInstrMatcherEod() = default;
48RoseInstrEnd::~RoseInstrEnd() = default;
49RoseInstrClearWorkDone::~RoseInstrClearWorkDone() = default;
50RoseInstrFlushCombination::~RoseInstrFlushCombination() = default;
51
52using OffsetMap = RoseInstruction::OffsetMap;
53
54static
55u32 calc_jump(const OffsetMap &offset_map, const RoseInstruction *from,
56 const RoseInstruction *to) {
57 DEBUG_PRINTF("computing relative jump from %p to %p\n", from, to);
58 assert(from && contains(offset_map, from));
59 assert(to && contains(offset_map, to));
60
61 u32 from_offset = offset_map.at(from);
62 u32 to_offset = offset_map.at(to);
63 DEBUG_PRINTF("offsets: %u -> %u\n", from_offset, to_offset);
64 assert(from_offset <= to_offset);
65
66 return to_offset - from_offset;
67}
68
69void RoseInstrAnchoredDelay::write(void *dest, RoseEngineBlob &blob,
70 const OffsetMap &offset_map) const {
71 RoseInstrBase::write(dest, blob, offset_map);
72 auto *inst = static_cast<impl_type *>(dest);
73 inst->groups = groups;
74 inst->anch_id = anch_id;
75 inst->done_jump = calc_jump(offset_map, this, target);
76}
77
78void RoseInstrCheckLitEarly::write(void *dest, RoseEngineBlob &blob,
79 const OffsetMap &offset_map) const {
80 RoseInstrBase::write(dest, blob, offset_map);
81 auto *inst = static_cast<impl_type *>(dest);
82 inst->min_offset = min_offset;
83 inst->fail_jump = calc_jump(offset_map, this, target);
84}
85
86void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob,
87 const OffsetMap &offset_map) const {
88 RoseInstrBase::write(dest, blob, offset_map);
89 auto *inst = static_cast<impl_type *>(dest);
90 inst->groups = groups;
91}
92
93void RoseInstrCheckOnlyEod::write(void *dest, RoseEngineBlob &blob,
94 const OffsetMap &offset_map) const {
95 RoseInstrBase::write(dest, blob, offset_map);
96 auto *inst = static_cast<impl_type *>(dest);
97 inst->fail_jump = calc_jump(offset_map, this, target);
98}
99
100void RoseInstrCheckBounds::write(void *dest, RoseEngineBlob &blob,
101 const OffsetMap &offset_map) const {
102 RoseInstrBase::write(dest, blob, offset_map);
103 auto *inst = static_cast<impl_type *>(dest);
104 inst->min_bound = min_bound;
105 inst->max_bound = max_bound;
106 inst->fail_jump = calc_jump(offset_map, this, target);
107}
108
109void RoseInstrCheckNotHandled::write(void *dest, RoseEngineBlob &blob,
110 const OffsetMap &offset_map) const {
111 RoseInstrBase::write(dest, blob, offset_map);
112 auto *inst = static_cast<impl_type *>(dest);
113 inst->key = key;
114 inst->fail_jump = calc_jump(offset_map, this, target);
115}
116
117void RoseInstrCheckSingleLookaround::write(void *dest, RoseEngineBlob &blob,
118 const OffsetMap &offset_map) const {
119 RoseInstrBase::write(dest, blob, offset_map);
120 auto *inst = static_cast<impl_type *>(dest);
121 inst->offset = offset;
122 inst->reach_index = blob.lookaround_cache.get_offset_of({reach}, blob);
123 inst->fail_jump = calc_jump(offset_map, this, target);
124}
125
126void RoseInstrCheckLookaround::write(void *dest, RoseEngineBlob &blob,
127 const OffsetMap &offset_map) const {
128 RoseInstrBase::write(dest, blob, offset_map);
129 auto *inst = static_cast<impl_type *>(dest);
130 vector<s8> look_offsets;
131 vector<CharReach> reaches;
132 for (const auto &le : look) {
133 look_offsets.push_back(le.offset);
134 reaches.push_back(le.reach);
135 }
136 inst->look_index = blob.lookaround_cache.get_offset_of(look_offsets, blob);
137 inst->reach_index = blob.lookaround_cache.get_offset_of(reaches, blob);
138 inst->count = verify_u32(look.size());
139 inst->fail_jump = calc_jump(offset_map, this, target);
140}
141
142void RoseInstrCheckMask::write(void *dest, RoseEngineBlob &blob,
143 const OffsetMap &offset_map) const {
144 RoseInstrBase::write(dest, blob, offset_map);
145 auto *inst = static_cast<impl_type *>(dest);
146 inst->and_mask = and_mask;
147 inst->cmp_mask = cmp_mask;
148 inst->neg_mask = neg_mask;
149 inst->offset = offset;
150 inst->fail_jump = calc_jump(offset_map, this, target);
151}
152
153void RoseInstrCheckMask32::write(void *dest, RoseEngineBlob &blob,
154 const OffsetMap &offset_map) const {
155 RoseInstrBase::write(dest, blob, offset_map);
156 auto *inst = static_cast<impl_type *>(dest);
157 copy(begin(and_mask), end(and_mask), inst->and_mask);
158 copy(begin(cmp_mask), end(cmp_mask), inst->cmp_mask);
159 inst->neg_mask = neg_mask;
160 inst->offset = offset;
161 inst->fail_jump = calc_jump(offset_map, this, target);
162}
163
164void RoseInstrCheckByte::write(void *dest, RoseEngineBlob &blob,
165 const OffsetMap &offset_map) const {
166 RoseInstrBase::write(dest, blob, offset_map);
167 auto *inst = static_cast<impl_type *>(dest);
168 inst->and_mask = and_mask;
169 inst->cmp_mask = cmp_mask;
170 inst->negation = negation;
171 inst->offset = offset;
172 inst->fail_jump = calc_jump(offset_map, this, target);
173}
174
175void RoseInstrCheckShufti16x8::write(void *dest, RoseEngineBlob &blob,
176 const OffsetMap &offset_map) const {
177 RoseInstrBase::write(dest, blob, offset_map);
178 auto *inst = static_cast<impl_type *>(dest);
179 copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
180 copy(begin(bucket_select_mask), end(bucket_select_mask),
181 inst->bucket_select_mask);
182 inst->neg_mask = neg_mask;
183 inst->offset = offset;
184 inst->fail_jump = calc_jump(offset_map, this, target);
185}
186
187void RoseInstrCheckShufti32x8::write(void *dest, RoseEngineBlob &blob,
188 const OffsetMap &offset_map) const {
189 RoseInstrBase::write(dest, blob, offset_map);
190 auto *inst = static_cast<impl_type *>(dest);
191 copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
192 copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
193 copy(begin(bucket_select_mask), end(bucket_select_mask),
194 inst->bucket_select_mask);
195
196 inst->neg_mask = neg_mask;
197 inst->offset = offset;
198 inst->fail_jump = calc_jump(offset_map, this, target);
199}
200
201void RoseInstrCheckShufti16x16::write(void *dest, RoseEngineBlob &blob,
202 const OffsetMap &offset_map) const {
203 RoseInstrBase::write(dest, blob, offset_map);
204 auto *inst = static_cast<impl_type *>(dest);
205 copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
206 copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
207 copy(begin(bucket_select_mask), end(bucket_select_mask),
208 inst->bucket_select_mask);
209 inst->neg_mask = neg_mask;
210 inst->offset = offset;
211 inst->fail_jump = calc_jump(offset_map, this, target);
212}
213
214void RoseInstrCheckShufti32x16::write(void *dest, RoseEngineBlob &blob,
215 const OffsetMap &offset_map) const {
216 RoseInstrBase::write(dest, blob, offset_map);
217 auto *inst = static_cast<impl_type *>(dest);
218 copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
219 copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
220 copy(begin(bucket_select_mask_hi), end(bucket_select_mask_hi),
221 inst->bucket_select_mask_hi);
222 copy(begin(bucket_select_mask_lo), end(bucket_select_mask_lo),
223 inst->bucket_select_mask_lo);
224 inst->neg_mask = neg_mask;
225 inst->offset = offset;
226 inst->fail_jump = calc_jump(offset_map, this, target);
227}
228
229void RoseInstrCheckInfix::write(void *dest, RoseEngineBlob &blob,
230 const OffsetMap &offset_map) const {
231 RoseInstrBase::write(dest, blob, offset_map);
232 auto *inst = static_cast<impl_type *>(dest);
233 inst->queue = queue;
234 inst->lag = lag;
235 inst->report = report;
236 inst->fail_jump = calc_jump(offset_map, this, target);
237}
238
239void RoseInstrCheckPrefix::write(void *dest, RoseEngineBlob &blob,
240 const OffsetMap &offset_map) const {
241 RoseInstrBase::write(dest, blob, offset_map);
242 auto *inst = static_cast<impl_type *>(dest);
243 inst->queue = queue;
244 inst->lag = lag;
245 inst->report = report;
246 inst->fail_jump = calc_jump(offset_map, this, target);
247}
248
249void RoseInstrPushDelayed::write(void *dest, RoseEngineBlob &blob,
250 const OffsetMap &offset_map) const {
251 RoseInstrBase::write(dest, blob, offset_map);
252 auto *inst = static_cast<impl_type *>(dest);
253 inst->delay = delay;
254 inst->index = index;
255}
256
257void RoseInstrSomAdjust::write(void *dest, RoseEngineBlob &blob,
258 const OffsetMap &offset_map) const {
259 RoseInstrBase::write(dest, blob, offset_map);
260 auto *inst = static_cast<impl_type *>(dest);
261 inst->distance = distance;
262}
263
264void RoseInstrSomLeftfix::write(void *dest, RoseEngineBlob &blob,
265 const OffsetMap &offset_map) const {
266 RoseInstrBase::write(dest, blob, offset_map);
267 auto *inst = static_cast<impl_type *>(dest);
268 inst->queue = queue;
269 inst->lag = lag;
270}
271
272void RoseInstrSomFromReport::write(void *dest, RoseEngineBlob &blob,
273 const OffsetMap &offset_map) const {
274 RoseInstrBase::write(dest, blob, offset_map);
275 auto *inst = static_cast<impl_type *>(dest);
276 inst->som = som;
277}
278
279void RoseInstrTriggerInfix::write(void *dest, RoseEngineBlob &blob,
280 const OffsetMap &offset_map) const {
281 RoseInstrBase::write(dest, blob, offset_map);
282 auto *inst = static_cast<impl_type *>(dest);
283 inst->cancel = cancel;
284 inst->queue = queue;
285 inst->event = event;
286}
287
288void RoseInstrTriggerSuffix::write(void *dest, RoseEngineBlob &blob,
289 const OffsetMap &offset_map) const {
290 RoseInstrBase::write(dest, blob, offset_map);
291 auto *inst = static_cast<impl_type *>(dest);
292 inst->queue = queue;
293 inst->event = event;
294}
295
296void RoseInstrDedupe::write(void *dest, RoseEngineBlob &blob,
297 const OffsetMap &offset_map) const {
298 RoseInstrBase::write(dest, blob, offset_map);
299 auto *inst = static_cast<impl_type *>(dest);
300 inst->quash_som = quash_som;
301 inst->dkey = dkey;
302 inst->offset_adjust = offset_adjust;
303 inst->fail_jump = calc_jump(offset_map, this, target);
304}
305
306void RoseInstrDedupeSom::write(void *dest, RoseEngineBlob &blob,
307 const OffsetMap &offset_map) const {
308 RoseInstrBase::write(dest, blob, offset_map);
309 auto *inst = static_cast<impl_type *>(dest);
310 inst->quash_som = quash_som;
311 inst->dkey = dkey;
312 inst->offset_adjust = offset_adjust;
313 inst->fail_jump = calc_jump(offset_map, this, target);
314}
315
316void RoseInstrReportChain::write(void *dest, RoseEngineBlob &blob,
317 const OffsetMap &offset_map) const {
318 RoseInstrBase::write(dest, blob, offset_map);
319 auto *inst = static_cast<impl_type *>(dest);
320 inst->event = event;
321 inst->top_squash_distance = top_squash_distance;
322}
323
324void RoseInstrReportSomInt::write(void *dest, RoseEngineBlob &blob,
325 const OffsetMap &offset_map) const {
326 RoseInstrBase::write(dest, blob, offset_map);
327 auto *inst = static_cast<impl_type *>(dest);
328 inst->som = som;
329}
330
331void RoseInstrReportSomAware::write(void *dest, RoseEngineBlob &blob,
332 const OffsetMap &offset_map) const {
333 RoseInstrBase::write(dest, blob, offset_map);
334 auto *inst = static_cast<impl_type *>(dest);
335 inst->som = som;
336}
337
338void RoseInstrReport::write(void *dest, RoseEngineBlob &blob,
339 const OffsetMap &offset_map) const {
340 RoseInstrBase::write(dest, blob, offset_map);
341 auto *inst = static_cast<impl_type *>(dest);
342 inst->onmatch = onmatch;
343 inst->offset_adjust = offset_adjust;
344}
345
346void RoseInstrReportExhaust::write(void *dest, RoseEngineBlob &blob,
347 const OffsetMap &offset_map) const {
348 RoseInstrBase::write(dest, blob, offset_map);
349 auto *inst = static_cast<impl_type *>(dest);
350 inst->onmatch = onmatch;
351 inst->offset_adjust = offset_adjust;
352 inst->ekey = ekey;
353}
354
355void RoseInstrReportSom::write(void *dest, RoseEngineBlob &blob,
356 const OffsetMap &offset_map) const {
357 RoseInstrBase::write(dest, blob, offset_map);
358 auto *inst = static_cast<impl_type *>(dest);
359 inst->onmatch = onmatch;
360 inst->offset_adjust = offset_adjust;
361}
362
363void RoseInstrReportSomExhaust::write(void *dest, RoseEngineBlob &blob,
364 const OffsetMap &offset_map) const {
365 RoseInstrBase::write(dest, blob, offset_map);
366 auto *inst = static_cast<impl_type *>(dest);
367 inst->onmatch = onmatch;
368 inst->offset_adjust = offset_adjust;
369 inst->ekey = ekey;
370}
371
372void RoseInstrDedupeAndReport::write(void *dest, RoseEngineBlob &blob,
373 const OffsetMap &offset_map) const {
374 RoseInstrBase::write(dest, blob, offset_map);
375 auto *inst = static_cast<impl_type *>(dest);
376 inst->quash_som = quash_som;
377 inst->dkey = dkey;
378 inst->onmatch = onmatch;
379 inst->offset_adjust = offset_adjust;
380 inst->fail_jump = calc_jump(offset_map, this, target);
381}
382
383void RoseInstrFinalReport::write(void *dest, RoseEngineBlob &blob,
384 const OffsetMap &offset_map) const {
385 RoseInstrBase::write(dest, blob, offset_map);
386 auto *inst = static_cast<impl_type *>(dest);
387 inst->onmatch = onmatch;
388 inst->offset_adjust = offset_adjust;
389}
390
391void RoseInstrCheckExhausted::write(void *dest, RoseEngineBlob &blob,
392 const OffsetMap &offset_map) const {
393 RoseInstrBase::write(dest, blob, offset_map);
394 auto *inst = static_cast<impl_type *>(dest);
395 inst->ekey = ekey;
396 inst->fail_jump = calc_jump(offset_map, this, target);
397}
398
399void RoseInstrCheckMinLength::write(void *dest, RoseEngineBlob &blob,
400 const OffsetMap &offset_map) const {
401 RoseInstrBase::write(dest, blob, offset_map);
402 auto *inst = static_cast<impl_type *>(dest);
403 inst->end_adj = end_adj;
404 inst->min_length = min_length;
405 inst->fail_jump = calc_jump(offset_map, this, target);
406}
407
408void RoseInstrSetState::write(void *dest, RoseEngineBlob &blob,
409 const OffsetMap &offset_map) const {
410 RoseInstrBase::write(dest, blob, offset_map);
411 auto *inst = static_cast<impl_type *>(dest);
412 inst->index = index;
413}
414
415void RoseInstrSetGroups::write(void *dest, RoseEngineBlob &blob,
416 const OffsetMap &offset_map) const {
417 RoseInstrBase::write(dest, blob, offset_map);
418 auto *inst = static_cast<impl_type *>(dest);
419 inst->groups = groups;
420}
421
422void RoseInstrSquashGroups::write(void *dest, RoseEngineBlob &blob,
423 const OffsetMap &offset_map) const {
424 RoseInstrBase::write(dest, blob, offset_map);
425 auto *inst = static_cast<impl_type *>(dest);
426 inst->groups = groups;
427}
428
429void RoseInstrCheckState::write(void *dest, RoseEngineBlob &blob,
430 const OffsetMap &offset_map) const {
431 RoseInstrBase::write(dest, blob, offset_map);
432 auto *inst = static_cast<impl_type *>(dest);
433 inst->index = index;
434 inst->fail_jump = calc_jump(offset_map, this, target);
435}
436
437void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
438 const OffsetMap &offset_map) const {
439 RoseInstrBase::write(dest, blob, offset_map);
440 auto *inst = static_cast<impl_type *>(dest);
441 inst->fail_jump = calc_jump(offset_map, this, target);
442
443 // Resolve and write the multibit sparse iterator and the jump table.
444 vector<u32> keys;
445 vector<u32> jump_offsets;
446 for (const auto &jump : jump_table) {
447 keys.push_back(jump.first);
448 assert(contains(offset_map, jump.second));
449 jump_offsets.push_back(offset_map.at(jump.second));
450 }
451
452 auto iter = mmbBuildSparseIterator(keys, num_keys);
453 assert(!iter.empty());
454 inst->iter_offset = blob.add_iterator(iter);
455 inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
456
457 // Store offsets for corresponding SPARSE_ITER_NEXT operations.
458 is_written = true;
459 iter_offset = inst->iter_offset;
460 jump_table_offset = inst->jump_table;
461}
462
463void RoseInstrSparseIterNext::write(void *dest, RoseEngineBlob &blob,
464 const OffsetMap &offset_map) const {
465 RoseInstrBase::write(dest, blob, offset_map);
466 auto *inst = static_cast<impl_type *>(dest);
467 inst->state = state;
468 inst->fail_jump = calc_jump(offset_map, this, target);
469
470 // Use the same sparse iterator and jump table as the SPARSE_ITER_BEGIN
471 // instruction.
472 assert(begin);
473 assert(contains(offset_map, begin));
474 assert(begin->is_written);
475 inst->iter_offset = begin->iter_offset;
476 inst->jump_table = begin->jump_table_offset;
477}
478
479void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
480 const OffsetMap &offset_map) const {
481 RoseInstrBase::write(dest, blob, offset_map);
482 auto *inst = static_cast<impl_type *>(dest);
483 inst->fail_jump = calc_jump(offset_map, this, target);
484
485 // Write the multibit sparse iterator.
486 auto iter = mmbBuildSparseIterator(keys, num_keys);
487 assert(!iter.empty());
488 inst->iter_offset = blob.add_iterator(iter);
489}
490
491void RoseInstrEnginesEod::write(void *dest, RoseEngineBlob &blob,
492 const OffsetMap &offset_map) const {
493 RoseInstrBase::write(dest, blob, offset_map);
494 auto *inst = static_cast<impl_type *>(dest);
495 inst->iter_offset = iter_offset;
496}
497
498void RoseInstrCheckLongLit::write(void *dest, RoseEngineBlob &blob,
499 const OffsetMap &offset_map) const {
500 RoseInstrBase::write(dest, blob, offset_map);
501 auto *inst = static_cast<impl_type *>(dest);
502 assert(!literal.empty());
503 inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
504 inst->lit_length = verify_u32(literal.size());
505 inst->fail_jump = calc_jump(offset_map, this, target);
506}
507
508void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
509 const OffsetMap &offset_map) const {
510 RoseInstrBase::write(dest, blob, offset_map);
511 auto *inst = static_cast<impl_type *>(dest);
512 assert(!literal.empty());
513 inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
514 inst->lit_length = verify_u32(literal.size());
515 inst->fail_jump = calc_jump(offset_map, this, target);
516}
517
518void RoseInstrCheckMedLit::write(void *dest, RoseEngineBlob &blob,
519 const OffsetMap &offset_map) const {
520 RoseInstrBase::write(dest, blob, offset_map);
521 auto *inst = static_cast<impl_type *>(dest);
522 assert(!literal.empty());
523 inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
524 inst->lit_length = verify_u32(literal.size());
525 inst->fail_jump = calc_jump(offset_map, this, target);
526}
527
528void RoseInstrCheckMedLitNocase::write(void *dest, RoseEngineBlob &blob,
529 const OffsetMap &offset_map) const {
530 RoseInstrBase::write(dest, blob, offset_map);
531 auto *inst = static_cast<impl_type *>(dest);
532 assert(!literal.empty());
533 inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
534 inst->lit_length = verify_u32(literal.size());
535 inst->fail_jump = calc_jump(offset_map, this, target);
536}
537
538void RoseInstrMultipathLookaround::write(void *dest, RoseEngineBlob &blob,
539 const OffsetMap &offset_map) const {
540 RoseInstrBase::write(dest, blob, offset_map);
541 auto *inst = static_cast<impl_type *>(dest);
542 auto &cache = blob.lookaround_cache;
543 vector<s8> look_offsets;
544 vector<vector<CharReach>> reaches;
545 for (const auto &vle : multi_look) {
546 reaches.push_back({});
547 bool done_offset = false;
548
549 for (const auto &le : vle) {
550 reaches.back().push_back(le.reach);
551
552 /* empty reaches don't have valid offsets */
553 if (!done_offset && le.reach.any()) {
554 look_offsets.push_back(le.offset);
555 done_offset = true;
556 }
557 }
558 }
559 inst->look_index = cache.get_offset_of(look_offsets, blob);
560 inst->reach_index = cache.get_offset_of(reaches, blob);
561 inst->count = verify_u32(multi_look.size());
562 inst->last_start = last_start;
563 copy(begin(start_mask), end(start_mask), inst->start_mask);
564 inst->fail_jump = calc_jump(offset_map, this, target);
565}
566
567void RoseInstrCheckMultipathShufti16x8::write(void *dest, RoseEngineBlob &blob,
568 const OffsetMap &offset_map) const {
569 RoseInstrBase::write(dest, blob, offset_map);
570 auto *inst = static_cast<impl_type *>(dest);
571 copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
572 copy(begin(bucket_select_mask), begin(bucket_select_mask) + 16,
573 inst->bucket_select_mask);
574 copy(begin(data_select_mask), begin(data_select_mask) + 16,
575 inst->data_select_mask);
576 inst->hi_bits_mask = hi_bits_mask;
577 inst->lo_bits_mask = lo_bits_mask;
578 inst->neg_mask = neg_mask;
579 inst->base_offset = base_offset;
580 inst->last_start = last_start;
581 inst->fail_jump = calc_jump(offset_map, this, target);
582}
583
584void RoseInstrCheckMultipathShufti32x8::write(void *dest, RoseEngineBlob &blob,
585 const OffsetMap &offset_map) const {
586 RoseInstrBase::write(dest, blob, offset_map);
587 auto *inst = static_cast<impl_type *>(dest);
588 copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
589 copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
590 copy(begin(bucket_select_mask), begin(bucket_select_mask) + 32,
591 inst->bucket_select_mask);
592 copy(begin(data_select_mask), begin(data_select_mask) + 32,
593 inst->data_select_mask);
594 inst->hi_bits_mask = hi_bits_mask;
595 inst->lo_bits_mask = lo_bits_mask;
596 inst->neg_mask = neg_mask;
597 inst->base_offset = base_offset;
598 inst->last_start = last_start;
599 inst->fail_jump = calc_jump(offset_map, this, target);
600}
601
602void RoseInstrCheckMultipathShufti32x16::write(void *dest, RoseEngineBlob &blob,
603 const OffsetMap &offset_map) const {
604 RoseInstrBase::write(dest, blob, offset_map);
605 auto *inst = static_cast<impl_type *>(dest);
606 copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
607 copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
608 copy(begin(bucket_select_mask_hi), begin(bucket_select_mask_hi) + 32,
609 inst->bucket_select_mask_hi);
610 copy(begin(bucket_select_mask_lo), begin(bucket_select_mask_lo) + 32,
611 inst->bucket_select_mask_lo);
612 copy(begin(data_select_mask), begin(data_select_mask) + 32,
613 inst->data_select_mask);
614 inst->hi_bits_mask = hi_bits_mask;
615 inst->lo_bits_mask = lo_bits_mask;
616 inst->neg_mask = neg_mask;
617 inst->base_offset = base_offset;
618 inst->last_start = last_start;
619 inst->fail_jump = calc_jump(offset_map, this, target);
620}
621
622void RoseInstrCheckMultipathShufti64::write(void *dest, RoseEngineBlob &blob,
623 const OffsetMap &offset_map) const {
624 RoseInstrBase::write(dest, blob, offset_map);
625 auto *inst = static_cast<impl_type *>(dest);
626 copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
627 copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
628 copy(begin(bucket_select_mask), end(bucket_select_mask),
629 inst->bucket_select_mask);
630 copy(begin(data_select_mask), end(data_select_mask),
631 inst->data_select_mask);
632 inst->hi_bits_mask = hi_bits_mask;
633 inst->lo_bits_mask = lo_bits_mask;
634 inst->neg_mask = neg_mask;
635 inst->base_offset = base_offset;
636 inst->last_start = last_start;
637 inst->fail_jump = calc_jump(offset_map, this, target);
638}
639
640void RoseInstrIncludedJump::write(void *dest, RoseEngineBlob &blob,
641 const OffsetMap &offset_map) const {
642 RoseInstrBase::write(dest, blob, offset_map);
643 auto *inst = static_cast<impl_type *>(dest);
644 inst->child_offset = child_offset;
645 inst->squash = squash;
646}
647
648void RoseInstrSetLogical::write(void *dest, RoseEngineBlob &blob,
649 const OffsetMap &offset_map) const {
650 RoseInstrBase::write(dest, blob, offset_map);
651 auto *inst = static_cast<impl_type *>(dest);
652 inst->lkey = lkey;
653 inst->offset_adjust = offset_adjust;
654}
655
656void RoseInstrSetCombination::write(void *dest, RoseEngineBlob &blob,
657 const OffsetMap &offset_map) const {
658 RoseInstrBase::write(dest, blob, offset_map);
659 auto *inst = static_cast<impl_type *>(dest);
660 inst->ckey = ckey;
661}
662
663void RoseInstrSetExhaust::write(void *dest, RoseEngineBlob &blob,
664 const OffsetMap &offset_map) const {
665 RoseInstrBase::write(dest, blob, offset_map);
666 auto *inst = static_cast<impl_type *>(dest);
667 inst->ekey = ekey;
668}
669
670}
671