TPDE
Loading...
Searching...
No Matches
ScratchReg.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4#pragma once
5
6namespace tpde {
7
8/// Owned unspillable and unevictable temporary register with RAII semantics.
9template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
10struct CompilerBase<Adaptor, Derived, Config>::ScratchReg {
11private:
12 CompilerBase *compiler;
13 // TODO(ts): get this using the CompilerConfig?
14 AsmReg reg = AsmReg::make_invalid();
15
16public:
17 /// Constructor, no register.
18 explicit ScratchReg(CompilerBase *compiler) : compiler(compiler) {}
19
20 explicit ScratchReg(const ScratchReg &) = delete;
21 ScratchReg(ScratchReg &&) noexcept;
22
23 ~ScratchReg() noexcept { reset(); }
24
25 ScratchReg &operator=(const ScratchReg &) = delete;
26 ScratchReg &operator=(ScratchReg &&) noexcept;
27
28 /// Whether a register is currently allocated.
29 bool has_reg() const noexcept { return reg.valid(); }
30
31 /// The allocated register.
32 AsmReg cur_reg() const noexcept {
33 assert(has_reg());
34 return reg;
35 }
36
37 /// Allocate a specific register.
38 AsmReg alloc_specific(AsmReg reg) noexcept;
39
40 /// Allocate a general-purpose register.
41 AsmReg alloc_gp() noexcept { return alloc(Config::GP_BANK); }
42
43 /// Allocate register in the specified bank. Does nothing if it holds a
44 /// register in the specified bank. Evicts a register if required.
45 AsmReg alloc(RegBank bank) noexcept;
46
47 /// Release register, marking it as unused; returns the register.
48 AsmReg release() noexcept {
49 AsmReg res = reg;
50 reset();
51 return res;
52 }
53
54 /// Deallocate register.
55 void reset() noexcept;
56
57 /// @internal Forcefully change register without updating register file.
58 /// Avoid.
59 void force_set_reg(AsmReg reg) noexcept { this->reg = reg; }
60};
61
62template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
64 ScratchReg &&other) noexcept {
65 this->compiler = other.compiler;
66 this->reg = other.reg;
67 other.reg = AsmReg::make_invalid();
68}
69
70template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
71typename CompilerBase<Adaptor, Derived, Config>::ScratchReg &
72 CompilerBase<Adaptor, Derived, Config>::ScratchReg::operator=(
73 ScratchReg &&other) noexcept {
74 if (this == &other) {
75 return *this;
76 }
77
78 reset();
79 this->compiler = other.compiler;
80 this->reg = other.reg;
81 other.reg = AsmReg::make_invalid();
82 return *this;
83}
84
85template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
86typename CompilerBase<Adaptor, Derived, Config>::AsmReg
88 AsmReg reg) noexcept {
89 assert(compiler->may_change_value_state());
90 assert(!compiler->register_file.is_fixed(reg));
91 reset();
92
93 if (compiler->register_file.is_used(reg)) {
94 compiler->evict_reg(reg);
95 }
96
97 compiler->register_file.mark_used(reg, INVALID_VAL_LOCAL_IDX, 0);
98 compiler->register_file.mark_clobbered(reg);
99 compiler->register_file.mark_fixed(reg);
100 this->reg = reg;
101 return reg;
102}
103
104template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
105CompilerBase<Adaptor, Derived, Config>::AsmReg
107 RegBank bank) noexcept {
108 assert(compiler->may_change_value_state());
109
110 auto &reg_file = compiler->register_file;
111 if (!reg.invalid()) {
112 assert(bank == reg_file.reg_bank(reg));
113 return reg;
114 }
115
116 reg = compiler->select_reg(bank, /*exclusion_mask=*/0);
117 reg_file.mark_used(reg, INVALID_VAL_LOCAL_IDX, 0);
118 reg_file.mark_clobbered(reg);
119 reg_file.mark_fixed(reg);
120 return reg;
121}
122
123template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
125 if (reg.invalid()) {
126 return;
127 }
128
129 compiler->register_file.unmark_fixed(reg);
130 compiler->register_file.unmark_used(reg);
131 reg = AsmReg::make_invalid();
132}
133} // namespace tpde
Owned unspillable and unevictable temporary register with RAII semantics.
AsmReg release() noexcept
Release register, marking it as unused; returns the register.
ScratchReg(CompilerBase *compiler)
Constructor, no register.
void reset() noexcept
Deallocate register.
AsmReg cur_reg() const noexcept
The allocated register.
AsmReg alloc_gp() noexcept
Allocate a general-purpose register.
AsmReg alloc(RegBank bank) noexcept
Allocate register in the specified bank.
bool has_reg() const noexcept
Whether a register is currently allocated.
void reset()
Reset any leftover data from the previous compilation such that it will not affect the next compilati...