FDR: Squash buckets of included literals in FDR confirm

- Change the compile of literal matchers to two passes.
 - Reverse the bucket assignment in FDR, bucket with longer literals has
   smaller bucket id.
 - Squash the buckets of included literals and jump to the the program of
   included literals directly from parent literal program without going
   through FDR confirm for included iterals.
This commit is contained in:
Wang, Xiang W
2017-06-22 04:50:45 -04:00
committed by Matthew Barr
parent d2b5523dd8
commit 86c5f7feb1
26 changed files with 1017 additions and 262 deletions

View File

@@ -2570,6 +2570,23 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t,
}
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(INCLUDED_JUMP) {
if (scratch->fdr_conf) {
// squash the bucket of included literal
u8 shift = scratch->fdr_conf_offset & ~7U;
u64a mask = ((~(u64a)ri->squash) << shift);
*(scratch->fdr_conf) &= mask;
pc = getByOffset(t, ri->child_offset);
pc_base = pc;
programOffset = (const u8 *)pc_base -(const u8 *)t;
DEBUG_PRINTF("pc_base %p pc %p child_offset %u\n",
pc_base, pc, ri->child_offset);
continue;
}
}
PROGRAM_NEXT_INSTRUCTION
}
}

View File

@@ -49,6 +49,7 @@
#include "rose_internal.h"
#include "rose_program.h"
#include "hwlm/hwlm.h" /* engine types */
#include "hwlm/hwlm_build.h"
#include "hwlm/hwlm_literal.h"
#include "nfa/castlecompile.h"
#include "nfa/goughcompile.h"
@@ -2803,7 +2804,7 @@ vector<LitFragment> groupByFragment(const RoseBuildImpl &build) {
auto groups = info.group_mask;
if (lit.s.length() < ROSE_SHORT_LITERAL_LEN_MAX) {
fragments.emplace_back(frag_id, groups, lit_id);
fragments.emplace_back(frag_id, lit.s, groups, lit_id);
frag_id++;
continue;
}
@@ -2816,10 +2817,11 @@ vector<LitFragment> groupByFragment(const RoseBuildImpl &build) {
}
for (auto &m : frag_info) {
auto &lit = m.first;
auto &fi = m.second;
DEBUG_PRINTF("frag %s -> ids: %s\n", dumpString(m.first.s).c_str(),
as_string_list(fi.lit_ids).c_str());
fragments.emplace_back(frag_id, fi.groups, move(fi.lit_ids));
fragments.emplace_back(frag_id, lit.s, fi.groups, move(fi.lit_ids));
frag_id++;
assert(frag_id == fragments.size());
}
@@ -2827,33 +2829,181 @@ vector<LitFragment> groupByFragment(const RoseBuildImpl &build) {
return fragments;
}
static
void buildIncludedIdMap(unordered_map<u32, pair<u32, u8>> &includedIdMap,
const LitProto *litProto) {
if (!litProto) {
return;
}
const auto &proto = *litProto->hwlmProto;
for (const auto &lit : proto.lits) {
if (lit.included_id != INVALID_LIT_ID) {
includedIdMap[lit.id] = make_pair(lit.included_id, lit.squash);
}
}
}
static
void findInclusionGroups(vector<LitFragment> &fragments,
LitProto *fproto, LitProto *drproto,
LitProto *eproto, LitProto *sbproto) {
unordered_map<u32, pair<u32, u8>> includedIdMap;
unordered_map<u32, pair<u32, u8>> includedDelayIdMap;
buildIncludedIdMap(includedIdMap, fproto);
buildIncludedIdMap(includedDelayIdMap, drproto);
buildIncludedIdMap(includedIdMap, eproto);
buildIncludedIdMap(includedIdMap, sbproto);
size_t fragNum = fragments.size();
vector<u32> candidates;
for (size_t j = 0; j < fragNum; j++) {
DEBUG_PRINTF("frag id %lu\n", j);
u32 id = j;
if (contains(includedIdMap, id) ||
contains(includedDelayIdMap, id)) {
candidates.push_back(j);
DEBUG_PRINTF("find candidate\n");
}
}
for (const auto &c : candidates) {
auto &frag = fragments[c];
u32 id = c;
if (contains(includedIdMap, id)) {
const auto &childId = includedIdMap[id];
frag.included_frag_id = childId.first;
frag.squash = childId.second;
DEBUG_PRINTF("frag id %u child frag id %u\n", c,
frag.included_frag_id);
}
if (contains(includedDelayIdMap, id)) {
const auto &childId = includedDelayIdMap[id];
frag.included_delay_frag_id = childId.first;
frag.delay_squash = childId.second;
DEBUG_PRINTF("delay frag id %u child frag id %u\n", c,
frag.included_delay_frag_id);
}
}
}
static
void buildFragmentPrograms(const RoseBuildImpl &build,
vector<LitFragment> &fragments,
build_context &bc, ProgramBuild &prog_build,
const map<u32, vector<RoseEdge>> &lit_edge_map) {
// Sort fragments based on literal length and case info to build
// included literal programs before their parent programs.
vector<LitFragment> ordered_fragments(fragments);
stable_sort(begin(ordered_fragments), end(ordered_fragments),
[](const LitFragment &a, const LitFragment &b) {
auto len1 = a.s.length();
auto caseful1 = !a.s.any_nocase();
auto len2 = b.s.length();
auto caseful2 = !b.s.any_nocase();
return tie(len1, caseful1) < tie(len2, caseful2);
});
for (auto &frag : ordered_fragments) {
auto &pfrag = fragments[frag.fragment_id];
DEBUG_PRINTF("frag_id=%u, lit_ids=[%s]\n", pfrag.fragment_id,
as_string_list(pfrag.lit_ids).c_str());
auto lit_prog = makeFragmentProgram(build, bc, prog_build,
pfrag.lit_ids, lit_edge_map);
if (pfrag.included_frag_id != INVALID_FRAG_ID &&
!lit_prog.empty()) {
auto &cfrag = fragments[pfrag.included_frag_id];
assert(pfrag.s.length() >= cfrag.s.length() &&
!pfrag.s.any_nocase() >= !cfrag.s.any_nocase());
u32 child_offset = cfrag.lit_program_offset;
DEBUG_PRINTF("child %u offset %u\n", cfrag.fragment_id,
child_offset);
addIncludedJumpProgram(lit_prog, child_offset, pfrag.squash);
}
pfrag.lit_program_offset = writeProgram(bc, move(lit_prog));
// We only do delayed rebuild in streaming mode.
if (!build.cc.streaming) {
continue;
}
auto rebuild_prog = makeDelayRebuildProgram(build, prog_build,
pfrag.lit_ids);
if (pfrag.included_delay_frag_id != INVALID_FRAG_ID &&
!rebuild_prog.empty()) {
auto &cfrag = fragments[pfrag.included_delay_frag_id];
assert(pfrag.s.length() >= cfrag.s.length() &&
!pfrag.s.any_nocase() >= !cfrag.s.any_nocase());
u32 child_offset = cfrag.delay_program_offset;
DEBUG_PRINTF("child %u offset %u\n", cfrag.fragment_id,
child_offset);
addIncludedJumpProgram(rebuild_prog, child_offset,
pfrag.delay_squash);
}
pfrag.delay_program_offset = writeProgram(bc, move(rebuild_prog));
}
}
static
void updateLitProtoProgramOffset(vector<LitFragment> &fragments,
LitProto &litProto, bool delay) {
auto &proto = *litProto.hwlmProto;
for (auto &lit : proto.lits) {
auto fragId = lit.id;
auto &frag = fragments[fragId];
if (delay) {
DEBUG_PRINTF("delay_program_offset:%u\n",
frag.delay_program_offset);
lit.id = frag.delay_program_offset;
} else {
DEBUG_PRINTF("lit_program_offset:%u\n",
frag.lit_program_offset);
lit.id = frag.lit_program_offset;
}
}
}
static
void updateLitProgramOffset(vector<LitFragment> &fragments,
LitProto *fproto, LitProto *drproto,
LitProto *eproto, LitProto *sbproto) {
if (fproto) {
updateLitProtoProgramOffset(fragments, *fproto, false);
}
if (drproto) {
updateLitProtoProgramOffset(fragments, *drproto, true);
}
if (eproto) {
updateLitProtoProgramOffset(fragments, *eproto, false);
}
if (sbproto) {
updateLitProtoProgramOffset(fragments, *sbproto, false);
}
}
/**
* \brief Build the interpreter programs for each literal.
*/
static
void buildLiteralPrograms(const RoseBuildImpl &build,
vector<LitFragment> &fragments, build_context &bc,
ProgramBuild &prog_build) {
ProgramBuild &prog_build, LitProto *fproto,
LitProto *drproto, LitProto *eproto,
LitProto *sbproto) {
DEBUG_PRINTF("%zu fragments\n", fragments.size());
auto lit_edge_map = findEdgesByLiteral(build);
for (auto &frag : fragments) {
DEBUG_PRINTF("frag_id=%u, lit_ids=[%s]\n", frag.fragment_id,
as_string_list(frag.lit_ids).c_str());
findInclusionGroups(fragments, fproto, drproto, eproto, sbproto);
auto lit_prog = makeFragmentProgram(build, bc, prog_build, frag.lit_ids,
lit_edge_map);
frag.lit_program_offset = writeProgram(bc, move(lit_prog));
buildFragmentPrograms(build, fragments, bc, prog_build, lit_edge_map);
// We only do delayed rebuild in streaming mode.
if (!build.cc.streaming) {
continue;
}
auto rebuild_prog = makeDelayRebuildProgram(build, prog_build,
frag.lit_ids);
frag.delay_program_offset = writeProgram(bc, move(rebuild_prog));
}
// update literal program offsets for literal matcher prototypes
updateLitProgramOffset(fragments, fproto, drproto, eproto, sbproto);
}
/**
@@ -3470,7 +3620,24 @@ bytecode_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
tie(proto.delayProgramOffset, proto.delay_count) =
writeDelayPrograms(*this, fragments, bc, prog_build);
buildLiteralPrograms(*this, fragments, bc, prog_build);
// Build floating HWLM matcher prototype.
rose_group fgroups = 0;
auto fproto = buildFloatingMatcherProto(*this, fragments,
longLitLengthThreshold,
&fgroups, &historyRequired);
// Build delay rebuild HWLM matcher prototype.
auto drproto = buildDelayRebuildMatcherProto(*this, fragments,
longLitLengthThreshold);
// Build EOD-anchored HWLM matcher prototype.
auto eproto = buildEodAnchoredMatcherProto(*this, fragments);
// Build small-block HWLM matcher prototype.
auto sbproto = buildSmallBlockMatcherProto(*this, fragments);
buildLiteralPrograms(*this, fragments, bc, prog_build, fproto.get(),
drproto.get(), eproto.get(), sbproto.get());
auto eod_prog = makeEodProgram(*this, bc, prog_build, eodNfaIterOffset);
proto.eodProgramOffset = writeProgram(bc, move(eod_prog));
@@ -3497,29 +3664,26 @@ bytecode_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
}
// Build floating HWLM matcher.
rose_group fgroups = 0;
auto ftable = buildFloatingMatcher(*this, fragments, longLitLengthThreshold,
&fgroups, &historyRequired);
auto ftable = buildHWLMMatcher(*this, fproto.get());
if (ftable) {
proto.fmatcherOffset = bc.engine_blob.add(ftable);
bc.resources.has_floating = true;
}
// Build delay rebuild HWLM matcher.
auto drtable = buildDelayRebuildMatcher(*this, fragments,
longLitLengthThreshold);
auto drtable = buildHWLMMatcher(*this, drproto.get());
if (drtable) {
proto.drmatcherOffset = bc.engine_blob.add(drtable);
}
// Build EOD-anchored HWLM matcher.
auto etable = buildEodAnchoredMatcher(*this, fragments);
auto etable = buildHWLMMatcher(*this, eproto.get());
if (etable) {
proto.ematcherOffset = bc.engine_blob.add(etable);
}
// Build small-block HWLM matcher.
auto sbtable = buildSmallBlockMatcher(*this, fragments);
auto sbtable = buildHWLMMatcher(*this, sbproto.get());
if (sbtable) {
proto.sbmatcherOffset = bc.engine_blob.add(sbtable);
}

View File

@@ -1463,6 +1463,12 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
}
PROGRAM_NEXT_INSTRUCTION
PROGRAM_CASE(INCLUDED_JUMP) {
os << " child_offset " << ri->child_offset << endl;
os << " squash " << ri->squash << endl;
}
PROGRAM_NEXT_INSTRUCTION
default:
os << " UNKNOWN (code " << int{code} << ")" << endl;
os << " <stopping>" << endl;

View File

@@ -636,4 +636,12 @@ void RoseInstrCheckMultipathShufti64::write(void *dest, RoseEngineBlob &blob,
inst->fail_jump = calc_jump(offset_map, this, target);
}
void RoseInstrIncludedJump::write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const {
RoseInstrBase::write(dest, blob, offset_map);
auto *inst = static_cast<impl_type *>(dest);
inst->child_offset = child_offset;
inst->squash = squash;
}
}

View File

@@ -2121,6 +2121,34 @@ public:
}
};
class RoseInstrIncludedJump
: public RoseInstrBaseNoTargets<ROSE_INSTR_INCLUDED_JUMP,
ROSE_STRUCT_INCLUDED_JUMP,
RoseInstrIncludedJump> {
public:
u32 child_offset;
u8 squash;
RoseInstrIncludedJump(u32 child_offset_in, u8 squash_in)
: child_offset(child_offset_in), squash(squash_in) {}
bool operator==(const RoseInstrIncludedJump &ri) const {
return child_offset == ri.child_offset && squash == ri.squash;
}
size_t hash() const override {
return hash_all(static_cast<int>(opcode), child_offset, squash);
}
void write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const override;
bool equiv_to(const RoseInstrIncludedJump &ri, const OffsetMap &,
const OffsetMap &) const {
return child_offset == ri.child_offset && squash == ri.squash;
}
};
class RoseInstrEnd
: public RoseInstrBaseTrivial<ROSE_INSTR_END, ROSE_STRUCT_END,
RoseInstrEnd> {

View File

@@ -46,6 +46,7 @@
#include "util/compile_context.h"
#include "util/compile_error.h"
#include "util/dump_charclass.h"
#include "util/make_unique.h"
#include "util/report.h"
#include "util/report_manager.h"
#include "util/verify_types.h"
@@ -699,8 +700,7 @@ struct MatcherProto {
static
void addFragmentLiteral(const RoseBuildImpl &build, MatcherProto &mp,
const LitFragment &f, u32 id, bool delay_rebuild,
size_t max_len) {
const LitFragment &f, u32 id, size_t max_len) {
const rose_literal_id &lit = build.literals.at(id);
DEBUG_PRINTF("lit='%s' (len %zu)\n", dumpString(lit.s).c_str(),
@@ -737,12 +737,10 @@ void addFragmentLiteral(const RoseBuildImpl &build, MatcherProto &mp,
return;
}
u32 prog_offset =
delay_rebuild ? f.delay_program_offset : f.lit_program_offset;
const auto &groups = f.groups;
mp.lits.emplace_back(move(s_final), nocase, noruns, prog_offset, groups,
msk, cmp);
mp.lits.emplace_back(move(s_final), nocase, noruns, f.fragment_id,
groups, msk, cmp);
}
static
@@ -837,8 +835,7 @@ MatcherProto makeMatcherProto(const RoseBuildImpl &build,
}
// Build our fragment (for the HWLM matcher) from the first literal.
addFragmentLiteral(build, mp, f, used_lit_ids.front(), delay_rebuild,
max_len);
addFragmentLiteral(build, mp, f, used_lit_ids.front(), max_len);
for (u32 id : used_lit_ids) {
const rose_literal_id &lit = build.literals.at(id);
@@ -876,8 +873,8 @@ void MatcherProto::insert(const MatcherProto &a) {
}
static
void buildAccel(const RoseBuildImpl &build, const MatcherProto &mp,
HWLM &hwlm) {
void buildAccel(const RoseBuildImpl &build,
const vector<AccelString> &accel_lits, HWLM &hwlm) {
if (!build.cc.grey.hamsterAccelForward) {
return;
}
@@ -886,49 +883,68 @@ void buildAccel(const RoseBuildImpl &build, const MatcherProto &mp,
return;
}
buildForwardAccel(&hwlm, mp.accel_lits, build.getInitialGroups());
buildForwardAccel(&hwlm, accel_lits, build.getInitialGroups());
}
bytecode_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
size_t longLitLengthThreshold,
rose_group *fgroups,
size_t *historyRequired) {
*fgroups = 0;
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
longLitLengthThreshold);
if (mp.lits.empty()) {
DEBUG_PRINTF("empty floating matcher\n");
bytecode_ptr<HWLM>
buildHWLMMatcher(const RoseBuildImpl &build, LitProto *litProto) {
if (!litProto) {
return nullptr;
}
dumpMatcherLiterals(mp.lits, "floating", build.cc.grey);
for (const hwlmLiteral &lit : mp.lits) {
*fgroups |= lit.groups;
}
auto hwlm = hwlmBuild(mp.lits, false, build.cc, build.getInitialGroups());
auto hwlm = hwlmBuild(*litProto->hwlmProto, build.cc,
build.getInitialGroups());
if (!hwlm) {
throw CompileError("Unable to generate bytecode.");
}
buildAccel(build, mp, *hwlm);
buildAccel(build, litProto->accel_lits, *hwlm);
if (build.cc.streaming) {
DEBUG_PRINTF("history_required=%zu\n", mp.history_required);
assert(mp.history_required <= build.cc.grey.maxHistoryAvailable);
*historyRequired = max(*historyRequired, mp.history_required);
}
DEBUG_PRINTF("built floating literal table size %zu bytes\n", hwlm.size());
DEBUG_PRINTF("built eod-anchored literal table size %zu bytes\n",
hwlm.size());
return hwlm;
}
bytecode_ptr<HWLM>
buildDelayRebuildMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
size_t longLitLengthThreshold) {
unique_ptr<LitProto>
buildFloatingMatcherProto(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
size_t longLitLengthThreshold,
rose_group *fgroups,
size_t *historyRequired) {
DEBUG_PRINTF("Floating literal matcher\n");
*fgroups = 0;
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
longLitLengthThreshold);
if (mp.lits.empty()) {
DEBUG_PRINTF("empty floating matcher\n");
return nullptr;
}
dumpMatcherLiterals(mp.lits, "floating", build.cc.grey);
for (const hwlmLiteral &lit : mp.lits) {
*fgroups |= lit.groups;
}
if (build.cc.streaming) {
DEBUG_PRINTF("history_required=%zu\n", mp.history_required);
assert(mp.history_required <= build.cc.grey.maxHistoryAvailable);
*historyRequired = max(*historyRequired, mp.history_required);
}
auto proto = hwlmBuildProto(mp.lits, false, build.cc);
if (!proto) {
throw CompileError("Unable to generate literal matcher proto.");
}
return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
}
unique_ptr<LitProto>
buildDelayRebuildMatcherProto(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
size_t longLitLengthThreshold) {
DEBUG_PRINTF("Delay literal matcher\n");
if (!build.cc.streaming) {
DEBUG_PRINTF("not streaming\n");
return nullptr;
@@ -942,20 +958,20 @@ buildDelayRebuildMatcher(const RoseBuildImpl &build,
}
dumpMatcherLiterals(mp.lits, "delay_rebuild", build.cc.grey);
auto hwlm = hwlmBuild(mp.lits, false, build.cc, build.getInitialGroups());
if (!hwlm) {
throw CompileError("Unable to generate bytecode.");
auto proto = hwlmBuildProto(mp.lits, false, build.cc);
if (!proto) {
throw CompileError("Unable to generate literal matcher proto.");
}
buildAccel(build, mp, *hwlm);
DEBUG_PRINTF("built delay rebuild table size %zu bytes\n", hwlm.size());
return hwlm;
return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
}
bytecode_ptr<HWLM>
buildSmallBlockMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments) {
unique_ptr<LitProto>
buildSmallBlockMatcherProto(const RoseBuildImpl &build,
const vector<LitFragment> &fragments) {
DEBUG_PRINTF("Small block literal matcher\n");
if (build.cc.streaming) {
DEBUG_PRINTF("streaming mode\n");
return nullptr;
@@ -1000,21 +1016,19 @@ buildSmallBlockMatcher(const RoseBuildImpl &build,
return nullptr;
}
auto hwlm = hwlmBuild(mp.lits, true, build.cc, build.getInitialGroups());
if (!hwlm) {
throw CompileError("Unable to generate bytecode.");
auto proto = hwlmBuildProto(mp.lits, false, build.cc);
if (!proto) {
throw CompileError("Unable to generate literal matcher proto.");
}
buildAccel(build, mp, *hwlm);
DEBUG_PRINTF("built small block literal table size %zu bytes\n",
hwlm.size());
return hwlm;
return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
}
bytecode_ptr<HWLM>
buildEodAnchoredMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments) {
unique_ptr<LitProto>
buildEodAnchoredMatcherProto(const RoseBuildImpl &build,
const vector<LitFragment> &fragments) {
DEBUG_PRINTF("Eod anchored literal matcher\n");
auto mp = makeMatcherProto(build, fragments, ROSE_EOD_ANCHORED, false,
build.ematcher_region_size);
@@ -1027,16 +1041,13 @@ buildEodAnchoredMatcher(const RoseBuildImpl &build,
assert(build.ematcher_region_size);
auto hwlm = hwlmBuild(mp.lits, true, build.cc, build.getInitialGroups());
if (!hwlm) {
throw CompileError("Unable to generate bytecode.");
auto proto = hwlmBuildProto(mp.lits, false, build.cc);
if (!proto) {
throw CompileError("Unable to generate literal matcher proto.");
}
buildAccel(build, mp, *hwlm);
DEBUG_PRINTF("built eod-anchored literal table size %zu bytes\n",
hwlm.size());
return hwlm;
return ue2::make_unique<LitProto>(move(proto), mp.accel_lits);
}
} // namespace ue2

View File

@@ -35,7 +35,10 @@
#define ROSE_BUILD_MATCHERS_H
#include "rose_build_impl.h"
#include "rose_build_lit_accel.h"
#include "hwlm/hwlm_build.h"
#include "util/bytecode_ptr.h"
#include "util/ue2string.h"
#include <vector>
@@ -44,38 +47,80 @@ struct HWLM;
namespace ue2 {
static constexpr u32 INVALID_FRAG_ID = ~0U;
struct LitFragment {
LitFragment(u32 fragment_id_in, rose_group groups_in, u32 lit_id)
: fragment_id(fragment_id_in), groups(groups_in), lit_ids({lit_id}) {}
LitFragment(u32 fragment_id_in, rose_group groups_in,
std::vector<u32> lit_ids_in)
: fragment_id(fragment_id_in), groups(groups_in),
lit_ids(std::move(lit_ids_in)) {}
LitFragment(u32 fragment_id_in, ue2_literal s_in,
rose_group groups_in, u32 lit_id)
: fragment_id(fragment_id_in), s(s_in), groups(groups_in),
lit_ids({lit_id}) {}
LitFragment(u32 fragment_id_in, ue2_literal s_in,
rose_group groups_in, std::vector<u32> lit_ids_in)
: fragment_id(fragment_id_in), s(s_in), groups(groups_in),
lit_ids(std::move(lit_ids_in)) {}
u32 fragment_id;
/**
* \brief literal fragment.
*/
ue2_literal s;
/**
* \brief FDR confirm squash mask for included literals.
*/
u8 squash;
/**
* \brief FDR confirm squash mask for included literals (Delayed
* literals only).
*/
u8 delay_squash;
/**
* \brief Fragment id of included literal.
*/
u32 included_frag_id = INVALID_FRAG_ID;
/**
* \brief Fragment Id of included literal (Delayed literals only).
*/
u32 included_delay_frag_id = INVALID_FRAG_ID;
rose_group groups;
std::vector<u32> lit_ids;
u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
};
bytecode_ptr<HWLM>
buildFloatingMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t longLitLengthThreshold, rose_group *fgroups,
size_t *historyRequired);
struct LitProto {
LitProto(std::unique_ptr<HWLMProto> hwlmProto_in,
std::vector<AccelString> &accel_lits_in)
: hwlmProto(std::move(hwlmProto_in)), accel_lits(accel_lits_in) {}
std::unique_ptr<HWLMProto> hwlmProto;
std::vector<AccelString> accel_lits;
};
bytecode_ptr<HWLM>
buildDelayRebuildMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t longLitLengthThreshold);
buildHWLMMatcher(const RoseBuildImpl &build, LitProto *proto);
bytecode_ptr<HWLM>
buildSmallBlockMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments);
std::unique_ptr<LitProto>
buildFloatingMatcherProto(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t longLitLengthThreshold,
rose_group *fgroups,
size_t *historyRequired);
bytecode_ptr<HWLM>
buildEodAnchoredMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments);
std::unique_ptr<LitProto>
buildDelayRebuildMatcherProto(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t longLitLengthThreshold);
std::unique_ptr<LitProto>
buildSmallBlockMatcherProto(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments);
std::unique_ptr<LitProto>
buildEodAnchoredMatcherProto(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments);
void findMoreLiteralMasks(RoseBuildImpl &build);

View File

@@ -2164,6 +2164,14 @@ RoseProgram makeBoundaryProgram(const RoseBuildImpl &build,
return prog;
}
void addIncludedJumpProgram(RoseProgram &program, u32 child_offset,
u8 squash) {
RoseProgram block;
block.add_before_end(make_unique<RoseInstrIncludedJump>(child_offset,
squash));
program.add_block(move(block));
}
static
void addPredBlockSingle(u32 pred_state, RoseProgram &pred_block,
RoseProgram &program) {

View File

@@ -282,6 +282,7 @@ void recordLongLiterals(std::vector<ue2_case_string> &longLiterals,
void recordResources(RoseResources &resources, const RoseProgram &program);
void addIncludedJumpProgram(RoseProgram &program, u32 child_offset, u8 squash);
} // namespace ue2
#endif // ROSE_BUILD_PROGRAM_H

View File

@@ -178,7 +178,12 @@ enum RoseInstructionCode {
*/
ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64,
LAST_ROSE_INSTRUCTION = ROSE_INSTR_CHECK_MULTIPATH_SHUFTI_64 //!< Sentinel.
/**
* \brief Jump to the program of included literal.
*/
ROSE_INSTR_INCLUDED_JUMP,
LAST_ROSE_INSTRUCTION = ROSE_INSTR_INCLUDED_JUMP //!< Sentinel.
};
struct ROSE_STRUCT_END {
@@ -625,4 +630,10 @@ struct ROSE_STRUCT_CHECK_MULTIPATH_SHUFTI_64 {
s32 last_start; //!< The latest start offset among 8 paths.
u32 fail_jump; //!< Jump forward this many bytes on failure.
};
struct ROSE_STRUCT_INCLUDED_JUMP {
u8 code; //!< From enum RoseInstructionCode.
u8 squash; //!< FDR confirm squash mask for included literal.
u32 child_offset; //!< Program offset of included literal.
};
#endif // ROSE_ROSE_PROGRAM_H