Proteus
Programmable JIT compilation and optimization for C/C++ using LLVM
Loading...
Searching...
No Matches
Var.hpp
Go to the documentation of this file.
1#ifndef PROTEUS_FRONTEND_VAR_HPP
2#define PROTEUS_FRONTEND_VAR_HPP
3
4#include "proteus/Error.h"
7#include <llvm/IR/IRBuilder.h>
8#include <llvm/IR/Module.h>
9#include <type_traits>
10
11namespace proteus {
12
13class FuncBase;
14
15using namespace llvm;
16
17template <typename From, typename To>
18Value *convert(IRBuilderBase IRB, Value *V) {
19 static_assert(std::is_arithmetic_v<From>, "From type must be arithmetic");
20 static_assert(std::is_arithmetic_v<To>, "To type must be arithmetic");
21
22 if constexpr (std::is_same_v<From, To>) {
23 return V;
24 } else if constexpr (std::is_integral_v<From> &&
25 std::is_floating_point_v<To>) {
26 Type *TargetType = TypeMap<To>::get(V->getContext());
27 if constexpr (std::is_signed_v<From>) {
28 return IRB.CreateSIToFP(V, TargetType);
29 } else {
30 return IRB.CreateUIToFP(V, TargetType);
31 }
32 } else if constexpr (std::is_floating_point_v<From> &&
33 std::is_integral_v<To>) {
34 Type *TargetType = TypeMap<To>::get(V->getContext());
35 if constexpr (std::is_signed_v<To>) {
36 return IRB.CreateFPToSI(V, TargetType);
37 } else {
38 return IRB.CreateFPToUI(V, TargetType);
39 }
40 } else if constexpr (std::is_integral_v<From> && std::is_integral_v<To>) {
41 Type *TargetType = TypeMap<To>::get(V->getContext());
42 Type *ValType = V->getType();
43
44 if (ValType->getIntegerBitWidth() < TargetType->getIntegerBitWidth()) {
45 if constexpr (std::is_signed_v<From>) {
46 return IRB.CreateSExt(V, TargetType);
47 } else {
48 return IRB.CreateZExt(V, TargetType);
49 }
50 } else if (ValType->getIntegerBitWidth() >
51 TargetType->getIntegerBitWidth()) {
52 return IRB.CreateTrunc(V, TargetType);
53 } else {
54 return V;
55 }
56 } else if constexpr (std::is_floating_point_v<From> &&
57 std::is_floating_point_v<To>) {
58 Type *TargetType = TypeMap<To>::get(V->getContext());
59 Type *ValType = V->getType();
60
61 if (ValType->getScalarSizeInBits() < TargetType->getScalarSizeInBits()) {
62 return IRB.CreateFPExt(V, TargetType);
63 }
64 if (ValType->getScalarSizeInBits() > TargetType->getScalarSizeInBits()) {
65 return IRB.CreateFPTrunc(V, TargetType);
66 }
67 return V;
68 }
69
70 PROTEUS_FATAL_ERROR("Unsupported conversion");
71}
72
73// Mixin that owns storage and exposes common helpers for Var specializations
74template <typename StorageT> struct VarStorageOwner {
76 std::unique_ptr<StorageT> Storage = nullptr;
77
78 VarStorageOwner(std::unique_ptr<StorageT> StorageIn, FuncBase &FnIn)
80
82
83 // Storage accessor helpers
84 Value *loadValue() const { return Storage->loadValue(); }
85
86 void storeValue(Value *Val) { Storage->storeValue(Val); }
87
88 Value *getSlot() const { return Storage->getSlot(); }
89 Type *getValueType() const { return Storage->getValueType(); }
90 Type *getAllocatedType() const { return Storage->getAllocatedType(); }
91};
92
93// Primary template declaration
94template <typename T, typename = void> struct Var;
95
96// Specialization for arithmetic types
97template <typename T>
98struct Var<T, std::enable_if_t<std::is_arithmetic_v<T>>>
99 : public VarStorageOwner<VarStorage> {
100 using ValueType = T;
101 using ElemType = T;
102
103 Var(std::unique_ptr<VarStorage> Storage, FuncBase &Fn)
104 : VarStorageOwner<VarStorage>(std::move(Storage), Fn) {}
105
106 // // Conversion constructor
107 // // TODO: Add an is_convertible check.
108 template <typename U> Var(const Var<U> &V);
109
111 Storage = V.Storage->clone();
112 }
113
115 std::swap(Storage, V.Storage);
116 }
117
118 Var &operator=(Var &&V);
119
120 // Assignment operators
121 Var &operator=(const Var &V);
122
123 template <typename U> Var &operator=(const Var<U> &V);
124
125 template <typename U> Var &operator=(const U &ConstValue);
126
127 Var<std::add_pointer_t<T>> getAddress();
128
129 // Arithmetic operators
130 template <typename U>
132
133 template <typename U>
134 std::enable_if_t<std::is_arithmetic_v<U>, Var<std::common_type_t<T, U>>>
135 operator+(const U &ConstValue) const;
136
137 template <typename U>
139
140 template <typename U>
141 std::enable_if_t<std::is_arithmetic_v<U>, Var<std::common_type_t<T, U>>>
142 operator-(const U &ConstValue) const;
143
144 template <typename U>
146
147 template <typename U>
148 std::enable_if_t<std::is_arithmetic_v<U>, Var<std::common_type_t<T, U>>>
149 operator*(const U &ConstValue) const;
150
151 template <typename U>
153
154 template <typename U>
155 std::enable_if_t<std::is_arithmetic_v<U>, Var<std::common_type_t<T, U>>>
156 operator/(const U &ConstValue) const;
157
158 template <typename U>
160
161 template <typename U>
162 std::enable_if_t<std::is_arithmetic_v<U>, Var<std::common_type_t<T, U>>>
163 operator%(const U &ConstValue) const;
164
165 // Unary operators
166 Var operator-() const;
167 Var<bool> operator!() const;
168
169 // Compound assignment operators
170 template <typename U> Var &operator+=(const Var<U> &Other);
171
172 template <typename U> Var &operator+=(const U &ConstValue);
173
174 template <typename U> Var &operator-=(const Var<U> &Other);
175
176 template <typename U> Var &operator-=(const U &ConstValue);
177
178 template <typename U> Var &operator*=(const Var<U> &Other);
179
180 template <typename U> Var &operator*=(const U &ConstValue);
181
182 template <typename U> Var &operator/=(const Var<U> &Other);
183
184 template <typename U> Var &operator/=(const U &ConstValue);
185
186 template <typename U> Var &operator%=(const Var<U> &Other);
187
188 template <typename U> Var &operator%=(const U &ConstValue);
189
190 // Comparison operators
191 template <typename U>
192 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
193 operator>(const Var<U> &Other) const;
194
195 template <typename U>
196 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
197 operator>=(const Var<U> &Other) const;
198
199 template <typename U>
200 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
201 operator<(const Var<U> &Other) const;
202
203 template <typename U>
204 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
205 operator<=(const Var<U> &Other) const;
206
207 template <typename U>
208 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
209 operator==(const Var<U> &Other) const;
210
211 template <typename U>
212 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
213 operator!=(const Var<U> &Other) const;
214
215 template <typename U>
216 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
217 operator>(const U &ConstValue) const;
218
219 template <typename U>
220 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
221 operator>=(const U &ConstValue) const;
222
223 template <typename U>
224 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
225 operator<(const U &ConstValue) const;
226
227 template <typename U>
228 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
229 operator<=(const U &ConstValue) const;
230
231 template <typename U>
232 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
233 operator==(const U &ConstValue) const;
234
235 template <typename U>
236 std::enable_if_t<std::is_arithmetic_v<U>, Var<bool>>
237 operator!=(const U &ConstValue) const;
238};
239
240// Specialization for array types
241template <typename T>
242struct Var<T, std::enable_if_t<std::is_array_v<T>>>
243 : public VarStorageOwner<ArrayStorage> {
244 using ValueType = T;
245 using ElemType = std::remove_extent_t<T>;
246
247 Var(std::unique_ptr<ArrayStorage> Storage, FuncBase &Fn)
248 : VarStorageOwner<ArrayStorage>(std::move(Storage), Fn) {}
249
250 Var<ElemType> operator[](size_t Index);
251
252 template <typename IdxT>
253 std::enable_if_t<std::is_integral_v<IdxT>, Var<ElemType>>
255
257};
258
259// Specialization for pointer types
260template <typename T>
261struct Var<T, std::enable_if_t<std::is_pointer_v<T>>>
262 : public VarStorageOwner<PointerStorage> {
263 using ValueType = T;
264 using ElemType = std::remove_pointer_t<T>;
265
266 Var(std::unique_ptr<PointerStorage> Storage, FuncBase &Fn)
267 : VarStorageOwner<PointerStorage>(std::move(Storage), Fn) {}
268
269 // Load/store the pointer value itself from/to the pointer slot.
270 Value *loadPointer() const { return this->Storage->loadPointer(); }
271 void storePointer(Value *Ptr) { this->Storage->storePointer(Ptr); }
272
273 Var<ElemType> operator[](size_t Index);
274
275 template <typename IdxT>
276 std::enable_if_t<std::is_arithmetic_v<IdxT>, Var<ElemType>>
278
280
282
283 template <typename OffsetT>
284 std::enable_if_t<std::is_arithmetic_v<OffsetT>,
286 operator+(const Var<OffsetT> &Offset) const;
287
288 template <typename OffsetT>
289 std::enable_if_t<std::is_arithmetic_v<OffsetT>,
291 operator+(OffsetT Offset) const;
292
293 template <typename OffsetT>
294 friend std::enable_if_t<std::is_arithmetic_v<OffsetT>,
296 operator+(OffsetT Offset, const Var &Ptr) {
297 return Ptr + Offset;
298 }
299};
300
301// Non-member arithmetic operators for Var
302template <typename T, typename U>
303std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>,
305operator+(const T &ConstValue, const Var<U> &Var);
306
307template <typename T, typename U>
308std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>,
310operator-(const T &ConstValue, const Var<U> &V);
311
312template <typename T, typename U>
313std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>,
315operator*(const T &ConstValue, const Var<U> &V);
316
317template <typename T, typename U>
318std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>,
320operator/(const T &ConstValue, const Var<U> &V);
321
322template <typename T, typename U>
323std::enable_if_t<std::is_arithmetic_v<T> && std::is_arithmetic_v<U>,
325operator%(const T &ConstValue, const Var<U> &V);
326
327} // namespace proteus
328
329#endif // PROTEUS_FRONTEND_VAR_HPP
#define PROTEUS_FATAL_ERROR(x)
Definition Error.h:7
Definition VarStorage.hpp:72
Definition Func.hpp:40
Definition VarStorage.hpp:46
Definition VarStorage.hpp:10
virtual std::unique_ptr< VarStorage > clone() const =0
Definition Helpers.h:138
Definition StorageCache.cpp:24
std::enable_if_t< std::is_arithmetic_v< T > &&std::is_arithmetic_v< U >, Var< std::common_type_t< T, U > > > operator-(const T &ConstValue, const Var< U > &V)
Definition Func.hpp:1180
Value * convert(IRBuilderBase IRB, Value *V)
Definition Var.hpp:18
std::enable_if_t< std::is_arithmetic_v< T > &&std::is_arithmetic_v< U >, Var< std::common_type_t< T, U > > > operator*(const T &ConstValue, const Var< U > &V)
Definition Func.hpp:1189
T getRuntimeConstantValue(void *Arg)
Definition CompilerInterfaceRuntimeConstantInfo.h:114
std::enable_if_t< std::is_arithmetic_v< T > &&std::is_arithmetic_v< U >, Var< std::common_type_t< T, U > > > operator+(const T &ConstValue, const Var< U > &V)
Definition Func.hpp:1172
std::enable_if_t< std::is_arithmetic_v< T > &&std::is_arithmetic_v< U >, Var< std::common_type_t< T, U > > > operator/(const T &ConstValue, const Var< U > &V)
Definition Func.hpp:1197
std::enable_if_t< std::is_arithmetic_v< T > &&std::is_arithmetic_v< U >, Var< std::common_type_t< T, U > > > operator%(const T &ConstValue, const Var< U > &V)
Definition Func.hpp:1205
Definition Hashing.hpp:147
Definition TypeMap.hpp:13
Definition Var.hpp:74
Type * getValueType() const
Definition Var.hpp:89
Type * getAllocatedType() const
Definition Var.hpp:90
std::unique_ptr< StorageT > Storage
Definition Var.hpp:76
Value * getSlot() const
Definition Var.hpp:88
Value * loadValue() const
Definition Var.hpp:84
VarStorageOwner(FuncBase &FnIn)
Definition Var.hpp:81
VarStorageOwner(std::unique_ptr< StorageT > StorageIn, FuncBase &FnIn)
Definition Var.hpp:78
void storeValue(Value *Val)
Definition Var.hpp:86
FuncBase & Fn
Definition Var.hpp:75
Var(std::unique_ptr< VarStorage > Storage, FuncBase &Fn)
Definition Var.hpp:103
Var< std::add_pointer_t< ValueType > > getAddress() const =delete
Var(std::unique_ptr< ArrayStorage > Storage, FuncBase &Fn)
Definition Var.hpp:247
std::remove_extent_t< T > ElemType
Definition Var.hpp:245
std::enable_if_t< std::is_integral_v< IdxT >, Var< ElemType > > operator[](const Var< IdxT > &Index)
std::remove_pointer_t< T > ElemType
Definition Var.hpp:264
friend std::enable_if_t< std::is_arithmetic_v< OffsetT >, Var< T, std::enable_if_t< std::is_pointer_v< T > > > > operator+(OffsetT Offset, const Var &Ptr)
Definition Var.hpp:296
void storePointer(Value *Ptr)
Definition Var.hpp:271
Var(std::unique_ptr< PointerStorage > Storage, FuncBase &Fn)
Definition Var.hpp:266
std::enable_if_t< std::is_arithmetic_v< IdxT >, Var< ElemType > > operator[](const Var< IdxT > &Index)
Definition Var.hpp:94