From e24c38a85c499c8af88a7ee3cdeed1ead63d65c8 Mon Sep 17 00:00:00 2001 From: Alex Coyte Date: Mon, 24 Apr 2017 10:22:44 +1000 Subject: [PATCH] rose: minor improvements to avoid unneeded program instructions - strip out lonely check handled instructions - avoid producing programs for empty ghost roles --- src/rose/rose_build_bytecode.cpp | 46 +++++++++++++++++++------------- src/rose/rose_build_program.cpp | 27 +++++++++++++++++++ src/rose/rose_build_program.h | 9 +++++-- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index a53cc534..0f41da71 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -4163,9 +4163,10 @@ void makeRoleEagerEodReports(const RoseBuildImpl &build, build_context &bc, program.add_before_end(move(eod_program)); } +/* Makes a program for a role/vertex given a specfic pred/in_edge. */ static -RoseProgram makeProgram(const RoseBuildImpl &build, build_context &bc, - ProgramBuild &prog_build, const RoseEdge &e) { +RoseProgram makeRoleProgram(const RoseBuildImpl &build, build_context &bc, + ProgramBuild &prog_build, const RoseEdge &e) { const RoseGraph &g = build.g; auto v = target(e, g); @@ -4187,10 +4188,11 @@ RoseProgram makeProgram(const RoseBuildImpl &build, build_context &bc, makeRoleCheckBounds(build, v, e, program); } - // This program may be triggered by different predecessors, with different - // offset bounds. We must ensure we put this check/set operation after the - // bounds check to deal with this case. + // This role program may be triggered by different predecessors, with + // different offset bounds. We must ensure we put this check/set operation + // after the bounds check to deal with this case. if (in_degree(v, g) > 1) { + assert(!build.isRootSuccessor(v)); makeRoleCheckNotHandled(prog_build, v, program); } @@ -4231,6 +4233,12 @@ RoseProgram makeProgram(const RoseBuildImpl &build, build_context &bc, makeRoleEagerEodReports(build, bc, v, eod_block); effects_block.add_block(move(eod_block)); + /* a 'ghost role' may do nothing if we know that its groups are already set + * - in this case we can avoid producing a program at all. */ + if (effects_block.empty()) { + return {}; + } + program.add_before_end(move(effects_block)); return program; } @@ -4414,6 +4422,7 @@ void addPredBlockSingle(u32 pred_state, RoseProgram &pred_block, RoseProgram &program) { // Prepend an instruction to check the pred state is on. const auto *end_inst = pred_block.end_instruction(); + assert(!pred_block.empty()); pred_block.insert(begin(pred_block), make_unique(pred_state, end_inst)); program.add_block(move(pred_block)); @@ -4434,6 +4443,12 @@ void addPredBlocksAny(map &pred_blocks, u32 num_states, sparse_program.add_before_end(move(ri)); RoseProgram &block = pred_blocks.begin()->second; + assert(!block.empty()); + + /* we no longer need the check handled instruction as all the pred-role + * blocks are being collapsed together */ + stripCheckHandledInstruction(block); + sparse_program.add_before_end(move(block)); program.add_block(move(sparse_program)); } @@ -4491,15 +4506,6 @@ void addPredBlocksMulti(map &pred_blocks, static void addPredBlocks(map &pred_blocks, u32 num_states, RoseProgram &program) { - // Trim empty blocks, if any exist. - for (auto it = pred_blocks.begin(); it != pred_blocks.end();) { - if (it->second.empty()) { - it = pred_blocks.erase(it); - } else { - ++it; - } - } - const size_t num_preds = pred_blocks.size(); if (num_preds == 0) { return; @@ -4815,8 +4821,10 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc, g[target(e, g)].index); assert(contains(bc.roleStateIndices, u)); u32 pred_state = bc.roleStateIndices.at(u); - pred_blocks[pred_state].add_block( - makeProgram(build, bc, prog_build, e)); + auto role_prog = makeRoleProgram(build, bc, prog_build, e); + if (!role_prog.empty()) { + pred_blocks[pred_state].add_block(move(role_prog)); + } } // Add blocks to deal with non-root edges (triggered by sparse iterator or @@ -4831,7 +4839,7 @@ 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(makeProgram(build, bc, prog_build, e)); + program.add_block(makeRoleProgram(build, bc, prog_build, e)); } if (lit_id == build.eod_event_literal_id) { @@ -4872,6 +4880,7 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc, if (contains(lit_edge_map, lit_id)) { edges_ptr = &lit_edge_map.at(lit_id); } else { + /* literal may happen only in a delay context */ edges_ptr = &no_edges; } @@ -5205,7 +5214,8 @@ pair writeAnchoredPrograms(const RoseBuildImpl &build, auto it = cache.find(offset); if (it != end(cache)) { anch_id = it->second; - DEBUG_PRINTF("reusing anch_id %u for offset %u\n", anch_id, offset); + DEBUG_PRINTF("reusing anch_id %u for offset %u\n", anch_id, + offset); } else { anch_id = verify_u32(programs.size()); programs.push_back(offset); diff --git a/src/rose/rose_build_program.cpp b/src/rose/rose_build_program.cpp index cd9b79c8..a659f22e 100644 --- a/src/rose/rose_build_program.cpp +++ b/src/rose/rose_build_program.cpp @@ -639,6 +639,11 @@ OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) { return offset_map; } +RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first, + RoseProgram::iterator last) { + return prog.erase(first, last); +} + bytecode_ptr writeProgram(RoseEngineBlob &blob, const RoseProgram &program) { u32 total_len = 0; @@ -681,6 +686,28 @@ bool RoseProgramEquivalence::operator()(const RoseProgram &prog1, return std::equal(prog1.begin(), prog1.end(), prog2.begin(), is_equiv); } +void stripCheckHandledInstruction(RoseProgram &prog) { + for (auto it = prog.begin(); it != prog.end();) { + auto ins = dynamic_cast(it->get()); + if (!ins) { + ++it; + continue; + } + + auto next_it = next(it); + assert(next_it != prog.end()); /* there should always be an end ins */ + auto next_ins = next_it->get(); + + /* update all earlier instructions which point to ins to instead point + * to the next instruction. Only need to look at earlier as we only ever + * jump forward. */ + RoseProgram::update_targets(prog.begin(), it, ins, next_ins); + + /* remove check handled instruction */ + it = prog.erase(it, next_it); + } +} + bool reads_work_done_flag(const RoseProgram &prog) { for (const auto &ri : prog) { if (dynamic_cast(ri.get())) { diff --git a/src/rose/rose_build_program.h b/src/rose/rose_build_program.h index d0c67382..19b9f90a 100644 --- a/src/rose/rose_build_program.h +++ b/src/rose/rose_build_program.h @@ -2219,7 +2219,6 @@ public: return prog.back().get(); } -private: static void update_targets(iterator it, iterator it_end, const RoseInstruction *old_target, const RoseInstruction *new_target) { @@ -2231,7 +2230,6 @@ private: } } -public: iterator insert(iterator it, std::unique_ptr ri) { assert(!prog.empty()); assert(it != end()); @@ -2267,6 +2265,10 @@ public: return it; } + /* Note: takes iterator rather than const_iterator to support toolchains + * with pre-C++11 standard libraries (i.e., gcc-4.8). */ + iterator erase(iterator first, iterator last); + /** * \brief Adds this instruction to the program just before the terminating * ROSE_INSTR_END. @@ -2348,6 +2350,9 @@ public: bool operator()(const RoseProgram &prog1, const RoseProgram &prog2) const; }; +/* Removes any CHECK_HANDLED instructions from the given program */ +void stripCheckHandledInstruction(RoseProgram &prog); + /** Returns true if the program may read the the interpreter's work_done flag */ bool reads_work_done_flag(const RoseProgram &prog);