diff --git a/src/rose/program_runtime.h b/src/rose/program_runtime.h index 090913ae..dac8345e 100644 --- a/src/rose/program_runtime.h +++ b/src/rose/program_runtime.h @@ -1892,6 +1892,8 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t, DEBUG_PRINTF("delay until playback\n"); tctxt->groups |= ri->groups; work_done = 1; + recordAnchoredLiteralMatch(t, scratch, ri->anch_id, end); + assert(ri->done_jump); // must progress pc += ri->done_jump; continue; @@ -2085,8 +2087,8 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t, } PROGRAM_NEXT_INSTRUCTION - PROGRAM_CASE(RECORD_ANCHORED) { - recordAnchoredLiteralMatch(t, scratch, ri->id, end); + PROGRAM_CASE(DUMMY_NOP) { + assert(0); } PROGRAM_NEXT_INSTRUCTION diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index 0f41da71..ae352e2e 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -3615,22 +3615,37 @@ void makeRoleCheckLeftfix(const RoseBuildImpl &build, } static -void makeRoleAnchoredDelay(const RoseBuildImpl &build, - u32 floatingMinLiteralMatchOffset, - RoseVertex v, RoseProgram &program) { - // Only relevant for roles that can be triggered by the anchored table. - if (!build.isAnchored(v)) { +void makeAnchoredLiteralDelay(const RoseBuildImpl &build, + const ProgramBuild &prog_build, u32 lit_id, + RoseProgram &program) { + // Only relevant for literals in the anchored table. + const rose_literal_id &lit = build.literals.right.at(lit_id); + if (lit.table != ROSE_ANCHORED) { return; } - // If this match cannot occur after floatingMinLiteralMatchOffset, we do - // not need this check. - if (build.g[v].max_offset <= floatingMinLiteralMatchOffset) { + // If this literal match cannot occur after floatingMinLiteralMatchOffset, + // we do not need this check. + bool all_too_early = true; + rose_group groups = 0; + + const auto &lit_vertices = build.literal_info.at(lit_id).vertices; + for (RoseVertex v : lit_vertices) { + if (build.g[v].max_offset > prog_build.floatingMinLiteralMatchOffset) { + all_too_early = false; + } + groups |= build.g[v].groups; + } + + if (all_too_early) { return; } + assert(contains(prog_build.anchored_programs, lit_id)); + u32 anch_id = prog_build.anchored_programs.at(lit_id); + const auto *end_inst = program.end_instruction(); - auto ri = make_unique(build.g[v].groups, end_inst); + auto ri = make_unique(groups, anch_id, end_inst); program.add_before_end(move(ri)); } @@ -4175,9 +4190,6 @@ RoseProgram makeRoleProgram(const RoseBuildImpl &build, build_context &bc, // First, add program instructions that enforce preconditions without // effects. - makeRoleAnchoredDelay(build, prog_build.floatingMinLiteralMatchOffset, v, - program); - if (onlyAtEod(build, v)) { DEBUG_PRINTF("only at eod\n"); const auto *end_inst = program.end_instruction(); @@ -4626,21 +4638,6 @@ u32 findMaxOffset(const RoseBuildImpl &build, u32 lit_id) { return max_offset; } -static -void makeRecordAnchoredInstruction(const RoseBuildImpl &build, - ProgramBuild &prog_build, u32 lit_id, - RoseProgram &program) { - if (build.literals.right.at(lit_id).table != ROSE_ANCHORED) { - return; - } - if (!contains(prog_build.anchored_programs, lit_id)) { - return; - } - auto anch_id = prog_build.anchored_programs.at(lit_id); - DEBUG_PRINTF("adding RECORD_ANCHORED for anch_id=%u\n", anch_id); - program.add_before_end(make_unique(anch_id)); -} - static u32 findMinOffset(const RoseBuildImpl &build, u32 lit_id) { const auto &lit_vertices = build.literal_info.at(lit_id).vertices; @@ -4768,8 +4765,8 @@ bool hasDelayedLiteral(const RoseBuildImpl &build, static RoseProgram makeLitInitialProgram(const RoseBuildImpl &build, build_context &bc, ProgramBuild &prog_build, - u32 lit_id, - const vector &lit_edges) { + u32 lit_id, const vector &lit_edges, + bool is_anchored_replay_program) { RoseProgram program; // Check long literal info. @@ -4794,6 +4791,11 @@ RoseProgram makeLitInitialProgram(const RoseBuildImpl &build, prog_build.floatingMinLiteralMatchOffset, program); + /* Check if we are able to deliever matches from the anchored table now */ + if (!is_anchored_replay_program) { + makeAnchoredLiteralDelay(build, prog_build, lit_id, program); + } + return program; } @@ -4806,7 +4808,13 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc, DEBUG_PRINTF("lit id=%u, %zu lit edges\n", lit_id, lit_edges.size()); - RoseProgram program; + // Construct initial program up front, as its early checks must be able + // to jump to end and terminate processing for this literal. + auto lit_program = makeLitInitialProgram(build, bc, prog_build, lit_id, + lit_edges, + is_anchored_replay_program); + + RoseProgram role_programs; // Predecessor state id -> program block. map pred_blocks; @@ -4829,7 +4837,7 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc, // Add blocks to deal with non-root edges (triggered by sparse iterator or // mmbit_isset checks). - addPredBlocks(pred_blocks, bc.roleStateIndices.size(), program); + addPredBlocks(pred_blocks, bc.roleStateIndices.size(), role_programs); // Add blocks to handle root roles. for (const auto &e : lit_edges) { @@ -4839,31 +4847,23 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc, } DEBUG_PRINTF("root edge (%zu,%zu)\n", g[u].index, g[target(e, g)].index); - program.add_block(makeRoleProgram(build, bc, prog_build, e)); + role_programs.add_block(makeRoleProgram(build, bc, prog_build, e)); } if (lit_id == build.eod_event_literal_id) { + /* Note: does not require the lit intial program */ assert(build.eod_event_literal_id != MO_INVALID_IDX); - return program; + return role_programs; } - RoseProgram root_block; + /* Instructions to run even if a role program bails out */ + RoseProgram unconditional_block; // Literal may squash groups. - makeGroupSquashInstruction(build, lit_id, root_block); + makeGroupSquashInstruction(build, lit_id, unconditional_block); - // Literal may be anchored and need to be recorded. - if (!is_anchored_replay_program) { - makeRecordAnchoredInstruction(build, prog_build, lit_id, root_block); - } - - program.add_block(move(root_block)); - - // Construct initial program up front, as its early checks must be able - // to jump to end and terminate processing for this literal. - auto lit_program = makeLitInitialProgram(build, bc, prog_build, lit_id, - lit_edges); - lit_program.add_before_end(move(program)); + role_programs.add_block(move(unconditional_block)); + lit_program.add_before_end(move(role_programs)); return lit_program; } diff --git a/src/rose/rose_build_dump.cpp b/src/rose/rose_build_dump.cpp index 73ed830e..dfbbe116 100644 --- a/src/rose/rose_build_dump.cpp +++ b/src/rose/rose_build_dump.cpp @@ -890,6 +890,7 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) { PROGRAM_CASE(ANCHORED_DELAY) { os << " groups 0x" << std::hex << ri->groups << std::dec << endl; + os << " anch_id " << ri->anch_id << "\n"; os << " done_jump " << offset + ri->done_jump << endl; } PROGRAM_NEXT_INSTRUCTION @@ -1097,9 +1098,7 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) { } PROGRAM_NEXT_INSTRUCTION - PROGRAM_CASE(RECORD_ANCHORED) { - os << " id " << ri->id << endl; - } + PROGRAM_CASE(DUMMY_NOP) {} PROGRAM_NEXT_INSTRUCTION PROGRAM_CASE(CATCH_UP) {} diff --git a/src/rose/rose_build_program.cpp b/src/rose/rose_build_program.cpp index a659f22e..5cf06200 100644 --- a/src/rose/rose_build_program.cpp +++ b/src/rose/rose_build_program.cpp @@ -72,6 +72,7 @@ void RoseInstrAnchoredDelay::write(void *dest, RoseEngineBlob &blob, 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); } @@ -248,13 +249,6 @@ void RoseInstrPushDelayed::write(void *dest, RoseEngineBlob &blob, inst->index = index; } -void RoseInstrRecordAnchored::write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const { - RoseInstrBase::write(dest, blob, offset_map); - auto *inst = static_cast(dest); - inst->id = id; -} - void RoseInstrSomAdjust::write(void *dest, RoseEngineBlob &blob, const OffsetMap &offset_map) const { RoseInstrBase::write(dest, blob, offset_map); diff --git a/src/rose/rose_build_program.h b/src/rose/rose_build_program.h index 19b9f90a..9c74d488 100644 --- a/src/rose/rose_build_program.h +++ b/src/rose/rose_build_program.h @@ -216,18 +216,20 @@ class RoseInstrAnchoredDelay RoseInstrAnchoredDelay> { public: rose_group groups; + u32 anch_id; const RoseInstruction *target; - RoseInstrAnchoredDelay(rose_group groups_in, + RoseInstrAnchoredDelay(rose_group groups_in, u32 anch_id_in, const RoseInstruction *target_in) - : groups(groups_in), target(target_in) {} + : groups(groups_in), anch_id(anch_id_in), target(target_in) {} bool operator==(const RoseInstrAnchoredDelay &ri) const { - return groups == ri.groups && target == ri.target; + return groups == ri.groups && anch_id == ri.anch_id + && target == ri.target; } size_t hash() const override { - return hash_all(static_cast(opcode), groups); + return hash_all(static_cast(opcode), groups, anch_id); } void write(void *dest, RoseEngineBlob &blob, @@ -235,8 +237,8 @@ public: bool equiv_to(const RoseInstrAnchoredDelay &ri, const OffsetMap &offsets, const OffsetMap &other_offsets) const { - return groups == ri.groups && - offsets.at(target) == other_offsets.at(ri.target); + return groups == ri.groups && anch_id == ri.anch_id + && offsets.at(target) == other_offsets.at(ri.target); } }; @@ -844,32 +846,6 @@ public: } }; -class RoseInstrRecordAnchored - : public RoseInstrBaseNoTargets { -public: - u32 id; - - explicit RoseInstrRecordAnchored(u32 id_in) : id(id_in) {} - - bool operator==(const RoseInstrRecordAnchored &ri) const { - return id == ri.id; - } - - size_t hash() const override { - return hash_all(static_cast(opcode), id); - } - - void write(void *dest, RoseEngineBlob &blob, - const OffsetMap &offset_map) const override; - - bool equiv_to(const RoseInstrRecordAnchored &ri, const OffsetMap &, - const OffsetMap &) const { - return id == ri.id; - } -}; - class RoseInstrCatchUp : public RoseInstrBaseTrivial { @@ -2281,6 +2257,8 @@ public: /** * \brief Adds this block to the program just before the terminating * ROSE_INSTR_END. + * + * Any existing instruction that was jumping to end continues to do so. */ void add_before_end(RoseProgram &&block) { assert(!prog.empty()); @@ -2295,6 +2273,9 @@ public: /** * \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()); diff --git a/src/rose/rose_program.h b/src/rose/rose_program.h index ebda679a..cdfe96ac 100644 --- a/src/rose/rose_program.h +++ b/src/rose/rose_program.h @@ -62,7 +62,7 @@ enum RoseInstructionCode { ROSE_INSTR_CHECK_INFIX, //!< Infix engine must be in accept state. ROSE_INSTR_CHECK_PREFIX, //!< Prefix engine must be in accept state. ROSE_INSTR_PUSH_DELAYED, //!< Push delayed literal matches. - ROSE_INSTR_RECORD_ANCHORED, //!< Record an anchored literal match. + ROSE_INSTR_DUMMY_NOP, //!< NOP. Should not exist in build programs. ROSE_INSTR_CATCH_UP, //!< Catch up engines, anchored matches. ROSE_INSTR_CATCH_UP_MPV, //!< Catch up the MPV. ROSE_INSTR_SOM_ADJUST, //!< Set SOM from a distance to EOM. @@ -188,7 +188,8 @@ struct ROSE_STRUCT_END { struct ROSE_STRUCT_ANCHORED_DELAY { u8 code; //!< From enum RoseInstructionCode. rose_group groups; //!< Bitmask. - u32 done_jump; //!< Jump forward this many bytes if successful. + u32 anch_id; //!< Program to restart after the delay. + u32 done_jump; //!< Jump forward this many bytes if we have to delay. }; struct ROSE_STRUCT_CHECK_LIT_EARLY { @@ -327,9 +328,8 @@ struct ROSE_STRUCT_PUSH_DELAYED { u32 index; // Delay literal index (relative to first delay lit). }; -struct ROSE_STRUCT_RECORD_ANCHORED { +struct ROSE_STRUCT_DUMMY_NOP { u8 code; //!< From enum RoseInstructionCode. - u32 id; //!< Literal ID. }; struct ROSE_STRUCT_CATCH_UP {