1 /*
2  * Copyright (c) 2017-2020, 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 
45 namespace ue2 {
46 
47 /**
48  * \brief Abstract base class representing a single Rose instruction.
49  */
50 class RoseInstruction {
51 public:
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      */
equiv(const RoseInstruction & other,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
102 private:
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  */
111 template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
112 class RoseInstrBase : public RoseInstruction {
113 protected:
114     static constexpr RoseInstructionCode opcode = Opcode;
115     using impl_type = ImplType;
116 
117 public:
code()118     RoseInstructionCode code() const override { return opcode; }
119 
byte_length()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      */
write(void * dest,RoseEngineBlob &,const RoseInstruction::OffsetMap &)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 
140 private:
equiv_impl(const RoseInstruction & other,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
153 template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
154 constexpr 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  */
161 template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
162 class RoseInstrBaseOneTarget
163     : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
164 public:
update_target(const RoseInstruction * old_target,const RoseInstruction * new_target)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  */
179 template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
180 class RoseInstrBaseNoTargets
181     : public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
182 public:
update_target(const RoseInstruction *,const RoseInstruction *)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  */
191 template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
192 class RoseInstrBaseTrivial
193     : public RoseInstrBaseNoTargets<Opcode, ImplType, RoseInstrType> {
194 public:
195     virtual bool operator==(const RoseInstrType &) const { return true; }
196 
hash()197     size_t hash() const override {
198         return hash_all(Opcode);
199     }
200 
equiv_to(const RoseInstrType &,const RoseInstruction::OffsetMap &,const RoseInstruction::OffsetMap &)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 
211 class RoseInstrAnchoredDelay
212     : public RoseInstrBaseOneTarget<ROSE_INSTR_ANCHORED_DELAY,
213                                     ROSE_STRUCT_ANCHORED_DELAY,
214                                     RoseInstrAnchoredDelay> {
215 public:
216     rose_group groups;
217     u32 anch_id;
218     const RoseInstruction *target;
219 
RoseInstrAnchoredDelay(rose_group groups_in,u32 anch_id_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrAnchoredDelay & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
243 class RoseInstrCheckLitEarly
244     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LIT_EARLY,
245                                     ROSE_STRUCT_CHECK_LIT_EARLY,
246                                     RoseInstrCheckLitEarly> {
247 public:
248     u32 min_offset;
249     const RoseInstruction *target;
250 
RoseInstrCheckLitEarly(u32 min_offset_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckLitEarly & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
272 class RoseInstrCheckGroups
273     : public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_GROUPS,
274                                     ROSE_STRUCT_CHECK_GROUPS,
275                                     RoseInstrCheckGroups> {
276 public:
277     rose_group groups;
278 
RoseInstrCheckGroups(rose_group groups_in)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 
hash()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 
equiv_to(const RoseInstrCheckGroups & ri,const OffsetMap &,const OffsetMap &)292     bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &,
293                   const OffsetMap &) const {
294         return groups == ri.groups;
295     }
296 };
297 
298 class RoseInstrCheckOnlyEod
299     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_ONLY_EOD,
300                                     ROSE_STRUCT_CHECK_ONLY_EOD,
301                                     RoseInstrCheckOnlyEod> {
302 public:
303     const RoseInstruction *target;
304 
RoseInstrCheckOnlyEod(const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckOnlyEod & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
325 class RoseInstrCheckBounds
326     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BOUNDS,
327                                     ROSE_STRUCT_CHECK_BOUNDS,
328                                     RoseInstrCheckBounds> {
329 public:
330     u64a min_bound;
331     u64a max_bound;
332     const RoseInstruction *target;
333 
RoseInstrCheckBounds(u64a min,u64a max,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckBounds & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
356 class RoseInstrCheckNotHandled
357     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_NOT_HANDLED,
358                                     ROSE_STRUCT_CHECK_NOT_HANDLED,
359                                     RoseInstrCheckNotHandled> {
360 public:
361     u32 key;
362     const RoseInstruction *target;
363 
RoseInstrCheckNotHandled(u32 key_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckNotHandled & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
385 class RoseInstrCheckSingleLookaround
386     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SINGLE_LOOKAROUND,
387                                     ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND,
388                                     RoseInstrCheckSingleLookaround> {
389 public:
390     s8 offset;
391     CharReach reach;
392     const RoseInstruction *target;
393 
RoseInstrCheckSingleLookaround(s8 offset_in,CharReach reach_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckSingleLookaround & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
417 class RoseInstrCheckLookaround
418     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LOOKAROUND,
419                                     ROSE_STRUCT_CHECK_LOOKAROUND,
420                                     RoseInstrCheckLookaround> {
421 public:
422     std::vector<LookEntry> look;
423     const RoseInstruction *target;
424 
RoseInstrCheckLookaround(std::vector<LookEntry> look_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckLookaround & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
447 class RoseInstrCheckMask
448     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK,
449                                     ROSE_STRUCT_CHECK_MASK,
450                                     RoseInstrCheckMask> {
451 public:
452     u64a and_mask;
453     u64a cmp_mask;
454     u64a neg_mask;
455     s32 offset;
456     const RoseInstruction *target;
457 
RoseInstrCheckMask(u64a and_mask_in,u64a cmp_mask_in,u64a neg_mask_in,s32 offset_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckMask & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
484 class RoseInstrCheckMask32
485     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK_32,
486                                     ROSE_STRUCT_CHECK_MASK_32,
487                                     RoseInstrCheckMask32> {
488 public:
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 
RoseInstrCheckMask32(std::array<u8,32> and_mask_in,std::array<u8,32> cmp_mask_in,u32 neg_mask_in,s32 offset_in,const RoseInstruction * target_in)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 
hash()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 
equiv_to(const RoseInstrCheckMask32 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)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 
522 class RoseInstrCheckMask64
523     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MASK_64,
524                                     ROSE_STRUCT_CHECK_MASK_64,
525                                     RoseInstrCheckMask64> {
526 public:
527     std::array<u8, 64> and_mask;
528     std::array<u8, 64> cmp_mask;
529     u64a neg_mask;
530     s32 offset;
531     const RoseInstruction *target;
532 
RoseInstrCheckMask64(std::array<u8,64> and_mask_in,std::array<u8,64> cmp_mask_in,u64a neg_mask_in,s32 offset_in,const RoseInstruction * target_in)533     RoseInstrCheckMask64(std::array<u8, 64> and_mask_in,
534                          std::array<u8, 64> cmp_mask_in, u64a neg_mask_in,
535                          s32 offset_in, const RoseInstruction *target_in)
536         : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)),
537           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
538     bool operator==(const RoseInstrCheckMask64 &ri) const {
539         return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
540                neg_mask == ri.neg_mask && offset == ri.offset &&
541                target == ri.target;
542     }
543 
hash()544     size_t hash() const override {
545         return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset);
546     }
547 
548     void write(void *dest, RoseEngineBlob &blob,
549                const OffsetMap &offset_map) const override;
550 
equiv_to(const RoseInstrCheckMask64 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)551     bool equiv_to(const RoseInstrCheckMask64 &ri, const OffsetMap &offsets,
552                   const OffsetMap &other_offsets) const {
553         return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
554                neg_mask == ri.neg_mask && offset == ri.offset &&
555                offsets.at(target) == other_offsets.at(ri.target);
556     }
557 };
558 
559 class RoseInstrCheckByte
560     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_BYTE,
561                                     ROSE_STRUCT_CHECK_BYTE,
562                                     RoseInstrCheckByte> {
563 public:
564     u8 and_mask;
565     u8 cmp_mask;
566     u8 negation;
567     s32 offset;
568     const RoseInstruction *target;
569 
RoseInstrCheckByte(u8 and_mask_in,u8 cmp_mask_in,u8 negation_in,s32 offset_in,const RoseInstruction * target_in)570     RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in,
571                        s32 offset_in, const RoseInstruction *target_in)
572         : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in),
573           offset(offset_in), target(target_in) {}
574 
575     bool operator==(const RoseInstrCheckByte &ri) const {
576         return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
577                negation == ri.negation && offset == ri.offset &&
578                target == ri.target;
579     }
580 
hash()581     size_t hash() const override {
582         return hash_all(opcode, and_mask, cmp_mask, negation, offset);
583     }
584 
585     void write(void *dest, RoseEngineBlob &blob,
586                const OffsetMap &offset_map) const override;
587 
equiv_to(const RoseInstrCheckByte & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)588     bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets,
589                   const OffsetMap &other_offsets) const {
590         return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask &&
591                negation == ri.negation && offset == ri.offset &&
592                offsets.at(target) == other_offsets.at(ri.target);
593     }
594 };
595 
596 class RoseInstrCheckShufti16x8
597     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x8,
598                                     ROSE_STRUCT_CHECK_SHUFTI_16x8,
599                                     RoseInstrCheckShufti16x8> {
600 public:
601     std::array<u8, 32> nib_mask;
602     std::array<u8, 16> bucket_select_mask;
603     u32 neg_mask;
604     s32 offset;
605     const RoseInstruction *target;
606 
RoseInstrCheckShufti16x8(std::array<u8,32> nib_mask_in,std::array<u8,16> bucket_select_mask_in,u32 neg_mask_in,s32 offset_in,const RoseInstruction * target_in)607     RoseInstrCheckShufti16x8(std::array<u8, 32> nib_mask_in,
608                              std::array<u8, 16> bucket_select_mask_in,
609                              u32 neg_mask_in, s32 offset_in,
610                              const RoseInstruction *target_in)
611         : nib_mask(std::move(nib_mask_in)),
612           bucket_select_mask(std::move(bucket_select_mask_in)),
613           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
614 
615     bool operator==(const RoseInstrCheckShufti16x8 &ri) const {
616         return nib_mask == ri.nib_mask &&
617                bucket_select_mask == ri.bucket_select_mask &&
618                neg_mask == ri.neg_mask && offset == ri.offset &&
619                target == ri.target;
620     }
621 
hash()622     size_t hash() const override {
623         return hash_all(opcode, nib_mask, bucket_select_mask, neg_mask, offset);
624     }
625 
626     void write(void *dest, RoseEngineBlob &blob,
627                const OffsetMap &offset_map) const override;
628 
equiv_to(const RoseInstrCheckShufti16x8 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)629     bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets,
630                   const OffsetMap &other_offsets) const {
631         return nib_mask == ri.nib_mask &&
632                bucket_select_mask == ri.bucket_select_mask &&
633                neg_mask == ri.neg_mask && offset == ri.offset &&
634                offsets.at(target) == other_offsets.at(ri.target);
635     }
636 };
637 
638 class RoseInstrCheckShufti32x8
639     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x8,
640                                     ROSE_STRUCT_CHECK_SHUFTI_32x8,
641                                     RoseInstrCheckShufti32x8> {
642 public:
643     std::array<u8, 16> hi_mask;
644     std::array<u8, 16> lo_mask;
645     std::array<u8, 32> bucket_select_mask;
646     u32 neg_mask;
647     s32 offset;
648     const RoseInstruction *target;
649 
RoseInstrCheckShufti32x8(std::array<u8,16> hi_mask_in,std::array<u8,16> lo_mask_in,std::array<u8,32> bucket_select_mask_in,u32 neg_mask_in,s32 offset_in,const RoseInstruction * target_in)650     RoseInstrCheckShufti32x8(std::array<u8, 16> hi_mask_in,
651                              std::array<u8, 16> lo_mask_in,
652                              std::array<u8, 32> bucket_select_mask_in,
653                              u32 neg_mask_in, s32 offset_in,
654                              const RoseInstruction *target_in)
655         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
656           bucket_select_mask(std::move(bucket_select_mask_in)),
657           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
658 
659     bool operator==(const RoseInstrCheckShufti32x8 &ri) const {
660         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
661                bucket_select_mask == ri.bucket_select_mask &&
662                neg_mask == ri.neg_mask && offset == ri.offset &&
663                target == ri.target;
664     }
665 
hash()666     size_t hash() const override {
667         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
668                         offset);
669     }
670 
671     void write(void *dest, RoseEngineBlob &blob,
672                const OffsetMap &offset_map) const override;
673 
equiv_to(const RoseInstrCheckShufti32x8 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)674     bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets,
675                   const OffsetMap &other_offsets) const {
676         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
677                bucket_select_mask == ri.bucket_select_mask &&
678                neg_mask == ri.neg_mask && offset == ri.offset &&
679                offsets.at(target) == other_offsets.at(ri.target);
680     }
681 };
682 
683 class RoseInstrCheckShufti16x16
684     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_16x16,
685                                     ROSE_STRUCT_CHECK_SHUFTI_16x16,
686                                     RoseInstrCheckShufti16x16> {
687 public:
688     std::array<u8, 32> hi_mask;
689     std::array<u8, 32> lo_mask;
690     std::array<u8, 32> bucket_select_mask;
691     u32 neg_mask;
692     s32 offset;
693     const RoseInstruction *target;
694 
RoseInstrCheckShufti16x16(std::array<u8,32> hi_mask_in,std::array<u8,32> lo_mask_in,std::array<u8,32> bucket_select_mask_in,u32 neg_mask_in,s32 offset_in,const RoseInstruction * target_in)695     RoseInstrCheckShufti16x16(std::array<u8, 32> hi_mask_in,
696                               std::array<u8, 32> lo_mask_in,
697                               std::array<u8, 32> bucket_select_mask_in,
698                               u32 neg_mask_in, s32 offset_in,
699                               const RoseInstruction *target_in)
700         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
701           bucket_select_mask(std::move(bucket_select_mask_in)),
702           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
703 
704     bool operator==(const RoseInstrCheckShufti16x16 &ri) const {
705         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
706                bucket_select_mask == ri.bucket_select_mask &&
707                neg_mask == ri.neg_mask && offset == ri.offset &&
708                target == ri.target;
709     }
710 
hash()711     size_t hash() const override {
712         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
713                         offset);
714     }
715 
716     void write(void *dest, RoseEngineBlob &blob,
717                const OffsetMap &offset_map) const override;
718 
equiv_to(const RoseInstrCheckShufti16x16 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)719     bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets,
720                   const OffsetMap &other_offsets) const {
721         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
722                bucket_select_mask == ri.bucket_select_mask &&
723                neg_mask == ri.neg_mask && offset == ri.offset &&
724                offsets.at(target) == other_offsets.at(ri.target);
725     }
726 };
727 
728 class RoseInstrCheckShufti32x16
729     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_32x16,
730                                     ROSE_STRUCT_CHECK_SHUFTI_32x16,
731                                     RoseInstrCheckShufti32x16> {
732 public:
733     std::array<u8, 32> hi_mask;
734     std::array<u8, 32> lo_mask;
735     std::array<u8, 32> bucket_select_mask_hi;
736     std::array<u8, 32> bucket_select_mask_lo;
737     u32 neg_mask;
738     s32 offset;
739     const RoseInstruction *target;
740 
RoseInstrCheckShufti32x16(std::array<u8,32> hi_mask_in,std::array<u8,32> lo_mask_in,std::array<u8,32> bucket_select_mask_hi_in,std::array<u8,32> bucket_select_mask_lo_in,u32 neg_mask_in,s32 offset_in,const RoseInstruction * target_in)741     RoseInstrCheckShufti32x16(std::array<u8, 32> hi_mask_in,
742                               std::array<u8, 32> lo_mask_in,
743                               std::array<u8, 32> bucket_select_mask_hi_in,
744                               std::array<u8, 32> bucket_select_mask_lo_in,
745                               u32 neg_mask_in, s32 offset_in,
746                               const RoseInstruction *target_in)
747         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
748           bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
749           bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
750           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
751 
752     bool operator==(const RoseInstrCheckShufti32x16 &ri) const {
753         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
754                bucket_select_mask_hi == ri.bucket_select_mask_hi &&
755                bucket_select_mask_lo == ri.bucket_select_mask_lo &&
756                neg_mask == ri.neg_mask && offset == ri.offset &&
757                target == ri.target;
758     }
759 
hash()760     size_t hash() const override {
761         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
762                         bucket_select_mask_lo, neg_mask, offset);
763     }
764 
765     void write(void *dest, RoseEngineBlob &blob,
766                const OffsetMap &offset_map) const override;
767 
equiv_to(const RoseInstrCheckShufti32x16 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)768     bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets,
769                   const OffsetMap &other_offsets) const {
770         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
771                bucket_select_mask_hi == ri.bucket_select_mask_hi &&
772                bucket_select_mask_lo == ri.bucket_select_mask_lo &&
773                neg_mask == ri.neg_mask && offset == ri.offset &&
774                offsets.at(target) == other_offsets.at(ri.target);
775     }
776 };
777 
778 class RoseInstrCheckShufti64x8
779     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_64x8,
780                                     ROSE_STRUCT_CHECK_SHUFTI_64x8,
781                                     RoseInstrCheckShufti64x8> {
782 public:
783     std::array<u8, 64> hi_mask;
784     std::array<u8, 64> lo_mask;
785     std::array<u8, 64> bucket_select_mask;
786     u64a neg_mask;
787     s32 offset;
788     const RoseInstruction *target;
789 
RoseInstrCheckShufti64x8(std::array<u8,64> hi_mask_in,std::array<u8,64> lo_mask_in,std::array<u8,64> bucket_select_mask_in,u64a neg_mask_in,s32 offset_in,const RoseInstruction * target_in)790     RoseInstrCheckShufti64x8(std::array<u8, 64> hi_mask_in,
791                              std::array<u8, 64> lo_mask_in,
792                              std::array<u8, 64> bucket_select_mask_in,
793                              u64a neg_mask_in, s32 offset_in,
794                              const RoseInstruction *target_in)
795         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
796           bucket_select_mask(std::move(bucket_select_mask_in)),
797           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
798 
799     bool operator==(const RoseInstrCheckShufti64x8 &ri) const {
800         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
801                bucket_select_mask == ri.bucket_select_mask &&
802                neg_mask == ri.neg_mask && offset == ri.offset &&
803                target == ri.target;
804     }
805 
hash()806     size_t hash() const override {
807         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask,
808                         offset);
809     }
810 
811     void write(void *dest, RoseEngineBlob &blob,
812                const OffsetMap &offset_map) const override;
813 
equiv_to(const RoseInstrCheckShufti64x8 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)814     bool equiv_to(const RoseInstrCheckShufti64x8 &ri, const OffsetMap &offsets,
815                   const OffsetMap &other_offsets) const {
816         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
817                bucket_select_mask == ri.bucket_select_mask &&
818                neg_mask == ri.neg_mask && offset == ri.offset &&
819                offsets.at(target) == other_offsets.at(ri.target);
820     }
821 };
822 
823 class RoseInstrCheckShufti64x16
824     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_SHUFTI_64x16,
825                                     ROSE_STRUCT_CHECK_SHUFTI_64x16,
826                                     RoseInstrCheckShufti64x16> {
827 public:
828     std::array<u8, 64> hi_mask_1;
829     std::array<u8, 64> hi_mask_2;
830     std::array<u8, 64> lo_mask_1;
831     std::array<u8, 64> lo_mask_2;
832     std::array<u8, 64> bucket_select_mask_hi;
833     std::array<u8, 64> bucket_select_mask_lo;
834     u64a neg_mask;
835     s32 offset;
836     const RoseInstruction *target;
837 
RoseInstrCheckShufti64x16(std::array<u8,64> hi_mask_1_in,std::array<u8,64> hi_mask_2_in,std::array<u8,64> lo_mask_1_in,std::array<u8,64> lo_mask_2_in,std::array<u8,64> bucket_select_mask_hi_in,std::array<u8,64> bucket_select_mask_lo_in,u64a neg_mask_in,s32 offset_in,const RoseInstruction * target_in)838     RoseInstrCheckShufti64x16(std::array<u8, 64> hi_mask_1_in,
839                               std::array<u8, 64> hi_mask_2_in,
840                               std::array<u8, 64> lo_mask_1_in,
841                               std::array<u8, 64> lo_mask_2_in,
842                               std::array<u8, 64> bucket_select_mask_hi_in,
843                               std::array<u8, 64> bucket_select_mask_lo_in,
844                               u64a neg_mask_in, s32 offset_in,
845                               const RoseInstruction *target_in)
846         : hi_mask_1(std::move(hi_mask_1_in)), hi_mask_2(std::move(hi_mask_2_in)),
847           lo_mask_1(std::move(lo_mask_1_in)), lo_mask_2(std::move(lo_mask_2_in)),
848           bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
849           bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
850           neg_mask(neg_mask_in), offset(offset_in), target(target_in) {}
851 
852     bool operator==(const RoseInstrCheckShufti64x16 &ri) const {
853         return hi_mask_1 == ri.hi_mask_1 && hi_mask_2 == ri.hi_mask_2 &&
854                lo_mask_1 == ri.lo_mask_1 && lo_mask_2 == ri.lo_mask_2 &&
855                bucket_select_mask_hi == ri.bucket_select_mask_hi &&
856                bucket_select_mask_lo == ri.bucket_select_mask_lo &&
857                neg_mask == ri.neg_mask && offset == ri.offset &&
858                target == ri.target;
859     }
860 
hash()861     size_t hash() const override {
862         return hash_all(opcode, hi_mask_1, hi_mask_2, lo_mask_1, lo_mask_2,
863                         bucket_select_mask_hi, bucket_select_mask_lo, neg_mask,
864                         offset);
865     }
866 
867     void write(void *dest, RoseEngineBlob &blob,
868                const OffsetMap &offset_map) const override;
869 
equiv_to(const RoseInstrCheckShufti64x16 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)870     bool equiv_to(const RoseInstrCheckShufti64x16 &ri, const OffsetMap &offsets,
871                   const OffsetMap &other_offsets) const {
872         return hi_mask_1 == ri.hi_mask_1 && hi_mask_2 == ri.hi_mask_2 &&
873                lo_mask_1 == ri.lo_mask_1 && lo_mask_2 == ri.lo_mask_2 &&
874                bucket_select_mask_hi == ri.bucket_select_mask_hi &&
875                bucket_select_mask_lo == ri.bucket_select_mask_lo &&
876                neg_mask == ri.neg_mask && offset == ri.offset &&
877                offsets.at(target) == other_offsets.at(ri.target);
878     }
879 };
880 
881 class RoseInstrCheckInfix
882     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_INFIX,
883                                     ROSE_STRUCT_CHECK_INFIX,
884                                     RoseInstrCheckInfix> {
885 public:
886     u32 queue;
887     u32 lag;
888     ReportID report;
889     const RoseInstruction *target;
890 
RoseInstrCheckInfix(u32 queue_in,u32 lag_in,ReportID report_in,const RoseInstruction * target_in)891     RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in,
892                         const RoseInstruction *target_in)
893         : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
894 
895     bool operator==(const RoseInstrCheckInfix &ri) const {
896         return queue == ri.queue && lag == ri.lag && report == ri.report &&
897                target == ri.target;
898     }
899 
hash()900     size_t hash() const override {
901         return hash_all(opcode, queue, lag, report);
902     }
903 
904     void write(void *dest, RoseEngineBlob &blob,
905                const OffsetMap &offset_map) const override;
906 
equiv_to(const RoseInstrCheckInfix & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)907     bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets,
908                   const OffsetMap &other_offsets) const {
909         return queue == ri.queue && lag == ri.lag && report == ri.report &&
910                offsets.at(target) == other_offsets.at(ri.target);
911     }
912 };
913 
914 class RoseInstrCheckPrefix
915     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_PREFIX,
916                                     ROSE_STRUCT_CHECK_PREFIX,
917                                     RoseInstrCheckPrefix> {
918 public:
919     u32 queue;
920     u32 lag;
921     ReportID report;
922     const RoseInstruction *target;
923 
RoseInstrCheckPrefix(u32 queue_in,u32 lag_in,ReportID report_in,const RoseInstruction * target_in)924     RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in,
925                          const RoseInstruction *target_in)
926         : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {}
927 
928     bool operator==(const RoseInstrCheckPrefix &ri) const {
929         return queue == ri.queue && lag == ri.lag && report == ri.report &&
930                target == ri.target;
931     }
932 
hash()933     size_t hash() const override {
934         return hash_all(opcode, queue, lag, report);
935     }
936 
937     void write(void *dest, RoseEngineBlob &blob,
938                const OffsetMap &offset_map) const override;
939 
equiv_to(const RoseInstrCheckPrefix & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)940     bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets,
941                   const OffsetMap &other_offsets) const {
942         return queue == ri.queue && lag == ri.lag && report == ri.report &&
943                offsets.at(target) == other_offsets.at(ri.target);
944     }
945 };
946 
947 class RoseInstrPushDelayed
948     : public RoseInstrBaseNoTargets<ROSE_INSTR_PUSH_DELAYED,
949                                     ROSE_STRUCT_PUSH_DELAYED,
950                                     RoseInstrPushDelayed> {
951 public:
952     u8 delay;
953     u32 index;
954 
RoseInstrPushDelayed(u8 delay_in,u32 index_in)955     RoseInstrPushDelayed(u8 delay_in, u32 index_in)
956         : delay(delay_in), index(index_in) {}
957 
958     bool operator==(const RoseInstrPushDelayed &ri) const {
959         return delay == ri.delay && index == ri.index;
960     }
961 
hash()962     size_t hash() const override {
963         return hash_all(opcode, delay, index);
964     }
965 
966     void write(void *dest, RoseEngineBlob &blob,
967                const OffsetMap &offset_map) const override;
968 
equiv_to(const RoseInstrPushDelayed & ri,const OffsetMap &,const OffsetMap &)969     bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &,
970                   const OffsetMap &) const {
971         return delay == ri.delay && index == ri.index;
972     }
973 };
974 
975 class RoseInstrCatchUp
976     : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP, ROSE_STRUCT_CATCH_UP,
977                                   RoseInstrCatchUp> {
978 public:
979     ~RoseInstrCatchUp() override;
980 };
981 
982 class RoseInstrCatchUpMpv
983     : public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP_MPV,
984                                   ROSE_STRUCT_CATCH_UP_MPV,
985                                   RoseInstrCatchUpMpv> {
986 public:
987     ~RoseInstrCatchUpMpv() override;
988 };
989 
990 class RoseInstrSomAdjust
991     : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_ADJUST,
992                                     ROSE_STRUCT_SOM_ADJUST,
993                                     RoseInstrSomAdjust> {
994 public:
995     u32 distance;
996 
RoseInstrSomAdjust(u32 distance_in)997     explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {}
998 
999     bool operator==(const RoseInstrSomAdjust &ri) const {
1000         return distance == ri.distance;
1001     }
1002 
hash()1003     size_t hash() const override {
1004         return hash_all(opcode, distance);
1005     }
1006 
1007     void write(void *dest, RoseEngineBlob &blob,
1008                const OffsetMap &offset_map) const override;
1009 
equiv_to(const RoseInstrSomAdjust & ri,const OffsetMap &,const OffsetMap &)1010     bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &,
1011                   const OffsetMap &) const {
1012         return distance == ri.distance;
1013     }
1014 };
1015 
1016 class RoseInstrSomLeftfix
1017     : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_LEFTFIX,
1018                                     ROSE_STRUCT_SOM_LEFTFIX,
1019                                     RoseInstrSomLeftfix> {
1020 public:
1021     u32 queue;
1022     u32 lag;
1023 
RoseInstrSomLeftfix(u32 queue_in,u32 lag_in)1024     RoseInstrSomLeftfix(u32 queue_in, u32 lag_in)
1025         : queue(queue_in), lag(lag_in) {}
1026 
1027     bool operator==(const RoseInstrSomLeftfix &ri) const {
1028         return queue == ri.queue && lag == ri.lag;
1029     }
1030 
hash()1031     size_t hash() const override {
1032         return hash_all(opcode, queue, lag);
1033     }
1034 
1035     void write(void *dest, RoseEngineBlob &blob,
1036                const OffsetMap &offset_map) const override;
1037 
equiv_to(const RoseInstrSomLeftfix & ri,const OffsetMap &,const OffsetMap &)1038     bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &,
1039                   const OffsetMap &) const {
1040         return queue == ri.queue && lag == ri.lag;
1041     }
1042 };
1043 
1044 class RoseInstrSomFromReport
1045     : public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_FROM_REPORT,
1046                                     ROSE_STRUCT_SOM_FROM_REPORT,
1047                                     RoseInstrSomFromReport> {
1048 public:
1049     som_operation som;
1050 
RoseInstrSomFromReport()1051     RoseInstrSomFromReport() {
1052         std::memset(&som, 0, sizeof(som));
1053     }
1054 
1055     bool operator==(const RoseInstrSomFromReport &ri) const {
1056         return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1057     }
1058 
hash()1059     size_t hash() const override {
1060         return hash_all(opcode, som.type, som.onmatch);
1061     }
1062 
1063     void write(void *dest, RoseEngineBlob &blob,
1064                const OffsetMap &offset_map) const override;
1065 
equiv_to(const RoseInstrSomFromReport & ri,const OffsetMap &,const OffsetMap &)1066     bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &,
1067                   const OffsetMap &) const {
1068         return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1069     }
1070 };
1071 
1072 class RoseInstrSomZero
1073     : public RoseInstrBaseTrivial<ROSE_INSTR_SOM_ZERO, ROSE_STRUCT_SOM_ZERO,
1074                                   RoseInstrSomZero> {
1075 public:
1076     ~RoseInstrSomZero() override;
1077 };
1078 
1079 class RoseInstrTriggerInfix
1080     : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_INFIX,
1081                                     ROSE_STRUCT_TRIGGER_INFIX,
1082                                     RoseInstrTriggerInfix> {
1083 public:
1084     u8 cancel;
1085     u32 queue;
1086     u32 event;
1087 
RoseInstrTriggerInfix(u8 cancel_in,u32 queue_in,u32 event_in)1088     RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in)
1089         : cancel(cancel_in), queue(queue_in), event(event_in) {}
1090 
1091     bool operator==(const RoseInstrTriggerInfix &ri) const {
1092         return cancel == ri.cancel && queue == ri.queue && event == ri.event;
1093     }
1094 
hash()1095     size_t hash() const override {
1096         return hash_all(opcode, cancel, queue, event);
1097     }
1098 
1099     void write(void *dest, RoseEngineBlob &blob,
1100                const OffsetMap &offset_map) const override;
1101 
equiv_to(const RoseInstrTriggerInfix & ri,const OffsetMap &,const OffsetMap &)1102     bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &,
1103                   const OffsetMap &) const {
1104         return cancel == ri.cancel && queue == ri.queue && event == ri.event;
1105     }
1106 };
1107 
1108 class RoseInstrTriggerSuffix
1109     : public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_SUFFIX,
1110                                     ROSE_STRUCT_TRIGGER_SUFFIX,
1111                                     RoseInstrTriggerSuffix> {
1112 public:
1113     u32 queue;
1114     u32 event;
1115 
RoseInstrTriggerSuffix(u32 queue_in,u32 event_in)1116     RoseInstrTriggerSuffix(u32 queue_in, u32 event_in)
1117         : queue(queue_in), event(event_in) {}
1118 
1119     bool operator==(const RoseInstrTriggerSuffix &ri) const {
1120         return queue == ri.queue && event == ri.event;
1121     }
1122 
hash()1123     size_t hash() const override {
1124         return hash_all(opcode, queue, event);
1125     }
1126 
1127     void write(void *dest, RoseEngineBlob &blob,
1128                const OffsetMap &offset_map) const override;
1129 
equiv_to(const RoseInstrTriggerSuffix & ri,const OffsetMap &,const OffsetMap &)1130     bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &,
1131                   const OffsetMap &) const {
1132         return queue == ri.queue && event == ri.event;
1133     }
1134 };
1135 
1136 class RoseInstrDedupe
1137     : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE, ROSE_STRUCT_DEDUPE,
1138                                     RoseInstrDedupe> {
1139 public:
1140     u8 quash_som;
1141     u32 dkey;
1142     s32 offset_adjust;
1143     const RoseInstruction *target;
1144 
RoseInstrDedupe(u8 quash_som_in,u32 dkey_in,s32 offset_adjust_in,const RoseInstruction * target_in)1145     RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
1146                     const RoseInstruction *target_in)
1147         : quash_som(quash_som_in), dkey(dkey_in),
1148           offset_adjust(offset_adjust_in), target(target_in) {}
1149 
1150     bool operator==(const RoseInstrDedupe &ri) const {
1151         return quash_som == ri.quash_som && dkey == ri.dkey &&
1152                offset_adjust == ri.offset_adjust && target == ri.target;
1153     }
1154 
hash()1155     size_t hash() const override {
1156         return hash_all(opcode, quash_som, dkey, offset_adjust);
1157     }
1158 
1159     void write(void *dest, RoseEngineBlob &blob,
1160                const OffsetMap &offset_map) const override;
1161 
equiv_to(const RoseInstrDedupe & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1162     bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets,
1163                   const OffsetMap &other_offsets) const {
1164         return quash_som == ri.quash_som && dkey == ri.dkey &&
1165                offset_adjust == ri.offset_adjust &&
1166                offsets.at(target) == other_offsets.at(ri.target);
1167     }
1168 };
1169 
1170 class RoseInstrDedupeSom
1171     : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_SOM,
1172                                     ROSE_STRUCT_DEDUPE_SOM,
1173                                     RoseInstrDedupeSom> {
1174 public:
1175     u8 quash_som;
1176     u32 dkey;
1177     s32 offset_adjust;
1178     const RoseInstruction *target;
1179 
RoseInstrDedupeSom(u8 quash_som_in,u32 dkey_in,s32 offset_adjust_in,const RoseInstruction * target_in)1180     RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in,
1181                        const RoseInstruction *target_in)
1182         : quash_som(quash_som_in), dkey(dkey_in),
1183           offset_adjust(offset_adjust_in), target(target_in) {}
1184 
1185     bool operator==(const RoseInstrDedupeSom &ri) const {
1186         return quash_som == ri.quash_som && dkey == ri.dkey &&
1187                offset_adjust == ri.offset_adjust && target == ri.target;
1188     }
1189 
hash()1190     size_t hash() const override {
1191         return hash_all(opcode, quash_som, dkey, offset_adjust);
1192     }
1193 
1194     void write(void *dest, RoseEngineBlob &blob,
1195                const OffsetMap &offset_map) const override;
1196 
equiv_to(const RoseInstrDedupeSom & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1197     bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets,
1198                   const OffsetMap &other_offsets) const {
1199         return quash_som == ri.quash_som && dkey == ri.dkey &&
1200                offset_adjust == ri.offset_adjust &&
1201                offsets.at(target) == other_offsets.at(ri.target);
1202     }
1203 };
1204 
1205 class RoseInstrReportChain
1206     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_CHAIN,
1207                                     ROSE_STRUCT_REPORT_CHAIN,
1208                                     RoseInstrReportChain> {
1209 public:
1210     u32 event;
1211     u64a top_squash_distance;
1212 
RoseInstrReportChain(u32 event_in,u32 top_squash_distance_in)1213     RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in)
1214         : event(event_in), top_squash_distance(top_squash_distance_in) {}
1215 
1216     bool operator==(const RoseInstrReportChain &ri) const {
1217         return event == ri.event &&
1218                top_squash_distance == ri.top_squash_distance;
1219     }
1220 
hash()1221     size_t hash() const override {
1222         return hash_all(opcode, event, top_squash_distance);
1223     }
1224 
1225     void write(void *dest, RoseEngineBlob &blob,
1226                const OffsetMap &offset_map) const override;
1227 
equiv_to(const RoseInstrReportChain & ri,const OffsetMap &,const OffsetMap &)1228     bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &,
1229                   const OffsetMap &) const {
1230         return event == ri.event &&
1231                top_squash_distance == ri.top_squash_distance;
1232     }
1233 };
1234 
1235 class RoseInstrReportSomInt
1236     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_INT,
1237                                     ROSE_STRUCT_REPORT_SOM_INT,
1238                                     RoseInstrReportSomInt> {
1239 public:
1240     som_operation som;
1241 
RoseInstrReportSomInt()1242     RoseInstrReportSomInt() {
1243         std::memset(&som, 0, sizeof(som));
1244     }
1245 
1246     bool operator==(const RoseInstrReportSomInt &ri) const {
1247         return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1248     }
1249 
hash()1250     size_t hash() const override {
1251         return hash_all(opcode, som.type, som.onmatch);
1252     }
1253 
1254     void write(void *dest, RoseEngineBlob &blob,
1255                const OffsetMap &offset_map) const override;
1256 
equiv_to(const RoseInstrReportSomInt & ri,const OffsetMap &,const OffsetMap &)1257     bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &,
1258                   const OffsetMap &) const {
1259         return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1260     }
1261 };
1262 
1263 class RoseInstrReportSomAware
1264     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_AWARE,
1265                                     ROSE_STRUCT_REPORT_SOM_AWARE,
1266                                     RoseInstrReportSomAware> {
1267 public:
1268     som_operation som;
1269 
RoseInstrReportSomAware()1270     RoseInstrReportSomAware() {
1271         std::memset(&som, 0, sizeof(som));
1272     }
1273 
1274     bool operator==(const RoseInstrReportSomAware &ri) const {
1275         return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1276     }
1277 
hash()1278     size_t hash() const override {
1279         return hash_all(opcode, som.type, som.onmatch);
1280     }
1281 
1282     void write(void *dest, RoseEngineBlob &blob,
1283                const OffsetMap &offset_map) const override;
1284 
equiv_to(const RoseInstrReportSomAware & ri,const OffsetMap &,const OffsetMap &)1285     bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &,
1286                   const OffsetMap &) const {
1287         return std::memcmp(&som, &ri.som, sizeof(som)) == 0;
1288     }
1289 };
1290 
1291 class RoseInstrReport
1292     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT, ROSE_STRUCT_REPORT,
1293                                     RoseInstrReport> {
1294 public:
1295     ReportID onmatch;
1296     s32 offset_adjust;
1297 
RoseInstrReport(ReportID onmatch_in,s32 offset_adjust_in)1298     RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in)
1299         : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
1300 
1301     bool operator==(const RoseInstrReport &ri) const {
1302         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1303     }
1304 
hash()1305     size_t hash() const override {
1306         return hash_all(opcode, onmatch, offset_adjust);
1307     }
1308 
1309     void write(void *dest, RoseEngineBlob &blob,
1310                const OffsetMap &offset_map) const override;
1311 
equiv_to(const RoseInstrReport & ri,const OffsetMap &,const OffsetMap &)1312     bool equiv_to(const RoseInstrReport &ri, const OffsetMap &,
1313                   const OffsetMap &) const {
1314         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1315     }
1316 };
1317 
1318 class RoseInstrReportExhaust
1319     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_EXHAUST,
1320                                     ROSE_STRUCT_REPORT_EXHAUST,
1321                                     RoseInstrReportExhaust> {
1322 public:
1323     ReportID onmatch;
1324     s32 offset_adjust;
1325     u32 ekey;
1326 
RoseInstrReportExhaust(ReportID onmatch_in,s32 offset_adjust_in,u32 ekey_in)1327     RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in,
1328                            u32 ekey_in)
1329         : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
1330 
1331     bool operator==(const RoseInstrReportExhaust &ri) const {
1332         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1333                ekey == ri.ekey;
1334     }
1335 
hash()1336     size_t hash() const override {
1337         return hash_all(opcode, onmatch, offset_adjust, ekey);
1338     }
1339 
1340     void write(void *dest, RoseEngineBlob &blob,
1341                const OffsetMap &offset_map) const override;
1342 
equiv_to(const RoseInstrReportExhaust & ri,const OffsetMap &,const OffsetMap &)1343     bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &,
1344                   const OffsetMap &) const {
1345         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1346                ekey == ri.ekey;
1347     }
1348 };
1349 
1350 class RoseInstrReportSom
1351     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM,
1352                                     ROSE_STRUCT_REPORT_SOM,
1353                                     RoseInstrReportSom> {
1354 public:
1355     ReportID onmatch;
1356     s32 offset_adjust;
1357 
RoseInstrReportSom(ReportID onmatch_in,s32 offset_adjust_in)1358     RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in)
1359         : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
1360 
1361     bool operator==(const RoseInstrReportSom &ri) const {
1362         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1363     }
1364 
hash()1365     size_t hash() const override {
1366         return hash_all(opcode, onmatch, offset_adjust);
1367     }
1368 
1369     void write(void *dest, RoseEngineBlob &blob,
1370                const OffsetMap &offset_map) const override;
1371 
equiv_to(const RoseInstrReportSom & ri,const OffsetMap &,const OffsetMap &)1372     bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &,
1373                   const OffsetMap &) const {
1374         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1375     }
1376 };
1377 
1378 class RoseInstrReportSomExhaust
1379     : public RoseInstrBaseNoTargets<ROSE_INSTR_REPORT_SOM_EXHAUST,
1380                                     ROSE_STRUCT_REPORT_SOM_EXHAUST,
1381                                     RoseInstrReportSomExhaust> {
1382 public:
1383     ReportID onmatch;
1384     s32 offset_adjust;
1385     u32 ekey;
1386 
RoseInstrReportSomExhaust(ReportID onmatch_in,s32 offset_adjust_in,u32 ekey_in)1387     RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in,
1388                               u32 ekey_in)
1389         : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {}
1390 
1391     bool operator==(const RoseInstrReportSomExhaust &ri) const {
1392         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1393                ekey == ri.ekey;
1394     }
1395 
hash()1396     size_t hash() const override {
1397         return hash_all(opcode, onmatch, offset_adjust, ekey);
1398     }
1399 
1400     void write(void *dest, RoseEngineBlob &blob,
1401                const OffsetMap &offset_map) const override;
1402 
equiv_to(const RoseInstrReportSomExhaust & ri,const OffsetMap &,const OffsetMap &)1403     bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &,
1404                   const OffsetMap &) const {
1405         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1406                ekey == ri.ekey;
1407     }
1408 };
1409 
1410 class RoseInstrDedupeAndReport
1411     : public RoseInstrBaseOneTarget<ROSE_INSTR_DEDUPE_AND_REPORT,
1412                                     ROSE_STRUCT_DEDUPE_AND_REPORT,
1413                                     RoseInstrDedupeAndReport> {
1414 public:
1415     u8 quash_som;
1416     u32 dkey;
1417     ReportID onmatch;
1418     s32 offset_adjust;
1419     const RoseInstruction *target;
1420 
RoseInstrDedupeAndReport(u8 quash_som_in,u32 dkey_in,ReportID onmatch_in,s32 offset_adjust_in,const RoseInstruction * target_in)1421     RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in,
1422                              s32 offset_adjust_in,
1423                              const RoseInstruction *target_in)
1424         : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in),
1425           offset_adjust(offset_adjust_in), target(target_in) {}
1426 
1427     bool operator==(const RoseInstrDedupeAndReport &ri) const {
1428         return quash_som == ri.quash_som && dkey == ri.dkey &&
1429                onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1430                target == ri.target;
1431     }
1432 
hash()1433     size_t hash() const override {
1434         return hash_all(opcode, quash_som, dkey, onmatch, offset_adjust);
1435     }
1436 
1437     void write(void *dest, RoseEngineBlob &blob,
1438                const OffsetMap &offset_map) const override;
1439 
equiv_to(const RoseInstrDedupeAndReport & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1440     bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets,
1441                   const OffsetMap &other_offsets) const {
1442         return quash_som == ri.quash_som && dkey == ri.dkey &&
1443                onmatch == ri.onmatch && offset_adjust == ri.offset_adjust &&
1444                offsets.at(target) == other_offsets.at(ri.target);
1445     }
1446 };
1447 
1448 class RoseInstrFinalReport
1449     : public RoseInstrBaseNoTargets<ROSE_INSTR_FINAL_REPORT,
1450                                     ROSE_STRUCT_FINAL_REPORT,
1451                                     RoseInstrFinalReport> {
1452 public:
1453     ReportID onmatch;
1454     s32 offset_adjust;
1455 
RoseInstrFinalReport(ReportID onmatch_in,s32 offset_adjust_in)1456     RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in)
1457         : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {}
1458 
1459     bool operator==(const RoseInstrFinalReport &ri) const {
1460         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1461     }
1462 
hash()1463     size_t hash() const override {
1464         return hash_all(opcode, onmatch, offset_adjust);
1465     }
1466 
1467     void write(void *dest, RoseEngineBlob &blob,
1468                const OffsetMap &offset_map) const override;
1469 
equiv_to(const RoseInstrFinalReport & ri,const OffsetMap &,const OffsetMap &)1470     bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &,
1471                   const OffsetMap &) const {
1472         return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust;
1473     }
1474 };
1475 
1476 class RoseInstrCheckExhausted
1477     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_EXHAUSTED,
1478                                     ROSE_STRUCT_CHECK_EXHAUSTED,
1479                                     RoseInstrCheckExhausted> {
1480 public:
1481     u32 ekey;
1482     const RoseInstruction *target;
1483 
RoseInstrCheckExhausted(u32 ekey_in,const RoseInstruction * target_in)1484     RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in)
1485         : ekey(ekey_in), target(target_in) {}
1486 
1487     bool operator==(const RoseInstrCheckExhausted &ri) const {
1488         return ekey == ri.ekey && target == ri.target;
1489     }
1490 
hash()1491     size_t hash() const override {
1492         return hash_all(opcode, ekey);
1493     }
1494 
1495     void write(void *dest, RoseEngineBlob &blob,
1496                const OffsetMap &offset_map) const override;
1497 
equiv_to(const RoseInstrCheckExhausted & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1498     bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets,
1499                   const OffsetMap &other_offsets) const {
1500         return ekey == ri.ekey &&
1501                offsets.at(target) == other_offsets.at(ri.target);
1502     }
1503 };
1504 
1505 class RoseInstrCheckMinLength
1506     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MIN_LENGTH,
1507                                     ROSE_STRUCT_CHECK_MIN_LENGTH,
1508                                     RoseInstrCheckMinLength> {
1509 public:
1510     s32 end_adj;
1511     u64a min_length;
1512     const RoseInstruction *target;
1513 
RoseInstrCheckMinLength(s32 end_adj_in,u64a min_length_in,const RoseInstruction * target_in)1514     RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in,
1515                             const RoseInstruction *target_in)
1516         : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {}
1517 
1518     bool operator==(const RoseInstrCheckMinLength &ri) const {
1519         return end_adj == ri.end_adj && min_length == ri.min_length &&
1520                target == ri.target;
1521     }
1522 
hash()1523     size_t hash() const override {
1524         return hash_all(opcode, end_adj, min_length);
1525     }
1526 
1527     void write(void *dest, RoseEngineBlob &blob,
1528                const OffsetMap &offset_map) const override;
1529 
equiv_to(const RoseInstrCheckMinLength & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1530     bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets,
1531                   const OffsetMap &other_offsets) const {
1532         return end_adj == ri.end_adj && min_length == ri.min_length &&
1533                offsets.at(target) == other_offsets.at(ri.target);
1534     }
1535 };
1536 
1537 class RoseInstrSetState
1538     : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_STATE, ROSE_STRUCT_SET_STATE,
1539                                     RoseInstrSetState> {
1540 public:
1541     u32 index;
1542 
RoseInstrSetState(u32 index_in)1543     explicit RoseInstrSetState(u32 index_in) : index(index_in) {}
1544 
1545     bool operator==(const RoseInstrSetState &ri) const {
1546         return index == ri.index;
1547     }
1548 
hash()1549     size_t hash() const override {
1550         return hash_all(opcode, index);
1551     }
1552 
1553     void write(void *dest, RoseEngineBlob &blob,
1554                const OffsetMap &offset_map) const override;
1555 
equiv_to(const RoseInstrSetState & ri,const OffsetMap &,const OffsetMap &)1556     bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &,
1557                   const OffsetMap &) const {
1558         return index == ri.index;
1559     }
1560 };
1561 
1562 class RoseInstrSetGroups
1563     : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_GROUPS,
1564                                     ROSE_STRUCT_SET_GROUPS,
1565                                     RoseInstrSetGroups> {
1566 public:
1567     rose_group groups;
1568 
RoseInstrSetGroups(rose_group groups_in)1569     explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {}
1570 
1571     bool operator==(const RoseInstrSetGroups &ri) const {
1572         return groups == ri.groups;
1573     }
1574 
hash()1575     size_t hash() const override {
1576         return hash_all(opcode, groups);
1577     }
1578 
1579     void write(void *dest, RoseEngineBlob &blob,
1580                const OffsetMap &offset_map) const override;
1581 
equiv_to(const RoseInstrSetGroups & ri,const OffsetMap &,const OffsetMap &)1582     bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &,
1583                   const OffsetMap &) const {
1584         return groups == ri.groups;
1585     }
1586 };
1587 
1588 class RoseInstrSquashGroups
1589     : public RoseInstrBaseNoTargets<ROSE_INSTR_SQUASH_GROUPS,
1590                                     ROSE_STRUCT_SQUASH_GROUPS,
1591                                     RoseInstrSquashGroups> {
1592 public:
1593     rose_group groups;
1594 
RoseInstrSquashGroups(rose_group groups_in)1595     explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {}
1596 
1597     bool operator==(const RoseInstrSquashGroups &ri) const {
1598         return groups == ri.groups;
1599     }
1600 
hash()1601     size_t hash() const override {
1602         return hash_all(opcode, groups);
1603     }
1604 
1605     void write(void *dest, RoseEngineBlob &blob,
1606                const OffsetMap &offset_map) const override;
1607 
equiv_to(const RoseInstrSquashGroups & ri,const OffsetMap &,const OffsetMap &)1608     bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &,
1609                   const OffsetMap &) const {
1610         return groups == ri.groups;
1611     }
1612 };
1613 
1614 class RoseInstrCheckState
1615     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_STATE,
1616                                     ROSE_STRUCT_CHECK_STATE,
1617                                     RoseInstrCheckState> {
1618 public:
1619     u32 index;
1620     const RoseInstruction *target;
1621 
RoseInstrCheckState(u32 index_in,const RoseInstruction * target_in)1622     RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in)
1623         : index(index_in), target(target_in) {}
1624 
1625     bool operator==(const RoseInstrCheckState &ri) const {
1626         return index == ri.index && target == ri.target;
1627     }
1628 
hash()1629     size_t hash() const override {
1630         return hash_all(opcode, index);
1631     }
1632 
1633     void write(void *dest, RoseEngineBlob &blob,
1634                const OffsetMap &offset_map) const override;
1635 
equiv_to(const RoseInstrCheckState & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1636     bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets,
1637                   const OffsetMap &other_offsets) const {
1638         return index == ri.index &&
1639                offsets.at(target) == other_offsets.at(ri.target);
1640     }
1641 };
1642 
1643 class RoseInstrSparseIterBegin
1644     : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_BEGIN,
1645                            ROSE_STRUCT_SPARSE_ITER_BEGIN,
1646                            RoseInstrSparseIterBegin> {
1647 public:
1648     u32 num_keys; // total number of multibit keys
1649     std::vector<std::pair<u32, const RoseInstruction *>> jump_table;
1650     const RoseInstruction *target;
1651 
RoseInstrSparseIterBegin(u32 num_keys_in,const RoseInstruction * target_in)1652     RoseInstrSparseIterBegin(u32 num_keys_in,
1653                              const RoseInstruction *target_in)
1654         : num_keys(num_keys_in), target(target_in) {}
1655 
1656     bool operator==(const RoseInstrSparseIterBegin &ri) const {
1657         return num_keys == ri.num_keys && jump_table == ri.jump_table &&
1658                target == ri.target;
1659     }
1660 
hash()1661     size_t hash() const override {
1662         size_t v = hash_all(opcode, num_keys);
1663         for (const u32 &key : jump_table | boost::adaptors::map_keys) {
1664             hash_combine(v, key);
1665         }
1666         return v;
1667     }
1668 
1669     void write(void *dest, RoseEngineBlob &blob,
1670                const OffsetMap &offset_map) const override;
1671 
update_target(const RoseInstruction * old_target,const RoseInstruction * new_target)1672     void update_target(const RoseInstruction *old_target,
1673                        const RoseInstruction *new_target) override {
1674         if (target == old_target) {
1675             target = new_target;
1676         }
1677         for (auto &jump : jump_table) {
1678             if (jump.second == old_target) {
1679                 jump.second = new_target;
1680             }
1681         }
1682     }
1683 
equiv_to(const RoseInstrSparseIterBegin & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1684     bool equiv_to(const RoseInstrSparseIterBegin &ri, const OffsetMap &offsets,
1685                   const OffsetMap &other_offsets) const {
1686         if (iter_offset != ri.iter_offset ||
1687             offsets.at(target) != other_offsets.at(ri.target)) {
1688             return false;
1689         }
1690         if (jump_table.size() != ri.jump_table.size()) {
1691             return false;
1692         }
1693         auto it1 = jump_table.begin(), it2 = ri.jump_table.begin();
1694         for (; it1 != jump_table.end(); ++it1, ++it2) {
1695             if (it1->first != it2->first) {
1696                 return false;
1697             }
1698             if (offsets.at(it1->second) != other_offsets.at(it2->second)) {
1699                 return false;
1700             }
1701         }
1702         return true;
1703     }
1704 
1705 private:
1706     friend class RoseInstrSparseIterNext;
1707 
1708     // These variables allow us to use the same multibit iterator and jump
1709     // table in subsequent SPARSE_ITER_NEXT write() operations.
1710     mutable bool is_written = false;
1711     mutable u32 iter_offset = 0;
1712     mutable u32 jump_table_offset = 0;
1713 };
1714 
1715 class RoseInstrSparseIterNext
1716     : public RoseInstrBase<ROSE_INSTR_SPARSE_ITER_NEXT,
1717                            ROSE_STRUCT_SPARSE_ITER_NEXT,
1718                            RoseInstrSparseIterNext> {
1719 public:
1720     u32 state;
1721     const RoseInstrSparseIterBegin *begin;
1722     const RoseInstruction *target;
1723 
RoseInstrSparseIterNext(u32 state_in,const RoseInstrSparseIterBegin * begin_in,const RoseInstruction * target_in)1724     RoseInstrSparseIterNext(u32 state_in,
1725                             const RoseInstrSparseIterBegin *begin_in,
1726                             const RoseInstruction *target_in)
1727         : state(state_in), begin(begin_in), target(target_in) {}
1728 
1729     bool operator==(const RoseInstrSparseIterNext &ri) const {
1730         return state == ri.state && begin == ri.begin && target == ri.target;
1731     }
1732 
hash()1733     size_t hash() const override {
1734         return hash_all(opcode, state);
1735     }
1736 
1737     void write(void *dest, RoseEngineBlob &blob,
1738                const OffsetMap &offset_map) const override;
1739 
update_target(const RoseInstruction * old_target,const RoseInstruction * new_target)1740     void update_target(const RoseInstruction *old_target,
1741                        const RoseInstruction *new_target) override {
1742         if (target == old_target) {
1743             target = new_target;
1744         }
1745         if (begin == old_target) {
1746             assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN);
1747             begin = static_cast<const RoseInstrSparseIterBegin *>(new_target);
1748         }
1749     }
1750 
equiv_to(const RoseInstrSparseIterNext & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1751     bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets,
1752                   const OffsetMap &other_offsets) const {
1753         return state == ri.state &&
1754                offsets.at(begin) == other_offsets.at(ri.begin) &&
1755                offsets.at(target) == other_offsets.at(ri.target);
1756     }
1757 };
1758 
1759 class RoseInstrSparseIterAny
1760     : public RoseInstrBaseOneTarget<ROSE_INSTR_SPARSE_ITER_ANY,
1761                                     ROSE_STRUCT_SPARSE_ITER_ANY,
1762                                     RoseInstrSparseIterAny> {
1763 public:
1764     u32 num_keys; // total number of multibit keys
1765     std::vector<u32> keys;
1766     const RoseInstruction *target;
1767 
RoseInstrSparseIterAny(u32 num_keys_in,std::vector<u32> keys_in,const RoseInstruction * target_in)1768     RoseInstrSparseIterAny(u32 num_keys_in, std::vector<u32> keys_in,
1769                            const RoseInstruction *target_in)
1770         : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {}
1771 
1772     bool operator==(const RoseInstrSparseIterAny &ri) const {
1773         return num_keys == ri.num_keys && keys == ri.keys &&
1774                target == ri.target;
1775     }
1776 
hash()1777     size_t hash() const override {
1778         return hash_all(opcode, num_keys, keys);
1779     }
1780 
1781     void write(void *dest, RoseEngineBlob &blob,
1782                const OffsetMap &offset_map) const override;
1783 
equiv_to(const RoseInstrSparseIterAny & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1784     bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets,
1785                   const OffsetMap &other_offsets) const {
1786         return num_keys == ri.num_keys && keys == ri.keys &&
1787                offsets.at(target) == other_offsets.at(ri.target);
1788     }
1789 };
1790 
1791 class RoseInstrEnginesEod
1792     : public RoseInstrBaseNoTargets<ROSE_INSTR_ENGINES_EOD,
1793                                     ROSE_STRUCT_ENGINES_EOD,
1794                                     RoseInstrEnginesEod> {
1795 public:
1796     u32 iter_offset;
1797 
RoseInstrEnginesEod(u32 iter_in)1798     explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {}
1799 
1800     bool operator==(const RoseInstrEnginesEod &ri) const {
1801         return iter_offset == ri.iter_offset;
1802     }
1803 
hash()1804     size_t hash() const override {
1805         return hash_all(opcode, iter_offset);
1806     }
1807 
1808     void write(void *dest, RoseEngineBlob &blob,
1809                const OffsetMap &offset_map) const override;
1810 
equiv_to(const RoseInstrEnginesEod & ri,const OffsetMap &,const OffsetMap &)1811     bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &,
1812                   const OffsetMap &) const {
1813         return iter_offset == ri.iter_offset;
1814     }
1815 };
1816 
1817 class RoseInstrSuffixesEod
1818     : public RoseInstrBaseTrivial<ROSE_INSTR_SUFFIXES_EOD,
1819                                   ROSE_STRUCT_SUFFIXES_EOD,
1820                                   RoseInstrSuffixesEod> {
1821 public:
1822     ~RoseInstrSuffixesEod() override;
1823 };
1824 
1825 class RoseInstrMatcherEod : public RoseInstrBaseTrivial<ROSE_INSTR_MATCHER_EOD,
1826                                                         ROSE_STRUCT_MATCHER_EOD,
1827                                                         RoseInstrMatcherEod> {
1828 public:
1829     ~RoseInstrMatcherEod() override;
1830 };
1831 
1832 class RoseInstrCheckLongLit
1833     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT,
1834                                     ROSE_STRUCT_CHECK_LONG_LIT,
1835                                     RoseInstrCheckLongLit> {
1836 public:
1837     std::string literal;
1838     const RoseInstruction *target;
1839 
RoseInstrCheckLongLit(std::string literal_in,const RoseInstruction * target_in)1840     RoseInstrCheckLongLit(std::string literal_in,
1841                           const RoseInstruction *target_in)
1842         : literal(std::move(literal_in)), target(target_in) {}
1843 
1844     bool operator==(const RoseInstrCheckLongLit &ri) const {
1845         return literal == ri.literal && target == ri.target;
1846     }
1847 
hash()1848     size_t hash() const override {
1849         return hash_all(opcode, literal);
1850     }
1851 
1852     void write(void *dest, RoseEngineBlob &blob,
1853                const OffsetMap &offset_map) const override;
1854 
equiv_to(const RoseInstrCheckLongLit & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1855     bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets,
1856                   const OffsetMap &other_offsets) const {
1857         return literal == ri.literal &&
1858                offsets.at(target) == other_offsets.at(ri.target);
1859     }
1860 };
1861 
1862 class RoseInstrCheckLongLitNocase
1863     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
1864                                     ROSE_STRUCT_CHECK_LONG_LIT_NOCASE,
1865                                     RoseInstrCheckLongLitNocase> {
1866 public:
1867     std::string literal;
1868     const RoseInstruction *target;
1869 
RoseInstrCheckLongLitNocase(std::string literal_in,const RoseInstruction * target_in)1870     RoseInstrCheckLongLitNocase(std::string literal_in,
1871                                 const RoseInstruction *target_in)
1872         : literal(std::move(literal_in)), target(target_in) {
1873         upperString(literal);
1874     }
1875 
1876     bool operator==(const RoseInstrCheckLongLitNocase &ri) const {
1877         return literal == ri.literal && target == ri.target;
1878     }
1879 
hash()1880     size_t hash() const override {
1881         return hash_all(opcode, literal);
1882     }
1883 
1884     void write(void *dest, RoseEngineBlob &blob,
1885                const OffsetMap &offset_map) const override;
1886 
equiv_to(const RoseInstrCheckLongLitNocase & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1887     bool equiv_to(const RoseInstrCheckLongLitNocase &ri,
1888                   const OffsetMap &offsets,
1889                   const OffsetMap &other_offsets) const {
1890         return literal == ri.literal &&
1891                offsets.at(target) == other_offsets.at(ri.target);
1892     }
1893 };
1894 
1895 class RoseInstrCheckMedLit
1896     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT,
1897                                     ROSE_STRUCT_CHECK_MED_LIT,
1898                                     RoseInstrCheckMedLit> {
1899 public:
1900     std::string literal;
1901     const RoseInstruction *target;
1902 
RoseInstrCheckMedLit(std::string literal_in,const RoseInstruction * target_in)1903     explicit RoseInstrCheckMedLit(std::string literal_in,
1904                                   const RoseInstruction *target_in)
1905         : literal(std::move(literal_in)), target(target_in) {}
1906 
1907     bool operator==(const RoseInstrCheckMedLit &ri) const {
1908         return literal == ri.literal && target == ri.target;
1909     }
1910 
hash()1911     size_t hash() const override {
1912         return hash_all(opcode, literal);
1913     }
1914 
1915     void write(void *dest, RoseEngineBlob &blob,
1916                const OffsetMap &offset_map) const override;
1917 
equiv_to(const RoseInstrCheckMedLit & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1918     bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets,
1919                   const OffsetMap &other_offsets) const {
1920         return literal == ri.literal &&
1921                offsets.at(target) == other_offsets.at(ri.target);
1922     }
1923 };
1924 
1925 class RoseInstrCheckMedLitNocase
1926     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
1927                                     ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
1928                                     RoseInstrCheckMedLitNocase> {
1929 public:
1930     std::string literal;
1931     const RoseInstruction *target;
1932 
RoseInstrCheckMedLitNocase(std::string literal_in,const RoseInstruction * target_in)1933     explicit RoseInstrCheckMedLitNocase(std::string literal_in,
1934                                         const RoseInstruction *target_in)
1935         : literal(std::move(literal_in)), target(target_in) {
1936         upperString(literal);
1937     }
1938 
1939     bool operator==(const RoseInstrCheckMedLitNocase &ri) const {
1940         return literal == ri.literal && target == ri.target;
1941     }
1942 
hash()1943     size_t hash() const override {
1944         return hash_all(opcode, literal);
1945     }
1946 
1947     void write(void *dest, RoseEngineBlob &blob,
1948                const OffsetMap &offset_map) const override;
1949 
equiv_to(const RoseInstrCheckMedLitNocase & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1950     bool equiv_to(const RoseInstrCheckMedLitNocase &ri,
1951                   const OffsetMap &offsets,
1952                   const OffsetMap &other_offsets) const {
1953         return literal == ri.literal &&
1954                offsets.at(target) == other_offsets.at(ri.target);
1955     }
1956 };
1957 
1958 class RoseInstrClearWorkDone
1959     : public RoseInstrBaseTrivial<ROSE_INSTR_CLEAR_WORK_DONE,
1960                                   ROSE_STRUCT_CLEAR_WORK_DONE,
1961                                   RoseInstrClearWorkDone> {
1962 public:
1963     ~RoseInstrClearWorkDone() override;
1964 };
1965 
1966 class RoseInstrMultipathLookaround
1967     : public RoseInstrBaseOneTarget<ROSE_INSTR_MULTIPATH_LOOKAROUND,
1968                                     ROSE_STRUCT_MULTIPATH_LOOKAROUND,
1969                                     RoseInstrMultipathLookaround> {
1970 public:
1971     std::vector<std::vector<LookEntry>> multi_look;
1972     s32 last_start;
1973     std::array<u8, 16> start_mask;
1974     const RoseInstruction *target;
1975 
RoseInstrMultipathLookaround(std::vector<std::vector<LookEntry>> ml,s32 last_start_in,std::array<u8,16> start_mask_in,const RoseInstruction * target_in)1976     RoseInstrMultipathLookaround(std::vector<std::vector<LookEntry>> ml,
1977                                  s32 last_start_in,
1978                                  std::array<u8, 16> start_mask_in,
1979                                  const RoseInstruction *target_in)
1980         : multi_look(std::move(ml)), last_start(last_start_in),
1981           start_mask(std::move(start_mask_in)), target(target_in) {}
1982 
1983     bool operator==(const RoseInstrMultipathLookaround &ri) const {
1984         return multi_look == ri.multi_look && last_start == ri.last_start
1985         && start_mask == ri.start_mask && target == ri.target;
1986     }
1987 
hash()1988     size_t hash() const override {
1989         return hash_all(opcode, multi_look, last_start, start_mask);
1990     }
1991 
1992     void write(void *dest, RoseEngineBlob &blob,
1993                const OffsetMap &offset_map) const override;
1994 
equiv_to(const RoseInstrMultipathLookaround & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)1995     bool equiv_to(const RoseInstrMultipathLookaround &ri,
1996                   const OffsetMap &offsets,
1997                   const OffsetMap &other_offsets) const {
1998         return multi_look == ri.multi_look && last_start == ri.last_start
1999             && start_mask == ri.start_mask
2000             && offsets.at(target) == other_offsets.at(ri.target);
2001     }
2002 };
2003 
2004 class RoseInstrCheckMultipathShufti16x8
2005     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
2006                                     ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8,
2007                                     RoseInstrCheckMultipathShufti16x8> {
2008 public:
2009     std::array<u8, 32> nib_mask;
2010     std::array<u8, 64> bucket_select_mask;
2011     std::array<u8, 64> data_select_mask;
2012     u16 hi_bits_mask;
2013     u16 lo_bits_mask;
2014     u16 neg_mask;
2015     s32 base_offset;
2016     s32 last_start;
2017     const RoseInstruction *target;
2018 
RoseInstrCheckMultipathShufti16x8(std::array<u8,32> nib_mask_in,std::array<u8,64> bucket_select_mask_in,std::array<u8,64> data_select_mask_in,u16 hi_bits_mask_in,u16 lo_bits_mask_in,u16 neg_mask_in,s32 base_offset_in,s32 last_start_in,const RoseInstruction * target_in)2019     RoseInstrCheckMultipathShufti16x8(std::array<u8, 32> nib_mask_in,
2020                                       std::array<u8, 64> bucket_select_mask_in,
2021                                       std::array<u8, 64> data_select_mask_in,
2022                                       u16 hi_bits_mask_in, u16 lo_bits_mask_in,
2023                                       u16 neg_mask_in, s32 base_offset_in,
2024                                       s32 last_start_in,
2025                                       const RoseInstruction *target_in)
2026         : nib_mask(std::move(nib_mask_in)),
2027           bucket_select_mask(std::move(bucket_select_mask_in)),
2028           data_select_mask(std::move(data_select_mask_in)),
2029           hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
2030           neg_mask(neg_mask_in), base_offset(base_offset_in),
2031           last_start(last_start_in), target(target_in) {}
2032 
2033     bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const {
2034         return nib_mask == ri.nib_mask &&
2035                bucket_select_mask == ri.bucket_select_mask &&
2036                data_select_mask == ri.data_select_mask &&
2037                hi_bits_mask == ri.hi_bits_mask &&
2038                lo_bits_mask == ri.lo_bits_mask &&
2039                neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
2040                last_start == ri.last_start && target == ri.target;
2041     }
2042 
hash()2043     size_t hash() const override {
2044         return hash_all(opcode, nib_mask, bucket_select_mask, data_select_mask,
2045                         hi_bits_mask, lo_bits_mask, neg_mask, base_offset,
2046                         last_start);
2047     }
2048 
2049     void write(void *dest, RoseEngineBlob &blob,
2050                const OffsetMap &offset_map) const override;
2051 
equiv_to(const RoseInstrCheckMultipathShufti16x8 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)2052     bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri,
2053                   const OffsetMap &offsets,
2054                   const OffsetMap &other_offsets) const {
2055         return nib_mask == ri.nib_mask &&
2056                bucket_select_mask == ri.bucket_select_mask &&
2057                data_select_mask == ri.data_select_mask &&
2058                hi_bits_mask == ri.hi_bits_mask &&
2059                lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
2060                base_offset == ri.base_offset && last_start == ri.last_start &&
2061                offsets.at(target) == other_offsets.at(ri.target);
2062     }
2063 };
2064 
2065 class RoseInstrCheckMultipathShufti32x8
2066     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
2067                                     ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8,
2068                                     RoseInstrCheckMultipathShufti32x8> {
2069 public:
2070     std::array<u8, 32> hi_mask;
2071     std::array<u8, 32> lo_mask;
2072     std::array<u8, 64> bucket_select_mask;
2073     std::array<u8, 64> data_select_mask;
2074     u32 hi_bits_mask;
2075     u32 lo_bits_mask;
2076     u32 neg_mask;
2077     s32 base_offset;
2078     s32 last_start;
2079     const RoseInstruction *target;
2080 
RoseInstrCheckMultipathShufti32x8(std::array<u8,32> hi_mask_in,std::array<u8,32> lo_mask_in,std::array<u8,64> bucket_select_mask_in,std::array<u8,64> data_select_mask_in,u32 hi_bits_mask_in,u32 lo_bits_mask_in,u32 neg_mask_in,s32 base_offset_in,s32 last_start_in,const RoseInstruction * target_in)2081     RoseInstrCheckMultipathShufti32x8(std::array<u8, 32> hi_mask_in,
2082                                       std::array<u8, 32> lo_mask_in,
2083                                       std::array<u8, 64> bucket_select_mask_in,
2084                                       std::array<u8, 64> data_select_mask_in,
2085                                       u32 hi_bits_mask_in, u32 lo_bits_mask_in,
2086                                       u32 neg_mask_in, s32 base_offset_in,
2087                                       s32 last_start_in,
2088                                       const RoseInstruction *target_in)
2089         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
2090           bucket_select_mask(std::move(bucket_select_mask_in)),
2091           data_select_mask(std::move(data_select_mask_in)),
2092           hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
2093           neg_mask(neg_mask_in), base_offset(base_offset_in),
2094           last_start(last_start_in), target(target_in) {}
2095 
2096     bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const {
2097         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2098                bucket_select_mask == ri.bucket_select_mask &&
2099                data_select_mask == ri.data_select_mask &&
2100                hi_bits_mask == ri.hi_bits_mask &&
2101                lo_bits_mask == ri.lo_bits_mask &&
2102                neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
2103                last_start == ri.last_start && target == ri.target;
2104     }
2105 
hash()2106     size_t hash() const override {
2107         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
2108                         data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
2109                         base_offset, last_start);
2110     }
2111 
2112     void write(void *dest, RoseEngineBlob &blob,
2113                const OffsetMap &offset_map) const override;
2114 
equiv_to(const RoseInstrCheckMultipathShufti32x8 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)2115     bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri,
2116                   const OffsetMap &offsets,
2117                   const OffsetMap &other_offsets) const {
2118         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2119                bucket_select_mask == ri.bucket_select_mask &&
2120                data_select_mask == ri.data_select_mask &&
2121                hi_bits_mask == ri.hi_bits_mask &&
2122                lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
2123                base_offset == ri.base_offset && last_start == ri.last_start &&
2124                offsets.at(target) == other_offsets.at(ri.target);
2125     }
2126 };
2127 
2128 class RoseInstrCheckMultipathShufti32x16
2129     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
2130                                     ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16,
2131                                     RoseInstrCheckMultipathShufti32x16> {
2132 public:
2133     std::array<u8, 32> hi_mask;
2134     std::array<u8, 32> lo_mask;
2135     std::array<u8, 64> bucket_select_mask_hi;
2136     std::array<u8, 64> bucket_select_mask_lo;
2137     std::array<u8, 64> data_select_mask;
2138     u32 hi_bits_mask;
2139     u32 lo_bits_mask;
2140     u32 neg_mask;
2141     s32 base_offset;
2142     s32 last_start;
2143     const RoseInstruction *target;
2144 
RoseInstrCheckMultipathShufti32x16(std::array<u8,32> hi_mask_in,std::array<u8,32> lo_mask_in,std::array<u8,64> bucket_select_mask_hi_in,std::array<u8,64> bucket_select_mask_lo_in,std::array<u8,64> data_select_mask_in,u32 hi_bits_mask_in,u32 lo_bits_mask_in,u32 neg_mask_in,s32 base_offset_in,s32 last_start_in,const RoseInstruction * target_in)2145     RoseInstrCheckMultipathShufti32x16(std::array<u8, 32> hi_mask_in,
2146                                        std::array<u8, 32> lo_mask_in,
2147                                    std::array<u8, 64> bucket_select_mask_hi_in,
2148                                    std::array<u8, 64> bucket_select_mask_lo_in,
2149                                        std::array<u8, 64> data_select_mask_in,
2150                                        u32 hi_bits_mask_in, u32 lo_bits_mask_in,
2151                                        u32 neg_mask_in, s32 base_offset_in,
2152                                        s32 last_start_in,
2153                                        const RoseInstruction *target_in)
2154         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
2155           bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)),
2156           bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)),
2157           data_select_mask(std::move(data_select_mask_in)),
2158           hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
2159           neg_mask(neg_mask_in), base_offset(base_offset_in),
2160           last_start(last_start_in), target(target_in) {}
2161 
2162     bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const {
2163         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2164                bucket_select_mask_hi == ri.bucket_select_mask_hi &&
2165                bucket_select_mask_lo == ri.bucket_select_mask_lo &&
2166                data_select_mask == ri.data_select_mask &&
2167                hi_bits_mask == ri.hi_bits_mask &&
2168                lo_bits_mask == ri.lo_bits_mask &&
2169                neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
2170                last_start == ri.last_start && target == ri.target;
2171     }
2172 
hash()2173     size_t hash() const override {
2174         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi,
2175                         bucket_select_mask_lo, data_select_mask, hi_bits_mask,
2176                         lo_bits_mask, neg_mask, base_offset, last_start);
2177     }
2178 
2179     void write(void *dest, RoseEngineBlob &blob,
2180                const OffsetMap &offset_map) const override;
2181 
equiv_to(const RoseInstrCheckMultipathShufti32x16 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)2182     bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri,
2183                   const OffsetMap &offsets,
2184                   const OffsetMap &other_offsets) const {
2185         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2186                bucket_select_mask_hi == ri.bucket_select_mask_hi &&
2187                bucket_select_mask_lo == ri.bucket_select_mask_lo &&
2188                data_select_mask == ri.data_select_mask &&
2189                hi_bits_mask == ri.hi_bits_mask &&
2190                lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
2191                base_offset == ri.base_offset && last_start == ri.last_start &&
2192                offsets.at(target) == other_offsets.at(ri.target);
2193     }
2194 };
2195 
2196 class RoseInstrCheckMultipathShufti64
2197     : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
2198                                     ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64,
2199                                     RoseInstrCheckMultipathShufti64> {
2200 public:
2201     std::array<u8, 32> hi_mask;
2202     std::array<u8, 32> lo_mask;
2203     std::array<u8, 64> bucket_select_mask;
2204     std::array<u8, 64> data_select_mask;
2205     u64a hi_bits_mask;
2206     u64a lo_bits_mask;
2207     u64a neg_mask;
2208     s32 base_offset;
2209     s32 last_start;
2210     const RoseInstruction *target;
2211 
RoseInstrCheckMultipathShufti64(std::array<u8,32> hi_mask_in,std::array<u8,32> lo_mask_in,std::array<u8,64> bucket_select_mask_in,std::array<u8,64> data_select_mask_in,u64a hi_bits_mask_in,u64a lo_bits_mask_in,u64a neg_mask_in,s32 base_offset_in,s32 last_start_in,const RoseInstruction * target_in)2212     RoseInstrCheckMultipathShufti64(std::array<u8, 32> hi_mask_in,
2213                                     std::array<u8, 32> lo_mask_in,
2214                                     std::array<u8, 64> bucket_select_mask_in,
2215                                     std::array<u8, 64> data_select_mask_in,
2216                                     u64a hi_bits_mask_in, u64a lo_bits_mask_in,
2217                                     u64a neg_mask_in, s32 base_offset_in,
2218                                     s32 last_start_in,
2219                                     const RoseInstruction *target_in)
2220         : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)),
2221           bucket_select_mask(std::move(bucket_select_mask_in)),
2222           data_select_mask(std::move(data_select_mask_in)),
2223           hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in),
2224           neg_mask(neg_mask_in), base_offset(base_offset_in),
2225           last_start(last_start_in), target(target_in) {}
2226 
2227     bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const {
2228         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2229                bucket_select_mask == ri.bucket_select_mask &&
2230                data_select_mask == ri.data_select_mask &&
2231                hi_bits_mask == ri.hi_bits_mask &&
2232                lo_bits_mask == ri.lo_bits_mask &&
2233                neg_mask == ri.neg_mask && base_offset == ri.base_offset &&
2234                last_start == ri.last_start && target == ri.target;
2235     }
2236 
hash()2237     size_t hash() const override {
2238         return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask,
2239                         data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask,
2240                         base_offset, last_start);
2241     }
2242 
2243     void write(void *dest, RoseEngineBlob &blob,
2244                const OffsetMap &offset_map) const override;
2245 
equiv_to(const RoseInstrCheckMultipathShufti64 & ri,const OffsetMap & offsets,const OffsetMap & other_offsets)2246     bool equiv_to(const RoseInstrCheckMultipathShufti64 &ri,
2247                   const OffsetMap &offsets,
2248                   const OffsetMap &other_offsets) const {
2249         return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask &&
2250                bucket_select_mask == ri.bucket_select_mask &&
2251                data_select_mask == ri.data_select_mask &&
2252                hi_bits_mask == ri.hi_bits_mask &&
2253                lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask &&
2254                base_offset == ri.base_offset && last_start == ri.last_start &&
2255                offsets.at(target) == other_offsets.at(ri.target);
2256     }
2257 };
2258 
2259 class RoseInstrIncludedJump
2260     : public RoseInstrBaseNoTargets<ROSE_INSTR_INCLUDED_JUMP,
2261                                     ROSE_STRUCT_INCLUDED_JUMP,
2262                                     RoseInstrIncludedJump> {
2263 public:
2264     u32 child_offset;
2265     u8 squash;
2266 
RoseInstrIncludedJump(u32 child_offset_in,u8 squash_in)2267     RoseInstrIncludedJump(u32 child_offset_in, u8 squash_in)
2268         : child_offset(child_offset_in), squash(squash_in) {}
2269 
2270     bool operator==(const RoseInstrIncludedJump &ri) const {
2271         return child_offset == ri.child_offset && squash == ri.squash;
2272     }
2273 
hash()2274     size_t hash() const override {
2275         return hash_all(static_cast<int>(opcode), child_offset, squash);
2276     }
2277 
2278     void write(void *dest, RoseEngineBlob &blob,
2279                const OffsetMap &offset_map) const override;
2280 
equiv_to(const RoseInstrIncludedJump & ri,const OffsetMap &,const OffsetMap &)2281     bool equiv_to(const RoseInstrIncludedJump &ri, const OffsetMap &,
2282                   const OffsetMap &) const {
2283         return child_offset == ri.child_offset && squash == ri.squash;
2284     }
2285 };
2286 
2287 class RoseInstrSetLogical
2288     : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_LOGICAL,
2289                                     ROSE_STRUCT_SET_LOGICAL,
2290                                     RoseInstrSetLogical> {
2291 public:
2292     u32 lkey;
2293     s32 offset_adjust;
2294 
RoseInstrSetLogical(u32 lkey_in,s32 offset_adjust_in)2295     RoseInstrSetLogical(u32 lkey_in, s32 offset_adjust_in)
2296         : lkey(lkey_in), offset_adjust(offset_adjust_in) {}
2297 
2298     bool operator==(const RoseInstrSetLogical &ri) const {
2299         return lkey == ri.lkey && offset_adjust == ri.offset_adjust;
2300     }
2301 
hash()2302     size_t hash() const override {
2303         return hash_all(opcode, lkey, offset_adjust);
2304     }
2305 
2306     void write(void *dest, RoseEngineBlob &blob,
2307                const OffsetMap &offset_map) const override;
2308 
equiv_to(const RoseInstrSetLogical & ri,const OffsetMap &,const OffsetMap &)2309     bool equiv_to(const RoseInstrSetLogical &ri, const OffsetMap &,
2310                   const OffsetMap &) const {
2311         return lkey == ri.lkey && offset_adjust == ri.offset_adjust;
2312     }
2313 };
2314 
2315 class RoseInstrSetCombination
2316     : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_COMBINATION,
2317                                     ROSE_STRUCT_SET_COMBINATION,
2318                                     RoseInstrSetCombination> {
2319 public:
2320     u32 ckey;
2321 
RoseInstrSetCombination(u32 ckey_in)2322     RoseInstrSetCombination(u32 ckey_in) : ckey(ckey_in) {}
2323 
2324     bool operator==(const RoseInstrSetCombination &ri) const {
2325         return ckey == ri.ckey;
2326     }
2327 
hash()2328     size_t hash() const override {
2329         return hash_all(opcode, ckey);
2330     }
2331 
2332     void write(void *dest, RoseEngineBlob &blob,
2333                const OffsetMap &offset_map) const override;
2334 
equiv_to(const RoseInstrSetCombination & ri,const OffsetMap &,const OffsetMap &)2335     bool equiv_to(const RoseInstrSetCombination &ri, const OffsetMap &,
2336                   const OffsetMap &) const {
2337         return ckey == ri.ckey;
2338     }
2339 };
2340 
2341 class RoseInstrFlushCombination
2342     : public RoseInstrBaseTrivial<ROSE_INSTR_FLUSH_COMBINATION,
2343                                   ROSE_STRUCT_FLUSH_COMBINATION,
2344                                   RoseInstrFlushCombination> {
2345 public:
2346     ~RoseInstrFlushCombination() override;
2347 };
2348 
2349 class RoseInstrLastFlushCombination
2350     : public RoseInstrBaseTrivial<ROSE_INSTR_LAST_FLUSH_COMBINATION,
2351                                   ROSE_STRUCT_LAST_FLUSH_COMBINATION,
2352                                   RoseInstrLastFlushCombination> {
2353 public:
2354     ~RoseInstrLastFlushCombination() override;
2355 };
2356 
2357 class RoseInstrSetExhaust
2358     : public RoseInstrBaseNoTargets<ROSE_INSTR_SET_EXHAUST,
2359                                     ROSE_STRUCT_SET_EXHAUST,
2360                                     RoseInstrSetExhaust> {
2361 public:
2362     u32 ekey;
2363 
RoseInstrSetExhaust(u32 ekey_in)2364     RoseInstrSetExhaust(u32 ekey_in) : ekey(ekey_in) {}
2365 
2366     bool operator==(const RoseInstrSetExhaust &ri) const {
2367         return ekey == ri.ekey;
2368     }
2369 
hash()2370     size_t hash() const override {
2371         return hash_all(opcode, ekey);
2372     }
2373 
2374     void write(void *dest, RoseEngineBlob &blob,
2375                const OffsetMap &offset_map) const override;
2376 
equiv_to(const RoseInstrSetExhaust & ri,const OffsetMap &,const OffsetMap &)2377     bool equiv_to(const RoseInstrSetExhaust &ri, const OffsetMap &,
2378                   const OffsetMap &) const {
2379         return ekey == ri.ekey;
2380     }
2381 };
2382 
2383 class RoseInstrEnd
2384     : public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
2385                                   RoseInstrEnd> {
2386 public:
2387     ~RoseInstrEnd() override;
2388 };
2389 
2390 }
2391 #endif
2392