24 return operation && operation->
narguments() == narguments()
25 && operation->GetStoredType() == GetStoredType()
26 && operation->GetAlignment() == GetAlignment();
35 std::unique_ptr<rvsdg::Operation>
38 return std::make_unique<StoreNonVolatileOperation>(*
this);
46 const auto memStateMergeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
47 if (!is<MemoryStateMergeOperation>(memStateMergeNode))
50 for (
size_t n = 2; n <
operands.size(); n++)
52 if (rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[n]) != memStateMergeNode)
62 const std::vector<jlm::rvsdg::Output *> &
operands)
67 const auto [store1Node, store1Op] =
68 rvsdg::TryGetSimpleNodeAndOptionalOp<StoreNonVolatileOperation>(*
operands[2]);
73 const auto & store2Address = *
operands[0];
80 for (
size_t n = 2; n <
operands.size(); n++)
82 if (rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[n]) != store1Node
88 const auto & store1Type = store1Op->GetStoredType();
102 const auto allocaNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[0]);
103 if (!is<AllocaOperation>(allocaNode))
106 std::unordered_set states(std::next(std::next(
operands.begin())),
operands.end());
107 if (states.find(allocaNode->output(1)) == states.end())
110 if (allocaNode->output(1)->nusers() != 1)
123 static std::vector<jlm::rvsdg::Output *>
126 const std::vector<jlm::rvsdg::Output *> &
operands)
128 const auto memStateMergeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
134 memStateMergeOperands,
139 static std::vector<jlm::rvsdg::Output *>
142 const std::vector<jlm::rvsdg::Output *> &
operands)
145 const auto storeNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*
operands[2]);
148 std::vector<jlm::rvsdg::Output *> states(std::next(std::next(storeops.begin())), storeops.end());
152 static std::vector<jlm::rvsdg::Output *>
155 const std::vector<jlm::rvsdg::Output *> &
operands)
159 auto alloca_state = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*address)->output(1);
160 std::unordered_set<jlm::rvsdg::Output *> states(
161 std::next(std::next(
operands.begin())),
166 states.erase(alloca_state);
168 return { states.begin(), states.end() };
171 static std::vector<jlm::rvsdg::Output *>
174 const std::vector<jlm::rvsdg::Output *> &
operands)
182 std::vector<rvsdg::Output *> newInputStates;
183 std::unordered_map<rvsdg::Output *, size_t> stateIndexMap;
184 for (
size_t n = 2; n <
operands.size(); n++)
187 if (stateIndexMap.find(state) == stateIndexMap.end())
189 const size_t resultIndex = newInputStates.size();
190 newInputStates.push_back(state);
191 stateIndexMap[state] = resultIndex;
195 const auto storeResults =
198 std::vector<rvsdg::Output *> results(operation.
nresults(),
nullptr);
199 for (
size_t n = 2; n <
operands.size(); n++)
202 JLM_ASSERT(stateIndexMap.find(state) != stateIndexMap.end());
203 results[n - 2] = storeResults[stateIndexMap[state]];
209 std::optional<std::vector<rvsdg::Output *>>
212 const std::vector<rvsdg::Output *> &
operands)
220 std::optional<std::vector<rvsdg::Output *>>
223 const std::vector<rvsdg::Output *> &
operands)
231 std::optional<std::vector<rvsdg::Output *>>
234 const std::vector<rvsdg::Output *> &
operands)
242 std::optional<std::vector<rvsdg::Output *>>
245 const std::vector<rvsdg::Output *> &
operands)
253 std::optional<std::vector<rvsdg::Output *>>
256 const std::vector<rvsdg::Output *> &
operands)
262 auto [ioBarrierNode, ioBarrierOperation] =
263 rvsdg::TryGetSimpleNodeAndOptionalOp<IOBarrierOperation>(*address);
264 if (!ioBarrierOperation)
269 if (!rvsdg::IsOwnerNodeOperation<AllocaOperation>(tracedAddress))
278 return {
outputs(&storeNode) };
281 std::optional<std::vector<rvsdg::Output *>>
284 const std::vector<rvsdg::Output *> &
operands)
287 const auto & address = *
operands[0];
292 if (!rvsdg::IsOwnerNodeOperation<AllocaOperation>(address))
295 if (address.nusers() != 1)
301 return newMemoryStateResults;
311 && operation->GetStoredType() == GetStoredType()
312 && operation->GetAlignment() == GetAlignment();
318 return "StoreVolatile";
321 std::unique_ptr<rvsdg::Operation>
324 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.
const rvsdg::Type & GetStoredType() const noexcept
size_t GetAlignment() const noexcept
size_t NumMemoryStates() const noexcept
static rvsdg::Input & AddressInput(const rvsdg::Node &node) 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, const rvsdg::Region *withinRegion)
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)
size_t GetTypeStoreSize(const rvsdg::Type &type)
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_store_reducible(const StoreNonVolatileOperation &store2Op, const std::vector< jlm::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)