glasm: Rework control flow introducing a syntax list
This commit regresses VertexA shaders, their transformation pass has to be adapted to the new control flow.
This commit is contained in:
parent
7ff5851608
commit
d54d7de40e
33 changed files with 437 additions and 505 deletions
56
src/shader_recompiler/frontend/ir/abstract_syntax_list.h
Normal file
56
src/shader_recompiler/frontend/ir/abstract_syntax_list.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
class Block;
|
||||
|
||||
struct AbstractSyntaxNode {
|
||||
enum class Type {
|
||||
Block,
|
||||
If,
|
||||
EndIf,
|
||||
Loop,
|
||||
Repeat,
|
||||
Break,
|
||||
Return,
|
||||
Unreachable,
|
||||
};
|
||||
Type type{};
|
||||
union {
|
||||
Block* block{};
|
||||
struct {
|
||||
U1 cond;
|
||||
Block* body;
|
||||
Block* merge;
|
||||
} if_node;
|
||||
struct {
|
||||
Block* merge;
|
||||
} end_if;
|
||||
struct {
|
||||
Block* body;
|
||||
Block* continue_block;
|
||||
Block* merge;
|
||||
} loop;
|
||||
struct {
|
||||
U1 cond;
|
||||
Block* loop_header;
|
||||
Block* merge;
|
||||
} repeat;
|
||||
struct {
|
||||
U1 cond;
|
||||
Block* merge;
|
||||
Block* skip;
|
||||
} break_node;
|
||||
};
|
||||
};
|
||||
using AbstractSyntaxList = std::vector<AbstractSyntaxNode>;
|
||||
|
||||
} // namespace Shader::IR
|
|
@ -14,10 +14,7 @@
|
|||
|
||||
namespace Shader::IR {
|
||||
|
||||
Block::Block(ObjectPool<Inst>& inst_pool_, u32 begin, u32 end)
|
||||
: inst_pool{&inst_pool_}, location_begin{begin}, location_end{end} {}
|
||||
|
||||
Block::Block(ObjectPool<Inst>& inst_pool_) : Block{inst_pool_, 0, 0} {}
|
||||
Block::Block(ObjectPool<Inst>& inst_pool_) : inst_pool{&inst_pool_} {}
|
||||
|
||||
Block::~Block() = default;
|
||||
|
||||
|
@ -40,39 +37,15 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
|
|||
return result_it;
|
||||
}
|
||||
|
||||
void Block::SetBranches(Condition cond, Block* branch_true_, Block* branch_false_) {
|
||||
branch_cond = cond;
|
||||
branch_true = branch_true_;
|
||||
branch_false = branch_false_;
|
||||
}
|
||||
|
||||
void Block::SetBranch(Block* branch) {
|
||||
branch_cond = Condition{true};
|
||||
branch_true = branch;
|
||||
}
|
||||
|
||||
void Block::SetReturn() {
|
||||
branch_cond = Condition{true};
|
||||
branch_true = nullptr;
|
||||
branch_false = nullptr;
|
||||
}
|
||||
|
||||
bool Block::IsVirtual() const noexcept {
|
||||
return location_begin == location_end;
|
||||
}
|
||||
|
||||
u32 Block::LocationBegin() const noexcept {
|
||||
return location_begin;
|
||||
}
|
||||
|
||||
u32 Block::LocationEnd() const noexcept {
|
||||
return location_end;
|
||||
}
|
||||
|
||||
void Block::AddImmediatePredecessor(Block* block) {
|
||||
if (std::ranges::find(imm_predecessors, block) == imm_predecessors.end()) {
|
||||
imm_predecessors.push_back(block);
|
||||
void Block::AddBranch(Block* block) {
|
||||
if (std::ranges::find(imm_successors, block) != imm_successors.end()) {
|
||||
throw LogicError("Successor already inserted");
|
||||
}
|
||||
if (std::ranges::find(block->imm_predecessors, this) != block->imm_predecessors.end()) {
|
||||
throw LogicError("Predecessor already inserted");
|
||||
}
|
||||
imm_successors.push_back(block);
|
||||
block->imm_predecessors.push_back(this);
|
||||
}
|
||||
|
||||
static std::string BlockToIndex(const std::map<const Block*, size_t>& block_to_index,
|
||||
|
@ -92,15 +65,11 @@ static size_t InstIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& in
|
|||
return it->second;
|
||||
}
|
||||
|
||||
static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_index,
|
||||
std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
|
||||
static std::string ArgToIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
|
||||
const Value& arg) {
|
||||
if (arg.IsEmpty()) {
|
||||
return "<null>";
|
||||
}
|
||||
if (arg.IsLabel()) {
|
||||
return BlockToIndex(block_to_index, arg.Label());
|
||||
}
|
||||
if (!arg.IsImmediate() || arg.IsIdentity()) {
|
||||
return fmt::format("%{}", InstIndex(inst_to_index, inst_index, arg.Inst()));
|
||||
}
|
||||
|
@ -140,8 +109,7 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>&
|
|||
if (const auto it{block_to_index.find(&block)}; it != block_to_index.end()) {
|
||||
ret += fmt::format(" ${}", it->second);
|
||||
}
|
||||
ret += fmt::format(": begin={:04x} end={:04x}\n", block.LocationBegin(), block.LocationEnd());
|
||||
|
||||
ret += '\n';
|
||||
for (const Inst& inst : block) {
|
||||
const Opcode op{inst.GetOpcode()};
|
||||
ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst));
|
||||
|
@ -153,7 +121,7 @@ std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>&
|
|||
const size_t arg_count{inst.NumArgs()};
|
||||
for (size_t arg_index = 0; arg_index < arg_count; ++arg_index) {
|
||||
const Value arg{inst.Arg(arg_index)};
|
||||
const std::string arg_str{ArgToIndex(block_to_index, inst_to_index, inst_index, arg)};
|
||||
const std::string arg_str{ArgToIndex(inst_to_index, inst_index, arg)};
|
||||
ret += arg_index != 0 ? ", " : " ";
|
||||
if (op == Opcode::Phi) {
|
||||
ret += fmt::format("[ {}, {} ]", arg_str,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
#include "common/bit_cast.h"
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/frontend/ir/condition.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/object_pool.h"
|
||||
|
@ -27,7 +28,6 @@ public:
|
|||
using reverse_iterator = InstructionList::reverse_iterator;
|
||||
using const_reverse_iterator = InstructionList::const_reverse_iterator;
|
||||
|
||||
explicit Block(ObjectPool<Inst>& inst_pool_, u32 begin, u32 end);
|
||||
explicit Block(ObjectPool<Inst>& inst_pool_);
|
||||
~Block();
|
||||
|
||||
|
@ -44,22 +44,8 @@ public:
|
|||
iterator PrependNewInst(iterator insertion_point, Opcode op,
|
||||
std::initializer_list<Value> args = {}, u32 flags = 0);
|
||||
|
||||
/// Set the branches to jump to when all instructions have executed.
|
||||
void SetBranches(Condition cond, Block* branch_true, Block* branch_false);
|
||||
/// Set the branch to unconditionally jump to when all instructions have executed.
|
||||
void SetBranch(Block* branch);
|
||||
/// Mark the block as a return block.
|
||||
void SetReturn();
|
||||
|
||||
/// Returns true when the block does not implement any guest instructions directly.
|
||||
[[nodiscard]] bool IsVirtual() const noexcept;
|
||||
/// Gets the starting location of this basic block.
|
||||
[[nodiscard]] u32 LocationBegin() const noexcept;
|
||||
/// Gets the end location for this basic block.
|
||||
[[nodiscard]] u32 LocationEnd() const noexcept;
|
||||
|
||||
/// Adds a new immediate predecessor to this basic block.
|
||||
void AddImmediatePredecessor(Block* block);
|
||||
/// Adds a new branch to this basic block.
|
||||
void AddBranch(Block* block);
|
||||
|
||||
/// Gets a mutable reference to the instruction list for this basic block.
|
||||
[[nodiscard]] InstructionList& Instructions() noexcept {
|
||||
|
@ -71,9 +57,13 @@ public:
|
|||
}
|
||||
|
||||
/// Gets an immutable span to the immediate predecessors.
|
||||
[[nodiscard]] std::span<Block* const> ImmediatePredecessors() const noexcept {
|
||||
[[nodiscard]] std::span<Block* const> ImmPredecessors() const noexcept {
|
||||
return imm_predecessors;
|
||||
}
|
||||
/// Gets an immutable span to the immediate successors.
|
||||
[[nodiscard]] std::span<Block* const> ImmSuccessors() const noexcept {
|
||||
return imm_successors;
|
||||
}
|
||||
|
||||
/// Intrusively store the host definition of this instruction.
|
||||
template <typename DefinitionType>
|
||||
|
@ -87,19 +77,6 @@ public:
|
|||
return Common::BitCast<DefinitionType>(definition);
|
||||
}
|
||||
|
||||
[[nodiscard]] Condition BranchCondition() const noexcept {
|
||||
return branch_cond;
|
||||
}
|
||||
[[nodiscard]] bool IsTerminationBlock() const noexcept {
|
||||
return !branch_true && !branch_false;
|
||||
}
|
||||
[[nodiscard]] Block* TrueBranch() const noexcept {
|
||||
return branch_true;
|
||||
}
|
||||
[[nodiscard]] Block* FalseBranch() const noexcept {
|
||||
return branch_false;
|
||||
}
|
||||
|
||||
void SetSsaRegValue(IR::Reg reg, const Value& value) noexcept {
|
||||
ssa_reg_values[RegIndex(reg)] = value;
|
||||
}
|
||||
|
@ -178,22 +155,14 @@ public:
|
|||
private:
|
||||
/// Memory pool for instruction list
|
||||
ObjectPool<Inst>* inst_pool;
|
||||
/// Starting location of this block
|
||||
u32 location_begin;
|
||||
/// End location of this block
|
||||
u32 location_end;
|
||||
|
||||
/// List of instructions in this block
|
||||
InstructionList instructions;
|
||||
|
||||
/// Condition to choose the branch to take
|
||||
Condition branch_cond{true};
|
||||
/// Block to jump into when the branch condition evaluates as true
|
||||
Block* branch_true{nullptr};
|
||||
/// Block to jump into when the branch condition evaluates as false
|
||||
Block* branch_false{nullptr};
|
||||
/// Block immediate predecessors
|
||||
std::vector<Block*> imm_predecessors;
|
||||
/// Block immediate successors
|
||||
std::vector<Block*> imm_successors;
|
||||
|
||||
/// Intrusively store the value of a register in the block.
|
||||
std::array<Value, NUM_REGS> ssa_reg_values;
|
||||
|
|
|
@ -61,25 +61,28 @@ F64 IREmitter::Imm64(f64 value) const {
|
|||
return F64{Value{value}};
|
||||
}
|
||||
|
||||
void IREmitter::Branch(Block* label) {
|
||||
label->AddImmediatePredecessor(block);
|
||||
block->SetBranch(label);
|
||||
Inst(Opcode::Branch, label);
|
||||
void IREmitter::Prologue() {
|
||||
Inst(Opcode::Prologue);
|
||||
}
|
||||
|
||||
void IREmitter::BranchConditional(const U1& condition, Block* true_label, Block* false_label) {
|
||||
block->SetBranches(IR::Condition{true}, true_label, false_label);
|
||||
true_label->AddImmediatePredecessor(block);
|
||||
false_label->AddImmediatePredecessor(block);
|
||||
Inst(Opcode::BranchConditional, condition, true_label, false_label);
|
||||
void IREmitter::Epilogue() {
|
||||
Inst(Opcode::Epilogue);
|
||||
}
|
||||
|
||||
void IREmitter::LoopMerge(Block* merge_block, Block* continue_target) {
|
||||
Inst(Opcode::LoopMerge, merge_block, continue_target);
|
||||
void IREmitter::BranchConditionRef(const U1& cond) {
|
||||
Inst(Opcode::BranchConditionRef, cond);
|
||||
}
|
||||
|
||||
void IREmitter::SelectionMerge(Block* merge_block) {
|
||||
Inst(Opcode::SelectionMerge, merge_block);
|
||||
void IREmitter::DemoteToHelperInvocation() {
|
||||
Inst(Opcode::DemoteToHelperInvocation);
|
||||
}
|
||||
|
||||
void IREmitter::EmitVertex(const U32& stream) {
|
||||
Inst(Opcode::EmitVertex, stream);
|
||||
}
|
||||
|
||||
void IREmitter::EndPrimitive(const U32& stream) {
|
||||
Inst(Opcode::EndPrimitive, stream);
|
||||
}
|
||||
|
||||
void IREmitter::Barrier() {
|
||||
|
@ -94,37 +97,6 @@ void IREmitter::DeviceMemoryBarrier() {
|
|||
Inst(Opcode::DeviceMemoryBarrier);
|
||||
}
|
||||
|
||||
void IREmitter::Return() {
|
||||
block->SetReturn();
|
||||
Inst(Opcode::Return);
|
||||
}
|
||||
|
||||
void IREmitter::Unreachable() {
|
||||
Inst(Opcode::Unreachable);
|
||||
}
|
||||
|
||||
void IREmitter::DemoteToHelperInvocation(Block* continue_label) {
|
||||
block->SetBranch(continue_label);
|
||||
continue_label->AddImmediatePredecessor(block);
|
||||
Inst(Opcode::DemoteToHelperInvocation, continue_label);
|
||||
}
|
||||
|
||||
void IREmitter::Prologue() {
|
||||
Inst(Opcode::Prologue);
|
||||
}
|
||||
|
||||
void IREmitter::Epilogue() {
|
||||
Inst(Opcode::Epilogue);
|
||||
}
|
||||
|
||||
void IREmitter::EmitVertex(const U32& stream) {
|
||||
Inst(Opcode::EmitVertex, stream);
|
||||
}
|
||||
|
||||
void IREmitter::EndPrimitive(const U32& stream) {
|
||||
Inst(Opcode::EndPrimitive, stream);
|
||||
}
|
||||
|
||||
U32 IREmitter::GetReg(IR::Reg reg) {
|
||||
return Inst<U32>(Opcode::GetRegister, reg);
|
||||
}
|
||||
|
|
|
@ -32,17 +32,10 @@ public:
|
|||
[[nodiscard]] U64 Imm64(s64 value) const;
|
||||
[[nodiscard]] F64 Imm64(f64 value) const;
|
||||
|
||||
void Branch(Block* label);
|
||||
void BranchConditional(const U1& condition, Block* true_label, Block* false_label);
|
||||
void LoopMerge(Block* merge_block, Block* continue_target);
|
||||
void SelectionMerge(Block* merge_block);
|
||||
void Return();
|
||||
void Unreachable();
|
||||
void DemoteToHelperInvocation(Block* continue_label);
|
||||
|
||||
void Prologue();
|
||||
void Epilogue();
|
||||
|
||||
void BranchConditionRef(const U1& cond);
|
||||
void DemoteToHelperInvocation();
|
||||
void EmitVertex(const U32& stream);
|
||||
void EndPrimitive(const U32& stream);
|
||||
|
||||
|
|
|
@ -56,19 +56,14 @@ Inst::~Inst() {
|
|||
|
||||
bool Inst::MayHaveSideEffects() const noexcept {
|
||||
switch (op) {
|
||||
case Opcode::Branch:
|
||||
case Opcode::BranchConditional:
|
||||
case Opcode::LoopMerge:
|
||||
case Opcode::SelectionMerge:
|
||||
case Opcode::Return:
|
||||
case Opcode::Prologue:
|
||||
case Opcode::Epilogue:
|
||||
case Opcode::BranchConditionRef:
|
||||
case Opcode::Join:
|
||||
case Opcode::Unreachable:
|
||||
case Opcode::DemoteToHelperInvocation:
|
||||
case Opcode::Barrier:
|
||||
case Opcode::WorkgroupMemoryBarrier:
|
||||
case Opcode::DeviceMemoryBarrier:
|
||||
case Opcode::Prologue:
|
||||
case Opcode::Epilogue:
|
||||
case Opcode::EmitVertex:
|
||||
case Opcode::EndPrimitive:
|
||||
case Opcode::SetAttribute:
|
||||
|
|
|
@ -30,7 +30,6 @@ struct OpcodeMeta {
|
|||
// using enum Type;
|
||||
constexpr Type Void{Type::Void};
|
||||
constexpr Type Opaque{Type::Opaque};
|
||||
constexpr Type Label{Type::Label};
|
||||
constexpr Type Reg{Type::Reg};
|
||||
constexpr Type Pred{Type::Pred};
|
||||
constexpr Type Attribute{Type::Attribute};
|
||||
|
|
|
@ -7,27 +7,20 @@ OPCODE(Phi, Opaque,
|
|||
OPCODE(Identity, Opaque, Opaque, )
|
||||
OPCODE(Void, Void, )
|
||||
|
||||
// Control flow
|
||||
OPCODE(Branch, Void, Label, )
|
||||
OPCODE(BranchConditional, Void, U1, Label, Label, )
|
||||
OPCODE(LoopMerge, Void, Label, Label, )
|
||||
OPCODE(SelectionMerge, Void, Label, )
|
||||
OPCODE(Return, Void, )
|
||||
// Special operations
|
||||
OPCODE(Prologue, Void, )
|
||||
OPCODE(Epilogue, Void, )
|
||||
OPCODE(BranchConditionRef, Void, U1, )
|
||||
OPCODE(Join, Void, )
|
||||
OPCODE(Unreachable, Void, )
|
||||
OPCODE(DemoteToHelperInvocation, Void, Label, )
|
||||
OPCODE(DemoteToHelperInvocation, Void, )
|
||||
OPCODE(EmitVertex, Void, U32, )
|
||||
OPCODE(EndPrimitive, Void, U32, )
|
||||
|
||||
// Barriers
|
||||
OPCODE(Barrier, Void, )
|
||||
OPCODE(WorkgroupMemoryBarrier, Void, )
|
||||
OPCODE(DeviceMemoryBarrier, Void, )
|
||||
|
||||
// Special operations
|
||||
OPCODE(Prologue, Void, )
|
||||
OPCODE(Epilogue, Void, )
|
||||
OPCODE(EmitVertex, Void, U32, )
|
||||
OPCODE(EndPrimitive, Void, U32, )
|
||||
|
||||
// Context getters/setters
|
||||
OPCODE(GetRegister, U32, Reg, )
|
||||
OPCODE(SetRegister, Void, Reg, U32, )
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
|
@ -10,35 +12,31 @@
|
|||
|
||||
namespace Shader::IR {
|
||||
|
||||
BlockList PostOrder(const BlockList& blocks) {
|
||||
BlockList PostOrder(const AbstractSyntaxNode& root) {
|
||||
boost::container::small_vector<Block*, 16> block_stack;
|
||||
boost::container::flat_set<Block*> visited;
|
||||
|
||||
BlockList post_order_blocks;
|
||||
post_order_blocks.reserve(blocks.size());
|
||||
|
||||
Block* const first_block{blocks.front()};
|
||||
if (root.type != AbstractSyntaxNode::Type::Block) {
|
||||
throw LogicError("First node in abstract syntax list root is not a block");
|
||||
}
|
||||
Block* const first_block{root.block};
|
||||
visited.insert(first_block);
|
||||
block_stack.push_back(first_block);
|
||||
|
||||
const auto visit_branch = [&](Block* block, Block* branch) {
|
||||
if (!branch) {
|
||||
return false;
|
||||
}
|
||||
if (!visited.insert(branch).second) {
|
||||
return false;
|
||||
}
|
||||
// Calling push_back twice is faster than insert on MSVC
|
||||
block_stack.push_back(block);
|
||||
block_stack.push_back(branch);
|
||||
return true;
|
||||
};
|
||||
while (!block_stack.empty()) {
|
||||
Block* const block{block_stack.back()};
|
||||
const auto visit{[&](Block* branch) {
|
||||
if (!visited.insert(branch).second) {
|
||||
return false;
|
||||
}
|
||||
// Calling push_back twice is faster than insert on MSVC
|
||||
block_stack.push_back(block);
|
||||
block_stack.push_back(branch);
|
||||
return true;
|
||||
}};
|
||||
block_stack.pop_back();
|
||||
|
||||
if (!visit_branch(block, block->TrueBranch()) &&
|
||||
!visit_branch(block, block->FalseBranch())) {
|
||||
if (std::ranges::none_of(block->ImmSuccessors(), visit)) {
|
||||
post_order_blocks.push_back(block);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||
#include "shader_recompiler/frontend/ir/abstract_syntax_list.h"
|
||||
|
||||
namespace Shader::IR {
|
||||
|
||||
BlockList PostOrder(const BlockList& blocks);
|
||||
BlockList PostOrder(const AbstractSyntaxNode& root);
|
||||
|
||||
} // namespace Shader::IR
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#include "shader_recompiler/frontend/ir/abstract_syntax_list.h"
|
||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||
#include "shader_recompiler/program_header.h"
|
||||
#include "shader_recompiler/shader_info.h"
|
||||
|
@ -17,6 +16,7 @@
|
|||
namespace Shader::IR {
|
||||
|
||||
struct Program {
|
||||
AbstractSyntaxList syntax_list;
|
||||
BlockList blocks;
|
||||
BlockList post_order_blocks;
|
||||
Info info;
|
||||
|
|
|
@ -16,31 +16,30 @@ namespace Shader::IR {
|
|||
enum class Type {
|
||||
Void = 0,
|
||||
Opaque = 1 << 0,
|
||||
Label = 1 << 1,
|
||||
Reg = 1 << 2,
|
||||
Pred = 1 << 3,
|
||||
Attribute = 1 << 4,
|
||||
Patch = 1 << 5,
|
||||
U1 = 1 << 6,
|
||||
U8 = 1 << 7,
|
||||
U16 = 1 << 8,
|
||||
U32 = 1 << 9,
|
||||
U64 = 1 << 10,
|
||||
F16 = 1 << 11,
|
||||
F32 = 1 << 12,
|
||||
F64 = 1 << 13,
|
||||
U32x2 = 1 << 14,
|
||||
U32x3 = 1 << 15,
|
||||
U32x4 = 1 << 16,
|
||||
F16x2 = 1 << 17,
|
||||
F16x3 = 1 << 18,
|
||||
F16x4 = 1 << 19,
|
||||
F32x2 = 1 << 20,
|
||||
F32x3 = 1 << 21,
|
||||
F32x4 = 1 << 22,
|
||||
F64x2 = 1 << 23,
|
||||
F64x3 = 1 << 24,
|
||||
F64x4 = 1 << 25,
|
||||
Reg = 1 << 1,
|
||||
Pred = 1 << 2,
|
||||
Attribute = 1 << 3,
|
||||
Patch = 1 << 4,
|
||||
U1 = 1 << 5,
|
||||
U8 = 1 << 6,
|
||||
U16 = 1 << 7,
|
||||
U32 = 1 << 8,
|
||||
U64 = 1 << 9,
|
||||
F16 = 1 << 10,
|
||||
F32 = 1 << 11,
|
||||
F64 = 1 << 12,
|
||||
U32x2 = 1 << 13,
|
||||
U32x3 = 1 << 14,
|
||||
U32x4 = 1 << 15,
|
||||
F16x2 = 1 << 16,
|
||||
F16x3 = 1 << 17,
|
||||
F16x4 = 1 << 18,
|
||||
F32x2 = 1 << 19,
|
||||
F32x3 = 1 << 20,
|
||||
F32x4 = 1 << 21,
|
||||
F64x2 = 1 << 22,
|
||||
F64x3 = 1 << 23,
|
||||
F64x4 = 1 << 24,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(Type)
|
||||
|
||||
|
|
|
@ -9,8 +9,6 @@ namespace Shader::IR {
|
|||
|
||||
Value::Value(IR::Inst* value) noexcept : type{Type::Opaque}, inst{value} {}
|
||||
|
||||
Value::Value(IR::Block* value) noexcept : type{Type::Label}, label{value} {}
|
||||
|
||||
Value::Value(IR::Reg value) noexcept : type{Type::Reg}, reg{value} {}
|
||||
|
||||
Value::Value(IR::Pred value) noexcept : type{Type::Pred}, pred{value} {}
|
||||
|
@ -33,10 +31,6 @@ Value::Value(u64 value) noexcept : type{Type::U64}, imm_u64{value} {}
|
|||
|
||||
Value::Value(f64 value) noexcept : type{Type::F64}, imm_f64{value} {}
|
||||
|
||||
bool Value::IsLabel() const noexcept {
|
||||
return type == Type::Label;
|
||||
}
|
||||
|
||||
IR::Type Value::Type() const noexcept {
|
||||
if (IsPhi()) {
|
||||
// The type of a phi node is stored in its flags
|
||||
|
@ -60,8 +54,6 @@ bool Value::operator==(const Value& other) const {
|
|||
return true;
|
||||
case Type::Opaque:
|
||||
return inst == other.inst;
|
||||
case Type::Label:
|
||||
return label == other.label;
|
||||
case Type::Reg:
|
||||
return reg == other.reg;
|
||||
case Type::Pred:
|
||||
|
|
|
@ -37,7 +37,6 @@ class Value {
|
|||
public:
|
||||
Value() noexcept = default;
|
||||
explicit Value(IR::Inst* value) noexcept;
|
||||
explicit Value(IR::Block* value) noexcept;
|
||||
explicit Value(IR::Reg value) noexcept;
|
||||
explicit Value(IR::Pred value) noexcept;
|
||||
explicit Value(IR::Attribute value) noexcept;
|
||||
|
@ -54,11 +53,9 @@ public:
|
|||
[[nodiscard]] bool IsPhi() const noexcept;
|
||||
[[nodiscard]] bool IsEmpty() const noexcept;
|
||||
[[nodiscard]] bool IsImmediate() const noexcept;
|
||||
[[nodiscard]] bool IsLabel() const noexcept;
|
||||
[[nodiscard]] IR::Type Type() const noexcept;
|
||||
|
||||
[[nodiscard]] IR::Inst* Inst() const;
|
||||
[[nodiscard]] IR::Block* Label() const;
|
||||
[[nodiscard]] IR::Inst* InstRecursive() const;
|
||||
[[nodiscard]] IR::Value Resolve() const;
|
||||
[[nodiscard]] IR::Reg Reg() const;
|
||||
|
@ -80,7 +77,6 @@ private:
|
|||
IR::Type type{};
|
||||
union {
|
||||
IR::Inst* inst{};
|
||||
IR::Block* label;
|
||||
IR::Reg reg;
|
||||
IR::Pred pred;
|
||||
IR::Attribute attribute;
|
||||
|
@ -304,11 +300,6 @@ inline IR::Inst* Value::Inst() const {
|
|||
return inst;
|
||||
}
|
||||
|
||||
inline IR::Block* Value::Label() const {
|
||||
DEBUG_ASSERT(type == Type::Label);
|
||||
return label;
|
||||
}
|
||||
|
||||
inline IR::Inst* Value::InstRecursive() const {
|
||||
DEBUG_ASSERT(type == Type::Opaque);
|
||||
if (IsIdentity()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue