src/rose/rose_build_impl.h
src/rose/rose_build_infix.cpp
src/rose/rose_build_infix.h
+ src/rose/rose_build_instructions.cpp
+ src/rose/rose_build_instructions.h
src/rose/rose_build_lit_accel.cpp
src/rose/rose_build_lit_accel.h
src/rose/rose_build_long_lit.cpp
#include "rose_build_exclusive.h"
#include "rose_build_groups.h"
#include "rose_build_infix.h"
+#include "rose_build_instructions.h"
#include "rose_build_long_lit.h"
#include "rose_build_lookaround.h"
#include "rose_build_matchers.h"
--- /dev/null
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+#include "rose_build_instructions.h"
+
+#include "rose_build_engine_blob.h"
+#include "util/multibit_build.h"
+#include "util/verify_types.h"
+
+#include <algorithm>
+
+using namespace std;
+
+namespace ue2 {
+/* Destructors to avoid weak vtables. */
+
+RoseInstruction::~RoseInstruction() = default;
+RoseInstrCatchUp::~RoseInstrCatchUp() = default;
+RoseInstrCatchUpMpv::~RoseInstrCatchUpMpv() = default;
+RoseInstrSomZero::~RoseInstrSomZero() = default;
+RoseInstrSuffixesEod::~RoseInstrSuffixesEod() = default;
+RoseInstrMatcherEod::~RoseInstrMatcherEod() = default;
+RoseInstrEnd::~RoseInstrEnd() = default;
+RoseInstrClearWorkDone::~RoseInstrClearWorkDone() = default;
+
+using OffsetMap = RoseInstruction::OffsetMap;
+
+static
+u32 calc_jump(const OffsetMap &offset_map, const RoseInstruction *from,
+ const RoseInstruction *to) {
+ DEBUG_PRINTF("computing relative jump from %p to %p\n", from, to);
+ assert(from && contains(offset_map, from));
+ assert(to && contains(offset_map, to));
+
+ u32 from_offset = offset_map.at(from);
+ u32 to_offset = offset_map.at(to);
+ DEBUG_PRINTF("offsets: %u -> %u\n", from_offset, to_offset);
+ assert(from_offset <= to_offset);
+
+ return to_offset - from_offset;
+}
+
+void RoseInstrAnchoredDelay::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+ inst->anch_id = anch_id;
+ inst->done_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckLitEarly::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->min_offset = min_offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+}
+
+void RoseInstrCheckOnlyEod::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckBounds::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->min_bound = min_bound;
+ inst->max_bound = max_bound;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckNotHandled::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->key = key;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckSingleLookaround::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->offset = offset;
+ inst->reach_index = reach_index;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckLookaround::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->look_index = look_index;
+ inst->reach_index = reach_index;
+ inst->count = count;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMask::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->and_mask = and_mask;
+ inst->cmp_mask = cmp_mask;
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMask32::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(and_mask), end(and_mask), inst->and_mask);
+ copy(begin(cmp_mask), end(cmp_mask), inst->cmp_mask);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckByte::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->and_mask = and_mask;
+ inst->cmp_mask = cmp_mask;
+ inst->negation = negation;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti16x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti32x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti16x16::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckShufti32x16::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask_hi), end(bucket_select_mask_hi),
+ inst->bucket_select_mask_hi);
+ copy(begin(bucket_select_mask_lo), end(bucket_select_mask_lo),
+ inst->bucket_select_mask_lo);
+ inst->neg_mask = neg_mask;
+ inst->offset = offset;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckInfix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->lag = lag;
+ inst->report = report;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckPrefix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->lag = lag;
+ inst->report = report;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrPushDelayed::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->delay = delay;
+ inst->index = index;
+}
+
+void RoseInstrSomAdjust::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->distance = distance;
+}
+
+void RoseInstrSomLeftfix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->lag = lag;
+}
+
+void RoseInstrSomFromReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->som = som;
+}
+
+void RoseInstrTriggerInfix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->cancel = cancel;
+ inst->queue = queue;
+ inst->event = event;
+}
+
+void RoseInstrTriggerSuffix::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->queue = queue;
+ inst->event = event;
+}
+
+void RoseInstrDedupe::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->quash_som = quash_som;
+ inst->dkey = dkey;
+ inst->offset_adjust = offset_adjust;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrDedupeSom::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->quash_som = quash_som;
+ inst->dkey = dkey;
+ inst->offset_adjust = offset_adjust;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrReportChain::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->event = event;
+ inst->top_squash_distance = top_squash_distance;
+}
+
+void RoseInstrReportSomInt::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->som = som;
+}
+
+void RoseInstrReportSomAware::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->som = som;
+}
+
+void RoseInstrReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+}
+
+void RoseInstrReportExhaust::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+ inst->ekey = ekey;
+}
+
+void RoseInstrReportSom::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+}
+
+void RoseInstrReportSomExhaust::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+ inst->ekey = ekey;
+}
+
+void RoseInstrDedupeAndReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->quash_som = quash_som;
+ inst->dkey = dkey;
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrFinalReport::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->onmatch = onmatch;
+ inst->offset_adjust = offset_adjust;
+}
+
+void RoseInstrCheckExhausted::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->ekey = ekey;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMinLength::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->end_adj = end_adj;
+ inst->min_length = min_length;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrSetState::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->index = index;
+}
+
+void RoseInstrSetGroups::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+}
+
+void RoseInstrSquashGroups::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->groups = groups;
+}
+
+void RoseInstrCheckState::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->index = index;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+
+ // Resolve and write the multibit sparse iterator and the jump table.
+ vector<u32> keys;
+ vector<u32> jump_offsets;
+ for (const auto &jump : jump_table) {
+ keys.push_back(jump.first);
+ assert(contains(offset_map, jump.second));
+ jump_offsets.push_back(offset_map.at(jump.second));
+ }
+
+ auto iter = mmbBuildSparseIterator(keys, num_keys);
+ assert(!iter.empty());
+ inst->iter_offset = blob.add_iterator(iter);
+ inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
+
+ // Store offsets for corresponding SPARSE_ITER_NEXT operations.
+ is_written = true;
+ iter_offset = inst->iter_offset;
+ jump_table_offset = inst->jump_table;
+}
+
+void RoseInstrSparseIterNext::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->state = state;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+
+ // Use the same sparse iterator and jump table as the SPARSE_ITER_BEGIN
+ // instruction.
+ assert(begin);
+ assert(contains(offset_map, begin));
+ assert(begin->is_written);
+ inst->iter_offset = begin->iter_offset;
+ inst->jump_table = begin->jump_table_offset;
+}
+
+void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+
+ // Write the multibit sparse iterator.
+ auto iter = mmbBuildSparseIterator(keys, num_keys);
+ assert(!iter.empty());
+ inst->iter_offset = blob.add_iterator(iter);
+}
+
+void RoseInstrEnginesEod::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->iter_offset = iter_offset;
+}
+
+void RoseInstrCheckLongLit::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMedLit::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMedLitNocase::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ assert(!literal.empty());
+ inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
+ inst->lit_length = verify_u32(literal.size());
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrMultipathLookaround::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ inst->look_index = look_index;
+ inst->reach_index = reach_index;
+ inst->count = count;
+ inst->last_start = last_start;
+ copy(begin(start_mask), end(start_mask), inst->start_mask);
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti16x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
+ copy(begin(bucket_select_mask), begin(bucket_select_mask) + 16,
+ inst->bucket_select_mask);
+ copy(begin(data_select_mask), begin(data_select_mask) + 16,
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti32x8::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
+ copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
+ copy(begin(bucket_select_mask), begin(bucket_select_mask) + 32,
+ inst->bucket_select_mask);
+ copy(begin(data_select_mask), begin(data_select_mask) + 32,
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti32x16::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
+ copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
+ copy(begin(bucket_select_mask_hi), begin(bucket_select_mask_hi) + 32,
+ inst->bucket_select_mask_hi);
+ copy(begin(bucket_select_mask_lo), begin(bucket_select_mask_lo) + 32,
+ inst->bucket_select_mask_lo);
+ copy(begin(data_select_mask), begin(data_select_mask) + 32,
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+void RoseInstrCheckMultipathShufti64::write(void *dest, RoseEngineBlob &blob,
+ const OffsetMap &offset_map) const {
+ RoseInstrBase::write(dest, blob, offset_map);
+ auto *inst = static_cast<impl_type *>(dest);
+ copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
+ copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
+ copy(begin(bucket_select_mask), end(bucket_select_mask),
+ inst->bucket_select_mask);
+ copy(begin(data_select_mask), end(data_select_mask),
+ inst->data_select_mask);
+ inst->hi_bits_mask = hi_bits_mask;
+ inst->lo_bits_mask = lo_bits_mask;
+ inst->neg_mask = neg_mask;
+ inst->base_offset = base_offset;
+ inst->last_start = last_start;
+ inst->fail_jump = calc_jump(offset_map, this, target);
+}
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017, 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_program.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 = 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);
+ }
+};
+
+/**
+ * \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 boost::hash_value(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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 boost::hash_value(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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;
+ u32 reach_index;
+ const RoseInstruction *target;
+
+ RoseInstrCheckSingleLookaround(s8 offset_in, u32 reach_index_in,
+ const RoseInstruction *target_in)
+ : offset(offset_in), reach_index(reach_index_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckSingleLookaround &ri) const {
+ return offset == ri.offset && reach_index == ri.reach_index &&
+ target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(static_cast<int>(opcode), offset, reach_index);
+ }
+
+ 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_index == ri.reach_index &&
+ offsets.at(target) == other_offsets.at(ri.target);
+ }
+};
+
+class RoseInstrCheckLookaround
+ : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LOOKAROUND,
+ ROSE_STRUCT_CHECK_LOOKAROUND,
+ RoseInstrCheckLookaround> {
+public:
+ u32 look_index;
+ u32 reach_index;
+ u32 count;
+ const RoseInstruction *target;
+
+ RoseInstrCheckLookaround(u32 look_index_in, u32 reach_index_in,
+ u32 count_in, const RoseInstruction *target_in)
+ : look_index(look_index_in), reach_index(reach_index_in),
+ count(count_in), target(target_in) {}
+
+ bool operator==(const RoseInstrCheckLookaround &ri) const {
+ return look_index == ri.look_index && reach_index == ri.reach_index &&
+ count == ri.count && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(static_cast<int>(opcode), look_index, reach_index,
+ count);
+ }
+
+ 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_index == ri.look_index && reach_index == ri.reach_index &&
+ count == ri.count &&
+ 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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(opcode), num_keys);
+ for (const u32 &key : jump_table | boost::adaptors::map_keys) {
+ boost::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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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:
+ u32 look_index;
+ u32 reach_index;
+ u32 count;
+ s32 last_start;
+ std::array<u8, 16> start_mask;
+ const RoseInstruction *target;
+
+ RoseInstrMultipathLookaround(u32 look_index_in, u32 reach_index_in,
+ u32 count_in, s32 last_start_in,
+ std::array<u8, 16> start_mask_in,
+ const RoseInstruction *target_in)
+ : look_index(look_index_in), reach_index(reach_index_in),
+ count(count_in), last_start(last_start_in),
+ start_mask(std::move(start_mask_in)), target(target_in) {}
+
+ bool operator==(const RoseInstrMultipathLookaround &ri) const {
+ return look_index == ri.look_index && reach_index == ri.reach_index &&
+ count == ri.count && last_start == ri.last_start &&
+ start_mask == ri.start_mask && target == ri.target;
+ }
+
+ size_t hash() const override {
+ return hash_all(static_cast<int>(opcode), look_index, reach_index,
+ count, 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 look_index == ri.look_index && reach_index == ri.reach_index &&
+ count == ri.count && 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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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 RoseInstrEnd
+ : public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
+ RoseInstrEnd> {
+public:
+ ~RoseInstrEnd() override;
+};
+
+}
+#endif
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include "rose_build_engine_blob.h"
#include "rose_build_program.h"
-#include "util/container.h"
-#include "util/multibit_build.h"
-#include "util/verify_types.h"
+
+#include "rose_build_instructions.h"
#include <algorithm>
#include <cstring>
namespace ue2 {
-/* Destructors to avoid weak vtables. */
-
-RoseInstruction::~RoseInstruction() = default;
-RoseInstrCatchUp::~RoseInstrCatchUp() = default;
-RoseInstrCatchUpMpv::~RoseInstrCatchUpMpv() = default;
-RoseInstrSomZero::~RoseInstrSomZero() = default;
-RoseInstrSuffixesEod::~RoseInstrSuffixesEod() = default;
-RoseInstrMatcherEod::~RoseInstrMatcherEod() = default;
-RoseInstrEnd::~RoseInstrEnd() = default;
-RoseInstrClearWorkDone::~RoseInstrClearWorkDone() = default;
-
using OffsetMap = RoseInstruction::OffsetMap;
static
-u32 calc_jump(const OffsetMap &offset_map, const RoseInstruction *from,
- const RoseInstruction *to) {
- DEBUG_PRINTF("computing relative jump from %p to %p\n", from, to);
- assert(from && contains(offset_map, from));
- assert(to && contains(offset_map, to));
-
- u32 from_offset = offset_map.at(from);
- u32 to_offset = offset_map.at(to);
- DEBUG_PRINTF("offsets: %u -> %u\n", from_offset, to_offset);
- assert(from_offset <= to_offset);
-
- return to_offset - from_offset;
-}
-
-void RoseInstrAnchoredDelay::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
- inst->anch_id = anch_id;
- inst->done_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckLitEarly::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->min_offset = min_offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
-}
-
-void RoseInstrCheckOnlyEod::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckBounds::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->min_bound = min_bound;
- inst->max_bound = max_bound;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckNotHandled::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->key = key;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckSingleLookaround::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->offset = offset;
- inst->reach_index = reach_index;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckLookaround::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->look_index = look_index;
- inst->reach_index = reach_index;
- inst->count = count;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMask::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->and_mask = and_mask;
- inst->cmp_mask = cmp_mask;
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMask32::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(and_mask), end(and_mask), inst->and_mask);
- copy(begin(cmp_mask), end(cmp_mask), inst->cmp_mask);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckByte::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->and_mask = and_mask;
- inst->cmp_mask = cmp_mask;
- inst->negation = negation;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti16x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti32x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
-
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti16x16::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckShufti32x16::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask_hi), end(bucket_select_mask_hi),
- inst->bucket_select_mask_hi);
- copy(begin(bucket_select_mask_lo), end(bucket_select_mask_lo),
- inst->bucket_select_mask_lo);
- inst->neg_mask = neg_mask;
- inst->offset = offset;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckInfix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->lag = lag;
- inst->report = report;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckPrefix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->lag = lag;
- inst->report = report;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrPushDelayed::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->delay = delay;
- inst->index = index;
-}
-
-void RoseInstrSomAdjust::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->distance = distance;
-}
-
-void RoseInstrSomLeftfix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->lag = lag;
-}
-
-void RoseInstrSomFromReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->som = som;
-}
-
-void RoseInstrTriggerInfix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->cancel = cancel;
- inst->queue = queue;
- inst->event = event;
-}
-
-void RoseInstrTriggerSuffix::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->queue = queue;
- inst->event = event;
-}
-
-void RoseInstrDedupe::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->quash_som = quash_som;
- inst->dkey = dkey;
- inst->offset_adjust = offset_adjust;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrDedupeSom::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->quash_som = quash_som;
- inst->dkey = dkey;
- inst->offset_adjust = offset_adjust;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrReportChain::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->event = event;
- inst->top_squash_distance = top_squash_distance;
-}
-
-void RoseInstrReportSomInt::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->som = som;
-}
-
-void RoseInstrReportSomAware::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->som = som;
-}
-
-void RoseInstrReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
-}
-
-void RoseInstrReportExhaust::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
- inst->ekey = ekey;
+OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) {
+ OffsetMap offset_map;
+ u32 offset = 0;
+ for (const auto &ri : program) {
+ offset = ROUNDUP_N(offset, ROSE_INSTR_MIN_ALIGN);
+ DEBUG_PRINTF("instr %p (opcode %d) -> offset %u\n", ri.get(),
+ ri->code(), offset);
+ assert(!contains(offset_map, ri.get()));
+ offset_map.emplace(ri.get(), offset);
+ offset += ri->byte_length();
+ }
+ *total_len = offset;
+ return offset_map;
}
-void RoseInstrReportSom::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
+RoseProgram::RoseProgram() {
+ prog.push_back(make_unique<RoseInstrEnd>());
}
-void RoseInstrReportSomExhaust::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
- inst->ekey = ekey;
-}
+RoseProgram::~RoseProgram() = default;
-void RoseInstrDedupeAndReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->quash_som = quash_som;
- inst->dkey = dkey;
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
+RoseProgram::RoseProgram(RoseProgram &&) = default;
+RoseProgram &RoseProgram::operator=(RoseProgram &&) = default;
-void RoseInstrFinalReport::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->onmatch = onmatch;
- inst->offset_adjust = offset_adjust;
+bool RoseProgram::empty() const {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
+ // Empty if we only have one element, the END instruction.
+ return next(prog.begin()) == prog.end();
}
-void RoseInstrCheckExhausted::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->ekey = ekey;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
+const RoseInstruction *RoseProgram::end_instruction() const {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
-void RoseInstrCheckMinLength::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->end_adj = end_adj;
- inst->min_length = min_length;
- inst->fail_jump = calc_jump(offset_map, this, target);
+ return prog.back().get();
}
-void RoseInstrSetState::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->index = index;
+void RoseProgram::update_targets(RoseProgram::iterator it,
+ RoseProgram::iterator it_end,
+ const RoseInstruction *old_target,
+ const RoseInstruction *new_target) {
+ assert(old_target && new_target && old_target != new_target);
+ for (; it != it_end; ++it) {
+ unique_ptr<RoseInstruction> &ri = *it;
+ assert(ri);
+ ri->update_target(old_target, new_target);
+ }
}
-void RoseInstrSetGroups::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
-}
+RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it,
+ unique_ptr<RoseInstruction> ri) {
+ assert(!prog.empty());
+ assert(it != end());
+ assert(prog.back()->code() == ROSE_INSTR_END);
-void RoseInstrSquashGroups::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->groups = groups;
+ return prog.insert(it, move(ri));
}
-void RoseInstrCheckState::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->index = index;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
+RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it,
+ RoseProgram &&block) {
+ assert(!prog.empty());
+ assert(it != end());
+ assert(prog.back()->code() == ROSE_INSTR_END);
-void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->fail_jump = calc_jump(offset_map, this, target);
-
- // Resolve and write the multibit sparse iterator and the jump table.
- vector<u32> keys;
- vector<u32> jump_offsets;
- for (const auto &jump : jump_table) {
- keys.push_back(jump.first);
- assert(contains(offset_map, jump.second));
- jump_offsets.push_back(offset_map.at(jump.second));
+ if (block.empty()) {
+ return it;
}
- auto iter = mmbBuildSparseIterator(keys, num_keys);
- assert(!iter.empty());
- inst->iter_offset = blob.add_iterator(iter);
- inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
+ const RoseInstruction *end_ptr = block.end_instruction();
+ assert(end_ptr->code() == ROSE_INSTR_END);
+ block.prog.pop_back();
- // Store offsets for corresponding SPARSE_ITER_NEXT operations.
- is_written = true;
- iter_offset = inst->iter_offset;
- jump_table_offset = inst->jump_table;
-}
-
-void RoseInstrSparseIterNext::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->state = state;
- inst->fail_jump = calc_jump(offset_map, this, target);
-
- // Use the same sparse iterator and jump table as the SPARSE_ITER_BEGIN
- // instruction.
- assert(begin);
- assert(contains(offset_map, begin));
- assert(begin->is_written);
- inst->iter_offset = begin->iter_offset;
- inst->jump_table = begin->jump_table_offset;
-}
-
-void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->fail_jump = calc_jump(offset_map, this, target);
+ const RoseInstruction *new_target = it->get();
+ update_targets(block.prog.begin(), block.prog.end(), end_ptr, new_target);
- // Write the multibit sparse iterator.
- auto iter = mmbBuildSparseIterator(keys, num_keys);
- assert(!iter.empty());
- inst->iter_offset = blob.add_iterator(iter);
+ // Workaround: container insert() for ranges doesn't return an iterator
+ // in the version of the STL distributed with gcc 4.8.
+ auto dist = distance(prog.begin(), it);
+ prog.insert(it, make_move_iterator(block.prog.begin()),
+ make_move_iterator(block.prog.end()));
+ it = prog.begin();
+ advance(it, dist);
+ return it;
}
-void RoseInstrEnginesEod::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->iter_offset = iter_offset;
-}
-
-void RoseInstrCheckLongLit::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckLongLitNocase::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMedLit::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
-
-void RoseInstrCheckMedLitNocase::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- assert(!literal.empty());
- inst->lit_offset = blob.add(literal.c_str(), literal.size(), 1);
- inst->lit_length = verify_u32(literal.size());
- inst->fail_jump = calc_jump(offset_map, this, target);
+RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first,
+ RoseProgram::iterator last) {
+ return prog.erase(first, last);
}
-void RoseInstrMultipathLookaround::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- inst->look_index = look_index;
- inst->reach_index = reach_index;
- inst->count = count;
- inst->last_start = last_start;
- copy(begin(start_mask), end(start_mask), inst->start_mask);
- inst->fail_jump = calc_jump(offset_map, this, target);
+void RoseProgram::add_before_end(std::unique_ptr<RoseInstruction> ri) {
+ assert(!prog.empty());
+ insert(std::prev(prog.end()), std::move(ri));
}
-void RoseInstrCheckMultipathShufti16x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map)
- const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(nib_mask), end(nib_mask), inst->nib_mask);
- copy(begin(bucket_select_mask), begin(bucket_select_mask) + 16,
- inst->bucket_select_mask);
- copy(begin(data_select_mask), begin(data_select_mask) + 16,
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
+void RoseProgram::add_before_end(RoseProgram &&block) {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
-void RoseInstrCheckMultipathShufti32x8::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map)
- const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
- copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
- copy(begin(bucket_select_mask), begin(bucket_select_mask) + 32,
- inst->bucket_select_mask);
- copy(begin(data_select_mask), begin(data_select_mask) + 32,
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
+ if (block.empty()) {
+ return;
+ }
-void RoseInstrCheckMultipathShufti32x16::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), end(hi_mask), inst->hi_mask);
- copy(begin(lo_mask), end(lo_mask), inst->lo_mask);
- copy(begin(bucket_select_mask_hi), begin(bucket_select_mask_hi) + 32,
- inst->bucket_select_mask_hi);
- copy(begin(bucket_select_mask_lo), begin(bucket_select_mask_lo) + 32,
- inst->bucket_select_mask_lo);
- copy(begin(data_select_mask), begin(data_select_mask) + 32,
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
+ insert(prev(prog.end()), move(block));
}
-void RoseInstrCheckMultipathShufti64::write(void *dest, RoseEngineBlob &blob,
- const OffsetMap &offset_map) const {
- RoseInstrBase::write(dest, blob, offset_map);
- auto *inst = static_cast<impl_type *>(dest);
- copy(begin(hi_mask), begin(hi_mask) + 16, inst->hi_mask);
- copy(begin(lo_mask), begin(lo_mask) + 16, inst->lo_mask);
- copy(begin(bucket_select_mask), end(bucket_select_mask),
- inst->bucket_select_mask);
- copy(begin(data_select_mask), end(data_select_mask),
- inst->data_select_mask);
- inst->hi_bits_mask = hi_bits_mask;
- inst->lo_bits_mask = lo_bits_mask;
- inst->neg_mask = neg_mask;
- inst->base_offset = base_offset;
- inst->last_start = last_start;
- inst->fail_jump = calc_jump(offset_map, this, target);
-}
+void RoseProgram::add_block(RoseProgram &&block) {
+ assert(!prog.empty());
+ assert(prog.back()->code() == ROSE_INSTR_END);
-static
-OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) {
- OffsetMap offset_map;
- u32 offset = 0;
- for (const auto &ri : program) {
- offset = ROUNDUP_N(offset, ROSE_INSTR_MIN_ALIGN);
- DEBUG_PRINTF("instr %p (opcode %d) -> offset %u\n", ri.get(),
- ri->code(), offset);
- assert(!contains(offset_map, ri.get()));
- offset_map.emplace(ri.get(), offset);
- offset += ri->byte_length();
+ if (block.empty()) {
+ return;
}
- *total_len = offset;
- return offset_map;
-}
-RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first,
- RoseProgram::iterator last) {
- return prog.erase(first, last);
+ // Replace pointers to the current END with pointers to the first
+ // instruction in the new sequence.
+ const RoseInstruction *end_ptr = end_instruction();
+ prog.pop_back();
+ update_targets(prog.begin(), prog.end(), end_ptr,
+ block.prog.front().get());
+ prog.insert(prog.end(), make_move_iterator(block.prog.begin()),
+ make_move_iterator(block.prog.end()));
}
bytecode_ptr<char> writeProgram(RoseEngineBlob &blob,
return bytecode;
}
+size_t RoseProgramHash::operator()(const RoseProgram &program) const {
+ size_t v = 0;
+ for (const auto &ri : program) {
+ assert(ri);
+ boost::hash_combine(v, ri->hash());
+ }
+ return v;
+}
+
bool RoseProgramEquivalence::operator()(const RoseProgram &prog1,
const RoseProgram &prog2) const {
if (prog1.size() != prog2.size()) {
#include "rose_build_impl.h"
#include "rose_program.h"
-#include "som/som_operation.h"
#include "util/bytecode_ptr.h"
-#include "util/container.h"
#include "util/hash.h"
#include "util/make_unique.h"
#include "util/ue2_containers.h"
-#include "util/ue2string.h"
-#include <algorithm>
-#include <array>
#include <vector>
-#include <boost/functional/hash/hash_fwd.hpp>
#include <boost/range/adaptor/map.hpp>
namespace ue2 {
class RoseEngineBlob;
-
-/**
- * \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 = 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);
- }
-};
-
-/**
- * \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 boost::hash_value(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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 boost::hash_value(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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;
- u32 reach_index;
- const RoseInstruction *target;
-
- RoseInstrCheckSingleLookaround(s8 offset_in, u32 reach_index_in,
- const RoseInstruction *target_in)
- : offset(offset_in), reach_index(reach_index_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckSingleLookaround &ri) const {
- return offset == ri.offset && reach_index == ri.reach_index &&
- target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(static_cast<int>(opcode), offset, reach_index);
- }
-
- 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_index == ri.reach_index &&
- offsets.at(target) == other_offsets.at(ri.target);
- }
-};
-
-class RoseInstrCheckLookaround
- : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LOOKAROUND,
- ROSE_STRUCT_CHECK_LOOKAROUND,
- RoseInstrCheckLookaround> {
-public:
- u32 look_index;
- u32 reach_index;
- u32 count;
- const RoseInstruction *target;
-
- RoseInstrCheckLookaround(u32 look_index_in, u32 reach_index_in,
- u32 count_in, const RoseInstruction *target_in)
- : look_index(look_index_in), reach_index(reach_index_in),
- count(count_in), target(target_in) {}
-
- bool operator==(const RoseInstrCheckLookaround &ri) const {
- return look_index == ri.look_index && reach_index == ri.reach_index &&
- count == ri.count && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(static_cast<int>(opcode), look_index, reach_index,
- count);
- }
-
- 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_index == ri.look_index && reach_index == ri.reach_index &&
- count == ri.count &&
- 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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(opcode), num_keys);
- for (const u32 &key : jump_table | boost::adaptors::map_keys) {
- boost::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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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:
- u32 look_index;
- u32 reach_index;
- u32 count;
- s32 last_start;
- std::array<u8, 16> start_mask;
- const RoseInstruction *target;
-
- RoseInstrMultipathLookaround(u32 look_index_in, u32 reach_index_in,
- u32 count_in, s32 last_start_in,
- std::array<u8, 16> start_mask_in,
- const RoseInstruction *target_in)
- : look_index(look_index_in), reach_index(reach_index_in),
- count(count_in), last_start(last_start_in),
- start_mask(std::move(start_mask_in)), target(target_in) {}
-
- bool operator==(const RoseInstrMultipathLookaround &ri) const {
- return look_index == ri.look_index && reach_index == ri.reach_index &&
- count == ri.count && last_start == ri.last_start &&
- start_mask == ri.start_mask && target == ri.target;
- }
-
- size_t hash() const override {
- return hash_all(static_cast<int>(opcode), look_index, reach_index,
- count, 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 look_index == ri.look_index && reach_index == ri.reach_index &&
- count == ri.count && 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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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(static_cast<int>(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 RoseInstrEnd
- : public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
- RoseInstrEnd> {
-public:
- ~RoseInstrEnd() override;
-};
+class RoseInstruction;
/**
* \brief Container for a list of program instructions.
std::vector<std::unique_ptr<RoseInstruction>> prog;
public:
- RoseProgram() {
- prog.push_back(make_unique<RoseInstrEnd>());
- }
+ RoseProgram();
+ ~RoseProgram();
+ RoseProgram(const RoseProgram &) = delete;
+ RoseProgram(RoseProgram &&);
+ RoseProgram &operator=(const RoseProgram &) = delete;
+ RoseProgram &operator=(RoseProgram &&);
- bool empty() const {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
- // Empty if we only have one element, the END instruction.
- return std::next(prog.begin()) == prog.end();
- }
+ bool empty() const;
size_t size() const { return prog.size(); }
const_reverse_iterator rend() const { return prog.rend(); }
/** \brief Retrieve a pointer to the terminating ROSE_INSTR_END. */
- const RoseInstruction *end_instruction() const {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- return prog.back().get();
- }
+ const RoseInstruction *end_instruction() const;
static void update_targets(iterator it, iterator it_end,
const RoseInstruction *old_target,
- const RoseInstruction *new_target) {
- assert(old_target && new_target && old_target != new_target);
- for (; it != it_end; ++it) {
- std::unique_ptr<RoseInstruction> &ri = *it;
- assert(ri);
- ri->update_target(old_target, new_target);
- }
- }
-
- iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri) {
- assert(!prog.empty());
- assert(it != end());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- return prog.insert(it, std::move(ri));
- }
-
- iterator insert(iterator it, RoseProgram &&block) {
- assert(!prog.empty());
- assert(it != end());
- assert(prog.back()->code() == ROSE_INSTR_END);
+ const RoseInstruction *new_target);
- if (block.empty()) {
- return it;
- }
+ iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri);
- const RoseInstruction *end_ptr = block.end_instruction();
- assert(end_ptr->code() == ROSE_INSTR_END);
- block.prog.pop_back();
-
- const RoseInstruction *new_target = it->get();
- update_targets(block.prog.begin(), block.prog.end(), end_ptr,
- new_target);
-
- // Workaround: container insert() for ranges doesn't return an iterator
- // in the version of the STL distributed with gcc 4.8.
- auto dist = distance(prog.begin(), it);
- prog.insert(it, std::make_move_iterator(block.prog.begin()),
- std::make_move_iterator(block.prog.end()));
- it = prog.begin();
- std::advance(it, dist);
- return it;
- }
+ iterator insert(iterator it, RoseProgram &&block);
/* Note: takes iterator rather than const_iterator to support toolchains
* with pre-C++11 standard libraries (i.e., gcc-4.8). */
* \brief Adds this instruction to the program just before the terminating
* ROSE_INSTR_END.
*/
- void add_before_end(std::unique_ptr<RoseInstruction> ri) {
- assert(!prog.empty());
- insert(std::prev(prog.end()), std::move(ri));
- }
+ void add_before_end(std::unique_ptr<RoseInstruction> ri);
/**
* \brief Adds this block to the program just before the terminating
*
* Any existing instruction that was jumping to end continues to do so.
*/
- void add_before_end(RoseProgram &&block) {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- if (block.empty()) {
- return;
- }
-
- insert(std::prev(prog.end()), std::move(block));
- }
-
+ void add_before_end(RoseProgram &&block);
/**
* \brief Append this program block, replacing our current ROSE_INSTR_END.
*
* Any existing instruction that was jumping to end, now leads to the newly
* added block.
*/
- void add_block(RoseProgram &&block) {
- assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
-
- if (block.empty()) {
- return;
- }
-
- // Replace pointers to the current END with pointers to the first
- // instruction in the new sequence.
- const RoseInstruction *end_ptr = end_instruction();
- prog.pop_back();
- update_targets(prog.begin(), prog.end(), end_ptr,
- block.prog.front().get());
- prog.insert(prog.end(), std::make_move_iterator(block.prog.begin()),
- std::make_move_iterator(block.prog.end()));
- }
+ void add_block(RoseProgram &&block);
/**
* \brief Replace the instruction pointed to by the given iterator.
template<class Iter>
void replace(Iter it, std::unique_ptr<RoseInstruction> ri) {
assert(!prog.empty());
- assert(prog.back()->code() == ROSE_INSTR_END);
const RoseInstruction *old_ptr = it->get();
*it = move(ri);
update_targets(prog.begin(), prog.end(), old_ptr, it->get());
-
- assert(prog.back()->code() == ROSE_INSTR_END);
}
};
class RoseProgramHash {
public:
- size_t operator()(const RoseProgram &program) const {
- size_t v = 0;
- for (const auto &ri : program) {
- assert(ri);
- boost::hash_combine(v, ri->hash());
- }
- return v;
- }
+ size_t operator()(const RoseProgram &program) const;
};
class RoseProgramEquivalence {