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
Owned unspillable and unevictable temporary register with RAII semantics.
The base class for the compiler.
void reset()
Reset any leftover data from the previous compilation such that it will not affect the next compilati...
ValueRef val_ref(IRValueRef value) noexcept
Get a using reference to a value.