OpenVDB  12.1.0
LegacyIR.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: Apache-2.0
3 
4 /// @file codegen/LegacyIR.h
5 ///
6 /// @authors Nick Avramoussis
7 ///
8 /// @brief Legacy IR utilities for LLVM_VERSION_MAJOR <= 15
9 ///
10 
11 #ifndef OPENVDB_AX_CODEGEN_LEGACY_IR_HAS_BEEN_INCLUDED
12 #define OPENVDB_AX_CODEGEN_LEGACY_IR_HAS_BEEN_INCLUDED
13 
14 #include <llvm/Config/llvm-config.h>
15 
16 #if LLVM_VERSION_MAJOR <= 15
17 
18 #include "Types.h"
19 #include "Utils.h"
20 #include <openvdb/version.h>
21 #include <openvdb/util/Assert.h>
22 #include <llvm/IR/IRBuilder.h>
23 
24 namespace openvdb {
26 namespace OPENVDB_VERSION_NAME {
27 
28 namespace ax {
29 namespace codegen {
30 
32 inline auto ir_load(llvm::IRBuilder<>& B, llvm::Value* ptr, const char* Name = "")
33 {
34  OPENVDB_ASSERT(ptr);
35  OPENVDB_ASSERT(ptr->getType()->isPointerTy());
36  return B.CreateLoad(ptr->getType()->getPointerElementType(), ptr, Name);
37 }
38 
40 inline auto ir_gep(llvm::IRBuilder<>& B,
41  llvm::Value* ptr, llvm::ArrayRef<llvm::Value*> IdxList, const char* Name = "")
42 {
43  OPENVDB_ASSERT(ptr);
44  OPENVDB_ASSERT(ptr->getType()->getScalarType());
45  OPENVDB_ASSERT(ptr->getType()->getScalarType()->isPointerTy());
46  return B.CreateGEP(ptr->getType()->getScalarType()->getPointerElementType(),
47  ptr, IdxList, Name);
48 #
49 }
50 
52 inline auto ir_constgep2_64(llvm::IRBuilder<>& B,
53  llvm::Value* ptr, uint64_t Idx0, uint64_t Idx1, const char* Name = "")
54 {
55  OPENVDB_ASSERT(ptr);
56  OPENVDB_ASSERT(ptr->getType()->getScalarType());
57  OPENVDB_ASSERT(ptr->getType()->getScalarType()->isPointerTy());
58  return B.CreateConstGEP2_64(
59  ptr->getType()->getScalarType()->getPointerElementType(), ptr, Idx0,
60  Idx1, Name);
61 }
62 
64 inline auto ir_constinboundsgep2_64(llvm::IRBuilder<>& B,
65  llvm::Value* ptr, uint64_t Idx0, uint64_t Idx1, const char* Name = "")
66 {
67  OPENVDB_ASSERT(ptr);
68  OPENVDB_ASSERT(ptr->getType()->getScalarType());
69  OPENVDB_ASSERT(ptr->getType()->getScalarType()->isPointerTy());
70  return B.CreateConstInBoundsGEP2_64(
71  ptr->getType()->getScalarType()->getPointerElementType(), ptr, Idx0,
72  Idx1, Name);
73 }
74 
75 /// @brief Return the base llvm value which is being pointed to through
76 /// any number of layered pointers.
77 /// @note This function does not check for cyclical pointer dependencies
78 ///
79 /// @param type A llvm pointer type to traverse
80 ///
82 inline llvm::Type*
83 getBaseContainedType(llvm::Type* const type)
84 {
85  llvm::Type* elementType = type;
86  while (elementType->isPointerTy()) {
87  elementType = elementType->getContainedType(0);
88  }
89  return elementType;
90 }
91 
92 /// @brief Casts an array to another array of equal size but of a different element
93 /// type. Both source and target array element types must be scalar types.
94 /// The source array llvm Value should be a pointer to the array to cast.
95 ///
96 /// @param ptrToArray A llvm value which is a pointer to a llvm array
97 /// @param targetElementType The target llvm scalar type to convert each element
98 /// of the input array
99 /// @param builder The current llvm IRBuilder
100 ///
102 inline llvm::Value*
103 arrayCast(llvm::Value* ptrToArray,
104  llvm::Type* targetElementType,
105  llvm::IRBuilder<>& builder)
106 {
107  OPENVDB_ASSERT(targetElementType && (targetElementType->isIntegerTy() ||
108  targetElementType->isFloatingPointTy()) &&
109  "Target element type is not a scalar type");
110  OPENVDB_ASSERT(ptrToArray && ptrToArray->getType()->isPointerTy() &&
111  "Input to arrayCast is not a pointer type.");
112 
113  llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0);
114  OPENVDB_ASSERT(arrayType && llvm::isa<llvm::ArrayType>(arrayType));
115 
116  // getArrayElementType() calls getContainedType(0)
117  llvm::Type* sourceElementType = arrayType->getArrayElementType();
118  OPENVDB_ASSERT(sourceElementType && (sourceElementType->isIntegerTy() ||
119  sourceElementType->isFloatingPointTy()) &&
120  "Source element type is not a scalar type");
121 
122  if (sourceElementType == targetElementType) return ptrToArray;
123 
124  CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
125 
126  const size_t elementSize = arrayType->getArrayNumElements();
127  llvm::Value* targetArray =
128  insertStaticAlloca(builder,
129  llvm::ArrayType::get(targetElementType, elementSize));
130 
131  for (size_t i = 0; i < elementSize; ++i) {
132  llvm::Value* target = builder.CreateConstGEP2_64(targetArray->getType()->getScalarType()->getPointerElementType(), targetArray, 0, i);
133  llvm::Value* source = builder.CreateConstGEP2_64(ptrToArray->getType()->getScalarType()->getPointerElementType(), ptrToArray, 0, i);
134  source = builder.CreateLoad(source->getType()->getPointerElementType(), source);
135  source = llvmCastFunction(builder, source, targetElementType);
136  builder.CreateStore(source, target);
137  }
138 
139  return targetArray;
140 }
141 
142 /// @brief Unpack a particular element of an array and return a pointer to that element
143 /// The provided llvm Value is expected to be a pointer to an array
144 ///
145 /// @param ptrToArray A llvm value which is a pointer to a llvm array
146 /// @param index The index at which to access the array
147 /// @param builder The current llvm IRBuilder
148 ///
150 inline llvm::Value*
151 arrayIndexUnpack(llvm::Value* ptrToArray,
152  const int16_t index,
153  llvm::IRBuilder<>& builder)
154 {
155  return builder.CreateConstGEP2_64(ptrToArray->getType()->getScalarType()->getPointerElementType(), ptrToArray, 0, index);
156 }
157 
158 /// @brief Unpack an array type into llvm Values which represent all its elements
159 /// The provided llvm Value is expected to be a pointer to an array
160 /// If loadElements is true, values will store loaded llvm values instead
161 /// of pointers to the array elements
162 ///
163 /// @param ptrToArray A llvm value which is a pointer to a llvm array
164 /// @param values A vector of llvm values where to store the array elements
165 /// @param builder The current llvm IRBuilder
166 /// @param loadElements Whether or not to load each array element into a register
167 ///
169 inline void
170 arrayUnpack(llvm::Value* ptrToArray,
171  std::vector<llvm::Value*>& values,
172  llvm::IRBuilder<>& builder,
173  const bool loadElements = false)
174 {
175  const size_t elements =
176  ptrToArray->getType()->getContainedType(0)->getArrayNumElements();
177 
178  values.reserve(elements);
179  for (size_t i = 0; i < elements; ++i) {
180  llvm::Value* value = builder.CreateConstGEP2_64(ptrToArray->getType()->getScalarType()->getPointerElementType(), ptrToArray, 0, i);
181  if (loadElements) value = builder.CreateLoad(value->getType()->getPointerElementType(), value);
182  values.push_back(value);
183  }
184 }
185 
186 /// @brief Unpack the first three elements of an array.
187 /// The provided llvm Value is expected to be a pointer to an array
188 /// @note The elements are note loaded
189 ///
190 /// @param ptrToArray A llvm value which is a pointer to a llvm array
191 /// @param value1 The first array value
192 /// @param value2 The second array value
193 /// @param value3 The third array value
194 /// @param builder The current llvm IRBuilder
195 ///
197 inline void
198 array3Unpack(llvm::Value* ptrToArray,
199  llvm::Value*& value1,
200  llvm::Value*& value2,
201  llvm::Value*& value3,
202  llvm::IRBuilder<>& builder)
203 {
204  OPENVDB_ASSERT(ptrToArray && ptrToArray->getType()->isPointerTy() &&
205  "Input to array3Unpack is not a pointer type.");
206 
207  value1 = builder.CreateConstGEP2_64(ptrToArray->getType()->getScalarType()->getPointerElementType(), ptrToArray, 0, 0);
208  value2 = builder.CreateConstGEP2_64(ptrToArray->getType()->getScalarType()->getPointerElementType(), ptrToArray, 0, 1);
209  value3 = builder.CreateConstGEP2_64(ptrToArray->getType()->getScalarType()->getPointerElementType(), ptrToArray, 0, 2);
210 }
211 
212 /// @brief Pack three values into a new array and return a pointer to the
213 /// newly allocated array. If the values are of a mismatching type,
214 /// the highets order type is uses, as defined by typePrecedence. All
215 /// llvm values are expected to a be a loaded scalar type
216 ///
217 /// @param value1 The first array value
218 /// @param value2 The second array value
219 /// @param value3 The third array value
220 /// @param builder The current llvm IRBuilder
221 ///
223 inline llvm::Value*
224 array3Pack(llvm::Value* value1,
225  llvm::Value* value2,
226  llvm::Value* value3,
227  llvm::IRBuilder<>& builder)
228 {
229  llvm::Type* type = typePrecedence(value1->getType(), value2->getType());
230  type = typePrecedence(type, value3->getType());
231 
232  value1 = arithmeticConversion(value1, type, builder);
233  value2 = arithmeticConversion(value2, type, builder);
234  value3 = arithmeticConversion(value3, type, builder);
235 
236  llvm::Type* vectorType = llvm::ArrayType::get(type, 3);
237  llvm::Value* vector = insertStaticAlloca(builder, vectorType);
238 
239  llvm::Value* e1 = builder.CreateConstGEP2_64(vector->getType()->getScalarType()->getPointerElementType(), vector, 0, 0);
240  llvm::Value* e2 = builder.CreateConstGEP2_64(vector->getType()->getScalarType()->getPointerElementType(), vector, 0, 1);
241  llvm::Value* e3 = builder.CreateConstGEP2_64(vector->getType()->getScalarType()->getPointerElementType(), vector, 0, 2);
242 
243  builder.CreateStore(value1, e1);
244  builder.CreateStore(value2, e2);
245  builder.CreateStore(value3, e3);
246 
247  return vector;
248 }
249 
250 /// @brief Pack a loaded llvm scalar value into a new array of a specified
251 /// size and return a pointer to the newly allocated array. Each element
252 /// of the new array will have the value of the given scalar
253 ///
254 /// @param value The uniform scalar llvm value to pack into the array
255 /// @param builder The current llvm IRBuilder
256 /// @param size The size of the newly allocated array
257 ///
259 inline llvm::Value*
260 arrayPack(llvm::Value* value,
261  llvm::IRBuilder<>& builder,
262  const size_t size = 3)
263 {
264  OPENVDB_ASSERT(value && (value->getType()->isIntegerTy() ||
265  value->getType()->isFloatingPointTy()) &&
266  "value type is not a scalar type");
267 
268  llvm::Type* type = value->getType();
269  llvm::Value* array =
270  insertStaticAlloca(builder,
271  llvm::ArrayType::get(type, size));
272 
273  for (size_t i = 0; i < size; ++i) {
274  llvm::Value* element = builder.CreateConstGEP2_64(array->getType()->getScalarType()->getPointerElementType(), array, 0, i);
275  builder.CreateStore(value, element);
276  }
277 
278  return array;
279 }
280 
281 /// @brief Pack a vector of loaded llvm scalar values into a new array of
282 /// equal size and return a pointer to the newly allocated array.
283 ///
284 /// @param values A vector of loaded llvm scalar values to pack
285 /// @param builder The current llvm IRBuilder
286 ///
288 inline llvm::Value*
289 arrayPack(const std::vector<llvm::Value*>& values,
290  llvm::IRBuilder<>& builder)
291 {
292  llvm::Type* type = values.front()->getType();
293  llvm::Value* array = insertStaticAlloca(builder,
294  llvm::ArrayType::get(type, values.size()));
295 
296  size_t idx = 0;
297  for (llvm::Value* const& value : values) {
298  llvm::Value* element = builder.CreateConstGEP2_64(array->getType()->getScalarType()->getPointerElementType(), array, 0, idx++);
299  builder.CreateStore(value, element);
300  }
301 
302  return array;
303 }
304 
305 /// @brief Pack a vector of loaded llvm scalar values into a new array of
306 /// equal size and return a pointer to the newly allocated array.
307 /// arrayPackCast first checks all the contained types in values
308 /// and casts all types to the highest order type present. All llvm
309 /// values in values are expected to be loaded scalar types
310 ///
311 /// @param values A vector of loaded llvm scalar values to pack
312 /// @param builder The current llvm IRBuilder
313 ///
315 inline llvm::Value*
316 arrayPackCast(std::vector<llvm::Value*>& values,
317  llvm::IRBuilder<>& builder)
318 {
319  // get the highest order type present
320 
321  llvm::Type* type = LLVMType<bool>::get(builder.getContext());
322  for (llvm::Value* const& value : values) {
323  type = typePrecedence(type, value->getType());
324  }
325 
326  // convert all to this type
327 
328  for (llvm::Value*& value : values) {
329  value = arithmeticConversion(value, type, builder);
330  }
331 
332  return arrayPack(values, builder);
333 }
334 
336 inline llvm::Value*
337 scalarToMatrix(llvm::Value* scalar,
338  llvm::IRBuilder<>& builder,
339  const size_t dim = 3)
340 {
341  OPENVDB_ASSERT(scalar && (scalar->getType()->isIntegerTy() ||
342  scalar->getType()->isFloatingPointTy()) &&
343  "value type is not a scalar type");
344 
345  llvm::Type* type = scalar->getType();
346  llvm::Value* array =
347  insertStaticAlloca(builder,
348  llvm::ArrayType::get(type, dim*dim));
349 
350  llvm::Value* zero = llvmConstant(0, type);
351  for (size_t i = 0; i < dim*dim; ++i) {
352  llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero);
353  llvm::Value* element = builder.CreateConstGEP2_64(array->getType()->getScalarType()->getPointerElementType(), array, 0, i);
354  builder.CreateStore(m, element);
355  }
356 
357  return array;
358 }
359 
360 } // namespace codegen
361 } // namespace ax
362 } // namespace OPENVDB_VERSION_NAME
363 } // namespace openvdb
364 
365 #endif // LLVM_VERSION_MAJOR <= 15
366 
367 #endif // OPENVDB_AX_CODEGEN_LEGACY_IR_HAS_BEEN_INCLUDED
368 
#define OPENVDB_DEPRECATED
Definition: Platform.h:170
llvm::Value * arrayIndexUnpack(llvm::Value *ptrToArray, const int16_t index, llvm::IRBuilder<> &builder)
Unpack a particular element of an array and return a pointer to that element The provided llvm Value ...
Definition: LegacyIR.h:151
llvm::Value * arrayPack(const std::vector< llvm::Value * > &values, llvm::IRBuilder<> &builder)
Pack a vector of loaded llvm scalar values into a new array of equal size and return a pointer to the...
Definition: LegacyIR.h:289
void array3Unpack(llvm::Value *ptrToArray, llvm::Value *&value1, llvm::Value *&value2, llvm::Value *&value3, llvm::IRBuilder<> &builder)
Unpack the first three elements of an array. The provided llvm Value is expected to be a pointer to a...
Definition: LegacyIR.h:198
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Type *)> CastFunction
Definition: Utils.h:38
LLVM type mapping from pod types.
Definition: Types.h:67
Consolidated llvm types for most supported types.
llvm::Value * scalarToMatrix(llvm::Value *scalar, llvm::IRBuilder<> &builder, const size_t dim=3)
Definition: LegacyIR.h:337
auto ir_gep(llvm::IRBuilder<> &B, llvm::Value *ptr, llvm::ArrayRef< llvm::Value * > IdxList, const char *Name="")
Definition: LegacyIR.h:40
llvm::Type * getBaseContainedType(llvm::Type *const type)
Return the base llvm value which is being pointed to through any number of layered pointers...
Definition: LegacyIR.h:83
llvm::Value * arrayCast(llvm::Value *ptrToArray, llvm::Type *targetElementType, llvm::IRBuilder<> &builder)
Casts an array to another array of equal size but of a different element type. Both source and target...
Definition: LegacyIR.h:103
#define OPENVDB_ASSERT(X)
Definition: Assert.h:41
llvm::Value * insertStaticAlloca(llvm::IRBuilder<> &B, llvm::Type *type, llvm::Value *size=nullptr)
Insert a stack allocation at the beginning of the current function of the provided type and size...
Definition: Utils.h:117
llvm::Value * array3Pack(llvm::Value *value1, llvm::Value *value2, llvm::Value *value3, llvm::IRBuilder<> &builder)
Pack three values into a new array and return a pointer to the newly allocated array. If the values are of a mismatching type, the highets order type is uses, as defined by typePrecedence. All llvm values are expected to a be a loaded scalar type.
Definition: LegacyIR.h:224
Definition: Exceptions.h:13
auto ir_constinboundsgep2_64(llvm::IRBuilder<> &B, llvm::Value *ptr, uint64_t Idx0, uint64_t Idx1, const char *Name="")
Definition: LegacyIR.h:64
auto ir_constgep2_64(llvm::IRBuilder<> &B, llvm::Value *ptr, uint64_t Idx0, uint64_t Idx1, const char *Name="")
Definition: LegacyIR.h:52
llvm::Constant * llvmConstant(const T t, llvm::Type *type)
Returns an llvm Constant holding a scalar value.
Definition: Types.h:360
llvm::Value * arithmeticConversion(llvm::Value *value, llvm::Type *targetType, llvm::IRBuilder<> &builder)
Casts a scalar llvm Value to a target scalar llvm Type. Returns the cast scalar value of type targetT...
Definition: Utils.h:484
llvm::Value * arrayPackCast(std::vector< llvm::Value * > &values, llvm::IRBuilder<> &builder)
Pack a vector of loaded llvm scalar values into a new array of equal size and return a pointer to the...
Definition: LegacyIR.h:316
auto ir_load(llvm::IRBuilder<> &B, llvm::Value *ptr, const char *Name="")
Definition: LegacyIR.h:32
CastFunction llvmArithmeticConversion(const llvm::Type *const sourceType, const llvm::Type *const targetType, const std::string &twine="")
Returns a CastFunction which represents the corresponding instruction to convert a source llvm Type t...
Definition: Utils.h:220
std::string Name
Definition: Name.h:19
Utility code generation methods for performing various llvm operations.
llvm::Type * typePrecedence(llvm::Type *const typeA, llvm::Type *const typeB)
Returns the highest order type from two LLVM Scalar types.
Definition: Utils.h:173
void arrayUnpack(llvm::Value *ptrToArray, std::vector< llvm::Value * > &values, llvm::IRBuilder<> &builder, const bool loadElements=false)
Unpack an array type into llvm Values which represent all its elements The provided llvm Value is exp...
Definition: LegacyIR.h:170
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:218