Jlm
MemCpy.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2024 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_LLVM_IR_OPERATORS_MEMCPY_HPP
7 #define JLM_LLVM_IR_OPERATORS_MEMCPY_HPP
8 
9 #include <jlm/llvm/ir/tac.hpp>
10 #include <jlm/llvm/ir/types.hpp>
11 #include <jlm/rvsdg/bitstring.hpp>
13 
14 namespace jlm::llvm
15 {
16 
24 {
25 protected:
27  const std::vector<std::shared_ptr<const rvsdg::Type>> & operandTypes,
28  const std::vector<std::shared_ptr<const rvsdg::Type>> & resultTypes)
29  : SimpleOperation(operandTypes, resultTypes)
30  {
31  JLM_ASSERT(operandTypes.size() >= 4);
32 
33  auto & dstAddressType = *operandTypes[0];
34  JLM_ASSERT(is<PointerType>(dstAddressType));
35 
36  auto & srcAddressType = *operandTypes[1];
37  JLM_ASSERT(is<PointerType>(srcAddressType));
38 
39  auto & lengthType = *operandTypes[2];
40  if (lengthType != *rvsdg::BitType::Create(32) && lengthType != *rvsdg::BitType::Create(64))
41  {
42  throw util::Error("Expected 32 bit or 64 bit integer type.");
43  }
44 
45  auto & memoryStateType = *operandTypes.back();
46  if (!is<MemoryStateType>(memoryStateType))
47  {
48  throw util::Error("Number of memory states cannot be zero.");
49  }
50  }
51 
52 public:
53  [[nodiscard]] const rvsdg::BitType &
54  LengthType() const noexcept
55  {
56  auto type = std::dynamic_pointer_cast<const rvsdg::BitType>(argument(2));
57  JLM_ASSERT(type != nullptr);
58  return *type;
59  }
60 
61  [[nodiscard]] virtual size_t
62  NumMemoryStates() const noexcept = 0;
63 
68  [[nodiscard]] static rvsdg::Input &
69  destinationInput(const rvsdg::Node & node) noexcept
70  {
71  JLM_ASSERT(is<MemCpyOperation>(&node));
72  const auto input = node.input(0);
73  JLM_ASSERT(is<PointerType>(input->Type()));
74  return *input;
75  }
76 
81  [[nodiscard]] static rvsdg::Input &
82  sourceInput(const rvsdg::Node & node) noexcept
83  {
84  JLM_ASSERT(is<MemCpyOperation>(&node));
85  const auto input = node.input(1);
86  JLM_ASSERT(is<PointerType>(input->Type()));
87  return *input;
88  }
89 
94  [[nodiscard]] static rvsdg::Input &
95  countInput(const rvsdg::Node & node) noexcept
96  {
97  JLM_ASSERT(is<MemCpyOperation>(&node));
98  const auto input = node.input(2);
99  JLM_ASSERT(is<rvsdg::BitType>(input->Type()));
100  return *input;
101  }
102 
106  [[nodiscard]] static rvsdg::Input &
108  {
109  JLM_ASSERT(is<MemoryStateType>(output.Type()));
110  auto [memCpyNode, memCpyOperation] =
111  rvsdg::TryGetSimpleNodeAndOptionalOp<MemCpyOperation>(output);
112  JLM_ASSERT(memCpyOperation);
113  const auto numNonMemoryStateOutputs =
114  memCpyNode->noutputs() - memCpyOperation->NumMemoryStates();
115  JLM_ASSERT(output.index() >= numNonMemoryStateOutputs);
116  const auto numNonMemoryStateInputs = memCpyNode->ninputs() - memCpyOperation->NumMemoryStates();
117  const auto inputIndex = numNonMemoryStateInputs + (output.index() - numNonMemoryStateOutputs);
118  const auto input = memCpyNode->input(inputIndex);
119  JLM_ASSERT(is<MemoryStateType>(input->Type()));
120  return *input;
121  }
122 
126  [[nodiscard]] static rvsdg::Output &
128  {
129  JLM_ASSERT(is<MemoryStateType>(input.Type()));
130  auto [memCpyNode, memCpyOperation] =
131  rvsdg::TryGetSimpleNodeAndOptionalOp<MemCpyOperation>(input);
132  JLM_ASSERT(memCpyOperation);
133  const auto numNonMemoryStateInputs = memCpyNode->ninputs() - memCpyOperation->NumMemoryStates();
134  JLM_ASSERT(input.index() >= numNonMemoryStateInputs);
135  const auto numNonMemoryStateOutputs =
136  memCpyNode->noutputs() - memCpyOperation->NumMemoryStates();
137  const auto outputIndex = numNonMemoryStateOutputs + (input.index() - numNonMemoryStateInputs);
138  const auto output = memCpyNode->output(outputIndex);
139  JLM_ASSERT(is<MemoryStateType>(output->Type()));
140  return *output;
141  }
142 };
143 
150 {
151 public:
153 
154  MemCpyNonVolatileOperation(std::shared_ptr<const rvsdg::Type> lengthType, size_t numMemoryStates)
155  : MemCpyOperation(
156  CreateOperandTypes(std::move(lengthType), numMemoryStates),
157  CreateResultTypes(numMemoryStates))
158  {}
159 
160  bool
161  operator==(const Operation & other) const noexcept override;
162 
163  [[nodiscard]] std::string
164  debug_string() const override;
165 
166  [[nodiscard]] std::unique_ptr<Operation>
167  copy() const override;
168 
169  [[nodiscard]] size_t
170  NumMemoryStates() const noexcept override;
171 
172  static std::unique_ptr<llvm::ThreeAddressCode>
174  const Variable * destination,
175  const Variable * source,
176  const Variable * length,
177  const std::vector<const Variable *> & memoryStates)
178  {
179  std::vector<const Variable *> operands = { destination, source, length };
180  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
181 
182  auto operation =
183  std::make_unique<MemCpyNonVolatileOperation>(length->Type(), memoryStates.size());
184  return ThreeAddressCode::create(std::move(operation), operands);
185  }
186 
187  static rvsdg::SimpleNode &
189  rvsdg::Output & destination,
190  rvsdg::Output & source,
191  rvsdg::Output & length,
192  const std::vector<rvsdg::Output *> & memoryStates)
193  {
194  std::vector operands = { &destination, &source, &length };
195  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
196 
197  return rvsdg::CreateOpNode<MemCpyNonVolatileOperation>(
198  operands,
199  length.Type(),
200  memoryStates.size());
201  }
202 
203  static std::vector<rvsdg::Output *>
205  rvsdg::Output * destination,
206  rvsdg::Output * source,
207  rvsdg::Output * length,
208  const std::vector<rvsdg::Output *> & memoryStates)
209  {
210  std::vector operands = { destination, source, length };
211  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
212 
213  return outputs(&rvsdg::CreateOpNode<MemCpyNonVolatileOperation>(
214  operands,
215  length->Type(),
216  memoryStates.size()));
217  }
218 
219 private:
220  static std::vector<std::shared_ptr<const rvsdg::Type>>
221  CreateOperandTypes(std::shared_ptr<const rvsdg::Type> length, size_t numMemoryStates)
222  {
223  auto pointerType = PointerType::Create();
224  std::vector<std::shared_ptr<const rvsdg::Type>> types = { pointerType, pointerType, length };
225  types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
226  return types;
227  }
228 
229  static std::vector<std::shared_ptr<const rvsdg::Type>>
230  CreateResultTypes(size_t numMemoryStates)
231  {
232  return { numMemoryStates, MemoryStateType::Create() };
233  }
234 };
235 
248 {
249 public:
250  ~MemCpyVolatileOperation() noexcept override;
251 
252  MemCpyVolatileOperation(std::shared_ptr<const rvsdg::Type> lengthType, size_t numMemoryStates)
253  : MemCpyOperation(
254  CreateOperandTypes(std::move(lengthType), numMemoryStates),
255  CreateResultTypes(numMemoryStates))
256  {}
257 
258  bool
259  operator==(const Operation & other) const noexcept override;
260 
261  [[nodiscard]] std::string
262  debug_string() const override;
263 
264  [[nodiscard]] std::unique_ptr<Operation>
265  copy() const override;
266 
267  [[nodiscard]] size_t
268  NumMemoryStates() const noexcept override;
269 
270  static std::unique_ptr<llvm::ThreeAddressCode>
272  const Variable & destination,
273  const Variable & source,
274  const Variable & length,
275  const Variable & ioState,
276  const std::vector<const Variable *> & memoryStates)
277  {
278  std::vector<const Variable *> operands = { &destination, &source, &length, &ioState };
279  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
280 
281  auto operation = std::make_unique<MemCpyVolatileOperation>(length.Type(), memoryStates.size());
282  return ThreeAddressCode::create(std::move(operation), operands);
283  }
284 
285  static rvsdg::SimpleNode &
287  rvsdg::Output & destination,
288  rvsdg::Output & source,
289  rvsdg::Output & length,
290  rvsdg::Output & ioState,
291  const std::vector<rvsdg::Output *> & memoryStates)
292  {
293  std::vector operands = { &destination, &source, &length, &ioState };
294  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
295 
296  return rvsdg::CreateOpNode<MemCpyVolatileOperation>(
297  operands,
298  length.Type(),
299  memoryStates.size());
300  }
301 
302 private:
303  static std::vector<std::shared_ptr<const rvsdg::Type>>
304  CreateOperandTypes(std::shared_ptr<const rvsdg::Type> lengthType, size_t numMemoryStates)
305  {
306  auto pointerType = PointerType::Create();
307  std::vector<std::shared_ptr<const rvsdg::Type>> types = { pointerType,
308  pointerType,
309  std::move(lengthType),
311  types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
312  return types;
313  }
314 
315  static std::vector<std::shared_ptr<const rvsdg::Type>>
316  CreateResultTypes(size_t numMemoryStates)
317  {
318  std::vector<std::shared_ptr<const rvsdg::Type>> types(1, IOStateType::Create());
319  types.insert(types.end(), numMemoryStates, MemoryStateType::Create());
320  return types;
321  }
322 };
323 
324 }
325 
326 #endif // JLM_LLVM_IR_OPERATORS_MEMCPY_HPP
static std::shared_ptr< const IOStateType > Create()
Definition: types.cpp:343
std::unique_ptr< Operation > copy() const override
Definition: MemCpy.cpp:28
MemCpyNonVolatileOperation(std::shared_ptr< const rvsdg::Type > lengthType, size_t numMemoryStates)
Definition: MemCpy.hpp:154
std::string debug_string() const override
Definition: MemCpy.cpp:22
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > length, size_t numMemoryStates)
Definition: MemCpy.hpp:221
size_t NumMemoryStates() const noexcept override
Definition: MemCpy.cpp:34
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
Definition: MemCpy.hpp:230
static std::vector< rvsdg::Output * > create(rvsdg::Output *destination, rvsdg::Output *source, rvsdg::Output *length, const std::vector< rvsdg::Output * > &memoryStates)
Definition: MemCpy.hpp:204
bool operator==(const Operation &other) const noexcept override
Definition: MemCpy.cpp:14
static rvsdg::SimpleNode & createNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, const std::vector< rvsdg::Output * > &memoryStates)
Definition: MemCpy.hpp:188
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
Definition: MemCpy.hpp:173
const rvsdg::BitType & LengthType() const noexcept
Definition: MemCpy.hpp:54
static rvsdg::Input & mapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition: MemCpy.hpp:107
static rvsdg::Input & destinationInput(const rvsdg::Node &node) noexcept
Definition: MemCpy.hpp:69
virtual size_t NumMemoryStates() const noexcept=0
MemCpyOperation(const std::vector< std::shared_ptr< const rvsdg::Type >> &operandTypes, const std::vector< std::shared_ptr< const rvsdg::Type >> &resultTypes)
Definition: MemCpy.hpp:26
static rvsdg::Input & countInput(const rvsdg::Node &node) noexcept
Definition: MemCpy.hpp:95
static rvsdg::Input & sourceInput(const rvsdg::Node &node) noexcept
Definition: MemCpy.hpp:82
static rvsdg::Output & mapMemoryStateInputToOutput(const rvsdg::Input &input)
Definition: MemCpy.hpp:127
std::string debug_string() const override
Definition: MemCpy.cpp:49
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > lengthType, size_t numMemoryStates)
Definition: MemCpy.hpp:304
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &destination, rvsdg::Output &source, rvsdg::Output &length, rvsdg::Output &ioState, const std::vector< rvsdg::Output * > &memoryStates)
Definition: MemCpy.hpp:286
static std::unique_ptr< llvm::ThreeAddressCode > CreateThreeAddressCode(const Variable &destination, const Variable &source, const Variable &length, const Variable &ioState, const std::vector< const Variable * > &memoryStates)
Definition: MemCpy.hpp:271
std::unique_ptr< Operation > copy() const override
Definition: MemCpy.cpp:55
~MemCpyVolatileOperation() noexcept override
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
Definition: MemCpy.hpp:316
bool operator==(const Operation &other) const noexcept override
Definition: MemCpy.cpp:42
size_t NumMemoryStates() const noexcept override
Definition: MemCpy.cpp:61
static std::shared_ptr< const MemoryStateType > Create()
Definition: types.cpp:379
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
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition: type.cpp:45
size_t index() const noexcept
Definition: node.hpp:52
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:67
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
size_t index() const noexcept
Definition: node.hpp:274
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
#define JLM_ASSERT(x)
Definition: common.hpp:16
Global memory state passed between functions.
static std::string type(const Node *n)
Definition: view.cpp:255
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition: node.hpp:1049
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition: node.hpp:1058