Jlm
Loading...
Searching...
No Matches
GetElementPtr.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
6#ifndef JLM_LLVM_IR_OPERATORS_GETELEMENTPTR_HPP
7#define JLM_LLVM_IR_OPERATORS_GETELEMENTPTR_HPP
8
9#include <jlm/llvm/ir/tac.hpp>
10#include <jlm/llvm/ir/types.hpp>
13
14namespace jlm::llvm
15{
16
25{
26public:
27 ~GetElementPtrOperation() noexcept override;
28
29private:
31 const std::shared_ptr<const rvsdg::Type> & baseAddressType,
32 const std::vector<std::shared_ptr<const rvsdg::Type>> & indexTypes,
33 std::shared_ptr<const rvsdg::Type> gepType,
34 std::shared_ptr<const rvsdg::Type> resultType)
35 : SimpleOperation(createOperandTypes(baseAddressType, indexTypes), { resultType }),
36 gepType_(std::move(gepType))
37 {}
38
39public:
41
42 GetElementPtrOperation(GetElementPtrOperation && other) noexcept = default;
43
44 bool
45 operator==(const Operation & other) const noexcept override;
46
47 [[nodiscard]] std::string
48 debug_string() const override;
49
50 [[nodiscard]] std::unique_ptr<Operation>
51 copy() const override;
52
53 [[nodiscard]] std::shared_ptr<const rvsdg::Type>
54 getPointeeType() const noexcept
55 {
56 return gepType_;
57 }
58
62 struct Constant
63 {
67 [[nodiscard]] int64_t
68 getOffsetInBytes() const noexcept;
69
70 std::shared_ptr<const rvsdg::Type> pointeeType;
71 std::vector<uint64_t> indices{};
72 };
73
81 [[nodiscard]] static std::optional<Constant>
82 tryGetAsConstant(const rvsdg::SimpleNode & gepNode);
83
92 [[nodiscard]] static rvsdg::Node::InputConstIteratorRange
93 indices(const rvsdg::Node & node) noexcept
94 {
96
97 const auto firstIndex = node.input(1);
98 JLM_ASSERT(is<rvsdg::BitType>(firstIndex->Type()));
99 return { rvsdg::Input::ConstIterator(firstIndex), rvsdg::Input::ConstIterator(nullptr) };
100 }
101
108 [[nodiscard]] static size_t
109 numIndices(const rvsdg::Node & node) noexcept
110 {
111 JLM_ASSERT(is<GetElementPtrOperation>(node.GetOperation()));
112 return node.ninputs() - 1; // Subtract base address
113 }
114
123 [[nodiscard]] static rvsdg::Input &
125 {
126 JLM_ASSERT(is<GetElementPtrOperation>(node.GetOperation()));
127 const auto baseAddress = node.input(0);
128 JLM_ASSERT(is<PointerType>(baseAddress->Type()));
129 return *baseAddress;
130 }
131
140 [[nodiscard]] static const rvsdg::Input &
142 {
143 JLM_ASSERT(is<GetElementPtrOperation>(node.GetOperation()));
144 const auto baseAddress = node.input(0);
145 JLM_ASSERT(is<PointerType>(baseAddress->Type()));
146 return *baseAddress;
147 }
148
158 static std::unique_ptr<ThreeAddressCode>
160 const Variable * baseAddress,
161 const std::vector<const Variable *> & offsets,
162 std::shared_ptr<const rvsdg::Type> gepType)
163 {
164 auto indexTypes = extractIndexTypes<const Variable>(offsets);
165 auto operation = createOperation(baseAddress->Type(), indexTypes, std::move(gepType));
166
167 std::vector operands(1, baseAddress);
168 operands.insert(operands.end(), offsets.begin(), offsets.end());
169
170 // FIXME: Validate structural integrity of GEP type
171 return ThreeAddressCode::create(std::move(operation), operands);
172 }
173
174 static std::unique_ptr<GetElementPtrOperation>
176 const std::shared_ptr<const rvsdg::Type> & baseAddressType,
177 const std::vector<std::shared_ptr<const rvsdg::Type>> & indexTypes,
178 const std::shared_ptr<const rvsdg::Type> & gepType)
179 {
180 // 1. Validate that the base address is a pointer or vector of pointers
181 checkBaseAddressType(*baseAddressType);
182
183 // 2. Validate that the index types are integers or vector of integers
184 checkIndexTypes(indexTypes);
185
186 // FIXME: Validate vector components align such as uniform lane count, etc.
187
188 auto resultType = getResultType(baseAddressType, indexTypes);
189
190 return std::unique_ptr<GetElementPtrOperation>(
191 new GetElementPtrOperation(baseAddressType, indexTypes, gepType, std::move(resultType)));
192 }
193
203 static rvsdg::SimpleNode &
205 rvsdg::Output & baseAddress,
206 const std::vector<rvsdg::Output *> & indices,
207 const std::shared_ptr<const rvsdg::Type> & gepType)
208 {
209 std::vector operands({ &baseAddress });
210 operands.insert(operands.end(), indices.begin(), indices.end());
211
212 auto indexTypes = extractIndexTypes(indices);
213 auto gepOperation = createOperation(baseAddress.Type(), indexTypes, gepType);
214
215 // 4. Validate structural integrity of GEP type
216 checkIndexedType(gepType, indices);
217
218 return rvsdg::SimpleNode::Create(*baseAddress.region(), std::move(gepOperation), operands);
219 }
220
230 static rvsdg::Output *
232 rvsdg::Output * baseAddress,
233 const std::vector<rvsdg::Output *> & indices,
234 std::shared_ptr<const rvsdg::Type> gepType)
235 {
236 return createNode(*baseAddress, indices, std::move(gepType)).output(0);
237 }
238
249 static std::optional<std::vector<rvsdg::Output *>>
251 const GetElementPtrOperation & operation,
252 const std::vector<rvsdg::Output *> & operands);
253
254private:
255 static std::shared_ptr<const rvsdg::Type>
257 const std::shared_ptr<const rvsdg::Type> & gepType,
258 const std::vector<rvsdg::Output *> & indices);
259
260 static void
262 const std::shared_ptr<const rvsdg::Type> & gepType,
263 const std::vector<rvsdg::Output *> & indices)
264 {
265 const auto indexedType = getIndexedType(gepType, indices);
266 if (indexedType == nullptr)
267 {
268 throw std::logic_error("Invalid GetElementPtrOperation indices for type!");
269 }
270 }
271
272 static void
274 {
275 const auto isPointerType = is<PointerType>(type);
276 const auto vectorType = dynamic_cast<const VectorType *>(&type);
277 const auto isVectorOfPointerType = vectorType && is<PointerType>(vectorType->Type());
278
279 if (!isPointerType && !isVectorOfPointerType)
280 {
281 throw std::logic_error("Expected pointer type.");
282 }
283 }
284
285 static void
286 checkIndexTypes(const std::vector<std::shared_ptr<const rvsdg::Type>> & indexTypes)
287 {
288 for (auto & indexType : indexTypes)
289 {
290 if (!is<rvsdg::BitType>(indexType) && !isVectorOf<rvsdg::BitType>(*indexType))
291 {
292 throw std::logic_error("Expected bitstring type.");
293 }
294 }
295 }
296
297 static std::shared_ptr<const rvsdg::Type>
299 const std::shared_ptr<const rvsdg::Type> & baseAddressType,
300 const std::vector<std::shared_ptr<const rvsdg::Type>> & indexTypes)
301 {
302 const auto resultType = PointerType::Create();
303
304 // FIXME: Fix vector type such that it can uniformly handle fixed and scalable vector types
305 // similar to LLVM
306 if (const auto fixedVectorType =
307 std::dynamic_pointer_cast<const FixedVectorType>(baseAddressType))
308 {
309 return FixedVectorType::Create(resultType, fixedVectorType->size());
310 }
311 if (const auto scalableVectorType =
312 std::dynamic_pointer_cast<const ScalableVectorType>(baseAddressType))
313 {
314 return ScalableVectorType::Create(resultType, scalableVectorType->size());
315 }
316
317 for (auto & indexType : indexTypes)
318 {
319 if (const auto fixedVectorType = std::dynamic_pointer_cast<const FixedVectorType>(indexType))
320 {
321 return FixedVectorType::Create(resultType, fixedVectorType->size());
322 }
323 if (const auto scalableVectorType =
324 std::dynamic_pointer_cast<const ScalableVectorType>(indexType))
325 {
326 return ScalableVectorType::Create(resultType, scalableVectorType->size());
327 }
328 }
329
330 return resultType;
331 }
332
333 template<class T>
334 static std::vector<std::shared_ptr<const rvsdg::Type>>
335 extractIndexTypes(const std::vector<T *> & indices)
336 {
337 std::vector<std::shared_ptr<const rvsdg::Type>> indexTypes;
338 for (const auto & index : indices)
339 {
340 indexTypes.emplace_back(std::move(index->Type()));
341 }
342
343 return indexTypes;
344 }
345
346 static std::vector<std::shared_ptr<const rvsdg::Type>>
348 std::shared_ptr<const rvsdg::Type> baseAddressType,
349 const std::vector<std::shared_ptr<const rvsdg::Type>> & indexTypes)
350 {
351 std::vector types({ std::move(baseAddressType) });
352 types.insert(types.end(), indexTypes.begin(), indexTypes.end());
353
354 return types;
355 }
356
357 std::shared_ptr<const rvsdg::Type> gepType_;
358};
359
360}
361
362#endif
static std::shared_ptr< const FixedVectorType > Create(std::shared_ptr< const rvsdg::Type > type, size_t size)
Definition types.hpp:413
static rvsdg::Input & getBaseAddressInput(rvsdg::Node &node)
std::string debug_string() const override
static std::shared_ptr< const rvsdg::Type > getResultType(const std::shared_ptr< const rvsdg::Type > &baseAddressType, const std::vector< std::shared_ptr< const rvsdg::Type > > &indexTypes)
GetElementPtrOperation(GetElementPtrOperation &&other) noexcept=default
static std::shared_ptr< const rvsdg::Type > getIndexedType(const std::shared_ptr< const rvsdg::Type > &gepType, const std::vector< rvsdg::Output * > &indices)
static size_t numIndices(const rvsdg::Node &node) noexcept
static std::vector< std::shared_ptr< const rvsdg::Type > > createOperandTypes(std::shared_ptr< const rvsdg::Type > baseAddressType, const std::vector< std::shared_ptr< const rvsdg::Type > > &indexTypes)
static std::unique_ptr< GetElementPtrOperation > createOperation(const std::shared_ptr< const rvsdg::Type > &baseAddressType, const std::vector< std::shared_ptr< const rvsdg::Type > > &indexTypes, const std::shared_ptr< const rvsdg::Type > &gepType)
static void checkBaseAddressType(const rvsdg::Type &type)
static rvsdg::Output * create(rvsdg::Output *baseAddress, const std::vector< rvsdg::Output * > &indices, std::shared_ptr< const rvsdg::Type > gepType)
std::shared_ptr< const rvsdg::Type > gepType_
GetElementPtrOperation(const GetElementPtrOperation &other)=default
static void checkIndexedType(const std::shared_ptr< const rvsdg::Type > &gepType, const std::vector< rvsdg::Output * > &indices)
static std::vector< std::shared_ptr< const rvsdg::Type > > extractIndexTypes(const std::vector< T * > &indices)
std::shared_ptr< const rvsdg::Type > getPointeeType() const noexcept
static const rvsdg::Input & getBaseAddressInput(const rvsdg::Node &node)
bool operator==(const Operation &other) const noexcept override
static rvsdg::Node::InputConstIteratorRange indices(const rvsdg::Node &node) noexcept
static std::optional< Constant > tryGetAsConstant(const rvsdg::SimpleNode &gepNode)
~GetElementPtrOperation() noexcept override
static rvsdg::SimpleNode & createNode(rvsdg::Output &baseAddress, const std::vector< rvsdg::Output * > &indices, const std::shared_ptr< const rvsdg::Type > &gepType)
static void checkIndexTypes(const std::vector< std::shared_ptr< const rvsdg::Type > > &indexTypes)
static std::optional< std::vector< rvsdg::Output * > > normalizeIdempotent(const GetElementPtrOperation &operation, const std::vector< rvsdg::Output * > &operands)
static std::unique_ptr< ThreeAddressCode > createTAC(const Variable *baseAddress, const std::vector< const Variable * > &offsets, std::shared_ptr< const rvsdg::Type > gepType)
std::unique_ptr< Operation > copy() const override
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static std::shared_ptr< const ScalableVectorType > Create(std::shared_ptr< const rvsdg::Type > type, size_t size)
Definition types.hpp:438
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition tac.hpp:135
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition variable.hpp:62
NodeInput * input(size_t index) const noexcept
Definition node.hpp:615
virtual const Operation & GetOperation() const noexcept=0
rvsdg::Region * region() const noexcept
Definition node.cpp:151
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
static SimpleNode & Create(Region &region, std::unique_ptr< Operation > operation, const std::vector< rvsdg::Output * > &operands)
NodeOutput * output(size_t index) const noexcept
SimpleOperation(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > operands, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > results)
Definition operation.hpp:61
#define JLM_ASSERT(x)
Definition common.hpp:16
Global memory state passed between functions.
std::shared_ptr< const rvsdg::Type > pointeeType