22 return operation && operation->
narguments() == narguments()
23 && operation->GetStoredType() == GetStoredType()
24 && operation->GetAlignment() == GetAlignment();
33 std::unique_ptr<rvsdg::Operation>
36 return std::make_unique<StoreNonVolatileOperation>(*
this);
44 const auto memStateMergeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
45 if (!is<MemoryStateMergeOperation>(memStateMergeNode))
48 for (
size_t n = 2; n <
operands.size(); n++)
50 if (rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[n]) != memStateMergeNode)
60 const std::vector<jlm::rvsdg::Output *> &
operands)
64 const auto storeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
65 if (!is<StoreNonVolatileOperation>(storeNode))
72 if (
operands[0] != storeNode->input(0)->origin())
75 for (
size_t n = 2; n <
operands.size(); n++)
77 if (rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[n]) != storeNode
93 const auto allocaNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[0]);
94 if (!is<AllocaOperation>(allocaNode))
97 std::unordered_set states(std::next(std::next(
operands.begin())),
operands.end());
98 if (states.find(allocaNode->output(1)) == states.end())
101 if (allocaNode->output(1)->nusers() != 1)
114 static std::vector<jlm::rvsdg::Output *>
117 const std::vector<jlm::rvsdg::Output *> &
operands)
119 const auto memStateMergeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
125 memStateMergeOperands,
130 static std::vector<jlm::rvsdg::Output *>
133 const std::vector<jlm::rvsdg::Output *> &
operands)
136 const auto storeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
139 std::vector<jlm::rvsdg::Output *> states(std::next(std::next(storeops.begin())), storeops.end());
143 static std::vector<jlm::rvsdg::Output *>
146 const std::vector<jlm::rvsdg::Output *> &
operands)
150 auto alloca_state = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*address)->output(1);
151 std::unordered_set<jlm::rvsdg::Output *> states(
152 std::next(std::next(
operands.begin())),
157 states.erase(alloca_state);
159 return { states.begin(), states.end() };
162 static std::vector<jlm::rvsdg::Output *>
165 const std::vector<jlm::rvsdg::Output *> &
operands)
173 std::vector<rvsdg::Output *> newInputStates;
174 std::unordered_map<rvsdg::Output *, size_t> stateIndexMap;
175 for (
size_t n = 2; n <
operands.size(); n++)
178 if (stateIndexMap.find(state) == stateIndexMap.end())
180 const size_t resultIndex = newInputStates.size();
181 newInputStates.push_back(state);
182 stateIndexMap[state] = resultIndex;
186 const auto storeResults =
189 std::vector<rvsdg::Output *> results(operation.
nresults(),
nullptr);
190 for (
size_t n = 2; n <
operands.size(); n++)
193 JLM_ASSERT(stateIndexMap.find(state) != stateIndexMap.end());
194 results[n - 2] = storeResults[stateIndexMap[state]];
200 std::optional<std::vector<rvsdg::Output *>>
203 const std::vector<rvsdg::Output *> &
operands)
211 std::optional<std::vector<rvsdg::Output *>>
214 const std::vector<rvsdg::Output *> &
operands)
222 std::optional<std::vector<rvsdg::Output *>>
225 const std::vector<rvsdg::Output *> &
operands)
233 std::optional<std::vector<rvsdg::Output *>>
236 const std::vector<rvsdg::Output *> &
operands)
244 std::optional<std::vector<rvsdg::Output *>>
247 const std::vector<rvsdg::Output *> &
operands)
253 auto [ioBarrierNode, ioBarrierOperation] =
254 rvsdg::TryGetSimpleNodeAndOptionalOp<IOBarrierOperation>(*address);
255 if (!ioBarrierOperation)
260 if (!rvsdg::IsOwnerNodeOperation<AllocaOperation>(tracedAddress))
269 return {
outputs(&storeNode) };
272 std::optional<std::vector<rvsdg::Output *>>
275 const std::vector<rvsdg::Output *> &
operands)
278 const auto & address = *
operands[0];
283 if (!rvsdg::IsOwnerNodeOperation<AllocaOperation>(address))
286 if (address.nusers() != 1)
292 return newMemoryStateResults;
302 && operation->GetStoredType() == GetStoredType()
303 && operation->GetAlignment() == GetAlignment();
309 return "StoreVolatile";
312 std::unique_ptr<rvsdg::Operation>
315 return std::make_unique<StoreVolatileOperation>(*
this);
static rvsdg::Input & BarredInput(const rvsdg::SimpleNode &node) noexcept
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
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 ...
std::string debug_string() const override
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.
~StoreNonVolatileOperation() noexcept override
static std::optional< std::vector< rvsdg::Output * > > normalizeStoreAllocaSingleUser(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
std::unique_ptr< Operation > copy() const override
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.
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.
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateStates(const StoreNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Remove duplicated state operands.
size_t GetAlignment() const noexcept
size_t NumMemoryStates() const noexcept
std::string debug_string() const override
~StoreVolatileOperation() noexcept override
std::unique_ptr< Operation > copy() const override
size_t nresults() const noexcept
size_t narguments() const noexcept
std::size_t Size() const noexcept
Global memory state passed between functions.
static std::vector< jlm::rvsdg::Output * > perform_store_mux_reduction(const StoreNonVolatileOperation &op, const std::vector< jlm::rvsdg::Output * > &operands)
rvsdg::Output & traceOutput(rvsdg::Output &output)
static bool is_store_store_reducible(const StoreNonVolatileOperation &op, const std::vector< jlm::rvsdg::Output * > &operands)
static std::vector< jlm::rvsdg::Output * > perform_store_alloca_reduction(const StoreNonVolatileOperation &op, const std::vector< jlm::rvsdg::Output * > &operands)
static bool is_store_mux_reducible(const std::vector< jlm::rvsdg::Output * > &operands)
static std::vector< jlm::rvsdg::Output * > perform_store_store_reduction(const StoreNonVolatileOperation &op, const std::vector< jlm::rvsdg::Output * > &operands)
static std::vector< rvsdg::Output * > perform_multiple_origin_reduction(const LoadNonVolatileOperation &op, const std::vector< rvsdg::Output * > &operands)
static bool is_multiple_origin_reducible(const std::vector< rvsdg::Output * > &operands)
static bool is_store_alloca_reducible(const std::vector< jlm::rvsdg::Output * > &operands)
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)