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,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<RoseInstrCheckState>(pred_state, end_inst));
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));
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<u32, RoseProgram> &pred_blocks,
static
void addPredBlocks(map<u32, RoseProgram> &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<u32, u32> 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);

View File

@ -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<char> 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<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) {
for (const auto &ri : prog) {
if (dynamic_cast<const RoseInstrSquashGroups *>(ri.get())) {

View File

@ -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<RoseInstruction> 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);