mirror of
https://github.com/Inori/GPCS4.git
synced 2024-06-01 19:08:08 -04:00
introduce loop info
This commit is contained in:
parent
25498bc283
commit
5a4b08868f
|
@ -456,7 +456,7 @@ BOOST_concept(VertexIndexGraph, (Graph))
|
|||
ignore_unused_variable_warning(x);
|
||||
|
||||
// This is relaxed
|
||||
renumber_vertex_indices(g);
|
||||
// renumber_vertex_indices(g);
|
||||
|
||||
const_constraints(g);
|
||||
}
|
||||
|
|
372
3rdParty/boost/boost/graph/tiernan_all_cycles.hpp
vendored
Normal file
372
3rdParty/boost/boost/graph/tiernan_all_cycles.hpp
vendored
Normal file
|
@ -0,0 +1,372 @@
|
|||
// (C) Copyright 2007-2009 Andrew Sutton
|
||||
//
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0 (See accompanying file
|
||||
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GRAPH_CYCLE_HPP
|
||||
#define BOOST_GRAPH_CYCLE_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/graph/graph_concepts.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/properties.hpp>
|
||||
#include <boost/concept/assert.hpp>
|
||||
|
||||
#include <boost/concept/detail/concept_def.hpp>
|
||||
namespace boost
|
||||
{
|
||||
namespace concepts
|
||||
{
|
||||
BOOST_concept(CycleVisitor, (Visitor)(Path)(Graph))
|
||||
{
|
||||
BOOST_CONCEPT_USAGE(CycleVisitor) { vis.cycle(p, g); }
|
||||
|
||||
private:
|
||||
Visitor vis;
|
||||
Graph g;
|
||||
Path p;
|
||||
};
|
||||
} /* namespace concepts */
|
||||
using concepts::CycleVisitorConcept;
|
||||
} /* namespace boost */
|
||||
#include <boost/concept/detail/concept_undef.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// The implementation of this algorithm is a reproduction of the Teirnan
|
||||
// approach for directed graphs: bibtex follows
|
||||
//
|
||||
// @article{362819,
|
||||
// author = {James C. Tiernan},
|
||||
// title = {An efficient search algorithm to find the elementary
|
||||
// circuits of a graph}, journal = {Commun. ACM}, volume = {13}, number
|
||||
// = {12}, year = {1970}, issn = {0001-0782}, pages = {722--726}, doi =
|
||||
// {http://doi.acm.org/10.1145/362814.362819},
|
||||
// publisher = {ACM Press},
|
||||
// address = {New York, NY, USA},
|
||||
// }
|
||||
//
|
||||
// It should be pointed out that the author does not provide a complete analysis
|
||||
// for either time or space. This is in part, due to the fact that it's a fairly
|
||||
// input sensitive problem related to the density and construction of the graph,
|
||||
// not just its size.
|
||||
//
|
||||
// I've also taken some liberties with the interpretation of the algorithm -
|
||||
// I've basically modernized it to use real data structures (no more arrays and
|
||||
// matrices). Oh... and there's explicit control structures - not just gotos.
|
||||
//
|
||||
// The problem is definitely NP-complete, an unbounded implementation of this
|
||||
// will probably run for quite a while on a large graph. The conclusions
|
||||
// of this paper also reference a Paton algorithm for undirected graphs as being
|
||||
// much more efficient (apparently based on spanning trees). Although not
|
||||
// implemented, it can be found here:
|
||||
//
|
||||
// @article{363232,
|
||||
// author = {Keith Paton},
|
||||
// title = {An algorithm for finding a fundamental set of cycles of a
|
||||
// graph}, journal = {Commun. ACM}, volume = {12}, number = {9}, year =
|
||||
// {1969}, issn = {0001-0782}, pages = {514--518}, doi =
|
||||
// {http://doi.acm.org/10.1145/363219.363232},
|
||||
// publisher = {ACM Press},
|
||||
// address = {New York, NY, USA},
|
||||
// }
|
||||
|
||||
/**
|
||||
* The default cycle visitor provides an empty visit function for cycle
|
||||
* visitors.
|
||||
*/
|
||||
struct cycle_visitor
|
||||
{
|
||||
template < typename Path, typename Graph >
|
||||
inline void cycle(const Path& p, const Graph& g)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The min_max_cycle_visitor simultaneously records the minimum and maximum
|
||||
* cycles in a graph.
|
||||
*/
|
||||
struct min_max_cycle_visitor
|
||||
{
|
||||
min_max_cycle_visitor(std::size_t& min_, std::size_t& max_)
|
||||
: minimum(min_), maximum(max_)
|
||||
{
|
||||
}
|
||||
|
||||
template < typename Path, typename Graph >
|
||||
inline void cycle(const Path& p, const Graph& g)
|
||||
{
|
||||
BOOST_USING_STD_MIN();
|
||||
BOOST_USING_STD_MAX();
|
||||
std::size_t len = p.size();
|
||||
minimum = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum, len);
|
||||
maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION(maximum, len);
|
||||
}
|
||||
std::size_t& minimum;
|
||||
std::size_t& maximum;
|
||||
};
|
||||
|
||||
inline min_max_cycle_visitor find_min_max_cycle(
|
||||
std::size_t& min_, std::size_t& max_)
|
||||
{
|
||||
return min_max_cycle_visitor(min_, max_);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template < typename Graph, typename Path >
|
||||
inline bool is_vertex_in_path(const Graph&,
|
||||
typename graph_traits< Graph >::vertex_descriptor v, const Path& p)
|
||||
{
|
||||
return (std::find(p.begin(), p.end(), v) != p.end());
|
||||
}
|
||||
|
||||
template < typename Graph, typename ClosedMatrix >
|
||||
inline bool is_path_closed(const Graph& g,
|
||||
typename graph_traits< Graph >::vertex_descriptor u,
|
||||
typename graph_traits< Graph >::vertex_descriptor v,
|
||||
const ClosedMatrix& closed)
|
||||
{
|
||||
// the path from u to v is closed if v can be found in the list
|
||||
// of closed vertices associated with u.
|
||||
typedef typename ClosedMatrix::const_reference Row;
|
||||
Row r = closed[get(vertex_index, g, u)];
|
||||
if (find(r.begin(), r.end(), v) != r.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template < typename Graph, typename Path, typename ClosedMatrix >
|
||||
inline bool can_extend_path(const Graph& g,
|
||||
typename graph_traits< Graph >::edge_descriptor e, const Path& p,
|
||||
const ClosedMatrix& m)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
|
||||
BOOST_CONCEPT_ASSERT((VertexIndexGraphConcept< Graph >));
|
||||
typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
|
||||
|
||||
// get the vertices in question
|
||||
Vertex u = source(e, g), v = target(e, g);
|
||||
|
||||
// conditions for allowing a traversal along this edge are:
|
||||
// 1. the index of v must be greater than that at which the
|
||||
// path is rooted (p.front()).
|
||||
// 2. the vertex v cannot already be in the path
|
||||
// 3. the vertex v cannot be closed to the vertex u
|
||||
|
||||
bool indices
|
||||
= get(vertex_index, g, p.front()) < get(vertex_index, g, v);
|
||||
bool path = !is_vertex_in_path(g, v, p);
|
||||
bool closed = !is_path_closed(g, u, v, m);
|
||||
return indices && path && closed;
|
||||
}
|
||||
|
||||
template < typename Graph, typename Path >
|
||||
inline bool can_wrap_path(const Graph& g, const Path& p)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
|
||||
typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
|
||||
typedef typename graph_traits< Graph >::out_edge_iterator OutIterator;
|
||||
|
||||
// iterate over the out-edges of the back, looking for the
|
||||
// front of the path. also, we can't travel along the same
|
||||
// edge that we did on the way here, but we don't quite have the
|
||||
// stringent requirements that we do in can_extend_path().
|
||||
Vertex u = p.back(), v = p.front();
|
||||
OutIterator i, end;
|
||||
for (boost::tie(i, end) = out_edges(u, g); i != end; ++i)
|
||||
{
|
||||
if ((target(*i, g) == v))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template < typename Graph, typename Path, typename ClosedMatrix >
|
||||
inline typename graph_traits< Graph >::vertex_descriptor extend_path(
|
||||
const Graph& g, Path& p, ClosedMatrix& closed)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
|
||||
typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
|
||||
typedef typename graph_traits< Graph >::out_edge_iterator OutIterator;
|
||||
|
||||
// get the current vertex
|
||||
Vertex u = p.back();
|
||||
Vertex ret = graph_traits< Graph >::null_vertex();
|
||||
|
||||
// AdjacencyIterator i, end;
|
||||
OutIterator i, end;
|
||||
for (boost::tie(i, end) = out_edges(u, g); i != end; ++i)
|
||||
{
|
||||
Vertex v = target(*i, g);
|
||||
|
||||
// if we can actually extend along this edge,
|
||||
// then that's what we want to do
|
||||
if (can_extend_path(g, *i, p, closed))
|
||||
{
|
||||
p.push_back(v); // add the vertex to the path
|
||||
ret = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template < typename Graph, typename Path, typename ClosedMatrix >
|
||||
inline bool exhaust_paths(const Graph& g, Path& p, ClosedMatrix& closed)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((GraphConcept< Graph >));
|
||||
typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
|
||||
|
||||
// if there's more than one vertex in the path, this closes
|
||||
// of some possible routes and returns true. otherwise, if there's
|
||||
// only one vertex left, the vertex has been used up
|
||||
if (p.size() > 1)
|
||||
{
|
||||
// get the last and second to last vertices, popping the last
|
||||
// vertex off the path
|
||||
Vertex last, prev;
|
||||
last = p.back();
|
||||
p.pop_back();
|
||||
prev = p.back();
|
||||
|
||||
// reset the closure for the last vertex of the path and
|
||||
// indicate that the last vertex in p is now closed to
|
||||
// the next-to-last vertex in p
|
||||
closed[get(vertex_index, g, last)].clear();
|
||||
closed[get(vertex_index, g, prev)].push_back(last);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Graph, typename Visitor >
|
||||
inline void all_cycles_from_vertex(const Graph& g,
|
||||
typename graph_traits< Graph >::vertex_descriptor v, Visitor vis,
|
||||
std::size_t minlen, std::size_t maxlen)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >));
|
||||
typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
|
||||
typedef std::vector< Vertex > Path;
|
||||
BOOST_CONCEPT_ASSERT((CycleVisitorConcept< Visitor, Path, Graph >));
|
||||
typedef std::vector< Vertex > VertexList;
|
||||
typedef std::vector< VertexList > ClosedMatrix;
|
||||
|
||||
Path p;
|
||||
ClosedMatrix closed(num_vertices(g), VertexList());
|
||||
Vertex null = graph_traits< Graph >::null_vertex();
|
||||
|
||||
// each path investigation starts at the ith vertex
|
||||
p.push_back(v);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// extend the path until we've reached the end or the
|
||||
// maxlen-sized cycle
|
||||
Vertex j = null;
|
||||
while (((j = detail::extend_path(g, p, closed)) != null)
|
||||
&& (p.size() < maxlen))
|
||||
; // empty loop
|
||||
|
||||
// if we're done extending the path and there's an edge
|
||||
// connecting the back to the front, then we should have
|
||||
// a cycle.
|
||||
if (detail::can_wrap_path(g, p) && p.size() >= minlen)
|
||||
{
|
||||
vis.cycle(p, g);
|
||||
}
|
||||
|
||||
if (!detail::exhaust_paths(g, p, closed))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select the minimum allowable length of a cycle based on the directedness
|
||||
// of the graph - 2 for directed, 3 for undirected.
|
||||
template < typename D > struct min_cycles
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = 2
|
||||
};
|
||||
};
|
||||
template <> struct min_cycles< undirected_tag >
|
||||
{
|
||||
enum
|
||||
{
|
||||
value = 3
|
||||
};
|
||||
};
|
||||
} /* namespace detail */
|
||||
|
||||
template < typename Graph, typename Visitor >
|
||||
inline void tiernan_all_cycles(
|
||||
const Graph& g, Visitor vis, std::size_t minlen, std::size_t maxlen)
|
||||
{
|
||||
BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >));
|
||||
typedef typename graph_traits< Graph >::vertex_iterator VertexIterator;
|
||||
|
||||
VertexIterator i, end;
|
||||
for (boost::tie(i, end) = vertices(g); i != end; ++i)
|
||||
{
|
||||
detail::all_cycles_from_vertex(g, *i, vis, minlen, maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
template < typename Graph, typename Visitor >
|
||||
inline void tiernan_all_cycles(const Graph& g, Visitor vis, std::size_t maxlen)
|
||||
{
|
||||
typedef typename graph_traits< Graph >::directed_category Dir;
|
||||
tiernan_all_cycles(g, vis, detail::min_cycles< Dir >::value, maxlen);
|
||||
}
|
||||
|
||||
template < typename Graph, typename Visitor >
|
||||
inline void tiernan_all_cycles(const Graph& g, Visitor vis)
|
||||
{
|
||||
typedef typename graph_traits< Graph >::directed_category Dir;
|
||||
tiernan_all_cycles(g, vis, detail::min_cycles< Dir >::value,
|
||||
(std::numeric_limits< std::size_t >::max)());
|
||||
}
|
||||
|
||||
template < typename Graph >
|
||||
inline std::pair< std::size_t, std::size_t > tiernan_girth_and_circumference(
|
||||
const Graph& g)
|
||||
{
|
||||
std::size_t min_ = (std::numeric_limits< std::size_t >::max)(), max_ = 0;
|
||||
tiernan_all_cycles(g, find_min_max_cycle(min_, max_));
|
||||
|
||||
// if this is the case, the graph is acyclic...
|
||||
if (max_ == 0)
|
||||
max_ = min_;
|
||||
|
||||
return std::make_pair(min_, max_);
|
||||
}
|
||||
|
||||
template < typename Graph > inline std::size_t tiernan_girth(const Graph& g)
|
||||
{
|
||||
return tiernan_girth_and_circumference(g).first;
|
||||
}
|
||||
|
||||
template < typename Graph >
|
||||
inline std::size_t tiernan_circumference(const Graph& g)
|
||||
{
|
||||
return tiernan_girth_and_circumference(g).second;
|
||||
}
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
4
3rdParty/tinydbr/TinyDBR.vcxproj
vendored
4
3rdParty/tinydbr/TinyDBR.vcxproj
vendored
|
@ -63,7 +63,7 @@
|
|||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
||||
<AdditionalOptions>-Wno-microsoft-include %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
@ -93,7 +93,7 @@
|
|||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<LanguageStandard_C>stdc11</LanguageStandard_C>
|
||||
<AdditionalOptions>-Wno-microsoft-include %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
|
|
6
3rdParty/winpthreads/winpthreads.vcxproj
vendored
6
3rdParty/winpthreads/winpthreads.vcxproj
vendored
|
@ -60,11 +60,12 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<AdditionalOptions>-Wno-deprecated-declarations -Wno-ignored-pragmas %(AdditionalOptions)</AdditionalOptions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard_C>Default</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
@ -79,11 +80,12 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<AdditionalOptions>-Wno-deprecated-declarations -Wno-ignored-pragmas %(AdditionalOptions)</AdditionalOptions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<LanguageStandard_C>Default</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
|
6
3rdParty/xbyak/xbyak.h
vendored
6
3rdParty/xbyak/xbyak.h
vendored
|
@ -13,9 +13,9 @@
|
|||
// clang 12.0.0:
|
||||
// error : invalid token at start of a preprocessor expression
|
||||
|
||||
//#if (not +0) && !defined(XBYAK_NO_OP_NAMES) // trick to detect whether 'not' is operator or not
|
||||
// #define XBYAK_NO_OP_NAMES
|
||||
//#endif
|
||||
#if (not +0) && !defined(XBYAK_NO_OP_NAMES) // trick to detect whether 'not' is operator or not
|
||||
#define XBYAK_NO_OP_NAMES
|
||||
#endif
|
||||
|
||||
#include <stdio.h> // for debug print
|
||||
#include <assert.h>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
<ClInclude Include="Graphics\Gcn\GcnInstruction.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnInstructionIterator.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnInstructionUtil.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnLoopInfo.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnModInfo.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnShaderMeta.h" />
|
||||
<ClInclude Include="Graphics\Gcn\GcnModule.h" />
|
||||
|
@ -316,6 +317,7 @@
|
|||
<ClCompile Include="Graphics\Gcn\GcnInstruction.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnInstructionIterator.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnInstructionUtil.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnLoopInfo.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnModule.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnProgramInfo.cpp" />
|
||||
<ClCompile Include="Graphics\Gcn\GcnStackifier.cpp" />
|
||||
|
@ -594,13 +596,13 @@
|
|||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<IncludePath>$(ProjectDir);$(ProjectDir)Emulator;$(ProjectDir)Algorithm;$(ProjectDir)Common;$(ProjectDir)Platform;$(ProjectDir)Util;$(ProjectDir)Graphics;$(ProjectDir)SceModules;$(SolutionDir)3rdParty;$(SolutionDir)3rdParty\zydis\include;$(SolutionDir)3rdParty\zydis\dependencies\zycore\include;$(SolutionDir)3rdParty\boost;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(ProjectDir);$(ProjectDir)Emulator;$(ProjectDir)Algorithm;$(ProjectDir)Common;$(ProjectDir)Platform;$(ProjectDir)Util;$(ProjectDir)Util\Object;$(ProjectDir)Graphics;$(ProjectDir)SceModules;$(SolutionDir)3rdParty;$(SolutionDir)3rdParty\zydis\include;$(SolutionDir)3rdParty\zydis\dependencies\zycore\include;$(SolutionDir)3rdParty\boost;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<EnableClangTidyCodeAnalysis>
|
||||
</EnableClangTidyCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<IncludePath>$(ProjectDir);$(ProjectDir)Emulator;$(ProjectDir)Algorithm;$(ProjectDir)Common;$(ProjectDir)Platform;$(ProjectDir)Util;$(ProjectDir)Graphics;$(ProjectDir)SceModules;$(SolutionDir)3rdParty;$(SolutionDir)3rdParty\zydis\include;$(SolutionDir)3rdParty\zydis\dependencies\zycore\include;$(SolutionDir)3rdParty\boost;$(IncludePath)</IncludePath>
|
||||
<IncludePath>$(ProjectDir);$(ProjectDir)Emulator;$(ProjectDir)Algorithm;$(ProjectDir)Common;$(ProjectDir)Platform;$(ProjectDir)Util;$(ProjectDir)Util\Object;$(ProjectDir)Graphics;$(ProjectDir)SceModules;$(SolutionDir)3rdParty;$(SolutionDir)3rdParty\zydis\include;$(SolutionDir)3rdParty\zydis\dependencies\zycore\include;$(SolutionDir)3rdParty\boost;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<EnableClangTidyCodeAnalysis>
|
||||
</EnableClangTidyCodeAnalysis>
|
||||
|
@ -617,13 +619,14 @@
|
|||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>$(VULKAN_SDK)\Include;$(SolutionDir)GPCS4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>GPCS4_DEBUG;__PTW32_STATIC_LIB;_CRT_SECURE_NO_WARNINGS;FMT_HEADER_ONLY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ControlFlowGuard>false</ControlFlowGuard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
|
||||
|
@ -640,13 +643,14 @@
|
|||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalIncludeDirectories>$(VULKAN_SDK)\Include;$(SolutionDir)GPCS4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>__PTW32_STATIC_LIB;_CRT_SECURE_NO_WARNINGS;FMT_HEADER_ONLY;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ControlFlowGuard>false</ControlFlowGuard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
|
|
|
@ -949,6 +949,9 @@
|
|||
<ClInclude Include="Util\Object\UtilStructBank.h">
|
||||
<Filter>Source Files\Util\Object</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Graphics\Gcn\GcnLoopInfo.h">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Loader\EbootObject.cpp">
|
||||
|
@ -1671,6 +1674,9 @@
|
|||
<ClCompile Include="Util\Object\UtilStructBank.cpp">
|
||||
<Filter>Source Files\Util\Object</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Graphics\Gcn\GcnLoopInfo.cpp">
|
||||
<Filter>Source Files\Graphics\Gcn</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="Emulator\TLSStub.asm">
|
||||
|
|
|
@ -72,6 +72,7 @@ namespace sce::gcn
|
|||
{
|
||||
GcnBasicBlock block;
|
||||
block.pcBegin = m_programCounter;
|
||||
block.pcEnd = m_programCounter + ins.length; // in case there is only one instruction in this block
|
||||
block.insList.push_back(ins);
|
||||
currentVtx = boost::add_vertex(block, m_cfg);
|
||||
}
|
||||
|
@ -97,7 +98,7 @@ namespace sce::gcn
|
|||
{
|
||||
uint32_t branchInstPc = basicBlock.pcEnd - lastInst.length;
|
||||
uint32_t targetPc = calculateBranchTarget(branchInstPc, lastInst);
|
||||
auto successor = findVertex(basicBlock.pcEnd);
|
||||
auto successor = findVertex(targetPc);
|
||||
LOG_ASSERT(successor.has_value(), "can't find successor for unconditional branch.");
|
||||
boost::add_edge(vtx, successor.value(), m_cfg);
|
||||
}
|
||||
|
|
|
@ -19,10 +19,16 @@ namespace sce::gcn
|
|||
|
||||
typedef boost::adjacency_list<
|
||||
boost::hash_setS, boost::vecS,
|
||||
boost::bidirectionalS,
|
||||
boost::directedS,
|
||||
GcnBasicBlock>
|
||||
GcnControlFlowGraph;
|
||||
|
||||
typedef GcnControlFlowGraph::vertex_descriptor
|
||||
GcnCfgVertex;
|
||||
|
||||
typedef GcnControlFlowGraph::edge_descriptor
|
||||
GcnCfgEdge;
|
||||
|
||||
typedef boost::graph_traits<
|
||||
GcnControlFlowGraph>::adjacency_iterator
|
||||
GcnAdjacencyIterator;
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace sce::gcn
|
|||
{
|
||||
auto sopp = gcnInstructionAs<GcnShaderInstSOPP>(ins);
|
||||
uint32_t target = static_cast<uint32_t>(static_cast<int32_t>(pc) +
|
||||
static_cast<int32_t>(sopp.control.simm << 2) + 4);
|
||||
static_cast<int16_t>(sopp.control.simm << 2) + 4);
|
||||
return target;
|
||||
}
|
||||
|
||||
|
|
131
GPCS4/Graphics/Gcn/GcnLoopInfo.cpp
Normal file
131
GPCS4/Graphics/Gcn/GcnLoopInfo.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include "GcnLoopInfo.h"
|
||||
|
||||
#include <boost/graph/tiernan_all_cycles.hpp>
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
GcnLoop::GcnLoop(const std::vector<GcnCfgVertex>& path):
|
||||
m_vertices(path)
|
||||
{
|
||||
}
|
||||
|
||||
GcnLoop::~GcnLoop()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
GcnLoopInfo::LoopVisitor::LoopVisitor(std::vector<GcnLoop>& loops) :
|
||||
m_loops(loops)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Path, typename Graph>
|
||||
void GcnLoopInfo::LoopVisitor::cycle(const Path& path, const Graph& g) const
|
||||
{
|
||||
// path is of type std::vector<vertex_descriptor>
|
||||
m_loops.emplace_back(path);
|
||||
}
|
||||
|
||||
GcnLoopInfo::GcnLoopInfo(GcnControlFlowGraph& cfg) :
|
||||
m_cfg(cfg)
|
||||
{
|
||||
detectLoops();
|
||||
detectLoopDomination();
|
||||
detectVertexMaping();
|
||||
}
|
||||
|
||||
GcnLoopInfo::~GcnLoopInfo()
|
||||
{
|
||||
}
|
||||
|
||||
GcnLoop* GcnLoopInfo::getLoop(GcnCfgVertex vertex) const
|
||||
{
|
||||
GcnLoop* loop = nullptr;
|
||||
auto iter = m_vertexMap.find(vertex);
|
||||
if (iter != m_vertexMap.end())
|
||||
{
|
||||
loop = iter->second;
|
||||
}
|
||||
return loop;
|
||||
}
|
||||
|
||||
bool GcnLoopInfo::isLoopHeader(GcnCfgVertex vtx) const
|
||||
{
|
||||
auto loop = getLoop(vtx);
|
||||
return (loop != nullptr) &&
|
||||
(loop->getHeader() == vtx);
|
||||
}
|
||||
|
||||
void GcnLoopInfo::detectLoops()
|
||||
{
|
||||
LoopVisitor visitor(m_loops);
|
||||
boost::tiernan_all_cycles(m_cfg, visitor);
|
||||
}
|
||||
|
||||
void GcnLoopInfo::detectLoopDomination()
|
||||
{
|
||||
for (auto& loop : m_loops)
|
||||
{
|
||||
const auto& loopHeader = loop.m_vertices.front();
|
||||
for (auto& anotherloop : m_loops)
|
||||
{
|
||||
if (loop == anotherloop)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// If a loop's header is a vertex of an another loop,
|
||||
// then this loop is the child of that loop.
|
||||
auto iter = std::find(
|
||||
anotherloop.m_vertices.begin(),
|
||||
anotherloop.m_vertices.end(),
|
||||
loopHeader);
|
||||
if (iter != anotherloop.m_vertices.end())
|
||||
{
|
||||
loop.m_parent = &anotherloop;
|
||||
anotherloop.m_child = &loop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GcnLoopInfo::detectVertexMaping()
|
||||
{
|
||||
for (const auto& vertex : boost::make_iterator_range(boost::vertices(m_cfg)))
|
||||
{
|
||||
auto loop = findLoop(vertex);
|
||||
m_vertexMap.insert(std::make_pair(vertex, loop));
|
||||
}
|
||||
}
|
||||
|
||||
GcnLoop* GcnLoopInfo::findLoop(GcnCfgVertex vtx)
|
||||
{
|
||||
GcnLoop* innerMostLoop = nullptr;
|
||||
for (auto& loop : m_loops)
|
||||
{
|
||||
if (!loop.contains(vtx))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
innerMostLoop = findInnerLoop(&loop, vtx);
|
||||
break;
|
||||
}
|
||||
return innerMostLoop;
|
||||
}
|
||||
|
||||
GcnLoop* GcnLoopInfo::findInnerLoop(GcnLoop* loop, GcnCfgVertex vtx)
|
||||
{
|
||||
GcnLoop* result = nullptr;
|
||||
if (loop->m_child == nullptr || !loop->m_child->contains(vtx))
|
||||
{
|
||||
result = loop;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = findInnerLoop(loop->m_child, vtx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace sce::gcn
|
89
GPCS4/Graphics/Gcn/GcnLoopInfo.h
Normal file
89
GPCS4/Graphics/Gcn/GcnLoopInfo.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
|
||||
#include "GcnCommon.h"
|
||||
#include "GcnControlFlowGraph.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
/**
|
||||
* \brief Represents a loop in CFG
|
||||
*/
|
||||
class GcnLoop
|
||||
{
|
||||
friend class GcnLoopInfo;
|
||||
public:
|
||||
GcnLoop(
|
||||
const std::vector<GcnCfgVertex>& path);
|
||||
~GcnLoop();
|
||||
|
||||
bool contains(GcnCfgVertex vtx) const
|
||||
{
|
||||
return std::find(
|
||||
m_vertices.begin(), m_vertices.end(), vtx) !=
|
||||
m_vertices.end();
|
||||
}
|
||||
|
||||
GcnCfgVertex getHeader() const
|
||||
{
|
||||
return m_vertices.front();
|
||||
}
|
||||
|
||||
bool operator==(const GcnLoop& other) const
|
||||
{
|
||||
return m_vertices == other.m_vertices;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<GcnCfgVertex> m_vertices;
|
||||
GcnLoop* m_parent = nullptr;
|
||||
GcnLoop* m_child = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Loop collection of the CFG
|
||||
*/
|
||||
class GcnLoopInfo
|
||||
{
|
||||
class LoopVisitor
|
||||
{
|
||||
public:
|
||||
LoopVisitor(std::vector<GcnLoop>& loops);
|
||||
|
||||
template <typename Path, typename Graph>
|
||||
void cycle(const Path& path, const Graph& g) const;
|
||||
|
||||
private:
|
||||
std::vector<GcnLoop>& m_loops;
|
||||
};
|
||||
|
||||
public:
|
||||
GcnLoopInfo(GcnControlFlowGraph& cfg);
|
||||
~GcnLoopInfo();
|
||||
|
||||
/**
|
||||
* \brief Get loop for vertex
|
||||
*
|
||||
* Return the inner most loop that vertex lives in. If a vertex is in no
|
||||
* loop (for example the entry node), null is returned.
|
||||
*/
|
||||
GcnLoop* getLoop(GcnCfgVertex vertex) const;
|
||||
|
||||
bool isLoopHeader(GcnCfgVertex vtx) const;
|
||||
|
||||
private:
|
||||
void detectLoops();
|
||||
void detectLoopDomination();
|
||||
void detectVertexMaping();
|
||||
|
||||
GcnLoop* findLoop(GcnCfgVertex vtx);
|
||||
GcnLoop* findInnerLoop(GcnLoop* loop, GcnCfgVertex vtx);
|
||||
private:
|
||||
GcnControlFlowGraph& m_cfg;
|
||||
std::vector<GcnLoop> m_loops;
|
||||
|
||||
// Mapping of vertex to the inner most loop they occur in
|
||||
std::unordered_map<GcnCfgVertex, GcnLoop*> m_vertexMap;
|
||||
};
|
||||
} // namespace sce::gcn
|
18
GPCS4/Graphics/Gcn/GcnStackifier.cpp
Normal file
18
GPCS4/Graphics/Gcn/GcnStackifier.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
#include "GcnStackifier.h"
|
||||
|
||||
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
GcnStackifier::GcnStackifier(GcnControlFlowGraph& cfg):
|
||||
m_cfg(cfg)
|
||||
{
|
||||
}
|
||||
|
||||
GcnStackifier::~GcnStackifier()
|
||||
{
|
||||
}
|
||||
} // namespace sce::gcn
|
24
GPCS4/Graphics/Gcn/GcnStackifier.h
Normal file
24
GPCS4/Graphics/Gcn/GcnStackifier.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "GcnCommon.h"
|
||||
#include "GcnTokenList.h"
|
||||
#include "GcnLoopInfo.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
|
||||
class GcnStackifier
|
||||
{
|
||||
public:
|
||||
GcnStackifier(GcnControlFlowGraph& cfg);
|
||||
~GcnStackifier();
|
||||
|
||||
private:
|
||||
GcnControlFlowGraph& m_cfg;
|
||||
GcnTokenList m_tokens;
|
||||
};
|
||||
|
||||
} // namespace sce::gcn
|
36
GPCS4/Graphics/Gcn/GcnTokenList.cpp
Normal file
36
GPCS4/Graphics/Gcn/GcnTokenList.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "GcnTokenList.h"
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
|
||||
GcnToken::GcnToken(GcnTokenKind kind, GcnCfgVertex vertex, GcnToken* match) :
|
||||
m_kind(kind),
|
||||
m_vertex(vertex),
|
||||
m_match(match)
|
||||
{
|
||||
}
|
||||
|
||||
GcnToken::~GcnToken()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
GcnTokenFactory::GcnTokenFactory(util::ObjectBank<GcnToken>& tokenPool):
|
||||
m_pool(tokenPool)
|
||||
{
|
||||
}
|
||||
|
||||
GcnTokenFactory::~GcnTokenFactory()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
GcnTokenList::GcnTokenList()
|
||||
{
|
||||
}
|
||||
|
||||
GcnTokenList::~GcnTokenList()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace sce::gcn
|
217
GPCS4/Graphics/Gcn/GcnTokenList.h
Normal file
217
GPCS4/Graphics/Gcn/GcnTokenList.h
Normal file
|
@ -0,0 +1,217 @@
|
|||
#pragma once
|
||||
|
||||
#include "GcnCommon.h"
|
||||
#include "GcnControlFlowGraph.h"
|
||||
#include "UtilObjectBank.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace sce::gcn
|
||||
{
|
||||
enum class GcnTokenKind : uint32_t
|
||||
{
|
||||
Invalid = 0,
|
||||
Code = 1 << 0,
|
||||
Loop = 1 << 1,
|
||||
Block = 1 << 2,
|
||||
If = 1 << 3,
|
||||
IfNot = 1 << 4,
|
||||
Else = 1 << 5,
|
||||
Branch = 1 << 6,
|
||||
End = 1 << 7,
|
||||
Condition = 1 << 8,
|
||||
};
|
||||
|
||||
class GcnToken
|
||||
{
|
||||
friend class GcnTokenFactory;
|
||||
public:
|
||||
GcnToken(GcnTokenKind kind,
|
||||
GcnCfgVertex vertex,
|
||||
GcnToken* match);
|
||||
~GcnToken();
|
||||
|
||||
private:
|
||||
GcnTokenKind m_kind;
|
||||
GcnCfgVertex m_vertex;
|
||||
// A related token, for example,
|
||||
// the match of a If token is End
|
||||
GcnToken* m_match;
|
||||
};
|
||||
|
||||
class GcnTokenFactory
|
||||
{
|
||||
public:
|
||||
GcnTokenFactory(
|
||||
util::ObjectBank<GcnToken>& tokenPool);
|
||||
~GcnTokenFactory();
|
||||
|
||||
GcnToken* createCode(GcnCfgVertex vertex)
|
||||
{
|
||||
return m_pool.allocate(GcnTokenKind::Code, vertex, nullptr);
|
||||
}
|
||||
|
||||
GcnToken* createLoop()
|
||||
{
|
||||
return m_pool.allocate(
|
||||
GcnTokenKind::Loop, GcnControlFlowGraph::null_vertex(), nullptr);
|
||||
}
|
||||
|
||||
GcnToken* createLoopEnd(GcnToken* loopBegin)
|
||||
{
|
||||
assert(loopBegin && loopBegin->m_kind == GcnTokenKind::Loop);
|
||||
auto loopEnd = m_pool.allocate(
|
||||
GcnTokenKind::End, GcnControlFlowGraph::null_vertex(), loopBegin);
|
||||
loopBegin->m_match = loopEnd;
|
||||
return loopEnd;
|
||||
}
|
||||
|
||||
GcnToken* createBlock()
|
||||
{
|
||||
return m_pool.allocate(
|
||||
GcnTokenKind::Block, GcnControlFlowGraph::null_vertex(), nullptr);
|
||||
}
|
||||
|
||||
GcnToken* createBlockEnd(GcnToken* blockBegin)
|
||||
{
|
||||
assert(blockBegin && blockBegin->m_kind == GcnTokenKind::Block);
|
||||
auto blockEnd = m_pool.allocate(
|
||||
GcnTokenKind::End, GcnControlFlowGraph::null_vertex(), blockBegin);
|
||||
blockBegin->m_match = blockEnd;
|
||||
return blockEnd;
|
||||
}
|
||||
|
||||
GcnToken* createIf(GcnCfgVertex condition)
|
||||
{
|
||||
return m_pool.allocate(GcnTokenKind::If, condition, nullptr);
|
||||
}
|
||||
|
||||
GcnToken* createIfNot(GcnCfgVertex condition)
|
||||
{
|
||||
return m_pool.allocate(GcnTokenKind::IfNot, condition, nullptr);
|
||||
}
|
||||
|
||||
GcnToken* createElse(GcnToken* tokenIf)
|
||||
{
|
||||
assert(!tokenIf || tokenIf->m_kind == GcnTokenKind::If);
|
||||
auto tokenElse = m_pool.allocate(
|
||||
GcnTokenKind::Else, GcnControlFlowGraph::null_vertex(), nullptr);
|
||||
if (tokenIf)
|
||||
{
|
||||
tokenIf->m_match = tokenElse;
|
||||
}
|
||||
return tokenElse;
|
||||
}
|
||||
|
||||
GcnToken* createIfEnd(GcnToken* tokenIf, GcnToken* tokenElse)
|
||||
{
|
||||
assert(!tokenIf || tokenIf->m_kind == GcnTokenKind::If);
|
||||
assert(!tokenElse || tokenElse->m_kind == GcnTokenKind::Else);
|
||||
assert(tokenIf || tokenElse);
|
||||
|
||||
auto tokenEnd = m_pool.allocate(
|
||||
GcnTokenKind::End, GcnControlFlowGraph::null_vertex(), tokenIf);
|
||||
if (tokenElse)
|
||||
{
|
||||
tokenElse->m_match = tokenEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
tokenIf->m_match = tokenEnd;
|
||||
}
|
||||
|
||||
return tokenEnd;
|
||||
}
|
||||
|
||||
GcnToken* createBranch(GcnToken* target)
|
||||
{
|
||||
return m_pool.allocate(
|
||||
GcnTokenKind::Branch, GcnControlFlowGraph::null_vertex(), target);
|
||||
}
|
||||
|
||||
GcnToken* createCondition(GcnCfgVertex condition)
|
||||
{
|
||||
return m_pool.allocate(GcnTokenKind::Condition, condition, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
util::ObjectBank<GcnToken>& m_pool;
|
||||
};
|
||||
|
||||
|
||||
class GcnTokenList
|
||||
{
|
||||
typedef std::list<GcnToken*> TokenListType;
|
||||
public:
|
||||
GcnTokenList();
|
||||
~GcnTokenList();
|
||||
|
||||
public:
|
||||
/// Token iterators...
|
||||
typedef TokenListType::iterator iterator;
|
||||
typedef TokenListType::const_iterator const_iterator;
|
||||
typedef TokenListType::reverse_iterator reverse_iterator;
|
||||
typedef TokenListType::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
/// Token iterator methods
|
||||
// clang-format off
|
||||
inline iterator begin() { return m_list.begin(); }
|
||||
inline const_iterator begin() const { return m_list.begin(); }
|
||||
inline iterator end () { return m_list.end(); }
|
||||
inline const_iterator end () const { return m_list.end(); }
|
||||
|
||||
inline reverse_iterator rbegin() { return m_list.rbegin(); }
|
||||
inline const_reverse_iterator rbegin() const { return m_list.rbegin(); }
|
||||
inline reverse_iterator rend () { return m_list.rend(); }
|
||||
inline const_reverse_iterator rend () const { return m_list.rend(); }
|
||||
|
||||
inline size_t size() const { return m_list.size(); }
|
||||
inline bool empty() const { return m_list.empty(); }
|
||||
inline const GcnToken &front() const { return *m_list.front(); }
|
||||
inline GcnToken &front() { return *m_list.front(); }
|
||||
inline const GcnToken &back() const { return *m_list.back(); }
|
||||
inline GcnToken &back() { return *m_list.back(); }
|
||||
// clang-format on
|
||||
|
||||
void append(GcnToken* token)
|
||||
{
|
||||
m_list.push_back(token);
|
||||
}
|
||||
|
||||
iterator insert(iterator where, GcnToken* token)
|
||||
{
|
||||
return m_list.insert(where, token);
|
||||
}
|
||||
|
||||
iterator insertAfter(iterator where, GcnToken* token)
|
||||
{
|
||||
iterator iter = {};
|
||||
if (empty())
|
||||
{
|
||||
iter = m_list.insert(begin(), token);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = m_list.insert(++where, token);
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
void moveAfter(iterator where, iterator first, iterator last)
|
||||
{
|
||||
return m_list.splice(std::next(where), m_list, first, last);
|
||||
}
|
||||
|
||||
void erase(GcnToken* token)
|
||||
{
|
||||
std::erase(m_list, token);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<GcnToken*> m_list;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace sce::gcn
|
|
@ -1,120 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
#include "UtilStructBank.h"
|
||||
|
||||
namespace util
|
||||
{
|
||||
// These work just like StructBanks but are for C++ objects that need their
|
||||
// constructors and destructors called.
|
||||
|
||||
constexpr uint32_t DEFAULT_OBJECT_CACHE_SIZE = 32;
|
||||
|
||||
class DummyThingForConstructor
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
class NullCS
|
||||
{
|
||||
public:
|
||||
void Enter()
|
||||
void enter()
|
||||
{
|
||||
}
|
||||
void Leave()
|
||||
void leave()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class CS = NullCS>
|
||||
class ObjectBank : public BaseObjectBank
|
||||
class ObjectBank
|
||||
{
|
||||
public:
|
||||
ObjectBank();
|
||||
ObjectBank(uint32_t cacheSize, uint32_t preAllocate = 0);
|
||||
virtual ~ObjectBank();
|
||||
ObjectBank()
|
||||
{
|
||||
m_bank = sbCreate();
|
||||
sbInit(m_bank, sizeof(T), DEFAULT_OBJECT_CACHE_SIZE);
|
||||
}
|
||||
|
||||
void init(uint32_t cacheSize, uint32_t preAllocate = 0);
|
||||
ObjectBank(uint32_t cacheSize, uint32_t preAllocate = 0)
|
||||
{
|
||||
m_bank = sbCreate();
|
||||
sbInitEx(m_bank, sizeof(T), cacheSize, preAllocate);
|
||||
}
|
||||
|
||||
void term();
|
||||
~ObjectBank()
|
||||
{
|
||||
sbTerm(&m_bank);
|
||||
sbDestroy(m_bank);
|
||||
}
|
||||
|
||||
// Set the cache size (in numbers of objects).
|
||||
// Default is DEFAULT_OBJECT_CACHE_SIZE.
|
||||
void setCacheSize(uint32_t size);
|
||||
void init(uint32_t cacheSize, uint32_t preAllocate = 0)
|
||||
{
|
||||
m_cs.enter();
|
||||
sbTerm(m_bank);
|
||||
sbInitEx(m_bank, sizeof(T), cacheSize, preAllocate);
|
||||
m_cs.leave();
|
||||
}
|
||||
|
||||
T* allocate();
|
||||
void free(T* pObj);
|
||||
void term()
|
||||
{
|
||||
m_cs.enter();
|
||||
sbTerm(m_bank);
|
||||
sbInit(m_bank, sizeof(T), DEFAULT_OBJECT_CACHE_SIZE);
|
||||
m_cs.leave();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set page granularity
|
||||
*
|
||||
* Set number of objects for each real memory allocation (malloc)
|
||||
* Default is DEFAULT_OBJECT_CACHE_SIZE.
|
||||
*/
|
||||
void setPageGranularity(uint32_t size)
|
||||
{
|
||||
m_cs.enter();
|
||||
m_bank->m_cacheSize = size;
|
||||
m_cs.leave();
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
//typename std::enable_if<std::is_constructible_v<T, Args...>, T*>::type
|
||||
requires std::is_constructible_v<T, Args...>
|
||||
T* allocate(Args&&... args)
|
||||
{
|
||||
T* object = nullptr;
|
||||
|
||||
m_cs.enter();
|
||||
object = (T*)sbAllocate(m_bank);
|
||||
if (object)
|
||||
{
|
||||
std::construct_at(object, std::forward<Args>(args)...);
|
||||
}
|
||||
m_cs.leave();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
void free(T* pObj)
|
||||
{
|
||||
m_cs.enter();
|
||||
std::destroy_at(pObj);
|
||||
sbFree(m_bank, object);
|
||||
m_cs.leave();
|
||||
}
|
||||
|
||||
public:
|
||||
StructBank m_bank;
|
||||
CS m_cs;
|
||||
StructBank* m_bank = nullptr;
|
||||
CS m_cs;
|
||||
};
|
||||
|
||||
template <class T, class CS>
|
||||
inline ObjectBank<T, CS>::ObjectBank()
|
||||
{
|
||||
sbInit(&m_bank, sizeof(T), DEFAULT_OBJECT_CACHE_SIZE);
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline ObjectBank<T, CS>::ObjectBank(uint32_t cacheSize, uint32_t preAllocate)
|
||||
{
|
||||
sbInitEx(&m_bank, sizeof(T), cacheSize, preAllocate);
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline ObjectBank<T, CS>::~ObjectBank()
|
||||
{
|
||||
sbTerm(&m_bank);
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline void ObjectBank<T, CS>::init(uint32_t cacheSize, uint32_t preAllocate)
|
||||
{
|
||||
m_cs.Enter();
|
||||
sbTerm(&m_bank);
|
||||
sbInitEx(&m_bank, sizeof(T), cacheSize, preAllocate);
|
||||
m_cs.Leave();
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline void ObjectBank<T, CS>::term()
|
||||
{
|
||||
m_cs.Enter();
|
||||
sbTerm(&m_bank);
|
||||
sbInit(&m_bank, sizeof(T), DEFAULT_OBJECT_CACHE_SIZE);
|
||||
m_cs.Leave();
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline void ObjectBank<T, CS>::setCacheSize(uint32_t size)
|
||||
{
|
||||
m_cs.Enter();
|
||||
m_bank.m_cacheSize = size;
|
||||
m_cs.Leave();
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline T* ObjectBank<T, CS>::allocate()
|
||||
{
|
||||
T* object;
|
||||
|
||||
m_cs.Enter();
|
||||
object = (T*)sbAllocate(&m_Bank);
|
||||
if (object)
|
||||
{
|
||||
::new ((DummyThingForConstructor*)0, object) T;
|
||||
}
|
||||
m_cs.Leave();
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
template <class T, class CS>
|
||||
inline void ObjectBank<T, CS>::free(T* object)
|
||||
{
|
||||
m_cs.Enter();
|
||||
object->~T();
|
||||
sbFree(&m_bank, object);
|
||||
m_cs.Leave();
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
|
|
|
@ -6,8 +6,59 @@ LOG_CHANNEL(Util.StructBank);
|
|||
|
||||
namespace util
|
||||
{
|
||||
struct StructLink
|
||||
{
|
||||
struct StructLink* m_slNext;
|
||||
};
|
||||
|
||||
struct StructBankPage
|
||||
{
|
||||
struct StructBankPage* m_next;
|
||||
unsigned long m_objects; // How many objects are in this page?
|
||||
uint32_t m_data[1];
|
||||
};
|
||||
|
||||
struct StructBank
|
||||
{
|
||||
// Struct size.
|
||||
unsigned long m_structSize;
|
||||
|
||||
// The actual size we allocate with (aligned to 4 bytes and with 4 bytes
|
||||
// extra for the StructLink).
|
||||
unsigned long m_alignedStructSize;
|
||||
|
||||
// How many structs per page.
|
||||
unsigned long m_cacheSize;
|
||||
|
||||
// How many pages have we allocated?
|
||||
unsigned long m_numPages;
|
||||
|
||||
// Total number of objects this StructBank has allocated.
|
||||
unsigned long m_numTotalObjects;
|
||||
|
||||
// The first page.
|
||||
StructBankPage* m_pageHead;
|
||||
|
||||
// The free list.
|
||||
StructLink* m_freeListHead;
|
||||
};
|
||||
|
||||
bool sbAllocateNewStructPage(StructBank* pBank, uint32_t nAllocations);
|
||||
|
||||
StructBank* sbCreate()
|
||||
{
|
||||
return (StructBank*)calloc(1, sizeof(StructBank));
|
||||
}
|
||||
|
||||
void sbDestroy(StructBank* pBank)
|
||||
{
|
||||
if (pBank)
|
||||
{
|
||||
sbTerm(pBank);
|
||||
}
|
||||
free(pBank);
|
||||
}
|
||||
|
||||
void sbInit(StructBank* pBank, uint32_t structSize, uint32_t cacheSize)
|
||||
{
|
||||
pBank->m_structSize = structSize;
|
||||
|
@ -137,7 +188,9 @@ namespace util
|
|||
}
|
||||
|
||||
// Allocate a new page.
|
||||
pPage = (StructBankPage*)malloc((pBank->m_alignedStructSize * nAllocations) + (sizeof(StructBankPage) - sizeof(uint32_t)));
|
||||
pPage = (StructBankPage*)malloc(
|
||||
(pBank->m_alignedStructSize * nAllocations) +
|
||||
(sizeof(StructBankPage) - sizeof(uint32_t)));
|
||||
if (!pPage)
|
||||
{
|
||||
break;
|
||||
|
|
|
@ -5,43 +5,13 @@
|
|||
|
||||
namespace util
|
||||
{
|
||||
struct StructBank;
|
||||
|
||||
struct StructLink
|
||||
{
|
||||
struct StructLink* m_slNext;
|
||||
};
|
||||
// Create an empty bank object
|
||||
StructBank* sbCreate();
|
||||
|
||||
struct StructBankPage
|
||||
{
|
||||
struct StructBankPage* m_next;
|
||||
unsigned long m_objects; // How many objects are in this page?
|
||||
uint32_t m_data[1];
|
||||
};
|
||||
|
||||
struct StructBank
|
||||
{
|
||||
// Struct size.
|
||||
unsigned long m_structSize;
|
||||
|
||||
// The actual size we allocate with (aligned to 4 bytes and with 4 bytes
|
||||
// extra for the StructLink).
|
||||
unsigned long m_alignedStructSize;
|
||||
|
||||
// How many structs per page.
|
||||
unsigned long m_cacheSize;
|
||||
|
||||
// How many pages have we allocated?
|
||||
unsigned long m_numPages;
|
||||
|
||||
// Total number of objects this StructBank has allocated.
|
||||
unsigned long m_numTotalObjects;
|
||||
|
||||
// The first page.
|
||||
StructBankPage* m_pageHead;
|
||||
|
||||
// The free list.
|
||||
StructLink* m_freeListHead;
|
||||
};
|
||||
// Destroy the bank created by sbCreate
|
||||
void sbDestroy(StructBank* pBank);
|
||||
|
||||
// Initialize.. pass in the size of your structure and how much to cache.
|
||||
void sbInit(StructBank* pBank, uint32_t structSize, uint32_t cacheSize);
|
||||
|
|
Loading…
Reference in a new issue