]> git.ipfire.org Git - thirdparty/vectorscan.git/commitdiff
rose: minor improvements to avoid unneeded program instructions
authorAlex Coyte <a.coyte@intel.com>
Mon, 24 Apr 2017 00:22:44 +0000 (10:22 +1000)
committerMatthew Barr <matthew.barr@intel.com>
Tue, 30 May 2017 03:58:32 +0000 (13:58 +1000)
- strip out lonely check handled instructions
- avoid producing programs for empty ghost roles

src/rose/rose_build_bytecode.cpp
src/rose/rose_build_program.cpp
src/rose/rose_build_program.h

index a53cc53411f51b5cda599c2c11495bfae1c412a0..0f41da71339addc0b6bd3c3654445aeee0bb2b06 100644 (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);
index cd9b79c86ace72c8ef7205475aa1b5788168a1ce..a659f22e23c63e90cadea4b4a6a54d36ed92c512 100644 (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())) {
index d0c67382ac2531ff0825c7655ccf01cd3693c473..19b9f90ac8836bebe69b61b64458c22952658e79 100644 (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);