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);
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);
}
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;
}
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));
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));
}
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;
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
}
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) {
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;
}
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);
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;
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())) {
return prog.back().get();
}
-private:
static void update_targets(iterator it, iterator it_end,
const RoseInstruction *old_target,
const RoseInstruction *new_target) {
}
}
-public:
iterator insert(iterator it, std::unique_ptr<RoseInstruction> ri) {
assert(!prog.empty());
assert(it != end());
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.
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);