Jlm
Loading...
Searching...
No Matches
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
16namespace jlm::llvm
17{
18
26{
27protected:
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),
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
55public:
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
82 [[nodiscard]] static size_t
83 numMemoryStates(const rvsdg::SimpleNode & node) noexcept
84 {
85 const auto storeOperation = util::assertedCast<const StoreOperation>(&node.GetOperation());
86 return storeOperation->NumMemoryStates_;
87 }
88
89 [[nodiscard]] static rvsdg::Input &
90 AddressInput(const rvsdg::Node & node) noexcept
91 {
92 JLM_ASSERT(is<StoreOperation>(&node));
93 auto & input = *node.input(0);
94 JLM_ASSERT(is<PointerType>(input.Type()));
95 return input;
96 }
97
98 [[nodiscard]] static rvsdg::Input &
99 StoredValueInput(const rvsdg::Node & node) noexcept
100 {
101 JLM_ASSERT(is<StoreOperation>(&node));
102 auto & input = *node.input(1);
103 JLM_ASSERT(input.Type()->Kind() == rvsdg::TypeKind::Value);
104 return input;
105 }
106
107 [[nodiscard]] static rvsdg::Node::OutputIteratorRange
108 MemoryStateOutputs(const rvsdg::Node & node) noexcept
109 {
110 const auto storeOperation = util::assertedCast<const StoreOperation>(&node.GetOperation());
111 if (storeOperation->NumMemoryStates_ == 0)
112 {
113 return { rvsdg::Output::Iterator(nullptr), rvsdg::Output::Iterator(nullptr) };
114 }
115
116 const auto firstMemoryStateOutput =
117 node.output(storeOperation->nresults() - storeOperation->NumMemoryStates_);
118 JLM_ASSERT(is<MemoryStateType>(firstMemoryStateOutput->Type()));
119 return { rvsdg::Output::Iterator(firstMemoryStateOutput), rvsdg::Output::Iterator(nullptr) };
120 }
121
130 [[nodiscard]] static rvsdg::Node::InputIteratorRange
131 getMemoryStateInputs(const rvsdg::Node & node) noexcept
132 {
133 const auto storeOperation = util::assertedCast<const StoreOperation>(&node.GetOperation());
134 if (storeOperation->NumMemoryStates_ == 0)
135 {
136 return { rvsdg::Input::Iterator(nullptr), rvsdg::Input::Iterator(nullptr) };
137 }
138
139 const auto firstMemoryStateInput =
140 node.input(storeOperation->narguments() - storeOperation->NumMemoryStates_);
141 JLM_ASSERT(is<MemoryStateType>(firstMemoryStateInput->Type()));
142 return { rvsdg::Input::Iterator(firstMemoryStateInput), rvsdg::Input::Iterator(nullptr) };
143 }
144
153 [[nodiscard]] static std::vector<rvsdg::Output *>
154 getMemoryStateOperands(const rvsdg::Node & node) noexcept
155 {
156 std::vector<rvsdg::Output *> operands;
157 for (auto & input : getMemoryStateInputs(node))
158 operands.push_back(input.origin());
159
160 return operands;
161 }
162
166 [[nodiscard]] static rvsdg::Input &
168 {
169 JLM_ASSERT(is<MemoryStateType>(output.Type()));
170 auto [storeNode, storeOperation] = rvsdg::TryGetSimpleNodeAndOptionalOp<StoreOperation>(output);
171 JLM_ASSERT(storeOperation);
172 JLM_ASSERT(storeNode->ninputs() - 2 == storeNode->noutputs());
173 const auto input = storeNode->input(output.index() + 2);
174 JLM_ASSERT(is<MemoryStateType>(input->Type()));
175 return *input;
176 }
177
178private:
181};
182
189{
190public:
191 ~StoreNonVolatileOperation() noexcept override;
192
194 std::shared_ptr<const rvsdg::Type> storedType,
195 const size_t numMemoryStates,
196 const size_t alignment)
198 CreateOperandTypes(std::move(storedType), numMemoryStates),
201 alignment)
202 {}
203
204 bool
205 operator==(const Operation & other) const noexcept override;
206
207 [[nodiscard]] std::string
208 debug_string() const override;
209
210 [[nodiscard]] std::unique_ptr<Operation>
211 copy() const override;
212
231 static std::optional<std::vector<rvsdg::Output *>>
233 const StoreNonVolatileOperation & operation,
234 const std::vector<rvsdg::Output *> & operands);
235
250 static std::optional<std::vector<rvsdg::Output *>>
252 const StoreNonVolatileOperation & store2Op,
253 const std::vector<rvsdg::Output *> & operands);
254
273 static std::optional<std::vector<rvsdg::Output *>>
275 const StoreNonVolatileOperation & operation,
276 const std::vector<rvsdg::Output *> & operands);
277
291 static std::optional<std::vector<rvsdg::Output *>>
293 const StoreNonVolatileOperation & operation,
294 const std::vector<rvsdg::Output *> & operands);
295
318 static std::optional<std::vector<rvsdg::Output *>>
320 const StoreNonVolatileOperation & storeOperation,
321 const std::vector<rvsdg::Output *> & operands);
322
335 static std::optional<std::vector<rvsdg::Output *>>
337 const StoreNonVolatileOperation & operation,
338 const std::vector<rvsdg::Output *> & operands);
339
340 static std::unique_ptr<llvm::ThreeAddressCode>
341 Create(const Variable * address, const Variable * value, const Variable * state, size_t alignment)
342 {
343 auto storedType = CheckAndExtractStoredType(value->Type());
344
345 auto op = std::make_unique<StoreNonVolatileOperation>(storedType, 1, alignment);
346 return ThreeAddressCode::create(std::move(op), { address, value, state });
347 }
348
349 static std::vector<rvsdg::Output *>
351 rvsdg::Output * address,
352 rvsdg::Output * value,
353 const std::vector<rvsdg::Output *> & memoryStates,
354 size_t alignment)
355 {
356 return outputs(&CreateNode(*address, *value, memoryStates, alignment));
357 }
358
359 static rvsdg::SimpleNode &
361 rvsdg::Output & address,
362 rvsdg::Output & value,
363 const std::vector<rvsdg::Output *> & memoryStates,
364 size_t alignment)
365 {
366 auto storedType = CheckAndExtractStoredType(value.Type());
367
368 std::vector operands({ &address, &value });
369 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
370
371 auto operation = std::make_unique<StoreNonVolatileOperation>(
372 std::move(storedType),
373 memoryStates.size(),
374 alignment);
375 return CreateNode(*address.region(), std::move(operation), operands);
376 }
377
378 static std::vector<rvsdg::Output *>
380 rvsdg::Region & region,
381 std::unique_ptr<StoreNonVolatileOperation> storeOperation,
382 const std::vector<rvsdg::Output *> & operands)
383 {
384 return outputs(&CreateNode(region, std::move(storeOperation), operands));
385 }
386
387 static rvsdg::SimpleNode &
389 rvsdg::Region & region,
390 std::unique_ptr<StoreNonVolatileOperation> storeOperation,
391 const std::vector<rvsdg::Output *> & operands)
392 {
393 return rvsdg::SimpleNode::Create(region, std::move(storeOperation), operands);
394 }
395
396private:
397 static const std::shared_ptr<const jlm::rvsdg::Type>
398 CheckAndExtractStoredType(const std::shared_ptr<const rvsdg::Type> & type)
399 {
400 if (type->Kind() == rvsdg::TypeKind::Value)
401 {
402 return type;
403 }
404
405 throw util::Error("Expected value type");
406 }
407
408 static std::vector<std::shared_ptr<const rvsdg::Type>>
409 CreateOperandTypes(std::shared_ptr<const rvsdg::Type> storedType, size_t numMemoryStates)
410 {
411 std::vector<std::shared_ptr<const rvsdg::Type>> types(
412 { PointerType::Create(), std::move(storedType) });
413 std::vector<std::shared_ptr<const rvsdg::Type>> states(
416 types.insert(types.end(), states.begin(), states.end());
417 return types;
418 }
419};
420
433{
434public:
435 ~StoreVolatileOperation() noexcept override;
436
438 std::shared_ptr<const rvsdg::Type> storedType,
439 const size_t numMemoryStates,
440 const size_t alignment)
442 CreateOperandTypes(std::move(storedType), numMemoryStates),
445 alignment)
446 {}
447
448 bool
449 operator==(const Operation & other) const noexcept override;
450
451 [[nodiscard]] std::string
452 debug_string() const override;
453
454 [[nodiscard]] std::unique_ptr<Operation>
455 copy() const override;
456
457 [[nodiscard]] static rvsdg::Input &
458 IOStateInput(const rvsdg::Node & node) noexcept
459 {
460 JLM_ASSERT(is<StoreOperation>(&node));
461 auto & input = *node.input(2);
462 JLM_ASSERT(is<IOStateType>(input.Type()));
463 return input;
464 }
465
466 [[nodiscard]] static rvsdg::Output &
467 IOStateOutput(const rvsdg::Node & node) noexcept
468 {
469 JLM_ASSERT(is<StoreOperation>(&node));
470 auto & output = *node.output(0);
471 JLM_ASSERT(is<IOStateType>(output.Type()));
472 return output;
473 }
474
475 static std::unique_ptr<llvm::ThreeAddressCode>
477 const Variable * address,
478 const Variable * value,
479 const Variable * ioState,
480 const Variable * memoryState,
481 size_t alignment)
482 {
483 auto storedType = CheckAndExtractStoredType(value->Type());
484
485 auto op = std::make_unique<StoreVolatileOperation>(storedType, 1, alignment);
486 return ThreeAddressCode::create(std::move(op), { address, value, ioState, memoryState });
487 }
488
489 static rvsdg::SimpleNode &
491 rvsdg::Region & region,
492 std::unique_ptr<StoreVolatileOperation> storeOperation,
493 const std::vector<rvsdg::Output *> & operands)
494 {
495 return rvsdg::SimpleNode::Create(region, std::move(storeOperation), operands);
496 }
497
498 static rvsdg::SimpleNode &
500 rvsdg::Output & address,
501 rvsdg::Output & value,
502 rvsdg::Output & ioState,
503 const std::vector<rvsdg::Output *> & memoryStates,
504 size_t alignment)
505 {
506 auto storedType = CheckAndExtractStoredType(value.Type());
507
508 std::vector<rvsdg::Output *> operands({ &address, &value, &ioState });
509 operands.insert(operands.end(), memoryStates.begin(), memoryStates.end());
510
511 auto operation =
512 std::make_unique<StoreVolatileOperation>(storedType, memoryStates.size(), alignment);
513 return CreateNode(*address.region(), std::move(operation), operands);
514 }
515
516 static std::vector<rvsdg::Output *>
518 rvsdg::Region & region,
519 std::unique_ptr<StoreVolatileOperation> storeOperation,
520 const std::vector<rvsdg::Output *> & operands)
521 {
522 return rvsdg::outputs(&CreateNode(region, std::move(storeOperation), operands));
523 }
524
525private:
526 static std::shared_ptr<const rvsdg::Type>
527 CheckAndExtractStoredType(const std::shared_ptr<const rvsdg::Type> & type)
528 {
529 if (type->Kind() == rvsdg::TypeKind::Value)
530 return type;
531
532 throw util::Error("Expected value type");
533 }
534
535 static std::vector<std::shared_ptr<const rvsdg::Type>>
536 CreateOperandTypes(std::shared_ptr<const rvsdg::Type> storedType, size_t numMemoryStates)
537 {
538 std::vector<std::shared_ptr<const rvsdg::Type>> types(
539 { PointerType::Create(), std::move(storedType), IOStateType::Create() });
540 std::vector<std::shared_ptr<const rvsdg::Type>> states(
543 types.insert(types.end(), states.begin(), states.end());
544 return types;
545 }
546
547 static std::vector<std::shared_ptr<const rvsdg::Type>>
549 {
550 std::vector<std::shared_ptr<const rvsdg::Type>> types({ IOStateType::Create() });
551 std::vector<std::shared_ptr<const rvsdg::Type>> memoryStates(
554 types.insert(types.end(), memoryStates.begin(), memoryStates.end());
555 return types;
556 }
557};
558
559}
560
561#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 std::optional< std::vector< rvsdg::Output * > > normalizeStoreStore(const StoreNonVolatileOperation &store2Op, const std::vector< rvsdg::Output * > &operands)
Removes a duplicated store to the same address.
Definition Store.cpp:174
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreNonVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition Store.hpp:388
static const std::shared_ptr< const jlm::rvsdg::Type > CheckAndExtractStoredType(const std::shared_ptr< const rvsdg::Type > &type)
Definition Store.hpp:398
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
Definition Store.hpp:341
std::string debug_string() const override
Definition Store.cpp:33
bool operator==(const Operation &other) const noexcept override
Definition Store.cpp:24
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:163
static std::optional< std::vector< rvsdg::Output * > > normalizeMemoryHoistBarrierAddress(const StoreNonVolatileOperation &storeOperation, const std::vector< rvsdg::Output * > &operands)
Redirect the address operand of the StoreNonVolatileOperation node from an MemoryHoistBarrierOperatio...
Definition Store.cpp:279
~StoreNonVolatileOperation() noexcept override
static std::vector< rvsdg::Output * > Create(rvsdg::Output *address, rvsdg::Output *value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition Store.hpp:350
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > storedType, size_t numMemoryStates)
Definition Store.hpp:409
static std::optional< std::vector< rvsdg::Output * > > normalizeStoreAllocaSingleUser(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Definition Store.cpp:320
std::unique_ptr< Operation > copy() const override
Definition Store.cpp:39
static std::vector< rvsdg::Output * > Create(rvsdg::Region &region, std::unique_ptr< StoreNonVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition Store.hpp:379
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:230
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition Store.hpp:360
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateStates(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Remove duplicated state operands.
Definition Store.cpp:241
static std::vector< rvsdg::Output * > getMemoryStateOperands(const rvsdg::Node &node) noexcept
Definition Store.hpp:154
static rvsdg::Input & StoredValueInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:99
static rvsdg::Input & MapMemoryStateOutputToInput(const rvsdg::Output &output)
Definition Store.hpp:167
size_t GetAlignment() const noexcept
Definition Store.hpp:57
static size_t numMemoryStates(const rvsdg::SimpleNode &node) noexcept
Definition Store.hpp:83
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:90
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::Node::OutputIteratorRange MemoryStateOutputs(const rvsdg::Node &node) noexcept
Definition Store.hpp:108
static rvsdg::Node::InputIteratorRange getMemoryStateInputs(const rvsdg::Node &node) noexcept
Definition Store.hpp:131
const rvsdg::Type & GetStoredType() const noexcept
Definition Store.hpp:63
size_t NumMemoryStates() const noexcept
Definition Store.hpp:69
bool operator==(const Operation &other) const noexcept override
Definition Store.cpp:345
std::string debug_string() const override
Definition Store.cpp:354
~StoreVolatileOperation() noexcept override
static rvsdg::Output & IOStateOutput(const rvsdg::Node &node) noexcept
Definition Store.hpp:467
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateResultTypes(size_t numMemoryStates)
Definition Store.hpp:548
std::unique_ptr< Operation > copy() const override
Definition Store.cpp:360
static std::vector< std::shared_ptr< const rvsdg::Type > > CreateOperandTypes(std::shared_ptr< const rvsdg::Type > storedType, size_t numMemoryStates)
Definition Store.hpp:536
static std::vector< rvsdg::Output * > Create(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition Store.hpp:517
static rvsdg::Input & IOStateInput(const rvsdg::Node &node) noexcept
Definition Store.hpp:458
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:476
static std::shared_ptr< const rvsdg::Type > CheckAndExtractStoredType(const std::shared_ptr< const rvsdg::Type > &type)
Definition Store.hpp:527
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:499
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition Store.hpp:490
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition tac.hpp:155
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition variable.hpp:62
rvsdg::Region * region() const noexcept
Definition node.cpp:151
size_t index() const noexcept
Definition node.hpp:274
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
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
#define JLM_ASSERT(x)
Definition common.hpp:16
Global memory state passed between functions.
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition node.hpp:1058
@ State
Designate a state type.
@ Value
Designate a value type.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872