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