@@ -133,27 +133,6 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> {
133133 return PossibleConstantValues{};
134134 }
135135
136- // Returns a block dropping the `ref` operand of the argument.
137- template <typename T> Block* makeRefDroppingBlock (T* curr) {
138- Builder builder (*getModule ());
139- return builder.blockify (
140- builder.makeDrop (builder.makeRefAs (RefAsNonNull, curr->ref )));
141- }
142-
143- // If an optimized access is sequentially consistent, then it synchronizes
144- // with other threads at least by participating in the global order of
145- // sequentially consistent operations. Preserve that effect by replacing the
146- // access with a fence. On the other hand, if we're optimizing an
147- // acquire-release operation, then we know the accessed field is constant and
148- // will not be modified, so the operation does not necessarily synchronize
149- // with other threads and no fence is required.
150- Block* maybeAddFence (Block* block, MemoryOrder order) {
151- if (order == MemoryOrder::SeqCst) {
152- block->list .push_back (Builder (*getModule ()).makeAtomicFence ());
153- }
154- return block;
155- }
156-
157136 // Given information about a constant value, and the struct type and
158137 // StructGet/RMW/Cmpxchg that reads it, create an expression for that value.
159138 template <typename T>
@@ -216,6 +195,16 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> {
216195 return ;
217196 }
218197
198+ if (curr->order != MemoryOrder::Unordered) {
199+ // The analysis we're basing the optimization on is not precise enough to
200+ // rule out the field being used to synchronize between a write of the
201+ // constant value and a subsequent read on another thread. This
202+ // synchronization is possible even when the write does not change the
203+ // value of the field. For now, simply avoid optimizing this case.
204+ // TODO: Track release and acquire operations in the analysis.
205+ return ;
206+ }
207+
219208 // If the value is not a constant, then it is unknown and we must give up
220209 // on simply applying a constant. However, we can try to use a ref.test, if
221210 // that is allowed.
@@ -231,69 +220,8 @@ struct FunctionOptimizer : public WalkerPass<PostWalker<FunctionOptimizer>> {
231220 // constant value. (Leave it to further optimizations to get rid of the
232221 // ref.)
233222 auto * value = makeExpression (info, heapType, curr);
234- auto * replacement = makeRefDroppingBlock (curr);
235- replacement = maybeAddFence (replacement, curr->order );
236- replacement->list .push_back (value);
237- replacement->type = value->type ;
238- replaceCurrent (replacement);
239- changed = true ;
240- }
241-
242- template <typename T>
243- std::optional<std::pair<HeapType, PossibleConstantValues>>
244- shouldOptimizeRMW (T* curr) {
245- auto type = getRelevantHeapType (curr);
246- if (!type) {
247- return std::nullopt ;
248- }
249- auto heapType = *type;
250-
251- // Get the info about the field. Since RMWs can only copy or mutate the
252- // value, we always have something recorded.
253- PossibleConstantValues info = getInfo (heapType, curr->index );
254- assert (info.hasNoted () && " unexpected lack of info for RMW" );
255-
256- if (!info.isConstant ()) {
257- // Optimizing using ref.test is not an option here because that only works
258- // on immutable fields, but RMW operations always access mutable fields.
259- return std::nullopt ;
260- }
261-
262- // We can optimize.
263- return std::pair (heapType, info);
264- }
265-
266- void visitStructRMW (StructRMW* curr) {
267- auto typeAndInfo = shouldOptimizeRMW (curr);
268- if (!typeAndInfo) {
269- return ;
270- }
271- // Only xchg allows the field to have a constant value.
272- assert (curr->op == RMWXchg && " unexpected op" );
273- auto & [type, info] = *typeAndInfo;
274- Builder builder (*getModule ());
275- auto * value = makeExpression (info, type, curr);
276- auto * replacement = makeRefDroppingBlock (curr);
277- replacement->list .push_back (builder.makeDrop (curr->value ));
278- replacement = maybeAddFence (replacement, curr->order );
279- replacement->list .push_back (value);
280- replacement->type = value->type ;
281- replaceCurrent (replacement);
282- changed = true ;
283- }
284-
285- void visitStructCmpxchg (StructCmpxchg* curr) {
286- auto typeAndInfo = shouldOptimizeRMW (curr);
287- if (!typeAndInfo) {
288- return ;
289- }
290- auto & [type, info] = *typeAndInfo;
291- Builder builder (*getModule ());
292- auto * value = makeExpression (info, type, curr);
293- auto * replacement = makeRefDroppingBlock (curr);
294- replacement->list .push_back (builder.makeDrop (curr->expected ));
295- replacement->list .push_back (builder.makeDrop (curr->replacement ));
296- replacement = maybeAddFence (replacement, curr->order );
223+ auto * replacement = builder.blockify (
224+ builder.makeDrop (builder.makeRefAs (RefAsNonNull, curr->ref )));
297225 replacement->list .push_back (value);
298226 replacement->type = value->type ;
299227 replaceCurrent (replacement);
0 commit comments