Jlm
Store.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_LLVM_IR_OPERATORS_STORE_HPP
7 #define JLM_LLVM_IR_OPERATORS_STORE_HPP
8 
9 #include <jlm/llvm/ir/tac.hpp>
10 #include <jlm/llvm/ir/types.hpp>
11 #include <jlm/rvsdg/graph.hpp>
13 
14 #include <optional>
15 
16 namespace jlm::llvm
17 {
18 
26 {
27 protected:
29  const std::vector<std::shared_ptr<const rvsdg::Type>> & operandTypes,
30  const std::vector<std::shared_ptr<const rvsdg::Type>> & resultTypes,
31  size_t numMemoryStates,
32  size_t alignment)
33  : SimpleOperation(operandTypes, resultTypes),
34  NumMemoryStates_(numMemoryStates),
35  Alignment_(alignment)
36  {
37  JLM_ASSERT(operandTypes.size() >= 2);
38 
39  auto & addressType = *operandTypes[0];
40  JLM_ASSERT(is<PointerType>(addressType));
41 
42  auto & storedType = *operandTypes[1];
43  JLM_ASSERT(storedType.Kind() == rvsdg::TypeKind::Value);
44 
45  JLM_ASSERT(operandTypes.size() == resultTypes.size() + 2);
46  for (size_t n = 0; n < resultTypes.size(); n++)
47  {
48  auto & operandType = *operandTypes[n + 2];
49  auto & resultType = *resultTypes[n];
50  JLM_ASSERT(operandType == resultType);
51  JLM_ASSERT(operandType.Kind() == rvsdg::TypeKind::State);
52  }
53  }
54 
55 public:
56  [[nodiscard]] size_t
57  GetAlignment() const noexcept
58  {
59  return Alignment_;
60  }
61 
62  [[nodiscard]] const rvsdg::Type &
63  GetStoredType() const noexcept
64  {
65  return *argument(1).get();
66  }
67 
68  [[nodiscard]] size_t
69  NumMemoryStates() const noexcept
70  {
71  return NumMemoryStates_;
72  }
73 
74  [[nodiscard]] static rvsdg::Input &
75  AddressInput(const rvsdg::Node & node) noexcept
76  {
77  JLM_ASSERT(is<StoreOperation>(&node));
78  auto & input = *node.input(0);
79  JLM_ASSERT(is<PointerType>(input.Type()));
80  return input;
81  }
82 
83  [[nodiscard]] static rvsdg::Input &
84  StoredValueInput(const rvsdg::Node & node) noexcept
85  {
86  JLM_ASSERT(is<StoreOperation>(&node));
87  auto & input = *node.input(1);
88  JLM_ASSERT(input.Type()->Kind() == rvsdg::TypeKind::Value);
89  return input;
90  }
91 
92  [[nodiscard]] static rvsdg::Node::OutputIteratorRange
93  MemoryStateOutputs(const rvsdg::SimpleNode & node) noexcept
94  {
95  const auto storeOperation = util::assertedCast<const StoreOperation>(&node.GetOperation());
96  if (storeOperation->NumMemoryStates_ == 0)
97  {
98  return { rvsdg::Output::Iterator(nullptr), rvsdg::Output::Iterator(nullptr) };
99  }
100 
101  const auto firstMemoryStateOutput =
102  node.output(storeOperation->nresults() - storeOperation->NumMemoryStates_);
103  JLM_ASSERT(is<MemoryStateType>(firstMemoryStateOutput->Type()));
104  return { rvsdg::Output::Iterator(firstMemoryStateOutput), rvsdg::Output::Iterator(nullptr) };
105  }
106 
110  [[nodiscard]] static rvsdg::Input &
112  {
113  JLM_ASSERT(is<MemoryStateType>(output.Type()));
114  auto [storeNode, storeOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<StoreOperation>(output);
115  JLM_ASSERT(storeOperation);
116  JLM_ASSERT(storeNode->ninputs() - 2 == storeNode->noutputs());
117  const auto input = storeNode->input(output.index() + 2);
118  JLM_ASSERT(is<MemoryStateType>(input->Type()));
119  return *input;
120  }
121 
122 private:
124  size_t Alignment_;
125 };
126 
133 {
134 public:
135  ~StoreNonVolatileOperation() noexcept override;
136 
138  std::shared_ptr<const rvsdg::Type> storedType,
139  const size_t numMemoryStates,
140  const size_t alignment)
141  : StoreOperation(
142  CreateOperandTypes(std::move(storedType), numMemoryStates),
143  { numMemoryStates, MemoryStateType::Create() },
144  numMemoryStates,
145  alignment)
146  {}
147 
148  bool
149  operator==(const Operation & other) const noexcept override;
150 
151  [[nodiscard]] std::string
152  debug_string() const override;
153 
154  [[nodiscard]] std::unique_ptr<Operation>
155  copy() const override;
156 
175  static std::optional<std::vector<rvsdg::Output *>>
177  const StoreNonVolatileOperation & operation,
178  const std::vector<rvsdg::Output *> & operands);
179 
194  static std::optional<std::vector<rvsdg::Output *>>
196  const StoreNonVolatileOperation & operation,
197  const std::vector<rvsdg::Output *> & operands);
198 
217  static std::optional<std::vector<rvsdg::Output *>>
219  const StoreNonVolatileOperation & operation,
220  const std::vector<rvsdg::Output *> & operands);
221 
235  static std::optional<std::vector<rvsdg::Output *>>
237  const StoreNonVolatileOperation & operation,
238  const std::vector<rvsdg::Output *> & operands);
239 
258  static std::optional<std::vector<rvsdg::Output *>>
260  const StoreNonVolatileOperation & operation,
261  const std::vector<rvsdg::Output *> & operands);
262 
275  static std::optional<std::vector<rvsdg::Output *>>
277  const StoreNonVolatileOperation & operation,
278  const std::vector<rvsdg::Output *> & operands);
279 
280  static std::unique_ptr<llvm::ThreeAddressCode>
281  Create(const Variable * address, const Variable * value, const Variable * state, size_t alignment)
282  {
283  auto storedType = CheckAndExtractStoredType(value->Type());
284 
285  auto op = std::make_unique<StoreNonVolatileOperation>(storedType, 1, alignment);
286  return ThreeAddressCode::create(std::move(op), { address, value, state });
287  }
288 
289  static std::vector<rvsdg::Output *>
291  rvsdg::Output * address,
292  rvsdg::Output * value,
293  const std::vector<rvsdg::Output *> & memoryStates,
294  size_t alignment)
295  {
296  return outputs(&CreateNode(*address, *value, memoryStates, alignment));
297  }
298 
299  static rvsdg::SimpleNode &
301  rvsdg::Output & address,
302  rvsdg::Output & value,
303  const std::vector<rvsdg::Output *> & memoryStates,
304  size_t alignment)
305  {
306  auto storedType = CheckAndExtractStoredType(value.Type());
307 
308  std::vector operands({ &address, &value });
309  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
310 
311  auto operation = std::make_unique<StoreNonVolatileOperation>(
312  std::move(storedType),
313  memoryStates.size(),
314  alignment);
315  return CreateNode(*address.region(), std::move(operation), operands);
316  }
317 
318  static std::vector<rvsdg::Output *>
320  rvsdg::Region & region,
321  std::unique_ptr<StoreNonVolatileOperation> storeOperation,
322  const std::vector<rvsdg::Output *> & operands)
323  {
324  return outputs(&CreateNode(region, std::move(storeOperation), operands));
325  }
326 
327  static rvsdg::SimpleNode &
329  rvsdg::Region & region,
330  std::unique_ptr<StoreNonVolatileOperation> storeOperation,
331  const std::vector<rvsdg::Output *> & operands)
332  {
333  return rvsdg::SimpleNode::Create(region, std::move(storeOperation), operands);
334  }
335 
336 private:
337  static const std::shared_ptr<const jlm::rvsdg::Type>
338  CheckAndExtractStoredType(const std::shared_ptr<const rvsdg::Type> & type)
339  {
340  if (type->Kind() == rvsdg::TypeKind::Value)
341  {
342  return type;
343  }
344 
345  throw util::Error("Expected value type");
346  }
347 
348  static std::vector<std::shared_ptr<const rvsdg::Type>>
349  CreateOperandTypes(std::shared_ptr<const rvsdg::Type> storedType, size_t numMemoryStates)
350  {
351  std::vector<std::shared_ptr<const rvsdg::Type>> types(
352  { PointerType::Create(), std::move(storedType) });
353  std::vector<std::shared_ptr<const rvsdg::Type>> states(
354  numMemoryStates,
356  types.insert(types.end(), states.begin(), states.end());
357  return types;
358  }
359 };
360 
373 {
374 public:
375  ~StoreVolatileOperation() noexcept override;
376 
378  std::shared_ptr<const rvsdg::Type> storedType,
379  const size_t numMemoryStates,
380  const size_t alignment)
381  : StoreOperation(
382  CreateOperandTypes(std::move(storedType), numMemoryStates),
383  CreateResultTypes(numMemoryStates),
384  numMemoryStates,
385  alignment)
386  {}
387 
388  bool
389  operator==(const Operation & other) const noexcept override;
390 
391  [[nodiscard]] std::string
392  debug_string() const override;
393 
394  [[nodiscard]] std::unique_ptr<Operation>
395  copy() const override;
396 
397  [[nodiscard]] static rvsdg::Input &
398  IOStateInput(const rvsdg::Node & node) noexcept
399  {
400  JLM_ASSERT(is<StoreOperation>(&node));
401  auto & input = *node.input(2);
402  JLM_ASSERT(is<IOStateType>(input.Type()));
403  return input;
404  }
405 
406  [[nodiscard]] static rvsdg::Output &
407  IOStateOutput(const rvsdg::Node & node) noexcept
408  {
409  JLM_ASSERT(is<StoreOperation>(&node));
410  auto & output = *node.output(0);
411  JLM_ASSERT(is<IOStateType>(output.Type()));
412  return output;
413  }
414 
415  static std::unique_ptr<llvm::ThreeAddressCode>
417  const Variable * address,
418  const Variable * value,
419  const Variable * ioState,
420  const Variable * memoryState,
421  size_t alignment)
422  {
423  auto storedType = CheckAndExtractStoredType(value->Type());
424 
425  auto op = std::make_unique<StoreVolatileOperation>(storedType, 1, alignment);
426  return ThreeAddressCode::create(std::move(op), { address, value, ioState, memoryState });
427  }
428 
429  static rvsdg::SimpleNode &
431  rvsdg::Region & region,
432  std::unique_ptr<StoreVolatileOperation> storeOperation,
433  const std::vector<rvsdg::Output *> & operands)
434  {
435  return rvsdg::SimpleNode::Create(region, std::move(storeOperation), operands);
436  }
437 
438  static rvsdg::SimpleNode &
440  rvsdg::Output & address,
441  rvsdg::Output & value,
442  rvsdg::Output & ioState,
443  const std::vector<rvsdg::Output *> & memoryStates,
444  size_t alignment)
445  {
446  auto storedType = CheckAndExtractStoredType(value.Type());
447 
448  std::vector<rvsdg::Output *> operands({ &address, &value, &ioState });
449  operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
450 
451  auto operation =
452  std::make_unique<StoreVolatileOperation>(storedType, memoryStates.size(), alignment);
453  return CreateNode(*address.region(), std::move(operation), operands);
454  }
455 
456  static std::vector<rvsdg::Output *>
458  rvsdg::Region & region,
459  std::unique_ptr<StoreVolatileOperation> storeOperation,
460  const std::vector<rvsdg::Output *> & operands)
461  {
462  return rvsdg::outputs(&CreateNode(region, std::move(storeOperation), operands));
463  }
464 
465 private:
466  static std::shared_ptr<const rvsdg::Type>
467  CheckAndExtractStoredType(const std::shared_ptr<const rvsdg::Type> & type)
468  {
469  if (type->Kind() == rvsdg::TypeKind::Value)
470  return type;
471 
472  throw util::Error("Expected value type");
473  }
474 
475  static std::vector<std::shared_ptr<const rvsdg::Type>>
476  CreateOperandTypes(std::shared_ptr<const rvsdg::Type> storedType, size_t numMemoryStates)
477  {
478  std::vector<std::shared_ptr<const rvsdg::Type>> types(
479  { PointerType::Create(), std::move(storedType), IOStateType::Create() });
480  std::vector<std::shared_ptr<const rvsdg::Type>> states(
481  numMemoryStates,
483  types.insert(types.end(), states.begin(), states.end());
484  return types;
485  }
486 
487  static std::vector<std::shared_ptr<const rvsdg::Type>>
488  CreateResultTypes(size_t numMemoryStates)
489  {
490  std::vector<std::shared_ptr<const rvsdg::Type>> types({ IOStateType::Create() });
491  std::vector<std::shared_ptr<const rvsdg::Type>> memoryStates(
492  numMemoryStates,
494  types.insert(types.end(), memoryStates.begin(), memoryStates.end());
495  return types;
496  }
497 };
498 
499 }
500 
501 #endif
static std::shared_ptr< const IOStateType > Create()
Definition: types.cpp:343
static std::shared_ptr< const MemoryStateType > Create()
Definition: types.cpp:379
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreNonVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.hpp:328
static const std::shared_ptr< const jlm::rvsdg::Type > CheckAndExtractStoredType(const std::shared_ptr< const rvsdg::Type > &type)
Definition: Store.hpp:338
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
Definition: Store.hpp:281
static std::vector< rvsdg::Output * > Create(rvsdg::Output *address, rvsdg::Output *value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition: Store.hpp:290
static std::vector< rvsdg::Output * > Create(rvsdg::Region &region, std::unique_ptr< StoreNonVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.hpp:319
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition: Store.hpp:300
static std::optional< std::vector< rvsdg::Output * > > NormalizeIOBarrierAllocaAddress(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Redirect the address operand of the StoreNonVolatileOperation from an IOBarrierOperation when it can ...
Definition: Store.cpp:245
StoreNonVolatileOperation(std::shared_ptr< const rvsdg::Type > storedType, const size_t numMemoryStates, const size_t alignment)
Definition: Store.hpp:137
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > storedType, size_t numMemoryStates)
Definition: Store.hpp:349
std::string debug_string() const override
Definition: Store.cpp:28
bool operator==(const Operation &other) const noexcept override
Definition: Store.cpp:19
static std::optional< std::vector< rvsdg::Output * > > NormalizeStoreMux(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Swaps a memory state merge operation and a store operation.
Definition: Store.cpp:201
~StoreNonVolatileOperation() noexcept override
static std::optional< std::vector< rvsdg::Output * > > normalizeStoreAllocaSingleUser(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.cpp:273
std::unique_ptr< Operation > copy() const override
Definition: Store.cpp:34
static std::optional< std::vector< rvsdg::Output * > > NormalizeStoreAlloca(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes unnecessary state from a store node when its address originates directly from an alloca node.
Definition: Store.cpp:223
static std::optional< std::vector< rvsdg::Output * > > NormalizeStoreStore(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Removes a duplicated store to the same address.
Definition: Store.cpp:212
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateStates(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Remove duplicated state operands.
Definition: Store.cpp:234
const rvsdg::Type & GetStoredType() const noexcept
Definition: Store.hpp:63
StoreOperation(const std::vector< std::shared_ptr< const rvsdg::Type >> &operandTypes, const std::vector< std::shared_ptr< const rvsdg::Type >> &resultTypes, size_t numMemoryStates, size_t alignment)
Definition: Store.hpp:28
static rvsdg::Input & StoredValueInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:84
size_t GetAlignment() const noexcept
Definition: Store.hpp:57
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition: Store.hpp:111
static rvsdg::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::SimpleNode &node) noexcept
Definition: Store.hpp:93
size_t NumMemoryStates() const noexcept
Definition: Store.hpp:69
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:75
bool operator==(const Operation &other) const noexcept override
Definition: Store.cpp:298
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:407
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.hpp:430
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *ioState, const Variable *memoryState, size_t alignment)
Definition: Store.hpp:416
std::string debug_string() const override
Definition: Store.cpp:307
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > storedType, size_t numMemoryStates)
Definition: Store.hpp:476
~StoreVolatileOperation() noexcept override
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
Definition: Store.hpp:488
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, rvsdg::Output &ioState, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition: Store.hpp:439
static std::shared_ptr< const rvsdg::Type > CheckAndExtractStoredType(const std::shared_ptr< const rvsdg::Type > &type)
Definition: Store.hpp:467
std::unique_ptr< Operation > copy() const override
Definition: Store.cpp:313
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition: Store.hpp:398
static std::vector< rvsdg::Output * > Create(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition: Store.hpp:457
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
size_t index() const noexcept
Definition: node.hpp:274
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
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
#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
@ State
Designate a state type.
@ Value
Designate a value type.
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