summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/ir_opt/get_set_elimination_pass.cpp
blob: 21b8526cd9259c9ccb871df07b35dde8326f0957 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#include <array>

#include "shader_recompiler/frontend/ir/basic_block.h"
#include "shader_recompiler/frontend/ir/microinstruction.h"
#include "shader_recompiler/ir_opt/passes.h"

namespace Shader::Optimization {
namespace {
using Iterator = IR::Block::iterator;

enum class TrackingType {
    Reg,
};

struct RegisterInfo {
    IR::Value register_value;
    TrackingType tracking_type;
    Iterator last_set_instruction;
    bool set_instruction_present = false;
};

void DoSet(IR::Block& block, RegisterInfo& info, IR::Value value, Iterator set_inst,
           TrackingType tracking_type) {
    if (info.set_instruction_present) {
        info.last_set_instruction->Invalidate();
        block.Instructions().erase(info.last_set_instruction);
    }
    info.register_value = value;
    info.tracking_type = tracking_type;
    info.set_instruction_present = true;
    info.last_set_instruction = set_inst;
}

RegisterInfo Nothing(Iterator get_inst, TrackingType tracking_type) {
    RegisterInfo info{};
    info.register_value = IR::Value{&*get_inst};
    info.tracking_type = tracking_type;
    return info;
}

void DoGet(RegisterInfo& info, Iterator get_inst, TrackingType tracking_type) {
    if (info.register_value.IsEmpty()) {
        info = Nothing(get_inst, tracking_type);
        return;
    }
    if (info.tracking_type == tracking_type) {
        get_inst->ReplaceUsesWith(info.register_value);
        return;
    }
    info = Nothing(get_inst, tracking_type);
}
} // Anonymous namespace

void GetSetElimination(IR::Block& block) {
    std::array<RegisterInfo, 255> reg_info;

    for (Iterator inst = block.begin(); inst != block.end(); ++inst) {
        switch (inst->Opcode()) {
        case IR::Opcode::GetRegister: {
            const IR::Reg reg{inst->Arg(0).Reg()};
            if (reg == IR::Reg::RZ) {
                break;
            }
            const size_t index{static_cast<size_t>(reg)};
            DoGet(reg_info.at(index), inst, TrackingType::Reg);
            break;
        }
        case IR::Opcode::SetRegister: {
            const IR::Reg reg{inst->Arg(0).Reg()};
            if (reg == IR::Reg::RZ) {
                break;
            }
            const size_t index{static_cast<size_t>(reg)};
            DoSet(block, reg_info.at(index), inst->Arg(1), inst, TrackingType::Reg);
            break;
        }
        default:
            break;
        }
    }
}

} // namespace Shader::Optimization