rose: group final ids by fragment

This commit is contained in:
Justin Viiret 2016-12-12 17:08:06 +11:00 committed by Matthew Barr
parent 07a6b6510c
commit eb14792a63
15 changed files with 354 additions and 122 deletions

View File

@ -37,6 +37,7 @@
#include "ue2common.h" #include "ue2common.h"
#include <string> #include <string>
#include <tuple>
#include <vector> #include <vector>
namespace ue2 { namespace ue2 {
@ -111,6 +112,19 @@ struct hwlmLiteral {
: hwlmLiteral(s_in, nocase_in, false, id_in, HWLM_ALL_GROUPS, {}, {}) {} : hwlmLiteral(s_in, nocase_in, false, id_in, HWLM_ALL_GROUPS, {}, {}) {}
}; };
inline
bool operator<(const hwlmLiteral &a, const hwlmLiteral &b) {
return std::tie(a.id, a.s, a.nocase, a.noruns, a.groups, a.msk, a.cmp) <
std::tie(b.id, b.s, b.nocase, b.noruns, b.groups, b.msk, b.cmp);
}
inline
bool operator==(const hwlmLiteral &a, const hwlmLiteral &b) {
return a.id == b.id && a.s == b.s && a.nocase == b.nocase &&
a.noruns == b.noruns && a.groups == b.groups && a.msk == b.msk &&
a.cmp == b.cmp;
}
/** /**
* Consistency test; returns false if the given msk/cmp test can never match * Consistency test; returns false if the given msk/cmp test can never match
* the literal string s. * the literal string s.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015-2016, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -253,24 +253,6 @@ hwlmcb_rv_t roseProcessMatchInline(const struct RoseEngine *t,
flags); flags);
} }
/**
* \brief Run the program for the given literal ID, with the interpreter
* out of line.
*
* Assumes not in_anchored.
*/
static really_inline
hwlmcb_rv_t roseProcessMatch(const struct RoseEngine *t,
struct hs_scratch *scratch, u64a end,
size_t match_len, u32 id) {
DEBUG_PRINTF("id=%u\n", id);
const u32 *programs = getByOffset(t, t->litProgramOffset);
assert(id < t->literalCount);
const u64a som = 0;
const u8 flags = 0;
return roseRunProgram(t, scratch, programs[id], som, end, match_len, flags);
}
static rose_inline static rose_inline
hwlmcb_rv_t playDelaySlot(const struct RoseEngine *t, hwlmcb_rv_t playDelaySlot(const struct RoseEngine *t,
struct hs_scratch *scratch, struct hs_scratch *scratch,
@ -290,14 +272,17 @@ hwlmcb_rv_t playDelaySlot(const struct RoseEngine *t,
roseFlushLastByteHistory(t, scratch, offset); roseFlushLastByteHistory(t, scratch, offset);
tctxt->lastEndOffset = offset; tctxt->lastEndOffset = offset;
const u32 *programs = getByOffset(t, t->delayProgramOffset);
for (u32 it = fatbit_iterate(vicSlot, delay_count, MMB_INVALID); for (u32 it = fatbit_iterate(vicSlot, delay_count, MMB_INVALID);
it != MMB_INVALID; it = fatbit_iterate(vicSlot, delay_count, it)) { it != MMB_INVALID; it = fatbit_iterate(vicSlot, delay_count, it)) {
u32 literal_id = t->delay_base_id + it;
UNUSED rose_group old_groups = tctxt->groups; UNUSED rose_group old_groups = tctxt->groups;
DEBUG_PRINTF("DELAYED MATCH id=%u offset=%llu\n", literal_id, offset); DEBUG_PRINTF("DELAYED MATCH id=%u offset=%llu\n", it, offset);
hwlmcb_rv_t rv = roseProcessMatch(t, scratch, offset, 0, literal_id); const u64a som = 0;
const u8 flags = 0;
hwlmcb_rv_t rv = roseRunProgram(t, scratch, programs[it], som, offset,
0, flags);
DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups); DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
/* delayed literals can't safely set groups. /* delayed literals can't safely set groups.
@ -322,16 +307,19 @@ hwlmcb_rv_t flushAnchoredLiteralAtLoc(const struct RoseEngine *t,
struct fatbit *curr_row = getAnchoredLiteralLog(scratch)[curr_loc - 1]; struct fatbit *curr_row = getAnchoredLiteralLog(scratch)[curr_loc - 1];
u32 region_width = t->anchored_count; u32 region_width = t->anchored_count;
const u32 *programs = getByOffset(t, t->anchoredProgramOffset);
DEBUG_PRINTF("report matches at curr loc\n"); DEBUG_PRINTF("report matches at curr loc\n");
for (u32 it = fatbit_iterate(curr_row, region_width, MMB_INVALID); for (u32 it = fatbit_iterate(curr_row, region_width, MMB_INVALID);
it != MMB_INVALID; it = fatbit_iterate(curr_row, region_width, it)) { it != MMB_INVALID; it = fatbit_iterate(curr_row, region_width, it)) {
DEBUG_PRINTF("it = %u/%u\n", it, region_width); DEBUG_PRINTF("it = %u/%u\n", it, region_width);
u32 literal_id = t->anchored_base_id + it;
rose_group old_groups = tctxt->groups; rose_group old_groups = tctxt->groups;
DEBUG_PRINTF("ANCH REPLAY MATCH id=%u offset=%u\n", literal_id, DEBUG_PRINTF("ANCH REPLAY MATCH id=%u offset=%u\n", it, curr_loc);
curr_loc); const u64a som = 0;
hwlmcb_rv_t rv = roseProcessMatch(t, scratch, curr_loc, 0, literal_id); const u8 flags = 0;
hwlmcb_rv_t rv = roseRunProgram(t, scratch, programs[it], som, curr_loc,
0, flags);
DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups); DEBUG_PRINTF("DONE groups=0x%016llx\n", tctxt->groups);
/* anchored literals can't safely set groups. /* anchored literals can't safely set groups.

View File

@ -1554,7 +1554,9 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t,
if (end < ri->min_offset) { if (end < ri->min_offset) {
DEBUG_PRINTF("halt: before min_offset=%u\n", DEBUG_PRINTF("halt: before min_offset=%u\n",
ri->min_offset); ri->min_offset);
return HWLM_CONTINUE_MATCHING; assert(ri->fail_jump); // must progress
pc += ri->fail_jump;
continue;
} }
} }
PROGRAM_NEXT_INSTRUCTION PROGRAM_NEXT_INSTRUCTION

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015-2016, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -208,7 +208,8 @@ void remapAnchoredReports(RoseBuildImpl &build) {
* raw_dfa with program offsets. * raw_dfa with program offsets.
*/ */
static static
void remapIdsToPrograms(raw_dfa &rdfa, const vector<u32> &litPrograms) { void remapIdsToPrograms(raw_dfa &rdfa, const vector<u32> &litPrograms,
const map<u32, u32> &final_to_frag_map) {
for (dstate &ds : rdfa.states) { for (dstate &ds : rdfa.states) {
assert(ds.reports_eod.empty()); // Not used in anchored matcher. assert(ds.reports_eod.empty()); // Not used in anchored matcher.
if (ds.reports.empty()) { if (ds.reports.empty()) {
@ -216,9 +217,11 @@ void remapIdsToPrograms(raw_dfa &rdfa, const vector<u32> &litPrograms) {
} }
flat_set<ReportID> new_reports; flat_set<ReportID> new_reports;
for (auto id : ds.reports) { for (auto final_id : ds.reports) {
assert(id < litPrograms.size()); assert(contains(final_to_frag_map, final_id));
new_reports.insert(litPrograms.at(id)); auto frag_id = final_to_frag_map.at(final_id);
assert(frag_id < litPrograms.size());
new_reports.insert(litPrograms.at(frag_id));
} }
ds.reports = move(new_reports); ds.reports = move(new_reports);
} }
@ -846,7 +849,8 @@ vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
aligned_unique_ptr<anchored_matcher_info> aligned_unique_ptr<anchored_matcher_info>
buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas, buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas,
const vector<u32> &litPrograms, size_t *asize) { const vector<u32> &litPrograms,
const map<u32, u32> &final_to_frag_map, size_t *asize) {
const CompileContext &cc = build.cc; const CompileContext &cc = build.cc;
if (dfas.empty()) { if (dfas.empty()) {
@ -856,7 +860,7 @@ buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas,
} }
for (auto &rdfa : dfas) { for (auto &rdfa : dfas) {
remapIdsToPrograms(rdfa, litPrograms); remapIdsToPrograms(rdfa, litPrograms, final_to_frag_map);
} }
vector<aligned_unique_ptr<NFA>> nfas; vector<aligned_unique_ptr<NFA>> nfas;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015-2016, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -59,7 +59,9 @@ std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build);
*/ */
aligned_unique_ptr<anchored_matcher_info> aligned_unique_ptr<anchored_matcher_info>
buildAnchoredMatcher(RoseBuildImpl &build, std::vector<raw_dfa> &dfas, buildAnchoredMatcher(RoseBuildImpl &build, std::vector<raw_dfa> &dfas,
const std::vector<u32> &litPrograms, size_t *asize); const std::vector<u32> &litPrograms,
const std::map<u32, u32> &final_to_frag_map,
size_t *asize);
u32 anchoredStateSize(const anchored_matcher_info &atable); u32 anchoredStateSize(const anchored_matcher_info &atable);

View File

@ -4346,7 +4346,9 @@ void makeCheckLitEarlyInstruction(const RoseBuildImpl &build, build_context &bc,
assert(min_offset < UINT32_MAX); assert(min_offset < UINT32_MAX);
DEBUG_PRINTF("adding lit early check, min_offset=%u\n", min_offset); DEBUG_PRINTF("adding lit early check, min_offset=%u\n", min_offset);
program.add_before_end(make_unique<RoseInstrCheckLitEarly>(min_offset)); const auto *end_inst = program.end_instruction();
program.add_before_end(
make_unique<RoseInstrCheckLitEarly>(min_offset, end_inst));
} }
static static
@ -4528,9 +4530,33 @@ RoseProgram buildLiteralProgram(RoseBuildImpl &build, build_context &bc,
} }
static static
u32 writeLiteralProgram(RoseBuildImpl &build, build_context &bc, u32 final_id, RoseProgram buildLiteralProgram(RoseBuildImpl &build, build_context &bc,
const vector<RoseEdge> &lit_edges) { const flat_set<u32> &final_ids,
RoseProgram program = buildLiteralProgram(build, bc, final_id, lit_edges); const map<u32, vector<RoseEdge>> &lit_edges) {
assert(!final_ids.empty());
DEBUG_PRINTF("entry, %zu final ids\n", final_ids.size());
const vector<RoseEdge> no_edges;
RoseProgram program;
for (const auto &final_id : final_ids) {
const auto *edges_ptr = &no_edges;
if (contains(lit_edges, final_id)) {
edges_ptr = &(lit_edges.at(final_id));
}
auto prog = buildLiteralProgram(build, bc, final_id, *edges_ptr);
DEBUG_PRINTF("final_id=%u, prog has %zu entries\n", final_id,
prog.size());
program.add_block(move(prog));
}
return program;
}
static
u32 writeLiteralProgram(RoseBuildImpl &build, build_context &bc,
const flat_set<u32> &final_ids,
const map<u32, vector<RoseEdge>> &lit_edges) {
RoseProgram program = buildLiteralProgram(build, bc, final_ids, lit_edges);
if (program.empty()) { if (program.empty()) {
return 0; return 0;
} }
@ -4540,18 +4566,26 @@ u32 writeLiteralProgram(RoseBuildImpl &build, build_context &bc, u32 final_id,
static static
u32 buildDelayRebuildProgram(RoseBuildImpl &build, build_context &bc, u32 buildDelayRebuildProgram(RoseBuildImpl &build, build_context &bc,
u32 final_id) { const flat_set<u32> &final_ids) {
RoseProgram program;
for (const auto &final_id : final_ids) {
const auto &lit_infos = getLiteralInfoByFinalId(build, final_id); const auto &lit_infos = getLiteralInfoByFinalId(build, final_id);
const auto &arb_lit_info = **lit_infos.begin(); const auto &arb_lit_info = **lit_infos.begin();
if (arb_lit_info.delayed_ids.empty()) { if (arb_lit_info.delayed_ids.empty()) {
return 0; // No delayed IDs, no work to do. continue; // No delayed IDs, no work to do.
} }
RoseProgram program; RoseProgram prog;
makeCheckLiteralInstruction(build, bc, final_id, program); makeCheckLiteralInstruction(build, bc, final_id, prog);
makeCheckLitMaskInstruction(build, bc, final_id, program); makeCheckLitMaskInstruction(build, bc, final_id, prog);
makePushDelayedInstructions(build, final_id, program); makePushDelayedInstructions(build, final_id, prog);
assert(!program.empty()); program.add_block(move(prog));
}
if (program.empty()) {
return 0;
}
applyFinalSpecialisation(program); applyFinalSpecialisation(program);
return writeProgram(bc, move(program)); return writeProgram(bc, move(program));
} }
@ -4590,27 +4624,104 @@ map<u32, vector<RoseEdge>> findEdgesByLiteral(const RoseBuildImpl &build) {
return lit_edge_map; return lit_edge_map;
} }
static
rose_literal_id getFragment(const rose_literal_id &lit) {
if (lit.s.length() <= ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("whole lit is frag\n");
return lit;
}
rose_literal_id frag = lit;
frag.s = frag.s.substr(frag.s.length() - ROSE_SHORT_LITERAL_LEN_MAX);
DEBUG_PRINTF("fragment: %s\n", dumpString(frag.s).c_str());
return frag;
}
map<u32, u32> groupByFragment(const RoseBuildImpl &build) {
u32 frag_id = 0;
map<u32, u32> final_to_frag;
map<rose_literal_id, vector<u32>> frag_lits;
for (const auto &m : build.final_id_to_literal) {
u32 final_id = m.first;
const auto &lit_ids = m.second;
assert(!lit_ids.empty());
if (lit_ids.size() > 1) {
final_to_frag.emplace(final_id, frag_id++);
continue;
}
const auto lit_id = *lit_ids.begin();
const auto &lit = build.literals.right.at(lit_id);
if (lit.s.length() < ROSE_SHORT_LITERAL_LEN_MAX) {
final_to_frag.emplace(final_id, frag_id++);
continue;
}
// Combining exploded fragments with others is unsafe.
const auto &info = build.literal_info[lit_id];
if (info.requires_explode) {
final_to_frag.emplace(final_id, frag_id++);
continue;
}
DEBUG_PRINTF("fragment candidate: final_id=%u %s\n", final_id,
dumpString(lit.s).c_str());
auto frag = getFragment(lit);
frag_lits[frag].push_back(final_id);
}
for (const auto &m : frag_lits) {
DEBUG_PRINTF("frag %s -> ids: %s\n", dumpString(m.first.s).c_str(),
as_string_list(m.second).c_str());
for (const auto final_id : m.second) {
assert(!contains(final_to_frag, final_id));
final_to_frag.emplace(final_id, frag_id);
}
frag_id++;
}
return final_to_frag;
}
/** /**
* \brief Build the interpreter programs for each literal. * \brief Build the interpreter programs for each literal.
* *
* Returns the base of the literal program list and the base of the delay * Returns the following as a tuple:
* rebuild program list. *
* - base of the literal program list
* - base of the delay rebuild program list
* - total number of literal fragments
*/ */
static static
pair<u32, u32> buildLiteralPrograms(RoseBuildImpl &build, build_context &bc) { tuple<u32, u32, u32>
const u32 num_literals = build.final_id_to_literal.size(); buildLiteralPrograms(RoseBuildImpl &build, build_context &bc,
const map<u32, u32> &final_to_frag_map) {
// Build a reverse mapping from fragment -> final_id.
map<u32, flat_set<u32>> frag_to_final_map;
for (const auto &m : final_to_frag_map) {
frag_to_final_map[m.second].insert(m.first);
}
const u32 num_fragments = verify_u32(frag_to_final_map.size());
DEBUG_PRINTF("%u fragments\n", num_fragments);
auto lit_edge_map = findEdgesByLiteral(build); auto lit_edge_map = findEdgesByLiteral(build);
bc.litPrograms.resize(num_literals); bc.litPrograms.resize(num_fragments);
vector<u32> delayRebuildPrograms(num_literals); vector<u32> delayRebuildPrograms(num_fragments);
for (u32 finalId = 0; finalId != num_literals; ++finalId) { for (u32 frag_id = 0; frag_id != num_fragments; ++frag_id) {
const auto &lit_edges = lit_edge_map[finalId]; const auto &final_ids = frag_to_final_map[frag_id];
DEBUG_PRINTF("frag_id=%u, final_ids=[%s]\n", frag_id,
as_string_list(final_ids).c_str());
bc.litPrograms[finalId] = bc.litPrograms[frag_id] =
writeLiteralProgram(build, bc, finalId, lit_edges); writeLiteralProgram(build, bc, final_ids, lit_edge_map);
delayRebuildPrograms[finalId] = delayRebuildPrograms[frag_id] =
buildDelayRebuildProgram(build, bc, finalId); buildDelayRebuildProgram(build, bc, final_ids);
} }
u32 litProgramsOffset = u32 litProgramsOffset =
@ -4618,7 +4729,40 @@ pair<u32, u32> buildLiteralPrograms(RoseBuildImpl &build, build_context &bc) {
u32 delayRebuildProgramsOffset = bc.engine_blob.add( u32 delayRebuildProgramsOffset = bc.engine_blob.add(
begin(delayRebuildPrograms), end(delayRebuildPrograms)); begin(delayRebuildPrograms), end(delayRebuildPrograms));
return {litProgramsOffset, delayRebuildProgramsOffset}; return tuple<u32, u32, u32>{litProgramsOffset, delayRebuildProgramsOffset,
num_fragments};
}
static
u32 buildDelayPrograms(RoseBuildImpl &build, build_context &bc) {
auto lit_edge_map = findEdgesByLiteral(build);
vector<u32> programs;
for (u32 final_id = build.delay_base_id;
final_id < build.final_id_to_literal.size(); final_id++) {
u32 offset = writeLiteralProgram(build, bc, {final_id}, lit_edge_map);
programs.push_back(offset);
}
DEBUG_PRINTF("%zu delay programs\n", programs.size());
return bc.engine_blob.add(begin(programs), end(programs));
}
static
u32 buildAnchoredPrograms(RoseBuildImpl &build, build_context &bc) {
auto lit_edge_map = findEdgesByLiteral(build);
vector<u32> programs;
for (u32 final_id = build.anchored_base_id;
final_id < build.delay_base_id; final_id++) {
u32 offset = writeLiteralProgram(build, bc, {final_id}, lit_edge_map);
programs.push_back(offset);
}
DEBUG_PRINTF("%zu anchored programs\n", programs.size());
return bc.engine_blob.add(begin(programs), end(programs));
} }
/** /**
@ -5253,6 +5397,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
DEBUG_PRINTF("longLitLengthThreshold=%zu\n", longLitLengthThreshold); DEBUG_PRINTF("longLitLengthThreshold=%zu\n", longLitLengthThreshold);
allocateFinalLiteralId(*this); allocateFinalLiteralId(*this);
auto final_to_frag_map = groupByFragment(*this);
auto anchored_dfas = buildAnchoredDfas(*this); auto anchored_dfas = buildAnchoredDfas(*this);
@ -5316,8 +5461,12 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
u32 litProgramOffset; u32 litProgramOffset;
u32 litDelayRebuildProgramOffset; u32 litDelayRebuildProgramOffset;
tie(litProgramOffset, litDelayRebuildProgramOffset) = u32 litProgramCount;
buildLiteralPrograms(*this, bc); tie(litProgramOffset, litDelayRebuildProgramOffset, litProgramCount) =
buildLiteralPrograms(*this, bc, final_to_frag_map);
u32 delayProgramOffset = buildDelayPrograms(*this, bc);
u32 anchoredProgramOffset = buildAnchoredPrograms(*this, bc);
u32 eodProgramOffset = writeEodProgram(*this, bc, eodNfaIterOffset); u32 eodProgramOffset = writeEodProgram(*this, bc, eodNfaIterOffset);
@ -5354,7 +5503,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
size_t asize = 0; size_t asize = 0;
u32 amatcherOffset = 0; u32 amatcherOffset = 0;
auto atable = buildAnchoredMatcher(*this, anchored_dfas, bc.litPrograms, auto atable = buildAnchoredMatcher(*this, anchored_dfas, bc.litPrograms,
&asize); final_to_frag_map, &asize);
if (atable) { if (atable) {
currOffset = ROUNDUP_CL(currOffset); currOffset = ROUNDUP_CL(currOffset);
amatcherOffset = currOffset; amatcherOffset = currOffset;
@ -5365,7 +5514,8 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
rose_group fgroups = 0; rose_group fgroups = 0;
size_t fsize = 0; size_t fsize = 0;
auto ftable = buildFloatingMatcher(*this, bc.longLitLengthThreshold, auto ftable = buildFloatingMatcher(*this, bc.longLitLengthThreshold,
&fgroups, &fsize, &historyRequired); final_to_frag_map, &fgroups, &fsize,
&historyRequired);
u32 fmatcherOffset = 0; u32 fmatcherOffset = 0;
if (ftable) { if (ftable) {
currOffset = ROUNDUP_CL(currOffset); currOffset = ROUNDUP_CL(currOffset);
@ -5375,7 +5525,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
// Build EOD-anchored HWLM matcher. // Build EOD-anchored HWLM matcher.
size_t esize = 0; size_t esize = 0;
auto etable = buildEodAnchoredMatcher(*this, &esize); auto etable = buildEodAnchoredMatcher(*this, final_to_frag_map, &esize);
u32 ematcherOffset = 0; u32 ematcherOffset = 0;
if (etable) { if (etable) {
currOffset = ROUNDUP_CL(currOffset); currOffset = ROUNDUP_CL(currOffset);
@ -5385,7 +5535,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
// Build small-block HWLM matcher. // Build small-block HWLM matcher.
size_t sbsize = 0; size_t sbsize = 0;
auto sbtable = buildSmallBlockMatcher(*this, &sbsize); auto sbtable = buildSmallBlockMatcher(*this, final_to_frag_map, &sbsize);
u32 sbmatcherOffset = 0; u32 sbmatcherOffset = 0;
if (sbtable) { if (sbtable) {
currOffset = ROUNDUP_CL(currOffset); currOffset = ROUNDUP_CL(currOffset);
@ -5495,11 +5645,13 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildFinalEngine(u32 minWidth) {
engine->needsCatchup = bc.needs_catchup ? 1 : 0; engine->needsCatchup = bc.needs_catchup ? 1 : 0;
engine->literalCount = verify_u32(final_id_to_literal.size()); engine->literalCount = litProgramCount;
engine->litProgramOffset = litProgramOffset; engine->litProgramOffset = litProgramOffset;
engine->litDelayRebuildProgramOffset = litDelayRebuildProgramOffset; engine->litDelayRebuildProgramOffset = litDelayRebuildProgramOffset;
engine->reportProgramOffset = reportProgramOffset; engine->reportProgramOffset = reportProgramOffset;
engine->reportProgramCount = reportProgramCount; engine->reportProgramCount = reportProgramCount;
engine->delayProgramOffset = delayProgramOffset;
engine->anchoredProgramOffset = anchoredProgramOffset;
engine->runtimeImpl = pickRuntimeImpl(*this, bc, outfixEndQueue); engine->runtimeImpl = pickRuntimeImpl(*this, bc, outfixEndQueue);
engine->mpvTriggeredByLeaf = anyEndfixMpvTriggers(*this); engine->mpvTriggeredByLeaf = anyEndfixMpvTriggers(*this);

View File

@ -505,19 +505,25 @@ void dumpRoseTestLiterals(const RoseBuildImpl &build, const string &base) {
size_t longLitLengthThreshold = size_t longLitLengthThreshold =
calcLongLitThreshold(build, historyRequired); calcLongLitThreshold(build, historyRequired);
auto mp = makeMatcherProto(build, ROSE_ANCHORED, longLitLengthThreshold); const auto final_to_frag_map = groupByFragment(build);
auto mp = makeMatcherProto(build, final_to_frag_map, ROSE_ANCHORED,
longLitLengthThreshold);
dumpTestLiterals(base + "rose_anchored_test_literals.txt", mp.lits); dumpTestLiterals(base + "rose_anchored_test_literals.txt", mp.lits);
mp = makeMatcherProto(build, ROSE_FLOATING, longLitLengthThreshold); mp = makeMatcherProto(build, final_to_frag_map, ROSE_FLOATING,
longLitLengthThreshold);
dumpTestLiterals(base + "rose_float_test_literals.txt", mp.lits); dumpTestLiterals(base + "rose_float_test_literals.txt", mp.lits);
mp = makeMatcherProto(build, ROSE_EOD_ANCHORED, build.ematcher_region_size); mp = makeMatcherProto(build, final_to_frag_map, ROSE_EOD_ANCHORED,
build.ematcher_region_size);
dumpTestLiterals(base + "rose_eod_test_literals.txt", mp.lits); dumpTestLiterals(base + "rose_eod_test_literals.txt", mp.lits);
if (!build.cc.streaming) { if (!build.cc.streaming) {
mp = makeMatcherProto(build, ROSE_FLOATING, ROSE_SMALL_BLOCK_LEN, mp = makeMatcherProto(build, final_to_frag_map, ROSE_FLOATING,
ROSE_SMALL_BLOCK_LEN); ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
auto mp2 = makeMatcherProto(build, ROSE_ANCHORED_SMALL_BLOCK, auto mp2 = makeMatcherProto(build, final_to_frag_map,
ROSE_ANCHORED_SMALL_BLOCK,
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN); ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
mp.lits.insert(end(mp.lits), begin(mp2.lits), end(mp2.lits)); mp.lits.insert(end(mp.lits), begin(mp2.lits), end(mp2.lits));
dumpTestLiterals(base + "rose_smallblock_test_literals.txt", mp.lits); dumpTestLiterals(base + "rose_smallblock_test_literals.txt", mp.lits);

View File

@ -644,6 +644,8 @@ void normaliseLiteralMask(const ue2_literal &s, std::vector<u8> &msk,
bool canImplementGraphs(const RoseBuildImpl &tbi); bool canImplementGraphs(const RoseBuildImpl &tbi);
#endif #endif
std::map<u32, u32> groupByFragment(const RoseBuildImpl &build);
} // namespace ue2 } // namespace ue2
#endif /* ROSE_BUILD_IMPL_H_17E20A3C6935D6 */ #endif /* ROSE_BUILD_IMPL_H_17E20A3C6935D6 */

View File

@ -632,7 +632,27 @@ u64a literalMinReportOffset(const RoseBuildImpl &build,
return lit_min_offset; return lit_min_offset;
} }
static
map<u32, hwlm_group_t> makeFragGroupMap(const RoseBuildImpl &build,
const map<u32, u32> &final_to_frag_map) {
map<u32, hwlm_group_t> frag_to_group;
for (const auto &m : final_to_frag_map) {
u32 final_id = m.first;
u32 frag_id = m.second;
hwlm_group_t groups = 0;
const auto &lits = build.final_id_to_literal.at(final_id);
for (auto lit_id : lits) {
groups |= build.literal_info[lit_id].group_mask;
}
frag_to_group[frag_id] |= groups;
}
return frag_to_group;
}
MatcherProto makeMatcherProto(const RoseBuildImpl &build, MatcherProto makeMatcherProto(const RoseBuildImpl &build,
const map<u32, u32> &final_to_frag_map,
rose_literal_table table, size_t max_len, rose_literal_table table, size_t max_len,
u32 max_offset) { u32 max_offset) {
MatcherProto mp; MatcherProto mp;
@ -710,23 +730,26 @@ MatcherProto makeMatcherProto(const RoseBuildImpl &build,
msk, cmp); msk, cmp);
} }
} else { } else {
string s = lit.get_string(); auto lit_final = lit; // copy
bool nocase = lit.any_nocase();
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("truncating to tail of length %zu\n",
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
lit_final.erase(0, lit_final.length() -
ROSE_SHORT_LITERAL_LEN_MAX);
// We shouldn't have set a threshold below 8 chars.
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
assert(!noruns);
}
const auto &s = lit_final.get_string();
bool nocase = lit_final.any_nocase();
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, " DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
"cmp=%s\n", "cmp=%s\n",
final_id, escapeString(s).c_str(), (int)nocase, noruns, final_id, escapeString(s).c_str(), (int)nocase, noruns,
dumpMask(msk).c_str(), dumpMask(cmp).c_str()); dumpMask(msk).c_str(), dumpMask(cmp).c_str());
if (s.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("truncating to tail of length %zu\n",
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
s.erase(0, s.length() - ROSE_SHORT_LITERAL_LEN_MAX);
// We shouldn't have set a threshold below 8 chars.
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
assert(!noruns);
}
if (!maskIsConsistent(s, nocase, msk, cmp)) { if (!maskIsConsistent(s, nocase, msk, cmp)) {
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n"); DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
continue; continue;
@ -738,18 +761,32 @@ MatcherProto makeMatcherProto(const RoseBuildImpl &build,
} }
} }
auto frag_group_map = makeFragGroupMap(build, final_to_frag_map);
for (auto &lit : mp.lits) {
u32 final_id = lit.id;
assert(contains(final_to_frag_map, final_id));
lit.id = final_to_frag_map.at(final_id);
assert(contains(frag_group_map, lit.id));
lit.groups = frag_group_map.at(lit.id);
}
sort(begin(mp.lits), end(mp.lits));
mp.lits.erase(unique(begin(mp.lits), end(mp.lits)), end(mp.lits));
return mp; return mp;
} }
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build, aligned_unique_ptr<HWLM>
size_t longLitLengthThreshold, buildFloatingMatcher(const RoseBuildImpl &build, size_t longLitLengthThreshold,
rose_group *fgroups, const map<u32, u32> &final_to_frag_map,
size_t *fsize, rose_group *fgroups, size_t *fsize,
size_t *historyRequired) { size_t *historyRequired) {
*fsize = 0; *fsize = 0;
*fgroups = 0; *fgroups = 0;
auto mp = makeMatcherProto(build, ROSE_FLOATING, longLitLengthThreshold); auto mp = makeMatcherProto(build, final_to_frag_map, ROSE_FLOATING,
longLitLengthThreshold);
if (mp.lits.empty()) { if (mp.lits.empty()) {
DEBUG_PRINTF("empty floating matcher\n"); DEBUG_PRINTF("empty floating matcher\n");
return nullptr; return nullptr;
@ -776,8 +813,9 @@ aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
return hwlm; return hwlm;
} }
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build, aligned_unique_ptr<HWLM>
size_t *sbsize) { buildSmallBlockMatcher(const RoseBuildImpl &build,
const map<u32, u32> &final_to_frag_map, size_t *sbsize) {
*sbsize = 0; *sbsize = 0;
if (build.cc.streaming) { if (build.cc.streaming) {
@ -792,8 +830,8 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
return nullptr; return nullptr;
} }
auto mp = makeMatcherProto(build, ROSE_FLOATING, ROSE_SMALL_BLOCK_LEN, auto mp = makeMatcherProto(build, final_to_frag_map, ROSE_FLOATING,
ROSE_SMALL_BLOCK_LEN); ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
if (mp.lits.empty()) { if (mp.lits.empty()) {
DEBUG_PRINTF("no floating table\n"); DEBUG_PRINTF("no floating table\n");
return nullptr; return nullptr;
@ -803,8 +841,8 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
} }
auto mp_anchored = auto mp_anchored =
makeMatcherProto(build, ROSE_ANCHORED_SMALL_BLOCK, ROSE_SMALL_BLOCK_LEN, makeMatcherProto(build, final_to_frag_map, ROSE_ANCHORED_SMALL_BLOCK,
ROSE_SMALL_BLOCK_LEN); ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
if (mp_anchored.lits.empty()) { if (mp_anchored.lits.empty()) {
DEBUG_PRINTF("no small-block anchored literals\n"); DEBUG_PRINTF("no small-block anchored literals\n");
return nullptr; return nullptr;
@ -834,12 +872,13 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
return hwlm; return hwlm;
} }
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build, aligned_unique_ptr<HWLM>
size_t *esize) { buildEodAnchoredMatcher(const RoseBuildImpl &build,
const map<u32, u32> &final_to_frag_map, size_t *esize) {
*esize = 0; *esize = 0;
auto mp = auto mp = makeMatcherProto(build, final_to_frag_map, ROSE_EOD_ANCHORED,
makeMatcherProto(build, ROSE_EOD_ANCHORED, build.ematcher_region_size); build.ematcher_region_size);
if (mp.lits.empty()) { if (mp.lits.empty()) {
DEBUG_PRINTF("no eod anchored literals\n"); DEBUG_PRINTF("no eod anchored literals\n");

View File

@ -36,6 +36,7 @@
#include "rose_build_impl.h" #include "rose_build_impl.h"
#include <map>
#include <vector> #include <vector>
struct HWLM; struct HWLM;
@ -57,19 +58,25 @@ struct MatcherProto {
* only lead to a pattern match after max_offset may be excluded. * only lead to a pattern match after max_offset may be excluded.
*/ */
MatcherProto makeMatcherProto(const RoseBuildImpl &build, MatcherProto makeMatcherProto(const RoseBuildImpl &build,
const std::map<u32, u32> &final_to_frag_map,
rose_literal_table table, size_t max_len, rose_literal_table table, size_t max_len,
u32 max_offset = ROSE_BOUND_INF); u32 max_offset = ROSE_BOUND_INF);
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build, aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
size_t longLitLengthThreshold, size_t longLitLengthThreshold,
const std::map<u32, u32> &final_to_frag_map,
rose_group *fgroups, rose_group *fgroups,
size_t *fsize, size_t *fsize,
size_t *historyRequired); size_t *historyRequired);
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build, aligned_unique_ptr<HWLM>
buildSmallBlockMatcher(const RoseBuildImpl &build,
const std::map<u32, u32> &final_to_frag_map,
size_t *sbsize); size_t *sbsize);
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build, aligned_unique_ptr<HWLM>
buildEodAnchoredMatcher(const RoseBuildImpl &build,
const std::map<u32, u32> &final_to_frag_map,
size_t *esize); size_t *esize);
void findMoreLiteralMasks(RoseBuildImpl &build); void findMoreLiteralMasks(RoseBuildImpl &build);

View File

@ -79,6 +79,7 @@ void RoseInstrCheckLitEarly::write(void *dest, RoseEngineBlob &blob,
RoseInstrBase::write(dest, blob, offset_map); RoseInstrBase::write(dest, blob, offset_map);
auto *inst = static_cast<impl_type *>(dest); auto *inst = static_cast<impl_type *>(dest);
inst->min_offset = min_offset; inst->min_offset = min_offset;
inst->fail_jump = calc_jump(offset_map, this, target);
} }
void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob, void RoseInstrCheckGroups::write(void *dest, RoseEngineBlob &blob,

View File

@ -241,16 +241,18 @@ public:
}; };
class RoseInstrCheckLitEarly class RoseInstrCheckLitEarly
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_LIT_EARLY, : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_LIT_EARLY,
ROSE_STRUCT_CHECK_LIT_EARLY, ROSE_STRUCT_CHECK_LIT_EARLY,
RoseInstrCheckLitEarly> { RoseInstrCheckLitEarly> {
public: public:
u32 min_offset; u32 min_offset;
const RoseInstruction *target;
explicit RoseInstrCheckLitEarly(u32 min) : min_offset(min) {} RoseInstrCheckLitEarly(u32 min_offset_in, const RoseInstruction *target_in)
: min_offset(min_offset_in), target(target_in) {}
bool operator==(const RoseInstrCheckLitEarly &ri) const { bool operator==(const RoseInstrCheckLitEarly &ri) const {
return min_offset == ri.min_offset; return min_offset == ri.min_offset && target == ri.target;
} }
size_t hash() const override { size_t hash() const override {
@ -260,9 +262,10 @@ public:
void write(void *dest, RoseEngineBlob &blob, void write(void *dest, RoseEngineBlob &blob,
const OffsetMap &offset_map) const override; const OffsetMap &offset_map) const override;
bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &, bool equiv_to(const RoseInstrCheckLitEarly &ri, const OffsetMap &offsets,
const OffsetMap &) const { const OffsetMap &other_offsets) const {
return min_offset == ri.min_offset; return min_offset == ri.min_offset &&
offsets.at(target) == other_offsets.at(ri.target);
} }
}; };
@ -1786,7 +1789,7 @@ public:
}; };
class RoseInstrCheckMedLit class RoseInstrCheckMedLit
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_MED_LIT, : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT,
ROSE_STRUCT_CHECK_MED_LIT, ROSE_STRUCT_CHECK_MED_LIT,
RoseInstrCheckMedLit> { RoseInstrCheckMedLit> {
public: public:
@ -1816,7 +1819,7 @@ public:
}; };
class RoseInstrCheckMedLitNocase class RoseInstrCheckMedLitNocase
: public RoseInstrBaseNoTargets<ROSE_INSTR_CHECK_MED_LIT_NOCASE, : public RoseInstrBaseOneTarget<ROSE_INSTR_CHECK_MED_LIT_NOCASE,
ROSE_STRUCT_CHECK_MED_LIT_NOCASE, ROSE_STRUCT_CHECK_MED_LIT_NOCASE,
RoseInstrCheckMedLitNocase> { RoseInstrCheckMedLitNocase> {
public: public:

View File

@ -250,6 +250,7 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
PROGRAM_CASE(CHECK_LIT_EARLY) { PROGRAM_CASE(CHECK_LIT_EARLY) {
os << " min_offset " << ri->min_offset << endl; os << " min_offset " << ri->min_offset << endl;
os << " fail_jump " << offset + ri->fail_jump << endl;
} }
PROGRAM_NEXT_INSTRUCTION PROGRAM_NEXT_INSTRUCTION

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015-2016, Intel Corporation * Copyright (c) 2015-2017, Intel Corporation
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -361,6 +361,17 @@ struct RoseEngine {
*/ */
u32 reportProgramCount; u32 reportProgramCount;
/**
* \brief Offset of u32 array of program offsets for delayed replay of
* literals.
*/
u32 delayProgramOffset;
/**
* \brief Offset of u32 array of program offsets for anchored literals.
*/
u32 anchoredProgramOffset;
/** /**
* \brief Number of entries in the arrays pointed to by litProgramOffset, * \brief Number of entries in the arrays pointed to by litProgramOffset,
* litDelayRebuildProgramOffset. * litDelayRebuildProgramOffset.

View File

@ -154,10 +154,10 @@ struct ROSE_STRUCT_ANCHORED_DELAY {
u32 done_jump; //!< Jump forward this many bytes if successful. u32 done_jump; //!< Jump forward this many bytes if successful.
}; };
/** Note: check failure will halt program. */
struct ROSE_STRUCT_CHECK_LIT_EARLY { struct ROSE_STRUCT_CHECK_LIT_EARLY {
u8 code; //!< From enum RoseInstructionCode. u8 code; //!< From enum RoseInstructionCode.
u32 min_offset; //!< Minimum offset for this literal. u32 min_offset; //!< Minimum offset for this literal.
u32 fail_jump; //!< Jump forward this many bytes on failure.
}; };
/** Note: check failure will halt program. */ /** Note: check failure will halt program. */