27 return operation && operation->
narguments() == narguments()
28 && operation->GetLoadedType() == GetLoadedType()
29 && operation->GetAlignment() == GetAlignment();
38std::unique_ptr<rvsdg::Operation>
41 return std::make_unique<LoadNonVolatileOperation>(*
this);
59 auto address = operands[0];
61 auto [allocaNode, allocaOperation] =
66 for (
size_t n = 1; n < operands.size(); n++)
69 if (is<AllocaOperation>(node) && node != allocaNode)
79 auto [storeNode, storeOperation] =
84 auto [allocaNode, allocaOperation] =
86 if (allocaOperation && allocaNode != loadalloca)
106 const std::vector<rvsdg::Output *> & operands)
108 auto address = operands[0];
110 if (operands.size() == 2)
113 auto [allocaNode, allocaOperation] =
115 if (!allocaOperation)
120 size_t redstates = 0;
121 for (
size_t n = 1; n < operands.size(); n++)
123 auto state = operands[n];
128 return redstates == op.
NumMemoryStates() || redstates == 0 ? false :
true;
140 return states.
Size() != operands.size() - 1;
143static std::vector<rvsdg::Output *>
146 const std::vector<rvsdg::Output *> & operands)
150 std::vector<rvsdg::Output *> loadstates;
151 std::vector<rvsdg::Output *> otherstates;
152 for (
size_t n = 1; n < operands.size(); n++)
155 if (!is<AllocaOperation>(node) || node == allocaNode)
156 loadstates.push_back(operands[n]);
158 otherstates.push_back(operands[n]);
167 std::vector<rvsdg::Output *> results(1, ld[0]);
168 results.insert(results.end(), std::next(ld.begin()), ld.end());
169 results.insert(results.end(), otherstates.begin(), otherstates.end());
173static std::vector<rvsdg::Output *>
176 const std::vector<rvsdg::Output *> & operands)
178 auto address = operands[0];
181 std::vector<rvsdg::Output *> new_loadstates;
182 std::vector<rvsdg::Output *> results(operands.size(),
nullptr);
183 for (
size_t n = 1; n < operands.size(); n++)
185 auto state = operands[n];
189 new_loadstates.push_back(state);
199 for (
size_t n = 1, s = 1; n < results.size(); n++)
201 if (results[n] ==
nullptr)
202 results[n] = ld[s++];
208static std::vector<rvsdg::Output *>
211 const std::vector<rvsdg::Output *> & operands)
214 const auto address = operands[0];
216 std::vector<rvsdg::Output *> newInputStates;
217 std::unordered_map<rvsdg::Output *, size_t> stateIndexMap;
218 for (
size_t n = 1; n < operands.size(); n++)
220 auto state = operands[n];
221 if (stateIndexMap.find(state) == stateIndexMap.end())
223 const size_t resultIndex = 1 + newInputStates.size();
224 newInputStates.push_back(state);
225 stateIndexMap[state] = resultIndex;
235 std::vector<rvsdg::Output *> results(operands.size(),
nullptr);
236 results[0] = loadResults[0];
237 for (
size_t n = 1; n < operands.size(); n++)
239 auto state = operands[n];
240 JLM_ASSERT(stateIndexMap.find(state) != stateIndexMap.end());
241 results[n] = loadResults[stateIndexMap[state]];
247std::optional<std::vector<rvsdg::Output *>>
250 const std::vector<rvsdg::Output *> & operands)
253 if (operands.size() < 2)
257 const auto loadAddressOperand = operands[0];
260 auto firstState = operands[1];
261 auto [storeNode, storeOperation] =
270 if (loadAddressOperand != storeAddressOperand)
280 for (
size_t n = 1; n < operands.size(); n++)
282 auto state = operands[n];
284 if (node != storeNode)
296 auto & storedValueType = *storeValueOperand->Type();
297 if (*loadedValueType != storedValueType)
302 std::vector results(1, storeValueOperand);
303 results.insert(results.end(), std::next(operands.begin()), operands.end());
308std::optional<std::vector<rvsdg::Output *>>
311 const std::vector<rvsdg::Output *> & operands)
319std::optional<std::vector<rvsdg::Output *>>
322 const std::vector<rvsdg::Output *> & operands)
330std::optional<std::vector<rvsdg::Output *>>
333 const std::vector<rvsdg::Output *> & operands)
341static std::optional<size_t>
344 auto [allocaNode, allocaOperation] =
353 const auto deltaOperation =
354 util::assertedCast<const LlvmDeltaOperation>(&deltaNode->GetOperation());
358 if (
const auto llvmImport =
dynamic_cast<const LlvmGraphImport *
>(&output))
366std::optional<std::vector<rvsdg::Output *>>
369 const std::vector<rvsdg::Output *> & operands)
372 const auto address = operands[0];
374 auto [ioBarrierNode, ioBarrierOperation] =
376 if (!ioBarrierOperation)
382 if (!allocationSizeInBytes.has_value())
385 size_t offsetInBytes = 0;
386 if (
const auto offsetInBytesOpt = pointerOrigin.getOffsetInBytes(); offsetInBytesOpt.has_value())
388 offsetInBytes = offsetInBytesOpt.value();
394 > allocationSizeInBytes.value())
399 { std::next(operands.begin()), operands.end() },
403 return { outputs(&loadNode) };
412 return operation && operation->
narguments() == narguments()
413 && operation->GetLoadedType() == GetLoadedType()
414 && operation->GetAlignment() == GetAlignment();
420 return "LoadVolatile";
423std::unique_ptr<rvsdg::Operation>
426 return std::make_unique<LoadVolatileOperation>(*
this);
432 std::unique_ptr<LoadVolatileOperation> loadOperation,
433 const std::vector<rvsdg::Output *> & operands)
static rvsdg::Input & BarredInput(const rvsdg::Node &node) noexcept
static std::optional< std::vector< rvsdg::Output * > > normalizeIOBarrierAddress(const LoadNonVolatileOperation &loadOperation, const std::vector< rvsdg::Output * > &operands)
Redirect the address operand of the LoadNonVolatileOperation node from an IOBarrierOperation node whe...
std::unique_ptr< Operation > copy() const override
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *state, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadStoreState(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
If the producer of a load's address is an alloca operation, then we can remove all state edges origin...
~LoadNonVolatileOperation() noexcept override
static std::optional< std::vector< rvsdg::Output * > > NormalizeDuplicateStates(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Remove duplicated state operands.
static rvsdg::SimpleNode & CreateNode(rvsdg::Region ®ion, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadAlloca(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
If the producer of a load's address is an alloca operation, then we can remove all state edges origin...
std::string debug_string() const override
static std::optional< std::vector< rvsdg::Output * > > NormalizeLoadStore(const LoadNonVolatileOperation &operation, const std::vector< rvsdg::Output * > &operands)
Forwards the value from a store operation.
size_t NumMemoryStates() const noexcept
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
size_t GetAlignment() const noexcept
std::string debug_string() const override
~LoadVolatileOperation() noexcept override
static rvsdg::SimpleNode & CreateNode(rvsdg::Region ®ion, std::unique_ptr< LoadVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
std::unique_ptr< Operation > copy() const override
static rvsdg::Input & StoredValueInput(const rvsdg::Node &node) noexcept
static rvsdg::Input & AddressInput(const rvsdg::Node &node) noexcept
Represent acyclic RVSDG subgraphs.
static SimpleNode & Create(Region ®ion, std::unique_ptr< Operation > operation, const std::vector< rvsdg::Output * > &operands)
size_t narguments() const noexcept
std::size_t Size() const noexcept
Global memory state passed between functions.
static bool is_load_alloca_reducible(const std::vector< rvsdg::Output * > &operands)
size_t GetTypeAllocSize(const rvsdg::Type &type)
TracedPointerOrigin TracePointerOriginPrecise(const rvsdg::Output &p)
static std::vector< rvsdg::Output * > perform_load_alloca_reduction(const LoadNonVolatileOperation &op, const std::vector< rvsdg::Output * > &operands)
static bool is_load_store_state_reducible(const LoadNonVolatileOperation &op, const std::vector< rvsdg::Output * > &operands)
size_t GetTypeStoreSize(const rvsdg::Type &type)
static std::optional< size_t > getAllocationSizeInBytes(const rvsdg::Output &output)
static bool is_multiple_origin_reducible(const std::vector< rvsdg::Output * > &operands)
static std::vector< rvsdg::Output * > perform_multiple_origin_reduction(const LoadNonVolatileOperation &op, const std::vector< rvsdg::Output * > &operands)
static bool is_reducible_state(const rvsdg::Output *state, const rvsdg::Node *loadalloca)
static std::vector< rvsdg::Output * > perform_load_store_state_reduction(const LoadNonVolatileOperation &op, const std::vector< rvsdg::Output * > &operands)
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.