Jlm
Loading...
Searching...
No Matches
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>
13
14namespace jlm::llvm
15{
16
24{
25 typedef std::vector<unsigned>::const_iterator const_iterator;
26
27public:
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
74private:
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{
113public:
114 ~InsertValueOperation() noexcept override;
115
116private:
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
125public:
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
191private:
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::vector< std::shared_ptr< const rvsdg::Type > > dsttype(const std::shared_ptr< const rvsdg::Type > &aggtype, const std::vector< unsigned > &indices)
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< ThreeAddressCode > create(const Variable *aggregate, const std::vector< unsigned > &indices)
std::string debug_string() const override
const rvsdg::Type & type() const noexcept
~ExtractValueOperation() noexcept override
std::vector< unsigned >::const_iterator const_iterator
const std::shared_ptr< const rvsdg::Type > & getAggregateType() const noexcept
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)
~InsertValueOperation() noexcept override
std::string debug_string() const override
const std::vector< unsigned > & getIndices() const noexcept
std::unique_ptr< Operation > copy() const override
bool operator==(const Operation &other) const noexcept override
const std::shared_ptr< const rvsdg::Type > & getValueType() const noexcept
static rvsdg::SimpleNode & createNode(rvsdg::Output &aggregateOperand, rvsdg::Output &valueOperand, std::vector< unsigned > indices)
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &aggregateOperand, const Variable &valueOperand, std::vector< unsigned > indices)
static void checkOperandTypes(const std::shared_ptr< const rvsdg::Type > &aggregateType, const std::shared_ptr< const rvsdg::Type > &valueType, const 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)
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 &)