Jlm
Loading...
Searching...
No Matches
IOBarrierElimination.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2026 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
10#include <jlm/rvsdg/lambda.hpp>
12#include <jlm/rvsdg/Phi.hpp>
15
16namespace jlm::llvm
17{
18
20{
21 const char * MarkTimerLabel_ = "MarkTime";
22 const char * SweepTimerLabel_ = "SweepTime";
23
24public:
25 ~Statistics() override = default;
26
27 explicit Statistics(const util::FilePath & sourceFile)
28 : util::Statistics(Id::IOBarrierElimination, sourceFile)
29 {}
30
31 void
36
37 void
39 {
41 }
42
43 void
48
49 void
54
55 static std::unique_ptr<Statistics>
56 create(const util::FilePath & sourceFile)
57 {
58 return std::make_unique<Statistics>(sourceFile);
59 }
60};
61
63{
64public:
70 bool
71 markDereferenceable(const rvsdg::Output & output, const size_t sizeInBytes)
72 {
73 const auto it = dereferenceableOutputs_.find(&output);
74 if (it == dereferenceableOutputs_.end())
75 {
76 dereferenceableOutputs_[&output] = sizeInBytes;
77 return true;
78 }
79
80 if (it->second < sizeInBytes)
81 dereferenceableOutputs_[&output] = sizeInBytes;
82
83 return false;
84 }
85
89 std::optional<size_t>
90 isDereferenceable(const rvsdg::Output & output) const
91 {
92 const auto it = dereferenceableOutputs_.find(&output);
93 if (it == dereferenceableOutputs_.end())
94 return std::nullopt;
95
96 return it->second;
97 }
98
99 static std::unique_ptr<Context>
101 {
102 return std::make_unique<Context>();
103 }
104
105private:
106 std::unordered_map<const rvsdg::Output *, size_t> dereferenceableOutputs_{};
107};
108
110
112 : Transformation("IOBarrierElimination")
113{}
114
115void
117 rvsdg::RvsdgModule & module,
119{
120 auto & rvsdg = module.Rvsdg();
121
123 auto statistics = Statistics::create(module.SourceFilePath().value());
124
125 statistics->startMarkStatistics();
126 markRegion(rvsdg.GetRootRegion());
127 statistics->stopMarkStatistics();
128
129 statistics->startSweepStatistics();
130 sweepRegion(rvsdg.GetRootRegion());
131 statistics->stopSweepStatistics();
132
133 statisticsCollector.CollectDemandedStatistics(std::move(statistics));
134
135 // Discard internal state to free up memory after we are done
136 context_.reset();
137}
138
139void
141{
142 for (const auto node : rvsdg::TopDownTraverser(&region))
143 {
144 markNode(*node);
145 }
146}
147
148void
150{
152 node.GetOperation(),
153 [&](const rvsdg::PhiOperation &)
154 {
155 const auto phiNode = util::assertedCast<const rvsdg::PhiNode>(&node);
156 markRegion(*phiNode->subregion());
157 },
158 [&](const LlvmLambdaOperation &)
159 {
160 const auto lambdaNode = util::assertedCast<const rvsdg::LambdaNode>(&node);
161 markRegion(*lambdaNode->subregion());
162 },
163 [&](const LoadNonVolatileOperation & loadOperation)
164 {
165 const auto & addressOperand = *LoadOperation::AddressInput(node).origin();
166 const auto sizeInBytes = GetTypeStoreSize(*loadOperation.GetLoadedType());
167
168 auto [ioBarrierNode, ioBarrierOp] =
169 rvsdg::TryGetSimpleNodeAndOptionalOp<IOBarrierOperation>(addressOperand);
170 if (ioBarrierOp)
171 {
172 const auto & barredAddressOperand =
173 *IOBarrierOperation::BarredInput(*ioBarrierNode).origin();
174 if (const auto & ioStateInput = IOBarrierOperation::getIOStateInput(*ioBarrierNode);
175 rvsdg::TryGetRegionParentNode<rvsdg::LambdaNode>(*ioStateInput.origin()))
176 {
177 // If the IO state is directly connected to a function argument, we can eliminate the
178 // IOBarrierOperation node as function inlining should reinsert a new IOBarrierOperation
179 // node when inlining is performed.
180 context_->markDereferenceable(barredAddressOperand, sizeInBytes);
181 }
182 }
183 else
184 {
185 // The load node is not connected to a IOBarrierOperation node. Mark its address operand
186 // as dereferenceable.
187 context_->markDereferenceable(addressOperand, sizeInBytes);
188 }
189 });
190}
191
192void
193IOBarrierElimination::sweepRegion(rvsdg::Region & region)
194{
195 for (auto & node : region.Nodes())
196 {
198 node.GetOperation(),
199 [&](const rvsdg::PhiOperation &)
200 {
201 const auto phiNode = util::assertedCast<const rvsdg::PhiNode>(&node);
202 sweepRegion(*phiNode->subregion());
203 },
204 [&](const LlvmLambdaOperation &)
205 {
206 const auto lambdaNode = util::assertedCast<const rvsdg::LambdaNode>(&node);
207 sweepRegion(*lambdaNode->subregion());
208 },
209 [&](const LoadNonVolatileOperation & loadOperation)
210 {
211 auto & loadAddress = LoadOperation::AddressInput(node);
212 auto [ioBarrierNode, ioBarrierOp] =
213 rvsdg::TryGetSimpleNodeAndOptionalOp<IOBarrierOperation>(*loadAddress.origin());
214 if (!ioBarrierOp)
215 return;
216
217 auto & barredAddressOperand = *IOBarrierOperation::BarredInput(*ioBarrierNode).origin();
218 const auto sizeOpt = context_->isDereferenceable(barredAddressOperand);
219 const auto sizeInBytes = GetTypeStoreSize(*loadOperation.GetLoadedType());
220 if (!sizeOpt.has_value() || sizeOpt.value() < sizeInBytes)
221 return;
222
223 loadAddress.divert_to(&barredAddressOperand);
224 });
225 }
226
227 region.prune(false);
228}
229
230}
static jlm::util::StatisticsCollector statisticsCollector
std::unordered_map< const rvsdg::Output *, size_t > dereferenceableOutputs_
std::optional< size_t > isDereferenceable(const rvsdg::Output &output) const
bool markDereferenceable(const rvsdg::Output &output, const size_t sizeInBytes)
static std::unique_ptr< Context > create()
Statistics(const util::FilePath &sourceFile)
static std::unique_ptr< Statistics > create(const util::FilePath &sourceFile)
void Run(rvsdg::RvsdgModule &module, util::StatisticsCollector &statisticsCollector) override
Perform RVSDG transformation.
void markNode(const rvsdg::Node &node)
void markRegion(rvsdg::Region &region)
void sweepRegion(rvsdg::Region &region)
std::unique_ptr< Context > context_
virtual const Operation & GetOperation() const noexcept=0
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
void prune(bool recursive)
Definition region.cpp:326
NodeRange Nodes() noexcept
Definition region.hpp:375
const std::optional< util::FilePath > & SourceFilePath() const noexcept
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
Statistics Interface.
util::Timer & GetTimer(const std::string &name)
util::Timer & AddTimer(std::string name)
void start() noexcept
Definition time.hpp:54
void stop() noexcept
Definition time.hpp:67
Global memory state passed between functions.
void MatchType(T &obj, const Fns &... fns)
Pattern match over subclass type of given object.
detail::TopDownTraverserGeneric< false > TopDownTraverser
Traverser for visiting every node in a region in a top down order.