Jlm
AggregateOperations.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2026 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_LLVM_IR_OPERATORS_AGGREGATEOPERATIONS_HPP
7 #define JLM_LLVM_IR_OPERATORS_AGGREGATEOPERATIONS_HPP
8 
9 #include <jlm/llvm/ir/tac.hpp>
10 #include <jlm/llvm/ir/types.hpp>
11 #include <jlm/llvm/ir/variable.hpp>
13 
14 namespace jlm::llvm
15 {
16 
24 {
25  typedef std::vector<unsigned>::const_iterator const_iterator;
26 
27 public:
28  ~ExtractValueOperation() noexcept override;
29 
31  const std::shared_ptr<const rvsdg::Type> & aggtype,
32  const std::vector<unsigned> & indices)
33  : SimpleOperation({ aggtype }, { dsttype(aggtype, indices) }),
34  indices_(indices)
35  {
36  if (indices.empty())
37  throw util::Error("expected at least one index.");
38  }
39 
40  bool
41  operator==(const Operation & other) const noexcept override;
42 
43  [[nodiscard]] std::string
44  debug_string() const override;
45 
46  [[nodiscard]] std::unique_ptr<Operation>
47  copy() const override;
48 
50  begin() const
51  {
52  return indices_.begin();
53  }
54 
56  end() const
57  {
58  return indices_.end();
59  }
60 
61  const rvsdg::Type &
62  type() const noexcept
63  {
64  return *argument(0);
65  }
66 
67  static std::unique_ptr<ThreeAddressCode>
68  create(const Variable * aggregate, const std::vector<unsigned> & indices)
69  {
70  auto op = std::make_unique<ExtractValueOperation>(aggregate->Type(), indices);
71  return ThreeAddressCode::create(std::move(op), { aggregate });
72  }
73 
74 private:
75  static std::vector<std::shared_ptr<const rvsdg::Type>>
76  dsttype(const std::shared_ptr<const rvsdg::Type> & aggtype, const std::vector<unsigned> & indices)
77  {
78  std::shared_ptr<const rvsdg::Type> type = aggtype;
79  for (const auto & index : indices)
80  {
81  if (auto st = std::dynamic_pointer_cast<const StructType>(type))
82  {
83  if (index >= st->numElements())
84  throw util::Error("extractvalue index out of bound.");
85 
86  type = st->getElementType(index);
87  }
88  else if (auto at = std::dynamic_pointer_cast<const ArrayType>(type))
89  {
90  if (index >= at->nelements())
91  throw util::Error("extractvalue index out of bound.");
92 
93  type = at->GetElementType();
94  }
95  else
96  throw util::Error("expected struct or array type.");
97  }
98 
99  return { type };
100  }
101 
102  std::vector<unsigned> indices_{};
103 };
104 
112 {
113 public:
114  ~InsertValueOperation() noexcept override;
115 
116 private:
118  const std::shared_ptr<const rvsdg::Type> & aggregateType,
119  const std::shared_ptr<const rvsdg::Type> & valueType,
120  std::vector<unsigned> indices)
121  : SimpleOperation({ aggregateType, valueType }, { aggregateType }),
122  indices_(std::move(indices))
123  {}
124 
125 public:
126  [[nodiscard]] const std::shared_ptr<const rvsdg::Type> &
127  getAggregateType() const noexcept
128  {
129  return argument(0);
130  }
131 
132  [[nodiscard]] const std::shared_ptr<const rvsdg::Type> &
133  getValueType() const noexcept
134  {
135  return argument(1);
136  }
137 
138  [[nodiscard]] const std::vector<unsigned> &
139  getIndices() const noexcept
140  {
141  return indices_;
142  }
143 
144  bool
145  operator==(const Operation & other) const noexcept override;
146 
147  std::string
148  debug_string() const override;
149 
150  [[nodiscard]] std::unique_ptr<Operation>
151  copy() const override;
152 
153  static std::unique_ptr<InsertValueOperation>
155  const std::shared_ptr<const rvsdg::Type> & aggregateType,
156  const std::shared_ptr<const rvsdg::Type> & valueType,
157  std::vector<unsigned> indices)
158  {
159  checkOperandTypes(aggregateType, valueType, indices);
160  return std::unique_ptr<InsertValueOperation>(
161  new InsertValueOperation(aggregateType, valueType, std::move(indices)));
162  }
163 
164  static rvsdg::SimpleNode &
166  rvsdg::Output & aggregateOperand,
167  rvsdg::Output & valueOperand,
168  std::vector<unsigned> indices)
169  {
170  auto insertValueOperation =
171  create(aggregateOperand.Type(), valueOperand.Type(), std::move(indices));
173  *aggregateOperand.region(),
174  std::move(insertValueOperation),
175  { &aggregateOperand, &valueOperand });
176  }
177 
178  static std::unique_ptr<ThreeAddressCode>
180  const Variable & aggregateOperand,
181  const Variable & valueOperand,
182  std::vector<unsigned> indices)
183  {
184  auto insertValueOperation =
185  create(aggregateOperand.Type(), valueOperand.Type(), std::move(indices));
187  std::move(insertValueOperation),
188  { &aggregateOperand, &valueOperand });
189  }
190 
191 private:
192  static void
194  const std::shared_ptr<const rvsdg::Type> & aggregateType,
195  const std::shared_ptr<const rvsdg::Type> & valueType,
196  const std::vector<unsigned> & indices)
197  {
198  if (indices.empty())
199  {
200  throw std::runtime_error("indices are empty.");
201  }
202 
203  auto type = aggregateType;
204  for (const auto & index : indices)
205  {
206  if (const auto structType = std::dynamic_pointer_cast<const StructType>(type))
207  {
208  if (index >= structType->numElements())
209  throw util::Error("insertvalue index out of bound.");
210 
211  type = structType->getElementType(index);
212  }
213  else if (const auto arrayType = std::dynamic_pointer_cast<const ArrayType>(type))
214  {
215  if (index >= arrayType->nelements())
216  throw util::Error("insertvalue index out of bound.");
217 
218  type = arrayType->GetElementType();
219  }
220  else
221  {
222  throw std::runtime_error("expected array or struct type.");
223  }
224  }
225 
226  if (*valueType != *type)
227  {
228  throw std::runtime_error("value operand does not have the right type.");
229  }
230  }
231 
232  std::vector<unsigned> indices_{};
233 };
234 
235 }
236 
237 #endif
bool operator==(const Operation &other) const noexcept override
static std::unique_ptr< ThreeAddressCode > create(const Variable *aggregate, const std::vector< unsigned > &indices)
std::unique_ptr< Operation > copy() const override
std::string debug_string() const override
~ExtractValueOperation() noexcept override
std::vector< unsigned >::const_iterator const_iterator
const rvsdg::Type & type() const noexcept
static std::vector< std::shared_ptr< const rvsdg::Type > > dsttype(const std::shared_ptr< const rvsdg::Type > &aggtype, const std::vector< unsigned > &indices)
static rvsdg::SimpleNode & createNode(rvsdg::Output &aggregateOperand, rvsdg::Output &valueOperand, std::vector< unsigned > indices)
~InsertValueOperation() noexcept override
std::string debug_string() const override
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &aggregateOperand, const Variable &valueOperand, std::vector< unsigned > indices)
std::unique_ptr< Operation > copy() const override
const std::vector< unsigned > & getIndices() const noexcept
bool operator==(const Operation &other) const noexcept override
const std::shared_ptr< const rvsdg::Type > & getValueType() const noexcept
const std::shared_ptr< const rvsdg::Type > & getAggregateType() const noexcept
static void checkOperandTypes(const std::shared_ptr< const rvsdg::Type > &aggregateType, const std::shared_ptr< const rvsdg::Type > &valueType, const std::vector< unsigned > &indices)
InsertValueOperation(const std::shared_ptr< const rvsdg::Type > &aggregateType, const std::shared_ptr< const rvsdg::Type > &valueType, std::vector< unsigned > indices)
static std::unique_ptr< InsertValueOperation > create(const std::shared_ptr< const rvsdg::Type > &aggregateType, const std::shared_ptr< const rvsdg::Type > &valueType, std::vector< unsigned > indices)
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
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)
Definition: simple-node.hpp:49
const std::shared_ptr< const rvsdg::Type > & argument(size_t index) const noexcept
Definition: operation.cpp:23
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
Global memory state passed between functions.
static ControlFlowGraphNode * aggregate(ControlFlowGraphNode *, ControlFlowGraphNode *, AggregationMap &)