TPDE
Loading...
Searching...
No Matches
GenericValuePart.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3#pragma once
4
5#include <array>
6#include <cstring>
7#include <span>
8
9namespace tpde {
10
11template <IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
12struct CompilerBase<Adaptor, Derived, Config>::GenericValuePart {
13 struct Expr {
14 std::variant<AsmReg, ScratchReg> base;
15 std::variant<AsmReg, ScratchReg> index;
16 i64 scale;
17 i64 disp;
18
19 explicit Expr() : base{AsmReg::make_invalid()}, scale{0}, disp{0} {}
20
21 explicit Expr(AsmReg base, i64 disp = 0)
22 : base(base), scale(0), disp(disp) {}
23
24 explicit Expr(ScratchReg &&base, i64 disp = 0)
25 : base(std::move(base)), scale(0), disp(disp) {}
26
27 AsmReg base_reg() const noexcept {
28 if (std::holds_alternative<AsmReg>(base)) {
29 return std::get<AsmReg>(base);
30 }
31 return std::get<ScratchReg>(base).cur_reg();
32 }
33
34 [[nodiscard]] bool has_base() const noexcept {
35 if (std::holds_alternative<AsmReg>(base)) {
36 return std::get<AsmReg>(base).valid();
37 }
38 return true;
39 }
40
41 AsmReg index_reg() const noexcept {
42 assert(scale != 0 && "index_reg() called on invalid index");
43 assert((scale != 1 || has_base()) &&
44 "Expr with unscaled index must have base");
45 if (std::holds_alternative<AsmReg>(index)) {
46 return std::get<AsmReg>(index);
47 }
48 return std::get<ScratchReg>(index).cur_reg();
49 }
50
51 [[nodiscard]] bool has_index() const noexcept { return scale != 0; }
52 };
53
54 // TODO(ts): evaluate the use of std::variant
55 // TODO(ts): I don't like the ValuePartRefs but we also don't want to
56 // force all the operands into registers at the start of the encoding...
57 std::variant<std::monostate, ValuePartRef, ScratchReg, Expr> state;
58
59 GenericValuePart() = default;
60
61 GenericValuePart(GenericValuePart &) = delete;
62
63 GenericValuePart(GenericValuePart &&other) noexcept {
64 state = std::move(other.state);
65 other.state = std::monostate{};
66 }
67
68 GenericValuePart &operator=(const GenericValuePart &) noexcept = delete;
69
70 GenericValuePart &operator=(GenericValuePart &&other) noexcept {
71 if (this == &other) {
72 return *this;
73 }
74 state = std::move(other.state);
75 other.state = std::monostate{};
76 return *this;
77 }
78
79 // salvaging
80 GenericValuePart(ScratchReg &&reg) noexcept {
81 assert(reg.has_reg());
82 state = std::move(reg);
83 }
84
85 // salvaging
86 GenericValuePart(ValuePartRef &&ref) noexcept : state{std::move(ref)} {}
87
88 GenericValuePart(Expr expr) noexcept {
89 ScratchReg *base_scratch = std::get_if<ScratchReg>(&expr.base);
90 if (base_scratch && !expr.has_index() && expr.disp == 0) {
91 state = std::move(*base_scratch);
92 } else {
93 state = std::move(expr);
94 }
95 }
96
97 [[nodiscard]] bool is_expr() const noexcept {
98 return std::holds_alternative<Expr>(state);
99 }
100
101 [[nodiscard]] bool is_imm() const noexcept {
102 auto *ptr = std::get_if<ValuePartRef>(&state);
103 return ptr && ptr->is_const();
104 }
105
106 u32 imm_size() const noexcept {
107 assert(is_imm());
108 return val_ref().part_size();
109 }
110
111 [[nodiscard]] u64 imm64() const noexcept {
112 assert(imm_size() <= 8);
113 return val_ref().const_data()[0];
114 }
115
116 [[nodiscard]] const ValuePartRef &val_ref() const noexcept {
117 return std::get<ValuePartRef>(state);
118 }
119
120 [[nodiscard]] ValuePartRef &val_ref() noexcept {
121 return std::get<ValuePartRef>(state);
122 }
123
124 void reset() noexcept { state = std::monostate{}; }
125};
126} // namespace tpde