TPDE
Loading...
Searching...
No Matches
AssignmentPartRef.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
6#include "tpde/RegisterFile.hpp"
7#include "tpde/ValueAssignment.hpp"
8
9#include <cstdint>
10
11namespace tpde {
12
13class AssignmentPartRef {
14 ValueAssignment *va;
15 uint32_t part;
16
17 // note for how parts are structured:
18 // |15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00|
19 // | | PS |RV| |IM|FA| bank | reg_id |
20 // | full_reg_id |
21 //
22 // PS: 1 << PS = part size (TODO(ts): maybe swap with NP so that it can be
23 // extracted easier?)
24 // RV: Register Valid
25 // IM: Is the current register value not on the stack?
26 // FA: Is the assignment a fixed assignment?
27 //
28 // RV + IM form a unit describing the following states:
29 // - !RV + IM: value uninitialized (default state)
30 // - RV + IM: register dirty, must be spilled before evicting
31 // - !RV + !IM: register invalid, value stored only in stack slot
32 // - RV + !IM: register identical to value in stack slot
33
34public:
35 AssignmentPartRef(ValueAssignment *va, const uint32_t part)
36 : va(va), part(part) {}
37
38 void reset() {
39 va->parts[part] = 0;
40 set_modified(true);
41 }
42
43 ValueAssignment *assignment() { return va; }
44
45 [[nodiscard]] RegBank bank() const {
46 return RegBank((va->parts[part] >> 5) & 0b111);
47 }
48
49 void set_bank(const RegBank bank) {
50 assert(bank.id() <= 0b111);
51 auto data = va->parts[part] & ~0b1110'0000;
52 data |= bank.id() << 5;
53 va->parts[part] = data;
54 }
55
56 [[nodiscard]] Reg get_reg() const { return Reg(va->parts[part] & 0xFF); }
57
58 void set_reg(Reg reg) {
59 assert(bank().id() == ((reg.id() >> 5) & 0b111));
60 va->parts[part] = (va->parts[part] & 0xFF00) | reg.id();
61 }
62
63 [[nodiscard]] bool modified() const {
64 return (va->parts[part] & (1u << 9)) != 0;
65 }
66
67 void set_modified(const bool val) {
68 if (val) {
69 va->parts[part] |= (1u << 9);
70 } else {
71 va->parts[part] &= ~(1u << 9);
72 }
73 }
74
75 [[nodiscard]] bool fixed_assignment() const {
76 return (va->parts[part] & (1u << 8)) != 0;
77 }
78
79 void set_fixed_assignment(const bool val) {
80 if (val) {
81 va->parts[part] |= (1u << 8);
82 } else {
83 va->parts[part] &= ~(1u << 8);
84 }
85 }
86
87 [[nodiscard]] bool variable_ref() const { return va->variable_ref; }
88
89 [[nodiscard]] bool is_stack_variable() const { return va->stack_variable; }
90
91 [[nodiscard]] bool register_valid() const {
92 return (va->parts[part] & (1u << 11)) != 0;
93 }
94
95 void set_register_valid(const bool val) {
96 if (val) {
97 va->parts[part] |= (1u << 11);
98 } else {
99 va->parts[part] &= ~(1u << 11);
100 }
101 }
102
103 [[nodiscard]] bool stack_valid() const {
104 return (va->parts[part] & (1u << 9)) == 0;
105 }
106
107 void set_stack_valid() { set_modified(false); }
108
109 [[nodiscard]] uint32_t part_size() const {
110 return 1u << ((va->parts[part] >> 12) & 0b111);
111 }
112
113 void set_part_size(const uint32_t part_size) {
114 assert((part_size & (part_size - 1)) == 0);
115 const uint32_t shift = util::cnt_tz(part_size);
116 assert(shift <= 0b111);
117 auto data = va->parts[part] & ~(0b111 << 12);
118 data |= (shift << 12);
119 va->parts[part] = data;
120 }
121
122 [[nodiscard]] int32_t frame_off() const {
123 assert(!variable_ref());
124 assert(va->frame_off != 0 && "attempt to access uninitialized stack slot");
125 return va->frame_off + part_off();
126 }
127
128 [[nodiscard]] int32_t variable_stack_off() const {
129 assert(variable_ref() && va->stack_variable);
130 assert(part == 0);
131 return va->frame_off;
132 }
133
134 [[nodiscard]] uint32_t variable_ref_data() const {
135 assert(variable_ref() && !va->stack_variable);
136 assert(part == 0);
137 return va->var_ref_custom_idx;
138 }
139
140 [[nodiscard]] uint32_t part_off() const { return va->max_part_size * part; }
141};
142
143} // namespace tpde