glsl: textures wip
This commit is contained in:
		@@ -8,9 +8,21 @@
 | 
			
		||||
#include "shader_recompiler/profile.h"
 | 
			
		||||
 | 
			
		||||
namespace Shader::Backend::GLSL {
 | 
			
		||||
namespace {
 | 
			
		||||
std::string_view InterpDecorator(Interpolation interp) {
 | 
			
		||||
    switch (interp) {
 | 
			
		||||
    case Interpolation::Smooth:
 | 
			
		||||
        return "";
 | 
			
		||||
    case Interpolation::Flat:
 | 
			
		||||
        return "flat";
 | 
			
		||||
    case Interpolation::NoPerspective:
 | 
			
		||||
        return "noperspective";
 | 
			
		||||
    }
 | 
			
		||||
    throw InvalidArgument("Invalid interpolation {}", interp);
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindings,
 | 
			
		||||
                         const Profile& profile_)
 | 
			
		||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_)
 | 
			
		||||
    : info{program.info}, profile{profile_} {
 | 
			
		||||
    std::string header = "#version 450\n";
 | 
			
		||||
    SetupExtensions(header);
 | 
			
		||||
@@ -49,7 +61,8 @@ EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindin
 | 
			
		||||
    for (size_t index = 0; index < info.input_generics.size(); ++index) {
 | 
			
		||||
        const auto& generic{info.input_generics[index]};
 | 
			
		||||
        if (generic.used) {
 | 
			
		||||
            Add("layout(location={})in vec4 in_attr{};", index, index);
 | 
			
		||||
            Add("layout(location={}) {} in vec4 in_attr{};", index,
 | 
			
		||||
                InterpDecorator(generic.interpolation), index);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
 | 
			
		||||
@@ -66,6 +79,7 @@ EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindin
 | 
			
		||||
    DefineConstantBuffers();
 | 
			
		||||
    DefineStorageBuffers();
 | 
			
		||||
    DefineHelperFunctions();
 | 
			
		||||
    SetupImages(bindings);
 | 
			
		||||
    Add("void main(){{");
 | 
			
		||||
 | 
			
		||||
    if (stage == Stage::VertexA || stage == Stage::VertexB) {
 | 
			
		||||
@@ -102,7 +116,7 @@ void EmitContext::DefineConstantBuffers() {
 | 
			
		||||
    }
 | 
			
		||||
    u32 binding{};
 | 
			
		||||
    for (const auto& desc : info.constant_buffer_descriptors) {
 | 
			
		||||
        Add("layout(std140,binding={}) uniform cbuf_{}{{vec4 cbuf{}[{}];}};", binding, binding,
 | 
			
		||||
        Add("layout(std140,binding={}) uniform cbuf_{}{{vec4 cbuf{}[{}];}};", binding, desc.index,
 | 
			
		||||
            desc.index, 4 * 1024);
 | 
			
		||||
        ++binding;
 | 
			
		||||
    }
 | 
			
		||||
@@ -164,4 +178,36 @@ void EmitContext::DefineHelperFunctions() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitContext::SetupImages(Bindings& bindings) {
 | 
			
		||||
    image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
 | 
			
		||||
    for (const auto& desc : info.image_buffer_descriptors) {
 | 
			
		||||
        throw NotImplementedException("image_buffer_descriptors");
 | 
			
		||||
        image_buffer_bindings.push_back(bindings.image);
 | 
			
		||||
        bindings.image += desc.count;
 | 
			
		||||
    }
 | 
			
		||||
    image_bindings.reserve(info.image_descriptors.size());
 | 
			
		||||
    for (const auto& desc : info.image_descriptors) {
 | 
			
		||||
        throw NotImplementedException("image_bindings");
 | 
			
		||||
 | 
			
		||||
        image_bindings.push_back(bindings.image);
 | 
			
		||||
        bindings.image += desc.count;
 | 
			
		||||
    }
 | 
			
		||||
    texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
 | 
			
		||||
    for (const auto& desc : info.texture_buffer_descriptors) {
 | 
			
		||||
        throw NotImplementedException("TextureType::Buffer");
 | 
			
		||||
 | 
			
		||||
        texture_buffer_bindings.push_back(bindings.texture);
 | 
			
		||||
        bindings.texture += desc.count;
 | 
			
		||||
    }
 | 
			
		||||
    texture_bindings.reserve(info.texture_descriptors.size());
 | 
			
		||||
    for (const auto& desc : info.texture_descriptors) {
 | 
			
		||||
        texture_bindings.push_back(bindings.texture);
 | 
			
		||||
        const auto indices{bindings.texture + desc.count};
 | 
			
		||||
        for (u32 index = bindings.texture; index < indices; ++index) {
 | 
			
		||||
            Add("layout(binding={}) uniform sampler2D tex{};", bindings.texture, index);
 | 
			
		||||
        }
 | 
			
		||||
        bindings.texture += desc.count;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Shader::Backend::GLSL
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,8 @@
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "shader_recompiler/backend/glsl/reg_alloc.h"
 | 
			
		||||
@@ -109,11 +111,17 @@ public:
 | 
			
		||||
    std::string_view stage_name = "invalid";
 | 
			
		||||
    std::string_view attrib_name = "invalid";
 | 
			
		||||
 | 
			
		||||
    std::vector<u32> texture_buffer_bindings;
 | 
			
		||||
    std::vector<u32> image_buffer_bindings;
 | 
			
		||||
    std::vector<u32> texture_bindings;
 | 
			
		||||
    std::vector<u32> image_bindings;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void SetupExtensions(std::string& header);
 | 
			
		||||
    void DefineConstantBuffers();
 | 
			
		||||
    void DefineStorageBuffers();
 | 
			
		||||
    void DefineHelperFunctions();
 | 
			
		||||
    void SetupImages(Bindings& bindings);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Shader::Backend::GLSL
 | 
			
		||||
 
 | 
			
		||||
@@ -113,7 +113,7 @@ void PrecolorInst(IR::Inst& phi) {
 | 
			
		||||
        if (arg.IsImmediate()) {
 | 
			
		||||
            ir.PhiMove(phi, arg);
 | 
			
		||||
        } else {
 | 
			
		||||
            ir.PhiMove(phi, IR::Value{&RegAlloc::AliasInst(*arg.Inst())});
 | 
			
		||||
            ir.PhiMove(phi, IR::Value{&*arg.InstRecursive()});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    for (size_t i = 0; i < num_args; ++i) {
 | 
			
		||||
@@ -157,7 +157,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
 | 
			
		||||
            break;
 | 
			
		||||
        case IR::AbstractSyntaxNode::Type::Return:
 | 
			
		||||
        case IR::AbstractSyntaxNode::Type::Unreachable:
 | 
			
		||||
            ctx.Add("return;\n}}");
 | 
			
		||||
            ctx.Add("return;");
 | 
			
		||||
            break;
 | 
			
		||||
        case IR::AbstractSyntaxNode::Type::Loop:
 | 
			
		||||
        case IR::AbstractSyntaxNode::Type::Repeat:
 | 
			
		||||
@@ -175,6 +175,8 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo&, IR::Program& pr
 | 
			
		||||
    EmitContext ctx{program, bindings, profile};
 | 
			
		||||
    Precolor(program);
 | 
			
		||||
    EmitCode(ctx, program);
 | 
			
		||||
    ctx.code += "}";
 | 
			
		||||
    fmt::print("\n{}\n", ctx.code);
 | 
			
		||||
    return ctx.code;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ static void Alias(IR::Inst& inst, const IR::Value& value) {
 | 
			
		||||
    if (value.IsImmediate()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    IR::Inst& value_inst{RegAlloc::AliasInst(*value.Inst())};
 | 
			
		||||
    IR::Inst& value_inst{*value.InstRecursive()};
 | 
			
		||||
    value_inst.DestructiveAddUsage(inst.UseCount());
 | 
			
		||||
    value_inst.DestructiveRemoveUsage();
 | 
			
		||||
    inst.SetDefinition(value_inst.Definition<Id>());
 | 
			
		||||
 
 | 
			
		||||
@@ -6,17 +6,39 @@
 | 
			
		||||
 | 
			
		||||
#include "shader_recompiler/backend/glsl/emit_context.h"
 | 
			
		||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/modifiers.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/value.h"
 | 
			
		||||
#include "shader_recompiler/profile.h"
 | 
			
		||||
 | 
			
		||||
namespace Shader::Backend::GLSL {
 | 
			
		||||
namespace {
 | 
			
		||||
std::string Texture(EmitContext& ctx, IR::TextureInstInfo info,
 | 
			
		||||
                    [[maybe_unused]] const IR::Value& index) {
 | 
			
		||||
    if (info.type == TextureType::Buffer) {
 | 
			
		||||
        throw NotImplementedException("TextureType::Buffer");
 | 
			
		||||
    } else {
 | 
			
		||||
        return fmt::format("tex{}", ctx.texture_bindings.at(info.descriptor_index));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
void EmitImageSampleImplicitLod([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
 | 
			
		||||
                                [[maybe_unused]] const IR::Value& index,
 | 
			
		||||
                                [[maybe_unused]] std::string_view coords,
 | 
			
		||||
                                [[maybe_unused]] std::string_view bias_lc,
 | 
			
		||||
                                [[maybe_unused]] const IR::Value& offset) {
 | 
			
		||||
    throw NotImplementedException("GLSL Instruction");
 | 
			
		||||
    const auto info{inst.Flags<IR::TextureInstInfo>()};
 | 
			
		||||
    if (info.has_bias) {
 | 
			
		||||
        throw NotImplementedException("Bias texture samples");
 | 
			
		||||
    }
 | 
			
		||||
    if (info.has_lod_clamp) {
 | 
			
		||||
        throw NotImplementedException("Lod clamp samples");
 | 
			
		||||
    }
 | 
			
		||||
    if (!offset.IsEmpty()) {
 | 
			
		||||
        throw NotImplementedException("Offset");
 | 
			
		||||
    }
 | 
			
		||||
    const auto texture{Texture(ctx, info, index)};
 | 
			
		||||
    ctx.AddF32x4("{}=texture({},{});", inst, texture, coords);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitImageSampleExplicitLod([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
 | 
			
		||||
 
 | 
			
		||||
@@ -89,11 +89,11 @@ void EmitIsHelperInvocation(EmitContext& ctx);
 | 
			
		||||
void EmitYDirection(EmitContext& ctx);
 | 
			
		||||
void EmitLoadLocal(EmitContext& ctx, std::string_view word_offset);
 | 
			
		||||
void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value);
 | 
			
		||||
void EmitUndefU1(EmitContext& ctx);
 | 
			
		||||
void EmitUndefU8(EmitContext& ctx);
 | 
			
		||||
void EmitUndefU16(EmitContext& ctx);
 | 
			
		||||
void EmitUndefU32(EmitContext& ctx);
 | 
			
		||||
void EmitUndefU64(EmitContext& ctx);
 | 
			
		||||
void EmitUndefU1(EmitContext& ctx, IR::Inst& inst);
 | 
			
		||||
void EmitUndefU8(EmitContext& ctx, IR::Inst& inst);
 | 
			
		||||
void EmitUndefU16(EmitContext& ctx, IR::Inst& inst);
 | 
			
		||||
void EmitUndefU32(EmitContext& ctx, IR::Inst& inst);
 | 
			
		||||
void EmitUndefU64(EmitContext& ctx, IR::Inst& inst);
 | 
			
		||||
void EmitLoadGlobalU8(EmitContext& ctx);
 | 
			
		||||
void EmitLoadGlobalS8(EmitContext& ctx);
 | 
			
		||||
void EmitLoadGlobalU16(EmitContext& ctx);
 | 
			
		||||
 
 | 
			
		||||
@@ -39,17 +39,26 @@ void EmitReference(EmitContext&) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
 | 
			
		||||
    IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
 | 
			
		||||
    IR::Inst& phi{*phi_value.InstRecursive()};
 | 
			
		||||
    const auto phi_type{phi.Arg(0).Type()};
 | 
			
		||||
    if (!phi.Definition<Id>().is_valid) {
 | 
			
		||||
        // The phi node wasn't forward defined
 | 
			
		||||
        ctx.Add("{};", ctx.reg_alloc.Define(phi, phi.Arg(0).Type()));
 | 
			
		||||
        ctx.Add("{};", ctx.reg_alloc.Define(phi, phi_type));
 | 
			
		||||
    }
 | 
			
		||||
    const auto phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
 | 
			
		||||
    const auto val_reg{ctx.reg_alloc.Consume(value)};
 | 
			
		||||
    if (phi_reg == val_reg) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    ctx.Add("{}={};", phi_reg, val_reg);
 | 
			
		||||
    if (phi_type == value.Type()) {
 | 
			
		||||
        ctx.Add("{}={}; // PHI MOVE", phi_reg, val_reg);
 | 
			
		||||
    } else if (phi_type == IR::Type::U32 && value.Type() == IR::Type::F32) {
 | 
			
		||||
        ctx.Add("{}=floatBitsToUint({}); // CAST PHI MOVE", phi_reg, val_reg);
 | 
			
		||||
    } else {
 | 
			
		||||
        throw NotImplementedException("{} to {} move", phi_type, value.Type());
 | 
			
		||||
        const auto cast{ctx.reg_alloc.GetGlslType(phi_type)};
 | 
			
		||||
        ctx.Add("{}={}({}); // CAST PHI MOVE", phi_reg, cast, val_reg);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitBranch(EmitContext& ctx, std::string_view label) {
 | 
			
		||||
@@ -235,23 +244,23 @@ void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_
 | 
			
		||||
    NotImplemented();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitUndefU1(EmitContext& ctx) {
 | 
			
		||||
void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
 | 
			
		||||
    NotImplemented();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitUndefU8(EmitContext& ctx) {
 | 
			
		||||
void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
 | 
			
		||||
    NotImplemented();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitUndefU16(EmitContext& ctx) {
 | 
			
		||||
void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
 | 
			
		||||
    NotImplemented();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitUndefU32(EmitContext& ctx) {
 | 
			
		||||
    NotImplemented();
 | 
			
		||||
void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
 | 
			
		||||
    ctx.AddU32("{}=0u;", inst);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EmitUndefU64(EmitContext& ctx) {
 | 
			
		||||
void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
 | 
			
		||||
    NotImplemented();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -71,26 +71,17 @@ std::string RegAlloc::Define(IR::Inst& inst) {
 | 
			
		||||
 | 
			
		||||
std::string RegAlloc::Define(IR::Inst& inst, Type type) {
 | 
			
		||||
    const Id id{Alloc()};
 | 
			
		||||
    const auto type_str{GetType(type, id.index)};
 | 
			
		||||
    std::string type_str = "";
 | 
			
		||||
    if (!register_defined[id.index]) {
 | 
			
		||||
        register_defined[id.index] = true;
 | 
			
		||||
        type_str = GetGlslType(type);
 | 
			
		||||
    }
 | 
			
		||||
    inst.SetDefinition<Id>(id);
 | 
			
		||||
    return type_str + Representation(id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string RegAlloc::Define(IR::Inst& inst, IR::Type type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case IR::Type::U1:
 | 
			
		||||
        return Define(inst, Type::U1);
 | 
			
		||||
    case IR::Type::U32:
 | 
			
		||||
        return Define(inst, Type::U32);
 | 
			
		||||
    case IR::Type::F32:
 | 
			
		||||
        return Define(inst, Type::F32);
 | 
			
		||||
    case IR::Type::U64:
 | 
			
		||||
        return Define(inst, Type::U64);
 | 
			
		||||
    case IR::Type::F64:
 | 
			
		||||
        return Define(inst, Type::F64);
 | 
			
		||||
    default:
 | 
			
		||||
        throw NotImplementedException("IR type {}", type);
 | 
			
		||||
    }
 | 
			
		||||
    return Define(inst, RegType(type));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string RegAlloc::Consume(const IR::Value& value) {
 | 
			
		||||
@@ -107,11 +98,24 @@ std::string RegAlloc::Consume(IR::Inst& inst) {
 | 
			
		||||
    return Representation(inst.Definition<Id>());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string RegAlloc::GetType(Type type, u32 index) {
 | 
			
		||||
    if (register_defined[index]) {
 | 
			
		||||
        return "";
 | 
			
		||||
Type RegAlloc::RegType(IR::Type type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case IR::Type::U1:
 | 
			
		||||
        return Type::U1;
 | 
			
		||||
    case IR::Type::U32:
 | 
			
		||||
        return Type::U32;
 | 
			
		||||
    case IR::Type::F32:
 | 
			
		||||
        return Type::F32;
 | 
			
		||||
    case IR::Type::U64:
 | 
			
		||||
        return Type::U64;
 | 
			
		||||
    case IR::Type::F64:
 | 
			
		||||
        return Type::F64;
 | 
			
		||||
    default:
 | 
			
		||||
        throw NotImplementedException("IR type {}", type);
 | 
			
		||||
    }
 | 
			
		||||
    register_defined[index] = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string RegAlloc::GetGlslType(Type type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case Type::U1:
 | 
			
		||||
        return "bool ";
 | 
			
		||||
@@ -144,6 +148,10 @@ std::string RegAlloc::GetType(Type type, u32 index) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string RegAlloc::GetGlslType(IR::Type type) {
 | 
			
		||||
    return GetGlslType(RegType(type));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Id RegAlloc::Alloc() {
 | 
			
		||||
    if (num_used_registers < NUM_REGS) {
 | 
			
		||||
        for (size_t reg = 0; reg < NUM_REGS; ++reg) {
 | 
			
		||||
@@ -170,30 +178,4 @@ void RegAlloc::Free(Id id) {
 | 
			
		||||
    register_use[id.index] = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*static*/ bool RegAlloc::IsAliased(const IR::Inst& inst) {
 | 
			
		||||
    switch (inst.GetOpcode()) {
 | 
			
		||||
    case IR::Opcode::Identity:
 | 
			
		||||
    case IR::Opcode::BitCastU16F16:
 | 
			
		||||
    case IR::Opcode::BitCastU32F32:
 | 
			
		||||
    case IR::Opcode::BitCastU64F64:
 | 
			
		||||
    case IR::Opcode::BitCastF16U16:
 | 
			
		||||
    case IR::Opcode::BitCastF32U32:
 | 
			
		||||
    case IR::Opcode::BitCastF64U64:
 | 
			
		||||
        return true;
 | 
			
		||||
    default:
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*static*/ IR::Inst& RegAlloc::AliasInst(IR::Inst& inst) {
 | 
			
		||||
    IR::Inst* it{&inst};
 | 
			
		||||
    while (IsAliased(*it)) {
 | 
			
		||||
        const IR::Value arg{it->Arg(0)};
 | 
			
		||||
        if (arg.IsImmediate()) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        it = arg.InstRecursive();
 | 
			
		||||
    }
 | 
			
		||||
    return *it;
 | 
			
		||||
}
 | 
			
		||||
} // namespace Shader::Backend::GLSL
 | 
			
		||||
 
 | 
			
		||||
@@ -59,20 +59,15 @@ public:
 | 
			
		||||
    std::string Define(IR::Inst& inst, IR::Type type);
 | 
			
		||||
 | 
			
		||||
    std::string Consume(const IR::Value& value);
 | 
			
		||||
 | 
			
		||||
    /// Returns true if the instruction is expected to be aliased to another
 | 
			
		||||
    static bool IsAliased(const IR::Inst& inst);
 | 
			
		||||
 | 
			
		||||
    /// Returns the underlying value out of an alias sequence
 | 
			
		||||
    static IR::Inst& AliasInst(IR::Inst& inst);
 | 
			
		||||
    std::string GetGlslType(Type type);
 | 
			
		||||
    std::string GetGlslType(IR::Type type);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static constexpr size_t NUM_REGS = 4096;
 | 
			
		||||
    static constexpr size_t NUM_ELEMENTS = 4;
 | 
			
		||||
 | 
			
		||||
    std::string Consume(IR::Inst& inst);
 | 
			
		||||
    std::string GetType(Type type, u32 index);
 | 
			
		||||
 | 
			
		||||
    Type RegType(IR::Type type);
 | 
			
		||||
    Id Alloc();
 | 
			
		||||
    void Free(Id id);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user