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 : state{std::move(reg)} {
81 assert(std::get<ScratchReg>(state).has_reg());
82 }
83
84 // salvaging
85 GenericValuePart(ValuePartRef &&ref) noexcept : state{std::move(ref)} {}
86
87 GenericValuePart(Expr expr) noexcept : state{std::move(expr)} {}
88
89 [[nodiscard]] bool is_expr() const noexcept {
90 return std::holds_alternative<Expr>(state);
91 }
92
93 [[nodiscard]] bool is_imm() const noexcept {
94 auto *ptr = std::get_if<ValuePartRef>(&state);
95 return ptr && ptr->is_const();
96 }
97
98 u32 imm_size() const noexcept {
99 assert(is_imm());
100 return val_ref().part_size();
101 }
102
103 [[nodiscard]] u64 imm64() const noexcept {
104 assert(imm_size() <= 8);
105 return val_ref().const_data()[0];
106 }
107
108 [[nodiscard]] const ValuePartRef &val_ref() const noexcept {
109 return std::get<ValuePartRef>(state);
110 }
111
112 [[nodiscard]] ValuePartRef &val_ref() noexcept {
113 return std::get<ValuePartRef>(state);
114 }
115
116 void reset() noexcept { state = std::monostate{}; }
117};
118} // namespace tpde