vectorscan/src/rose/rose_build_instructions.h

2252 lines
80 KiB
C++

/*
* 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<const RoseInstruction *, u32>;
/**
* \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<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
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<impl_type *>(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<const RoseInstrType *>(&other);
if (!ri_that) {
return false;
}
const auto *ri_this = dynamic_cast<const RoseInstrType *>(this);
assert(ri_this);
return ri_this->equiv_to(*ri_that, offsets, other_offsets);
}
};
template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
constexpr RoseInstructionCode
RoseInstrBase<Opcode, ImplType, RoseInstrType>::opcode;
/**
* \brief Refinement of RoseInstrBase to use for instructions that have
* just a single target member, called "target".
*/
template<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
class RoseInstrBaseOneTarget
: public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
public:
void update_target(const RoseInstruction *old_target,
const RoseInstruction *new_target) override {
RoseInstrType *ri = dynamic_cast<RoseInstrType *>(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<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
class RoseInstrBaseNoTargets
: public RoseInstrBase<Opcode, ImplType, RoseInstrType> {
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<RoseInstructionCode Opcode, class ImplType, class RoseInstrType>
class RoseInstrBaseTrivial
: public RoseInstrBaseNoTargets<Opcode, ImplType, RoseInstrType> {
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<ROSE_INSTR_ANCHORED_DELAY,
ROSE_STRUCT_ANCHORED_DELAY,
RoseInstrAnchoredDelay> {
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<ROSE_INSTR_CHECK_LIT_EARLY,
ROSE_STRUCT_CHECK_LIT_EARLY,
RoseInstrCheckLitEarly> {
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<ROSE_INSTR_CHECK_GROUPS,
ROSE_STRUCT_CHECK_GROUPS,
RoseInstrCheckGroups> {
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<ROSE_INSTR_CHECK_ONLY_EOD,
ROSE_STRUCT_CHECK_ONLY_EOD,
RoseInstrCheckOnlyEod> {
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<ROSE_INSTR_CHECK_BOUNDS,
ROSE_STRUCT_CHECK_BOUNDS,
RoseInstrCheckBounds> {
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<ROSE_INSTR_CHECK_NOT_HANDLED,
ROSE_STRUCT_CHECK_NOT_HANDLED,
RoseInstrCheckNotHandled> {
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<ROSE_INSTR_CHECK_SINGLE_LOOKAROUND,
ROSE_STRUCT_CHECK_SINGLE_LOOKAROUND,
RoseInstrCheckSingleLookaround> {
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<ROSE_INSTR_CHECK_LOOKAROUND,
ROSE_STRUCT_CHECK_LOOKAROUND,
RoseInstrCheckLookaround> {
public:
std::vector<LookEntry> look;
const RoseInstruction *target;
RoseInstrCheckLookaround(std::vector<LookEntry> 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<ROSE_INSTR_CHECK_MASK,
ROSE_STRUCT_CHECK_MASK,
RoseInstrCheckMask> {
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<ROSE_INSTR_CHECK_MASK_32,
ROSE_STRUCT_CHECK_MASK_32,
RoseInstrCheckMask32> {
public:
std::array<u8, 32> and_mask;
std::array<u8, 32> cmp_mask;
u32 neg_mask;
s32 offset;
const RoseInstruction *target;
RoseInstrCheckMask32(std::array<u8, 32> and_mask_in,
std::array<u8, 32> cmp_mask_in, u32 neg_mask_in,
s32 offset_in, const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_BYTE,
ROSE_STRUCT_CHECK_BYTE,
RoseInstrCheckByte> {
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<ROSE_INSTR_CHECK_SHUFTI_16x8,
ROSE_STRUCT_CHECK_SHUFTI_16x8,
RoseInstrCheckShufti16x8> {
public:
std::array<u8, 32> nib_mask;
std::array<u8, 16> bucket_select_mask;
u32 neg_mask;
s32 offset;
const RoseInstruction *target;
RoseInstrCheckShufti16x8(std::array<u8, 32> nib_mask_in,
std::array<u8, 16> bucket_select_mask_in,
u32 neg_mask_in, s32 offset_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_SHUFTI_32x8,
ROSE_STRUCT_CHECK_SHUFTI_32x8,
RoseInstrCheckShufti32x8> {
public:
std::array<u8, 16> hi_mask;
std::array<u8, 16> lo_mask;
std::array<u8, 32> bucket_select_mask;
u32 neg_mask;
s32 offset;
const RoseInstruction *target;
RoseInstrCheckShufti32x8(std::array<u8, 16> hi_mask_in,
std::array<u8, 16> lo_mask_in,
std::array<u8, 32> bucket_select_mask_in,
u32 neg_mask_in, s32 offset_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_SHUFTI_16x16,
ROSE_STRUCT_CHECK_SHUFTI_16x16,
RoseInstrCheckShufti16x16> {
public:
std::array<u8, 32> hi_mask;
std::array<u8, 32> lo_mask;
std::array<u8, 32> bucket_select_mask;
u32 neg_mask;
s32 offset;
const RoseInstruction *target;
RoseInstrCheckShufti16x16(std::array<u8, 32> hi_mask_in,
std::array<u8, 32> lo_mask_in,
std::array<u8, 32> bucket_select_mask_in,
u32 neg_mask_in, s32 offset_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_SHUFTI_32x16,
ROSE_STRUCT_CHECK_SHUFTI_32x16,
RoseInstrCheckShufti32x16> {
public:
std::array<u8, 32> hi_mask;
std::array<u8, 32> lo_mask;
std::array<u8, 32> bucket_select_mask_hi;
std::array<u8, 32> bucket_select_mask_lo;
u32 neg_mask;
s32 offset;
const RoseInstruction *target;
RoseInstrCheckShufti32x16(std::array<u8, 32> hi_mask_in,
std::array<u8, 32> lo_mask_in,
std::array<u8, 32> bucket_select_mask_hi_in,
std::array<u8, 32> bucket_select_mask_lo_in,
u32 neg_mask_in, s32 offset_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_INFIX,
ROSE_STRUCT_CHECK_INFIX,
RoseInstrCheckInfix> {
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<ROSE_INSTR_CHECK_PREFIX,
ROSE_STRUCT_CHECK_PREFIX,
RoseInstrCheckPrefix> {
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<ROSE_INSTR_PUSH_DELAYED,
ROSE_STRUCT_PUSH_DELAYED,
RoseInstrPushDelayed> {
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<ROSE_INSTR_CATCH_UP, ROSE_STRUCT_CATCH_UP,
RoseInstrCatchUp> {
public:
~RoseInstrCatchUp() override;
};
class RoseInstrCatchUpMpv
: public RoseInstrBaseTrivial<ROSE_INSTR_CATCH_UP_MPV,
ROSE_STRUCT_CATCH_UP_MPV,
RoseInstrCatchUpMpv> {
public:
~RoseInstrCatchUpMpv() override;
};
class RoseInstrSomAdjust
: public RoseInstrBaseNoTargets<ROSE_INSTR_SOM_ADJUST,
ROSE_STRUCT_SOM_ADJUST,
RoseInstrSomAdjust> {
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<ROSE_INSTR_SOM_LEFTFIX,
ROSE_STRUCT_SOM_LEFTFIX,
RoseInstrSomLeftfix> {
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<ROSE_INSTR_SOM_FROM_REPORT,
ROSE_STRUCT_SOM_FROM_REPORT,
RoseInstrSomFromReport> {
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<ROSE_INSTR_SOM_ZERO, ROSE_STRUCT_SOM_ZERO,
RoseInstrSomZero> {
public:
~RoseInstrSomZero() override;
};
class RoseInstrTriggerInfix
: public RoseInstrBaseNoTargets<ROSE_INSTR_TRIGGER_INFIX,
ROSE_STRUCT_TRIGGER_INFIX,
RoseInstrTriggerInfix> {
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<ROSE_INSTR_TRIGGER_SUFFIX,
ROSE_STRUCT_TRIGGER_SUFFIX,
RoseInstrTriggerSuffix> {
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<ROSE_INSTR_DEDUPE, ROSE_STRUCT_DEDUPE,
RoseInstrDedupe> {
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<ROSE_INSTR_DEDUPE_SOM,
ROSE_STRUCT_DEDUPE_SOM,
RoseInstrDedupeSom> {
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<ROSE_INSTR_REPORT_CHAIN,
ROSE_STRUCT_REPORT_CHAIN,
RoseInstrReportChain> {
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<ROSE_INSTR_REPORT_SOM_INT,
ROSE_STRUCT_REPORT_SOM_INT,
RoseInstrReportSomInt> {
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<ROSE_INSTR_REPORT_SOM_AWARE,
ROSE_STRUCT_REPORT_SOM_AWARE,
RoseInstrReportSomAware> {
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<ROSE_INSTR_REPORT, ROSE_STRUCT_REPORT,
RoseInstrReport> {
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<ROSE_INSTR_REPORT_EXHAUST,
ROSE_STRUCT_REPORT_EXHAUST,
RoseInstrReportExhaust> {
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<ROSE_INSTR_REPORT_SOM,
ROSE_STRUCT_REPORT_SOM,
RoseInstrReportSom> {
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<ROSE_INSTR_REPORT_SOM_EXHAUST,
ROSE_STRUCT_REPORT_SOM_EXHAUST,
RoseInstrReportSomExhaust> {
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<ROSE_INSTR_DEDUPE_AND_REPORT,
ROSE_STRUCT_DEDUPE_AND_REPORT,
RoseInstrDedupeAndReport> {
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<ROSE_INSTR_FINAL_REPORT,
ROSE_STRUCT_FINAL_REPORT,
RoseInstrFinalReport> {
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<ROSE_INSTR_CHECK_EXHAUSTED,
ROSE_STRUCT_CHECK_EXHAUSTED,
RoseInstrCheckExhausted> {
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<ROSE_INSTR_CHECK_MIN_LENGTH,
ROSE_STRUCT_CHECK_MIN_LENGTH,
RoseInstrCheckMinLength> {
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<ROSE_INSTR_SET_STATE, ROSE_STRUCT_SET_STATE,
RoseInstrSetState> {
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<ROSE_INSTR_SET_GROUPS,
ROSE_STRUCT_SET_GROUPS,
RoseInstrSetGroups> {
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<ROSE_INSTR_SQUASH_GROUPS,
ROSE_STRUCT_SQUASH_GROUPS,
RoseInstrSquashGroups> {
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<ROSE_INSTR_CHECK_STATE,
ROSE_STRUCT_CHECK_STATE,
RoseInstrCheckState> {
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<ROSE_INSTR_SPARSE_ITER_BEGIN,
ROSE_STRUCT_SPARSE_ITER_BEGIN,
RoseInstrSparseIterBegin> {
public:
u32 num_keys; // total number of multibit keys
std::vector<std::pair<u32, const RoseInstruction *>> 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<ROSE_INSTR_SPARSE_ITER_NEXT,
ROSE_STRUCT_SPARSE_ITER_NEXT,
RoseInstrSparseIterNext> {
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<const RoseInstrSparseIterBegin *>(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<ROSE_INSTR_SPARSE_ITER_ANY,
ROSE_STRUCT_SPARSE_ITER_ANY,
RoseInstrSparseIterAny> {
public:
u32 num_keys; // total number of multibit keys
std::vector<u32> keys;
const RoseInstruction *target;
RoseInstrSparseIterAny(u32 num_keys_in, std::vector<u32> 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<ROSE_INSTR_ENGINES_EOD,
ROSE_STRUCT_ENGINES_EOD,
RoseInstrEnginesEod> {
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<ROSE_INSTR_SUFFIXES_EOD,
ROSE_STRUCT_SUFFIXES_EOD,
RoseInstrSuffixesEod> {
public:
~RoseInstrSuffixesEod() override;
};
class RoseInstrMatcherEod : public RoseInstrBaseTrivial<ROSE_INSTR_MATCHER_EOD,
ROSE_STRUCT_MATCHER_EOD,
RoseInstrMatcherEod> {
public:
~RoseInstrMatcherEod() override;
};
class RoseInstrCheckLongLit
: public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LONG_LIT,
ROSE_STRUCT_CHECK_LONG_LIT,
RoseInstrCheckLongLit> {
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<ROSE_INSTR_CHECK_LONG_LIT_NOCASE,
ROSE_STRUCT_CHECK_LONG_LIT_NOCASE,
RoseInstrCheckLongLitNocase> {
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<ROSE_INSTR_CHECK_MED_LIT,
ROSE_STRUCT_CHECK_MED_LIT,
RoseInstrCheckMedLit> {
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<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
RoseInstrCheckMedLitNocase> {
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<ROSE_INSTR_CLEAR_WORK_DONE,
ROSE_STRUCT_CLEAR_WORK_DONE,
RoseInstrClearWorkDone> {
public:
~RoseInstrClearWorkDone() override;
};
class RoseInstrMultipathLookaround
: public RoseInstrBaseOneTarget<ROSE_INSTR_MULTIPATH_LOOKAROUND,
ROSE_STRUCT_MULTIPATH_LOOKAROUND,
RoseInstrMultipathLookaround> {
public:
std::vector<std::vector<LookEntry>> multi_look;
s32 last_start;
std::array<u8, 16> start_mask;
const RoseInstruction *target;
RoseInstrMultipathLookaround(std::vector<std::vector<LookEntry>> ml,
s32 last_start_in,
std::array<u8, 16> 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<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_16x8,
ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_16x8,
RoseInstrCheckMultipathShufti16x8> {
public:
std::array<u8, 32> nib_mask;
std::array<u8, 64> bucket_select_mask;
std::array<u8, 64> 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<u8, 32> nib_mask_in,
std::array<u8, 64> bucket_select_mask_in,
std::array<u8, 64> data_select_mask_in,
u16 hi_bits_mask_in, u16 lo_bits_mask_in,
u16 neg_mask_in, s32 base_offset_in,
s32 last_start_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x8,
ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x8,
RoseInstrCheckMultipathShufti32x8> {
public:
std::array<u8, 32> hi_mask;
std::array<u8, 32> lo_mask;
std::array<u8, 64> bucket_select_mask;
std::array<u8, 64> 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<u8, 32> hi_mask_in,
std::array<u8, 32> lo_mask_in,
std::array<u8, 64> bucket_select_mask_in,
std::array<u8, 64> data_select_mask_in,
u32 hi_bits_mask_in, u32 lo_bits_mask_in,
u32 neg_mask_in, s32 base_offset_in,
s32 last_start_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_32x16,
ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_32x16,
RoseInstrCheckMultipathShufti32x16> {
public:
std::array<u8, 32> hi_mask;
std::array<u8, 32> lo_mask;
std::array<u8, 64> bucket_select_mask_hi;
std::array<u8, 64> bucket_select_mask_lo;
std::array<u8, 64> 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<u8, 32> hi_mask_in,
std::array<u8, 32> lo_mask_in,
std::array<u8, 64> bucket_select_mask_hi_in,
std::array<u8, 64> bucket_select_mask_lo_in,
std::array<u8, 64> data_select_mask_in,
u32 hi_bits_mask_in, u32 lo_bits_mask_in,
u32 neg_mask_in, s32 base_offset_in,
s32 last_start_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64,
RoseInstrCheckMultipathShufti64> {
public:
std::array<u8, 32> hi_mask;
std::array<u8, 32> lo_mask;
std::array<u8, 64> bucket_select_mask;
std::array<u8, 64> 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<u8, 32> hi_mask_in,
std::array<u8, 32> lo_mask_in,
std::array<u8, 64> bucket_select_mask_in,
std::array<u8, 64> data_select_mask_in,
u64a hi_bits_mask_in, u64a lo_bits_mask_in,
u64a neg_mask_in, s32 base_offset_in,
s32 last_start_in,
const RoseInstruction *target_in)
: 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<ROSE_INSTR_INCLUDED_JUMP,
ROSE_STRUCT_INCLUDED_JUMP,
RoseInstrIncludedJump> {
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<int>(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<ROSE_INSTR_SET_LOGICAL,
ROSE_STRUCT_SET_LOGICAL,
RoseInstrSetLogical> {
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<ROSE_INSTR_SET_COMBINATION,
ROSE_STRUCT_SET_COMBINATION,
RoseInstrSetCombination> {
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<ROSE_INSTR_FLUSH_COMBINATION,
ROSE_STRUCT_FLUSH_COMBINATION,
RoseInstrFlushCombination> {
public:
~RoseInstrFlushCombination() override;
};
class RoseInstrLastFlushCombination
: public RoseInstrBaseTrivial<ROSE_INSTR_LAST_FLUSH_COMBINATION,
ROSE_STRUCT_LAST_FLUSH_COMBINATION,
RoseInstrLastFlushCombination> {
public:
~RoseInstrLastFlushCombination() override;
};
class RoseInstrSetExhaust
: public RoseInstrBaseNoTargets<ROSE_INSTR_SET_EXHAUST,
ROSE_STRUCT_SET_EXHAUST,
RoseInstrSetExhaust> {
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<ROSE_INSTR_END, ROSE_STRUCT_END,
RoseInstrEnd> {
public:
~RoseInstrEnd() override;
};
}
#endif