From 1287b70f4b3a41c78b90dd308ded609279650b61 Mon Sep 17 00:00:00 2001 From: Alex Coyte Date: Wed, 26 Apr 2017 10:38:55 +1000 Subject: [PATCH] split out instruction details to own files --- CMakeLists.txt | 2 + src/rose/rose_build_bytecode.cpp | 1 + src/rose/rose_build_instructions.cpp | 616 +++++++ src/rose/rose_build_instructions.h | 2143 +++++++++++++++++++++++++ src/rose/rose_build_program.cpp | 700 ++------ src/rose/rose_build_program.h | 2218 +------------------------- 6 files changed, 2896 insertions(+), 2784 deletions(-) create mode 100644 src/rose/rose_build_instructions.cpp create mode 100644 src/rose/rose_build_instructions.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 34405097..f03969ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -955,6 +955,8 @@ SET (hs_SRCS 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 diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index ae352e2e..94927558 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -38,6 +38,7 @@ #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" diff --git a/src/rose/rose_build_instructions.cpp b/src/rose/rose_build_instructions.cpp new file mode 100644 index 00000000..f39fbe98 --- /dev/null +++ b/src/rose/rose_build_instructions.cpp @@ -0,0 +1,616 @@ +/* + * 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 + +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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(dest); + inst->fail_jump = calc_jump(offset_map, this, target); + + // Resolve and write the multibit sparse iterator and the jump table. + vector keys; + vector 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(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(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(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(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(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(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(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(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(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(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(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(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); +} + +} diff --git a/src/rose/rose_build_instructions.h b/src/rose/rose_build_instructions.h new file mode 100644 index 00000000..06d146a5 --- /dev/null +++ b/src/rose/rose_build_instructions.h @@ -0,0 +1,2143 @@ +/* + * 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; + + /** + * \brief Writes a concrete implementation of this instruction. + * + * Other data that this instruction depends on is written directly into the + * blob, while the instruction structure itself (of size given by + * the byte_length() function) is written to dest. + */ + virtual void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const = 0; + + /** + * \brief Update a target pointer. + * + * If this instruction contains any reference to the old target, replace it + * with the new one. + */ + virtual void update_target(const RoseInstruction *old_target, + const RoseInstruction *new_target) = 0; + + /** + * \brief True if these instructions are equivalent within their own + * programs. + * + * Checks that any pointers to other instructions point to the same + * offsets. + */ + bool equiv(const RoseInstruction &other, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return equiv_impl(other, offsets, other_offsets); + } + +private: + virtual bool equiv_impl(const RoseInstruction &other, + const OffsetMap &offsets, + const OffsetMap &other_offsets) const = 0; +}; + +/** + * \brief Templated implementation class to handle boring boilerplate code. + */ +template +class RoseInstrBase : public RoseInstruction { +protected: + static constexpr RoseInstructionCode opcode = Opcode; + using impl_type = ImplType; + +public: + RoseInstructionCode code() const override { return opcode; } + + size_t byte_length() const override { + return sizeof(impl_type); + } + + /** + * Note: this implementation simply zeroes the destination region and + * writes in the correct opcode. This is sufficient for trivial + * instructions, but instructions with data members will want to override + * it. + */ + void write(void *dest, RoseEngineBlob &, + const RoseInstruction::OffsetMap &) const override { + assert(dest != nullptr); + assert(ISALIGNED_N(dest, ROSE_INSTR_MIN_ALIGN)); + + impl_type *inst = static_cast(dest); + memset(inst, 0, sizeof(impl_type)); + inst->code = verify_u8(opcode); + } + +private: + bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets, + const OffsetMap &other_offsets) const override { + const auto *ri_that = dynamic_cast(&other); + if (!ri_that) { + return false; + } + const auto *ri_this = dynamic_cast(this); + assert(ri_this); + return ri_this->equiv_to(*ri_that, offsets, other_offsets); + } +}; + +/** + * \brief Refinement of RoseInstrBase to use for instructions that have + * just a single target member, called "target". + */ +template +class RoseInstrBaseOneTarget + : public RoseInstrBase { +public: + void update_target(const RoseInstruction *old_target, + const RoseInstruction *new_target) override { + RoseInstrType *ri = dynamic_cast(this); + assert(ri); + if (ri->target == old_target) { + ri->target = new_target; + } + } +}; + +/** + * \brief Refinement of RoseInstrBase to use for instructions that have no + * targets. + */ +template +class RoseInstrBaseNoTargets + : public RoseInstrBase { +public: + void update_target(const RoseInstruction *, + const RoseInstruction *) override {} +}; + +/** + * \brief Refinement of RoseInstrBaseNoTargets to use for instructions that + * have no members at all, just an opcode. + */ +template +class RoseInstrBaseTrivial + : public RoseInstrBaseNoTargets { +public: + virtual bool operator==(const RoseInstrType &) const { return true; } + + size_t hash() const override { + return boost::hash_value(static_cast(Opcode)); + } + + bool equiv_to(const RoseInstrType &, const RoseInstruction::OffsetMap &, + const RoseInstruction::OffsetMap &) const { + return true; + } +}; + +//// +//// Concrete implementation classes start here. +//// + +class RoseInstrAnchoredDelay + : public RoseInstrBaseOneTarget { +public: + rose_group groups; + u32 anch_id; + const RoseInstruction *target; + + RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in, + const RoseInstruction *target_in) + : groups(groups_in), anch_id(anch_id_in), target(target_in) {} + + bool operator==(const RoseInstrAnchoredDelay &ri) const { + return groups == ri.groups && anch_id == ri.anch_id + && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), groups, anch_id); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return groups == ri.groups && anch_id == ri.anch_id + && offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckLitEarly + : public RoseInstrBaseOneTarget { +public: + u32 min_offset; + const RoseInstruction *target; + + RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in) + : min_offset(min_offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckLitEarly &ri) const { + return min_offset == ri.min_offset && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), min_offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return min_offset == ri.min_offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckGroups + : public RoseInstrBaseNoTargets { +public: + rose_group groups; + + explicit RoseInstrCheckGroups(rose_group groups_in) : groups(groups_in) {} + + bool operator==(const RoseInstrCheckGroups &ri) const { + return groups == ri.groups; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), groups); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &, + const OffsetMap &) const { + return groups == ri.groups; + } +}; + +class RoseInstrCheckOnlyEod + : public RoseInstrBaseOneTarget { +public: + const RoseInstruction *target; + + explicit RoseInstrCheckOnlyEod(const RoseInstruction *target_in) + : target(target_in) {} + + bool operator==(const RoseInstrCheckOnlyEod &ri) const { + return target == ri.target; + } + + size_t hash() const override { + return boost::hash_value(static_cast(opcode)); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckOnlyEod &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckBounds + : public RoseInstrBaseOneTarget { +public: + u64a min_bound; + u64a max_bound; + const RoseInstruction *target; + + RoseInstrCheckBounds(u64a min, u64a max, const RoseInstruction *target_in) + : min_bound(min), max_bound(max), target(target_in) {} + + bool operator==(const RoseInstrCheckBounds &ri) const { + return min_bound == ri.min_bound && max_bound == ri.max_bound && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), min_bound, max_bound); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckBounds &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return min_bound == ri.min_bound && max_bound == ri.max_bound && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckNotHandled + : public RoseInstrBaseOneTarget { +public: + u32 key; + const RoseInstruction *target; + + RoseInstrCheckNotHandled(u32 key_in, const RoseInstruction *target_in) + : key(key_in), target(target_in) {} + + bool operator==(const RoseInstrCheckNotHandled &ri) const { + return key == ri.key && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), key); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckNotHandled &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return key == ri.key && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckSingleLookaround + : public RoseInstrBaseOneTarget { +public: + s8 offset; + 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(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 { +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(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 { +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(opcode), and_mask, cmp_mask, neg_mask, + offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMask &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMask32 + : public RoseInstrBaseOneTarget { +public: + std::array and_mask; + std::array cmp_mask; + u32 neg_mask; + s32 offset; + const RoseInstruction *target; + + RoseInstrCheckMask32(std::array and_mask_in, + std::array cmp_mask_in, u32 neg_mask_in, + s32 offset_in, const RoseInstruction *target_in) + : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)), + neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckMask32 &ri) const { + return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), and_mask, cmp_mask, neg_mask, + offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMask32 &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckByte + : public RoseInstrBaseOneTarget { +public: + u8 and_mask; + u8 cmp_mask; + u8 negation; + s32 offset; + const RoseInstruction *target; + + RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in, + s32 offset_in, const RoseInstruction *target_in) + : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in), + offset(offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckByte &ri) const { + return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && + negation == ri.negation && offset == ri.offset && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), and_mask, cmp_mask, negation, + offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && + negation == ri.negation && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckShufti16x8 + : public RoseInstrBaseOneTarget { +public: + std::array nib_mask; + std::array bucket_select_mask; + u32 neg_mask; + s32 offset; + const RoseInstruction *target; + + RoseInstrCheckShufti16x8(std::array nib_mask_in, + std::array bucket_select_mask_in, + u32 neg_mask_in, s32 offset_in, + const RoseInstruction *target_in) + : nib_mask(std::move(nib_mask_in)), + bucket_select_mask(std::move(bucket_select_mask_in)), + neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckShufti16x8 &ri) const { + return nib_mask == ri.nib_mask && + bucket_select_mask == ri.bucket_select_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), nib_mask, + bucket_select_mask, neg_mask, offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return nib_mask == ri.nib_mask && + bucket_select_mask == ri.bucket_select_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckShufti32x8 + : public RoseInstrBaseOneTarget { +public: + std::array hi_mask; + std::array lo_mask; + std::array bucket_select_mask; + u32 neg_mask; + s32 offset; + const RoseInstruction *target; + + RoseInstrCheckShufti32x8(std::array hi_mask_in, + std::array lo_mask_in, + std::array bucket_select_mask_in, + u32 neg_mask_in, s32 offset_in, + const RoseInstruction *target_in) + : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), + bucket_select_mask(std::move(bucket_select_mask_in)), + neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckShufti32x8 &ri) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), hi_mask, lo_mask, + bucket_select_mask, neg_mask, offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckShufti16x16 + : public RoseInstrBaseOneTarget { +public: + std::array hi_mask; + std::array lo_mask; + std::array bucket_select_mask; + u32 neg_mask; + s32 offset; + const RoseInstruction *target; + + RoseInstrCheckShufti16x16(std::array hi_mask_in, + std::array lo_mask_in, + std::array bucket_select_mask_in, + u32 neg_mask_in, s32 offset_in, + const RoseInstruction *target_in) + : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), + bucket_select_mask(std::move(bucket_select_mask_in)), + neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckShufti16x16 &ri) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), hi_mask, lo_mask, + bucket_select_mask, neg_mask, offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + neg_mask == ri.neg_mask && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckShufti32x16 + : public RoseInstrBaseOneTarget { +public: + std::array hi_mask; + std::array lo_mask; + std::array bucket_select_mask_hi; + std::array bucket_select_mask_lo; + u32 neg_mask; + s32 offset; + const RoseInstruction *target; + + RoseInstrCheckShufti32x16(std::array hi_mask_in, + std::array lo_mask_in, + std::array bucket_select_mask_hi_in, + std::array bucket_select_mask_lo_in, + u32 neg_mask_in, s32 offset_in, + const RoseInstruction *target_in) + : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), + bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)), + bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)), + neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} + + bool operator==(const RoseInstrCheckShufti32x16 &ri) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask_hi == ri.bucket_select_mask_hi && + bucket_select_mask_lo == ri.bucket_select_mask_lo && + neg_mask == ri.neg_mask && offset == ri.offset && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), hi_mask, lo_mask, + bucket_select_mask_hi, bucket_select_mask_lo, + neg_mask, offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask_hi == ri.bucket_select_mask_hi && + bucket_select_mask_lo == ri.bucket_select_mask_lo && + neg_mask == ri.neg_mask && offset == ri.offset && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckInfix + : public RoseInstrBaseOneTarget { +public: + u32 queue; + u32 lag; + ReportID report; + const RoseInstruction *target; + + RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in, + const RoseInstruction *target_in) + : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {} + + bool operator==(const RoseInstrCheckInfix &ri) const { + return queue == ri.queue && lag == ri.lag && report == ri.report && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), queue, lag, report); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return queue == ri.queue && lag == ri.lag && report == ri.report && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckPrefix + : public RoseInstrBaseOneTarget { +public: + u32 queue; + u32 lag; + ReportID report; + const RoseInstruction *target; + + RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in, + const RoseInstruction *target_in) + : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {} + + bool operator==(const RoseInstrCheckPrefix &ri) const { + return queue == ri.queue && lag == ri.lag && report == ri.report && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), queue, lag, report); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return queue == ri.queue && lag == ri.lag && report == ri.report && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrPushDelayed + : public RoseInstrBaseNoTargets { +public: + u8 delay; + u32 index; + + RoseInstrPushDelayed(u8 delay_in, u32 index_in) + : delay(delay_in), index(index_in) {} + + bool operator==(const RoseInstrPushDelayed &ri) const { + return delay == ri.delay && index == ri.index; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), delay, index); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &, + const OffsetMap &) const { + return delay == ri.delay && index == ri.index; + } +}; + +class RoseInstrCatchUp + : public RoseInstrBaseTrivial { +public: + ~RoseInstrCatchUp() override; +}; + +class RoseInstrCatchUpMpv + : public RoseInstrBaseTrivial { +public: + ~RoseInstrCatchUpMpv() override; +}; + +class RoseInstrSomAdjust + : public RoseInstrBaseNoTargets { +public: + u32 distance; + + explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {} + + bool operator==(const RoseInstrSomAdjust &ri) const { + return distance == ri.distance; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), distance); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &, + const OffsetMap &) const { + return distance == ri.distance; + } +}; + +class RoseInstrSomLeftfix + : public RoseInstrBaseNoTargets { +public: + u32 queue; + u32 lag; + + RoseInstrSomLeftfix(u32 queue_in, u32 lag_in) + : queue(queue_in), lag(lag_in) {} + + bool operator==(const RoseInstrSomLeftfix &ri) const { + return queue == ri.queue && lag == ri.lag; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), queue, lag); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &, + const OffsetMap &) const { + return queue == ri.queue && lag == ri.lag; + } +}; + +class RoseInstrSomFromReport + : public RoseInstrBaseNoTargets { +public: + som_operation som; + + RoseInstrSomFromReport() { + std::memset(&som, 0, sizeof(som)); + } + + bool operator==(const RoseInstrSomFromReport &ri) const { + return std::memcmp(&som, &ri.som, sizeof(som)) == 0; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), som.type, som.onmatch); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &, + const OffsetMap &) const { + return std::memcmp(&som, &ri.som, sizeof(som)) == 0; + } +}; + +class RoseInstrSomZero + : public RoseInstrBaseTrivial { +public: + ~RoseInstrSomZero() override; +}; + +class RoseInstrTriggerInfix + : public RoseInstrBaseNoTargets { +public: + u8 cancel; + u32 queue; + u32 event; + + RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in) + : cancel(cancel_in), queue(queue_in), event(event_in) {} + + bool operator==(const RoseInstrTriggerInfix &ri) const { + return cancel == ri.cancel && queue == ri.queue && event == ri.event; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), cancel, queue, event); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &, + const OffsetMap &) const { + return cancel == ri.cancel && queue == ri.queue && event == ri.event; + } +}; + +class RoseInstrTriggerSuffix + : public RoseInstrBaseNoTargets { +public: + u32 queue; + u32 event; + + RoseInstrTriggerSuffix(u32 queue_in, u32 event_in) + : queue(queue_in), event(event_in) {} + + bool operator==(const RoseInstrTriggerSuffix &ri) const { + return queue == ri.queue && event == ri.event; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), queue, event); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &, + const OffsetMap &) const { + return queue == ri.queue && event == ri.event; + } +}; + +class RoseInstrDedupe + : public RoseInstrBaseOneTarget { +public: + u8 quash_som; + u32 dkey; + s32 offset_adjust; + const RoseInstruction *target; + + RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in, + const RoseInstruction *target_in) + : quash_som(quash_som_in), dkey(dkey_in), + offset_adjust(offset_adjust_in), target(target_in) {} + + bool operator==(const RoseInstrDedupe &ri) const { + return quash_som == ri.quash_som && dkey == ri.dkey && + offset_adjust == ri.offset_adjust && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), quash_som, dkey, + offset_adjust); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return quash_som == ri.quash_som && dkey == ri.dkey && + offset_adjust == ri.offset_adjust && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrDedupeSom + : public RoseInstrBaseOneTarget { +public: + u8 quash_som; + u32 dkey; + s32 offset_adjust; + const RoseInstruction *target; + + RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in, + const RoseInstruction *target_in) + : quash_som(quash_som_in), dkey(dkey_in), + offset_adjust(offset_adjust_in), target(target_in) {} + + bool operator==(const RoseInstrDedupeSom &ri) const { + return quash_som == ri.quash_som && dkey == ri.dkey && + offset_adjust == ri.offset_adjust && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), quash_som, dkey, + offset_adjust); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return quash_som == ri.quash_som && dkey == ri.dkey && + offset_adjust == ri.offset_adjust && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrReportChain + : public RoseInstrBaseNoTargets { +public: + u32 event; + u64a top_squash_distance; + + RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in) + : event(event_in), top_squash_distance(top_squash_distance_in) {} + + bool operator==(const RoseInstrReportChain &ri) const { + return event == ri.event && + top_squash_distance == ri.top_squash_distance; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), event, top_squash_distance); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &, + const OffsetMap &) const { + return event == ri.event && + top_squash_distance == ri.top_squash_distance; + } +}; + +class RoseInstrReportSomInt + : public RoseInstrBaseNoTargets { +public: + som_operation som; + + RoseInstrReportSomInt() { + std::memset(&som, 0, sizeof(som)); + } + + bool operator==(const RoseInstrReportSomInt &ri) const { + return std::memcmp(&som, &ri.som, sizeof(som)) == 0; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), som.type, som.onmatch); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &, + const OffsetMap &) const { + return std::memcmp(&som, &ri.som, sizeof(som)) == 0; + } +}; + +class RoseInstrReportSomAware + : public RoseInstrBaseNoTargets { +public: + som_operation som; + + RoseInstrReportSomAware() { + std::memset(&som, 0, sizeof(som)); + } + + bool operator==(const RoseInstrReportSomAware &ri) const { + return std::memcmp(&som, &ri.som, sizeof(som)) == 0; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), som.type, som.onmatch); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &, + const OffsetMap &) const { + return std::memcmp(&som, &ri.som, sizeof(som)) == 0; + } +}; + +class RoseInstrReport + : public RoseInstrBaseNoTargets { +public: + ReportID onmatch; + s32 offset_adjust; + + RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in) + : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} + + bool operator==(const RoseInstrReport &ri) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), onmatch, offset_adjust); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReport &ri, const OffsetMap &, + const OffsetMap &) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; + } +}; + +class RoseInstrReportExhaust + : public RoseInstrBaseNoTargets { +public: + ReportID onmatch; + s32 offset_adjust; + u32 ekey; + + RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in, + u32 ekey_in) + : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {} + + bool operator==(const RoseInstrReportExhaust &ri) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && + ekey == ri.ekey; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), onmatch, offset_adjust, ekey); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &, + const OffsetMap &) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && + ekey == ri.ekey; + } +}; + +class RoseInstrReportSom + : public RoseInstrBaseNoTargets { +public: + ReportID onmatch; + s32 offset_adjust; + + RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in) + : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} + + bool operator==(const RoseInstrReportSom &ri) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), onmatch, offset_adjust); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &, + const OffsetMap &) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; + } +}; + +class RoseInstrReportSomExhaust + : public RoseInstrBaseNoTargets { +public: + ReportID onmatch; + s32 offset_adjust; + u32 ekey; + + RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in, + u32 ekey_in) + : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {} + + bool operator==(const RoseInstrReportSomExhaust &ri) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && + ekey == ri.ekey; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), onmatch, offset_adjust, ekey); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &, + const OffsetMap &) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && + ekey == ri.ekey; + } +}; + +class RoseInstrDedupeAndReport + : public RoseInstrBaseOneTarget { +public: + u8 quash_som; + u32 dkey; + ReportID onmatch; + s32 offset_adjust; + const RoseInstruction *target; + + RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in, + s32 offset_adjust_in, + const RoseInstruction *target_in) + : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in), + offset_adjust(offset_adjust_in), target(target_in) {} + + bool operator==(const RoseInstrDedupeAndReport &ri) const { + return quash_som == ri.quash_som && dkey == ri.dkey && + onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), quash_som, dkey, onmatch, + offset_adjust); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return quash_som == ri.quash_som && dkey == ri.dkey && + onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrFinalReport + : public RoseInstrBaseNoTargets { +public: + ReportID onmatch; + s32 offset_adjust; + + RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in) + : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} + + bool operator==(const RoseInstrFinalReport &ri) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), onmatch, offset_adjust); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &, + const OffsetMap &) const { + return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; + } +}; + +class RoseInstrCheckExhausted + : public RoseInstrBaseOneTarget { +public: + u32 ekey; + const RoseInstruction *target; + + RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in) + : ekey(ekey_in), target(target_in) {} + + bool operator==(const RoseInstrCheckExhausted &ri) const { + return ekey == ri.ekey && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), ekey); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return ekey == ri.ekey && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMinLength + : public RoseInstrBaseOneTarget { +public: + s32 end_adj; + u64a min_length; + const RoseInstruction *target; + + RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in, + const RoseInstruction *target_in) + : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {} + + bool operator==(const RoseInstrCheckMinLength &ri) const { + return end_adj == ri.end_adj && min_length == ri.min_length && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), end_adj, min_length); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return end_adj == ri.end_adj && min_length == ri.min_length && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrSetState + : public RoseInstrBaseNoTargets { +public: + u32 index; + + explicit RoseInstrSetState(u32 index_in) : index(index_in) {} + + bool operator==(const RoseInstrSetState &ri) const { + return index == ri.index; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), index); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &, + const OffsetMap &) const { + return index == ri.index; + } +}; + +class RoseInstrSetGroups + : public RoseInstrBaseNoTargets { +public: + rose_group groups; + + explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {} + + bool operator==(const RoseInstrSetGroups &ri) const { + return groups == ri.groups; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), groups); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &, + const OffsetMap &) const { + return groups == ri.groups; + } +}; + +class RoseInstrSquashGroups + : public RoseInstrBaseNoTargets { +public: + rose_group groups; + + explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {} + + bool operator==(const RoseInstrSquashGroups &ri) const { + return groups == ri.groups; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), groups); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &, + const OffsetMap &) const { + return groups == ri.groups; + } +}; + +class RoseInstrCheckState + : public RoseInstrBaseOneTarget { +public: + u32 index; + const RoseInstruction *target; + + RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in) + : index(index_in), target(target_in) {} + + bool operator==(const RoseInstrCheckState &ri) const { + return index == ri.index && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), index); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return index == ri.index && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrSparseIterBegin + : public RoseInstrBase { +public: + u32 num_keys; // total number of multibit keys + std::vector> jump_table; + const RoseInstruction *target; + + RoseInstrSparseIterBegin(u32 num_keys_in, + const RoseInstruction *target_in) + : num_keys(num_keys_in), target(target_in) {} + + bool operator==(const RoseInstrSparseIterBegin &ri) const { + return num_keys == ri.num_keys && jump_table == ri.jump_table && + target == ri.target; + } + + size_t hash() const override { + size_t v = hash_all(static_cast(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 { +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(opcode), state); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + void update_target(const RoseInstruction *old_target, + const RoseInstruction *new_target) override { + if (target == old_target) { + target = new_target; + } + if (begin == old_target) { + assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN); + begin = static_cast(new_target); + } + } + + bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return state == ri.state && + offsets.at(begin) == other_offsets.at(ri.begin) && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrSparseIterAny + : public RoseInstrBaseOneTarget { +public: + u32 num_keys; // total number of multibit keys + std::vector keys; + const RoseInstruction *target; + + RoseInstrSparseIterAny(u32 num_keys_in, std::vector keys_in, + const RoseInstruction *target_in) + : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {} + + bool operator==(const RoseInstrSparseIterAny &ri) const { + return num_keys == ri.num_keys && keys == ri.keys && + target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), num_keys, keys); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return num_keys == ri.num_keys && keys == ri.keys && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrEnginesEod + : public RoseInstrBaseNoTargets { +public: + u32 iter_offset; + + explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {} + + bool operator==(const RoseInstrEnginesEod &ri) const { + return iter_offset == ri.iter_offset; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), iter_offset); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &, + const OffsetMap &) const { + return iter_offset == ri.iter_offset; + } +}; + +class RoseInstrSuffixesEod + : public RoseInstrBaseTrivial { +public: + ~RoseInstrSuffixesEod() override; +}; + +class RoseInstrMatcherEod : public RoseInstrBaseTrivial { +public: + ~RoseInstrMatcherEod() override; +}; + +class RoseInstrCheckLongLit + : public RoseInstrBaseOneTarget { +public: + std::string literal; + const RoseInstruction *target; + + RoseInstrCheckLongLit(std::string literal_in, + const RoseInstruction *target_in) + : literal(std::move(literal_in)), target(target_in) {} + + bool operator==(const RoseInstrCheckLongLit &ri) const { + return literal == ri.literal && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), literal); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return literal == ri.literal && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckLongLitNocase + : public RoseInstrBaseOneTarget { +public: + std::string literal; + const RoseInstruction *target; + + RoseInstrCheckLongLitNocase(std::string literal_in, + const RoseInstruction *target_in) + : literal(std::move(literal_in)), target(target_in) { + upperString(literal); + } + + bool operator==(const RoseInstrCheckLongLitNocase &ri) const { + return literal == ri.literal && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), literal); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckLongLitNocase &ri, + const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return literal == ri.literal && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMedLit + : public RoseInstrBaseOneTarget { +public: + std::string literal; + const RoseInstruction *target; + + explicit RoseInstrCheckMedLit(std::string literal_in, + const RoseInstruction *target_in) + : literal(std::move(literal_in)), target(target_in) {} + + bool operator==(const RoseInstrCheckMedLit &ri) const { + return literal == ri.literal && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), literal); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return literal == ri.literal && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMedLitNocase + : public RoseInstrBaseOneTarget { +public: + std::string literal; + const RoseInstruction *target; + + explicit RoseInstrCheckMedLitNocase(std::string literal_in, + const RoseInstruction *target_in) + : literal(std::move(literal_in)), target(target_in) { + upperString(literal); + } + + bool operator==(const RoseInstrCheckMedLitNocase &ri) const { + return literal == ri.literal && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), literal); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMedLitNocase &ri, + const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return literal == ri.literal && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrClearWorkDone + : public RoseInstrBaseTrivial { +public: + ~RoseInstrClearWorkDone() override; +}; + +class RoseInstrMultipathLookaround + : public RoseInstrBaseOneTarget { +public: + u32 look_index; + u32 reach_index; + u32 count; + s32 last_start; + std::array start_mask; + const RoseInstruction *target; + + RoseInstrMultipathLookaround(u32 look_index_in, u32 reach_index_in, + u32 count_in, s32 last_start_in, + std::array 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(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 { +public: + std::array nib_mask; + std::array bucket_select_mask; + std::array data_select_mask; + u16 hi_bits_mask; + u16 lo_bits_mask; + u16 neg_mask; + s32 base_offset; + s32 last_start; + const RoseInstruction *target; + + RoseInstrCheckMultipathShufti16x8(std::array nib_mask_in, + std::array bucket_select_mask_in, + std::array data_select_mask_in, + u16 hi_bits_mask_in, u16 lo_bits_mask_in, + u16 neg_mask_in, s32 base_offset_in, + s32 last_start_in, + const RoseInstruction *target_in) + : nib_mask(std::move(nib_mask_in)), + bucket_select_mask(std::move(bucket_select_mask_in)), + data_select_mask(std::move(data_select_mask_in)), + hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), + neg_mask(neg_mask_in), base_offset(base_offset_in), + last_start(last_start_in), target(target_in) {} + + bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const { + return nib_mask == ri.nib_mask && + bucket_select_mask == ri.bucket_select_mask && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && + neg_mask == ri.neg_mask && base_offset == ri.base_offset && + last_start == ri.last_start && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), nib_mask, + bucket_select_mask, data_select_mask, hi_bits_mask, + lo_bits_mask, neg_mask, base_offset, last_start); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri, + const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return nib_mask == ri.nib_mask && + bucket_select_mask == ri.bucket_select_mask && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && + base_offset == ri.base_offset && last_start == ri.last_start && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMultipathShufti32x8 + : public RoseInstrBaseOneTarget { +public: + std::array hi_mask; + std::array lo_mask; + std::array bucket_select_mask; + std::array data_select_mask; + u32 hi_bits_mask; + u32 lo_bits_mask; + u32 neg_mask; + s32 base_offset; + s32 last_start; + const RoseInstruction *target; + + RoseInstrCheckMultipathShufti32x8(std::array hi_mask_in, + std::array lo_mask_in, + std::array bucket_select_mask_in, + std::array data_select_mask_in, + u32 hi_bits_mask_in, u32 lo_bits_mask_in, + u32 neg_mask_in, s32 base_offset_in, + s32 last_start_in, + const RoseInstruction *target_in) + : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), + bucket_select_mask(std::move(bucket_select_mask_in)), + data_select_mask(std::move(data_select_mask_in)), + hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), + neg_mask(neg_mask_in), base_offset(base_offset_in), + last_start(last_start_in), target(target_in) {} + + bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && + neg_mask == ri.neg_mask && base_offset == ri.base_offset && + last_start == ri.last_start && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), hi_mask, lo_mask, + bucket_select_mask, data_select_mask, hi_bits_mask, + lo_bits_mask, neg_mask, base_offset, last_start); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri, + const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && + base_offset == ri.base_offset && last_start == ri.last_start && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMultipathShufti32x16 + : public RoseInstrBaseOneTarget { +public: + std::array hi_mask; + std::array lo_mask; + std::array bucket_select_mask_hi; + std::array bucket_select_mask_lo; + std::array data_select_mask; + u32 hi_bits_mask; + u32 lo_bits_mask; + u32 neg_mask; + s32 base_offset; + s32 last_start; + const RoseInstruction *target; + + RoseInstrCheckMultipathShufti32x16(std::array hi_mask_in, + std::array lo_mask_in, + std::array bucket_select_mask_hi_in, + std::array bucket_select_mask_lo_in, + std::array data_select_mask_in, + u32 hi_bits_mask_in, u32 lo_bits_mask_in, + u32 neg_mask_in, s32 base_offset_in, + s32 last_start_in, + const RoseInstruction *target_in) + : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), + bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)), + bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)), + data_select_mask(std::move(data_select_mask_in)), + hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), + neg_mask(neg_mask_in), base_offset(base_offset_in), + last_start(last_start_in), target(target_in) {} + + bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask_hi == ri.bucket_select_mask_hi && + bucket_select_mask_lo == ri.bucket_select_mask_lo && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && + neg_mask == ri.neg_mask && base_offset == ri.base_offset && + last_start == ri.last_start && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(opcode), hi_mask, lo_mask, + bucket_select_mask_hi, bucket_select_mask_lo, + data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask, + base_offset, last_start); + } + + void write(void *dest, RoseEngineBlob &blob, + const OffsetMap &offset_map) const override; + + bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri, + const OffsetMap &offsets, + const OffsetMap &other_offsets) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask_hi == ri.bucket_select_mask_hi && + bucket_select_mask_lo == ri.bucket_select_mask_lo && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && + base_offset == ri.base_offset && last_start == ri.last_start && + offsets.at(target) == other_offsets.at(ri.target); + } +}; + +class RoseInstrCheckMultipathShufti64 + : public RoseInstrBaseOneTarget { +public: + std::array hi_mask; + std::array lo_mask; + std::array bucket_select_mask; + std::array data_select_mask; + u64a hi_bits_mask; + u64a lo_bits_mask; + u64a neg_mask; + s32 base_offset; + s32 last_start; + const RoseInstruction *target; + + RoseInstrCheckMultipathShufti64(std::array hi_mask_in, + std::array lo_mask_in, + std::array bucket_select_mask_in, + std::array data_select_mask_in, + u64a hi_bits_mask_in, u64a lo_bits_mask_in, + u64a neg_mask_in, s32 base_offset_in, + s32 last_start_in, + const RoseInstruction *target_in) + : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), + bucket_select_mask(std::move(bucket_select_mask_in)), + data_select_mask(std::move(data_select_mask_in)), + hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), + neg_mask(neg_mask_in), base_offset(base_offset_in), + last_start(last_start_in), target(target_in) {} + + bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const { + return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && + bucket_select_mask == ri.bucket_select_mask && + data_select_mask == ri.data_select_mask && + hi_bits_mask == ri.hi_bits_mask && + lo_bits_mask == ri.lo_bits_mask && + neg_mask == ri.neg_mask && base_offset == ri.base_offset && + last_start == ri.last_start && target == ri.target; + } + + size_t hash() const override { + return hash_all(static_cast(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 { +public: + ~RoseInstrEnd() override; +}; + +} +#endif diff --git a/src/rose/rose_build_program.cpp b/src/rose/rose_build_program.cpp index 5cf06200..c319eed2 100644 --- a/src/rose/rose_build_program.cpp +++ b/src/rose/rose_build_program.cpp @@ -26,11 +26,9 @@ * 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 #include @@ -39,584 +37,8 @@ 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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(dest); - inst->fail_jump = calc_jump(offset_map, this, target); - - // Resolve and write the multibit sparse iterator and the jump table. - vector keys; - vector 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(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(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(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(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(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(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(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(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(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(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(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(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); -} - static OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) { OffsetMap offset_map; @@ -633,9 +55,114 @@ OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) { return offset_map; } +RoseProgram::RoseProgram() { + prog.push_back(make_unique()); +} + +RoseProgram::~RoseProgram() = default; + +RoseProgram::RoseProgram(RoseProgram &&) = default; +RoseProgram &RoseProgram::operator=(RoseProgram &&) = default; + +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(); +} + +const RoseInstruction *RoseProgram::end_instruction() const { + assert(!prog.empty()); + assert(prog.back()->code() == ROSE_INSTR_END); + + return prog.back().get(); +} + +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 &ri = *it; + assert(ri); + ri->update_target(old_target, new_target); + } +} + +RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it, + unique_ptr ri) { + assert(!prog.empty()); + assert(it != end()); + assert(prog.back()->code() == ROSE_INSTR_END); + + return prog.insert(it, move(ri)); +} + +RoseProgram::iterator RoseProgram::insert(RoseProgram::iterator it, + RoseProgram &&block) { + assert(!prog.empty()); + assert(it != end()); + assert(prog.back()->code() == ROSE_INSTR_END); + + if (block.empty()) { + return it; + } + + 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, make_move_iterator(block.prog.begin()), + make_move_iterator(block.prog.end())); + it = prog.begin(); + advance(it, dist); + return it; +} + RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first, - RoseProgram::iterator last) { - return prog.erase(first, last); + RoseProgram::iterator last) { + return prog.erase(first, last); +} + +void RoseProgram::add_before_end(std::unique_ptr ri) { + assert(!prog.empty()); + insert(std::prev(prog.end()), std::move(ri)); +} + +void RoseProgram::add_before_end(RoseProgram &&block) { + assert(!prog.empty()); + assert(prog.back()->code() == ROSE_INSTR_END); + + if (block.empty()) { + return; + } + + insert(prev(prog.end()), move(block)); +} + +void RoseProgram::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(), make_move_iterator(block.prog.begin()), + make_move_iterator(block.prog.end())); } bytecode_ptr writeProgram(RoseEngineBlob &blob, @@ -657,6 +184,15 @@ bytecode_ptr 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()) { diff --git a/src/rose/rose_build_program.h b/src/rose/rose_build_program.h index 9c74d488..c25aab61 100644 --- a/src/rose/rose_build_program.h +++ b/src/rose/rose_build_program.h @@ -31,2121 +31,19 @@ #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 -#include #include -#include #include 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; - - /** - * \brief Writes a concrete implementation of this instruction. - * - * Other data that this instruction depends on is written directly into the - * blob, while the instruction structure itself (of size given by - * the byte_length() function) is written to dest. - */ - virtual void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const = 0; - - /** - * \brief Update a target pointer. - * - * If this instruction contains any reference to the old target, replace it - * with the new one. - */ - virtual void update_target(const RoseInstruction *old_target, - const RoseInstruction *new_target) = 0; - - /** - * \brief True if these instructions are equivalent within their own - * programs. - * - * Checks that any pointers to other instructions point to the same - * offsets. - */ - bool equiv(const RoseInstruction &other, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return equiv_impl(other, offsets, other_offsets); - } - -private: - virtual bool equiv_impl(const RoseInstruction &other, - const OffsetMap &offsets, - const OffsetMap &other_offsets) const = 0; -}; - -/** - * \brief Templated implementation class to handle boring boilerplate code. - */ -template -class RoseInstrBase : public RoseInstruction { -protected: - static constexpr RoseInstructionCode opcode = Opcode; - using impl_type = ImplType; - -public: - RoseInstructionCode code() const override { return opcode; } - - size_t byte_length() const override { - return sizeof(impl_type); - } - - /** - * Note: this implementation simply zeroes the destination region and - * writes in the correct opcode. This is sufficient for trivial - * instructions, but instructions with data members will want to override - * it. - */ - void write(void *dest, RoseEngineBlob &, - const RoseInstruction::OffsetMap &) const override { - assert(dest != nullptr); - assert(ISALIGNED_N(dest, ROSE_INSTR_MIN_ALIGN)); - - impl_type *inst = static_cast(dest); - memset(inst, 0, sizeof(impl_type)); - inst->code = verify_u8(opcode); - } - -private: - bool equiv_impl(const RoseInstruction &other, const OffsetMap &offsets, - const OffsetMap &other_offsets) const override { - const auto *ri_that = dynamic_cast(&other); - if (!ri_that) { - return false; - } - const auto *ri_this = dynamic_cast(this); - assert(ri_this); - return ri_this->equiv_to(*ri_that, offsets, other_offsets); - } -}; - -/** - * \brief Refinement of RoseInstrBase to use for instructions that have - * just a single target member, called "target". - */ -template -class RoseInstrBaseOneTarget - : public RoseInstrBase { -public: - void update_target(const RoseInstruction *old_target, - const RoseInstruction *new_target) override { - RoseInstrType *ri = dynamic_cast(this); - assert(ri); - if (ri->target == old_target) { - ri->target = new_target; - } - } -}; - -/** - * \brief Refinement of RoseInstrBase to use for instructions that have no - * targets. - */ -template -class RoseInstrBaseNoTargets - : public RoseInstrBase { -public: - void update_target(const RoseInstruction *, - const RoseInstruction *) override {} -}; - -/** - * \brief Refinement of RoseInstrBaseNoTargets to use for instructions that - * have no members at all, just an opcode. - */ -template -class RoseInstrBaseTrivial - : public RoseInstrBaseNoTargets { -public: - virtual bool operator==(const RoseInstrType &) const { return true; } - - size_t hash() const override { - return boost::hash_value(static_cast(Opcode)); - } - - bool equiv_to(const RoseInstrType &, const RoseInstruction::OffsetMap &, - const RoseInstruction::OffsetMap &) const { - return true; - } -}; - -//// -//// Concrete implementation classes start here. -//// - -class RoseInstrAnchoredDelay - : public RoseInstrBaseOneTarget { -public: - rose_group groups; - u32 anch_id; - const RoseInstruction *target; - - RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in, - const RoseInstruction *target_in) - : groups(groups_in), anch_id(anch_id_in), target(target_in) {} - - bool operator==(const RoseInstrAnchoredDelay &ri) const { - return groups == ri.groups && anch_id == ri.anch_id - && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), groups, anch_id); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return groups == ri.groups && anch_id == ri.anch_id - && offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckLitEarly - : public RoseInstrBaseOneTarget { -public: - u32 min_offset; - const RoseInstruction *target; - - RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in) - : min_offset(min_offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckLitEarly &ri) const { - return min_offset == ri.min_offset && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), min_offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return min_offset == ri.min_offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckGroups - : public RoseInstrBaseNoTargets { -public: - rose_group groups; - - explicit RoseInstrCheckGroups(rose_group groups_in) : groups(groups_in) {} - - bool operator==(const RoseInstrCheckGroups &ri) const { - return groups == ri.groups; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), groups); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckGroups &ri, const OffsetMap &, - const OffsetMap &) const { - return groups == ri.groups; - } -}; - -class RoseInstrCheckOnlyEod - : public RoseInstrBaseOneTarget { -public: - const RoseInstruction *target; - - explicit RoseInstrCheckOnlyEod(const RoseInstruction *target_in) - : target(target_in) {} - - bool operator==(const RoseInstrCheckOnlyEod &ri) const { - return target == ri.target; - } - - size_t hash() const override { - return boost::hash_value(static_cast(opcode)); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckOnlyEod &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckBounds - : public RoseInstrBaseOneTarget { -public: - u64a min_bound; - u64a max_bound; - const RoseInstruction *target; - - RoseInstrCheckBounds(u64a min, u64a max, const RoseInstruction *target_in) - : min_bound(min), max_bound(max), target(target_in) {} - - bool operator==(const RoseInstrCheckBounds &ri) const { - return min_bound == ri.min_bound && max_bound == ri.max_bound && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), min_bound, max_bound); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckBounds &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return min_bound == ri.min_bound && max_bound == ri.max_bound && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckNotHandled - : public RoseInstrBaseOneTarget { -public: - u32 key; - const RoseInstruction *target; - - RoseInstrCheckNotHandled(u32 key_in, const RoseInstruction *target_in) - : key(key_in), target(target_in) {} - - bool operator==(const RoseInstrCheckNotHandled &ri) const { - return key == ri.key && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), key); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckNotHandled &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return key == ri.key && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckSingleLookaround - : public RoseInstrBaseOneTarget { -public: - s8 offset; - 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(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 { -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(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 { -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(opcode), and_mask, cmp_mask, neg_mask, - offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMask &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMask32 - : public RoseInstrBaseOneTarget { -public: - std::array and_mask; - std::array cmp_mask; - u32 neg_mask; - s32 offset; - const RoseInstruction *target; - - RoseInstrCheckMask32(std::array and_mask_in, - std::array cmp_mask_in, u32 neg_mask_in, - s32 offset_in, const RoseInstruction *target_in) - : and_mask(std::move(and_mask_in)), cmp_mask(std::move(cmp_mask_in)), - neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckMask32 &ri) const { - return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), and_mask, cmp_mask, neg_mask, - offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMask32 &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckByte - : public RoseInstrBaseOneTarget { -public: - u8 and_mask; - u8 cmp_mask; - u8 negation; - s32 offset; - const RoseInstruction *target; - - RoseInstrCheckByte(u8 and_mask_in, u8 cmp_mask_in, u8 negation_in, - s32 offset_in, const RoseInstruction *target_in) - : and_mask(and_mask_in), cmp_mask(cmp_mask_in), negation(negation_in), - offset(offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckByte &ri) const { - return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && - negation == ri.negation && offset == ri.offset && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), and_mask, cmp_mask, negation, - offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckByte &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return and_mask == ri.and_mask && cmp_mask == ri.cmp_mask && - negation == ri.negation && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckShufti16x8 - : public RoseInstrBaseOneTarget { -public: - std::array nib_mask; - std::array bucket_select_mask; - u32 neg_mask; - s32 offset; - const RoseInstruction *target; - - RoseInstrCheckShufti16x8(std::array nib_mask_in, - std::array bucket_select_mask_in, - u32 neg_mask_in, s32 offset_in, - const RoseInstruction *target_in) - : nib_mask(std::move(nib_mask_in)), - bucket_select_mask(std::move(bucket_select_mask_in)), - neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckShufti16x8 &ri) const { - return nib_mask == ri.nib_mask && - bucket_select_mask == ri.bucket_select_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), nib_mask, - bucket_select_mask, neg_mask, offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckShufti16x8 &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return nib_mask == ri.nib_mask && - bucket_select_mask == ri.bucket_select_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckShufti32x8 - : public RoseInstrBaseOneTarget { -public: - std::array hi_mask; - std::array lo_mask; - std::array bucket_select_mask; - u32 neg_mask; - s32 offset; - const RoseInstruction *target; - - RoseInstrCheckShufti32x8(std::array hi_mask_in, - std::array lo_mask_in, - std::array bucket_select_mask_in, - u32 neg_mask_in, s32 offset_in, - const RoseInstruction *target_in) - : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), - bucket_select_mask(std::move(bucket_select_mask_in)), - neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckShufti32x8 &ri) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), hi_mask, lo_mask, - bucket_select_mask, neg_mask, offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckShufti32x8 &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckShufti16x16 - : public RoseInstrBaseOneTarget { -public: - std::array hi_mask; - std::array lo_mask; - std::array bucket_select_mask; - u32 neg_mask; - s32 offset; - const RoseInstruction *target; - - RoseInstrCheckShufti16x16(std::array hi_mask_in, - std::array lo_mask_in, - std::array bucket_select_mask_in, - u32 neg_mask_in, s32 offset_in, - const RoseInstruction *target_in) - : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), - bucket_select_mask(std::move(bucket_select_mask_in)), - neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckShufti16x16 &ri) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), hi_mask, lo_mask, - bucket_select_mask, neg_mask, offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckShufti16x16 &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - neg_mask == ri.neg_mask && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckShufti32x16 - : public RoseInstrBaseOneTarget { -public: - std::array hi_mask; - std::array lo_mask; - std::array bucket_select_mask_hi; - std::array bucket_select_mask_lo; - u32 neg_mask; - s32 offset; - const RoseInstruction *target; - - RoseInstrCheckShufti32x16(std::array hi_mask_in, - std::array lo_mask_in, - std::array bucket_select_mask_hi_in, - std::array bucket_select_mask_lo_in, - u32 neg_mask_in, s32 offset_in, - const RoseInstruction *target_in) - : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), - bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)), - bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)), - neg_mask(neg_mask_in), offset(offset_in), target(target_in) {} - - bool operator==(const RoseInstrCheckShufti32x16 &ri) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask_hi == ri.bucket_select_mask_hi && - bucket_select_mask_lo == ri.bucket_select_mask_lo && - neg_mask == ri.neg_mask && offset == ri.offset && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), hi_mask, lo_mask, - bucket_select_mask_hi, bucket_select_mask_lo, - neg_mask, offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckShufti32x16 &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask_hi == ri.bucket_select_mask_hi && - bucket_select_mask_lo == ri.bucket_select_mask_lo && - neg_mask == ri.neg_mask && offset == ri.offset && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckInfix - : public RoseInstrBaseOneTarget { -public: - u32 queue; - u32 lag; - ReportID report; - const RoseInstruction *target; - - RoseInstrCheckInfix(u32 queue_in, u32 lag_in, ReportID report_in, - const RoseInstruction *target_in) - : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {} - - bool operator==(const RoseInstrCheckInfix &ri) const { - return queue == ri.queue && lag == ri.lag && report == ri.report && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), queue, lag, report); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckInfix &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return queue == ri.queue && lag == ri.lag && report == ri.report && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckPrefix - : public RoseInstrBaseOneTarget { -public: - u32 queue; - u32 lag; - ReportID report; - const RoseInstruction *target; - - RoseInstrCheckPrefix(u32 queue_in, u32 lag_in, ReportID report_in, - const RoseInstruction *target_in) - : queue(queue_in), lag(lag_in), report(report_in), target(target_in) {} - - bool operator==(const RoseInstrCheckPrefix &ri) const { - return queue == ri.queue && lag == ri.lag && report == ri.report && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), queue, lag, report); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckPrefix &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return queue == ri.queue && lag == ri.lag && report == ri.report && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrPushDelayed - : public RoseInstrBaseNoTargets { -public: - u8 delay; - u32 index; - - RoseInstrPushDelayed(u8 delay_in, u32 index_in) - : delay(delay_in), index(index_in) {} - - bool operator==(const RoseInstrPushDelayed &ri) const { - return delay == ri.delay && index == ri.index; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), delay, index); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrPushDelayed &ri, const OffsetMap &, - const OffsetMap &) const { - return delay == ri.delay && index == ri.index; - } -}; - -class RoseInstrCatchUp - : public RoseInstrBaseTrivial { -public: - ~RoseInstrCatchUp() override; -}; - -class RoseInstrCatchUpMpv - : public RoseInstrBaseTrivial { -public: - ~RoseInstrCatchUpMpv() override; -}; - -class RoseInstrSomAdjust - : public RoseInstrBaseNoTargets { -public: - u32 distance; - - explicit RoseInstrSomAdjust(u32 distance_in) : distance(distance_in) {} - - bool operator==(const RoseInstrSomAdjust &ri) const { - return distance == ri.distance; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), distance); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSomAdjust &ri, const OffsetMap &, - const OffsetMap &) const { - return distance == ri.distance; - } -}; - -class RoseInstrSomLeftfix - : public RoseInstrBaseNoTargets { -public: - u32 queue; - u32 lag; - - RoseInstrSomLeftfix(u32 queue_in, u32 lag_in) - : queue(queue_in), lag(lag_in) {} - - bool operator==(const RoseInstrSomLeftfix &ri) const { - return queue == ri.queue && lag == ri.lag; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), queue, lag); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSomLeftfix &ri, const OffsetMap &, - const OffsetMap &) const { - return queue == ri.queue && lag == ri.lag; - } -}; - -class RoseInstrSomFromReport - : public RoseInstrBaseNoTargets { -public: - som_operation som; - - RoseInstrSomFromReport() { - std::memset(&som, 0, sizeof(som)); - } - - bool operator==(const RoseInstrSomFromReport &ri) const { - return std::memcmp(&som, &ri.som, sizeof(som)) == 0; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), som.type, som.onmatch); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSomFromReport &ri, const OffsetMap &, - const OffsetMap &) const { - return std::memcmp(&som, &ri.som, sizeof(som)) == 0; - } -}; - -class RoseInstrSomZero - : public RoseInstrBaseTrivial { -public: - ~RoseInstrSomZero() override; -}; - -class RoseInstrTriggerInfix - : public RoseInstrBaseNoTargets { -public: - u8 cancel; - u32 queue; - u32 event; - - RoseInstrTriggerInfix(u8 cancel_in, u32 queue_in, u32 event_in) - : cancel(cancel_in), queue(queue_in), event(event_in) {} - - bool operator==(const RoseInstrTriggerInfix &ri) const { - return cancel == ri.cancel && queue == ri.queue && event == ri.event; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), cancel, queue, event); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrTriggerInfix &ri, const OffsetMap &, - const OffsetMap &) const { - return cancel == ri.cancel && queue == ri.queue && event == ri.event; - } -}; - -class RoseInstrTriggerSuffix - : public RoseInstrBaseNoTargets { -public: - u32 queue; - u32 event; - - RoseInstrTriggerSuffix(u32 queue_in, u32 event_in) - : queue(queue_in), event(event_in) {} - - bool operator==(const RoseInstrTriggerSuffix &ri) const { - return queue == ri.queue && event == ri.event; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), queue, event); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrTriggerSuffix &ri, const OffsetMap &, - const OffsetMap &) const { - return queue == ri.queue && event == ri.event; - } -}; - -class RoseInstrDedupe - : public RoseInstrBaseOneTarget { -public: - u8 quash_som; - u32 dkey; - s32 offset_adjust; - const RoseInstruction *target; - - RoseInstrDedupe(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in, - const RoseInstruction *target_in) - : quash_som(quash_som_in), dkey(dkey_in), - offset_adjust(offset_adjust_in), target(target_in) {} - - bool operator==(const RoseInstrDedupe &ri) const { - return quash_som == ri.quash_som && dkey == ri.dkey && - offset_adjust == ri.offset_adjust && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), quash_som, dkey, - offset_adjust); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrDedupe &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return quash_som == ri.quash_som && dkey == ri.dkey && - offset_adjust == ri.offset_adjust && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrDedupeSom - : public RoseInstrBaseOneTarget { -public: - u8 quash_som; - u32 dkey; - s32 offset_adjust; - const RoseInstruction *target; - - RoseInstrDedupeSom(u8 quash_som_in, u32 dkey_in, s32 offset_adjust_in, - const RoseInstruction *target_in) - : quash_som(quash_som_in), dkey(dkey_in), - offset_adjust(offset_adjust_in), target(target_in) {} - - bool operator==(const RoseInstrDedupeSom &ri) const { - return quash_som == ri.quash_som && dkey == ri.dkey && - offset_adjust == ri.offset_adjust && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), quash_som, dkey, - offset_adjust); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrDedupeSom &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return quash_som == ri.quash_som && dkey == ri.dkey && - offset_adjust == ri.offset_adjust && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrReportChain - : public RoseInstrBaseNoTargets { -public: - u32 event; - u64a top_squash_distance; - - RoseInstrReportChain(u32 event_in, u32 top_squash_distance_in) - : event(event_in), top_squash_distance(top_squash_distance_in) {} - - bool operator==(const RoseInstrReportChain &ri) const { - return event == ri.event && - top_squash_distance == ri.top_squash_distance; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), event, top_squash_distance); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReportChain &ri, const OffsetMap &, - const OffsetMap &) const { - return event == ri.event && - top_squash_distance == ri.top_squash_distance; - } -}; - -class RoseInstrReportSomInt - : public RoseInstrBaseNoTargets { -public: - som_operation som; - - RoseInstrReportSomInt() { - std::memset(&som, 0, sizeof(som)); - } - - bool operator==(const RoseInstrReportSomInt &ri) const { - return std::memcmp(&som, &ri.som, sizeof(som)) == 0; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), som.type, som.onmatch); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReportSomInt &ri, const OffsetMap &, - const OffsetMap &) const { - return std::memcmp(&som, &ri.som, sizeof(som)) == 0; - } -}; - -class RoseInstrReportSomAware - : public RoseInstrBaseNoTargets { -public: - som_operation som; - - RoseInstrReportSomAware() { - std::memset(&som, 0, sizeof(som)); - } - - bool operator==(const RoseInstrReportSomAware &ri) const { - return std::memcmp(&som, &ri.som, sizeof(som)) == 0; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), som.type, som.onmatch); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReportSomAware &ri, const OffsetMap &, - const OffsetMap &) const { - return std::memcmp(&som, &ri.som, sizeof(som)) == 0; - } -}; - -class RoseInstrReport - : public RoseInstrBaseNoTargets { -public: - ReportID onmatch; - s32 offset_adjust; - - RoseInstrReport(ReportID onmatch_in, s32 offset_adjust_in) - : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} - - bool operator==(const RoseInstrReport &ri) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), onmatch, offset_adjust); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReport &ri, const OffsetMap &, - const OffsetMap &) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; - } -}; - -class RoseInstrReportExhaust - : public RoseInstrBaseNoTargets { -public: - ReportID onmatch; - s32 offset_adjust; - u32 ekey; - - RoseInstrReportExhaust(ReportID onmatch_in, s32 offset_adjust_in, - u32 ekey_in) - : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {} - - bool operator==(const RoseInstrReportExhaust &ri) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && - ekey == ri.ekey; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), onmatch, offset_adjust, ekey); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReportExhaust &ri, const OffsetMap &, - const OffsetMap &) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && - ekey == ri.ekey; - } -}; - -class RoseInstrReportSom - : public RoseInstrBaseNoTargets { -public: - ReportID onmatch; - s32 offset_adjust; - - RoseInstrReportSom(ReportID onmatch_in, s32 offset_adjust_in) - : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} - - bool operator==(const RoseInstrReportSom &ri) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), onmatch, offset_adjust); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReportSom &ri, const OffsetMap &, - const OffsetMap &) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; - } -}; - -class RoseInstrReportSomExhaust - : public RoseInstrBaseNoTargets { -public: - ReportID onmatch; - s32 offset_adjust; - u32 ekey; - - RoseInstrReportSomExhaust(ReportID onmatch_in, s32 offset_adjust_in, - u32 ekey_in) - : onmatch(onmatch_in), offset_adjust(offset_adjust_in), ekey(ekey_in) {} - - bool operator==(const RoseInstrReportSomExhaust &ri) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && - ekey == ri.ekey; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), onmatch, offset_adjust, ekey); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrReportSomExhaust &ri, const OffsetMap &, - const OffsetMap &) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && - ekey == ri.ekey; - } -}; - -class RoseInstrDedupeAndReport - : public RoseInstrBaseOneTarget { -public: - u8 quash_som; - u32 dkey; - ReportID onmatch; - s32 offset_adjust; - const RoseInstruction *target; - - RoseInstrDedupeAndReport(u8 quash_som_in, u32 dkey_in, ReportID onmatch_in, - s32 offset_adjust_in, - const RoseInstruction *target_in) - : quash_som(quash_som_in), dkey(dkey_in), onmatch(onmatch_in), - offset_adjust(offset_adjust_in), target(target_in) {} - - bool operator==(const RoseInstrDedupeAndReport &ri) const { - return quash_som == ri.quash_som && dkey == ri.dkey && - onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), quash_som, dkey, onmatch, - offset_adjust); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrDedupeAndReport &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return quash_som == ri.quash_som && dkey == ri.dkey && - onmatch == ri.onmatch && offset_adjust == ri.offset_adjust && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrFinalReport - : public RoseInstrBaseNoTargets { -public: - ReportID onmatch; - s32 offset_adjust; - - RoseInstrFinalReport(ReportID onmatch_in, s32 offset_adjust_in) - : onmatch(onmatch_in), offset_adjust(offset_adjust_in) {} - - bool operator==(const RoseInstrFinalReport &ri) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), onmatch, offset_adjust); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrFinalReport &ri, const OffsetMap &, - const OffsetMap &) const { - return onmatch == ri.onmatch && offset_adjust == ri.offset_adjust; - } -}; - -class RoseInstrCheckExhausted - : public RoseInstrBaseOneTarget { -public: - u32 ekey; - const RoseInstruction *target; - - RoseInstrCheckExhausted(u32 ekey_in, const RoseInstruction *target_in) - : ekey(ekey_in), target(target_in) {} - - bool operator==(const RoseInstrCheckExhausted &ri) const { - return ekey == ri.ekey && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), ekey); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckExhausted &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return ekey == ri.ekey && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMinLength - : public RoseInstrBaseOneTarget { -public: - s32 end_adj; - u64a min_length; - const RoseInstruction *target; - - RoseInstrCheckMinLength(s32 end_adj_in, u64a min_length_in, - const RoseInstruction *target_in) - : end_adj(end_adj_in), min_length(min_length_in), target(target_in) {} - - bool operator==(const RoseInstrCheckMinLength &ri) const { - return end_adj == ri.end_adj && min_length == ri.min_length && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), end_adj, min_length); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMinLength &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return end_adj == ri.end_adj && min_length == ri.min_length && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrSetState - : public RoseInstrBaseNoTargets { -public: - u32 index; - - explicit RoseInstrSetState(u32 index_in) : index(index_in) {} - - bool operator==(const RoseInstrSetState &ri) const { - return index == ri.index; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), index); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSetState &ri, const OffsetMap &, - const OffsetMap &) const { - return index == ri.index; - } -}; - -class RoseInstrSetGroups - : public RoseInstrBaseNoTargets { -public: - rose_group groups; - - explicit RoseInstrSetGroups(rose_group groups_in) : groups(groups_in) {} - - bool operator==(const RoseInstrSetGroups &ri) const { - return groups == ri.groups; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), groups); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSetGroups &ri, const OffsetMap &, - const OffsetMap &) const { - return groups == ri.groups; - } -}; - -class RoseInstrSquashGroups - : public RoseInstrBaseNoTargets { -public: - rose_group groups; - - explicit RoseInstrSquashGroups(rose_group groups_in) : groups(groups_in) {} - - bool operator==(const RoseInstrSquashGroups &ri) const { - return groups == ri.groups; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), groups); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSquashGroups &ri, const OffsetMap &, - const OffsetMap &) const { - return groups == ri.groups; - } -}; - -class RoseInstrCheckState - : public RoseInstrBaseOneTarget { -public: - u32 index; - const RoseInstruction *target; - - RoseInstrCheckState(u32 index_in, const RoseInstruction *target_in) - : index(index_in), target(target_in) {} - - bool operator==(const RoseInstrCheckState &ri) const { - return index == ri.index && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), index); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckState &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return index == ri.index && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrSparseIterBegin - : public RoseInstrBase { -public: - u32 num_keys; // total number of multibit keys - std::vector> jump_table; - const RoseInstruction *target; - - RoseInstrSparseIterBegin(u32 num_keys_in, - const RoseInstruction *target_in) - : num_keys(num_keys_in), target(target_in) {} - - bool operator==(const RoseInstrSparseIterBegin &ri) const { - return num_keys == ri.num_keys && jump_table == ri.jump_table && - target == ri.target; - } - - size_t hash() const override { - size_t v = hash_all(static_cast(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 { -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(opcode), state); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - void update_target(const RoseInstruction *old_target, - const RoseInstruction *new_target) override { - if (target == old_target) { - target = new_target; - } - if (begin == old_target) { - assert(new_target->code() == ROSE_INSTR_SPARSE_ITER_BEGIN); - begin = static_cast(new_target); - } - } - - bool equiv_to(const RoseInstrSparseIterNext &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return state == ri.state && - offsets.at(begin) == other_offsets.at(ri.begin) && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrSparseIterAny - : public RoseInstrBaseOneTarget { -public: - u32 num_keys; // total number of multibit keys - std::vector keys; - const RoseInstruction *target; - - RoseInstrSparseIterAny(u32 num_keys_in, std::vector keys_in, - const RoseInstruction *target_in) - : num_keys(num_keys_in), keys(std::move(keys_in)), target(target_in) {} - - bool operator==(const RoseInstrSparseIterAny &ri) const { - return num_keys == ri.num_keys && keys == ri.keys && - target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), num_keys, keys); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrSparseIterAny &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return num_keys == ri.num_keys && keys == ri.keys && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrEnginesEod - : public RoseInstrBaseNoTargets { -public: - u32 iter_offset; - - explicit RoseInstrEnginesEod(u32 iter_in) : iter_offset(iter_in) {} - - bool operator==(const RoseInstrEnginesEod &ri) const { - return iter_offset == ri.iter_offset; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), iter_offset); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrEnginesEod &ri, const OffsetMap &, - const OffsetMap &) const { - return iter_offset == ri.iter_offset; - } -}; - -class RoseInstrSuffixesEod - : public RoseInstrBaseTrivial { -public: - ~RoseInstrSuffixesEod() override; -}; - -class RoseInstrMatcherEod : public RoseInstrBaseTrivial { -public: - ~RoseInstrMatcherEod() override; -}; - -class RoseInstrCheckLongLit - : public RoseInstrBaseOneTarget { -public: - std::string literal; - const RoseInstruction *target; - - RoseInstrCheckLongLit(std::string literal_in, - const RoseInstruction *target_in) - : literal(std::move(literal_in)), target(target_in) {} - - bool operator==(const RoseInstrCheckLongLit &ri) const { - return literal == ri.literal && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), literal); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckLongLit &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return literal == ri.literal && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckLongLitNocase - : public RoseInstrBaseOneTarget { -public: - std::string literal; - const RoseInstruction *target; - - RoseInstrCheckLongLitNocase(std::string literal_in, - const RoseInstruction *target_in) - : literal(std::move(literal_in)), target(target_in) { - upperString(literal); - } - - bool operator==(const RoseInstrCheckLongLitNocase &ri) const { - return literal == ri.literal && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), literal); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckLongLitNocase &ri, - const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return literal == ri.literal && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMedLit - : public RoseInstrBaseOneTarget { -public: - std::string literal; - const RoseInstruction *target; - - explicit RoseInstrCheckMedLit(std::string literal_in, - const RoseInstruction *target_in) - : literal(std::move(literal_in)), target(target_in) {} - - bool operator==(const RoseInstrCheckMedLit &ri) const { - return literal == ri.literal && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), literal); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMedLit &ri, const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return literal == ri.literal && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMedLitNocase - : public RoseInstrBaseOneTarget { -public: - std::string literal; - const RoseInstruction *target; - - explicit RoseInstrCheckMedLitNocase(std::string literal_in, - const RoseInstruction *target_in) - : literal(std::move(literal_in)), target(target_in) { - upperString(literal); - } - - bool operator==(const RoseInstrCheckMedLitNocase &ri) const { - return literal == ri.literal && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), literal); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMedLitNocase &ri, - const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return literal == ri.literal && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrClearWorkDone - : public RoseInstrBaseTrivial { -public: - ~RoseInstrClearWorkDone() override; -}; - -class RoseInstrMultipathLookaround - : public RoseInstrBaseOneTarget { -public: - u32 look_index; - u32 reach_index; - u32 count; - s32 last_start; - std::array start_mask; - const RoseInstruction *target; - - RoseInstrMultipathLookaround(u32 look_index_in, u32 reach_index_in, - u32 count_in, s32 last_start_in, - std::array 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(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 { -public: - std::array nib_mask; - std::array bucket_select_mask; - std::array data_select_mask; - u16 hi_bits_mask; - u16 lo_bits_mask; - u16 neg_mask; - s32 base_offset; - s32 last_start; - const RoseInstruction *target; - - RoseInstrCheckMultipathShufti16x8(std::array nib_mask_in, - std::array bucket_select_mask_in, - std::array data_select_mask_in, - u16 hi_bits_mask_in, u16 lo_bits_mask_in, - u16 neg_mask_in, s32 base_offset_in, - s32 last_start_in, - const RoseInstruction *target_in) - : nib_mask(std::move(nib_mask_in)), - bucket_select_mask(std::move(bucket_select_mask_in)), - data_select_mask(std::move(data_select_mask_in)), - hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), - neg_mask(neg_mask_in), base_offset(base_offset_in), - last_start(last_start_in), target(target_in) {} - - bool operator==(const RoseInstrCheckMultipathShufti16x8 &ri) const { - return nib_mask == ri.nib_mask && - bucket_select_mask == ri.bucket_select_mask && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && - neg_mask == ri.neg_mask && base_offset == ri.base_offset && - last_start == ri.last_start && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), nib_mask, - bucket_select_mask, data_select_mask, hi_bits_mask, - lo_bits_mask, neg_mask, base_offset, last_start); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMultipathShufti16x8 &ri, - const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return nib_mask == ri.nib_mask && - bucket_select_mask == ri.bucket_select_mask && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && - base_offset == ri.base_offset && last_start == ri.last_start && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMultipathShufti32x8 - : public RoseInstrBaseOneTarget { -public: - std::array hi_mask; - std::array lo_mask; - std::array bucket_select_mask; - std::array data_select_mask; - u32 hi_bits_mask; - u32 lo_bits_mask; - u32 neg_mask; - s32 base_offset; - s32 last_start; - const RoseInstruction *target; - - RoseInstrCheckMultipathShufti32x8(std::array hi_mask_in, - std::array lo_mask_in, - std::array bucket_select_mask_in, - std::array data_select_mask_in, - u32 hi_bits_mask_in, u32 lo_bits_mask_in, - u32 neg_mask_in, s32 base_offset_in, - s32 last_start_in, - const RoseInstruction *target_in) - : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), - bucket_select_mask(std::move(bucket_select_mask_in)), - data_select_mask(std::move(data_select_mask_in)), - hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), - neg_mask(neg_mask_in), base_offset(base_offset_in), - last_start(last_start_in), target(target_in) {} - - bool operator==(const RoseInstrCheckMultipathShufti32x8 &ri) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && - neg_mask == ri.neg_mask && base_offset == ri.base_offset && - last_start == ri.last_start && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), hi_mask, lo_mask, - bucket_select_mask, data_select_mask, hi_bits_mask, - lo_bits_mask, neg_mask, base_offset, last_start); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMultipathShufti32x8 &ri, - const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && - base_offset == ri.base_offset && last_start == ri.last_start && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMultipathShufti32x16 - : public RoseInstrBaseOneTarget { -public: - std::array hi_mask; - std::array lo_mask; - std::array bucket_select_mask_hi; - std::array bucket_select_mask_lo; - std::array data_select_mask; - u32 hi_bits_mask; - u32 lo_bits_mask; - u32 neg_mask; - s32 base_offset; - s32 last_start; - const RoseInstruction *target; - - RoseInstrCheckMultipathShufti32x16(std::array hi_mask_in, - std::array lo_mask_in, - std::array bucket_select_mask_hi_in, - std::array bucket_select_mask_lo_in, - std::array data_select_mask_in, - u32 hi_bits_mask_in, u32 lo_bits_mask_in, - u32 neg_mask_in, s32 base_offset_in, - s32 last_start_in, - const RoseInstruction *target_in) - : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), - bucket_select_mask_hi(std::move(bucket_select_mask_hi_in)), - bucket_select_mask_lo(std::move(bucket_select_mask_lo_in)), - data_select_mask(std::move(data_select_mask_in)), - hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), - neg_mask(neg_mask_in), base_offset(base_offset_in), - last_start(last_start_in), target(target_in) {} - - bool operator==(const RoseInstrCheckMultipathShufti32x16 &ri) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask_hi == ri.bucket_select_mask_hi && - bucket_select_mask_lo == ri.bucket_select_mask_lo && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && - neg_mask == ri.neg_mask && base_offset == ri.base_offset && - last_start == ri.last_start && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), hi_mask, lo_mask, - bucket_select_mask_hi, bucket_select_mask_lo, - data_select_mask, hi_bits_mask, lo_bits_mask, neg_mask, - base_offset, last_start); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrCheckMultipathShufti32x16 &ri, - const OffsetMap &offsets, - const OffsetMap &other_offsets) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask_hi == ri.bucket_select_mask_hi && - bucket_select_mask_lo == ri.bucket_select_mask_lo && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && neg_mask == ri.neg_mask && - base_offset == ri.base_offset && last_start == ri.last_start && - offsets.at(target) == other_offsets.at(ri.target); - } -}; - -class RoseInstrCheckMultipathShufti64 - : public RoseInstrBaseOneTarget { -public: - std::array hi_mask; - std::array lo_mask; - std::array bucket_select_mask; - std::array data_select_mask; - u64a hi_bits_mask; - u64a lo_bits_mask; - u64a neg_mask; - s32 base_offset; - s32 last_start; - const RoseInstruction *target; - - RoseInstrCheckMultipathShufti64(std::array hi_mask_in, - std::array lo_mask_in, - std::array bucket_select_mask_in, - std::array data_select_mask_in, - u64a hi_bits_mask_in, u64a lo_bits_mask_in, - u64a neg_mask_in, s32 base_offset_in, - s32 last_start_in, - const RoseInstruction *target_in) - : hi_mask(std::move(hi_mask_in)), lo_mask(std::move(lo_mask_in)), - bucket_select_mask(std::move(bucket_select_mask_in)), - data_select_mask(std::move(data_select_mask_in)), - hi_bits_mask(hi_bits_mask_in), lo_bits_mask(lo_bits_mask_in), - neg_mask(neg_mask_in), base_offset(base_offset_in), - last_start(last_start_in), target(target_in) {} - - bool operator==(const RoseInstrCheckMultipathShufti64 &ri) const { - return hi_mask == ri.hi_mask && lo_mask == ri.lo_mask && - bucket_select_mask == ri.bucket_select_mask && - data_select_mask == ri.data_select_mask && - hi_bits_mask == ri.hi_bits_mask && - lo_bits_mask == ri.lo_bits_mask && - neg_mask == ri.neg_mask && base_offset == ri.base_offset && - last_start == ri.last_start && target == ri.target; - } - - size_t hash() const override { - return hash_all(static_cast(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 { -public: - ~RoseInstrEnd() override; -}; +class RoseInstruction; /** * \brief Container for a list of program instructions. @@ -2155,16 +53,14 @@ private: std::vector> prog; public: - RoseProgram() { - prog.push_back(make_unique()); - } + 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(); } @@ -2188,58 +84,15 @@ public: 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 &ri = *it; - assert(ri); - ri->update_target(old_target, new_target); - } - } + const RoseInstruction *new_target); - iterator insert(iterator it, std::unique_ptr ri) { - assert(!prog.empty()); - assert(it != end()); - assert(prog.back()->code() == ROSE_INSTR_END); + iterator insert(iterator it, std::unique_ptr ri); - 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); - - if (block.empty()) { - return it; - } - - 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). */ @@ -2249,10 +102,7 @@ public: * \brief Adds this instruction to the program just before the terminating * ROSE_INSTR_END. */ - void add_before_end(std::unique_ptr ri) { - assert(!prog.empty()); - insert(std::prev(prog.end()), std::move(ri)); - } + void add_before_end(std::unique_ptr ri); /** * \brief Adds this block to the program just before the terminating @@ -2260,40 +110,14 @@ public: * * 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. @@ -2301,13 +125,10 @@ public: template void replace(Iter it, std::unique_ptr 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); } }; @@ -2316,14 +137,7 @@ bytecode_ptr writeProgram(RoseEngineBlob &blob, 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 {