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/** \file
30 * \brief Concrete classes for interpreter instructions.
31 *
32 * Note: this header should only be included in files which need to deal with
33 * the details of actual instructions. It is expected that most will only
34 * require access to the RoseInstruction API exposed in rose_build_program.h
35 */
36
37#ifndef ROSE_BUILD_INSTRUCTIONS_H
38#define ROSE_BUILD_INSTRUCTIONS_H
39
40#include "rose_build_lookaround.h"
41#include "rose_build_program.h"
42#include "util/hash.h"
43#include "util/verify_types.h"
44
45namespace ue2 {
46
47/**
48 * \brief Abstract base class representing a single Rose instruction.
49 */
50class RoseInstruction {
51public:
52 virtual ~RoseInstruction();
53
54 /** \brief Opcode used for the instruction in the bytecode. */
55 virtual RoseInstructionCode code() const = 0;
56
57 /**
58 * \brief Simple hash used for program equivalence.
59 *
60 * Note that pointers (jumps, for example) should not be used when
61 * calculating the hash: they will be converted to instruction offsets when
62 * compared later.
63 */
64 virtual size_t hash() const = 0;
65
66 /** \brief Length of the bytecode instruction in bytes. */
67 virtual size_t byte_length() const = 0;
68
69 using OffsetMap = std::unordered_map<const RoseInstruction *, u32>;
70
71 /**
72 * \brief Writes a concrete implementation of this instruction.
73 *
74 * Other data that this instruction depends on is written directly into the
75 * blob, while the instruction structure itself (of size given by
76 * the byte_length() function) is written to dest.
77 */
78 virtual void write(void *dest, RoseEngineBlob &blob,
79 const OffsetMap &offset_map) const = 0;
80
81 /**
82 * \brief Update a target pointer.
83 *
84 * If this instruction contains any reference to the old target, replace it
85 * with the new one.
86 */
87 virtual void update_target(const RoseInstruction *old_target,
88 const RoseInstruction *new_target) = 0;
89
90 /**
91 * \brief True if these instructions are equivalent within their own
92 * programs.
93 *
94 * Checks that any pointers to other instructions point to the same
95 * offsets.
96 */
97 bool equiv(const RoseInstruction &other, const OffsetMap &offsets,
98 const OffsetMap &other_offsets) const {
99 return equiv_impl(other, offsets, other_offsets);
100 }
101
102private:
103 virtual bool equiv_impl(const RoseInstruction &other,
104 const OffsetMap &offsets,
105 const OffsetMap &other_offsets) const = 0;
106};
107
108/**
109 * \brief Templated implementation class to handle boring boilerplate code.
110 */
111template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
112class RoseInstrBase : public RoseInstruction {
113protected:
114 static constexpr RoseInstructionCode opcode = Opcode;
115 using impl_type = ImplType;
116
117public:
118 RoseInstructionCode code() const override { return opcode; }
119
120 size_t byte_length() const override {
121 return sizeof(impl_type);
122 }
123
124 /**
125 * Note: this implementation simply zeroes the destination region and
126 * writes in the correct opcode. This is sufficient for trivial
127 * instructions, but instructions with data members will want to override
128 * it.
129 */
130 void write(void *dest, RoseEngineBlob &,
131 const RoseInstruction::OffsetMap &) const override {
132 assert(dest != nullptr);
133 assert(ISALIGNED_N(dest, ROSE_INSTR_MIN_ALIGN));
134
135 impl_type *inst = static_cast<impl_type *>(dest);
136 memset(inst, 0, sizeof(impl_type));
137 inst->code = verify_u8(opcode);
138 }
139
140private:
141 bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets,
142 const OffsetMap &other_offsets) const override {
143 const auto *ri_that = dynamic_cast<const RoseInstrType *>(&other);
144 if (!ri_that) {
145 return false;
146 }
147 const auto *ri_this = dynamic_cast<const RoseInstrType *>(this);
148 assert(ri_this);
149 return ri_this->equiv_to(*ri_that, offsets, other_offsets);
150 }
151};
152
153template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
154constexpr RoseInstructionCode
155 RoseInstrBase<Opcode, ImplType, RoseInstrType>::opcode;
156
157/**
158 * \brief Refinement of RoseInstrBase to use for instructions that have
159 * just a single target member, called "target".
160 */
161template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
162class RoseInstrBaseOneTarget
163 : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
164public:
165 void update_target(const RoseInstruction *old_target,
166 const RoseInstruction *new_target) override {
167 RoseInstrType *ri = dynamic_cast<RoseInstrType *>(this);
168 assert(ri);
169 if (ri->target == old_target) {
170 ri->target = new_target;
171 }
172 }
173};
174
175/**
176 * \brief Refinement of RoseInstrBase to use for instructions that have no
177 * targets.
178 */
179template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
180class RoseInstrBaseNoTargets
181 : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
182public:
183 void update_target(const RoseInstruction *,
184 const RoseInstruction *) override {}
185};
186
187/**
188 * \brief Refinement of RoseInstrBaseNoTargets to use for instructions that
189 * have no members at all, just an opcode.
190 */
191template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
192class RoseInstrBaseTrivial
193 : public RoseInstrBaseNoTargets<Opcode, ImplType, RoseInstrType> {
194public:
195 virtual bool operator==(const RoseInstrType &) const { return true; }
196
197 size_t hash() const override {
198 return hash_all(Opcode);
199 }
200
201 bool equiv_to(const RoseInstrType &, const RoseInstruction::OffsetMap &,
202 const RoseInstruction::OffsetMap &) const {
203 return true;
204 }
205};
206
207////
208//// Concrete implementation classes start here.
209////
210
211class RoseInstrAnchoredDelay
212 : public RoseInstrBaseOneTarget<ROSE_INSTR_ANCHORED_DELAY,
213 ROSE_STRUCT_ANCHORED_DELAY,
214 RoseInstrAnchoredDelay> {
215public:
216 rose_group groups;
217 u32 anch_id;
218 const RoseInstruction *target;
219
220 RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in,
221 const RoseInstruction *target_in)
222 : groups(groups_in), anch_id(anch_id_in), target(target_in) {}
223
224 bool operator==(const RoseInstrAnchoredDelay &ri) const {
225 return groups == ri.groups && anch_id == ri.anch_id
226 && target == ri.target;
227 }
228
229 size_t hash() const override {
230 return hash_all(opcode, groups, anch_id);
231 }
232
233 void write(void *dest, RoseEngineBlob &blob,
234 const OffsetMap &offset_map) const override;
235
236 bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets,
237 const OffsetMap &other_offsets) const {
238 return groups == ri.groups && anch_id == ri.anch_id
239 && offsets.at(target) == other_offsets.at(ri.target);
240 }
241};
242
243class RoseInstrCheckLitEarly
244 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LIT_EARLY,
245 ROSE_STRUCT_CHECK_LIT_EARLY,
246 RoseInstrCheckLitEarly> {
247public:
248 u32 min_offset;
249 const RoseInstruction *target;
250
251 RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in)
252 : min_offset(min_offset_in), target(target_in) {}
253
254 bool operator==(const RoseInstrCheckLitEarly &ri) const {
255 return min_offset == ri.min_offset && target == ri.target;
256 }
257
258 size_t hash() const override {
259 return hash_all(opcode, min_offset);
260 }
261
262 void write(void *dest, RoseEngineBlob &blob,
263 const OffsetMap &offset_map) const override;
264
265 bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets,
266 const OffsetMap &other_offsets) const {
267 return min_offset == ri.min_offset &&
268 offsets.at(target) == other_offsets.at(ri.target);
269 }
270};
271
272class RoseInstrCheckGroups
273 : public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_GROUPS,
274 ROSE_STRUCT_CHECK_GROUPS,
275 RoseInstrCheckGroups> {
276public:
277 rose_group groups;
278
279 explicit RoseInstrCheckGroups(rose_group groups_in) : groups(groups_in) {}
280
281 bool operator==(const RoseInstrCheckGroups &ri) const {
282 return groups == ri.groups;
283 }
284
285 size_t hash() const override {
286 return hash_all(opcode, groups);
287 }
288
289 void write(void *dest, RoseEngineBlob &blob,
290 const OffsetMap &offset_map) const override;
291
292 bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &,
293 const OffsetMap &) const {
294 return groups == ri.groups;
295 }
296};
297
298class RoseInstrCheckOnlyEod
299 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_ONLY_EOD,
300 ROSE_STRUCT_CHECK_ONLY_EOD,
301 RoseInstrCheckOnlyEod> {
302public:
303 const RoseInstruction *target;
304
305 explicit RoseInstrCheckOnlyEod(const RoseInstruction *target_in)
306 : target(target_in) {}
307
308 bool operator==(const RoseInstrCheckOnlyEod &ri) const {
309 return target == ri.target;
310 }
311
312 size_t hash() const override {
313 return hash_all(opcode);
314 }
315
316 void write(void *dest, RoseEngineBlob &blob,
317 const OffsetMap &offset_map) const override;
318
319 bool equiv_to(const RoseInstrCheckOnlyEod &ri, const OffsetMap &offsets,
320 const OffsetMap &other_offsets) const {
321 return offsets.at(target) == other_offsets.at(ri.target);
322 }
323};
324
325class RoseInstrCheckBounds
326 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BOUNDS,
327 ROSE_STRUCT_CHECK_BOUNDS,
328 RoseInstrCheckBounds> {
329public:
330 u64a min_bound;
331 u64a max_bound;
332 const RoseInstruction *target;
333
334 RoseInstrCheckBounds(u64a min, u64a max, const RoseInstruction *target_in)
335 : min_bound(min), max_bound(max), target(target_in) {}
336
337 bool operator==(const RoseInstrCheckBounds &ri) const {
338 return min_bound == ri.min_bound && max_bound == ri.max_bound &&
339 target == ri.target;
340 }
341
342 size_t hash() const override {
343 return hash_all(opcode, min_bound, max_bound);
344 }
345
346 void write(void *dest, RoseEngineBlob &blob,
347 const OffsetMap &offset_map) const override;
348
349 bool equiv_to(const RoseInstrCheckBounds &ri, const OffsetMap &offsets,
350 const OffsetMap &other_offsets) const {
351 return min_bound == ri.min_bound && max_bound == ri.max_bound &&
352 offsets.at(target) == other_offsets.at(ri.target);
353 }
354};
355
356class RoseInstrCheckNotHandled
357 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_NOT_HANDLED,
358 ROSE_STRUCT_CHECK_NOT_HANDLED,
359 RoseInstrCheckNotHandled> {
360public:
361 u32 key;
362 const RoseInstruction *target;
363
364 RoseInstrCheckNotHandled(u32 key_in, const RoseInstruction *target_in)
365 : key(key_in), target(target_in) {}
366
367 bool operator==(const RoseInstrCheckNotHandled &ri) const {
368 return key == ri.key && target == ri.target;
369 }
370
371 size_t hash() const override {
372 return hash_all(opcode, key);
373 }
374
375 void write(void *dest, RoseEngineBlob &blob,
376 const OffsetMap &offset_map) const override;
377
378 bool equiv_to(const RoseInstrCheckNotHandled &ri, const OffsetMap &offsets,
379 const OffsetMap &other_offsets) const {
380 return key == ri.key &&
381 offsets.at(target) == other_offsets.at(ri.target);
382 }
383};
384
385class RoseInstrCheckSingleLookaround
386 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SINGLE_LOOKAROUND,
387 ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND,
388 RoseInstrCheckSingleLookaround> {
389public:
390 s8 offset;
391 CharReach reach;
392 const RoseInstruction *target;
393
394 RoseInstrCheckSingleLookaround(s8 offset_in, CharReach reach_in,
395 const RoseInstruction *target_in)
396 : offset(offset_in), reach(std::move(reach_in)), target(target_in) {}
397
398 bool operator==(const RoseInstrCheckSingleLookaround &ri) const {
399 return offset == ri.offset && reach == ri.reach && target == ri.target;
400 }
401
402 size_t hash() const override {
403 return hash_all(opcode, offset, reach);
404 }
405
406 void write(void *dest, RoseEngineBlob &blob,
407 const OffsetMap &offset_map) const override;
408
409 bool equiv_to(const RoseInstrCheckSingleLookaround &ri,
410 const OffsetMap &offsets,
411 const OffsetMap &other_offsets) const {
412 return offset == ri.offset && reach == ri.reach &&
413 offsets.at(target) == other_offsets.at(ri.target);
414 }
415};
416
417class RoseInstrCheckLookaround
418 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LOOKAROUND,
419 ROSE_STRUCT_CHECK_LOOKAROUND,
420 RoseInstrCheckLookaround> {
421public:
422 std::vector<LookEntry> look;
423 const RoseInstruction *target;
424
425 RoseInstrCheckLookaround(std::vector<LookEntry> look_in,
426 const RoseInstruction *target_in)
427 : look(std::move(look_in)), target(target_in) {}
428
429 bool operator==(const RoseInstrCheckLookaround &ri) const {
430 return look == ri.look && target == ri.target;
431 }
432
433 size_t hash() const override {
434 return hash_all(opcode, look);
435 }
436
437 void write(void *dest, RoseEngineBlob &blob,
438 const OffsetMap &offset_map) const override;
439
440 bool equiv_to(const RoseInstrCheckLookaround &ri, const OffsetMap &offsets,
441 const OffsetMap &other_offsets) const {
442 return look == ri.look
443 && offsets.at(target) == other_offsets.at(ri.target);
444 }
445};
446
447class RoseInstrCheckMask
448 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK,
449 ROSE_STRUCT_CHECK_MASK,
450 RoseInstrCheckMask> {
451public:
452 u64a and_mask;
453 u64a cmp_mask;
454 u64a neg_mask;
455 s32 offset;
456 const RoseInstruction *target;
457
458 RoseInstrCheckMask(u64a and_mask_in, u64a cmp_mask_in, u64a neg_mask_in,
459 s32 offset_in, const RoseInstruction *target_in)
460 : and_mask(and_mask_in), cmp_mask(cmp_mask_in), neg_mask(neg_mask_in),
461 offset(offset_in), target(target_in) {}
462
463 bool operator==(const RoseInstrCheckMask &ri) const {
464 return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
465 neg_mask == ri.neg_mask && offset == ri.offset &&
466 target == ri.target;
467 }
468
469 size_t hash() const override {
470 return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
471 }
472
473 void write(void *dest, RoseEngineBlob &blob,
474 const OffsetMap &offset_map) const override;
475
476 bool equiv_to(const RoseInstrCheckMask &ri, const OffsetMap &offsets,
477 const OffsetMap &other_offsets) const {
478 return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
479 neg_mask == ri.neg_mask && offset == ri.offset &&
480 offsets.at(target) == other_offsets.at(ri.target);
481 }
482};
483
484class RoseInstrCheckMask32
485 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK_32,
486 ROSE_STRUCT_CHECK_MASK_32,
487 RoseInstrCheckMask32> {
488public:
489 std::array<u8, 32> and_mask;
490 std::array<u8, 32> cmp_mask;
491 u32 neg_mask;
492 s32 offset;
493 const RoseInstruction *target;
494
495 RoseInstrCheckMask32(std::array<u8, 32> and_mask_in,
496 std::array<u8, 32> cmp_mask_in, u32 neg_mask_in,
497 s32 offset_in, const RoseInstruction *target_in)
498 : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)),
499 neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
500
501 bool operator==(const RoseInstrCheckMask32 &ri) const {
502 return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
503 neg_mask == ri.neg_mask && offset == ri.offset &&
504 target == ri.target;
505 }
506
507 size_t hash() const override {
508 return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
509 }
510
511 void write(void *dest, RoseEngineBlob &blob,
512 const OffsetMap &offset_map) const override;
513
514 bool equiv_to(const RoseInstrCheckMask32 &ri, const OffsetMap &offsets,
515 const OffsetMap &other_offsets) const {
516 return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
517 neg_mask == ri.neg_mask && offset == ri.offset &&
518 offsets.at(target) == other_offsets.at(ri.target);
519 }
520};
521
522class RoseInstrCheckByte
523 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BYTE,
524 ROSE_STRUCT_CHECK_BYTE,
525 RoseInstrCheckByte> {
526public:
527 u8 and_mask;
528 u8 cmp_mask;
529 u8 negation;
530 s32 offset;
531 const RoseInstruction *target;
532
533 RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in,
534 s32 offset_in, const RoseInstruction *target_in)
535 : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in),
536 offset(offset_in), target(target_in) {}
537
538 bool operator==(const RoseInstrCheckByte &ri) const {
539 return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
540 negation == ri.negation && offset == ri.offset &&
541 target == ri.target;
542 }
543
544 size_t hash() const override {
545 return hash_all(opcode, and_mask, cmp_mask, negation, offset);
546 }
547
548 void write(void *dest, RoseEngineBlob &blob,
549 const OffsetMap &offset_map) const override;
550
551 bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets,
552 const OffsetMap &other_offsets) const {
553 return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
554 negation == ri.negation && offset == ri.offset &&
555 offsets.at(target) == other_offsets.at(ri.target);
556 }
557};
558
559class RoseInstrCheckShufti16x8
560 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x8,
561 ROSE_STRUCT_CHECK_SHUFTI_16x8,
562 RoseInstrCheckShufti16x8> {
563public:
564 std::array<u8, 32> nib_mask;
565 std::array<u8, 16> bucket_select_mask;
566 u32 neg_mask;
567 s32 offset;
568 const RoseInstruction *target;
569
570 RoseInstrCheckShufti16x8(std::array<u8, 32> nib_mask_in,
571 std::array<u8, 16> bucket_select_mask_in,
572 u32 neg_mask_in, s32 offset_in,
573 const RoseInstruction *target_in)
574 : nib_mask(std::move(nib_mask_in)),
575 bucket_select_mask(std::move(bucket_select_mask_in)),
576 neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
577
578 bool operator==(const RoseInstrCheckShufti16x8 &ri) const {
579 return nib_mask == ri.nib_mask &&
580 bucket_select_mask == ri.bucket_select_mask &&
581 neg_mask == ri.neg_mask && offset == ri.offset &&
582 target == ri.target;
583 }
584
585 size_t hash() const override {
586 return hash_all(opcode, nib_mask, bucket_select_mask, neg_mask, offset);
587 }
588
589 void write(void *dest, RoseEngineBlob &blob,
590 const OffsetMap &offset_map) const override;
591
592 bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets,
593 const OffsetMap &other_offsets) const {
594 return nib_mask == ri.nib_mask &&
595 bucket_select_mask == ri.bucket_select_mask &&
596 neg_mask == ri.neg_mask && offset == ri.offset &&
597 offsets.at(target) == other_offsets.at(ri.target);
598 }
599};
600
601class RoseInstrCheckShufti32x8
602 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x8,
603 ROSE_STRUCT_CHECK_SHUFTI_32x8,
604 RoseInstrCheckShufti32x8> {
605public:
606 std::array<u8, 16> hi_mask;
607 std::array<u8, 16> lo_mask;
608 std::array<u8, 32> bucket_select_mask;
609 u32 neg_mask;
610 s32 offset;
611 const RoseInstruction *target;
612
613 RoseInstrCheckShufti32x8(std::array<u8, 16> hi_mask_in,
614 std::array<u8, 16> lo_mask_in,
615 std::array<u8, 32> bucket_select_mask_in,
616 u32 neg_mask_in, s32 offset_in,
617 const RoseInstruction *target_in)
618 : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
619 bucket_select_mask(std::move(bucket_select_mask_in)),
620 neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
621
622 bool operator==(const RoseInstrCheckShufti32x8 &ri) const {
623 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
624 bucket_select_mask == ri.bucket_select_mask &&
625 neg_mask == ri.neg_mask && offset == ri.offset &&
626 target == ri.target;
627 }
628
629 size_t hash() const override {
630 return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
631 offset);
632 }
633
634 void write(void *dest, RoseEngineBlob &blob,
635 const OffsetMap &offset_map) const override;
636
637 bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets,
638 const OffsetMap &other_offsets) const {
639 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
640 bucket_select_mask == ri.bucket_select_mask &&
641 neg_mask == ri.neg_mask && offset == ri.offset &&
642 offsets.at(target) == other_offsets.at(ri.target);
643 }
644};
645
646class RoseInstrCheckShufti16x16
647 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x16,
648 ROSE_STRUCT_CHECK_SHUFTI_16x16,
649 RoseInstrCheckShufti16x16> {
650public:
651 std::array<u8, 32> hi_mask;
652 std::array<u8, 32> lo_mask;
653 std::array<u8, 32> bucket_select_mask;
654 u32 neg_mask;
655 s32 offset;
656 const RoseInstruction *target;
657
658 RoseInstrCheckShufti16x16(std::array<u8, 32> hi_mask_in,
659 std::array<u8, 32> lo_mask_in,
660 std::array<u8, 32> bucket_select_mask_in,
661 u32 neg_mask_in, s32 offset_in,
662 const RoseInstruction *target_in)
663 : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
664 bucket_select_mask(std::move(bucket_select_mask_in)),
665 neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
666
667 bool operator==(const RoseInstrCheckShufti16x16 &ri) const {
668 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
669 bucket_select_mask == ri.bucket_select_mask &&
670 neg_mask == ri.neg_mask && offset == ri.offset &&
671 target == ri.target;
672 }
673
674 size_t hash() const override {
675 return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
676 offset);
677 }
678
679 void write(void *dest, RoseEngineBlob &blob,
680 const OffsetMap &offset_map) const override;
681
682 bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets,
683 const OffsetMap &other_offsets) const {
684 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
685 bucket_select_mask == ri.bucket_select_mask &&
686 neg_mask == ri.neg_mask && offset == ri.offset &&
687 offsets.at(target) == other_offsets.at(ri.target);
688 }
689};
690
691class RoseInstrCheckShufti32x16
692 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x16,
693 ROSE_STRUCT_CHECK_SHUFTI_32x16,
694 RoseInstrCheckShufti32x16> {
695public:
696 std::array<u8, 32> hi_mask;
697 std::array<u8, 32> lo_mask;
698 std::array<u8, 32> bucket_select_mask_hi;
699 std::array<u8, 32> bucket_select_mask_lo;
700 u32 neg_mask;
701 s32 offset;
702 const RoseInstruction *target;
703
704 RoseInstrCheckShufti32x16(std::array<u8, 32> hi_mask_in,
705 std::array<u8, 32> lo_mask_in,
706 std::array<u8, 32> bucket_select_mask_hi_in,
707 std::array<u8, 32> bucket_select_mask_lo_in,
708 u32 neg_mask_in, s32 offset_in,
709 const RoseInstruction *target_in)
710 : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
711 bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
712 bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
713 neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
714
715 bool operator==(const RoseInstrCheckShufti32x16 &ri) const {
716 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
717 bucket_select_mask_hi == ri.bucket_select_mask_hi &&
718 bucket_select_mask_lo == ri.bucket_select_mask_lo &&
719 neg_mask == ri.neg_mask && offset == ri.offset &&
720 target == ri.target;
721 }
722
723 size_t hash() const override {
724 return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
725 bucket_select_mask_lo, neg_mask, offset);
726 }
727
728 void write(void *dest, RoseEngineBlob &blob,
729 const OffsetMap &offset_map) const override;
730
731 bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets,
732 const OffsetMap &other_offsets) const {
733 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
734 bucket_select_mask_hi == ri.bucket_select_mask_hi &&
735 bucket_select_mask_lo == ri.bucket_select_mask_lo &&
736 neg_mask == ri.neg_mask && offset == ri.offset &&
737 offsets.at(target) == other_offsets.at(ri.target);
738 }
739};
740
741class RoseInstrCheckInfix
742 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_INFIX,
743 ROSE_STRUCT_CHECK_INFIX,
744 RoseInstrCheckInfix> {
745public:
746 u32 queue;
747 u32 lag;
748 ReportID report;
749 const RoseInstruction *target;
750
751 RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in,
752 const RoseInstruction *target_in)
753 : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
754
755 bool operator==(const RoseInstrCheckInfix &ri) const {
756 return queue == ri.queue && lag == ri.lag && report == ri.report &&
757 target == ri.target;
758 }
759
760 size_t hash() const override {
761 return hash_all(opcode, queue, lag, report);
762 }
763
764 void write(void *dest, RoseEngineBlob &blob,
765 const OffsetMap &offset_map) const override;
766
767 bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets,
768 const OffsetMap &other_offsets) const {
769 return queue == ri.queue && lag == ri.lag && report == ri.report &&
770 offsets.at(target) == other_offsets.at(ri.target);
771 }
772};
773
774class RoseInstrCheckPrefix
775 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_PREFIX,
776 ROSE_STRUCT_CHECK_PREFIX,
777 RoseInstrCheckPrefix> {
778public:
779 u32 queue;
780 u32 lag;
781 ReportID report;
782 const RoseInstruction *target;
783
784 RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in,
785 const RoseInstruction *target_in)
786 : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
787
788 bool operator==(const RoseInstrCheckPrefix &ri) const {
789 return queue == ri.queue && lag == ri.lag && report == ri.report &&
790 target == ri.target;
791 }
792
793 size_t hash() const override {
794 return hash_all(opcode, queue, lag, report);
795 }
796
797 void write(void *dest, RoseEngineBlob &blob,
798 const OffsetMap &offset_map) const override;
799
800 bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets,
801 const OffsetMap &other_offsets) const {
802 return queue == ri.queue && lag == ri.lag && report == ri.report &&
803 offsets.at(target) == other_offsets.at(ri.target);
804 }
805};
806
807class RoseInstrPushDelayed
808 : public RoseInstrBaseNoTargets<ROSE_INSTR_PUSH_DELAYED,
809 ROSE_STRUCT_PUSH_DELAYED,
810 RoseInstrPushDelayed> {
811public:
812 u8 delay;
813 u32 index;
814
815 RoseInstrPushDelayed(u8 delay_in, u32 index_in)
816 : delay(delay_in), index(index_in) {}
817
818 bool operator==(const RoseInstrPushDelayed &ri) const {
819 return delay == ri.delay && index == ri.index;
820 }
821
822 size_t hash() const override {
823 return hash_all(opcode, delay, index);
824 }
825
826 void write(void *dest, RoseEngineBlob &blob,
827 const OffsetMap &offset_map) const override;
828
829 bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &,
830 const OffsetMap &) const {
831 return delay == ri.delay && index == ri.index;
832 }
833};
834
835class RoseInstrCatchUp
836 : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP, ROSE_STRUCT_CATCH_UP,
837 RoseInstrCatchUp> {
838public:
839 ~RoseInstrCatchUp() override;
840};
841
842class RoseInstrCatchUpMpv
843 : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP_MPV,
844 ROSE_STRUCT_CATCH_UP_MPV,
845 RoseInstrCatchUpMpv> {
846public:
847 ~RoseInstrCatchUpMpv() override;
848};
849
850class RoseInstrSomAdjust
851 : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_ADJUST,
852 ROSE_STRUCT_SOM_ADJUST,
853 RoseInstrSomAdjust> {
854public:
855 u32 distance;
856
857 explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {}
858
859 bool operator==(const RoseInstrSomAdjust &ri) const {
860 return distance == ri.distance;
861 }
862
863 size_t hash() const override {
864 return hash_all(opcode, distance);
865 }
866
867 void write(void *dest, RoseEngineBlob &blob,
868 const OffsetMap &offset_map) const override;
869
870 bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &,
871 const OffsetMap &) const {
872 return distance == ri.distance;
873 }
874};
875
876class RoseInstrSomLeftfix
877 : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_LEFTFIX,
878 ROSE_STRUCT_SOM_LEFTFIX,
879 RoseInstrSomLeftfix> {
880public:
881 u32 queue;
882 u32 lag;
883
884 RoseInstrSomLeftfix(u32 queue_in, u32 lag_in)
885 : queue(queue_in), lag(lag_in) {}
886
887 bool operator==(const RoseInstrSomLeftfix &ri) const {
888 return queue == ri.queue && lag == ri.lag;
889 }
890
891 size_t hash() const override {
892 return hash_all(opcode, queue, lag);
893 }
894
895 void write(void *dest, RoseEngineBlob &blob,
896 const OffsetMap &offset_map) const override;
897
898 bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &,
899 const OffsetMap &) const {
900 return queue == ri.queue && lag == ri.lag;
901 }
902};
903
904class RoseInstrSomFromReport
905 : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_FROM_REPORT,
906 ROSE_STRUCT_SOM_FROM_REPORT,
907 RoseInstrSomFromReport> {
908public:
909 som_operation som;
910
911 RoseInstrSomFromReport() {
912 std::memset(&som, 0, sizeof(som));
913 }
914
915 bool operator==(const RoseInstrSomFromReport &ri) const {
916 return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
917 }
918
919 size_t hash() const override {
920 return hash_all(opcode, som.type, som.onmatch);
921 }
922
923 void write(void *dest, RoseEngineBlob &blob,
924 const OffsetMap &offset_map) const override;
925
926 bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &,
927 const OffsetMap &) const {
928 return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
929 }
930};
931
932class RoseInstrSomZero
933 : public RoseInstrBaseTrivial<ROSE_INSTR_SOM_ZERO, ROSE_STRUCT_SOM_ZERO,
934 RoseInstrSomZero> {
935public:
936 ~RoseInstrSomZero() override;
937};
938
939class RoseInstrTriggerInfix
940 : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_INFIX,
941 ROSE_STRUCT_TRIGGER_INFIX,
942 RoseInstrTriggerInfix> {
943public:
944 u8 cancel;
945 u32 queue;
946 u32 event;
947
948 RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in)
949 : cancel(cancel_in), queue(queue_in), event(event_in) {}
950
951 bool operator==(const RoseInstrTriggerInfix &ri) const {
952 return cancel == ri.cancel && queue == ri.queue && event == ri.event;
953 }
954
955 size_t hash() const override {
956 return hash_all(opcode, cancel, queue, event);
957 }
958
959 void write(void *dest, RoseEngineBlob &blob,
960 const OffsetMap &offset_map) const override;
961
962 bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &,
963 const OffsetMap &) const {
964 return cancel == ri.cancel && queue == ri.queue && event == ri.event;
965 }
966};
967
968class RoseInstrTriggerSuffix
969 : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_SUFFIX,
970 ROSE_STRUCT_TRIGGER_SUFFIX,
971 RoseInstrTriggerSuffix> {
972public:
973 u32 queue;
974 u32 event;
975
976 RoseInstrTriggerSuffix(u32 queue_in, u32 event_in)
977 : queue(queue_in), event(event_in) {}
978
979 bool operator==(const RoseInstrTriggerSuffix &ri) const {
980 return queue == ri.queue && event == ri.event;
981 }
982
983 size_t hash() const override {
984 return hash_all(opcode, queue, event);
985 }
986
987 void write(void *dest, RoseEngineBlob &blob,
988 const OffsetMap &offset_map) const override;
989
990 bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &,
991 const OffsetMap &) const {
992 return queue == ri.queue && event == ri.event;
993 }
994};
995
996class RoseInstrDedupe
997 : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE, ROSE_STRUCT_DEDUPE,
998 RoseInstrDedupe> {
999public:
1000 u8 quash_som;
1001 u32 dkey;
1002 s32 offset_adjust;
1003 const RoseInstruction *target;
1004
1005 RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
1006 const RoseInstruction *target_in)
1007 : quash_som(quash_som_in), dkey(dkey_in),
1008 offset_adjust(offset_adjust_in), target(target_in) {}
1009
1010 bool operator==(const RoseInstrDedupe &ri) const {
1011 return quash_som == ri.quash_som && dkey == ri.dkey &&
1012 offset_adjust == ri.offset_adjust && target == ri.target;
1013 }
1014
1015 size_t hash() const override {
1016 return hash_all(opcode, quash_som, dkey, offset_adjust);
1017 }
1018
1019 void write(void *dest, RoseEngineBlob &blob,
1020 const OffsetMap &offset_map) const override;
1021
1022 bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets,
1023 const OffsetMap &other_offsets) const {
1024 return quash_som == ri.quash_som && dkey == ri.dkey &&
1025 offset_adjust == ri.offset_adjust &&
1026 offsets.at(target) == other_offsets.at(ri.target);
1027 }
1028};
1029
1030class RoseInstrDedupeSom
1031 : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_SOM,
1032 ROSE_STRUCT_DEDUPE_SOM,
1033 RoseInstrDedupeSom> {
1034public:
1035 u8 quash_som;
1036 u32 dkey;
1037 s32 offset_adjust;
1038 const RoseInstruction *target;
1039
1040 RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
1041 const RoseInstruction *target_in)
1042 : quash_som(quash_som_in), dkey(dkey_in),
1043 offset_adjust(offset_adjust_in), target(target_in) {}
1044
1045 bool operator==(const RoseInstrDedupeSom &ri) const {
1046 return quash_som == ri.quash_som && dkey == ri.dkey &&
1047 offset_adjust == ri.offset_adjust && target == ri.target;
1048 }
1049
1050 size_t hash() const override {
1051 return hash_all(opcode, quash_som, dkey, offset_adjust);
1052 }
1053
1054 void write(void *dest, RoseEngineBlob &blob,
1055 const OffsetMap &offset_map) const override;
1056
1057 bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets,
1058 const OffsetMap &other_offsets) const {
1059 return quash_som == ri.quash_som && dkey == ri.dkey &&
1060 offset_adjust == ri.offset_adjust &&
1061 offsets.at(target) == other_offsets.at(ri.target);
1062 }
1063};
1064
1065class RoseInstrReportChain
1066 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_CHAIN,
1067 ROSE_STRUCT_REPORT_CHAIN,
1068 RoseInstrReportChain> {
1069public:
1070 u32 event;
1071 u64a top_squash_distance;
1072
1073 RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in)
1074 : event(event_in), top_squash_distance(top_squash_distance_in) {}
1075
1076 bool operator==(const RoseInstrReportChain &ri) const {
1077 return event == ri.event &&
1078 top_squash_distance == ri.top_squash_distance;
1079 }
1080
1081 size_t hash() const override {
1082 return hash_all(opcode, event, top_squash_distance);
1083 }
1084
1085 void write(void *dest, RoseEngineBlob &blob,
1086 const OffsetMap &offset_map) const override;
1087
1088 bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &,
1089 const OffsetMap &) const {
1090 return event == ri.event &&
1091 top_squash_distance == ri.top_squash_distance;
1092 }
1093};
1094
1095class RoseInstrReportSomInt
1096 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_INT,
1097 ROSE_STRUCT_REPORT_SOM_INT,
1098 RoseInstrReportSomInt> {
1099public:
1100 som_operation som;
1101
1102 RoseInstrReportSomInt() {
1103 std::memset(&som, 0, sizeof(som));
1104 }
1105
1106 bool operator==(const RoseInstrReportSomInt &ri) const {
1107 return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1108 }
1109
1110 size_t hash() const override {
1111 return hash_all(opcode, som.type, som.onmatch);
1112 }
1113
1114 void write(void *dest, RoseEngineBlob &blob,
1115 const OffsetMap &offset_map) const override;
1116
1117 bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &,
1118 const OffsetMap &) const {
1119 return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1120 }
1121};
1122
1123class RoseInstrReportSomAware
1124 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_AWARE,
1125 ROSE_STRUCT_REPORT_SOM_AWARE,
1126 RoseInstrReportSomAware> {
1127public:
1128 som_operation som;
1129
1130 RoseInstrReportSomAware() {
1131 std::memset(&som, 0, sizeof(som));
1132 }
1133
1134 bool operator==(const RoseInstrReportSomAware &ri) const {
1135 return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1136 }
1137
1138 size_t hash() const override {
1139 return hash_all(opcode, som.type, som.onmatch);
1140 }
1141
1142 void write(void *dest, RoseEngineBlob &blob,
1143 const OffsetMap &offset_map) const override;
1144
1145 bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &,
1146 const OffsetMap &) const {
1147 return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1148 }
1149};
1150
1151class RoseInstrReport
1152 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT, ROSE_STRUCT_REPORT,
1153 RoseInstrReport> {
1154public:
1155 ReportID onmatch;
1156 s32 offset_adjust;
1157
1158 RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in)
1159 : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
1160
1161 bool operator==(const RoseInstrReport &ri) const {
1162 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1163 }
1164
1165 size_t hash() const override {
1166 return hash_all(opcode, onmatch, offset_adjust);
1167 }
1168
1169 void write(void *dest, RoseEngineBlob &blob,
1170 const OffsetMap &offset_map) const override;
1171
1172 bool equiv_to(const RoseInstrReport &ri, const OffsetMap &,
1173 const OffsetMap &) const {
1174 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1175 }
1176};
1177
1178class RoseInstrReportExhaust
1179 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_EXHAUST,
1180 ROSE_STRUCT_REPORT_EXHAUST,
1181 RoseInstrReportExhaust> {
1182public:
1183 ReportID onmatch;
1184 s32 offset_adjust;
1185 u32 ekey;
1186
1187 RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in,
1188 u32 ekey_in)
1189 : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
1190
1191 bool operator==(const RoseInstrReportExhaust &ri) const {
1192 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1193 ekey == ri.ekey;
1194 }
1195
1196 size_t hash() const override {
1197 return hash_all(opcode, onmatch, offset_adjust, ekey);
1198 }
1199
1200 void write(void *dest, RoseEngineBlob &blob,
1201 const OffsetMap &offset_map) const override;
1202
1203 bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &,
1204 const OffsetMap &) const {
1205 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1206 ekey == ri.ekey;
1207 }
1208};
1209
1210class RoseInstrReportSom
1211 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM,
1212 ROSE_STRUCT_REPORT_SOM,
1213 RoseInstrReportSom> {
1214public:
1215 ReportID onmatch;
1216 s32 offset_adjust;
1217
1218 RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in)
1219 : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
1220
1221 bool operator==(const RoseInstrReportSom &ri) const {
1222 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1223 }
1224
1225 size_t hash() const override {
1226 return hash_all(opcode, onmatch, offset_adjust);
1227 }
1228
1229 void write(void *dest, RoseEngineBlob &blob,
1230 const OffsetMap &offset_map) const override;
1231
1232 bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &,
1233 const OffsetMap &) const {
1234 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1235 }
1236};
1237
1238class RoseInstrReportSomExhaust
1239 : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_EXHAUST,
1240 ROSE_STRUCT_REPORT_SOM_EXHAUST,
1241 RoseInstrReportSomExhaust> {
1242public:
1243 ReportID onmatch;
1244 s32 offset_adjust;
1245 u32 ekey;
1246
1247 RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in,
1248 u32 ekey_in)
1249 : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
1250
1251 bool operator==(const RoseInstrReportSomExhaust &ri) const {
1252 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1253 ekey == ri.ekey;
1254 }
1255
1256 size_t hash() const override {
1257 return hash_all(opcode, onmatch, offset_adjust, ekey);
1258 }
1259
1260 void write(void *dest, RoseEngineBlob &blob,
1261 const OffsetMap &offset_map) const override;
1262
1263 bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &,
1264 const OffsetMap &) const {
1265 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1266 ekey == ri.ekey;
1267 }
1268};
1269
1270class RoseInstrDedupeAndReport
1271 : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_AND_REPORT,
1272 ROSE_STRUCT_DEDUPE_AND_REPORT,
1273 RoseInstrDedupeAndReport> {
1274public:
1275 u8 quash_som;
1276 u32 dkey;
1277 ReportID onmatch;
1278 s32 offset_adjust;
1279 const RoseInstruction *target;
1280
1281 RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in,
1282 s32 offset_adjust_in,
1283 const RoseInstruction *target_in)
1284 : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in),
1285 offset_adjust(offset_adjust_in), target(target_in) {}
1286
1287 bool operator==(const RoseInstrDedupeAndReport &ri) const {
1288 return quash_som == ri.quash_som && dkey == ri.dkey &&
1289 onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1290 target == ri.target;
1291 }
1292
1293 size_t hash() const override {
1294 return hash_all(opcode, quash_som, dkey, onmatch, offset_adjust);
1295 }
1296
1297 void write(void *dest, RoseEngineBlob &blob,
1298 const OffsetMap &offset_map) const override;
1299
1300 bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets,
1301 const OffsetMap &other_offsets) const {
1302 return quash_som == ri.quash_som && dkey == ri.dkey &&
1303 onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1304 offsets.at(target) == other_offsets.at(ri.target);
1305 }
1306};
1307
1308class RoseInstrFinalReport
1309 : public RoseInstrBaseNoTargets<ROSE_INSTR_FINAL_REPORT,
1310 ROSE_STRUCT_FINAL_REPORT,
1311 RoseInstrFinalReport> {
1312public:
1313 ReportID onmatch;
1314 s32 offset_adjust;
1315
1316 RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in)
1317 : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
1318
1319 bool operator==(const RoseInstrFinalReport &ri) const {
1320 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1321 }
1322
1323 size_t hash() const override {
1324 return hash_all(opcode, onmatch, offset_adjust);
1325 }
1326
1327 void write(void *dest, RoseEngineBlob &blob,
1328 const OffsetMap &offset_map) const override;
1329
1330 bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &,
1331 const OffsetMap &) const {
1332 return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1333 }
1334};
1335
1336class RoseInstrCheckExhausted
1337 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_EXHAUSTED,
1338 ROSE_STRUCT_CHECK_EXHAUSTED,
1339 RoseInstrCheckExhausted> {
1340public:
1341 u32 ekey;
1342 const RoseInstruction *target;
1343
1344 RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in)
1345 : ekey(ekey_in), target(target_in) {}
1346
1347 bool operator==(const RoseInstrCheckExhausted &ri) const {
1348 return ekey == ri.ekey && target == ri.target;
1349 }
1350
1351 size_t hash() const override {
1352 return hash_all(opcode, ekey);
1353 }
1354
1355 void write(void *dest, RoseEngineBlob &blob,
1356 const OffsetMap &offset_map) const override;
1357
1358 bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets,
1359 const OffsetMap &other_offsets) const {
1360 return ekey == ri.ekey &&
1361 offsets.at(target) == other_offsets.at(ri.target);
1362 }
1363};
1364
1365class RoseInstrCheckMinLength
1366 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MIN_LENGTH,
1367 ROSE_STRUCT_CHECK_MIN_LENGTH,
1368 RoseInstrCheckMinLength> {
1369public:
1370 s32 end_adj;
1371 u64a min_length;
1372 const RoseInstruction *target;
1373
1374 RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in,
1375 const RoseInstruction *target_in)
1376 : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {}
1377
1378 bool operator==(const RoseInstrCheckMinLength &ri) const {
1379 return end_adj == ri.end_adj && min_length == ri.min_length &&
1380 target == ri.target;
1381 }
1382
1383 size_t hash() const override {
1384 return hash_all(opcode, end_adj, min_length);
1385 }
1386
1387 void write(void *dest, RoseEngineBlob &blob,
1388 const OffsetMap &offset_map) const override;
1389
1390 bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets,
1391 const OffsetMap &other_offsets) const {
1392 return end_adj == ri.end_adj && min_length == ri.min_length &&
1393 offsets.at(target) == other_offsets.at(ri.target);
1394 }
1395};
1396
1397class RoseInstrSetState
1398 : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_STATE, ROSE_STRUCT_SET_STATE,
1399 RoseInstrSetState> {
1400public:
1401 u32 index;
1402
1403 explicit RoseInstrSetState(u32 index_in) : index(index_in) {}
1404
1405 bool operator==(const RoseInstrSetState &ri) const {
1406 return index == ri.index;
1407 }
1408
1409 size_t hash() const override {
1410 return hash_all(opcode, index);
1411 }
1412
1413 void write(void *dest, RoseEngineBlob &blob,
1414 const OffsetMap &offset_map) const override;
1415
1416 bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &,
1417 const OffsetMap &) const {
1418 return index == ri.index;
1419 }
1420};
1421
1422class RoseInstrSetGroups
1423 : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_GROUPS,
1424 ROSE_STRUCT_SET_GROUPS,
1425 RoseInstrSetGroups> {
1426public:
1427 rose_group groups;
1428
1429 explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {}
1430
1431 bool operator==(const RoseInstrSetGroups &ri) const {
1432 return groups == ri.groups;
1433 }
1434
1435 size_t hash() const override {
1436 return hash_all(opcode, groups);
1437 }
1438
1439 void write(void *dest, RoseEngineBlob &blob,
1440 const OffsetMap &offset_map) const override;
1441
1442 bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &,
1443 const OffsetMap &) const {
1444 return groups == ri.groups;
1445 }
1446};
1447
1448class RoseInstrSquashGroups
1449 : public RoseInstrBaseNoTargets<ROSE_INSTR_SQUASH_GROUPS,
1450 ROSE_STRUCT_SQUASH_GROUPS,
1451 RoseInstrSquashGroups> {
1452public:
1453 rose_group groups;
1454
1455 explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {}
1456
1457 bool operator==(const RoseInstrSquashGroups &ri) const {
1458 return groups == ri.groups;
1459 }
1460
1461 size_t hash() const override {
1462 return hash_all(opcode, groups);
1463 }
1464
1465 void write(void *dest, RoseEngineBlob &blob,
1466 const OffsetMap &offset_map) const override;
1467
1468 bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &,
1469 const OffsetMap &) const {
1470 return groups == ri.groups;
1471 }
1472};
1473
1474class RoseInstrCheckState
1475 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_STATE,
1476 ROSE_STRUCT_CHECK_STATE,
1477 RoseInstrCheckState> {
1478public:
1479 u32 index;
1480 const RoseInstruction *target;
1481
1482 RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in)
1483 : index(index_in), target(target_in) {}
1484
1485 bool operator==(const RoseInstrCheckState &ri) const {
1486 return index == ri.index && target == ri.target;
1487 }
1488
1489 size_t hash() const override {
1490 return hash_all(opcode, index);
1491 }
1492
1493 void write(void *dest, RoseEngineBlob &blob,
1494 const OffsetMap &offset_map) const override;
1495
1496 bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets,
1497 const OffsetMap &other_offsets) const {
1498 return index == ri.index &&
1499 offsets.at(target) == other_offsets.at(ri.target);
1500 }
1501};
1502
1503class RoseInstrSparseIterBegin
1504 : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_BEGIN,
1505 ROSE_STRUCT_SPARSE_ITER_BEGIN,
1506 RoseInstrSparseIterBegin> {
1507public:
1508 u32 num_keys; // total number of multibit keys
1509 std::vector<std::pair<u32, const RoseInstruction *>> jump_table;
1510 const RoseInstruction *target;
1511
1512 RoseInstrSparseIterBegin(u32 num_keys_in,
1513 const RoseInstruction *target_in)
1514 : num_keys(num_keys_in), target(target_in) {}
1515
1516 bool operator==(const RoseInstrSparseIterBegin &ri) const {
1517 return num_keys == ri.num_keys && jump_table == ri.jump_table &&
1518 target == ri.target;
1519 }
1520
1521 size_t hash() const override {
1522 size_t v = hash_all(opcode, num_keys);
1523 for (const u32 &key : jump_table | boost::adaptors::map_keys) {
1524 hash_combine(v, key);
1525 }
1526 return v;
1527 }
1528
1529 void write(void *dest, RoseEngineBlob &blob,
1530 const OffsetMap &offset_map) const override;
1531
1532 void update_target(const RoseInstruction *old_target,
1533 const RoseInstruction *new_target) override {
1534 if (target == old_target) {
1535 target = new_target;
1536 }
1537 for (auto &jump : jump_table) {
1538 if (jump.second == old_target) {
1539 jump.second = new_target;
1540 }
1541 }
1542 }
1543
1544 bool equiv_to(const RoseInstrSparseIterBegin &ri, const OffsetMap &offsets,
1545 const OffsetMap &other_offsets) const {
1546 if (iter_offset != ri.iter_offset ||
1547 offsets.at(target) != other_offsets.at(ri.target)) {
1548 return false;
1549 }
1550 if (jump_table.size() != ri.jump_table.size()) {
1551 return false;
1552 }
1553 auto it1 = jump_table.begin(), it2 = ri.jump_table.begin();
1554 for (; it1 != jump_table.end(); ++it1, ++it2) {
1555 if (it1->first != it2->first) {
1556 return false;
1557 }
1558 if (offsets.at(it1->second) != other_offsets.at(it2->second)) {
1559 return false;
1560 }
1561 }
1562 return true;
1563 }
1564
1565private:
1566 friend class RoseInstrSparseIterNext;
1567
1568 // These variables allow us to use the same multibit iterator and jump
1569 // table in subsequent SPARSE_ITER_NEXT write() operations.
1570 mutable bool is_written = false;
1571 mutable u32 iter_offset = 0;
1572 mutable u32 jump_table_offset = 0;
1573};
1574
1575class RoseInstrSparseIterNext
1576 : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_NEXT,
1577 ROSE_STRUCT_SPARSE_ITER_NEXT,
1578 RoseInstrSparseIterNext> {
1579public:
1580 u32 state;
1581 const RoseInstrSparseIterBegin *begin;
1582 const RoseInstruction *target;
1583
1584 RoseInstrSparseIterNext(u32 state_in,
1585 const RoseInstrSparseIterBegin *begin_in,
1586 const RoseInstruction *target_in)
1587 : state(state_in), begin(begin_in), target(target_in) {}
1588
1589 bool operator==(const RoseInstrSparseIterNext &ri) const {
1590 return state == ri.state && begin == ri.begin && target == ri.target;
1591 }
1592
1593 size_t hash() const override {
1594 return hash_all(opcode, state);
1595 }
1596
1597 void write(void *dest, RoseEngineBlob &blob,
1598 const OffsetMap &offset_map) const override;
1599
1600 void update_target(const RoseInstruction *old_target,
1601 const RoseInstruction *new_target) override {
1602 if (target == old_target) {
1603 target = new_target;
1604 }
1605 if (begin == old_target) {
1606 assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN);
1607 begin = static_cast<const RoseInstrSparseIterBegin *>(new_target);
1608 }
1609 }
1610
1611 bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets,
1612 const OffsetMap &other_offsets) const {
1613 return state == ri.state &&
1614 offsets.at(begin) == other_offsets.at(ri.begin) &&
1615 offsets.at(target) == other_offsets.at(ri.target);
1616 }
1617};
1618
1619class RoseInstrSparseIterAny
1620 : public RoseInstrBaseOneTarget<ROSE_INSTR_SPARSE_ITER_ANY,
1621 ROSE_STRUCT_SPARSE_ITER_ANY,
1622 RoseInstrSparseIterAny> {
1623public:
1624 u32 num_keys; // total number of multibit keys
1625 std::vector<u32> keys;
1626 const RoseInstruction *target;
1627
1628 RoseInstrSparseIterAny(u32 num_keys_in, std::vector<u32> keys_in,
1629 const RoseInstruction *target_in)
1630 : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {}
1631
1632 bool operator==(const RoseInstrSparseIterAny &ri) const {
1633 return num_keys == ri.num_keys && keys == ri.keys &&
1634 target == ri.target;
1635 }
1636
1637 size_t hash() const override {
1638 return hash_all(opcode, num_keys, keys);
1639 }
1640
1641 void write(void *dest, RoseEngineBlob &blob,
1642 const OffsetMap &offset_map) const override;
1643
1644 bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets,
1645 const OffsetMap &other_offsets) const {
1646 return num_keys == ri.num_keys && keys == ri.keys &&
1647 offsets.at(target) == other_offsets.at(ri.target);
1648 }
1649};
1650
1651class RoseInstrEnginesEod
1652 : public RoseInstrBaseNoTargets<ROSE_INSTR_ENGINES_EOD,
1653 ROSE_STRUCT_ENGINES_EOD,
1654 RoseInstrEnginesEod> {
1655public:
1656 u32 iter_offset;
1657
1658 explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {}
1659
1660 bool operator==(const RoseInstrEnginesEod &ri) const {
1661 return iter_offset == ri.iter_offset;
1662 }
1663
1664 size_t hash() const override {
1665 return hash_all(opcode, iter_offset);
1666 }
1667
1668 void write(void *dest, RoseEngineBlob &blob,
1669 const OffsetMap &offset_map) const override;
1670
1671 bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &,
1672 const OffsetMap &) const {
1673 return iter_offset == ri.iter_offset;
1674 }
1675};
1676
1677class RoseInstrSuffixesEod
1678 : public RoseInstrBaseTrivial<ROSE_INSTR_SUFFIXES_EOD,
1679 ROSE_STRUCT_SUFFIXES_EOD,
1680 RoseInstrSuffixesEod> {
1681public:
1682 ~RoseInstrSuffixesEod() override;
1683};
1684
1685class RoseInstrMatcherEod : public RoseInstrBaseTrivial<ROSE_INSTR_MATCHER_EOD,
1686 ROSE_STRUCT_MATCHER_EOD,
1687 RoseInstrMatcherEod> {
1688public:
1689 ~RoseInstrMatcherEod() override;
1690};
1691
1692class RoseInstrCheckLongLit
1693 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT,
1694 ROSE_STRUCT_CHECK_LONG_LIT,
1695 RoseInstrCheckLongLit> {
1696public:
1697 std::string literal;
1698 const RoseInstruction *target;
1699
1700 RoseInstrCheckLongLit(std::string literal_in,
1701 const RoseInstruction *target_in)
1702 : literal(std::move(literal_in)), target(target_in) {}
1703
1704 bool operator==(const RoseInstrCheckLongLit &ri) const {
1705 return literal == ri.literal && target == ri.target;
1706 }
1707
1708 size_t hash() const override {
1709 return hash_all(opcode, literal);
1710 }
1711
1712 void write(void *dest, RoseEngineBlob &blob,
1713 const OffsetMap &offset_map) const override;
1714
1715 bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets,
1716 const OffsetMap &other_offsets) const {
1717 return literal == ri.literal &&
1718 offsets.at(target) == other_offsets.at(ri.target);
1719 }
1720};
1721
1722class RoseInstrCheckLongLitNocase
1723 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
1724 ROSE_STRUCT_CHECK_LONG_LIT_NOCASE,
1725 RoseInstrCheckLongLitNocase> {
1726public:
1727 std::string literal;
1728 const RoseInstruction *target;
1729
1730 RoseInstrCheckLongLitNocase(std::string literal_in,
1731 const RoseInstruction *target_in)
1732 : literal(std::move(literal_in)), target(target_in) {
1733 upperString(literal);
1734 }
1735
1736 bool operator==(const RoseInstrCheckLongLitNocase &ri) const {
1737 return literal == ri.literal && target == ri.target;
1738 }
1739
1740 size_t hash() const override {
1741 return hash_all(opcode, literal);
1742 }
1743
1744 void write(void *dest, RoseEngineBlob &blob,
1745 const OffsetMap &offset_map) const override;
1746
1747 bool equiv_to(const RoseInstrCheckLongLitNocase &ri,
1748 const OffsetMap &offsets,
1749 const OffsetMap &other_offsets) const {
1750 return literal == ri.literal &&
1751 offsets.at(target) == other_offsets.at(ri.target);
1752 }
1753};
1754
1755class RoseInstrCheckMedLit
1756 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT,
1757 ROSE_STRUCT_CHECK_MED_LIT,
1758 RoseInstrCheckMedLit> {
1759public:
1760 std::string literal;
1761 const RoseInstruction *target;
1762
1763 explicit RoseInstrCheckMedLit(std::string literal_in,
1764 const RoseInstruction *target_in)
1765 : literal(std::move(literal_in)), target(target_in) {}
1766
1767 bool operator==(const RoseInstrCheckMedLit &ri) const {
1768 return literal == ri.literal && target == ri.target;
1769 }
1770
1771 size_t hash() const override {
1772 return hash_all(opcode, literal);
1773 }
1774
1775 void write(void *dest, RoseEngineBlob &blob,
1776 const OffsetMap &offset_map) const override;
1777
1778 bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets,
1779 const OffsetMap &other_offsets) const {
1780 return literal == ri.literal &&
1781 offsets.at(target) == other_offsets.at(ri.target);
1782 }
1783};
1784
1785class RoseInstrCheckMedLitNocase
1786 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
1787 ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
1788 RoseInstrCheckMedLitNocase> {
1789public:
1790 std::string literal;
1791 const RoseInstruction *target;
1792
1793 explicit RoseInstrCheckMedLitNocase(std::string literal_in,
1794 const RoseInstruction *target_in)
1795 : literal(std::move(literal_in)), target(target_in) {
1796 upperString(literal);
1797 }
1798
1799 bool operator==(const RoseInstrCheckMedLitNocase &ri) const {
1800 return literal == ri.literal && target == ri.target;
1801 }
1802
1803 size_t hash() const override {
1804 return hash_all(opcode, literal);
1805 }
1806
1807 void write(void *dest, RoseEngineBlob &blob,
1808 const OffsetMap &offset_map) const override;
1809
1810 bool equiv_to(const RoseInstrCheckMedLitNocase &ri,
1811 const OffsetMap &offsets,
1812 const OffsetMap &other_offsets) const {
1813 return literal == ri.literal &&
1814 offsets.at(target) == other_offsets.at(ri.target);
1815 }
1816};
1817
1818class RoseInstrClearWorkDone
1819 : public RoseInstrBaseTrivial<ROSE_INSTR_CLEAR_WORK_DONE,
1820 ROSE_STRUCT_CLEAR_WORK_DONE,
1821 RoseInstrClearWorkDone> {
1822public:
1823 ~RoseInstrClearWorkDone() override;
1824};
1825
1826class RoseInstrMultipathLookaround
1827 : public RoseInstrBaseOneTarget<ROSE_INSTR_MULTIPATH_LOOKAROUND,
1828 ROSE_STRUCT_MULTIPATH_LOOKAROUND,
1829 RoseInstrMultipathLookaround> {
1830public:
1831 std::vector<std::vector<LookEntry>> multi_look;
1832 s32 last_start;
1833 std::array<u8, 16> start_mask;
1834 const RoseInstruction *target;
1835
1836 RoseInstrMultipathLookaround(std::vector<std::vector<LookEntry>> ml,
1837 s32 last_start_in,
1838 std::array<u8, 16> start_mask_in,
1839 const RoseInstruction *target_in)
1840 : multi_look(std::move(ml)), last_start(last_start_in),
1841 start_mask(std::move(start_mask_in)), target(target_in) {}
1842
1843 bool operator==(const RoseInstrMultipathLookaround &ri) const {
1844 return multi_look == ri.multi_look && last_start == ri.last_start
1845 && start_mask == ri.start_mask && target == ri.target;
1846 }
1847
1848 size_t hash() const override {
1849 return hash_all(opcode, multi_look, last_start, start_mask);
1850 }
1851
1852 void write(void *dest, RoseEngineBlob &blob,
1853 const OffsetMap &offset_map) const override;
1854
1855 bool equiv_to(const RoseInstrMultipathLookaround &ri,
1856 const OffsetMap &offsets,
1857 const OffsetMap &other_offsets) const {
1858 return multi_look == ri.multi_look && last_start == ri.last_start
1859 && start_mask == ri.start_mask
1860 && offsets.at(target) == other_offsets.at(ri.target);
1861 }
1862};
1863
1864class RoseInstrCheckMultipathShufti16x8
1865 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
1866 ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8,
1867 RoseInstrCheckMultipathShufti16x8> {
1868public:
1869 std::array<u8, 32> nib_mask;
1870 std::array<u8, 64> bucket_select_mask;
1871 std::array<u8, 64> data_select_mask;
1872 u16 hi_bits_mask;
1873 u16 lo_bits_mask;
1874 u16 neg_mask;
1875 s32 base_offset;
1876 s32 last_start;
1877 const RoseInstruction *target;
1878
1879 RoseInstrCheckMultipathShufti16x8(std::array<u8, 32> nib_mask_in,
1880 std::array<u8, 64> bucket_select_mask_in,
1881 std::array<u8, 64> data_select_mask_in,
1882 u16 hi_bits_mask_in, u16 lo_bits_mask_in,
1883 u16 neg_mask_in, s32 base_offset_in,
1884 s32 last_start_in,
1885 const RoseInstruction *target_in)
1886 : nib_mask(std::move(nib_mask_in)),
1887 bucket_select_mask(std::move(bucket_select_mask_in)),
1888 data_select_mask(std::move(data_select_mask_in)),
1889 hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
1890 neg_mask(neg_mask_in), base_offset(base_offset_in),
1891 last_start(last_start_in), target(target_in) {}
1892
1893 bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const {
1894 return nib_mask == ri.nib_mask &&
1895 bucket_select_mask == ri.bucket_select_mask &&
1896 data_select_mask == ri.data_select_mask &&
1897 hi_bits_mask == ri.hi_bits_mask &&
1898 lo_bits_mask == ri.lo_bits_mask &&
1899 neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
1900 last_start == ri.last_start && target == ri.target;
1901 }
1902
1903 size_t hash() const override {
1904 return hash_all(opcode, nib_mask, bucket_select_mask, data_select_mask,
1905 hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
1906 last_start);
1907 }
1908
1909 void write(void *dest, RoseEngineBlob &blob,
1910 const OffsetMap &offset_map) const override;
1911
1912 bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri,
1913 const OffsetMap &offsets,
1914 const OffsetMap &other_offsets) const {
1915 return nib_mask == ri.nib_mask &&
1916 bucket_select_mask == ri.bucket_select_mask &&
1917 data_select_mask == ri.data_select_mask &&
1918 hi_bits_mask == ri.hi_bits_mask &&
1919 lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
1920 base_offset == ri.base_offset && last_start == ri.last_start &&
1921 offsets.at(target) == other_offsets.at(ri.target);
1922 }
1923};
1924
1925class RoseInstrCheckMultipathShufti32x8
1926 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
1927 ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8,
1928 RoseInstrCheckMultipathShufti32x8> {
1929public:
1930 std::array<u8, 32> hi_mask;
1931 std::array<u8, 32> lo_mask;
1932 std::array<u8, 64> bucket_select_mask;
1933 std::array<u8, 64> data_select_mask;
1934 u32 hi_bits_mask;
1935 u32 lo_bits_mask;
1936 u32 neg_mask;
1937 s32 base_offset;
1938 s32 last_start;
1939 const RoseInstruction *target;
1940
1941 RoseInstrCheckMultipathShufti32x8(std::array<u8, 32> hi_mask_in,
1942 std::array<u8, 32> lo_mask_in,
1943 std::array<u8, 64> bucket_select_mask_in,
1944 std::array<u8, 64> data_select_mask_in,
1945 u32 hi_bits_mask_in, u32 lo_bits_mask_in,
1946 u32 neg_mask_in, s32 base_offset_in,
1947 s32 last_start_in,
1948 const RoseInstruction *target_in)
1949 : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
1950 bucket_select_mask(std::move(bucket_select_mask_in)),
1951 data_select_mask(std::move(data_select_mask_in)),
1952 hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
1953 neg_mask(neg_mask_in), base_offset(base_offset_in),
1954 last_start(last_start_in), target(target_in) {}
1955
1956 bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const {
1957 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
1958 bucket_select_mask == ri.bucket_select_mask &&
1959 data_select_mask == ri.data_select_mask &&
1960 hi_bits_mask == ri.hi_bits_mask &&
1961 lo_bits_mask == ri.lo_bits_mask &&
1962 neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
1963 last_start == ri.last_start && target == ri.target;
1964 }
1965
1966 size_t hash() const override {
1967 return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
1968 data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
1969 base_offset, last_start);
1970 }
1971
1972 void write(void *dest, RoseEngineBlob &blob,
1973 const OffsetMap &offset_map) const override;
1974
1975 bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri,
1976 const OffsetMap &offsets,
1977 const OffsetMap &other_offsets) const {
1978 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
1979 bucket_select_mask == ri.bucket_select_mask &&
1980 data_select_mask == ri.data_select_mask &&
1981 hi_bits_mask == ri.hi_bits_mask &&
1982 lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
1983 base_offset == ri.base_offset && last_start == ri.last_start &&
1984 offsets.at(target) == other_offsets.at(ri.target);
1985 }
1986};
1987
1988class RoseInstrCheckMultipathShufti32x16
1989 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
1990 ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16,
1991 RoseInstrCheckMultipathShufti32x16> {
1992public:
1993 std::array<u8, 32> hi_mask;
1994 std::array<u8, 32> lo_mask;
1995 std::array<u8, 64> bucket_select_mask_hi;
1996 std::array<u8, 64> bucket_select_mask_lo;
1997 std::array<u8, 64> data_select_mask;
1998 u32 hi_bits_mask;
1999 u32 lo_bits_mask;
2000 u32 neg_mask;
2001 s32 base_offset;
2002 s32 last_start;
2003 const RoseInstruction *target;
2004
2005 RoseInstrCheckMultipathShufti32x16(std::array<u8, 32> hi_mask_in,
2006 std::array<u8, 32> lo_mask_in,
2007 std::array<u8, 64> bucket_select_mask_hi_in,
2008 std::array<u8, 64> bucket_select_mask_lo_in,
2009 std::array<u8, 64> data_select_mask_in,
2010 u32 hi_bits_mask_in, u32 lo_bits_mask_in,
2011 u32 neg_mask_in, s32 base_offset_in,
2012 s32 last_start_in,
2013 const RoseInstruction *target_in)
2014 : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
2015 bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
2016 bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
2017 data_select_mask(std::move(data_select_mask_in)),
2018 hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
2019 neg_mask(neg_mask_in), base_offset(base_offset_in),
2020 last_start(last_start_in), target(target_in) {}
2021
2022 bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const {
2023 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2024 bucket_select_mask_hi == ri.bucket_select_mask_hi &&
2025 bucket_select_mask_lo == ri.bucket_select_mask_lo &&
2026 data_select_mask == ri.data_select_mask &&
2027 hi_bits_mask == ri.hi_bits_mask &&
2028 lo_bits_mask == ri.lo_bits_mask &&
2029 neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
2030 last_start == ri.last_start && target == ri.target;
2031 }
2032
2033 size_t hash() const override {
2034 return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
2035 bucket_select_mask_lo, data_select_mask, hi_bits_mask,
2036 lo_bits_mask, neg_mask, base_offset, last_start);
2037 }
2038
2039 void write(void *dest, RoseEngineBlob &blob,
2040 const OffsetMap &offset_map) const override;
2041
2042 bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri,
2043 const OffsetMap &offsets,
2044 const OffsetMap &other_offsets) const {
2045 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2046 bucket_select_mask_hi == ri.bucket_select_mask_hi &&
2047 bucket_select_mask_lo == ri.bucket_select_mask_lo &&
2048 data_select_mask == ri.data_select_mask &&
2049 hi_bits_mask == ri.hi_bits_mask &&
2050 lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
2051 base_offset == ri.base_offset && last_start == ri.last_start &&
2052 offsets.at(target) == other_offsets.at(ri.target);
2053 }
2054};
2055
2056class RoseInstrCheckMultipathShufti64
2057 : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
2058 ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64,
2059 RoseInstrCheckMultipathShufti64> {
2060public:
2061 std::array<u8, 32> hi_mask;
2062 std::array<u8, 32> lo_mask;
2063 std::array<u8, 64> bucket_select_mask;
2064 std::array<u8, 64> data_select_mask;
2065 u64a hi_bits_mask;
2066 u64a lo_bits_mask;
2067 u64a neg_mask;
2068 s32 base_offset;
2069 s32 last_start;
2070 const RoseInstruction *target;
2071
2072 RoseInstrCheckMultipathShufti64(std::array<u8, 32> hi_mask_in,
2073 std::array<u8, 32> lo_mask_in,
2074 std::array<u8, 64> bucket_select_mask_in,
2075 std::array<u8, 64> data_select_mask_in,
2076 u64a hi_bits_mask_in, u64a lo_bits_mask_in,
2077 u64a neg_mask_in, s32 base_offset_in,
2078 s32 last_start_in,
2079 const RoseInstruction *target_in)
2080 : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
2081 bucket_select_mask(std::move(bucket_select_mask_in)),
2082 data_select_mask(std::move(data_select_mask_in)),
2083 hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
2084 neg_mask(neg_mask_in), base_offset(base_offset_in),
2085 last_start(last_start_in), target(target_in) {}
2086
2087 bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const {
2088 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2089 bucket_select_mask == ri.bucket_select_mask &&
2090 data_select_mask == ri.data_select_mask &&
2091 hi_bits_mask == ri.hi_bits_mask &&
2092 lo_bits_mask == ri.lo_bits_mask &&
2093 neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
2094 last_start == ri.last_start && target == ri.target;
2095 }
2096
2097 size_t hash() const override {
2098 return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
2099 data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
2100 base_offset, last_start);
2101 }
2102
2103 void write(void *dest, RoseEngineBlob &blob,
2104 const OffsetMap &offset_map) const override;
2105
2106 bool equiv_to(const RoseInstrCheckMultipathShufti64 &ri,
2107 const OffsetMap &offsets,
2108 const OffsetMap &other_offsets) const {
2109 return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2110 bucket_select_mask == ri.bucket_select_mask &&
2111 data_select_mask == ri.data_select_mask &&
2112 hi_bits_mask == ri.hi_bits_mask &&
2113 lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
2114 base_offset == ri.base_offset && last_start == ri.last_start &&
2115 offsets.at(target) == other_offsets.at(ri.target);
2116 }
2117};
2118
2119class RoseInstrIncludedJump
2120 : public RoseInstrBaseNoTargets<ROSE_INSTR_INCLUDED_JUMP,
2121 ROSE_STRUCT_INCLUDED_JUMP,
2122 RoseInstrIncludedJump> {
2123public:
2124 u32 child_offset;
2125 u8 squash;
2126
2127 RoseInstrIncludedJump(u32 child_offset_in, u8 squash_in)
2128 : child_offset(child_offset_in), squash(squash_in) {}
2129
2130 bool operator==(const RoseInstrIncludedJump &ri) const {
2131 return child_offset == ri.child_offset && squash == ri.squash;
2132 }
2133
2134 size_t hash() const override {
2135 return hash_all(static_cast<int>(opcode), child_offset, squash);
2136 }
2137
2138 void write(void *dest, RoseEngineBlob &blob,
2139 const OffsetMap &offset_map) const override;
2140
2141 bool equiv_to(const RoseInstrIncludedJump &ri, const OffsetMap &,
2142 const OffsetMap &) const {
2143 return child_offset == ri.child_offset && squash == ri.squash;
2144 }
2145};
2146
2147class RoseInstrSetLogical
2148 : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_LOGICAL,
2149 ROSE_STRUCT_SET_LOGICAL,
2150 RoseInstrSetLogical> {
2151public:
2152 u32 lkey;
2153 s32 offset_adjust;
2154
2155 RoseInstrSetLogical(u32 lkey_in, s32 offset_adjust_in)
2156 : lkey(lkey_in), offset_adjust(offset_adjust_in) {}
2157
2158 bool operator==(const RoseInstrSetLogical &ri) const {
2159 return lkey == ri.lkey && offset_adjust == ri.offset_adjust;
2160 }
2161
2162 size_t hash() const override {
2163 return hash_all(opcode, lkey, offset_adjust);
2164 }
2165
2166 void write(void *dest, RoseEngineBlob &blob,
2167 const OffsetMap &offset_map) const override;
2168
2169 bool equiv_to(const RoseInstrSetLogical &ri, const OffsetMap &,
2170 const OffsetMap &) const {
2171 return lkey == ri.lkey && offset_adjust == ri.offset_adjust;
2172 }
2173};
2174
2175class RoseInstrSetCombination
2176 : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_COMBINATION,
2177 ROSE_STRUCT_SET_COMBINATION,
2178 RoseInstrSetCombination> {
2179public:
2180 u32 ckey;
2181
2182 RoseInstrSetCombination(u32 ckey_in) : ckey(ckey_in) {}
2183
2184 bool operator==(const RoseInstrSetCombination &ri) const {
2185 return ckey == ri.ckey;
2186 }
2187
2188 size_t hash() const override {
2189 return hash_all(opcode, ckey);
2190 }
2191
2192 void write(void *dest, RoseEngineBlob &blob,
2193 const OffsetMap &offset_map) const override;
2194
2195 bool equiv_to(const RoseInstrSetCombination &ri, const OffsetMap &,
2196 const OffsetMap &) const {
2197 return ckey == ri.ckey;
2198 }
2199};
2200
2201class RoseInstrFlushCombination
2202 : public RoseInstrBaseTrivial<ROSE_INSTR_FLUSH_COMBINATION,
2203 ROSE_STRUCT_FLUSH_COMBINATION,
2204 RoseInstrFlushCombination> {
2205public:
2206 ~RoseInstrFlushCombination() override;
2207};
2208
2209class RoseInstrSetExhaust
2210 : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_EXHAUST,
2211 ROSE_STRUCT_SET_EXHAUST,
2212 RoseInstrSetExhaust> {
2213public:
2214 u32 ekey;
2215
2216 RoseInstrSetExhaust(u32 ekey_in) : ekey(ekey_in) {}
2217
2218 bool operator==(const RoseInstrSetExhaust &ri) const {
2219 return ekey == ri.ekey;
2220 }
2221
2222 size_t hash() const override {
2223 return hash_all(opcode, ekey);
2224 }
2225
2226 void write(void *dest, RoseEngineBlob &blob,
2227 const OffsetMap &offset_map) const override;
2228
2229 bool equiv_to(const RoseInstrSetExhaust &ri, const OffsetMap &,
2230 const OffsetMap &) const {
2231 return ekey == ri.ekey;
2232 }
2233};
2234
2235class RoseInstrEnd
2236 : public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
2237 RoseInstrEnd> {
2238public:
2239 ~RoseInstrEnd() override;
2240};
2241
2242}
2243#endif
2244