shader: Use shared_ptr to store nodes and move initialization to file

Instead of having a vector of unique_ptr stored in a vector and
returning star pointers to this, use shared_ptr. While changing
initialization code, move it to a separate file when possible.

This is a first step to allow code analysis and node generation beyond
the ShaderIR class.
This commit is contained in:
ReinUsesLisp
2019-06-04 22:44:06 -03:00
parent a20ba09bfd
commit bf4dfb3ad4
35 changed files with 296 additions and 248 deletions

View File

@ -38,7 +38,7 @@ using ProgramCode = std::vector<u64>;
using NodeData =
std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode,
PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>;
using Node = const NodeData*;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
@ -342,23 +342,20 @@ using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>;
/// Holds any kind of operation that can be done in the IR
class OperationNode final {
public:
explicit OperationNode(OperationCode code) : code{code} {}
explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {}
explicit OperationNode(OperationCode code, Meta&& meta) : code{code}, meta{std::move(meta)} {}
explicit OperationNode(OperationCode code, Meta meta)
: OperationNode(code, meta, std::vector<Node>{}) {}
template <typename... T>
explicit OperationNode(OperationCode code, const T*... operands)
: OperationNode(code, {}, operands...) {}
explicit OperationNode(OperationCode code, std::vector<Node> operands)
: OperationNode(code, Meta{}, std::move(operands)) {}
template <typename... T>
explicit OperationNode(OperationCode code, Meta&& meta, const T*... operands_)
: code{code}, meta{std::move(meta)}, operands{operands_...} {}
explicit OperationNode(OperationCode code, Meta meta, std::vector<Node> operands)
: code{code}, meta{std::move(meta)}, operands{std::move(operands)} {}
explicit OperationNode(OperationCode code, Meta&& meta, std::vector<Node>&& operands)
: code{code}, meta{meta}, operands{std::move(operands)} {}
explicit OperationNode(OperationCode code, std::vector<Node>&& operands)
: code{code}, operands{std::move(operands)} {}
template <typename... Args>
explicit OperationNode(OperationCode code, Meta meta, Args&&... operands)
: code{code}, meta{std::move(meta)}, operands{operands...} {}
OperationCode GetCode() const {
return code;
@ -372,13 +369,13 @@ public:
return operands.size();
}
Node operator[](std::size_t operand_index) const {
const Node& operator[](std::size_t operand_index) const {
return operands.at(operand_index);
}
private:
const OperationCode code;
const Meta meta;
OperationCode code{};
Meta meta{};
std::vector<Node> operands;
};
@ -463,13 +460,12 @@ private:
class AbufNode final {
public:
// Initialize for standard attributes (index is explicit).
explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element,
Node buffer = {})
: buffer{buffer}, index{index}, element{element} {}
explicit AbufNode(Tegra::Shader::Attribute::Index index, u32 element, Node buffer = {})
: buffer{std::move(buffer)}, index{index}, element{element} {}
// Initialize for physical attributes (index is a variable value).
explicit constexpr AbufNode(Node physical_address, Node buffer = {})
: physical_address{physical_address}, buffer{buffer} {}
explicit AbufNode(Node physical_address, Node buffer = {})
: physical_address{physical_address}, buffer{std::move(buffer)} {}
Tegra::Shader::Attribute::Index GetIndex() const {
return index;
@ -484,16 +480,16 @@ public:
}
bool IsPhysicalBuffer() const {
return physical_address != nullptr;
return static_cast<bool>(physical_address);
}
Node GetPhysicalAddress() const {
const Node& GetPhysicalAddress() const {
return physical_address;
}
private:
Node physical_address{};
Node buffer{};
Node physical_address;
Node buffer;
Tegra::Shader::Attribute::Index index{};
u32 element{};
};
@ -501,7 +497,7 @@ private:
/// Constant buffer node, usually mapped to uniform buffers in GLSL
class CbufNode final {
public:
explicit constexpr CbufNode(u32 index, Node offset) : index{index}, offset{offset} {}
explicit CbufNode(u32 index, Node offset) : index{index}, offset{offset} {}
u32 GetIndex() const {
return index;
@ -519,7 +515,7 @@ private:
/// Local memory node
class LmemNode final {
public:
explicit constexpr LmemNode(Node address) : address{address} {}
explicit LmemNode(Node address) : address{address} {}
Node GetAddress() const {
return address;
@ -532,8 +528,7 @@ private:
/// Global memory node
class GmemNode final {
public:
explicit constexpr GmemNode(Node real_address, Node base_address,
const GlobalMemoryBase& descriptor)
explicit GmemNode(Node real_address, Node base_address, const GlobalMemoryBase& descriptor)
: real_address{real_address}, base_address{base_address}, descriptor{descriptor} {}
Node GetRealAddress() const {
@ -663,26 +658,6 @@ private:
u32 DecodeXmad(NodeBlock& bb, u32 pc);
u32 DecodeOther(NodeBlock& bb, u32 pc);
/// Internalizes node's data and returns a managed pointer to a clone of that node
Node StoreNode(NodeData&& node_data);
/// Creates a conditional node
Node Conditional(Node condition, std::vector<Node>&& code);
/// Creates a commentary
Node Comment(std::string text);
/// Creates an u32 immediate
Node Immediate(u32 value);
/// Creates a s32 immediate
Node Immediate(s32 value) {
return Immediate(static_cast<u32>(value));
}
/// Creates a f32 immediate
Node Immediate(f32 value) {
u32 integral;
std::memcpy(&integral, &value, sizeof(u32));
return Immediate(integral);
}
/// Generates a node for a passed register.
Node GetRegister(Tegra::Shader::Register reg);
/// Generates a node representing a 19-bit immediate value
@ -827,37 +802,6 @@ private:
std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(
NodeBlock& bb, Tegra::Shader::Instruction instr, bool is_write);
template <typename... T>
Node Operation(OperationCode code, const T*... operands) {
return StoreNode(OperationNode(code, operands...));
}
template <typename... T>
Node Operation(OperationCode code, Meta&& meta, const T*... operands) {
return StoreNode(OperationNode(code, std::move(meta), operands...));
}
Node Operation(OperationCode code, std::vector<Node>&& operands) {
return StoreNode(OperationNode(code, std::move(operands)));
}
Node Operation(OperationCode code, Meta&& meta, std::vector<Node>&& operands) {
return StoreNode(OperationNode(code, std::move(meta), std::move(operands)));
}
template <typename... T>
Node SignedOperation(OperationCode code, bool is_signed, const T*... operands) {
return StoreNode(OperationNode(SignedToUnsignedCode(code, is_signed), operands...));
}
template <typename... T>
Node SignedOperation(OperationCode code, bool is_signed, Meta&& meta, const T*... operands) {
return StoreNode(
OperationNode(SignedToUnsignedCode(code, is_signed), std::move(meta), operands...));
}
static OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed);
const ProgramCode& program_code;
const u32 main_offset;
@ -868,8 +812,6 @@ private:
std::map<u32, NodeBlock> basic_blocks;
NodeBlock global_code;
std::vector<std::unique_ptr<NodeData>> stored_nodes;
std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates;
std::set<Tegra::Shader::Attribute::Index> used_input_attributes;