rose: minor improvements to avoid unneeded program instructions

- strip out lonely check handled instructions
- avoid producing programs for empty ghost roles
This commit is contained in:
Alex Coyte 2017-04-24 10:22:44 +10:00 committed by Matthew Barr
parent 88fd95e38a
commit e24c38a85c
3 changed files with 62 additions and 20 deletions

View File

@ -4163,8 +4163,9 @@ void makeRoleEagerEodReports(const RoseBuildImpl &build, build_context &bc,
program.add_before_end(move(eod_program)); program.add_before_end(move(eod_program));
} }
/* Makes a program for a role/vertex given a specfic pred/in_edge. */
static static
RoseProgram makeProgram(const RoseBuildImpl &build, build_context &bc, RoseProgram makeRoleProgram(const RoseBuildImpl &build, build_context &bc,
ProgramBuild &prog_build, const RoseEdge &e) { ProgramBuild &prog_build, const RoseEdge &e) {
const RoseGraph &g = build.g; const RoseGraph &g = build.g;
auto v = target(e, g); auto v = target(e, g);
@ -4187,10 +4188,11 @@ RoseProgram makeProgram(const RoseBuildImpl &build, build_context &bc,
makeRoleCheckBounds(build, v, e, program); makeRoleCheckBounds(build, v, e, program);
} }
// This program may be triggered by different predecessors, with different // This role program may be triggered by different predecessors, with
// offset bounds. We must ensure we put this check/set operation after the // different offset bounds. We must ensure we put this check/set operation
// bounds check to deal with this case. // after the bounds check to deal with this case.
if (in_degree(v, g) > 1) { if (in_degree(v, g) > 1) {
assert(!build.isRootSuccessor(v));
makeRoleCheckNotHandled(prog_build, v, program); makeRoleCheckNotHandled(prog_build, v, program);
} }
@ -4231,6 +4233,12 @@ RoseProgram makeProgram(const RoseBuildImpl &build, build_context &bc,
makeRoleEagerEodReports(build, bc, v, eod_block); makeRoleEagerEodReports(build, bc, v, eod_block);
effects_block.add_block(move(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)); program.add_before_end(move(effects_block));
return program; return program;
} }
@ -4414,6 +4422,7 @@ void addPredBlockSingle(u32 pred_state, RoseProgram &pred_block,
RoseProgram &program) { RoseProgram &program) {
// Prepend an instruction to check the pred state is on. // Prepend an instruction to check the pred state is on.
const auto *end_inst = pred_block.end_instruction(); const auto *end_inst = pred_block.end_instruction();
assert(!pred_block.empty());
pred_block.insert(begin(pred_block), pred_block.insert(begin(pred_block),
make_unique<RoseInstrCheckState>(pred_state, end_inst)); make_unique<RoseInstrCheckState>(pred_state, end_inst));
program.add_block(move(pred_block)); program.add_block(move(pred_block));
@ -4434,6 +4443,12 @@ void addPredBlocksAny(map<u32, RoseProgram> &pred_blocks, u32 num_states,
sparse_program.add_before_end(move(ri)); sparse_program.add_before_end(move(ri));
RoseProgram &block = pred_blocks.begin()->second; 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)); sparse_program.add_before_end(move(block));
program.add_block(move(sparse_program)); program.add_block(move(sparse_program));
} }
@ -4491,15 +4506,6 @@ void addPredBlocksMulti(map<u32, RoseProgram> &pred_blocks,
static static
void addPredBlocks(map<u32, RoseProgram> &pred_blocks, u32 num_states, void addPredBlocks(map<u32, RoseProgram> &pred_blocks, u32 num_states,
RoseProgram &program) { 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(); const size_t num_preds = pred_blocks.size();
if (num_preds == 0) { if (num_preds == 0) {
return; return;
@ -4815,8 +4821,10 @@ RoseProgram makeLiteralProgram(const RoseBuildImpl &build, build_context &bc,
g[target(e, g)].index); g[target(e, g)].index);
assert(contains(bc.roleStateIndices, u)); assert(contains(bc.roleStateIndices, u));
u32 pred_state = bc.roleStateIndices.at(u); u32 pred_state = bc.roleStateIndices.at(u);
pred_blocks[pred_state].add_block( auto role_prog = makeRoleProgram(build, bc, prog_build, e);
makeProgram(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 // 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, DEBUG_PRINTF("root edge (%zu,%zu)\n", g[u].index,
g[target(e, g)].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) { 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)) { if (contains(lit_edge_map, lit_id)) {
edges_ptr = &lit_edge_map.at(lit_id); edges_ptr = &lit_edge_map.at(lit_id);
} else { } else {
/* literal may happen only in a delay context */
edges_ptr = &no_edges; edges_ptr = &no_edges;
} }
@ -5205,7 +5214,8 @@ pair<u32, u32> writeAnchoredPrograms(const RoseBuildImpl &build,
auto it = cache.find(offset); auto it = cache.find(offset);
if (it != end(cache)) { if (it != end(cache)) {
anch_id = it->second; 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 { } else {
anch_id = verify_u32(programs.size()); anch_id = verify_u32(programs.size());
programs.push_back(offset); programs.push_back(offset);

View File

@ -639,6 +639,11 @@ OffsetMap makeOffsetMap(const RoseProgram &program, u32 *total_len) {
return offset_map; return offset_map;
} }
RoseProgram::iterator RoseProgram::erase(RoseProgram::iterator first,
RoseProgram::iterator last) {
return prog.erase(first, last);
}
bytecode_ptr<char> writeProgram(RoseEngineBlob &blob, bytecode_ptr<char> writeProgram(RoseEngineBlob &blob,
const RoseProgram &program) { const RoseProgram &program) {
u32 total_len = 0; 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); 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<const RoseInstrCheckNotHandled *>(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) { bool reads_work_done_flag(const RoseProgram &prog) {
for (const auto &ri : prog) { for (const auto &ri : prog) {
if (dynamic_cast<const RoseInstrSquashGroups *>(ri.get())) { if (dynamic_cast<const RoseInstrSquashGroups *>(ri.get())) {

View File

@ -2219,7 +2219,6 @@ public:
return prog.back().get(); return prog.back().get();
} }
private:
static void update_targets(iterator it, iterator it_end, static void update_targets(iterator it, iterator it_end,
const RoseInstruction *old_target, const RoseInstruction *old_target,
const RoseInstruction *new_target) { const RoseInstruction *new_target) {
@ -2231,7 +2230,6 @@ private:
} }
} }
public:
iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri) { iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri) {
assert(!prog.empty()); assert(!prog.empty());
assert(it != end()); assert(it != end());
@ -2267,6 +2265,10 @@ public:
return it; 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 * \brief Adds this instruction to the program just before the terminating
* ROSE_INSTR_END. * ROSE_INSTR_END.
@ -2348,6 +2350,9 @@ public:
bool operator()(const RoseProgram &prog1, const RoseProgram &prog2) const; 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 */ /** Returns true if the program may read the the interpreter's work_done flag */
bool reads_work_done_flag(const RoseProgram &prog); bool reads_work_done_flag(const RoseProgram &prog);