diff --git a/src/rose/program_runtime.h b/src/rose/program_runtime.h index d67c307f..30ff8527 100644 --- a/src/rose/program_runtime.h +++ b/src/rose/program_runtime.h @@ -2166,6 +2166,12 @@ hwlmcb_rv_t roseRunProgram_i(const struct RoseEngine *t, } } PROGRAM_NEXT_INSTRUCTION + + PROGRAM_CASE(CLEAR_WORK_DONE) { + DEBUG_PRINTF("clear work_done flag\n"); + work_done = 0; + } + PROGRAM_NEXT_INSTRUCTION } } diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index 32a1d075..f51e0449 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -4517,6 +4517,18 @@ u32 writeLiteralProgram(const RoseBuildImpl &build, build_context &bc, bool is_anchored_program) { assert(!lit_ids.empty()); + // If we have multiple literals and any of them squash groups, we will have + // to add a CLEAR_WORK_DONE instruction to each literal program block to + // clear the work_done flags so that it's only set if a state has been + // switched on for that literal. + + // Note that we add it to every lit program, as they may be + // reordered/uniquified by assembleProgramBlocks() above. + const bool needs_clear_work = lit_ids.size() > 1 && + any_of_in(lit_ids, [&](u32 lit_id) { + return build.literal_info.at(lit_id).squash_group; + }); + vector blocks; const vector no_edges; @@ -4531,6 +4543,11 @@ u32 writeLiteralProgram(const RoseBuildImpl &build, build_context &bc, } auto prog = buildLiteralProgram(build, bc, prog_build, lit_id, *edges_ptr, is_anchored_program); + if (needs_clear_work) { + RoseProgram clear_block; + clear_block.add_before_end(make_unique()); + prog.add_block(move(clear_block)); + } blocks.push_back(move(prog)); } diff --git a/src/rose/rose_build_dump.cpp b/src/rose/rose_build_dump.cpp index 0d05e8ac..0e53d59d 100644 --- a/src/rose/rose_build_dump.cpp +++ b/src/rose/rose_build_dump.cpp @@ -1100,6 +1100,9 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) { } PROGRAM_NEXT_INSTRUCTION + PROGRAM_CASE(CLEAR_WORK_DONE) {} + PROGRAM_NEXT_INSTRUCTION + default: os << " UNKNOWN (code " << int{code} << ")" << endl; os << " " << endl; diff --git a/src/rose/rose_build_program.cpp b/src/rose/rose_build_program.cpp index 112b93f9..1c0fd2ab 100644 --- a/src/rose/rose_build_program.cpp +++ b/src/rose/rose_build_program.cpp @@ -48,6 +48,7 @@ RoseInstrSomZero::~RoseInstrSomZero() = default; RoseInstrSuffixesEod::~RoseInstrSuffixesEod() = default; RoseInstrMatcherEod::~RoseInstrMatcherEod() = default; RoseInstrEnd::~RoseInstrEnd() = default; +RoseInstrClearWorkDone::~RoseInstrClearWorkDone() = default; using OffsetMap = RoseInstruction::OffsetMap; diff --git a/src/rose/rose_build_program.h b/src/rose/rose_build_program.h index fd966a8d..a63f03c8 100644 --- a/src/rose/rose_build_program.h +++ b/src/rose/rose_build_program.h @@ -1851,6 +1851,14 @@ public: } }; +class RoseInstrClearWorkDone + : public RoseInstrBaseTrivial { +public: + ~RoseInstrClearWorkDone() override; +}; + class RoseInstrEnd : public RoseInstrBaseTrivial { diff --git a/src/rose/rose_program.h b/src/rose/rose_program.h index 652b9109..cf1a9eb6 100644 --- a/src/rose/rose_program.h +++ b/src/rose/rose_program.h @@ -141,7 +141,12 @@ enum RoseInstructionCode { */ ROSE_INSTR_CHECK_MED_LIT_NOCASE, - LAST_ROSE_INSTRUCTION = ROSE_INSTR_CHECK_MED_LIT_NOCASE //!< Sentinel. + /** + * \brief Clear the "work done" flag used by the SQUASH_GROUPS instruction. + */ + ROSE_INSTR_CLEAR_WORK_DONE, + + LAST_ROSE_INSTRUCTION = ROSE_INSTR_CLEAR_WORK_DONE //!< Sentinel. }; struct ROSE_STRUCT_END { @@ -517,4 +522,8 @@ struct ROSE_STRUCT_CHECK_MED_LIT_NOCASE { u32 fail_jump; //!< Jump forward this many bytes on failure. }; +struct ROSE_STRUCT_CLEAR_WORK_DONE { + u8 code; //!< From enum RoseInstructionCode. +}; + #endif // ROSE_ROSE_PROGRAM_H