Jlm
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 
14 namespace jlm::llvm
15 {
16 
29 {
30 public:
31  ~GetElementPtrOperation() noexcept override;
32 
34  const std::vector<std::shared_ptr<const rvsdg::BitType>> & indexTypes,
35  std::shared_ptr<const rvsdg::Type> pointeeType)
37  pointeeType_(std::move(pointeeType))
38  {}
39 
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]] const rvsdg::Type &
54  getPointeeType() const noexcept
55  {
56  return *pointeeType_.get();
57  }
58 
65  static std::optional<std::vector<uint64_t>>
66  tryGetConstantIndices(const rvsdg::Node & node) noexcept;
67 
76  [[nodiscard]] static rvsdg::Node::InputConstIteratorRange
77  indices(const rvsdg::Node & node) noexcept
78  {
80 
81  const auto firstIndex = node.input(1);
82  JLM_ASSERT(is<rvsdg::BitType>(firstIndex->Type()));
83  return { rvsdg::Input::ConstIterator(firstIndex), rvsdg::Input::ConstIterator(nullptr) };
84  }
85 
92  [[nodiscard]] static size_t
93  numIndices(const rvsdg::Node & node) noexcept
94  {
95  JLM_ASSERT(is<GetElementPtrOperation>(node.GetOperation()));
96  return node.ninputs() - 1; // Subtract base address
97  }
98 
107  [[nodiscard]] static rvsdg::Input &
109  {
110  JLM_ASSERT(is<GetElementPtrOperation>(node.GetOperation()));
111  const auto baseAddress = node.input(0);
112  JLM_ASSERT(is<PointerType>(baseAddress->Type()));
113  return *baseAddress;
114  }
115 
124  [[nodiscard]] static const rvsdg::Input &
126  {
127  JLM_ASSERT(is<GetElementPtrOperation>(node.GetOperation()));
128  const auto baseAddress = node.input(0);
129  JLM_ASSERT(is<PointerType>(baseAddress->Type()));
130  return *baseAddress;
131  }
132 
142  static std::unique_ptr<ThreeAddressCode>
144  const Variable * baseAddress,
145  const std::vector<const Variable *> & offsets,
146  std::shared_ptr<const rvsdg::Type> pointeeType)
147  {
148  checkPointerType(baseAddress->type());
149  auto offsetTypes = checkAndExtractIndexTypes<const Variable>(offsets);
150 
151  auto operation = std::make_unique<GetElementPtrOperation>(offsetTypes, std::move(pointeeType));
152  std::vector operands(1, baseAddress);
153  operands.insert(operands.end(), offsets.begin(), offsets.end());
154 
155  return ThreeAddressCode::create(std::move(operation), operands);
156  }
157 
167  static rvsdg::SimpleNode &
169  rvsdg::Output & baseAddress,
170  const std::vector<rvsdg::Output *> & indices,
171  std::shared_ptr<const rvsdg::Type> pointeeType)
172  {
173  checkPointerType(*baseAddress.Type());
174  const auto indicesTypes = checkAndExtractIndexTypes<rvsdg::Output>(indices);
175 
176  std::vector operands(1, &baseAddress);
177  operands.insert(operands.end(), indices.begin(), indices.end());
178 
179  return rvsdg::CreateOpNode<GetElementPtrOperation>(
180  operands,
181  indicesTypes,
182  std::move(pointeeType));
183  }
184 
194  static rvsdg::Output *
196  rvsdg::Output * baseAddress,
197  const std::vector<rvsdg::Output *> & indices,
198  std::shared_ptr<const rvsdg::Type> pointeeType)
199  {
200  return createNode(*baseAddress, indices, std::move(pointeeType)).output(0);
201  }
202 
203 private:
204  static void
206  {
207  if (!is<PointerType>(type))
208  {
209  throw util::Error("Expected pointer type.");
210  }
211  }
212 
213  template<class T>
214  static std::vector<std::shared_ptr<const rvsdg::BitType>>
215  checkAndExtractIndexTypes(const std::vector<T *> & indices)
216  {
217  std::vector<std::shared_ptr<const rvsdg::BitType>> offsetTypes;
218  for (const auto & offset : indices)
219  {
220  if (auto offsetType = std::dynamic_pointer_cast<const rvsdg::BitType>(offset->Type()))
221  {
222  offsetTypes.emplace_back(std::move(offsetType));
223  continue;
224  }
225 
226  throw util::Error("Expected bitstring type.");
227  }
228 
229  return offsetTypes;
230  }
231 
232  static std::vector<std::shared_ptr<const rvsdg::Type>>
233  createOperandTypes(const std::vector<std::shared_ptr<const rvsdg::BitType>> & indexTypes)
234  {
235  std::vector<std::shared_ptr<const rvsdg::Type>> types({ PointerType::Create() });
236  types.insert(types.end(), indexTypes.begin(), indexTypes.end());
237 
238  return types;
239  }
240 
241  std::shared_ptr<const rvsdg::Type> pointeeType_;
242 };
243 
244 }
245 
246 #endif
std::string debug_string() const override
static std::optional< std::vector< uint64_t > > tryGetConstantIndices(const rvsdg::Node &node) noexcept
GetElementPtrOperation(GetElementPtrOperation &&other) noexcept=default
static size_t numIndices(const rvsdg::Node &node) noexcept
GetElementPtrOperation(const GetElementPtrOperation &other)=default
static rvsdg::Output * create(rvsdg::Output *baseAddress, const std::vector< rvsdg::Output * > &indices, std::shared_ptr< const rvsdg::Type > pointeeType)
std::shared_ptr< const rvsdg::Type > pointeeType_
static rvsdg::Input & getBaseAddressInput(rvsdg::Node &node)
bool operator==(const Operation &other) const noexcept override
static rvsdg::SimpleNode & createNode(rvsdg::Output &baseAddress, const std::vector< rvsdg::Output * > &indices, std::shared_ptr< const rvsdg::Type > pointeeType)
static void checkPointerType(const rvsdg::Type &type)
static rvsdg::Node::InputConstIteratorRange indices(const rvsdg::Node &node) noexcept
~GetElementPtrOperation() noexcept override
static std::vector< std::shared_ptr< const rvsdg::BitType > > checkAndExtractIndexTypes(const std::vector< T * > &indices)
const rvsdg::Type & getPointeeType() const noexcept
static const rvsdg::Input & getBaseAddressInput(const rvsdg::Node &node)
std::unique_ptr< Operation > copy() const override
static std::vector< std::shared_ptr< const rvsdg::Type > > createOperandTypes(const std::vector< std::shared_ptr< const rvsdg::BitType >> &indexTypes)
static std::unique_ptr< ThreeAddressCode > createTAC(const Variable *baseAddress, const std::vector< const Variable * > &offsets, std::shared_ptr< const rvsdg::Type > pointeeType)
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition: tac.hpp:135
const jlm::rvsdg::Type & type() const noexcept
Definition: variable.hpp:56
virtual const Operation & GetOperation() const noexcept=0
NodeInput * input(size_t index) const noexcept
Definition: node.hpp:615
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
NodeOutput * output(size_t index) const noexcept
Definition: simple-node.hpp:88
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.
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition: node.hpp:1049