From c2496fbf769cbba62bebc252c1fb4b3d81480eca Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Tue, 31 May 2016 15:24:59 +1000 Subject: [PATCH] rose: elide SET_GROUPS when possible --- CMakeLists.txt | 2 + src/rose/rose_build_bytecode.cpp | 57 ++++++++++++--- src/rose/rose_build_groups.cpp | 116 +++++++++++++++++++++++++++++++ src/rose/rose_build_groups.h | 50 +++++++++++++ 4 files changed, 216 insertions(+), 9 deletions(-) create mode 100644 src/rose/rose_build_groups.cpp create mode 100644 src/rose/rose_build_groups.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c824b6a6..536be260 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -825,6 +825,8 @@ SET (hs_SRCS src/rose/rose_build_compile.cpp src/rose/rose_build_convert.cpp src/rose/rose_build_convert.h + src/rose/rose_build_groups.cpp + src/rose/rose_build_groups.h src/rose/rose_build_impl.h src/rose/rose_build_infix.cpp src/rose/rose_build_infix.h diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index 578c4b4a..3d1b5c6b 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -33,6 +33,7 @@ #include "hs_compile.h" // for HS_MODE_* #include "rose_build_add_internal.h" #include "rose_build_anchored.h" +#include "rose_build_groups.h" #include "rose_build_infix.h" #include "rose_build_lookaround.h" #include "rose_build_matchers.h" @@ -408,6 +409,13 @@ struct build_context : boost::noncopyable { /** \brief Resources in use (tracked as programs are added). */ RoseResources resources; + /** \brief Mapping from every vertex to the groups that must be on for that + * vertex to be reached. */ + ue2::unordered_map vertex_group_map; + + /** \brief Global bitmap of groups that can be squashed. */ + rose_group squashable_groups = 0; + /** \brief Base offset of engine_blob in the Rose engine bytecode. */ static constexpr u32 engine_blob_base = ROUNDUP_CL(sizeof(RoseEngine)); }; @@ -2911,11 +2919,38 @@ void makeRoleSuffix(RoseBuildImpl &build, build_context &bc, RoseVertex v, } static -void makeRoleGroups(const rose_group &groups, +void makeRoleGroups(RoseBuildImpl &build, build_context &bc, RoseVertex v, vector &program) { + const auto &g = build.g; + rose_group groups = g[v].groups; if (!groups) { return; } + + // The set of "already on" groups as we process this vertex is the + // intersection of the groups set by our predecessors. + assert(in_degree(v, g) > 0); + rose_group already_on = ~rose_group{0}; + for (const auto &u : inv_adjacent_vertices_range(v, g)) { + already_on &= bc.vertex_group_map.at(u); + } + + DEBUG_PRINTF("already_on=0x%llx\n", already_on); + DEBUG_PRINTF("squashable=0x%llx\n", bc.squashable_groups); + DEBUG_PRINTF("groups=0x%llx\n", groups); + + already_on &= ~bc.squashable_groups; + DEBUG_PRINTF("squashed already_on=0x%llx\n", already_on); + + // We don't *have* to mask off the groups that we know are already on, but + // this will make bugs more apparent. + groups &= ~already_on; + + if (!groups) { + DEBUG_PRINTF("no new groups to set, skipping\n"); + return; + } + auto ri = RoseInstruction(ROSE_INSTR_SET_GROUPS); ri.u.setGroups.groups = groups; program.push_back(ri); @@ -3086,11 +3121,12 @@ vector makeProgram(RoseBuildImpl &build, build_context &bc, // Next, we can add program instructions that have effects. makeRoleReports(build, bc, v, program); + makeRoleInfixTriggers(build, bc, v, program); // Note: SET_GROUPS instruction must be after infix triggers, as an infix // going dead may switch off groups. - makeRoleGroups(g[v].groups, program); + makeRoleGroups(build, bc, v, program); makeRoleSuffix(build, bc, v, program); makeRoleSetState(bc, v, program); @@ -3457,8 +3493,7 @@ void makePushDelayedInstructions(const RoseBuildImpl &build, u32 final_id, } static -void makeGroupCheckInstruction(const RoseBuildImpl &build, u32 final_id, - vector &program) { +rose_group getFinalIdGroupsUnion(const RoseBuildImpl &build, u32 final_id) { assert(contains(build.final_id_to_literal, final_id)); const auto &lit_infos = getLiteralInfoByFinalId(build, final_id); @@ -3466,7 +3501,13 @@ void makeGroupCheckInstruction(const RoseBuildImpl &build, u32 final_id, for (const auto &li : lit_infos) { groups |= li->group_mask; } + return groups; +} +static +void makeGroupCheckInstruction(const RoseBuildImpl &build, u32 final_id, + vector &program) { + rose_group groups = getFinalIdGroupsUnion(build, final_id); if (!groups) { return; } @@ -3515,11 +3556,7 @@ void makeGroupSquashInstruction(const RoseBuildImpl &build, u32 final_id, return; } - rose_group groups = 0; - for (const auto &li : lit_infos) { - groups |= li->group_mask; - } - + rose_group groups = getFinalIdGroupsUnion(build, final_id); if (!groups) { return; } @@ -3999,6 +4036,8 @@ aligned_unique_ptr RoseBuildImpl::buildFinalEngine(u32 minWidth) { bc.resources.has_anchored = true; } bc.needs_mpv_catchup = needsMpvCatchup(*this); + bc.vertex_group_map = getVertexGroupMap(*this); + bc.squashable_groups = getSquashableGroups(*this); auto boundary_out = makeBoundaryPrograms(*this, bc, boundary, dboundary); diff --git a/src/rose/rose_build_groups.cpp b/src/rose/rose_build_groups.cpp new file mode 100644 index 00000000..f99ac171 --- /dev/null +++ b/src/rose/rose_build_groups.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * \brief Rose build: code for analysing literal groups. + */ + +#include "rose_build_groups.h" + +#include + +#include +#include + +using namespace std; + +namespace ue2 { + +/** + * \brief Returns a mapping from each graph vertex v to the intersection of the + * groups switched on by all of the paths leading up to (and including) v from + * the start vertexes. + */ +unordered_map +getVertexGroupMap(const RoseBuildImpl &build) { + const RoseGraph &g = build.g; + vector v_order; + v_order.reserve(num_vertices(g)); + + boost::topological_sort(g, back_inserter(v_order), + vertex_index_map(get(&RoseVertexProps::idx, g))); + + unordered_map vertex_group_map; + vertex_group_map.reserve(num_vertices(g)); + + const rose_group initial_groups = build.getInitialGroups(); + + for (const auto &v : boost::adaptors::reverse(v_order)) { + DEBUG_PRINTF("vertex %zu\n", g[v].idx); + + if (build.isAnyStart(v)) { + DEBUG_PRINTF("start vertex, groups=0x%llx\n", initial_groups); + vertex_group_map.emplace(v, initial_groups); + continue; + } + + // To get to this vertex, we must have come through a predecessor, and + // everyone who isn't a start vertex has one. + assert(in_degree(v, g) > 0); + rose_group pred_groups = ~rose_group{0}; + for (auto u : inv_adjacent_vertices_range(v, g)) { + DEBUG_PRINTF("pred %zu\n", g[u].idx); + assert(contains(vertex_group_map, u)); + pred_groups &= vertex_group_map.at(u); + } + + DEBUG_PRINTF("pred_groups=0x%llx\n", pred_groups); + DEBUG_PRINTF("g[v].groups=0x%llx\n", g[v].groups); + + rose_group v_groups = pred_groups | g[v].groups; + DEBUG_PRINTF("v_groups=0x%llx\n", v_groups); + + vertex_group_map.emplace(v, v_groups); + } + + return vertex_group_map; +} + +/** + * \brief Find the set of groups that can be squashed anywhere in the graph, + * either by a literal or by a leftfix. + */ +rose_group getSquashableGroups(const RoseBuildImpl &build) { + rose_group squashable_groups = 0; + for (const auto &info : build.literal_info) { + if (info.squash_group) { + DEBUG_PRINTF("lit squash mask 0x%llx\n", info.group_mask); + squashable_groups |= info.group_mask; + } + } + for (const auto &m : build.rose_squash_masks) { + DEBUG_PRINTF("left squash mask 0x%llx\n", ~m.second); + squashable_groups |= ~m.second; + } + + DEBUG_PRINTF("squashable groups=0x%llx\n", squashable_groups); + return squashable_groups; +} + +} // namespace ue2 diff --git a/src/rose/rose_build_groups.h b/src/rose/rose_build_groups.h new file mode 100644 index 00000000..608eda4a --- /dev/null +++ b/src/rose/rose_build_groups.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file + * \brief Rose build: code for analysing literal groups. + */ + +#ifndef ROSE_BUILD_GROUPS_H +#define ROSE_BUILD_GROUPS_H + +#include "rose_build_impl.h" +#include "util/ue2_containers.h" + +namespace ue2 { + +unordered_map +getVertexGroupMap(const RoseBuildImpl &build); + +rose_group getSquashableGroups(const RoseBuildImpl &build); + +} // namespace ue2 + +#endif // ROSE_BUILD_GROUPS_H +