/* * Copyright (c) 2017-2019, Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** \file * \brief Concrete classes for interpreter instructions. * * Note: this header should only be included in files which need to deal with * the details of actual instructions. It is expected that most will only * require access to the RoseInstruction API exposed in rose_build_program.h */ #ifndef ROSE_BUILD_INSTRUCTIONS_H #define ROSE_BUILD_INSTRUCTIONS_H #include "rose_build_lookaround.h" #include "rose_build_program.h" #include "util/hash.h" #include "util/verify_types.h" namespace ue2 { /** * \brief Abstract base class representing a single Rose instruction. */ class RoseInstruction { public: virtual ~RoseInstruction(); /** \brief Opcode used for the instruction in the bytecode. */ virtual RoseInstructionCode code() const = 0; /** * \brief Simple hash used for program equivalence. * * Note that pointers (jumps, for example) should not be used when * calculating the hash: they will be converted to instruction offsets when * compared later. */ virtual size_t hash() const = 0; /** \brief Length of the bytecode instruction in bytes. */ virtual size_t byte_length() const = 0; using OffsetMap = std::unordered_map; /** * \brief Writes a concrete implementation of this instruction. * * Other data that this instruction depends on is written directly into the * blob, while the instruction structure itself (of size given by * the byte_length() function) is written to dest. */ virtual void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const = 0; /** * \brief Update a target pointer. * * If this instruction contains any reference to the old target, replace it * with the new one. */ virtual void update_target(const RoseInstruction *old_target, const RoseInstruction *new_target) = 0; /** * \brief True if these instructions are equivalent within their own * programs. * * Checks that any pointers to other instructions point to the same * offsets. */ bool equiv(const RoseInstruction &other, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return equiv_impl(other, offsets, other_offsets); } private: virtual bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets, const OffsetMap &other_offsets) const = 0; }; /** * \brief Templated implementation class to handle boring boilerplate code. */ template class RoseInstrBase : public RoseInstruction { protected: static constexpr RoseInstructionCode opcode = Opcode; using impl_type = ImplType; public: RoseInstructionCode code() const override { return opcode; } size_t byte_length() const override { return sizeof(impl_type); } /** * Note: this implementation simply zeroes the destination region and * writes in the correct opcode. This is sufficient for trivial * instructions, but instructions with data members will want to override * it. */ void write(void *dest, RoseEngineBlob &, const RoseInstruction::OffsetMap &) const override { assert(dest != nullptr); assert(ISALIGNED_N(dest, ROSE_INSTR_MIN_ALIGN)); impl_type *inst = static_cast(dest); memset(inst, 0, sizeof(impl_type)); inst->code = verify_u8(opcode); } private: bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets, const OffsetMap &other_offsets) const override { const auto *ri_that = dynamic_cast(&other); if (!ri_that) { return false; } const auto *ri_this = dynamic_cast(this); assert(ri_this); return ri_this->equiv_to(*ri_that, offsets, other_offsets); } }; template constexpr RoseInstructionCode RoseInstrBase::opcode; /** * \brief Refinement of RoseInstrBase to use for instructions that have * just a single target member, called "target". */ template class RoseInstrBaseOneTarget : public RoseInstrBase { public: void update_target(const RoseInstruction *old_target, const RoseInstruction *new_target) override { RoseInstrType *ri = dynamic_cast(this); assert(ri); if (ri->target == old_target) { ri->target = new_target; } } }; /** * \brief Refinement of RoseInstrBase to use for instructions that have no * targets. */ template class RoseInstrBaseNoTargets : public RoseInstrBase { public: void update_target(const RoseInstruction *, const RoseInstruction *) override {} }; /** * \brief Refinement of RoseInstrBaseNoTargets to use for instructions that * have no members at all, just an opcode. */ template class RoseInstrBaseTrivial : public RoseInstrBaseNoTargets { public: virtual bool operator==(const RoseInstrType &) const { return true; } size_t hash() const override { return hash_all(Opcode); } bool equiv_to(const RoseInstrType &, const RoseInstruction::OffsetMap &, const RoseInstruction::OffsetMap &) const { return true; } }; //// //// Concrete implementation classes start here. //// class RoseInstrAnchoredDelay : public RoseInstrBaseOneTarget { public: rose_group groups; u32 anch_id; const RoseInstruction *target; RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in, const RoseInstruction *target_in) : groups(groups_in), anch_id(anch_id_in), target(target_in) {} bool operator==(const RoseInstrAnchoredDelay &ri) const { return groups == ri.groups && anch_id == ri.anch_id && target == ri.target; } size_t hash() const override { return hash_all(opcode, groups, anch_id); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return groups == ri.groups && anch_id == ri.anch_id && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckLitEarly : public RoseInstrBaseOneTarget { public: u32 min_offset; const RoseInstruction *target; RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in) : min_offset(min_offset_in), target(target_in) {} bool operator==(const RoseInstrCheckLitEarly &ri) const { return min_offset == ri.min_offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, min_offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return min_offset == ri.min_offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckGroups : public RoseInstrBaseNoTargets { public: rose_group groups; explicit RoseInstrCheckGroups(rose_group groups_in) : groups(groups_in) {} bool operator==(const RoseInstrCheckGroups &ri) const { return groups == ri.groups; } size_t hash() const override { return hash_all(opcode, groups); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &, const OffsetMap &) const { return groups == ri.groups; } }; class RoseInstrCheckOnlyEod : public RoseInstrBaseOneTarget { public: const RoseInstruction *target; explicit RoseInstrCheckOnlyEod(const RoseInstruction *target_in) : target(target_in) {} bool operator==(const RoseInstrCheckOnlyEod &ri) const { return target == ri.target; } size_t hash() const override { return hash_all(opcode); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckOnlyEod &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckBounds : public RoseInstrBaseOneTarget { public: u64a min_bound; u64a max_bound; const RoseInstruction *target; RoseInstrCheckBounds(u64a min, u64a max, const RoseInstruction *target_in) : min_bound(min), max_bound(max), target(target_in) {} bool operator==(const RoseInstrCheckBounds &ri) const { return min_bound == ri.min_bound && max_bound == ri.max_bound && target == ri.target; } size_t hash() const override { return hash_all(opcode, min_bound, max_bound); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckBounds &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return min_bound == ri.min_bound && max_bound == ri.max_bound && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckNotHandled : public RoseInstrBaseOneTarget { public: u32 key; const RoseInstruction *target; RoseInstrCheckNotHandled(u32 key_in, const RoseInstruction *target_in) : key(key_in), target(target_in) {} bool operator==(const RoseInstrCheckNotHandled &ri) const { return key == ri.key && target == ri.target; } size_t hash() const override { return hash_all(opcode, key); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckNotHandled &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return key == ri.key && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckSingleLookaround : public RoseInstrBaseOneTarget { public: s8 offset; CharReach reach; const RoseInstruction *target; RoseInstrCheckSingleLookaround(s8 offset_in, CharReach reach_in, const RoseInstruction *target_in) : offset(offset_in), reach(std::move(reach_in)), target(target_in) {} bool operator==(const RoseInstrCheckSingleLookaround &ri) const { return offset == ri.offset && reach == ri.reach && target == ri.target; } size_t hash() const override { return hash_all(opcode, offset, reach); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckSingleLookaround &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return offset == ri.offset && reach == ri.reach && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckLookaround : public RoseInstrBaseOneTarget { public: std::vector look; const RoseInstruction *target; RoseInstrCheckLookaround(std::vector look_in, const RoseInstruction *target_in) : look(std::move(look_in)), target(target_in) {} bool operator==(const RoseInstrCheckLookaround &ri) const { return look == ri.look && target == ri.target; } size_t hash() const override { return hash_all(opcode, look); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckLookaround &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return look == ri.look && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMask : public RoseInstrBaseOneTarget { public: u64a and_mask; u64a cmp_mask; u64a neg_mask; s32 offset; const RoseInstruction *target; RoseInstrCheckMask(u64a and_mask_in, u64a cmp_mask_in, u64a neg_mask_in, s32 offset_in, const RoseInstruction *target_in) : and_mask(and_mask_in), cmp_mask(cmp_mask_in), neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckMask &ri) const { return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && neg_mask == ri.neg_mask && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMask &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && neg_mask == ri.neg_mask && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMask32 : public RoseInstrBaseOneTarget { public: std::array and_mask; std::array cmp_mask; u32 neg_mask; s32 offset; const RoseInstruction *target; RoseInstrCheckMask32(std::array and_mask_in, std::array cmp_mask_in, u32 neg_mask_in, s32 offset_in, const RoseInstruction *target_in) : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)), neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckMask32 &ri) const { return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && neg_mask == ri.neg_mask && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, and_mask, cmp_mask, neg_mask, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMask32 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && neg_mask == ri.neg_mask && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckByte : public RoseInstrBaseOneTarget { public: u8 and_mask; u8 cmp_mask; u8 negation; s32 offset; const RoseInstruction *target; RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in, s32 offset_in, const RoseInstruction *target_in) : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckByte &ri) const { return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && negation == ri.negation && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, and_mask, cmp_mask, negation, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && negation == ri.negation && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckShufti16x8 : public RoseInstrBaseOneTarget { public: std::array nib_mask; std::array bucket_select_mask; u32 neg_mask; s32 offset; const RoseInstruction *target; RoseInstrCheckShufti16x8(std::array nib_mask_in, std::array bucket_select_mask_in, u32 neg_mask_in, s32 offset_in, const RoseInstruction *target_in) : nib_mask(std::move(nib_mask_in)), bucket_select_mask(std::move(bucket_select_mask_in)), neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckShufti16x8 &ri) const { return nib_mask == ri.nib_mask && bucket_select_mask == ri.bucket_select_mask && neg_mask == ri.neg_mask && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, nib_mask, bucket_select_mask, neg_mask, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return nib_mask == ri.nib_mask && bucket_select_mask == ri.bucket_select_mask && neg_mask == ri.neg_mask && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckShufti32x8 : public RoseInstrBaseOneTarget { public: std::array hi_mask; std::array lo_mask; std::array bucket_select_mask; u32 neg_mask; s32 offset; const RoseInstruction *target; RoseInstrCheckShufti32x8(std::array hi_mask_in, std::array lo_mask_in, std::array bucket_select_mask_in, u32 neg_mask_in, s32 offset_in, const RoseInstruction *target_in) : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), bucket_select_mask(std::move(bucket_select_mask_in)), neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckShufti32x8 &ri) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && neg_mask == ri.neg_mask && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && neg_mask == ri.neg_mask && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckShufti16x16 : public RoseInstrBaseOneTarget { public: std::array hi_mask; std::array lo_mask; std::array bucket_select_mask; u32 neg_mask; s32 offset; const RoseInstruction *target; RoseInstrCheckShufti16x16(std::array hi_mask_in, std::array lo_mask_in, std::array bucket_select_mask_in, u32 neg_mask_in, s32 offset_in, const RoseInstruction *target_in) : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), bucket_select_mask(std::move(bucket_select_mask_in)), neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckShufti16x16 &ri) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && neg_mask == ri.neg_mask && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, neg_mask, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && neg_mask == ri.neg_mask && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckShufti32x16 : public RoseInstrBaseOneTarget { public: std::array hi_mask; std::array lo_mask; std::array bucket_select_mask_hi; std::array bucket_select_mask_lo; u32 neg_mask; s32 offset; const RoseInstruction *target; RoseInstrCheckShufti32x16(std::array hi_mask_in, std::array lo_mask_in, std::array bucket_select_mask_hi_in, std::array bucket_select_mask_lo_in, u32 neg_mask_in, s32 offset_in, const RoseInstruction *target_in) : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)), bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)), neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} bool operator==(const RoseInstrCheckShufti32x16 &ri) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask_hi == ri.bucket_select_mask_hi && bucket_select_mask_lo == ri.bucket_select_mask_lo && neg_mask == ri.neg_mask && offset == ri.offset && target == ri.target; } size_t hash() const override { return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi, bucket_select_mask_lo, neg_mask, offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask_hi == ri.bucket_select_mask_hi && bucket_select_mask_lo == ri.bucket_select_mask_lo && neg_mask == ri.neg_mask && offset == ri.offset && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckInfix : public RoseInstrBaseOneTarget { public: u32 queue; u32 lag; ReportID report; const RoseInstruction *target; RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in, const RoseInstruction *target_in) : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {} bool operator==(const RoseInstrCheckInfix &ri) const { return queue == ri.queue && lag == ri.lag && report == ri.report && target == ri.target; } size_t hash() const override { return hash_all(opcode, queue, lag, report); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return queue == ri.queue && lag == ri.lag && report == ri.report && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckPrefix : public RoseInstrBaseOneTarget { public: u32 queue; u32 lag; ReportID report; const RoseInstruction *target; RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in, const RoseInstruction *target_in) : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {} bool operator==(const RoseInstrCheckPrefix &ri) const { return queue == ri.queue && lag == ri.lag && report == ri.report && target == ri.target; } size_t hash() const override { return hash_all(opcode, queue, lag, report); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return queue == ri.queue && lag == ri.lag && report == ri.report && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrPushDelayed : public RoseInstrBaseNoTargets { public: u8 delay; u32 index; RoseInstrPushDelayed(u8 delay_in, u32 index_in) : delay(delay_in), index(index_in) {} bool operator==(const RoseInstrPushDelayed &ri) const { return delay == ri.delay && index == ri.index; } size_t hash() const override { return hash_all(opcode, delay, index); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &, const OffsetMap &) const { return delay == ri.delay && index == ri.index; } }; class RoseInstrCatchUp : public RoseInstrBaseTrivial { public: ~RoseInstrCatchUp() override; }; class RoseInstrCatchUpMpv : public RoseInstrBaseTrivial { public: ~RoseInstrCatchUpMpv() override; }; class RoseInstrSomAdjust : public RoseInstrBaseNoTargets { public: u32 distance; explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {} bool operator==(const RoseInstrSomAdjust &ri) const { return distance == ri.distance; } size_t hash() const override { return hash_all(opcode, distance); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &, const OffsetMap &) const { return distance == ri.distance; } }; class RoseInstrSomLeftfix : public RoseInstrBaseNoTargets { public: u32 queue; u32 lag; RoseInstrSomLeftfix(u32 queue_in, u32 lag_in) : queue(queue_in), lag(lag_in) {} bool operator==(const RoseInstrSomLeftfix &ri) const { return queue == ri.queue && lag == ri.lag; } size_t hash() const override { return hash_all(opcode, queue, lag); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &, const OffsetMap &) const { return queue == ri.queue && lag == ri.lag; } }; class RoseInstrSomFromReport : public RoseInstrBaseNoTargets { public: som_operation som; RoseInstrSomFromReport() { std::memset(&som, 0, sizeof(som)); } bool operator==(const RoseInstrSomFromReport &ri) const { return std::memcmp(&som, &ri.som, sizeof(som)) == 0; } size_t hash() const override { return hash_all(opcode, som.type, som.onmatch); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &, const OffsetMap &) const { return std::memcmp(&som, &ri.som, sizeof(som)) == 0; } }; class RoseInstrSomZero : public RoseInstrBaseTrivial { public: ~RoseInstrSomZero() override; }; class RoseInstrTriggerInfix : public RoseInstrBaseNoTargets { public: u8 cancel; u32 queue; u32 event; RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in) : cancel(cancel_in), queue(queue_in), event(event_in) {} bool operator==(const RoseInstrTriggerInfix &ri) const { return cancel == ri.cancel && queue == ri.queue && event == ri.event; } size_t hash() const override { return hash_all(opcode, cancel, queue, event); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &, const OffsetMap &) const { return cancel == ri.cancel && queue == ri.queue && event == ri.event; } }; class RoseInstrTriggerSuffix : public RoseInstrBaseNoTargets { public: u32 queue; u32 event; RoseInstrTriggerSuffix(u32 queue_in, u32 event_in) : queue(queue_in), event(event_in) {} bool operator==(const RoseInstrTriggerSuffix &ri) const { return queue == ri.queue && event == ri.event; } size_t hash() const override { return hash_all(opcode, queue, event); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &, const OffsetMap &) const { return queue == ri.queue && event == ri.event; } }; class RoseInstrDedupe : public RoseInstrBaseOneTarget { public: u8 quash_som; u32 dkey; s32 offset_adjust; const RoseInstruction *target; RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in, const RoseInstruction *target_in) : quash_som(quash_som_in), dkey(dkey_in), offset_adjust(offset_adjust_in), target(target_in) {} bool operator==(const RoseInstrDedupe &ri) const { return quash_som == ri.quash_som && dkey == ri.dkey && offset_adjust == ri.offset_adjust && target == ri.target; } size_t hash() const override { return hash_all(opcode, quash_som, dkey, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return quash_som == ri.quash_som && dkey == ri.dkey && offset_adjust == ri.offset_adjust && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrDedupeSom : public RoseInstrBaseOneTarget { public: u8 quash_som; u32 dkey; s32 offset_adjust; const RoseInstruction *target; RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in, const RoseInstruction *target_in) : quash_som(quash_som_in), dkey(dkey_in), offset_adjust(offset_adjust_in), target(target_in) {} bool operator==(const RoseInstrDedupeSom &ri) const { return quash_som == ri.quash_som && dkey == ri.dkey && offset_adjust == ri.offset_adjust && target == ri.target; } size_t hash() const override { return hash_all(opcode, quash_som, dkey, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return quash_som == ri.quash_som && dkey == ri.dkey && offset_adjust == ri.offset_adjust && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrReportChain : public RoseInstrBaseNoTargets { public: u32 event; u64a top_squash_distance; RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in) : event(event_in), top_squash_distance(top_squash_distance_in) {} bool operator==(const RoseInstrReportChain &ri) const { return event == ri.event && top_squash_distance == ri.top_squash_distance; } size_t hash() const override { return hash_all(opcode, event, top_squash_distance); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &, const OffsetMap &) const { return event == ri.event && top_squash_distance == ri.top_squash_distance; } }; class RoseInstrReportSomInt : public RoseInstrBaseNoTargets { public: som_operation som; RoseInstrReportSomInt() { std::memset(&som, 0, sizeof(som)); } bool operator==(const RoseInstrReportSomInt &ri) const { return std::memcmp(&som, &ri.som, sizeof(som)) == 0; } size_t hash() const override { return hash_all(opcode, som.type, som.onmatch); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &, const OffsetMap &) const { return std::memcmp(&som, &ri.som, sizeof(som)) == 0; } }; class RoseInstrReportSomAware : public RoseInstrBaseNoTargets { public: som_operation som; RoseInstrReportSomAware() { std::memset(&som, 0, sizeof(som)); } bool operator==(const RoseInstrReportSomAware &ri) const { return std::memcmp(&som, &ri.som, sizeof(som)) == 0; } size_t hash() const override { return hash_all(opcode, som.type, som.onmatch); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &, const OffsetMap &) const { return std::memcmp(&som, &ri.som, sizeof(som)) == 0; } }; class RoseInstrReport : public RoseInstrBaseNoTargets { public: ReportID onmatch; s32 offset_adjust; RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in) : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} bool operator==(const RoseInstrReport &ri) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; } size_t hash() const override { return hash_all(opcode, onmatch, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReport &ri, const OffsetMap &, const OffsetMap &) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; } }; class RoseInstrReportExhaust : public RoseInstrBaseNoTargets { public: ReportID onmatch; s32 offset_adjust; u32 ekey; RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in, u32 ekey_in) : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {} bool operator==(const RoseInstrReportExhaust &ri) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && ekey == ri.ekey; } size_t hash() const override { return hash_all(opcode, onmatch, offset_adjust, ekey); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &, const OffsetMap &) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && ekey == ri.ekey; } }; class RoseInstrReportSom : public RoseInstrBaseNoTargets { public: ReportID onmatch; s32 offset_adjust; RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in) : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} bool operator==(const RoseInstrReportSom &ri) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; } size_t hash() const override { return hash_all(opcode, onmatch, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &, const OffsetMap &) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; } }; class RoseInstrReportSomExhaust : public RoseInstrBaseNoTargets { public: ReportID onmatch; s32 offset_adjust; u32 ekey; RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in, u32 ekey_in) : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {} bool operator==(const RoseInstrReportSomExhaust &ri) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && ekey == ri.ekey; } size_t hash() const override { return hash_all(opcode, onmatch, offset_adjust, ekey); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &, const OffsetMap &) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && ekey == ri.ekey; } }; class RoseInstrDedupeAndReport : public RoseInstrBaseOneTarget { public: u8 quash_som; u32 dkey; ReportID onmatch; s32 offset_adjust; const RoseInstruction *target; RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in, s32 offset_adjust_in, const RoseInstruction *target_in) : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in), offset_adjust(offset_adjust_in), target(target_in) {} bool operator==(const RoseInstrDedupeAndReport &ri) const { return quash_som == ri.quash_som && dkey == ri.dkey && onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && target == ri.target; } size_t hash() const override { return hash_all(opcode, quash_som, dkey, onmatch, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return quash_som == ri.quash_som && dkey == ri.dkey && onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrFinalReport : public RoseInstrBaseNoTargets { public: ReportID onmatch; s32 offset_adjust; RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in) : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} bool operator==(const RoseInstrFinalReport &ri) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; } size_t hash() const override { return hash_all(opcode, onmatch, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &, const OffsetMap &) const { return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; } }; class RoseInstrCheckExhausted : public RoseInstrBaseOneTarget { public: u32 ekey; const RoseInstruction *target; RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in) : ekey(ekey_in), target(target_in) {} bool operator==(const RoseInstrCheckExhausted &ri) const { return ekey == ri.ekey && target == ri.target; } size_t hash() const override { return hash_all(opcode, ekey); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return ekey == ri.ekey && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMinLength : public RoseInstrBaseOneTarget { public: s32 end_adj; u64a min_length; const RoseInstruction *target; RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in, const RoseInstruction *target_in) : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {} bool operator==(const RoseInstrCheckMinLength &ri) const { return end_adj == ri.end_adj && min_length == ri.min_length && target == ri.target; } size_t hash() const override { return hash_all(opcode, end_adj, min_length); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return end_adj == ri.end_adj && min_length == ri.min_length && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrSetState : public RoseInstrBaseNoTargets { public: u32 index; explicit RoseInstrSetState(u32 index_in) : index(index_in) {} bool operator==(const RoseInstrSetState &ri) const { return index == ri.index; } size_t hash() const override { return hash_all(opcode, index); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &, const OffsetMap &) const { return index == ri.index; } }; class RoseInstrSetGroups : public RoseInstrBaseNoTargets { public: rose_group groups; explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {} bool operator==(const RoseInstrSetGroups &ri) const { return groups == ri.groups; } size_t hash() const override { return hash_all(opcode, groups); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &, const OffsetMap &) const { return groups == ri.groups; } }; class RoseInstrSquashGroups : public RoseInstrBaseNoTargets { public: rose_group groups; explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {} bool operator==(const RoseInstrSquashGroups &ri) const { return groups == ri.groups; } size_t hash() const override { return hash_all(opcode, groups); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &, const OffsetMap &) const { return groups == ri.groups; } }; class RoseInstrCheckState : public RoseInstrBaseOneTarget { public: u32 index; const RoseInstruction *target; RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in) : index(index_in), target(target_in) {} bool operator==(const RoseInstrCheckState &ri) const { return index == ri.index && target == ri.target; } size_t hash() const override { return hash_all(opcode, index); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return index == ri.index && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrSparseIterBegin : public RoseInstrBase { public: u32 num_keys; // total number of multibit keys std::vector> jump_table; const RoseInstruction *target; RoseInstrSparseIterBegin(u32 num_keys_in, const RoseInstruction *target_in) : num_keys(num_keys_in), target(target_in) {} bool operator==(const RoseInstrSparseIterBegin &ri) const { return num_keys == ri.num_keys && jump_table == ri.jump_table && target == ri.target; } size_t hash() const override { size_t v = hash_all(opcode, num_keys); for (const u32 &key : jump_table | boost::adaptors::map_keys) { hash_combine(v, key); } return v; } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; void update_target(const RoseInstruction *old_target, const RoseInstruction *new_target) override { if (target == old_target) { target = new_target; } for (auto &jump : jump_table) { if (jump.second == old_target) { jump.second = new_target; } } } bool equiv_to(const RoseInstrSparseIterBegin &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { if (iter_offset != ri.iter_offset || offsets.at(target) != other_offsets.at(ri.target)) { return false; } if (jump_table.size() != ri.jump_table.size()) { return false; } auto it1 = jump_table.begin(), it2 = ri.jump_table.begin(); for (; it1 != jump_table.end(); ++it1, ++it2) { if (it1->first != it2->first) { return false; } if (offsets.at(it1->second) != other_offsets.at(it2->second)) { return false; } } return true; } private: friend class RoseInstrSparseIterNext; // These variables allow us to use the same multibit iterator and jump // table in subsequent SPARSE_ITER_NEXT write() operations. mutable bool is_written = false; mutable u32 iter_offset = 0; mutable u32 jump_table_offset = 0; }; class RoseInstrSparseIterNext : public RoseInstrBase { public: u32 state; const RoseInstrSparseIterBegin *begin; const RoseInstruction *target; RoseInstrSparseIterNext(u32 state_in, const RoseInstrSparseIterBegin *begin_in, const RoseInstruction *target_in) : state(state_in), begin(begin_in), target(target_in) {} bool operator==(const RoseInstrSparseIterNext &ri) const { return state == ri.state && begin == ri.begin && target == ri.target; } size_t hash() const override { return hash_all(opcode, state); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; void update_target(const RoseInstruction *old_target, const RoseInstruction *new_target) override { if (target == old_target) { target = new_target; } if (begin == old_target) { assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN); begin = static_cast(new_target); } } bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return state == ri.state && offsets.at(begin) == other_offsets.at(ri.begin) && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrSparseIterAny : public RoseInstrBaseOneTarget { public: u32 num_keys; // total number of multibit keys std::vector keys; const RoseInstruction *target; RoseInstrSparseIterAny(u32 num_keys_in, std::vector keys_in, const RoseInstruction *target_in) : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {} bool operator==(const RoseInstrSparseIterAny &ri) const { return num_keys == ri.num_keys && keys == ri.keys && target == ri.target; } size_t hash() const override { return hash_all(opcode, num_keys, keys); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return num_keys == ri.num_keys && keys == ri.keys && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrEnginesEod : public RoseInstrBaseNoTargets { public: u32 iter_offset; explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {} bool operator==(const RoseInstrEnginesEod &ri) const { return iter_offset == ri.iter_offset; } size_t hash() const override { return hash_all(opcode, iter_offset); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &, const OffsetMap &) const { return iter_offset == ri.iter_offset; } }; class RoseInstrSuffixesEod : public RoseInstrBaseTrivial { public: ~RoseInstrSuffixesEod() override; }; class RoseInstrMatcherEod : public RoseInstrBaseTrivial { public: ~RoseInstrMatcherEod() override; }; class RoseInstrCheckLongLit : public RoseInstrBaseOneTarget { public: std::string literal; const RoseInstruction *target; RoseInstrCheckLongLit(std::string literal_in, const RoseInstruction *target_in) : literal(std::move(literal_in)), target(target_in) {} bool operator==(const RoseInstrCheckLongLit &ri) const { return literal == ri.literal && target == ri.target; } size_t hash() const override { return hash_all(opcode, literal); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return literal == ri.literal && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckLongLitNocase : public RoseInstrBaseOneTarget { public: std::string literal; const RoseInstruction *target; RoseInstrCheckLongLitNocase(std::string literal_in, const RoseInstruction *target_in) : literal(std::move(literal_in)), target(target_in) { upperString(literal); } bool operator==(const RoseInstrCheckLongLitNocase &ri) const { return literal == ri.literal && target == ri.target; } size_t hash() const override { return hash_all(opcode, literal); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckLongLitNocase &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return literal == ri.literal && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMedLit : public RoseInstrBaseOneTarget { public: std::string literal; const RoseInstruction *target; explicit RoseInstrCheckMedLit(std::string literal_in, const RoseInstruction *target_in) : literal(std::move(literal_in)), target(target_in) {} bool operator==(const RoseInstrCheckMedLit &ri) const { return literal == ri.literal && target == ri.target; } size_t hash() const override { return hash_all(opcode, literal); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return literal == ri.literal && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMedLitNocase : public RoseInstrBaseOneTarget { public: std::string literal; const RoseInstruction *target; explicit RoseInstrCheckMedLitNocase(std::string literal_in, const RoseInstruction *target_in) : literal(std::move(literal_in)), target(target_in) { upperString(literal); } bool operator==(const RoseInstrCheckMedLitNocase &ri) const { return literal == ri.literal && target == ri.target; } size_t hash() const override { return hash_all(opcode, literal); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMedLitNocase &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return literal == ri.literal && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrClearWorkDone : public RoseInstrBaseTrivial { public: ~RoseInstrClearWorkDone() override; }; class RoseInstrMultipathLookaround : public RoseInstrBaseOneTarget { public: std::vector> multi_look; s32 last_start; std::array start_mask; const RoseInstruction *target; RoseInstrMultipathLookaround(std::vector> ml, s32 last_start_in, std::array start_mask_in, const RoseInstruction *target_in) : multi_look(std::move(ml)), last_start(last_start_in), start_mask(std::move(start_mask_in)), target(target_in) {} bool operator==(const RoseInstrMultipathLookaround &ri) const { return multi_look == ri.multi_look && last_start == ri.last_start && start_mask == ri.start_mask && target == ri.target; } size_t hash() const override { return hash_all(opcode, multi_look, last_start, start_mask); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrMultipathLookaround &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return multi_look == ri.multi_look && last_start == ri.last_start && start_mask == ri.start_mask && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMultipathShufti16x8 : public RoseInstrBaseOneTarget { public: std::array nib_mask; std::array bucket_select_mask; std::array data_select_mask; u16 hi_bits_mask; u16 lo_bits_mask; u16 neg_mask; s32 base_offset; s32 last_start; const RoseInstruction *target; RoseInstrCheckMultipathShufti16x8(std::array nib_mask_in, std::array bucket_select_mask_in, std::array 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) : nib_mask(std::move(nib_mask_in)), bucket_select_mask(std::move(bucket_select_mask_in)), data_select_mask(std::move(data_select_mask_in)), hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), neg_mask(neg_mask_in), base_offset(base_offset_in), last_start(last_start_in), target(target_in) {} bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const { return nib_mask == ri.nib_mask && bucket_select_mask == ri.bucket_select_mask && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && target == ri.target; } size_t hash() const override { return hash_all(opcode, nib_mask, bucket_select_mask, data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask, base_offset, last_start); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return nib_mask == ri.nib_mask && bucket_select_mask == ri.bucket_select_mask && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMultipathShufti32x8 : public RoseInstrBaseOneTarget { public: std::array hi_mask; std::array lo_mask; std::array bucket_select_mask; std::array data_select_mask; u32 hi_bits_mask; u32 lo_bits_mask; u32 neg_mask; s32 base_offset; s32 last_start; const RoseInstruction *target; RoseInstrCheckMultipathShufti32x8(std::array hi_mask_in, std::array lo_mask_in, std::array bucket_select_mask_in, std::array 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) : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), bucket_select_mask(std::move(bucket_select_mask_in)), data_select_mask(std::move(data_select_mask_in)), hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), neg_mask(neg_mask_in), base_offset(base_offset_in), last_start(last_start_in), target(target_in) {} bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && target == ri.target; } size_t hash() const override { return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask, base_offset, last_start); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMultipathShufti32x16 : public RoseInstrBaseOneTarget { public: std::array hi_mask; std::array lo_mask; std::array bucket_select_mask_hi; std::array bucket_select_mask_lo; std::array data_select_mask; u32 hi_bits_mask; u32 lo_bits_mask; u32 neg_mask; s32 base_offset; s32 last_start; const RoseInstruction *target; RoseInstrCheckMultipathShufti32x16(std::array hi_mask_in, std::array lo_mask_in, std::array bucket_select_mask_hi_in, std::array bucket_select_mask_lo_in, std::array 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) : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)), bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)), data_select_mask(std::move(data_select_mask_in)), hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), neg_mask(neg_mask_in), base_offset(base_offset_in), last_start(last_start_in), target(target_in) {} bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask_hi == ri.bucket_select_mask_hi && bucket_select_mask_lo == ri.bucket_select_mask_lo && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && target == ri.target; } size_t hash() const override { return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask_hi, bucket_select_mask_lo, data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask, base_offset, last_start); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask_hi == ri.bucket_select_mask_hi && bucket_select_mask_lo == ri.bucket_select_mask_lo && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrCheckMultipathShufti64 : public RoseInstrBaseOneTarget { public: std::array hi_mask; std::array lo_mask; std::array bucket_select_mask; std::array data_select_mask; u64a hi_bits_mask; u64a lo_bits_mask; u64a neg_mask; s32 base_offset; s32 last_start; const RoseInstruction *target; RoseInstrCheckMultipathShufti64(std::array hi_mask_in, std::array lo_mask_in, std::array bucket_select_mask_in, std::array 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) : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), bucket_select_mask(std::move(bucket_select_mask_in)), data_select_mask(std::move(data_select_mask_in)), hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), neg_mask(neg_mask_in), base_offset(base_offset_in), last_start(last_start_in), target(target_in) {} bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && target == ri.target; } size_t hash() const override { return hash_all(opcode, hi_mask, lo_mask, bucket_select_mask, data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask, base_offset, last_start); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrCheckMultipathShufti64 &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && bucket_select_mask == ri.bucket_select_mask && data_select_mask == ri.data_select_mask && hi_bits_mask == ri.hi_bits_mask && lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && base_offset == ri.base_offset && last_start == ri.last_start && offsets.at(target) == other_offsets.at(ri.target); } }; class RoseInstrIncludedJump : public RoseInstrBaseNoTargets { public: u32 child_offset; u8 squash; RoseInstrIncludedJump(u32 child_offset_in, u8 squash_in) : child_offset(child_offset_in), squash(squash_in) {} bool operator==(const RoseInstrIncludedJump &ri) const { return child_offset == ri.child_offset && squash == ri.squash; } size_t hash() const override { return hash_all(static_cast(opcode), child_offset, squash); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrIncludedJump &ri, const OffsetMap &, const OffsetMap &) const { return child_offset == ri.child_offset && squash == ri.squash; } }; class RoseInstrSetLogical : public RoseInstrBaseNoTargets { public: u32 lkey; s32 offset_adjust; RoseInstrSetLogical(u32 lkey_in, s32 offset_adjust_in) : lkey(lkey_in), offset_adjust(offset_adjust_in) {} bool operator==(const RoseInstrSetLogical &ri) const { return lkey == ri.lkey && offset_adjust == ri.offset_adjust; } size_t hash() const override { return hash_all(opcode, lkey, offset_adjust); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSetLogical &ri, const OffsetMap &, const OffsetMap &) const { return lkey == ri.lkey && offset_adjust == ri.offset_adjust; } }; class RoseInstrSetCombination : public RoseInstrBaseNoTargets { public: u32 ckey; RoseInstrSetCombination(u32 ckey_in) : ckey(ckey_in) {} bool operator==(const RoseInstrSetCombination &ri) const { return ckey == ri.ckey; } size_t hash() const override { return hash_all(opcode, ckey); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSetCombination &ri, const OffsetMap &, const OffsetMap &) const { return ckey == ri.ckey; } }; class RoseInstrFlushCombination : public RoseInstrBaseTrivial { public: ~RoseInstrFlushCombination() override; }; class RoseInstrLastFlushCombination : public RoseInstrBaseTrivial { public: ~RoseInstrLastFlushCombination() override; }; class RoseInstrSetExhaust : public RoseInstrBaseNoTargets { public: u32 ekey; RoseInstrSetExhaust(u32 ekey_in) : ekey(ekey_in) {} bool operator==(const RoseInstrSetExhaust &ri) const { return ekey == ri.ekey; } size_t hash() const override { return hash_all(opcode, ekey); } void write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const override; bool equiv_to(const RoseInstrSetExhaust &ri, const OffsetMap &, const OffsetMap &) const { return ekey == ri.ekey; } }; class RoseInstrEnd : public RoseInstrBaseTrivial { public: ~RoseInstrEnd() override; }; } #endif