summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/frontend/maxwell/location.h
blob: 66b51a19e6575aca626a90d600ee2b578c8790ec (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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <compare>
#include <iterator>

#include <fmt/format.h>

#include "common/common_types.h"
#include "shader_recompiler/exception.h"

namespace Shader::Maxwell {

class Location {
    static constexpr u32 VIRTUAL_OFFSET{std::numeric_limits<u32>::max()};

public:
    constexpr Location() = default;

    constexpr Location(u32 initial_offset) : offset{initial_offset} {
        if (initial_offset % 8 != 0) {
            throw InvalidArgument("initial_offset={} is not a multiple of 8", initial_offset);
        }
        Align();
    }

    [[nodiscard]] constexpr u32 Offset() const noexcept {
        return offset;
    }

    [[nodiscard]] constexpr bool IsVirtual() const {
        return offset == VIRTUAL_OFFSET;
    }

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

    constexpr Location operator++() noexcept {
        const Location copy{*this};
        Step();
        return copy;
    }

    constexpr Location operator++(int) noexcept {
        Step();
        return *this;
    }

    constexpr Location operator--() noexcept {
        const Location copy{*this};
        Back();
        return copy;
    }

    constexpr Location operator--(int) noexcept {
        Back();
        return *this;
    }

    constexpr Location operator+(int number) const {
        Location new_pc{*this};
        while (number > 0) {
            --number;
            ++new_pc;
        }
        while (number < 0) {
            ++number;
            --new_pc;
        }
        return new_pc;
    }

    constexpr Location operator-(int number) const {
        return operator+(-number);
    }

private:
    constexpr void Align() {
        offset += offset % 32 == 0 ? 8 : 0;
    }

    constexpr void Step() {
        offset += 8 + (offset % 32 == 24 ? 8 : 0);
    }

    constexpr void Back() {
        offset -= 8 + (offset % 32 == 8 ? 8 : 0);
    }

    u32 offset{VIRTUAL_OFFSET};
};

} // namespace Shader::Maxwell

template <>
struct fmt::formatter<Shader::Maxwell::Location> {
    constexpr auto parse(format_parse_context& ctx) {
        return ctx.begin();
    }
    template <typename FormatContext>
    auto format(const Shader::Maxwell::Location& location, FormatContext& ctx) {
        return fmt::format_to(ctx.out(), "{:04x}", location.Offset());
    }
};