5#include "tpde/ValueAssignment.hpp"
11template <IRAdaptor Adaptor,
typename Derived, CompilerConfig Config>
12struct CompilerBase<Adaptor, Derived, Config>::ValueRef {
13 struct AssignmentData {
16 ValLocalIdx local_idx;
17 ValueAssignment *assignment;
19 static_assert(ValRefSpecialStruct<AssignmentData>);
23 Derived::ValRefSpecial s;
28 ValueRef(CompilerBase *compiler) noexcept
29 : state{AssignmentData()}, compiler(compiler) {}
31 ValueRef(CompilerBase *compiler, ValLocalIdx local_idx) noexcept
32 : state{AssignmentData{
33 .local_idx = local_idx,
34 .assignment = compiler->val_assignment(local_idx),
36 }, compiler(compiler) {
37 assert(!state.a.assignment->pending_free &&
"access of free'd assignment");
41 if (!variable_ref()) {
42 const auto &liveness =
43 compiler->analyzer.liveness_info(state.a.local_idx);
44 assert(liveness.last >= compiler->cur_block_idx &&
45 "ref-counted value used outside of its live range");
46 assert(state.a.assignment->references_left != 0);
47 if (state.a.assignment->references_left == 1 && !liveness.last_full) {
48 assert(liveness.last == compiler->cur_block_idx &&
49 "liveness of non-last-full value must end at last use");
56 }
else if (state.a.assignment->references_left <= 1 &&
57 !state.a.assignment->delay_free) {
64 template <
typename... T>
65 ValueRef(CompilerBase *compiler, T &&...args) noexcept
66 : state{.s =
typename Derived::ValRefSpecial(std::forward<T>(args)...)},
68 assert(state.a.mode >= 4);
71 explicit ValueRef(
const ValueRef &) =
delete;
73 ValueRef(ValueRef &&other) noexcept
74 : state{other.state}, compiler(other.compiler) {
75 other.state.a = AssignmentData{};
78 ~ValueRef() noexcept {
reset(); }
80 ValueRef &operator=(
const ValueRef &) =
delete;
82 ValueRef &operator=(ValueRef &&other)
noexcept {
87 assert(compiler == other.compiler);
88 this->state = other.state;
89 other.state.a.mode = 0;
93 bool has_assignment() const noexcept {
return state.a.mode < 4; }
95 [[nodiscard]] ValueAssignment *assignment() const noexcept {
96 assert(has_assignment());
97 assert(state.a.assignment !=
nullptr);
98 return state.a.assignment;
103 void disown() noexcept {
104 if (has_assignment()) {
109 ValLocalIdx local_idx() const noexcept {
110 assert(has_assignment());
111 return state.a.local_idx;
114 ValuePartRef part(
unsigned part)
noexcept TPDE_LIFETIMEBOUND {
115 if (has_assignment()) {
117 compiler, local_idx(), state.a.assignment, part, state.a.mode == 2};
119 return compiler->derived()->val_part_ref_special(state.s, part);
123 void reset() noexcept;
125 bool variable_ref() const noexcept {
126 assert(has_assignment());
127 return state.a.assignment->variable_ref;
131template <IRAdaptor Adaptor,
typename Derived, CompilerConfig Config>
132void CompilerBase<Adaptor, Derived, Config>::ValueRef::reset() noexcept {
133 if (state.a.mode == 1 || state.a.mode == 2) {
136 assert(!state.a.assignment->pending_free &&
"access of free'd assignment");
138 auto &ref_count = state.a.assignment->references_left;
139 assert(ref_count != 0);
140 if (--ref_count == 0) {
141 ValLocalIdx local_idx = state.a.local_idx;
142 if (!state.a.assignment->delay_free) {
143 compiler->free_assignment(local_idx);
146 TPDE_LOG_TRACE(
"Delay freeing assignment for value {}",
147 static_cast<u32
>(local_idx));
148 const auto &liveness = compiler->analyzer.liveness_info(local_idx);
149 auto &free_list_head =
150 compiler->assignments.delayed_free_lists[u32(liveness.last)];
151 state.a.assignment->next_delayed_free_entry = free_list_head;
153 state.a.assignment->pending_free =
true;
155 free_list_head = local_idx;
161 state.a.assignment =
nullptr;
162 state.a.local_idx = INVALID_VAL_LOCAL_IDX;
CompilerBase(Adaptor *adaptor)
Initialize a CompilerBase, should be called by the derived classes.