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;
22
23 ~ScratchReg() { reset(); }
24
25 ScratchReg &operator=(const ScratchReg &) = delete;
26 ScratchReg &operator=(ScratchReg &&);
27
28 /// Whether a register is currently allocated.
29 bool has_reg() const { return reg.valid(); }
30
31 /// The allocated register.
32 AsmReg cur_reg() const {
33 assert(has_reg());
34 return reg;
35 }
36
37 /// Allocate a specific register.
38 AsmReg alloc_specific(AsmReg reg);
39
40 /// Allocate a general-purpose register.
41 AsmReg alloc_gp() { 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);
46
47 /// Release register, marking it as unused; returns the register.
48 AsmReg release() {
49 AsmReg res = reg;
50 reset();
51 return res;
52 }
53
54 /// Deallocate register.
55 void reset();
56
57 /// @internal Forcefully change register without updating register file.
58 /// Avoid.
59 void force_set_reg(AsmReg reg) { this->reg = reg; }
60};
61
62template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
64 ScratchReg &&other) {
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) {
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>
88 AsmReg reg) {
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 assert(compiler->may_change_value_state());
108
109 auto &reg_file = compiler->register_file;
110 if (!reg.invalid()) {
111 assert(bank == reg_file.reg_bank(reg));
112 return reg;
113 }
114
115 reg = compiler->select_reg(bank);
116 reg_file.mark_used(reg, INVALID_VAL_LOCAL_IDX, 0);
117 reg_file.mark_clobbered(reg);
118 reg_file.mark_fixed(reg);
119 return reg;
120}
121
122template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
124 if (reg.invalid()) {
125 return;
126 }
127
128 compiler->register_file.unmark_fixed(reg);
129 compiler->register_file.unmark_used(reg);
130 reg = AsmReg::make_invalid();
131}
132} // namespace tpde
Owned unspillable and unevictable temporary register with RAII semantics.
void reset()
Deallocate register.
AsmReg cur_reg() const
The allocated register.
ScratchReg(CompilerBase *compiler)
Constructor, no register.
AsmReg release()
Release register, marking it as unused; returns the register.
bool has_reg() const
Whether a register is currently allocated.
AsmReg alloc(RegBank bank)
Allocate register in the specified bank.
AsmReg alloc_gp()
Allocate a general-purpose register.
void reset()
Reset any leftover data from the previous compilation such that it will not affect the next compilati...