code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

#include <sirit/sirit.h>

#include "shader_recompiler/backend/bindings.h"
#include "shader_recompiler/frontend/ir/program.h"
#include "shader_recompiler/profile.h"
#include "shader_recompiler/runtime_info.h"
#include "shader_recompiler/shader_info.h"

namespace Shader::Backend::SPIRV {

using Sirit::Id;

class VectorTypes {
public:
    void Define(Sirit::Module& sirit_ctx, Id base_type, std::string_view name);

    [[nodiscard]] Id operator[](size_t size) const noexcept {
        return defs[size - 1];
    }

private:
    std::array<Id, 4> defs{};
};

struct TextureDefinition {
    Id id;
    Id sampled_type;
    Id pointer_type;
    Id image_type;
    u32 count;
    bool is_multisample;
};

struct TextureBufferDefinition {
    Id id;
    u32 count;
};

struct ImageBufferDefinition {
    Id id;
    Id image_type;
    u32 count;
    bool is_integer;
};

struct ImageDefinition {
    Id id;
    Id image_type;
    u32 count;
    bool is_integer;
};

struct UniformDefinitions {
    Id U8{};
    Id S8{};
    Id U16{};
    Id S16{};
    Id U32{};
    Id F32{};
    Id U32x2{};
    Id U32x4{};

    constexpr static size_t NumElements(Id UniformDefinitions::*member_ptr) {
        if (member_ptr == &UniformDefinitions::U8) {
            return 1;
        }
        if (member_ptr == &UniformDefinitions::S8) {
            return 1;
        }
        if (member_ptr == &UniformDefinitions::U16) {
            return 1;
        }
        if (member_ptr == &UniformDefinitions::S16) {
            return 1;
        }
        if (member_ptr == &UniformDefinitions::U32) {
            return 1;
        }
        if (member_ptr == &UniformDefinitions::F32) {
            return 1;
        }
        if (member_ptr == &UniformDefinitions::U32x2) {
            return 2;
        }
        if (member_ptr == &UniformDefinitions::U32x4) {
            return 4;
        }
        ASSERT(false);
        return 1;
    }

    constexpr static bool IsFloat(Id UniformDefinitions::*member_ptr) {
        if (member_ptr == &UniformDefinitions::F32) {
            return true;
        }
        return false;
    }
};

struct StorageTypeDefinition {
    Id array{};
    Id element{};
};

struct StorageTypeDefinitions {
    StorageTypeDefinition U8{};
    StorageTypeDefinition S8{};
    StorageTypeDefinition U16{};
    StorageTypeDefinition S16{};
    StorageTypeDefinition U32{};
    StorageTypeDefinition U64{};
    StorageTypeDefinition F32{};
    StorageTypeDefinition U32x2{};
    StorageTypeDefinition U32x4{};
};

struct StorageDefinitions {
    Id U8{};
    Id S8{};
    Id U16{};
    Id S16{};
    Id U32{};
    Id F32{};
    Id U64{};
    Id U32x2{};
    Id U32x4{};
};

enum class InputGenericLoadOp {
    None,
    Bitcast,
    SToF,
    UToF,
};

struct InputGenericInfo {
    Id id;
    Id pointer_type;
    Id component_type;
    InputGenericLoadOp load_op;
};

struct GenericElementInfo {
    Id id{};
    u32 first_element{};
    u32 num_components{};
};

class EmitContext final : public Sirit::Module {
public:
    explicit EmitContext(const Profile& profile, const RuntimeInfo& runtime_info,
                         IR::Program& program, Bindings& binding);
    ~EmitContext();

    [[nodiscard]] Id Def(const IR::Value& value);

    [[nodiscard]] Id BitOffset8(const IR::Value& offset);
    [[nodiscard]] Id BitOffset16(const IR::Value& offset);

    Id Const(u32 value) {
        return Constant(U32[1], value);
    }

    Id Const(u32 element_1, u32 element_2) {
        return ConstantComposite(U32[2], Const(element_1), Const(element_2));
    }

    Id Const(u32 element_1, u32 element_2, u32 element_3) {
        return ConstantComposite(U32[3], Const(element_1), Const(element_2), Const(element_3));
    }

    Id Const(u32 element_1, u32 element_2, u32 element_3, u32 element_4) {
        return ConstantComposite(U32[4], Const(element_1), Const(element_2), Const(element_3),
                                 Const(element_4));
    }

    Id SConst(s32 value) {
        return Constant(S32[1], value);
    }

    Id SConst(s32 element_1, s32 element_2) {
        return ConstantComposite(S32[2], SConst(element_1), SConst(element_2));
    }

    Id SConst(s32 element_1, s32 element_2, s32 element_3) {
        return ConstantComposite(S32[3], SConst(element_1), SConst(element_2), SConst(element_3));
    }

    Id SConst(s32 element_1, s32 element_2, s32 element_3, s32 element_4) {
        return ConstantComposite(S32[4], SConst(element_1), SConst(element_2), SConst(element_3),
                                 SConst(element_4));
    }

    Id Const(f32 value) {
        return Constant(F32[1], value);
    }

    const Profile& profile;
    const RuntimeInfo& runtime_info;
    Stage stage{};

    Id void_id{};
    Id U1{};
    Id U8{};
    Id S8{};
    Id U16{};
    Id S16{};
    Id U64{};
    VectorTypes F32;
    VectorTypes U32;
    VectorTypes S32;
    VectorTypes F16;
    VectorTypes F64;

    Id true_value{};
    Id false_value{};
    Id u32_zero_value{};
    Id f32_zero_value{};

    UniformDefinitions uniform_types;
    StorageTypeDefinitions storage_types;

    Id private_u32{};

    Id shared_u8{};
    Id shared_u16{};
    Id shared_u32{};
    Id shared_u64{};
    Id shared_u32x2{};
    Id shared_u32x4{};

    Id input_f32{};
    Id input_u32{};
    Id input_s32{};

    Id output_f32{};
    Id output_u32{};

    Id image_buffer_type{};
    Id image_u32{};

    std::array<UniformDefinitions, Info::MAX_CBUFS> cbufs{};
    std::array<StorageDefinitions, Info::MAX_SSBOS> ssbos{};
    std::vector<TextureBufferDefinition> texture_buffers;
    std::vector<ImageBufferDefinition> image_buffers;
    std::vector<TextureDefinition> textures;
    std::vector<ImageDefinition> images;

    Id workgroup_id{};
    Id local_invocation_id{};
    Id invocation_id{};
    Id patch_vertices_in{};
    Id sample_id{};
    Id is_helper_invocation{};
    Id subgroup_local_invocation_id{};
    Id subgroup_mask_eq{};
    Id subgroup_mask_lt{};
    Id subgroup_mask_le{};
    Id subgroup_mask_gt{};
    Id subgroup_mask_ge{};
    Id instance_id{};
    Id instance_index{};
    Id base_instance{};
    Id vertex_id{};
    Id vertex_index{};
    Id draw_index{};
    Id base_vertex{};
    Id front_face{};
    Id point_coord{};
    Id tess_coord{};
    Id clip_distances{};
    Id layer{};
    Id viewport_index{};
    Id viewport_mask{};
    Id primitive_id{};

    Id fswzadd_lut_a{};
    Id fswzadd_lut_b{};

    Id indexed_load_func{};
    Id indexed_store_func{};

    Id rescaling_uniform_constant{};
    Id rescaling_push_constants{};
    Id rescaling_textures_type{};
    Id rescaling_images_type{};
    u32 rescaling_textures_member_index{};
    u32 rescaling_images_member_index{};
    u32 rescaling_downfactor_member_index{};
    u32 texture_rescaling_index{};
    u32 image_rescaling_index{};

    Id render_area_push_constant{};
    u32 render_are_member_index{};

    Id local_memory{};

    Id shared_memory_u8{};
    Id shared_memory_u16{};
    Id shared_memory_u32{};
    Id shared_memory_u64{};
    Id shared_memory_u32x2{};
    Id shared_memory_u32x4{};

    Id shared_memory_u32_type{};

    Id shared_store_u8_func{};
    Id shared_store_u16_func{};
    Id increment_cas_shared{};
    Id increment_cas_ssbo{};
    Id decrement_cas_shared{};
    Id decrement_cas_ssbo{};
    Id f32_add_cas{};
    Id f16x2_add_cas{};
    Id f16x2_min_cas{};
    Id f16x2_max_cas{};
    Id f32x2_add_cas{};
    Id f32x2_min_cas{};
    Id f32x2_max_cas{};

    Id write_storage_cas_loop_func{};

    Id load_global_func_u32{};
    Id load_global_func_u32x2{};
    Id load_global_func_u32x4{};
    Id write_global_func_u32{};
    Id write_global_func_u32x2{};
    Id write_global_func_u32x4{};

    bool need_input_position_indirect{};
    Id input_position{};
    std::array<InputGenericInfo, 32> input_generics{};

    Id output_point_size{};
    Id output_position{};
    std::array<std::array<GenericElementInfo, 4>, 32> output_generics{};

    Id output_tess_level_outer{};
    Id output_tess_level_inner{};
    std::array<Id, 30> patches{};

    std::array<Id, 8> frag_color{};
    Id sample_mask{};
    Id frag_depth{};

    std::vector<Id> interfaces;

    Id load_const_func_u8{};
    Id load_const_func_u16{};
    Id load_const_func_u32{};
    Id load_const_func_f32{};
    Id load_const_func_u32x2{};
    Id load_const_func_u32x4{};

private:
    void DefineCommonTypes(const Info& info);
    void DefineCommonConstants();
    void DefineInterfaces(const IR::Program& program);
    void DefineLocalMemory(const IR::Program& program);
    void DefineSharedMemory(const IR::Program& program);
    void DefineSharedMemoryFunctions(const IR::Program& program);
    void DefineConstantBuffers(const Info& info, u32& binding);
    void DefineConstantBufferIndirectFunctions(const Info& info);
    void DefineStorageBuffers(const Info& info, u32& binding);
    void DefineTextureBuffers(const Info& info, u32& binding);
    void DefineImageBuffers(const Info& info, u32& binding);
    void DefineTextures(const Info& info, u32& binding, u32& scaling_index);
    void DefineImages(const Info& info, u32& binding, u32& scaling_index);
    void DefineAttributeMemAccess(const Info& info);
    void DefineWriteStorageCasLoopFunction(const Info& info);
    void DefineGlobalMemoryFunctions(const Info& info);
    void DefineRescalingInput(const Info& info);
    void DefineRescalingInputPushConstant();
    void DefineRescalingInputUniformConstant();
    void DefineRenderArea(const Info& info);

    void DefineInputs(const IR::Program& program);
    void DefineOutputs(const IR::Program& program);
};

} // namespace Shader::Backend::SPIRV


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

#include "common/common_types.h"
#include "shader_recompiler/program_header.h"
#include "shader_recompiler/shader_info.h"
#include "shader_recompiler/stage.h"

namespace Shader {

class Environment {
public:
    virtual ~Environment() = default;

    [[nodiscard]] virtual u64 ReadInstruction(u32 address) = 0;

    [[nodiscard]] virtual u32 ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) = 0;

    [[nodiscard]] virtual TextureType ReadTextureType(u32 raw_handle) = 0;

    [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0;

    [[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0;

    [[nodiscard]] virtual u32 ReadViewportTransformState() = 0;

    [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0;

    [[nodiscard]] virtual u32 LocalMemorySize() const = 0;

    [[nodiscard]] virtual u32 SharedMemorySize() const = 0;

    [[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() const = 0;

    [[nodiscard]] virtual bool HasHLEMacroState() const = 0;

    [[nodiscard]] virtual std::optional<ReplaceConstant> GetReplaceConstBuffer(u32 bank,
                                                                               u32 offset) = 0;

    virtual void Dump(u64 pipeline_hash, u64 shader_hash) = 0;

    [[nodiscard]] const ProgramHeader& SPH() const noexcept {
        return sph;
    }

    [[nodiscard]] const std::array<u32, 8>& GpPassthroughMask() const noexcept {
        return gp_passthrough_mask;
    }

    [[nodiscard]] Stage ShaderStage() const noexcept {
        return stage;
    }

    [[nodiscard]] u32 StartAddress() const noexcept {
        return start_address;
    }

    [[nodiscard]] bool IsProprietaryDriver() const noexcept {
        return is_proprietary_driver;
    }

protected:
    ProgramHeader sph{};
    std::array<u32, 8> gp_passthrough_mask{};
    Stage stage{};
    u32 start_address{};
    bool is_proprietary_driver{};
};

} // namespace Shader

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <exception>
#include <string>
#include <utility>

#include "common/logging/formatter.h"

namespace Shader {

class Exception : public std::exception {
public:
    explicit Exception(std::string message) noexcept : err_message{std::move(message)} {}

    [[nodiscard]] const char* what() const noexcept override {
        return err_message.c_str();
    }

    void Prepend(std::string_view prepend) {
        err_message.insert(0, prepend);
    }

    void Append(std::string_view append) {
        err_message += append;
    }

private:
    std::string err_message;
};

class LogicError : public Exception {
public:
    template <typename... Args>
    explicit LogicError(const char* message, Args&&... args)
        : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
};

class RuntimeError : public Exception {
public:
    template <typename... Args>
    explicit RuntimeError(const char* message, Args&&... args)
        : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
};

class NotImplementedException : public Exception {
public:
    template <typename... Args>
    explicit NotImplementedException(const char* message, Args&&... args)
        : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {
        Append(" is not implemented");
    }
};

class InvalidArgument : public Exception {
public:
    template <typename... Args>
    explicit InvalidArgument(const char* message, Args&&... args)
        : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
};

} // namespace Shader


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#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,
    };
    union Data {
        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;
    };

    Data data{};
    Type type{};
};
using AbstractSyntaxList = std::vector<AbstractSyntaxNode>;

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <fmt/format.h>

#include "shader_recompiler/exception.h"
#include "shader_recompiler/frontend/ir/attribute.h"

namespace Shader::IR {

bool IsGeneric(Attribute attribute) noexcept {
    return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
}

u32 GenericAttributeIndex(Attribute attribute) {
    if (!IsGeneric(attribute)) {
        throw InvalidArgument("Attribute is not generic {}", attribute);
    }
    return (static_cast<u32>(attribute) - static_cast<u32>(Attribute::Generic0X)) / 4u;
}

u32 GenericAttributeElement(Attribute attribute) {
    if (!IsGeneric(attribute)) {
        throw InvalidArgument("Attribute is not generic {}", attribute);
    }
    return static_cast<u32>(attribute) % 4;
}

std::string NameOf(Attribute attribute) {
    switch (attribute) {
    case Attribute::PrimitiveId:
        return "PrimitiveId";
    case Attribute::Layer:
        return "Layer";
    case Attribute::ViewportIndex:
        return "ViewportIndex";
    case Attribute::PointSize:
        return "PointSize";
    case Attribute::PositionX:
        return "Position.X";
    case Attribute::PositionY:
        return "Position.Y";
    case Attribute::PositionZ:
        return "Position.Z";
    case Attribute::PositionW:
        return "Position.W";
    case Attribute::Generic0X:
        return "Generic[0].X";
    case Attribute::Generic0Y:
        return "Generic[0].Y";
    case Attribute::Generic0Z:
        return "Generic[0].Z";
    case Attribute::Generic0W:
        return "Generic[0].W";
    case Attribute::Generic1X:
        return "Generic[1].X";
    case Attribute::Generic1Y:
        return "Generic[1].Y";
    case Attribute::Generic1Z:
        return "Generic[1].Z";
    case Attribute::Generic1W:
        return "Generic[1].W";
    case Attribute::Generic2X:
        return "Generic[2].X";
    case Attribute::Generic2Y:
        return "Generic[2].Y";
    case Attribute::Generic2Z:
        return "Generic[2].Z";
    case Attribute::Generic2W:
        return "Generic[2].W";
    case Attribute::Generic3X:
        return "Generic[3].X";
    case Attribute::Generic3Y:
        return "Generic[3].Y";
    case Attribute::Generic3Z:
        return "Generic[3].Z";
    case Attribute::Generic3W:
        return "Generic[3].W";
    case Attribute::Generic4X:
        return "Generic[4].X";
    case Attribute::Generic4Y:
        return "Generic[4].Y";
    case Attribute::Generic4Z:
        return "Generic[4].Z";
    case Attribute::Generic4W:
        return "Generic[4].W";
    case Attribute::Generic5X:
        return "Generic[5].X";
    case Attribute::Generic5Y:
        return "Generic[5].Y";
    case Attribute::Generic5Z:
        return "Generic[5].Z";
    case Attribute::Generic5W:
        return "Generic[5].W";
    case Attribute::Generic6X:
        return "Generic[6].X";
    case Attribute::Generic6Y:
        return "Generic[6].Y";
    case Attribute::Generic6Z:
        return "Generic[6].Z";
    case Attribute::Generic6W:
        return "Generic[6].W";
    case Attribute::Generic7X:
        return "Generic[7].X";
    case Attribute::Generic7Y:
        return "Generic[7].Y";
    case Attribute::Generic7Z:
        return "Generic[7].Z";
    case Attribute::Generic7W:
        return "Generic[7].W";
    case Attribute::Generic8X:
        return "Generic[8].X";
    case Attribute::Generic8Y:
        return "Generic[8].Y";
    case Attribute::Generic8Z:
        return "Generic[8].Z";
    case Attribute::Generic8W:
        return "Generic[8].W";
    case Attribute::Generic9X:
        return "Generic[9].X";
    case Attribute::Generic9Y:
        return "Generic[9].Y";
    case Attribute::Generic9Z:
        return "Generic[9].Z";
    case Attribute::Generic9W:
        return "Generic[9].W";
    case Attribute::Generic10X:
        return "Generic[10].X";
    case Attribute::Generic10Y:
        return "Generic[10].Y";
    case Attribute::Generic10Z:
        return "Generic[10].Z";
    case Attribute::Generic10W:
        return "Generic[10].W";
    case Attribute::Generic11X:
        return "Generic[11].X";
    case Attribute::Generic11Y:
        return "Generic[11].Y";
    case Attribute::Generic11Z:
        return "Generic[11].Z";
    case Attribute::Generic11W:
        return "Generic[11].W";
    case Attribute::Generic12X:
        return "Generic[12].X";
    case Attribute::Generic12Y:
        return "Generic[12].Y";
    case Attribute::Generic12Z:
        return "Generic[12].Z";
    case Attribute::Generic12W:
        return "Generic[12].W";
    case Attribute::Generic13X:
        return "Generic[13].X";
    case Attribute::Generic13Y:
        return "Generic[13].Y";
    case Attribute::Generic13Z:
        return "Generic[13].Z";
    case Attribute::Generic13W:
        return "Generic[13].W";
    case Attribute::Generic14X:
        return "Generic[14].X";
    case Attribute::Generic14Y:
        return "Generic[14].Y";
    case Attribute::Generic14Z:
        return "Generic[14].Z";
    case Attribute::Generic14W:
        return "Generic[14].W";
    case Attribute::Generic15X:
        return "Generic[15].X";
    case Attribute::Generic15Y:
        return "Generic[15].Y";
    case Attribute::Generic15Z:
        return "Generic[15].Z";
    case Attribute::Generic15W:
        return "Generic[15].W";
    case Attribute::Generic16X:
        return "Generic[16].X";
    case Attribute::Generic16Y:
        return "Generic[16].Y";
    case Attribute::Generic16Z:
        return "Generic[16].Z";
    case Attribute::Generic16W:
        return "Generic[16].W";
    case Attribute::Generic17X:
        return "Generic[17].X";
    case Attribute::Generic17Y:
        return "Generic[17].Y";
    case Attribute::Generic17Z:
        return "Generic[17].Z";
    case Attribute::Generic17W:
        return "Generic[17].W";
    case Attribute::Generic18X:
        return "Generic[18].X";
    case Attribute::Generic18Y:
        return "Generic[18].Y";
    case Attribute::Generic18Z:
        return "Generic[18].Z";
    case Attribute::Generic18W:
        return "Generic[18].W";
    case Attribute::Generic19X:
        return "Generic[19].X";
    case Attribute::Generic19Y:
        return "Generic[19].Y";
    case Attribute::Generic19Z:
        return "Generic[19].Z";
    case Attribute::Generic19W:
        return "Generic[19].W";
    case Attribute::Generic20X:
        return "Generic[20].X";
    case Attribute::Generic20Y:
        return "Generic[20].Y";
    case Attribute::Generic20Z:
        return "Generic[20].Z";
    case Attribute::Generic20W:
        return "Generic[20].W";
    case Attribute::Generic21X:
        return "Generic[21].X";
    case Attribute::Generic21Y:
        return "Generic[21].Y";
    case Attribute::Generic21Z:
        return "Generic[21].Z";
    case Attribute::Generic21W:
        return "Generic[21].W";
    case Attribute::Generic22X:
        return "Generic[22].X";
    case Attribute::Generic22Y:
        return "Generic[22].Y";
    case Attribute::Generic22Z:
        return "Generic[22].Z";
    case Attribute::Generic22W:
        return "Generic[22].W";
    case Attribute::Generic23X:
        return "Generic[23].X";
    case Attribute::Generic23Y:
        return "Generic[23].Y";
    case Attribute::Generic23Z:
        return "Generic[23].Z";
    case Attribute::Generic23W:
        return "Generic[23].W";
    case Attribute::Generic24X:
        return "Generic[24].X";
    case Attribute::Generic24Y:
        return "Generic[24].Y";
    case Attribute::Generic24Z:
        return "Generic[24].Z";
    case Attribute::Generic24W:
        return "Generic[24].W";
    case Attribute::Generic25X:
        return "Generic[25].X";
    case Attribute::Generic25Y:
        return "Generic[25].Y";
    case Attribute::Generic25Z:
        return "Generic[25].Z";
    case Attribute::Generic25W:
        return "Generic[25].W";
    case Attribute::Generic26X:
        return "Generic[26].X";
    case Attribute::Generic26Y:
        return "Generic[26].Y";
    case Attribute::Generic26Z:
        return "Generic[26].Z";
    case Attribute::Generic26W:
        return "Generic[26].W";
    case Attribute::Generic27X:
        return "Generic[27].X";
    case Attribute::Generic27Y:
        return "Generic[27].Y";
    case Attribute::Generic27Z:
        return "Generic[27].Z";
    case Attribute::Generic27W:
        return "Generic[27].W";
    case Attribute::Generic28X:
        return "Generic[28].X";
    case Attribute::Generic28Y:
        return "Generic[28].Y";
    case Attribute::Generic28Z:
        return "Generic[28].Z";
    case Attribute::Generic28W:
        return "Generic[28].W";
    case Attribute::Generic29X:
        return "Generic[29].X";
    case Attribute::Generic29Y:
        return "Generic[29].Y";
    case Attribute::Generic29Z:
        return "Generic[29].Z";
    case Attribute::Generic29W:
        return "Generic[29].W";
    case Attribute::Generic30X:
        return "Generic[30].X";
    case Attribute::Generic30Y:
        return "Generic[30].Y";
    case Attribute::Generic30Z:
        return "Generic[30].Z";
    case Attribute::Generic30W:
        return "Generic[30].W";
    case Attribute::Generic31X:
        return "Generic[31].X";
    case Attribute::Generic31Y:
        return "Generic[31].Y";
    case Attribute::Generic31Z:
        return "Generic[31].Z";
    case Attribute::Generic31W:
        return "Generic[31].W";
    case Attribute::ColorFrontDiffuseR:
        return "ColorFrontDiffuse.R";
    case Attribute::ColorFrontDiffuseG:
        return "ColorFrontDiffuse.G";
    case Attribute::ColorFrontDiffuseB:
        return "ColorFrontDiffuse.B";
    case Attribute::ColorFrontDiffuseA:
        return "ColorFrontDiffuse.A";
    case Attribute::ColorFrontSpecularR:
        return "ColorFrontSpecular.R";
    case Attribute::ColorFrontSpecularG:
        return "ColorFrontSpecular.G";
    case Attribute::ColorFrontSpecularB:
        return "ColorFrontSpecular.B";
    case Attribute::ColorFrontSpecularA:
        return "ColorFrontSpecular.A";
    case Attribute::ColorBackDiffuseR:
        return "ColorBackDiffuse.R";
    case Attribute::ColorBackDiffuseG:
        return "ColorBackDiffuse.G";
    case Attribute::ColorBackDiffuseB:
        return "ColorBackDiffuse.B";
    case Attribute::ColorBackDiffuseA:
        return "ColorBackDiffuse.A";
    case Attribute::ColorBackSpecularR:
        return "ColorBackSpecular.R";
    case Attribute::ColorBackSpecularG:
        return "ColorBackSpecular.G";
    case Attribute::ColorBackSpecularB:
        return "ColorBackSpecular.B";
    case Attribute::ColorBackSpecularA:
        return "ColorBackSpecular.A";
    case Attribute::ClipDistance0:
        return "ClipDistance[0]";
    case Attribute::ClipDistance1:
        return "ClipDistance[1]";
    case Attribute::ClipDistance2:
        return "ClipDistance[2]";
    case Attribute::ClipDistance3:
        return "ClipDistance[3]";
    case Attribute::ClipDistance4:
        return "ClipDistance[4]";
    case Attribute::ClipDistance5:
        return "ClipDistance[5]";
    case Attribute::ClipDistance6:
        return "ClipDistance[6]";
    case Attribute::ClipDistance7:
        return "ClipDistance[7]";
    case Attribute::PointSpriteS:
        return "PointSprite.S";
    case Attribute::PointSpriteT:
        return "PointSprite.T";
    case Attribute::FogCoordinate:
        return "FogCoordinate";
    case Attribute::TessellationEvaluationPointU:
        return "TessellationEvaluationPoint.U";
    case Attribute::TessellationEvaluationPointV:
        return "TessellationEvaluationPoint.V";
    case Attribute::InstanceId:
        return "InstanceId";
    case Attribute::VertexId:
        return "VertexId";
    case Attribute::FixedFncTexture0S:
        return "FixedFncTexture[0].S";
    case Attribute::FixedFncTexture0T:
        return "FixedFncTexture[0].T";
    case Attribute::FixedFncTexture0R:
        return "FixedFncTexture[0].R";
    case Attribute::FixedFncTexture0Q:
        return "FixedFncTexture[0].Q";
    case Attribute::FixedFncTexture1S:
        return "FixedFncTexture[1].S";
    case Attribute::FixedFncTexture1T:
        return "FixedFncTexture[1].T";
    case Attribute::FixedFncTexture1R:
        return "FixedFncTexture[1].R";
    case Attribute::FixedFncTexture1Q:
        return "FixedFncTexture[1].Q";
    case Attribute::FixedFncTexture2S:
        return "FixedFncTexture[2].S";
    case Attribute::FixedFncTexture2T:
        return "FixedFncTexture[2].T";
    case Attribute::FixedFncTexture2R:
        return "FixedFncTexture[2].R";
    case Attribute::FixedFncTexture2Q:
        return "FixedFncTexture[2].Q";
    case Attribute::FixedFncTexture3S:
        return "FixedFncTexture[3].S";
    case Attribute::FixedFncTexture3T:
        return "FixedFncTexture[3].T";
    case Attribute::FixedFncTexture3R:
        return "FixedFncTexture[3].R";
    case Attribute::FixedFncTexture3Q:
        return "FixedFncTexture[3].Q";
    case Attribute::FixedFncTexture4S:
        return "FixedFncTexture[4].S";
    case Attribute::FixedFncTexture4T:
        return "FixedFncTexture[4].T";
    case Attribute::FixedFncTexture4R:
        return "FixedFncTexture[4].R";
    case Attribute::FixedFncTexture4Q:
        return "FixedFncTexture[4].Q";
    case Attribute::FixedFncTexture5S:
        return "FixedFncTexture[5].S";
    case Attribute::FixedFncTexture5T:
        return "FixedFncTexture[5].T";
    case Attribute::FixedFncTexture5R:
        return "FixedFncTexture[5].R";
    case Attribute::FixedFncTexture5Q:
        return "FixedFncTexture[5].Q";
    case Attribute::FixedFncTexture6S:
        return "FixedFncTexture[6].S";
    case Attribute::FixedFncTexture6T:
        return "FixedFncTexture[6].T";
    case Attribute::FixedFncTexture6R:
        return "FixedFncTexture[6].R";
    case Attribute::FixedFncTexture6Q:
        return "FixedFncTexture[6].Q";
    case Attribute::FixedFncTexture7S:
        return "FixedFncTexture[7].S";
    case Attribute::FixedFncTexture7T:
        return "FixedFncTexture[7].T";
    case Attribute::FixedFncTexture7R:
        return "FixedFncTexture[7].R";
    case Attribute::FixedFncTexture7Q:
        return "FixedFncTexture[7].Q";
    case Attribute::FixedFncTexture8S:
        return "FixedFncTexture[8].S";
    case Attribute::FixedFncTexture8T:
        return "FixedFncTexture[8].T";
    case Attribute::FixedFncTexture8R:
        return "FixedFncTexture[8].R";
    case Attribute::FixedFncTexture8Q:
        return "FixedFncTexture[8].Q";
    case Attribute::FixedFncTexture9S:
        return "FixedFncTexture[9].S";
    case Attribute::FixedFncTexture9T:
        return "FixedFncTexture[9].T";
    case Attribute::FixedFncTexture9R:
        return "FixedFncTexture[9].R";
    case Attribute::FixedFncTexture9Q:
        return "FixedFncTexture[9].Q";
    case Attribute::ViewportMask:
        return "ViewportMask";
    case Attribute::FrontFace:
        return "FrontFace";
    case Attribute::BaseInstance:
        return "BaseInstance";
    case Attribute::BaseVertex:
        return "BaseVertex";
    case Attribute::DrawID:
        return "DrawID";
    }
    return fmt::format("<reserved attribute {}>", static_cast<int>(attribute));
}

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <fmt/format.h>

#include "common/common_types.h"

namespace Shader::IR {

enum class Attribute : u64 {
    PrimitiveId = 24,
    Layer = 25,
    ViewportIndex = 26,
    PointSize = 27,
    PositionX = 28,
    PositionY = 29,
    PositionZ = 30,
    PositionW = 31,
    Generic0X = 32,
    Generic0Y = 33,
    Generic0Z = 34,
    Generic0W = 35,
    Generic1X = 36,
    Generic1Y = 37,
    Generic1Z = 38,
    Generic1W = 39,
    Generic2X = 40,
    Generic2Y = 41,
    Generic2Z = 42,
    Generic2W = 43,
    Generic3X = 44,
    Generic3Y = 45,
    Generic3Z = 46,
    Generic3W = 47,
    Generic4X = 48,
    Generic4Y = 49,
    Generic4Z = 50,
    Generic4W = 51,
    Generic5X = 52,
    Generic5Y = 53,
    Generic5Z = 54,
    Generic5W = 55,
    Generic6X = 56,
    Generic6Y = 57,
    Generic6Z = 58,
    Generic6W = 59,
    Generic7X = 60,
    Generic7Y = 61,
    Generic7Z = 62,
    Generic7W = 63,
    Generic8X = 64,
    Generic8Y = 65,
    Generic8Z = 66,
    Generic8W = 67,
    Generic9X = 68,
    Generic9Y = 69,
    Generic9Z = 70,
    Generic9W = 71,
    Generic10X = 72,
    Generic10Y = 73,
    Generic10Z = 74,
    Generic10W = 75,
    Generic11X = 76,
    Generic11Y = 77,
    Generic11Z = 78,
    Generic11W = 79,
    Generic12X = 80,
    Generic12Y = 81,
    Generic12Z = 82,
    Generic12W = 83,
    Generic13X = 84,
    Generic13Y = 85,
    Generic13Z = 86,
    Generic13W = 87,
    Generic14X = 88,
    Generic14Y = 89,
    Generic14Z = 90,
    Generic14W = 91,
    Generic15X = 92,
    Generic15Y = 93,
    Generic15Z = 94,
    Generic15W = 95,
    Generic16X = 96,
    Generic16Y = 97,
    Generic16Z = 98,
    Generic16W = 99,
    Generic17X = 100,
    Generic17Y = 101,
    Generic17Z = 102,
    Generic17W = 103,
    Generic18X = 104,
    Generic18Y = 105,
    Generic18Z = 106,
    Generic18W = 107,
    Generic19X = 108,
    Generic19Y = 109,
    Generic19Z = 110,
    Generic19W = 111,
    Generic20X = 112,
    Generic20Y = 113,
    Generic20Z = 114,
    Generic20W = 115,
    Generic21X = 116,
    Generic21Y = 117,
    Generic21Z = 118,
    Generic21W = 119,
    Generic22X = 120,
    Generic22Y = 121,
    Generic22Z = 122,
    Generic22W = 123,
    Generic23X = 124,
    Generic23Y = 125,
    Generic23Z = 126,
    Generic23W = 127,
    Generic24X = 128,
    Generic24Y = 129,
    Generic24Z = 130,
    Generic24W = 131,
    Generic25X = 132,
    Generic25Y = 133,
    Generic25Z = 134,
    Generic25W = 135,
    Generic26X = 136,
    Generic26Y = 137,
    Generic26Z = 138,
    Generic26W = 139,
    Generic27X = 140,
    Generic27Y = 141,
    Generic27Z = 142,
    Generic27W = 143,
    Generic28X = 144,
    Generic28Y = 145,
    Generic28Z = 146,
    Generic28W = 147,
    Generic29X = 148,
    Generic29Y = 149,
    Generic29Z = 150,
    Generic29W = 151,
    Generic30X = 152,
    Generic30Y = 153,
    Generic30Z = 154,
    Generic30W = 155,
    Generic31X = 156,
    Generic31Y = 157,
    Generic31Z = 158,
    Generic31W = 159,
    ColorFrontDiffuseR = 160,
    ColorFrontDiffuseG = 161,
    ColorFrontDiffuseB = 162,
    ColorFrontDiffuseA = 163,
    ColorFrontSpecularR = 164,
    ColorFrontSpecularG = 165,
    ColorFrontSpecularB = 166,
    ColorFrontSpecularA = 167,
    ColorBackDiffuseR = 168,
    ColorBackDiffuseG = 169,
    ColorBackDiffuseB = 170,
    ColorBackDiffuseA = 171,
    ColorBackSpecularR = 172,
    ColorBackSpecularG = 173,
    ColorBackSpecularB = 174,
    ColorBackSpecularA = 175,
    ClipDistance0 = 176,
    ClipDistance1 = 177,
    ClipDistance2 = 178,
    ClipDistance3 = 179,
    ClipDistance4 = 180,
    ClipDistance5 = 181,
    ClipDistance6 = 182,
    ClipDistance7 = 183,
    PointSpriteS = 184,
    PointSpriteT = 185,
    FogCoordinate = 186,
    TessellationEvaluationPointU = 188,
    TessellationEvaluationPointV = 189,
    InstanceId = 190,
    VertexId = 191,
    FixedFncTexture0S = 192,
    FixedFncTexture0T = 193,
    FixedFncTexture0R = 194,
    FixedFncTexture0Q = 195,
    FixedFncTexture1S = 196,
    FixedFncTexture1T = 197,
    FixedFncTexture1R = 198,
    FixedFncTexture1Q = 199,
    FixedFncTexture2S = 200,
    FixedFncTexture2T = 201,
    FixedFncTexture2R = 202,
    FixedFncTexture2Q = 203,
    FixedFncTexture3S = 204,
    FixedFncTexture3T = 205,
    FixedFncTexture3R = 206,
    FixedFncTexture3Q = 207,
    FixedFncTexture4S = 208,
    FixedFncTexture4T = 209,
    FixedFncTexture4R = 210,
    FixedFncTexture4Q = 211,
    FixedFncTexture5S = 212,
    FixedFncTexture5T = 213,
    FixedFncTexture5R = 214,
    FixedFncTexture5Q = 215,
    FixedFncTexture6S = 216,
    FixedFncTexture6T = 217,
    FixedFncTexture6R = 218,
    FixedFncTexture6Q = 219,
    FixedFncTexture7S = 220,
    FixedFncTexture7T = 221,
    FixedFncTexture7R = 222,
    FixedFncTexture7Q = 223,
    FixedFncTexture8S = 224,
    FixedFncTexture8T = 225,
    FixedFncTexture8R = 226,
    FixedFncTexture8Q = 227,
    FixedFncTexture9S = 228,
    FixedFncTexture9T = 229,
    FixedFncTexture9R = 230,
    FixedFncTexture9Q = 231,
    ViewportMask = 232,
    FrontFace = 255,

    // Implementation attributes
    BaseInstance = 256,
    BaseVertex = 257,
    DrawID = 258,
};

constexpr size_t NUM_GENERICS = 32;

constexpr size_t NUM_FIXEDFNCTEXTURE = 10;

[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;

[[nodiscard]] u32 GenericAttributeIndex(Attribute attribute);

[[nodiscard]] u32 GenericAttributeElement(Attribute attribute);

[[nodiscard]] std::string NameOf(Attribute attribute);

[[nodiscard]] constexpr IR::Attribute operator+(IR::Attribute attribute, size_t value) noexcept {
    return static_cast<IR::Attribute>(static_cast<size_t>(attribute) + value);
}

} // namespace Shader::IR

template <>
struct fmt::formatter<Shader::IR::Attribute> {
    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }
    template <typename FormatContext>
    auto format(const Shader::IR::Attribute& attribute, FormatContext& ctx) {
        return fmt::format_to(ctx.out(), "{}", Shader::IR::NameOf(attribute));
    }
};


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <initializer_list>
#include <map>

#include "common/common_types.h"
#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/ir/value.h"

namespace Shader::IR {

Block::Block(ObjectPool<Inst>& inst_pool_) : inst_pool{&inst_pool_} {}

Block::~Block() = default;

void Block::AppendNewInst(Opcode op, std::initializer_list<Value> args) {
    PrependNewInst(end(), op, args);
}

Block::iterator Block::PrependNewInst(iterator insertion_point, const Inst& base_inst) {
    Inst* const inst{inst_pool->Create(base_inst)};
    return instructions.insert(insertion_point, *inst);
}

Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode op,
                                      std::initializer_list<Value> args, u32 flags) {
    Inst* const inst{inst_pool->Create(op, flags)};
    const auto result_it{instructions.insert(insertion_point, *inst)};

    if (inst->NumArgs() != args.size()) {
        throw InvalidArgument("Invalid number of arguments {} in {}", args.size(), op);
    }
    std::ranges::for_each(args, [inst, index = size_t{0}](const Value& arg) mutable {
        inst->SetArg(index, arg);
        ++index;
    });
    return result_it;
}

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,
                                Block* block) {
    if (const auto it{block_to_index.find(block)}; it != block_to_index.end()) {
        return fmt::format("{{Block ${}}}", it->second);
    }
    return fmt::format("$<unknown block {:016x}>", reinterpret_cast<u64>(block));
}

static size_t InstIndex(std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index,
                        const Inst* inst) {
    const auto [it, is_inserted]{inst_to_index.emplace(inst, inst_index + 1)};
    if (is_inserted) {
        ++inst_index;
    }
    return it->second;
}

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.IsImmediate() || arg.IsIdentity()) {
        return fmt::format("%{}", InstIndex(inst_to_index, inst_index, arg.Inst()));
    }
    switch (arg.Type()) {
    case Type::U1:
        return fmt::format("#{}", arg.U1() ? "true" : "false");
    case Type::U8:
        return fmt::format("#{}", arg.U8());
    case Type::U16:
        return fmt::format("#{}", arg.U16());
    case Type::U32:
        return fmt::format("#{}", arg.U32());
    case Type::U64:
        return fmt::format("#{}", arg.U64());
    case Type::F32:
        return fmt::format("#{}", arg.F32());
    case Type::Reg:
        return fmt::format("{}", arg.Reg());
    case Type::Pred:
        return fmt::format("{}", arg.Pred());
    case Type::Attribute:
        return fmt::format("{}", arg.Attribute());
    default:
        return "<unknown immediate type>";
    }
}

std::string DumpBlock(const Block& block) {
    size_t inst_index{0};
    std::map<const Inst*, size_t> inst_to_index;
    return DumpBlock(block, {}, inst_to_index, inst_index);
}

std::string DumpBlock(const Block& block, const std::map<const Block*, size_t>& block_to_index,
                      std::map<const Inst*, size_t>& inst_to_index, size_t& inst_index) {
    std::string ret{"Block"};
    if (const auto it{block_to_index.find(&block)}; it != block_to_index.end()) {
        ret += fmt::format(" ${}", it->second);
    }
    ret += '\n';
    for (const Inst& inst : block) {
        const Opcode op{inst.GetOpcode()};
        ret += fmt::format("[{:016x}] ", reinterpret_cast<u64>(&inst));
        if (TypeOf(op) != Type::Void) {
            ret += fmt::format("%{:<5} = {}", InstIndex(inst_to_index, inst_index, &inst), op);
        } else {
            ret += fmt::format("         {}", op); // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
        }
        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(inst_to_index, inst_index, arg)};
            ret += arg_index != 0 ? ", " : " ";
            if (op == Opcode::Phi) {
                ret += fmt::format("[ {}, {} ]", arg_str,
                                   BlockToIndex(block_to_index, inst.PhiBlock(arg_index)));
            } else {
                ret += arg_str;
            }
            if (op != Opcode::Phi) {
                const Type actual_type{arg.Type()};
                const Type expected_type{ArgTypeOf(op, arg_index)};
                if (!AreTypesCompatible(actual_type, expected_type)) {
                    ret += fmt::format("<type error: {} != {}>", actual_type, expected_type);
                }
            }
        }
        if (TypeOf(op) != Type::Void) {
            ret += fmt::format(" (uses: {})\n", inst.UseCount());
        } else {
            ret += '\n';
        }
    }
    return ret;
}

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <initializer_list>
#include <map>
#include <span>
#include <vector>

#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"

namespace Shader::IR {

class Block {
public:
    using InstructionList = boost::intrusive::list<Inst>;
    using size_type = InstructionList::size_type;
    using iterator = InstructionList::iterator;
    using const_iterator = InstructionList::const_iterator;
    using reverse_iterator = InstructionList::reverse_iterator;
    using const_reverse_iterator = InstructionList::const_reverse_iterator;

    explicit Block(ObjectPool<Inst>& inst_pool_);
    ~Block();

    Block(const Block&) = delete;
    Block& operator=(const Block&) = delete;

    Block(Block&&) = default;
    Block& operator=(Block&&) = default;

    /// Appends a new instruction to the end of this basic block.
    void AppendNewInst(Opcode op, std::initializer_list<Value> args);

    /// Prepends a copy of an instruction to this basic block before the insertion point.
    iterator PrependNewInst(iterator insertion_point, const Inst& base_inst);

    /// Prepends a new instruction to this basic block before the insertion point.
    iterator PrependNewInst(iterator insertion_point, Opcode op,
                            std::initializer_list<Value> args = {}, u32 flags = 0);

    /// 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 {
        return instructions;
    }
    /// Gets an immutable reference to the instruction list for this basic block.
    [[nodiscard]] const InstructionList& Instructions() const noexcept {
        return instructions;
    }

    /// Gets an immutable span to the immediate predecessors.
    [[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>
    void SetDefinition(DefinitionType def) {
        definition = Common::BitCast<u32>(def);
    }

    /// Return the intrusively stored host definition of this instruction.
    template <typename DefinitionType>
    [[nodiscard]] DefinitionType Definition() const noexcept {
        return Common::BitCast<DefinitionType>(definition);
    }

    void SetSsaRegValue(IR::Reg reg, const Value& value) noexcept {
        ssa_reg_values[RegIndex(reg)] = value;
    }
    const Value& SsaRegValue(IR::Reg reg) const noexcept {
        return ssa_reg_values[RegIndex(reg)];
    }

    void SsaSeal() noexcept {
        is_ssa_sealed = true;
    }
    [[nodiscard]] bool IsSsaSealed() const noexcept {
        return is_ssa_sealed;
    }

    [[nodiscard]] bool empty() const {
        return instructions.empty();
    }
    [[nodiscard]] size_type size() const {
        return instructions.size();
    }

    [[nodiscard]] Inst& front() {
        return instructions.front();
    }
    [[nodiscard]] const Inst& front() const {
        return instructions.front();
    }

    [[nodiscard]] Inst& back() {
        return instructions.back();
    }
    [[nodiscard]] const Inst& back() const {
        return instructions.back();
    }

    [[nodiscard]] iterator begin() {
        return instructions.begin();
    }
    [[nodiscard]] const_iterator begin() const {
        return instructions.begin();
    }
    [[nodiscard]] iterator end() {
        return instructions.end();
    }
    [[nodiscard]] const_iterator end() const {
        return instructions.end();
    }

    [[nodiscard]] reverse_iterator rbegin() {
        return instructions.rbegin();
    }
    [[nodiscard]] const_reverse_iterator rbegin() const {
        return instructions.rbegin();
    }
    [[nodiscard]] reverse_iterator rend() {
        return instructions.rend();
    }
    [[nodiscard]] const_reverse_iterator rend() const {
        return instructions.rend();
    }

    [[nodiscard]] const_iterator cbegin() const {
        return instructions.cbegin();
    }
    [[nodiscard]] const_iterator cend() const {
        return instructions.cend();
    }

    [[nodiscard]] const_reverse_iterator crbegin() const {
        return instructions.crbegin();
    }
    [[nodiscard]] const_reverse_iterator crend() const {
        return instructions.crend();
    }

    // Set the order of the block, it can be set pre order, the user decides
    void SetOrder(u32 new_order) {
        order = new_order;
    }

    // Get the order of the block.
    // The higher, the closer is the block to the end.
    [[nodiscard]] u32 GetOrder() const {
        return order;
    }

private:
    /// Memory pool for instruction list
    ObjectPool<Inst>* inst_pool;

    /// List of instructions in this block
    InstructionList instructions;

    /// 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;
    /// Intrusively store if the block is sealed in the SSA pass.
    bool is_ssa_sealed{false};

    /// Intrusively stored host definition of this block.
    u32 definition{};

    /// Order of the block.
    u32 order{};
};

using BlockList = std::vector<Block*>;

[[nodiscard]] std::string DumpBlock(const Block& block);

[[nodiscard]] std::string DumpBlock(const Block& block,
                                    const std::map<const Block*, size_t>& block_to_index,
                                    std::map<const Inst*, size_t>& inst_to_index,
                                    size_t& inst_index);

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <optional>
#include <type_traits>
#include <queue>

#include <boost/container/small_vector.hpp>

#include "shader_recompiler/frontend/ir/value.h"

namespace Shader::IR {

template <typename Pred>
auto BreadthFirstSearch(const Value& value, Pred&& pred)
    -> std::invoke_result_t<Pred, const Inst*> {
    if (value.IsImmediate()) {
        // Nothing to do with immediates
        return std::nullopt;
    }
    // Breadth-first search visiting the right most arguments first
    // Small vector has been determined from shaders in Super Smash Bros. Ultimate
    boost::container::small_vector<const Inst*, 2> visited;
    std::queue<const Inst*> queue;
    queue.push(value.InstRecursive());

    while (!queue.empty()) {
        // Pop one instruction from the queue
        const Inst* const inst{queue.front()};
        queue.pop();
        if (const std::optional result = pred(inst)) {
            // This is the instruction we were looking for
            return result;
        }
        // Visit the right most arguments first
        for (size_t arg = inst->NumArgs(); arg--;) {
            const Value arg_value{inst->Arg(arg)};
            if (arg_value.IsImmediate()) {
                continue;
            }
            // Queue instruction if it hasn't been visited
            const Inst* const arg_inst{arg_value.InstRecursive()};
            if (std::ranges::find(visited, arg_inst) == visited.end()) {
                visited.push_back(arg_inst);
                queue.push(arg_inst);
            }
        }
    }
    // SSA tree has been traversed and the result hasn't been found
    return std::nullopt;
}

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <string>

#include <fmt/format.h>

#include "shader_recompiler/frontend/ir/condition.h"

namespace Shader::IR {

std::string NameOf(Condition condition) {
    std::string ret;
    if (condition.GetFlowTest() != FlowTest::T) {
        ret = fmt::to_string(condition.GetFlowTest());
    }
    const auto [pred, negated]{condition.GetPred()};
    if (!ret.empty()) {
        ret += '&';
    }
    if (negated) {
        ret += '!';
    }
    ret += fmt::to_string(pred);
    return ret;
}

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <string>

#include <fmt/format.h>

#include "common/common_types.h"
#include "shader_recompiler/frontend/ir/flow_test.h"
#include "shader_recompiler/frontend/ir/pred.h"

namespace Shader::IR {

class Condition {
public:
    Condition() noexcept = default;

    explicit Condition(FlowTest flow_test_, Pred pred_, bool pred_negated_ = false) noexcept
        : flow_test{static_cast<u16>(flow_test_)}, pred{static_cast<u8>(pred_)},
          pred_negated{pred_negated_ ? u8{1} : u8{0}} {}

    explicit Condition(Pred pred_, bool pred_negated_ = false) noexcept
        : Condition(FlowTest::T, pred_, pred_negated_) {}

    explicit Condition(bool value) : Condition(Pred::PT, !value) {}

    auto operator<=>(const Condition&) const noexcept = default;

    [[nodiscard]] IR::FlowTest GetFlowTest() const noexcept {
        return static_cast<IR::FlowTest>(flow_test);
    }

    [[nodiscard]] std::pair<IR::Pred, bool> GetPred() const noexcept {
        return {static_cast<IR::Pred>(pred), pred_negated != 0};
    }

private:
    u16 flow_test;
    u8 pred;
    u8 pred_negated;
};

std::string NameOf(Condition condition);

} // namespace Shader::IR

template <>
struct fmt::formatter<Shader::IR::Condition> {
    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }
    template <typename FormatContext>
    auto format(const Shader::IR::Condition& cond, FormatContext& ctx) {
        return fmt::format_to(ctx.out(), "{}", Shader::IR::NameOf(cond));
    }
};


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <string>

#include <fmt/format.h>

#include "shader_recompiler/frontend/ir/flow_test.h"

namespace Shader::IR {

std::string NameOf(FlowTest flow_test) {
    switch (flow_test) {
    case FlowTest::F:
        return "F";
    case FlowTest::LT:
        return "LT";
    case FlowTest::EQ:
        return "EQ";
    case FlowTest::LE:
        return "LE";
    case FlowTest::GT:
        return "GT";
    case FlowTest::NE:
        return "NE";
    case FlowTest::GE:
        return "GE";
    case FlowTest::NUM:
        return "NUM";
    case FlowTest::NaN:
        return "NAN";
    case FlowTest::LTU:
        return "LTU";
    case FlowTest::EQU:
        return "EQU";
    case FlowTest::LEU:
        return "LEU";
    case FlowTest::GTU:
        return "GTU";
    case FlowTest::NEU:
        return "NEU";
    case FlowTest::GEU:
        return "GEU";
    case FlowTest::T:
        return "T";
    case FlowTest::OFF:
        return "OFF";
    case FlowTest::LO:
        return "LO";
    case FlowTest::SFF:
        return "SFF";
    case FlowTest::LS:
        return "LS";
    case FlowTest::HI:
        return "HI";
    case FlowTest::SFT:
        return "SFT";
    case FlowTest::HS:
        return "HS";
    case FlowTest::OFT:
        return "OFT";
    case FlowTest::CSM_TA:
        return "CSM_TA";
    case FlowTest::CSM_TR:
        return "CSM_TR";
    case FlowTest::CSM_MX:
        return "CSM_MX";
    case FlowTest::FCSM_TA:
        return "FCSM_TA";
    case FlowTest::FCSM_TR:
        return "FCSM_TR";
    case FlowTest::FCSM_MX:
        return "FCSM_MX";
    case FlowTest::RLE:
        return "RLE";
    case FlowTest::RGT:
        return "RGT";
    }
    return fmt::format("<invalid flow test {}>", static_cast<int>(flow_test));
}

} // namespace Shader::IR


code:
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <string>
#include <fmt/format.h>

#include "common/common_types.h"

namespace Shader::IR {

enum class FlowTest : u64 {
    F,
    LT,
    EQ,
    LE,
    GT,
    NE,
    GE,
    NUM,
    NaN,
    LTU,
    EQU,
    LEU,
    GTU,
    NEU,
    GEU,
    T,
    OFF,
    LO,
    SFF,
    LS,
    HI,
    SFT,
    HS,
    OFT,
    CSM_TA,
    CSM_TR,
    CSM_MX,
    FCSM_TA,
    FCSM_TR,
    FCSM_MX,
    RLE,
    RGT,
};

[[nodiscard]] std::string NameOf(FlowTest flow_test);

} // namespace Shader::IR

template <>
struct fmt::formatter<Shader::IR::FlowTest> {
    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }
    template <typename FormatContext>
    auto format(const Shader::IR::FlowTest& flow_test, FormatContext& ctx) {
        return fmt::format_to(ctx.out(), "{}", Shader::IR::NameOf(flow_test));
    }
};