From a810bac8f7dffb960acafa2243319375878bbcb6 Mon Sep 17 00:00:00 2001 From: Alex Coyte Date: Tue, 11 Apr 2017 10:50:16 +1000 Subject: [PATCH] be more selective about generating CLEAR_WORK_DONE instructions --- src/rose/rose_build_bytecode.cpp | 39 ++++++++++++++------------------ src/rose/rose_build_program.cpp | 9 ++++++++ src/rose/rose_build_program.h | 3 +++ 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index 620ba3df..bd7481ab 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -4879,8 +4879,11 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc, } /** - * \brief Consumes list of program blocks, checks them for duplicates and then - * concatenates them into one program. + * \brief Consumes list of program blocks corresponding to different literals, + * checks them for duplicates and then concatenates them into one program. + * + * Note: if a block will squash groups, a CLEAR_WORK_DONE instruction is + * inserted to prevent the work_done flag being contaminated by early blocks. */ static RoseProgram assembleProgramBlocks(vector &&blocks) { @@ -4899,8 +4902,18 @@ RoseProgram assembleProgramBlocks(vector &&blocks) { DEBUG_PRINTF("%zu blocks after dedupe\n", blocks.size()); - for (auto &prog : blocks) { - program.add_block(move(prog)); + for (auto &block : blocks) { + /* If we have multiple blocks from different 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. */ + if (!program.empty() && reads_work_done_flag(block)) { + RoseProgram clear_block; + clear_block.add_before_end(make_unique()); + program.add_block(move(clear_block)); + } + + program.add_block(move(block)); } return program; @@ -4913,28 +4926,10 @@ RoseProgram makeFragmentProgram(const RoseBuildImpl &build, build_context &bc, const map> &lit_edge_map) { 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; - for (const auto &lit_id : lit_ids) { auto prog = makeLiteralProgram(build, bc, prog_build, lit_id, lit_edge_map, false); - 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_program.cpp b/src/rose/rose_build_program.cpp index bca867f0..cd9b79c8 100644 --- a/src/rose/rose_build_program.cpp +++ b/src/rose/rose_build_program.cpp @@ -681,4 +681,13 @@ bool RoseProgramEquivalence::operator()(const RoseProgram &prog1, return std::equal(prog1.begin(), prog1.end(), prog2.begin(), is_equiv); } +bool reads_work_done_flag(const RoseProgram &prog) { + for (const auto &ri : prog) { + if (dynamic_cast(ri.get())) { + return true; + } + } + return false; +} + } // namespace ue2 diff --git a/src/rose/rose_build_program.h b/src/rose/rose_build_program.h index 06233231..d0c67382 100644 --- a/src/rose/rose_build_program.h +++ b/src/rose/rose_build_program.h @@ -2348,6 +2348,9 @@ public: bool operator()(const RoseProgram &prog1, const RoseProgram &prog2) const; }; +/** Returns true if the program may read the the interpreter's work_done flag */ +bool reads_work_done_flag(const RoseProgram &prog); + } // namespace ue2 #endif // ROSE_BUILD_PROGRAM_H